From a7485784ca403fbc4d6f2c0806df7ae4124f9f97 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Wed, 3 Nov 2021 15:29:19 +0100 Subject: [PATCH] [envelope] Reverse holes to avoid calculating mbr for the outside in spherical and geographic CS. --- .../algorithms/detail/envelope/areal.hpp | 27 ++++++++++++++----- .../envelope_expand/envelope_on_spheroid.cpp | 20 ++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/envelope/areal.hpp b/include/boost/geometry/algorithms/detail/envelope/areal.hpp index 81aa1c82c..ece4d3d14 100644 --- a/include/boost/geometry/algorithms/detail/envelope/areal.hpp +++ b/include/boost/geometry/algorithms/detail/envelope/areal.hpp @@ -22,6 +22,8 @@ #include +#include + namespace boost { namespace geometry { @@ -29,6 +31,24 @@ namespace boost { namespace geometry namespace detail { namespace envelope { + +struct envelope_hole +{ + template + static inline void apply(Range const& range, Box& mbr, Strategies const& strategies) + { + // Reverse holes to avoid calculating the envelope for the outside + // in spherical and geographic coordinate systems + detail::clockwise_view + < + Range const, + geometry::point_order::value == counterclockwise + ? clockwise : counterclockwise + > view(range); + strategies.envelope(range, mbr).apply(view, mbr); + } +}; + struct envelope_polygon { template @@ -39,18 +59,13 @@ struct envelope_polygon if (geometry::is_empty(ext_ring)) { - // TODO: In spherical and geographic this is ambiguous. A hole technically is a ring - // defining the outside so the envelope would cover more than half of the globe. - // So depending on what we want we could consider reversing holes before passing them - // below. - // use dummy multi polygon to get the strategy because there is no multi ring concept using strategy_t = decltype(strategy.envelope(detail::dummy_multi_polygon(), detail::dummy_box())); // if the exterior ring is empty, consider the interior rings envelope_multi_range < - envelope_range + envelope_hole >::template apply(interior_rings(polygon), mbr, strategy); } else diff --git a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp index 58fe132ab..e270fdba4 100644 --- a/test/algorithms/envelope_expand/envelope_on_spheroid.cpp +++ b/test/algorithms/envelope_expand/envelope_on_spheroid.cpp @@ -2710,20 +2710,40 @@ BOOST_AUTO_TEST_CASE( envelope_cw_ring ) #endif // From disjoint https://svn.boost.org/trac/boost/ticket/9162 + // Polygons containing poles tester::apply("r22cw", from_wkt("POLYGON((0 80,-90 80,-180 80,90 80,0 80))"), -180, 80, 180, 90); tester::apply("r23cw", from_wkt("POLYGON((0 -80,90 -80,-180 -80,-90 -80,0 -80))"), -180, -90, 180, -80); + // Polygons greater than half of the globe tester::apply("r24cw", from_wkt("POLYGON((0 80,90 80,-180 80,-90 80,0 80))"), -180, -90, 180, 82.892923889553458); tester::apply("r25cw", from_wkt("POLYGON((0 -80,-90 -80,-180 -80,90 -80,0 -80))"), -180, -82.892923889553458, 180, 90); + // Normal test case tester::apply("r26cw", from_wkt("POLYGON((30 0,30 30,90 30, 90 0, 30 0))"), 30, 0, 90, 33.690067525979771); + + // Invalid polygons with holes containing poles + tester::apply("r27cw", + from_wkt("POLYGON((),(0 80,90 80,-180 80,-90 80,0 80))"), + -180, 80, 180, 90); + tester::apply("r28cw", + from_wkt("POLYGON((),(0 -80,-90 -80,-180 -80,90 -80,0 -80))"), + -180, -90, 180, -80); + + typedef bg::model::polygon G2; + typedef test_envelope_on_sphere_or_spheroid tester2; + tester2::apply("r27ccw", + from_wkt("POLYGON((),(0 80,-90 80,-180 80,90 80,0 80))"), + -180, 80, 180, 90); + tester2::apply("r28ccw", + from_wkt("POLYGON((),(0 -80,90 -80,-180 -80,-90 -80,0 -80))"), + -180, -90, 180, -80); }