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 c81bc87c4..e61ad7286 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 d0a53ab9c..8d391aa10 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 8810f61b4..cc9db5707 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 37ef6c4a2..733a9d9e7 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 d325a8740..792aa4e41 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);