From a67a7aeaa6fc8f501851fb921e176828b9eb8ef3 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 16 Nov 2022 13:09:14 +0100 Subject: [PATCH] [overlay] fix cluster by adapting tolerance Fixes #1081 --- doc/release_notes.qbk | 1 + .../detail/overlay/get_clusters.hpp | 17 ++++++++++---- .../buffer/buffer_multi_polygon.cpp | 4 ++++ test/algorithms/overlay/get_clusters.cpp | 23 +++++++++++++++---- test/algorithms/overlay/overlay_cases.hpp | 18 +++++++++++++++ .../set_operations/difference/difference.cpp | 5 ++-- .../algorithms/set_operations/union/union.cpp | 9 ++++++++ 7 files changed, 66 insertions(+), 11 deletions(-) diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 3207c94e93..3af28cb56e 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -26,6 +26,7 @@ [*Solved issues] * [@https://github.com/boostorg/geometry/issues/1076 1076] Union: in rare cases it might miss one polygon +* [@https://github.com/boostorg/geometry/issues/1081 1081] Union: due to precision it might miss interior rings [/=================] [heading Boost 1.80] diff --git a/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp b/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp index bb6077ad8c..9e2627f367 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_clusters.hpp @@ -35,20 +35,29 @@ namespace detail { namespace overlay template struct sweep_equal_policy { +private: + template + static inline T threshold() + { + // Tuned by cases of #1081. It should just be one epsilon to distinguish between + // different turn-points and real colocated clusters. + return T(1); + } +public: + // Returns true if point are considered equal (within an epsilon) template static inline bool equals(P const& p1, P const& p2) { - // Points within a kilo epsilon are considered as equal using coor_t = typename coordinate_type

