From d7698b1c8a7250962f086e1749719e85d4dbecca Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 16 Nov 2024 10:12:22 +0100 Subject: [PATCH] fix: distinguish turn to discard in case of start turns Fixes #1342 --- .../overlay/discard_duplicate_turns.hpp | 21 ++++++++++++------- test/algorithms/overlay/overlay_cases.hpp | 12 +++++++++++ .../set_operations/difference/difference.cpp | 14 ++++++++++++- .../intersection/intersection.cpp | 3 +++ .../algorithms/set_operations/union/union.cpp | 6 ++++++ 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp index f85483a1d..3c1ef5f34 100644 --- a/include/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp @@ -104,7 +104,7 @@ void discard_duplicate_start_turns(Turns& turns, return multi_and_ring_id_type{seg_id.multi_index, seg_id.ring_index}; }; - for (auto const& turn : turns) + for (auto& turn : turns) { // Any turn which "crosses" does not have a corresponding turn. // Also avoid comparing "start" with itself @@ -112,18 +112,23 @@ void discard_duplicate_start_turns(Turns& turns, { continue; } + bool const is_touch = turn.method == method_touch; for (auto const& op : turn.operations) { auto it = start_turns_by_segment.find(adapt_id(op.seg_id)); - if (it != start_turns_by_segment.end()) + if (it == start_turns_by_segment.end()) { - for (std::size_t const& i : it->second) + continue; + } + for (std::size_t const& i : it->second) + { + auto& start_turn = turns[i]; + if (start_turn.cluster_id == turn.cluster_id + && corresponding_turn(turn, start_turn, geometry0, geometry1)) { - if (turns[i].cluster_id == turn.cluster_id - && corresponding_turn(turn, turns[i], geometry0, geometry1)) - { - turns[i].discarded = true; - } + // Discard the start turn, unless there is a touch before. + // In that case the start is used and the touch is discarded. + (is_touch ? turn : start_turn).discarded = true; } } } diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index f1b1bb613..3fcabd6c0 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -1219,6 +1219,18 @@ static std::string issue_1326[2] = "POLYGON((-8.78625207542057 1.47256621042848,-8.7713880762347 1.56833897112359,-8.54870763952499 1.98231380430185,-8.38536606998748 2.07941797642276,-8.33146477996655 2.0901167844798,-6.33512517561985 2.16974517238479,-5.57210759837464 2.18803744441122,-1.10154617615509 2.18080908730283,-0.182335452668298 1.77473544450602,-0.101072642349846 1.70875977436368,-0.00289004633636303 1.59446412805576,0.123812278264287 1.4079409294325,0.130584672613603 1.37357814410482,0.17646634130118 0.897752998467649,0.184490648597164 0.600369907975512,0.180036363994123 0.284803921497103,0.07694307247317141 0.151908777171867,0.0269420690240159 0.09795742893367709,-0.984492757676803 -0.593037244494384,-1.07964346095732 -0.633124388260264,-8.500679967807759 1.25877844922534,-8.78625207542057 1.47256621042848))" }; +static std::string issue_1342_a[2] = +{ + "POLYGON((0 0,2.000000861538488 2.0000008,23.52786548447633 2.0000008,25.3497180322038 1.569919497715026,26 0,0 0))", + "POLYGON((2.000000861538488 0,2.000000861538488 2.0000008,23.52786548447633 2.0000008,23.52786548447633 0,2.000000861538488 0))" +}; + +static std::string issue_1342_b[2] = +{ + "POLYGON((0 2.944711629068049e-16,2.000000861538488 2.0000008,23.52786548447633 2.0000008,25.3497180322038 1.569919497715026,26 2.775557561562891e-15,0 2.944711629068049e-16))", + "POLYGON((2.000000861538488 2.944711629068049e-16,2.000000861538488 2.0000008,23.52786548447633 2.0000008,23.52786548447633 2.944711629068049e-16,2.000000861538488 2.944711629068049e-16))" +}; + static std::string ggl_list_20120229_volker[3] = { "POLYGON((1716 1554,2076 2250,2436 2352,2796 1248,3156 2484,3516 2688,3516 2688,3156 2484,2796 1248,2436 2352,2076 2250, 1716 1554))", diff --git a/test/algorithms/set_operations/difference/difference.cpp b/test/algorithms/set_operations/difference/difference.cpp index 0ceec3e35..b2c2dc6ea 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -624,7 +624,16 @@ void test_all() TEST_DIFFERENCE(issue_1244, 3, 8, 3, 2, 6); - TEST_DIFFERENCE(issue_1293, 1, 1.40999, 1, 2.318951, 2); + { + // The symmetric difference reports an invalidity since the choice of + // discarding start/touch turns. + // This might be a false negative. + // Clockwise: "method: t; operations: u/x" + // CCW: "method: m; operations: i/x" + ut_settings settings; + settings.validity_of_sym = false; + TEST_DIFFERENCE_WITH(issue_1293, 1, 1.40999, 1, 2.318951, 2, settings); + } #if defined(BOOST_GEOMETRY_TEST_FAILURES) // Difference fails for this case. This was not reported for this case. @@ -635,6 +644,9 @@ void test_all() TEST_DIFFERENCE(issue_1326, 3, 6.7128537626409130468, 6, 0.00372806966532758478, 9); + TEST_DIFFERENCE(issue_1342_a, 2, 5.762381026454777, 0, 0.0, 2); + TEST_DIFFERENCE(issue_1342_b, 2, 5.762381026454777, 1, 2.55e-14, 3); + TEST_DIFFERENCE(mysql_21977775, 2, 160.856568913, 2, 92.3565689126, 4); TEST_DIFFERENCE(mysql_21965285, 1, 92.0, 1, 14.0, 1); TEST_DIFFERENCE(mysql_23023665_1, 1, 92.0, 1, 142.5, 2); diff --git a/test/algorithms/set_operations/intersection/intersection.cpp b/test/algorithms/set_operations/intersection/intersection.cpp index 309ea7d3b..fe926a646 100644 --- a/test/algorithms/set_operations/intersection/intersection.cpp +++ b/test/algorithms/set_operations/intersection/intersection.cpp @@ -312,6 +312,9 @@ void test_areal() TEST_INTERSECTION(issue_1295, 1, -1, 4.90121); TEST_INTERSECTION(issue_1326, 1, -1, 16.4844); + TEST_INTERSECTION(issue_1342_a, 1, -1, 43.05575); + TEST_INTERSECTION(issue_1342_b, 1, -1, 43.05575); + test_one("buffer_mp1", buffer_mp1[0], buffer_mp1[1], 1, 31, 2.271707796); test_one("buffer_mp2", buffer_mp2[0], buffer_mp2[1], diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 6e7fb1be4..0473c5cfa 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -487,6 +487,12 @@ void test_areal() TEST_UNION(issue_1326, 1, 0, -1, 23.201); TEST_UNION_REV(issue_1326, 1, 0, -1, 23.201); + TEST_UNION(issue_1342_a, 1, 0, -1, 48.81812749462216); + TEST_UNION_REV(issue_1342_a, 1, 0, -1, 48.81812749462216); + + TEST_UNION(issue_1342_b, 1, 0, -1, 48.81812749462214); + TEST_UNION_REV(issue_1342_b, 1, 0, -1, 48.81812749462214); + TEST_UNION(geos_1, 1, 0, -1, expectation_limits(3458.0, 3461.3203125)); TEST_UNION(geos_2, 1, 0, -1, expectation_limits(349.0625, 350.55102539)); TEST_UNION(geos_3, 1, 0, -1, 29391548.4998779);