From d03167598c485b5303baee555e370672b8cbc316 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 15 Nov 2024 19:11:56 +0100 Subject: [PATCH 1/6] fix: extra round over ring in #1226 and #1326 This can occur in a sequence of touch and then touch_interior --- .../overlay/discard_duplicate_turns.hpp | 176 +++++++++++++----- .../overlay/enrich_intersection_points.hpp | 2 +- test/algorithms/overlay/overlay_cases.hpp | 12 ++ .../set_operations/difference/difference.cpp | 9 + .../intersection/intersection.cpp | 2 + .../algorithms/set_operations/union/union.cpp | 6 + 6 files changed, 160 insertions(+), 47 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 604dd9fd36..f85483a1d5 100644 --- a/include/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp @@ -14,9 +14,11 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DISCARD_DUPLICATE_TURNS_HPP #include +#include #include #include +#include namespace boost { namespace geometry { @@ -88,72 +90,154 @@ inline bool corresponding_turn(Turn const& turn, Turn const& start_turn, return count == 2; } -template -inline void discard_duplicate_start_turns(Turns& turns, - Geometry0 const& geometry0, - Geometry1 const& geometry1) +// Verify turns (other than start, and cross) if they are present in the map, and if so, +// if they have the other turns as corresponding, discard the start turn. +template +void discard_duplicate_start_turns(Turns& turns, + TurnBySegmentMap const& start_turns_by_segment, + Geometry0 const& geometry0, + Geometry1 const& geometry1) { - // Start turns are generated, in case the previous turn is missed. - // But often it is not missed, and then it should be deleted. - // This is how it can be - // (in float, collinear, points far apart due to floating point precision) - // [m, i s:0, v:6 1/1 (1) // u s:1, v:5 pnt (2.54044, 3.12623)] - // [s, i s:0, v:7 0/1 (0) // u s:1, v:5 pnt (2.70711, 3.29289)] - using multi_and_ring_id_type = std::pair; - auto adapt_id = [](segment_identifier const& seg_id) { return multi_and_ring_id_type{seg_id.multi_index, seg_id.ring_index}; }; - // 1 Build map of start turns (multi/ring-id -> turn indices) - std::map> start_turns_per_segment; - std::size_t index = 0; for (auto const& turn : turns) { - if (turn.method == method_start) + // Any turn which "crosses" does not have a corresponding turn. + // Also avoid comparing "start" with itself + if (turn.method == method_crosses || turn.method == method_start) + { + continue; + } + for (auto const& op : turn.operations) { - 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()) { - start_turns_per_segment[adapt_id(op.seg_id)].push_back(index); + for (std::size_t const& i : it->second) + { + if (turns[i].cluster_id == turn.cluster_id + && corresponding_turn(turn, turns[i], geometry0, geometry1)) + { + turns[i].discarded = true; + } + } } } - index++; } +} - // 2: Verify all other turns if they are present in the map, and if so, - // if they have the other turns as corresponding - for (auto const& turn : turns) +// Discard turns for the following (rare) case: +// - they are consecutive +// - the first has a touch, the second a touch_interior +// And then one of the segments touches the others next in the middle. +// This is geometrically not possible, and caused by floating point precision. +// Discard the second (touch interior) +template +void discard_touch_touch_interior_turns(Turns& turns, + Geometry0 const& geometry0, + Geometry1 const& geometry1) +{ + for (auto& current_turn : turns) { - // Any turn which "crosses" does not have a corresponding turn. - // Also avoid comparing "start" with itself. - if (turn.method != method_crosses && turn.method != method_start) + if (current_turn.method != method_touch_interior) { - for (auto const& op : turn.operations) + // Because touch_interior is a rarer case, it is more efficient to start with that + continue; + } + for (auto const& previous_turn : turns) + { + if (previous_turn.method != method_touch) { - auto it = start_turns_per_segment.find(adapt_id(op.seg_id)); - if (it != start_turns_per_segment.end()) - { - for (std::size_t const& i : it->second) - { - if (turns[i].cluster_id != turn.cluster_id) - { - // The turns are not part of the same cluster, - // or one is clustered and the other is not. - // This is not corresponding. - continue; - } - if (corresponding_turn(turn, turns[i], - geometry0, geometry1)) - { - turns[i].discarded = true; - } - } - } + continue; + } + + // Compare 0 with 0 and 1 with 1 + // Note that 0 has always source 0 and 1 has always source 1 + // (not in buffer). Therefore this comparison is OK. + // MAYBE we need to check for buffer. + bool const common0 = current_turn.operations[0].seg_id == previous_turn.operations[0].seg_id; + bool const common1 = current_turn.operations[1].seg_id == previous_turn.operations[1].seg_id; + + // If one of the operations is common, and the other is not, then there is one comment segment. + bool const has_common_segment = common0 != common1; + + if (! has_common_segment) + { + continue; } + + // If the second index (1) is common, we need to check consecutivity of the first index (0) + // and vice versa. + bool const consecutive = + common1 ? is_consecutive(previous_turn.operations[0].seg_id, current_turn.operations[0].seg_id, geometry0, geometry1) + : is_consecutive(previous_turn.operations[1].seg_id, current_turn.operations[1].seg_id, geometry0, geometry1); + + if (consecutive) + { + current_turn.discarded = true; + } + } + } +} + +template +void discard_duplicate_turns(Turns& turns, + Geometry0 const& geometry0, + Geometry1 const& geometry1) +{ + // Start turns are generated, in case the previous turn is missed. + // But often it is not missed, and then it should be deleted. + // This is how it can be + // (in float, collinear, points far apart due to floating point precision) + // [m, i s:0, v:6 1/1 (1) // u s:1, v:5 pnt (2.54044, 3.12623)] + // [s, i s:0, v:7 0/1 (0) // u s:1, v:5 pnt (2.70711, 3.29289)] + // + // Also, if two turns are consecutive, and one is touch and the other touch_interior, + // the touch_interior is discarded. + + using multi_and_ring_id_type = std::pair; + + auto add_to_map = [](auto const& turn, auto& map, std::size_t index) + { + auto adapt_id = [](segment_identifier const& seg_id) + { + return multi_and_ring_id_type{seg_id.multi_index, seg_id.ring_index}; + }; + for (auto const& op : turn.operations) + { + map[adapt_id(op.seg_id)].insert(index); + } + }; + + // Build map of start turns (multi/ring-id -> turn indices) + // and count touch and touch_interior turns (to verify if later checks are needed) + std::map> start_turns_by_segment; + std::size_t touch_count = 0; + std::size_t touch_interior_count = 0; + for (auto const& item : util::enumerate(turns)) + { + auto const& turn = item.value; + switch(turn.method) + { + case method_start: add_to_map(turn, start_turns_by_segment, item.index); break; + case method_touch: touch_count++; break; + case method_touch_interior: touch_interior_count++; break; + default: break; } - index++; + } + + if (!start_turns_by_segment.empty()) + { + discard_duplicate_start_turns(turns, start_turns_by_segment, geometry0, geometry1); + } + + if (touch_count > 0 && touch_interior_count > 0) + { + discard_touch_touch_interior_turns(turns, geometry0, geometry1); } } diff --git a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index 40eb0ed5a5..215a53298f 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -442,7 +442,7 @@ inline void enrich_intersection_points(Turns& turns, has_colocations = ! clusters.empty(); } - discard_duplicate_start_turns(turns, geometry1, geometry2); + discard_duplicate_turns(turns, geometry1, geometry2); // Discard turns not part of target overlay for (auto& turn : turns) diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 3ded5aa154..f1b1bb6134 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -1176,6 +1176,12 @@ static std::string issue_1186[2] = "POLYGON((-13848.1446527556 6710443.1496919869,-13848.2559722463 6710440.2884572418,-13847.8106942832 6710440.1096301023,-13847.6993747924 6710443.1496919869,-13847.3654163201 6710442.9708647905,-13846.0295824308 6710442.9708647905,-13846.4748603939 6710435.1024718173,-13847.8106942832 6710435.1024718173,-13848.1446527556 6710435.1024718173,-13849.8144451172 6710443.1496919869,-13848.1446527556 6710443.1496919869),(-13847.4767358109 6710440.1096301023,-13847.8106942832 6710440.1096301023,-13847.9220137740 6710439.9308029665,-13847.5880553017 6710439.7519758362,-13847.4767358109 6710440.1096301023))" }; +static std::string issue_1226[2] = +{ + "POLYGON((-0.90478776881879274807 0.51756843862589896332,-0.91 0.48,-1.2 0.4,-1.4 1.9,-0.90478776881879274807 0.51756843862589896332))", + "POLYGON((-0.91943242964602156508 0.55292377741135378955,-0.90478776881879174887 0.51756843862590162786,-0.91 0.48,-0.91943242964602156508 0.55292377741135378955))" +}; + // Triangle, nearly a line static std::string issue_1229[2] = { @@ -1207,6 +1213,12 @@ static std::string issue_1295[2] = "POLYGON((5.7885861030591501 1.2258588412299519e-16, 4.9808473496052885 -0.91020845951432006, 3.0646473238074286e-16 -0.91020843804041685, 0.0 0.0, 5.7885861030591501 1.2258588412299519e-16))" }; +static std::string issue_1326[2] = +{ + "POLYGON((-2.89115098058377 -0.25,-9.34535427093506 -0.25,-9.34535427093506 1.75,-8.741949140272411 1.75,-8.75132236364928 1.78066623424071,-8.72379640157045 1.98517649674012,-8.697157657744199 2.08892604820013,-8.46516432879152 2.10694502899749,-8.450862779791599 2.11134809476174,-8.38919349162909 2.11284570322019,-8.123031147354849 2.13351860011817,-6.54486857587017 2.15952214498774,-6.33512517561985 2.16974517238479,-6.09011821087143 2.17207715057343,-5.97563428310822 2.17637335012843,-5.57133260872244 2.18630252700583,-5.07887848661571 2.18416804606516,-5.0359022373011 2.18529905658276,-1.19310678637991 2.2589664950919,-0.345028190203889 2.01010408632087,-0.0299072068264135 1.77159468023247,-0.02022234569985 1.75,0 1.75,0 1.7049095146299,0.246630961988226 1.15498766340636,0.268832205492555 0.460222803594299,0.180040345346232 0.355084664215225,0.180036363994124 0.284803921497104,0.08623260647096399 0.174496413890264,0.0780023740039386 0.150962829485067,0.0280089059206103 0.0970044986024092,0 0.07806844106142739,0 -0.25,-0.452569566324256 -0.25,-0.959885872828952 -0.5758450741921251,-0.984492757676798 -0.593037244494381,-0.986053937110457 -0.592652605781279,-1.03380615828627 -0.623323463099221,-1.05433104239722 -0.636707963526427,-1.05455277432398 -0.636648843252325,-1.08230325522736 -0.654472747969937,-1.10154815200623 -0.653773778128255,-1.27688251591406 -0.61035431255586,-2.30803967424193 -0.423843667604139,-2.89115098058377 -0.25))", + "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 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 819c8c8523..0ceec3e35c 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -613,6 +613,13 @@ void test_all() TEST_DIFFERENCE(issue_1138, 1, 203161.751, 2, 1237551.0171, 1); + { + ut_settings settings; + settings.set_test_validity(false); + settings.validity_of_sym = false; + TEST_DIFFERENCE_WITH(issue_1226, 1, 0.238037722, 0, 0.0, 1, settings); + } + TEST_DIFFERENCE(issue_1231, 2, 36.798659456837477, 3, 195.2986, 5); TEST_DIFFERENCE(issue_1244, 3, 8, 3, 2, 6); @@ -626,6 +633,8 @@ void test_all() TEST_DIFFERENCE(issue_1295, 1, 9.999, 1, 9.999, 1); #endif + TEST_DIFFERENCE(issue_1326, 3, 6.7128537626409130468, 6, 0.00372806966532758478, 9); + 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 29e4da6144..309ea7d3b2 100644 --- a/test/algorithms/set_operations/intersection/intersection.cpp +++ b/test/algorithms/set_operations/intersection/intersection.cpp @@ -301,6 +301,7 @@ void test_areal() TEST_INTERSECTION(issue_861, 1, -1, 1.4715007684573677693e-10); + TEST_INTERSECTION(issue_1226, 1, -1, 0.00036722862); TEST_INTERSECTION(issue_1229, 0, -1, 0); TEST_INTERSECTION(issue_1231, 1, -1, 54.701340543162516); @@ -309,6 +310,7 @@ void test_areal() TEST_INTERSECTION(issue_1293, 1, -1, 1.49123); TEST_INTERSECTION(issue_1295, 1, -1, 4.90121); + TEST_INTERSECTION(issue_1326, 1, -1, 16.4844); test_one("buffer_mp1", buffer_mp1[0], buffer_mp1[1], 1, 31, 2.271707796); diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index e4ea757b82..6e7fb1be48 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -466,6 +466,9 @@ void test_areal() TEST_UNION(issue_1186, 1, 1, -1, 21.6189); TEST_UNION_REV(issue_1186, 1, 1, -1, 21.6189); + TEST_UNION(issue_1226, 1, 0, -1, 0.238405); + TEST_UNION_REV(issue_1226, 1, 0, -1, 0.238405); + TEST_UNION(issue_1229, 1, 0, -1, 384869.166); TEST_UNION_REV(issue_1229, 1, 0, -1, 384869.166); @@ -481,6 +484,9 @@ void test_areal() TEST_UNION(issue_1295, 1, 0, -1, 17.56273); TEST_UNION_REV(issue_1295, 1, 0, -1, 17.56273); + TEST_UNION(issue_1326, 1, 0, -1, 23.201); + TEST_UNION_REV(issue_1326, 1, 0, -1, 23.201); + 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); From a14dc9d2c16210914a7233617a50e45a88693f9c Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 16 Nov 2024 10:12:22 +0100 Subject: [PATCH 2/6] 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 f85483a1d5..3c1ef5f345 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 f1b1bb6134..3fcabd6c03 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 0ceec3e35c..b2c2dc6ea7 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 309ea7d3b2..fe926a6462 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 6e7fb1be48..0473c5cfa2 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); From 75469596907b42394fa849ccb92a03370f4592f6 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 20 Nov 2024 16:48:25 +0100 Subject: [PATCH 3/6] fix: add condition to handle_imperfect_touch Fixes #1345 --- .../detail/overlay/get_turn_info.hpp | 11 +++- .../detail/overlay/get_turn_info_helpers.hpp | 13 ++--- test/algorithms/overlay/overlay_cases.hpp | 53 +++++++++++++++++++ .../set_operations/difference/difference.cpp | 3 ++ .../intersection/intersection.cpp | 3 ++ .../algorithms/set_operations/union/union.cpp | 6 +++ 6 files changed, 82 insertions(+), 7 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index 4dd823f96c..c81bc87c4b 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -569,7 +569,7 @@ struct touch : public base_turn_handler // || // |^---- // >----->P - // * * they touch here (P/Q are (nearly) on top) + // * * they touch here (P/Q are (nearly) on top of each other) // // Q continues from where P comes. // P continues from where Q comes @@ -586,6 +586,14 @@ struct touch : public base_turn_handler // >----->P qj is LEFT of P1 and pi is LEFT of Q2 // (the other way round is also possible) + // There are also cases like this: + // P + // ^ + // || + // || + // P----^----- bool { auto const d1 = get_distance_measure(r1.at(0), r1.at(1), r2.at(1), umbrella_strategy); @@ -674,6 +682,7 @@ struct touch : public base_turn_handler { if (side_qk_p1 == 0 && side_pk_q1 == 0 && has_pk && has_qk + && opposite(side.pi_wrt_q1(), side.qk_wrt_p2()) && handle_imperfect_touch(range_p, range_q, side_pk_q2, umbrella_strategy, ti)) { // If q continues collinearly (opposite) with p, it should be blocked diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp index 4ef747f019..12db5ac8e2 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -58,6 +58,13 @@ struct side_calculator , m_range_q(range_q) {} + inline int pi_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pi()); } + + inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); } + inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); } + inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); } + inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); } + inline int pk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_pk()); } inline int pk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pk()); } inline int qk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qk()); } @@ -66,12 +73,6 @@ struct side_calculator inline int pk_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pk()); } inline int qk_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qk()); } - // Necessary when rescaling turns off: - inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); } - inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); } - inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); } - inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); } - inline auto const& get_pi() const { return m_range_p.at(0); } inline auto const& get_pj() const { return m_range_p.at(1); } inline auto const& get_pk() const { return m_range_p.at(2); } diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 3fcabd6c03..6b54807313 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -1231,6 +1231,59 @@ static std::string issue_1342_b[2] = "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 issue_1345_a[2] = +{ + // Needs check for opposite in handle_imperfect_touch + R""""( + POLYGON(( + -2.0785311235613415 -0.6304193410175202, + -2.0534946127981359 -0.6304193410175202, + -2.0534946127981359 -0.8867932112327471, + -2.3098684830133629 -0.8867932112327471, + -2.3098684830133629 -0.6554558517807265, + -2.2848319722501573 -0.6554558517807265, + -2.0785311235613415 -0.6554558517807265, + -2.0785311235613415 -0.6304193410175202 + )) + )"""", + R""""( + POLYGON(( + -2.0785311235613420 -0.6304193410175202, + -2.0534946127981359 -0.6304193410175202, + -2.0534946127981359 -0.6554558517807265, + -2.0785311235613420 -0.6554558517807265, + -2.0785311235613420 -0.6304193410175202 + )) + )"""" +}; + +static std::string issue_1345_b[2] = +{ + // Needs check for opposite in handle_imperfect_touch + R""""( + POLYGON(( + -6.1723606999999996 3.2834021000000000, + -6.1723606999999996 2.8006724999999992, + -5.7133718999999994 2.8006724999999992, + -5.7133718999999994 3.2834021000000000, + -5.6896310999999997 3.2834021000000000, + -5.6896310999999997 2.7769316999999996, + -6.1961014999999993 2.7769316999999996, + -6.1961014999999993 3.2834021000000000, + -6.1723606999999996 3.2834021000000000 + )) + )"""", + R""""( + POLYGON(( + -6.1723606999999996 2.8006724999999997, + -5.7133718999999994 2.8006724999999997, + -5.7133718999999994 2.7769316999999996, + -6.1723606999999996 2.7769316999999996, + -6.1723606999999996 2.8006724999999997 + )) + )"""" +}; + 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 b2c2dc6ea7..d6112f9118 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -647,6 +647,9 @@ void test_all() 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(issue_1345_a, 1, 0.059308854, 0, 0.0, 1); + TEST_DIFFERENCE(issue_1345_b, 2, 0.024048025, 0, 0.0, 2); + 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 fe926a6462..2ce4956a86 100644 --- a/test/algorithms/set_operations/intersection/intersection.cpp +++ b/test/algorithms/set_operations/intersection/intersection.cpp @@ -315,6 +315,9 @@ void test_areal() TEST_INTERSECTION(issue_1342_a, 1, -1, 43.05575); TEST_INTERSECTION(issue_1342_b, 1, -1, 43.05575); + TEST_INTERSECTION(issue_1345_a, 1, -1, 0.00062682687); + TEST_INTERSECTION(issue_1345_b, 1, -1, 0.010896761); + 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 0473c5cfa2..2824016d2b 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -493,6 +493,12 @@ void test_areal() TEST_UNION(issue_1342_b, 1, 0, -1, 48.81812749462214); TEST_UNION_REV(issue_1342_b, 1, 0, -1, 48.81812749462214); + TEST_UNION(issue_1345_a, 1, 0, -1, 0.059935681); + TEST_UNION_REV(issue_1345_a, 1, 0, -1, 0.059935681); + + TEST_UNION(issue_1345_b, 1, 0, -1, 0.034944786); + TEST_UNION_REV(issue_1345_b, 1, 0, -1, 0.034944786); + 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); From 9c4d7529b1c03d1e611fa1b55358350eb8c26d46 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 24 Nov 2024 10:32:55 +0100 Subject: [PATCH 4/6] fix: add condition to handle_as_touch Fixes #1288 --- .../detail/overlay/get_turn_info.hpp | 26 ++++++++++++++++--- .../overlay/multi_overlay_cases.hpp | 14 ++++++++++ .../difference/difference_multi.cpp | 10 +++++++ .../intersection/intersection_multi.cpp | 3 +++ .../set_operations/union/union_multi.cpp | 3 +++ 5 files changed, 52 insertions(+), 4 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index c81bc87c4b..e61ad72860 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -343,10 +343,14 @@ struct touch_interior : public base_turn_handler template < typename IntersectionInfo, - typename UniqueSubRange + typename SideCalculator, + typename UniqueSubRange1, + typename UniqueSubRange2 > static bool handle_as_touch(IntersectionInfo const& info, - UniqueSubRange const& non_touching_range) + SideCalculator const& side, + UniqueSubRange1 const& non_touching_range, + UniqueSubRange2 const& other_range) { if BOOST_GEOMETRY_CONSTEXPR (! VerifyPolicy::use_handle_as_touch) { @@ -354,6 +358,20 @@ struct touch_interior : public base_turn_handler } else // else prevents unreachable code warning { + bool const has_k = ! non_touching_range.is_last_segment() + && ! other_range.is_last_segment(); + if (has_k + && (same(side.pj_wrt_q1(), side.qj_wrt_p2()) + || same(side.pj_wrt_q2(), side.qj_wrt_p1()))) + { + // At a touch, the touching points (pj and qj) should be collinear + // with both other segments. + // If that is not the case (both left or both right), it should not be handled as a touch, + // (though the intersection point might be close to the end), + // because segments might cross each other or touch the other in the middle. + return false; + } + // // // ^ Q(i) ^ P(i) @@ -1461,7 +1479,7 @@ struct get_turn_info if ( inters.d_info().arrival[1] == 1 ) { // Q arrives - if (handler::handle_as_touch(inters.i_info(), range_p)) + if (handler::handle_as_touch(inters.i_info(), inters.sides(), range_p, range_q)) { handle_as_touch = true; } @@ -1475,7 +1493,7 @@ struct get_turn_info else { // P arrives, swap p/q - if (handler::handle_as_touch(inters.i_info(), range_q)) + if (handler::handle_as_touch(inters.i_info(), inters.swapped_sides(), range_q, range_p)) { handle_as_touch = true; } diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index d0a53ab9cd..8d391aa105 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -1580,6 +1580,20 @@ static std::string issue_1109[2] = "MULTIPOLYGON(((0 -88,0 -115.40000152587890625,-10 -88,0 -88)))" }; +static std::string issue_1222[2] = +{ + "MULTIPOLYGON(((2 4,2 2,0 2,0 4,2 4)),((6 4,4 4,2 4,2 6,0 6,0 10,6 10,6 4)))", + "MULTIPOLYGON(((4 4,4 2,2 2,2 4,4 4)),((4 8,4 6,2 6,2 8,4 8)))" +}; + +static std::string issue_1288[3] = +{ + // Issue with differences in behaviour for multi polygon vs polygon + "MULTIPOLYGON(((-2.0 -1.5, 2.0 -1.5, 2.0 1.5, -2.0 1.5)))", + "MULTIPOLYGON(((-0.5 -1.49999999, -2.0 -0.1, -1.99999999 -1.5)))", + "POLYGON((-0.5 -1.49999999, -2.0 -0.1, -1.99999999 -1.5))" +}; + static std::string bug_21155501[2] = { "MULTIPOLYGON(((-8.3935546875 27.449790329784214,4.9658203125 18.729501999072138,11.8212890625 23.563987128451217,9.7119140625 25.48295117535531,9.8876953125 31.728167146023935,8.3056640625 32.99023555965106,8.5693359375 37.16031654673677,-1.8896484375 35.60371874069731,-0.5712890625 32.02670629333614,-8.9208984375 29.458731185355344,-8.3935546875 27.449790329784214)))", diff --git a/test/algorithms/set_operations/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index 8810f61b4e..cc9db5707c 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -211,6 +211,16 @@ void test_areal() TEST_DIFFERENCE(issue_900, 0, 0.0, 2, 35, 2); + TEST_DIFFERENCE(issue_1222, 2, 32.0, 1, 4.0, 1); + { + // "method: t; operations: c/c;" still happening in the result + // for multi/multi + ut_settings settings; + settings.set_test_validity(BG_IF_TEST_FAILURES); + settings.validity_of_sym = BG_IF_TEST_FAILURES; + TEST_DIFFERENCE_WITH(0, 1, issue_1288, 2, 10.95, 0, 0.0, 2); + } + // Areas and #clips correspond with POSTGIS (except sym case) test_one("case_101_multi", case_101_multi[0], case_101_multi[1], diff --git a/test/algorithms/set_operations/intersection/intersection_multi.cpp b/test/algorithms/set_operations/intersection/intersection_multi.cpp index 37ef6c4a20..733a9d9e7e 100644 --- a/test/algorithms/set_operations/intersection/intersection_multi.cpp +++ b/test/algorithms/set_operations/intersection/intersection_multi.cpp @@ -362,6 +362,9 @@ void test_areal() TEST_INTERSECTION(issue_888_34, 7, -1, 0.0256838); TEST_INTERSECTION(issue_888_37, 13, -1, 0.0567043); + TEST_INTERSECTION(issue_1222, 1, -1, 4.0); + TEST_INTERSECTION(issue_1288, 1, -1, 1.05); + TEST_INTERSECTION(mysql_23023665_7, 2, 11, 9.80505786783); TEST_INTERSECTION(mysql_23023665_12, 2, 0, 11.812440191387557); TEST_INTERSECTION(mysql_regression_1_65_2017_08_31, 2, -1, 29.9022122); diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index d325a87401..792aa4e417 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -437,6 +437,9 @@ void test_areal() TEST_UNION(issue_1109, 2, 0, -1, 3946.5); + TEST_UNION(issue_1222, 1, 0, -1, 40.0); + TEST_UNION(issue_1288, 1, 0, -1, 12.0); + // One or two polygons, the ideal case is 1 TEST_UNION(mail_2019_01_21_johan, count_set(1, 2), 0, -1, 0.00058896); From e13d5d6b2fa42290d7b93e4a5cc6d0a9e2329e6e Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 24 Nov 2024 12:54:42 +0100 Subject: [PATCH 5/6] fix: avoid blocking rings for some non union conditions Fixes #893 Fixes #1299 --- .../algorithms/detail/overlay/overlay.hpp | 33 +++++++++++-------- .../overlay/multi_overlay_cases.hpp | 6 ++++ test/algorithms/overlay/overlay_cases.hpp | 6 ++++ .../set_operations/difference/difference.cpp | 8 +++++ .../difference/difference_multi.cpp | 16 ++------- .../intersection/intersection.cpp | 2 ++ .../intersection/intersection_multi.cpp | 2 ++ .../algorithms/set_operations/union/union.cpp | 3 ++ .../set_operations/union/union_multi.cpp | 2 ++ 9 files changed, 51 insertions(+), 27 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index 1d950306ac..6ce28be735 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -102,38 +102,42 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C = target_operation == operation_union ? operation_intersection : operation_union; + static const bool is_union = target_operation == operation_union; for (auto const& turn : turns) { bool cluster_checked = false; bool has_blocked = false; - if (is_self_turn(turn) && turn.discarded) + if (turn.discarded && (turn.method == method_start || is_self_turn(turn))) { - // Discarded self-turns don't count as traversed + // Discarded self-turns or start turns don't need to block the ring continue; } - for (auto const& op : turn.operations) + for (int i = 0; i < 2; i++) { + auto const& op = turn.operations[i]; + auto const& other_op = turn.operations[1 - i]; ring_identifier const ring_id = ring_id_by_seg_id(op.seg_id); - if (! is_self_turn(turn) - && ( - (BOOST_GEOMETRY_CONDITION(target_operation == operation_union) - && op.enriched.count_left > 0) - || (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection) - && op.enriched.count_right <= 2))) + // If the turn (one of its operations) is used during traversal, + // and it is an intersection or difference, it cannot be set to blocked. + // This is a rare case, related to floating point precision, + // and can happen if there is, for example, only one start turn which is + // used to traverse through one of the rings (the other should be marked + // as not traversed, but neither blocked). + bool const can_block + = is_union + || ! (op.visited.finalized() || other_op.visited.finalized()); + + if (! is_self_turn(turn) && can_block) { - // Avoid including untraversed rings which have polygons on - // their left side (union) or not two on their right side (int) - // This can only be done for non-self-turns because of count - // information turn_info_map[ring_id].has_blocked_turn = true; continue; } - if (turn.any_blocked()) + if (is_union && turn.any_blocked()) { turn_info_map[ring_id].has_blocked_turn = true; } @@ -157,6 +161,7 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C // don't block (for union) i/u if there is an self-ii too if (has_blocked || (op.operation == opposite_operation + && can_block && ! turn.has_colocated_both && ! (turn.both(opposite_operation) && is_self_turn(turn)))) diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index 8d391aa105..fd0d80ad8f 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -1600,6 +1600,12 @@ static std::string bug_21155501[2] = "MULTIPOLYGON(((4.9658203125 18.729501999072138,-3.4868710311820115 24.246968623627644,8.3589904332912 33.833614418115445,8.3056640625 32.99023555965106,9.8876953125 31.728167146023935,9.7119140625 25.48295117535531,11.8212890625 23.563987128451217,4.9658203125 18.729501999072138)),((-3.88714525609152 24.508246314579743,-8.3935546875 27.449790329784214,-8.9208984375 29.458731185355344,-0.5712890625 32.02670629333614,-1.8896484375 35.60371874069731,8.5693359375 37.16031654673677,8.362166569827938 33.883846345901595,-3.88714525609152 24.508246314579743)))", }; +static std::string issue_1299[2] = +{ + "MULTIPOLYGON(((1.2549999979079400 0.85000000411847698, -1.2550000020920500 0.84999999897038103, -1.2549999999999999 -0.85000000102961903, 1.2549999999999999 -0.84999999999999998)))", + "MULTIPOLYGON(((-0.87500000000000000 -0.84999999999999998, -0.87500000000000000 -0.070000000000000201, -1.2549999999999999 -0.070000000000000201, -1.2549999999999999 -0.84999999999999998)))" +}; + static std::string mysql_21965285_b[2] = { "MULTIPOLYGON(((3 0, -19 -19, -7 3, -2 10, 15 0, 3 0)))", diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 6b54807313..7a896eca96 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -1077,6 +1077,12 @@ static std::string issue_876b[2] = "POLYGON((-71.6230763305201634 -132.587678014412745,-106.959839171856814 -102.936613347248112,-40.4477408440520776 -23.6705812141075285,-5.11097800271543878 -53.3216458812721612,-71.6230763305201634 -132.587678014412745))" }; +static std::string issue_893[2] = +{ + "POLYGON((-9133.3885344331684 3976.3162451998137, -6748.2449169873034 -5735.0734557728138, 12359.886942916415 -1042.0645095456412, 5126.3084924076147 2226.9708710750697, -1604.5619839035633 573.85084904357439, -9133.3885344331684 3976.3162451998137))", + "POLYGON((-3228.4265340177531 1307.7159344890201, -4500.2645033380131 1882.4913860267370, -4294.7752070657516 1045.8178117890784, -3228.4265340177531 1307.7159344890201))" +}; + static std::string issue_1076[2] = { "POLYGON((981.792858339935151 98, 927.152135631899114 0, 970 98, 981.792858339935151 98))", diff --git a/test/algorithms/set_operations/difference/difference.cpp b/test/algorithms/set_operations/difference/difference.cpp index d6112f9118..e89d48b115 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -611,6 +611,14 @@ void test_all() TEST_DIFFERENCE(issue_876a, 1, 4728.89916, 1, 786.29563, 2); TEST_DIFFERENCE(issue_876b, 1, 6114.18234, 1, 4754.29449, count_set(1, 2)); + { + // Results are still invalid + ut_settings settings; + settings.set_test_validity(false); + settings.validity_of_sym = false; + TEST_DIFFERENCE_WITH(issue_893, 1, 97213916.0, 0, 0.0, 1, settings); + } + TEST_DIFFERENCE(issue_1138, 1, 203161.751, 2, 1237551.0171, 1); { diff --git a/test/algorithms/set_operations/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index cc9db5707c..20be703b9e 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -152,19 +152,7 @@ void test_areal() TEST_DIFFERENCE_WITH(0, 1, ggl_list_20120221_volker, 2, 7962.66, 2, 2775258.93, 4); } - { - // 1: Very small sliver for B (discarded when rescaling) - // 2: sym difference is not considered as valid (without rescaling - // this is a false negative) - // 3: with rescaling A is considered as invalid (robustness problem) - ut_settings settings; - settings.validity_of_sym = true; - settings.validity_false_negative_sym = true; - TEST_DIFFERENCE_WITH(0, 1, bug_21155501, - (count_set(1, 4)), expectation_limits(3.75893, 3.75894), - (count_set(1, 4)), (expectation_limits(1.776357e-15, 7.661281e-15)), - (count_set(2, 5))); - } + TEST_DIFFERENCE(bug_21155501, 1, 3.758937, 1, 1.78e-15, 1); #if defined(BOOST_GEOMETRY_TEST_FAILURES) { @@ -410,6 +398,8 @@ void test_areal() TEST_DIFFERENCE(mysql_regression_1_65_2017_08_31, optional(), optional_sliver(1e-6), 3, 152.064185, count_set(3, 4)); + + TEST_DIFFERENCE(issue_1299, 1, 3.9706, 0, 0, 1); } diff --git a/test/algorithms/set_operations/intersection/intersection.cpp b/test/algorithms/set_operations/intersection/intersection.cpp index 2ce4956a86..07573ef4cc 100644 --- a/test/algorithms/set_operations/intersection/intersection.cpp +++ b/test/algorithms/set_operations/intersection/intersection.cpp @@ -301,6 +301,8 @@ void test_areal() TEST_INTERSECTION(issue_861, 1, -1, 1.4715007684573677693e-10); + TEST_INTERSECTION(issue_893, 1, -1, 473001.5082956461); + TEST_INTERSECTION(issue_1226, 1, -1, 0.00036722862); TEST_INTERSECTION(issue_1229, 0, -1, 0); diff --git a/test/algorithms/set_operations/intersection/intersection_multi.cpp b/test/algorithms/set_operations/intersection/intersection_multi.cpp index 733a9d9e7e..c74f4e4053 100644 --- a/test/algorithms/set_operations/intersection/intersection_multi.cpp +++ b/test/algorithms/set_operations/intersection/intersection_multi.cpp @@ -368,6 +368,8 @@ void test_areal() TEST_INTERSECTION(mysql_23023665_7, 2, 11, 9.80505786783); TEST_INTERSECTION(mysql_23023665_12, 2, 0, 11.812440191387557); TEST_INTERSECTION(mysql_regression_1_65_2017_08_31, 2, -1, 29.9022122); + + TEST_INTERSECTION(issue_1299, 1, -1, 0.2964); } template diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 2824016d2b..1cf4565c33 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -442,6 +442,9 @@ void test_areal() TEST_UNION(issue_838, 1, 0, -1, expectation_limits(1.3333, 1.33785)); TEST_UNION_REV(issue_838, 1, 0, -1, expectation_limits(1.3333, 1.33785)); + TEST_UNION(issue_893, 1, 0, -1, 97686917.29298662); + TEST_UNION_REV(issue_893, 1, 0, -1, 97686917.29298662); + TEST_UNION(issue_1076, 1, 0, -1, 1225.0); TEST_UNION_REV(issue_1076, 1, 0, -1, 1225.0); diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index 792aa4e417..020650a747 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -451,6 +451,8 @@ void test_areal() 1, 9, -1, 1250.0); TEST_UNION(mysql_regression_1_65_2017_08_31, 3, 0, -1, 181.966397646608); + + TEST_UNION(issue_1299, 1, 0, -1, 4.267); } // Test cases (generic) From b3d35b341ae7a76e8cdb3eac2a13b09d612c5419 Mon Sep 17 00:00:00 2001 From: Vissarion Fisikopoulos Date: Wed, 30 Oct 2024 13:56:40 +0200 Subject: [PATCH 6/6] test: Remove extensions dependency from tests --- .../recursive_polygons_linear_areal.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/test/robustness/overlay/linear_areal/recursive_polygons_linear_areal.cpp b/test/robustness/overlay/linear_areal/recursive_polygons_linear_areal.cpp index 83ee49f7f1..88846eb08f 100644 --- a/test/robustness/overlay/linear_areal/recursive_polygons_linear_areal.cpp +++ b/test/robustness/overlay/linear_areal/recursive_polygons_linear_areal.cpp @@ -28,7 +28,7 @@ #include #include -#include +//#include #include #include @@ -213,14 +213,9 @@ public : bg::convert(segment, seg2); bg::strategy::intersection::cartesian_segments<> strategy; - bg::policies::relate::segments_intersection_points - < - bg::segment_intersection_points - > policy; - bg::detail::segment_as_subrange subrange1(seg1); bg::detail::segment_as_subrange subrange2(seg2); - bg::segment_intersection_points is + bg::segment_intersection_points is = strategy.apply(subrange1, subrange2, policy_t()); if (is.count == 2) @@ -307,6 +302,7 @@ bool verify(std::string const& caseid, MultiPolygon const& mp, Linestring const& border_check bc(mp, result); bg::for_each_segment(difference, bc); + /* commented out since it needs extensions, tests are passing without that part // 3) check also the mid-points from the difference to remove false positives for (Linestring const& d : difference) { @@ -315,11 +311,11 @@ bool verify(std::string const& caseid, MultiPolygon const& mp, Linestring const& outside_check ocm(mp, result); bg::for_each_point(difference_midpoints, ocm); } - + */ if (settings.verbose) { - std::cout << " [" << bg::area(mp) << " " << bg::length(ls) << - " " << bg::length(intersection) << + std::cout << " [" << bg::area(mp) << " " << bg::length(ls) << + " " << bg::length(intersection) << " " << bg::length(difference) << "]"; }