From ed217554490e9a9e210023b814d8087f05b30f05 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 11 Nov 2017 01:20:51 +0100 Subject: [PATCH 1/2] [overlay] For union do not check area of result before adding polygons to the output. --- .../geometry/algorithms/detail/overlay/add_rings.hpp | 6 ++++-- .../boost/geometry/algorithms/detail/overlay/overlay.hpp | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/include/boost/geometry/algorithms/detail/overlay/add_rings.hpp index fcb240941..317bacc78 100644 --- a/include/boost/geometry/algorithms/detail/overlay/add_rings.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/add_rings.hpp @@ -74,7 +74,8 @@ template inline OutputIterator add_rings(SelectionMap const& map, Geometry1 const& geometry1, Geometry2 const& geometry2, RingCollection const& collection, - OutputIterator out) + OutputIterator out, + bool require_positive_area = true) { typedef typename SelectionMap::const_iterator iterator; typedef typename SelectionMap::mapped_type property_type; @@ -123,7 +124,8 @@ inline OutputIterator add_rings(SelectionMap const& map, // This cannot be done earlier (during traversal), not // everything is figured out yet (sum of positive/negative rings) if (geometry::num_points(result) >= min_num_points - && math::larger(geometry::area(result), zero)) + && (! require_positive_area + || math::larger(geometry::area(result), zero))) { *out++ = result; } diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index b415f97a0..57855f1f3 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -387,7 +387,13 @@ std::cout << "traverse" << std::endl; assign_parents(geometry1, geometry2, rings, selected_ring_properties, strategy); - return add_rings(selected_ring_properties, geometry1, geometry2, rings, out); + // NOTE: There is no need to check result area for union because + // as long as the polygons in the input are valid the resulting + // polygons should be valid as well. + // This also solves the issue with non-cartesian CSes, the result may + // be too big so the area is negative but it's returned anyway. + return add_rings(selected_ring_properties, geometry1, geometry2, rings, out, + OverlayType != overlay_union); } template From 0413013fbcdb130ab795c50ea03a5db7ee6504c3 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 11 Nov 2017 02:07:36 +0100 Subject: [PATCH 2/2] [test][union] Add geographic union tests (big result, negative area). --- .../set_operations/union/Jamfile.v2 | 5 +- .../algorithms/set_operations/union/union.cpp | 29 ----- .../set_operations/union/union_aa_geo.cpp | 104 ++++++++++++++++++ 3 files changed, 107 insertions(+), 31 deletions(-) create mode 100644 test/algorithms/set_operations/union/union_aa_geo.cpp diff --git a/test/algorithms/set_operations/union/Jamfile.v2 b/test/algorithms/set_operations/union/Jamfile.v2 index ea558953c..3be60cecb 100644 --- a/test/algorithms/set_operations/union/Jamfile.v2 +++ b/test/algorithms/set_operations/union/Jamfile.v2 @@ -4,8 +4,8 @@ # Copyright (c) 2008-2015 Bruno Lalande, Paris, France. # Copyright (c) 2009-2015 Mateusz Loskot, London, UK. # -# This file was modified by Oracle on 2014, 2015. -# Modifications copyright (c) 2014-2015, Oracle and/or its affiliates. +# This file was modified by Oracle on 2014, 2015, 2017. +# Modifications copyright (c) 2014-2017, Oracle and/or its affiliates. # # Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle # Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -18,6 +18,7 @@ test-suite boost-geometry-algorithms-union : [ run union.cpp : : : BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_union ] + [ run union_aa_geo.cpp : : : : algorithms_union_aa_geo ] [ run union_linear_linear.cpp : : : : algorithms_union_linear_linear ] [ run union_multi.cpp : : : BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE : algorithms_union_multi ] diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 40644c6c0..bb1513455 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -482,33 +482,6 @@ void test_areal() 1, 1, -1, 220.5); } -void test_geographic() -{ - typedef bg::model::point > point; - typedef bg::model::polygon polygon; - typedef bg::model::multi_polygon multipolygon; - - bg::srs::spheroid sph(6378137.0000000000, 6356752.3142451793); - - bg::strategy::intersection::geographic_segments<> is(sph); - bg::strategy::area::geographic as(sph); - - polygon p1, p2; - - boost::geometry::read_wkt("POLYGON((16 15,-132 10,-56 89,67 5,16 15))", p1); - boost::geometry::read_wkt("POLYGON((101 49,12 40,-164 10,117 0,101 49))", p2); - - multipolygon result; - boost::geometry::union_(p1, p2, result, is); - - double result_area = bg::area(result, as); - - BOOST_CHECK(boost::size(result) == 1 - && boost::size(bg::exterior_ring(bg::range::at(result, 0))) == 9 - && boost::size(bg::interior_rings(bg::range::at(result, 0))) == 0); - BOOST_CHECK_CLOSE(result_area, 144265751613509.06, 0.001); -} - template void test_all() { @@ -584,7 +557,5 @@ int test_main(int, char* []) #endif #endif - test_geographic(); - return 0; } diff --git a/test/algorithms/set_operations/union/union_aa_geo.cpp b/test/algorithms/set_operations/union/union_aa_geo.cpp new file mode 100644 index 000000000..a2d573be7 --- /dev/null +++ b/test/algorithms/set_operations/union/union_aa_geo.cpp @@ -0,0 +1,104 @@ +// Boost.Geometry +// Unit Test + +// Copyright (c) 2017, Oracle and/or its affiliates. +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include "test_union.hpp" + +#include + + +struct exterior_points_counter +{ + exterior_points_counter() : count(0) {} + + template + void operator()(Polygon const& poly) + { + count += boost::size(bg::exterior_ring(poly)); + } + + std::size_t count; +}; + +struct interiors_counter + : exterior_points_counter +{ + template + void operator()(Polygon const& poly) + { + count += boost::size(bg::interior_rings(poly)); + } +}; + +void test_geographic_one(std::string const& wkt1, std::string const& wkt2, + std::size_t count, std::size_t exterior_points_count, std::size_t interiors_count, + double expected_area) +{ + typedef bg::model::point > point; + typedef bg::model::polygon polygon; + typedef bg::model::multi_polygon multipolygon; + + bg::srs::spheroid sph(6378137.0000000000, 6356752.3142451793); + + bg::strategy::intersection::geographic_segments<> is(sph); + bg::strategy::area::geographic as(sph); + + polygon p1, p2; + + boost::geometry::read_wkt(wkt1, p1); + boost::geometry::read_wkt(wkt2, p2); + + multipolygon result; + boost::geometry::union_(p1, p2, result, is); + + double result_area = bg::area(result, as); + + std::size_t result_count = boost::size(result); + std::size_t result_exterior_points = std::for_each(boost::begin(result), + boost::end(result), + exterior_points_counter()).count; + std::size_t result_interiors = std::for_each(boost::begin(result), + boost::end(result), + interiors_counter()).count; + BOOST_CHECK_EQUAL(result_count, count); + BOOST_CHECK_EQUAL(result_exterior_points, exterior_points_count); + BOOST_CHECK_EQUAL(result_interiors, interiors_count); + BOOST_CHECK_CLOSE(result_area, expected_area, 0.001); +} + + +void test_geographic() +{ + // input ok and the result is ok + test_geographic_one("POLYGON((16 15,-132 10,-56 89,67 5,16 15))", + "POLYGON((101 49,12 40,-164 10,117 0,101 49))", + 1, 9, 0, 144265751613509.06); + + // input ok but the result is too big + test_geographic_one("POLYGON((16 -15,-132 -22,-56 89,67 -29,16 -15))", + "POLYGON((101 49,12 40,-164 -21,117 -61,101 49))", + 1, 9, 0, -163427005620080.0); + + // the second polygon is reversed i.e. it covers more than half of the globe + // so the result is also too big + test_geographic_one("POLYGON((16 -15,-132 -22,-56 89,67 -29,16 -15))", + "POLYGON((101 49,117 -61,-164 -21,12 40,101 49))", + 1, 7, 0, -125258931656228.08); +} + + +int test_main(int, char* []) +{ + test_geographic(); + + return 0; +}