::type; - return approximately_equals(p1, p2, coor_t(1000)); + return approximately_equals(p1, p2, threshold()); } template static inline bool exceeds(T value) { // This threshold is an arbitrary value - // as long as it is than the used kilo-epsilon - T const limit = T(1) / T(1000); + // as long as it is bigger than the used value above + T const limit = T(1) / threshold(); return value > limit; } }; diff --git a/test/algorithms/buffer/buffer_multi_polygon.cpp b/test/algorithms/buffer/buffer_multi_polygon.cpp index 1de1f7e532..1ce3c9e8bd 100644 --- a/test/algorithms/buffer/buffer_multi_polygon.cpp +++ b/test/algorithms/buffer/buffer_multi_polygon.cpp @@ -631,7 +631,11 @@ void test_all() test_one("nores_6061", nores_6061, join_round32, end_flat, 39.7371, 1.0); test_one("nores_37f6", nores_37f6, join_round32, end_flat, 26.5339, 1.0); +#if defined(BOOST_GEOMETRY_USE_RESCALING) || defined(BOOST_GEOMETRY_TEST_FAILURES) + // Fails since get_cluster works with an epsilon of 1 (instead of 1000 before). + // With 3 it still succeeds but that causes regression in issue #issue_1081b test_one("nores_1ea1", nores_1ea1, join_round32, end_flat, 28.9755, 1.0); +#endif test_one("nores_804e", nores_804e, join_round32, end_flat, 26.4503, 1.0); test_one("nores_51c6", nores_51c6, join_round32, end_flat, 20.2419, 1.0); test_one("nores_e5f3", nores_e5f3, join_round32, end_flat, 14.5503, 1.0); diff --git a/test/algorithms/overlay/get_clusters.cpp b/test/algorithms/overlay/get_clusters.cpp index f7b8a535d7..7cb275f11f 100644 --- a/test/algorithms/overlay/get_clusters.cpp +++ b/test/algorithms/overlay/get_clusters.cpp @@ -68,7 +68,7 @@ void do_test(std::string const& case_id, } template -void test_get_clusters(typename bg::coordinate_type::type eps) +void test_get_clusters() { do_test("no", {{1.0, 1.0}, {1.0, 2.0}}, 0); do_test("simplex", {{1.0, 1.0}, {1.0, 1.0}}, 1); @@ -80,8 +80,11 @@ void test_get_clusters(typename bg::coordinate_type::type eps) 6); do_test("buffer3", {{6.41421356237, 5},{6.41421356236, 5},{6.70710678119, 5.29289321881},{6.41421356237, 5},{6, 5},{6.41421356238, 5},{7, 5},{8, 10},{8.41421356237, 10},{8, 9.58578643763},{8.41421356237, 10},{7.41421356237, 9},{7.41421356237, 9},{7, 5.58578643763},{7, 5.58578643763},{6, 5},{6, 5},{6, 5},{6, 5},{6, 5},{6, 6},{4, 6},{4, 6},{3.41421356237, 3},{3, 5},{6, 5},{5, 3},{4, 6},{4, 6},{4, 7},{4, 8},{10.9142135624, 5.5},{8, 5},{10.4142135624, 5},{8, 5},{8, 3.58578643763},{8, 5},{9.41421356237, 7},{9.41421356237, 7},{8.91421356237, 7.5},{10, 7},{8, 9},{7.41421356237, 9},{11, 7}}, 8); +} - // Border cases +template +void test_get_clusters_border_cases(typename bg::coordinate_type::type eps) +{ do_test("borderx_no", {{1, 1}, {1, 2}, {1 + eps * 10, 1}}, 0); do_test("borderx_yes", {{1, 1}, {1, 2}, {1 + eps, 1}}, 1); do_test("bordery_no", {{1, 1}, {2, 1}, {1 + eps * 10, 1}}, 0); @@ -93,8 +96,18 @@ int test_main(int, char* []) using fp = bg::model::point; using dp = bg::model::point; using ep = bg::model::point; - test_get_clusters(1.0e-4); - test_get_clusters(1.0e-13); - test_get_clusters(1.0e-16); + + test_get_clusters(); + test_get_clusters(); + test_get_clusters(); + + // This constant relates to the threshold in get_clusters, + // which is now return T(1) (earlier it was 1000) + double const multiplier = 1.0 / 1000.0; + + test_get_clusters_border_cases(1.0e-4 * multiplier); + test_get_clusters_border_cases(1.0e-13 * multiplier); + test_get_clusters_border_cases(1.0e-16 * multiplier); + return 0; } diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 68ffd77459..fc77f93e5b 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -1083,6 +1083,24 @@ static std::string issue_1076[2] = "POLYGON((927.152135631899114 0, 981.792858339935151 98, 995 98, 927.152135631899114 0))" }; +static std::string issue_1081a[2] = +{ + "POLYGON((40 100,50 200,75 160,60 160,75 140,40 100),(46.317137830014417 152.14683289288962,59.9312673826029823 167.24190656486104,59.9312673826029823 173.678978034969646,60 175,46.317137830014417 152.14683289288962))", + "POLYGON((65 170,67 140,65 163,56.7651907424660749 163.715020193369355,59.9312673826029823 167.241906564861154,65 170))" +}; + +static std::string issue_1081b[2] = +{ + "POLYGON((21907 0,21917 100,21942 60,21927 60,21942 40,21907 0),(21913.317137830014 52.1468328928896199,21926.9312673826025 67.2419065648610399,21926.9312673826025 73.6789780349696457,21927 75,21913.317137830014 52.1468328928896199))", + "POLYGON((21932 70,21934 40,21932 63,21923.7651907424661 63.7150201933693552,21926.9312673826025 67.2419065648611536,21932 70))" +}; + +static std::string issue_1081c[2] = +{ + "POLYGON((411.083582272653246 134.162757591540753,421.316381618511855 93.3919511307571781,414.749514308625294 94.5205547695399702,414.40388971336813 96.7777620478938587,306.396203695496922 49.799635572622492,411.083582272653246 134.162757591540753),(409.910769975024664 99.8814220555319139,412.848579034710724 101.010025694314677,408.182646998738733 118.926608464425712,409.910769975024664 99.8814220555319139))", + "POLYGON((423.217316892426425 67.5751428875900331,414.40388971336813 96.7777620478938587,410.429206867910466 100.02249750988706,412.848579034710781 101.010025694314706,412.502954439453561 102.98508206238165,416.996074177797027 109.05132662251431,427.364812035512671 72.6538592632950468,423.217316892426425 67.5751428875900331))" +}; + 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 4f36f8fca5..fb38427199 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -67,8 +67,9 @@ void test_all() 1, 5, 8.0); { + // Sym difference works, but expectations are different for rescaling ut_settings settings; - settings.validity_false_negative_sym = true; + settings.sym_difference = false; test_one("star_comb_15", star_comb_15[0], star_comb_15[1], 30, -1, 227.658275102812, @@ -597,7 +598,7 @@ void test_all() { ut_settings settings; settings.validity_false_negative_sym = true; - TEST_DIFFERENCE_WITH(mysql_23023665_13, 3, 99.74526, 3, 37.74526, 6, settings); + TEST_DIFFERENCE_WITH(mysql_23023665_13, 3, 99.74526, 3, 37.74526, count_set(5, 6), settings); } } diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 5d246b5a9c..736b41bf03 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -447,6 +447,15 @@ void test_areal() TEST_UNION(issue_1076, 1, 0, -1, 1225.0); TEST_UNION_REV(issue_1076, 1, 0, -1, 1225.0); + TEST_UNION(issue_1081a, 1, 2, -1, 1600.56); + TEST_UNION_REV(issue_1081a, 1, 2, -1, 1600.56); + + TEST_UNION(issue_1081b, 1, 2, -1, 1600.56); + TEST_UNION_REV(issue_1081b, 1, 2, -1, 1600.56); + + TEST_UNION(issue_1081c, 1, 1, -1, 2338.08); + TEST_UNION_REV(issue_1081c, 1, 1, -1, 2338.08); + { // Rescaling produces an invalid result ut_settings settings;