diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index f7b0ed28e..f39b70ed5 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -34,12 +34,15 @@ [*Solved tickets] * [@https://svn.boost.org/trac/boost/ticket/10866 10866] union_ doesn't work in 1.56 and 1.57. +* [@https://svn.boost.org/trac/boost/ticket/11018 11018] Invalid geometry intersection * [@https://svn.boost.org/trac/boost/ticket/11576 11576] Intersection gives wrong results. * [@https://svn.boost.org/trac/boost/ticket/11637 11637] Unused parameter warning. +* [@https://svn.boost.org/trac/boost/ticket/11725 11725] union_ fails to create holes +* [@https://svn.boost.org/trac/boost/ticket/11789 11789] Assertion failure or invalid result of set operations for spherical_equatorial coordinate system. * [@https://svn.boost.org/trac/boost/ticket/11917 11917] Andoyer distance strategy returns 0 for antipodal points (default geographic distance). * [@https://svn.boost.org/trac/boost/ticket/11928 11928] Improvement of the accuracy of surveyor area strategy. * [@https://svn.boost.org/trac/boost/ticket/11966 11966] Compilation error in svg() for box and non-int coordinate type. -* [@https://svn.boost.org/trac/boost/ticket/11789 11789] Assertion failure or invalid result of set operations for spherical_equatorial coordinate system. +* [@https://svn.boost.org/trac/boost/ticket/11984 11984] union_() generates self-intersecting polygon * [@https://svn.boost.org/trac/boost/ticket/11987 11987] rtree::remove() not compiling for geographic CS. * [@https://svn.boost.org/trac/boost/ticket/12000 12000] Uninitialized reference in (unused) constructor of relate's mask_handler. diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index ebf74c5ef..a8f423212 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -93,7 +93,8 @@ template typename Turns, typename Clusters, typename RobustPolicy, - typename Visitor + typename Visitor, + typename Backtrack > struct traversal { @@ -117,6 +118,9 @@ struct traversal , m_clusters(clusters) , m_robust_policy(robust_policy) , m_visitor(visitor) + , m_has_uu(false) + , m_has_only_uu(true) + , m_switch_at_uu(true) {} @@ -147,7 +151,10 @@ struct traversal : seg_id1.multi_index == seg_id2.multi_index; } - return turn.switch_source + // Temporarily use m_switch_at_uu, which does not solve all cases, + // but the majority of the more simple cases, making the interior + // rings valid + return m_switch_at_uu // turn.switch_source ? seg_id1.source_index != seg_id2.source_index : seg_id1.source_index == seg_id2.source_index; } @@ -671,6 +678,115 @@ struct traversal return traverse_error_endless_loop; } + template + void traverse_with_operation(turn_type const& start_turn, + std::size_t turn_index, int op_index, + Rings& rings, std::size_t& finalized_ring_size, + typename Backtrack::state_type& state) + { + typedef typename boost::range_value::type ring_type; + + turn_operation_type const& start_op = start_turn.operations[op_index]; + + if (! start_op.visited.none() + || ! start_op.enriched.startable + || start_op.visited.rejected() + || ! (start_op.operation == OperationType + || start_op.operation == detail::overlay::operation_continue)) + { + return; + } + + ring_type ring; + traverse_error_type traverse_error = traverse(ring, turn_index, op_index); + + if (traverse_error == traverse_error_none) + { + std::size_t const min_num_points + = core_detail::closure::minimum_ring_size + < + geometry::closure::value + >::value; + + if (geometry::num_points(ring) >= min_num_points) + { + clean_closing_dups_and_spikes(ring, m_robust_policy); + rings.push_back(ring); + + finalize_visit_info(); + finalized_ring_size++; + } + } + else + { + Backtrack::apply( + finalized_ring_size, + rings, ring, m_turns, start_turn, + m_turns[turn_index].operations[op_index], + traverse_error, + m_geometry1, m_geometry2, m_robust_policy, + state, m_visitor); + } + } + + template + void iterate(Rings& rings, std::size_t& finalized_ring_size, + typename Backtrack::state_type& state, + int pass) + { + if (pass == 1) + { + if (OperationType == operation_intersection) + { + // Second pass currently only used for uu + return; + } + if (! m_has_uu) + { + // There is no uu found in first pass + return; + } + if (m_has_only_uu) + { + m_switch_at_uu = false; + } + } + + // Iterate through all unvisited points + for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) + { + turn_type const& start_turn = m_turns[turn_index]; + + if (start_turn.discarded || start_turn.blocked()) + { + // Skip discarded and blocked turns + continue; + } + if (OperationType == operation_union) + { + if (start_turn.both(operation_union)) + { + // Start with a uu-turn only in the second pass + m_has_uu = true; + if (pass == 0) + { + continue; + } + } + else + { + m_has_only_uu = false; + } + } + + for (int op_index = 0; op_index < 2; op_index++) + { + traverse_with_operation(start_turn, turn_index, op_index, + rings, finalized_ring_size, state); + } + } + } + private : Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; @@ -678,8 +794,12 @@ private : Clusters const& m_clusters; RobustPolicy const& m_robust_policy; Visitor& m_visitor; -}; + // Next members are only used for operation union + bool m_has_uu; + bool m_has_only_uu; + bool m_switch_at_uu; +}; /*! @@ -691,7 +811,7 @@ template bool Reverse1, bool Reverse2, typename Geometry1, typename Geometry2, - operation_type OpType, + operation_type OperationType, typename Backtrack = backtrack_check_self_intersections > class traverse @@ -712,79 +832,23 @@ public : Clusters const& clusters, Visitor& visitor) { - typedef typename boost::range_value::type ring_type; - typedef typename boost::range_value::type turn_type; - typedef typename turn_type::turn_operation_type op_type; - traversal < - Reverse1, Reverse2, OpType, + Reverse1, Reverse2, OperationType, Geometry1, Geometry2, Turns, Clusters, - RobustPolicy, Visitor + RobustPolicy, Visitor, + Backtrack > trav(geometry1, geometry2, turns, clusters, robust_policy, visitor); - std::size_t const min_num_points - = core_detail::closure::minimum_ring_size - < - geometry::closure::value - >::value; - std::size_t finalized_ring_size = boost::size(rings); typename Backtrack::state_type state; - // Iterate through all unvisited points - for (std::size_t turn_index = 0; turn_index < turns.size(); ++turn_index) + for (int pass = 0; pass < 2; pass++) { - turn_type const& start_turn = turns[turn_index]; - - // Skip discarded ones - if (start_turn.discarded - || start_turn.blocked()) - { - continue; - } - - for (int op_index = 0; op_index < 2; op_index++) - { - op_type const& start_op = start_turn.operations[op_index]; - - if (! start_op.visited.none() - || ! start_op.enriched.startable - || start_op.visited.rejected() - || ! (start_op.operation == OpType - || start_op.operation == detail::overlay::operation_continue)) - { - continue; - } - - ring_type ring; - traverse_error_type traverse_error = trav.traverse(ring, - turn_index, op_index); - - if (traverse_error == traverse_error_none) - { - if (geometry::num_points(ring) >= min_num_points) - { - clean_closing_dups_and_spikes(ring, robust_policy); - rings.push_back(ring); - - trav.finalize_visit_info(); - finalized_ring_size++; - } - } - else - { - Backtrack::apply( - finalized_ring_size, - rings, ring, turns, start_turn, - turns[turn_index].operations[op_index], - traverse_error, - geometry1, geometry2, robust_policy, state, visitor); - } - } + trav.iterate(rings, finalized_ring_size, state, pass); } } }; diff --git a/test/algorithms/buffer/buffer_polygon.cpp b/test/algorithms/buffer/buffer_polygon.cpp index 1a257480e..ff67ebbfc 100644 --- a/test/algorithms/buffer/buffer_polygon.cpp +++ b/test/algorithms/buffer/buffer_polygon.cpp @@ -129,6 +129,9 @@ static std::string const ticket_10398_4 static std::string const ticket_10412 = "POLYGON((897747.8 6270564.3,897764.3 6270569.7,897776.5 6270529.5,897768.1 6270527.1,897767.6 6270529.4,897756.3 6270525.8,897745.8 6270522.3,897752 6270502.9,897749.7 6270502,897750.7 6270499.1,897751.8 6270498.6,897752.3 6270499.3,897754.6 6270497.9,897755.8 6270500.2,897766.8 6270494.1,897765.6 6270491.5,897768.3 6270490.5,897770.9 6270491.5,897770.2 6270494.6,897780.1 6270497.5,897781 6270494.6,897786.8 6270496.6,897790.8 6270482.5,897785.3 6270480.7,897785.9 6270478.2,897768.9 6270473.2,897768.1 6270475.8,897766.1 6270475.2,897758.7 6270479.2,897753.2 6270481.8,897751.9 6270479,897746.5 6270481.9,897748 6270484.6,897745.2 6270486.1,897743.9 6270483.3,897741.4 6270484.7,897742.6 6270487.3,897739.4 6270488.9,897738.3 6270486.3,897735.6 6270487.8,897733.1 6270496.8,897731.2 6270502.7,897732.4 6270503.2,897731.5 6270506.1,897730.3 6270505.7,897725.8 6270520.2,897726.8 6270520.7,897726 6270523,897728 6270523.7,897726.3 6270529.6,897742.8 6270534.5,897741.2 6270539.9,897751.4 6270543.4,897750.7 6270546.4,897753.2 6270547.2,897747.8 6270564.3))"; +static std::string const ticket_11580 + = "POLYGON((14.02 474.96,14.02 494.96,14.022 494.96,14.022 486.24,14.02 474.96))"; + // CCW Polygons not working in 1.56 static std::string const mysql_report_2014_10_24 = "POLYGON((0 0, 0 8, 8 8, 8 10, -10 10, -10 0, 0 0))"; @@ -518,6 +521,11 @@ void test_all() test_one("ticket_10398_4_91", ticket_10398_4, join_miter, end_flat, 819.1406, 9.1, -999, false); test_one("ticket_10412", ticket_10412, join_miter, end_flat, 3109.6616, 1.5, -999, false); + test_one("ticket_11580_100", ticket_11580, join_miter, end_flat, 52.0221000, 1.00, -999, false); +#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS + // Larger distance, resulting in only one circle + test_one("ticket_11580_237", ticket_11580, join_miter, end_flat, 999.999, 2.37, -999, false); +#endif // Tickets - deflated test_one("ticket_10398_1_5", ticket_10398_1, join_miter, end_flat, 404.3936, -0.5); diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index c4ee6be4b..382da538a 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -388,6 +388,18 @@ static std::string case_108_multi[3] = "MULTIPOLYGON(((0 3,0 4,1 4,0 3)),((3 6,3 5,5 5,5 1, 1 1,1 2,2 3,2 4,2.5 3.5,3 4,4 3,3 3,3 2,4 2,4 4,2 4,1 3,1 5,2 6,3 6)),((1 3,1 2,0 2,0 3,1 3)))" }; +static std::string case_109_multi[2] = + { + "MULTIPOLYGON(((0 0,0 40,40 40,40 0,0 0),(10 10,30 10,30 30,10 30,10 10)))", + "MULTIPOLYGON(((10 10,10 20,20 10,10 10)),((20 10,30 20,30 10,20 10)),((10 20,10 30,20 20,10 20)),((20 20,30 30,30 20,20 20)))" + }; + +static std::string case_110_multi[2] = + { + "MULTIPOLYGON(((0 0,0 40,40 40,40 0,0 0),(10 10,30 10,30 30,10 30,10 10)))", + "MULTIPOLYGON(((15 10,10 15,10 17,15 10)),((15 10,10 20,10 22,15 10)),((15 10,10 25,10 27,15 10)),((25 10,30 17,30 15,25 10)),((25 10,30 22,30 20,25 10)),((25 10,30 27,30 25,25 10)),((18 10,20 30,19 10,18 10)),((21 10,20 30,22 10,21 10)))" + }; + static std::string case_recursive_boxes_1[2] = { // == 70 @@ -753,6 +765,13 @@ static std::string ticket_10803[2] = "MULTIPOLYGON(((1374 1092,1734 1092,3174 2526,3174 2886,1374 2886,1374 1092)))" }; +// Intersection was reported as invalid +static std::string ticket_11018[2] = + { + "MULTIPOLYGON(((66.32861177 -32.36106001,66.32805654 -32.36294657,66.32805697 -32.36294666,66.2558847 -32.60687137,66.18259719 -32.85172659,66.18259756 -32.85172667,66.10923256 -33.09561483,66.10923294 -33.09561491,66.03574675 -33.34044236,65.96214887 -33.58529255,65.96214918 -33.58529261,65.94391227 -33.64484979,65.839119 -33.032507,66.32861177 -32.36106001)),((67.77272059 -31.62519092,67.77272315 -31.62518165,67.77272398 -31.62517863,67.84057793 -31.37975346,67.90737994 -31.13429944,67.92189506 -31.0817063,68.151987 -31.013051,69.236142 -30.678138,70.320296 -31.013051,71.411955 -31.338781,72.016906 -32.187175,72.633163 -33.032507,72.464921 -34.015608,72.292755 -34.998316,71.385165 -35.656005,70.46265 -36.306671,69.236142 -36.312964,68.009631 -36.306671,67.087119 -35.656005,66.69381557 -35.37099587,66.7156576 -35.29873723,66.78843343 -35.05443368,66.86117133 -34.80910208,66.86117388 -34.80909338,66.86117494 -34.8090898,66.93281945 -34.5647568,67.00441882 -34.31942369,67.00441834 -34.31942359,67.07592335 -34.07510168,67.14737287 -33.83073849,67.21777858 -33.58537517,67.28811831 -33.34001123,67.35838201 -33.09560549,67.42858934 -32.85025274,67.49773049 -32.6058299,67.56682212 -32.36043528,67.63585135 -32.11504002,67.63585413 -32.11503015,67.63585478 -32.1150278,67.70382724 -31.86961401,67.77272059 -31.62519092)))", + "MULTIPOLYGON(((67.840578 -31.37975347,67.77272059 -31.62519092,66.61484414 -31.38427789,66.68556685 -31.13932219,67.840578 -31.37975347)))", + }; + // Integer, ccw, open static std::string ticket_11674[2] = { @@ -760,6 +779,14 @@ static std::string ticket_11674[2] = "MULTIPOLYGON(((528 3218,528 2498,1734 1406,2556 1522,1734 1784,528 3218)),((4610 2288,5340 1178,5340 1832,4609 2289,4140 3002,2934 1574,2555 1521,2934 1400,4140 2582,4610 2288)))", }; +// Union was reported as invalid because of no generated interior rings, fixed +static std::string ticket_11984[2] = + { + "MULTIPOLYGON(((-104.025 72.5541,-95 67,-94 64,-95 60,-81.5804 61.9881,-75 52,-73.1862 50.0729,-75 48,-69.2 42.6,-96 56,-102 51,-119 49,-128 41,-126 33,-99 29,-61.9276 35.8291,-46 21,-30 10,-45 8,-104 6,-119 -8,-89 -18,-29 -10,-20 -9,-16 -11,-15 -13,-27 -29,-9 -13,-7 -14,-13.4737 -33.4211,-21 -34,-25 -36,-30 -40,-40 -49,-35 -50,-30 -51,-27 -53,-21 -52,-20.037 -52.642,-31.5314 -70.8413,-37.9815 -75.2274,-52.1689 -78.5148,-55 -78,-55 -79,-55 -79.1707,-112.692 -92.5385,-120 -94,-90.9143 -94.9695,-91 -95,-90 -99.5,-90 -103,-95 -114,-93 -116,-92 -117,-90 -119,-87.28 -119.68,-87 -120,-86.4444 -119.889,-82 -121,-80.821 -119.728,-77.6667 -119,-73 -119,-55 -114,-54 -114,-47 -114,-40 -121,-39.9327 -120.951,-39.3478 -121.609,-39 -123,-35.2182 -118.927,-24.536 -110.248,-22.875 -109.292,-22 -109,-22 -109,-16 -107,-9 -105,-7.83333 -104.833,-1.33333 -104.333,0.962934 -105.481,11.9682 -122.413,13 -129,20.1579 -120.053,22 -119,29.5 -115.25,30.2903 -114.968,39 -114,48 -112,47.156 -108.962,61 -117,54.9172 -103.176,65 -107,51.482 -95.3683,50.2426 -92.5515,53 -92,51.806 -91.0448,52 -91,49.1363 -88.9091,25.1429 -69.7143,22.733 -56.1314,24.9744 -49.3053,26.9174 -45.1157,27 -45,27.1481 -44.6543,33.4226 -34.0476,35.5919 -31.272,39 -29,39.4424 -26.3458,44.296 -20.136,46 -19,53 -14,53.3759 -13.4361,58.9297 -10.7874,115 13,110.286 13,114 14,112.414 14.7207,247.196 184.001,250 189,239.971 201.765,239 216,237.627 218.027,237.317 223.454,243 229)))", + "MULTIPOLYGON(((-31 6,-51 220,-84 241,-120 249,-146 224,-67 56,-74 52,-95 60,-38 10,-38 9)))", + }; + + 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/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index d8272fc0b..d27c4d0ae 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -380,6 +380,78 @@ static std::string case_83[2] = { "POLYGON((5 6,5 0,2 4,1 3,0 6,5 6))" }; + +// Cases for u/u touches creating interior rings (originally they were called 80-89. +// but in another branch - now renamed to 90-99) + +static std::string case_90[2] = + { + // union has one polygon with two holes; one of them is + // touching the exterior ring + // reported by MySQL QA on Aug 19, 2015 + "POLYGON((0 6,-11 -6,6 0,0 6),(3 1,5 0,-2 0,3 1))", + "POLYGON((5 4,6 0,9 12,-7 -12,5 -19,5 4))" + }; + +static std::string case_91[2] = + { + // union has a polygon with one hole touching the exterior ring + "POLYGON((0 0,10 10,20 0,0 0))", + "POLYGON((10 5,30 10,20 0,20 5,10 5))" + }; + +static std::string case_92[2] = + { + "POLYGON((0 0,10 10,20 0,0 0))", + "POLYGON((10 10,30 10,20 0,20 5,10 10))" + }; + +static std::string case_93[2] = + { + // union as a single polygon and two holes both touching the + // exterior ring at vertices + "POLYGON((0 0,10 10,20 0,0 0))", + "POLYGON((10 5,20 7,10 10,30 10,20 0,20 5,10 5))" + }; + +static std::string case_94[2] = + { + "POLYGON((0 0,10 10,20 0,0 0))", + "POLYGON((15 5,20 7,10 10,30 10,20 0,20 5,15 5))" + }; + +static std::string case_95[2] = + { + // union has a single polygon and two holes that touch each + // other at a vertex + "POLYGON((0 0,0 40,40 40,40 0,0 0),(10 10,30 10,30 30,10 30,10 10))", + "POLYGON((5 15,5 30,30 15,5 15))" + }; + +static std::string case_96[2] = + { + "POLYGON((0 0,0 40,40 40,40 0,20 0,0 0),(10 10,20 0,30 10,30 30,10 30,10 10))", + "POLYGON((10 10,10 30,30 30,30 10,10 10))" + }; + +static std::string case_97[2] = + { + "POLYGON((0 5,-6 -17,12 17,0 5),(4 6,5 5,0 1,4 6))", + "POLYGON((3 9,-15 -5,13 -11,3 9))" + }; + +static std::string case_98[2] = + { + "POLYGON((5 6,-15 -13,1 -8,5 6))", + "POLYGON((0 8,-19 6,18 -17,20 8,11 17,0 8),(3 2,3 -1,1 0,3 2),(1 3,4 4,0 -1,1 3))" + }; + +static std::string case_99[2] = + { + "POLYGON((0 0,0 40,40 40,40 0,0 0),(10 10,20 19,20 20,10 10),(20 20,30 30,20 21,20 20))", + "POLYGON((10 10,10 30,30 30,30 10,10 10))" + }; + static std::string case_many_situations[2] = { "POLYGON((2 6,2 14,10 18,18 14,18 6,16 5,14 4,12 3,10 2,8 3,6 4,4 5,2 6))", "POLYGON((2 6,2 7,2 8,2 9,2 10,2 11,2 12,1 14" @@ -879,6 +951,12 @@ static std::string ticket_10835[3] = "POLYGON((5233 2986,5200 3078,1020 3078,1020 2895,5200 2895))" }; +static std::string ticket_10866[2] = + { + "POLYGON((8126 3.18455e+07,8127 3.18455e+07,8129 3.18455e+07,8130 3.18455e+07,8130 -146305,8129 -146306,8127 -146306,8126 -146305,8126 3.18455e+07))", + "POLYGON((5.12064e+07 -146302,5.12064e+07 -146303,5.12064e+07 -146305,5.12064e+07 -146306,8127 -146306,8126 -146305,8126 -146303,8127 -146302,5.12064e+07 -146302))" + }; + static std::string ticket_10868[2] = { "POLYGON((42817136 -3774506,43029074 -3929862,31446819 18947953,30772384 19615678,30101303 19612322,30114725 16928001,33520458 6878575,35332375 2413654,35725796 2024148))", @@ -892,18 +970,18 @@ static std::string ticket_11121[2] = }; +static std::string ticket_11576[2] = + { + "POLYGON((-0 0,0.0030892383152813277 0,0.0017033357506405240 0.0015364430953530355,-0 0))", + "POLYGON((0.0016845031281539609 0.0015194556912103366,0.00079878052059454633 0.00072051609032968962,0.0023117731015916947 0.00082400923980274917,0.0016845031281539609 0.0015194556912103366))" + }; + static std::string ticket_11725[2] = { "POLYGON((0 0, 0 1, 3 1, 3 0, 0 0))", "POLYGON((0 1, 0 3, 3 3, 3 1, 2 2, 1 2 , 1 1, 0 1))" }; -static std::string ticket_11725_2[2] = - { - "POLYGON((0 0, 0 3, 3 3, 3 0, 0 0))", - "POLYGON((3 1, 1 1, 1 2, 2 2, 3 1))", - }; - // Integer, ccw, open static std::string ticket_11676[2] = { diff --git a/test/algorithms/set_operations/difference/difference.cpp b/test/algorithms/set_operations/difference/difference.cpp index 7865c704b..953b72b49 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -296,7 +296,7 @@ void test_all() ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], 1, -1, 71495.3331, 2, -1, 8960.49049, - 2, -1, 71495.3331 + 8960.49049); + 1, -1, 71495.3331 + 8960.49049); test_one("ggl_list_20110307_javier", ggl_list_20110307_javier[0], ggl_list_20110307_javier[1], @@ -385,6 +385,12 @@ void test_all() 1, 5, 1342.65795); #endif + test_one("ticket_11725", + ticket_11725[0], ticket_11725[1], + 1, -1, 3.0, + 1, -1, 4.5, + 1, -1, 7.5); + // From assemble-test, with a u/u case test_one("assemble_0210", "POLYGON((0 0,0 10,10 10,10 0,0 0),(8.5 1,9.5 1,9.5 2,8.5 2,8.5 1))", @@ -453,9 +459,6 @@ void test_all() ***/ #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS - test_one("ticket_11725_2", - ticket_11725_2[0], ticket_11725_2[1], - 2, -1, 7.5, 0, -1, 0.0); test_one("mysql_21977775", mysql_21977775[0], mysql_21977775[1], 2, -1, 160.856568913, 2, -1, 92.3565689126); @@ -508,7 +511,7 @@ void test_specific() ticket_11676[0], ticket_11676[1], 1, 18, 2537992.5, 2, 11, 294963.5, - 2, -1, 2537992.5 + 294963.5, + 1, -1, 2537992.5 + 294963.5, settings); } } diff --git a/test/algorithms/set_operations/difference/difference_multi.cpp b/test/algorithms/set_operations/difference/difference_multi.cpp index eb8f7ebe4..3621f15d4 100644 --- a/test/algorithms/set_operations/difference/difference_multi.cpp +++ b/test/algorithms/set_operations/difference/difference_multi.cpp @@ -86,7 +86,7 @@ void test_areal() case_77_multi[0], case_77_multi[1], 6, 31, 7.0, 5, 36, 13.0, - 5, 43, 7.0 + 13.0); + 4, 43, 7.0 + 13.0); test_one("case_78_multi", case_78_multi[0], case_78_multi[1], @@ -148,12 +148,12 @@ void test_areal() } - // Areas and #clips correspond with POSTGIS + // Areas and #clips correspond with POSTGIS (except sym case) test_one("case_101_multi", case_101_multi[0], case_101_multi[1], 5, 23, 4.75, 5, 40, 12.75, - 5, 48, 4.75 + 12.75); + 4, 48, 4.75 + 12.75); // Areas and #clips correspond with POSTGIS test_one("case_102_multi", @@ -162,12 +162,12 @@ void test_areal() 6, 25, 3.75, 6, 27, 0.75 + 3.75); - // Areas and #clips correspond with POSTGIS + // Areas and #clips correspond with POSTGIS (except sym case) test_one("case_107_multi", case_107_multi[0], case_107_multi[1], 2, 11, 2.25, 3, 14, 3.0, - 4, 21, 5.25); + 3, 21, 5.25); // Areas correspond with POSTGIS, // #clips in PostGIS is 11,11,5 but should most probably be be 12,12,6 @@ -175,7 +175,7 @@ void test_areal() case_recursive_boxes_1[0], case_recursive_boxes_1[1], 10, 75, 26.0, 11, 77, 24.0, - 4, 98, 50.0); + 3, 98, 50.0); // Areas and #clips correspond with POSTGIS test_one("case_recursive_boxes_2", @@ -183,12 +183,12 @@ void test_areal() 3, 15, 3.0, 5, 33, 7.0); - // Areas and #clips by POSTGIS + // Areas and #clips by POSTGIS (except sym case) test_one("case_recursive_boxes_3", case_recursive_boxes_3[0], case_recursive_boxes_3[1], 24, -1, 21.5, 25, -1, 22.5, - 37, -1, 44.0); + 18, -1, 44.0); // 4, input is not valid @@ -196,31 +196,31 @@ void test_areal() case_recursive_boxes_5[0], case_recursive_boxes_5[1], 15, -1, 22.0, // #clips should be 16 11, -1, 27.0, // #clips should be 12 - 8, -1, 49.0); + 7, -1, 49.0); test_one("case_recursive_boxes_6", case_recursive_boxes_6[0], case_recursive_boxes_6[1], 6, -1, 3.5, 3, -1, 1.5, - 8, -1, 5.0); + 7, -1, 5.0); test_one("case_recursive_boxes_7", case_recursive_boxes_7[0], case_recursive_boxes_7[1], 3, 15, 2.75, 4, 19, 2.75, - 3, 22, 5.5); + 2, 22, 5.5); test_one("case_recursive_boxes_8", case_recursive_boxes_8[0], case_recursive_boxes_8[1], 2, -1, 2.50, 4, -1, 5.75, - 4, -1, 8.25); + 3, -1, 8.25); test_one("case_recursive_boxes_9", case_recursive_boxes_9[0], case_recursive_boxes_9[1], 3, -1, 1.5, 4, -1, 2.5, - 6, -1, 4.0); + 4, -1, 4.0); test_one("case_recursive_boxes_10", case_recursive_boxes_10[0], case_recursive_boxes_10[1], @@ -232,7 +232,7 @@ void test_areal() case_recursive_boxes_11[0], case_recursive_boxes_11[1], 3, -1, 2.5, 3, -1, 4.5, - 3, -1, 7.0); + 2, -1, 7.0); test_one("mysql_21965285_b", mysql_21965285_b[0], diff --git a/test/algorithms/set_operations/intersection/intersection.cpp b/test/algorithms/set_operations/intersection/intersection.cpp index 3e9c1a10c..266c4f09b 100644 --- a/test/algorithms/set_operations/intersection/intersection.cpp +++ b/test/algorithms/set_operations/intersection/intersection.cpp @@ -143,7 +143,7 @@ void test_areal() test_one("distance_zero", distance_zero[0], distance_zero[1], - 1, 0 /* f: 4, other: 5 */, 0.29516139, 0.01); + 1, 0 /* f: 4, other: 5 */, 0.29516139, ut_settings(0.01)); test_one("equal_holes_disjoint", equal_holes_disjoint[0], equal_holes_disjoint[1], @@ -166,19 +166,19 @@ void test_areal() test_one("pie_2_3_23_0", pie_2_3_23_0[0], pie_2_3_23_0[1], - 1, 4, 163292.679042133, 0.1); + 1, 4, 163292.679042133, ut_settings(0.1)); test_one("isovist", isovist1[0], isovist1[1], 1, 19, 88.19203, - if_typed_tt(0.01, 0.1)); + ut_settings(if_typed_tt(0.01, 0.1))); // SQL Server gives: 88.1920416352664 // PostGIS gives: 88.19203677911 test_one("geos_1", geos_1[0], geos_1[1], - 1, -1, 3461.0214843, 0.005); // MSVC 14 reports 3461.025390625 + 1, -1, 3461.0214843, ut_settings(0.005)); // MSVC 14 reports 3461.025390625 // Expectations: // In most cases: 0 (no intersection) @@ -186,7 +186,7 @@ void test_areal() // In some cases: 5.6022983000000002e-05 (powerpc64le-gcc-6-0) test_one("geos_2", geos_2[0], geos_2[1], - 0, 0, 6.0e-5, -1.0); // -1 denotes: compare with <= + 0, 0, 6.0e-5, ut_settings(-1.0)); // -1 denotes: compare with <= #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("geos_3", @@ -208,7 +208,7 @@ void test_areal() ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], 1, if_typed(4, 5), 0.6649875, - if_typed(1.0, 0.01)); + ut_settings(if_typed(1.0, 0.01))); } // SQL Server reports: 0.400390625 @@ -221,7 +221,7 @@ void test_areal() #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) 0.40 #else - 0.397162651, 0.01 + 0.397162651, ut_settings(0.01) #endif ); @@ -237,20 +237,20 @@ void test_areal() test_one("ggl_list_20131119_james", ggl_list_20131119_james[0], ggl_list_20131119_james[1], - 1, 4, 6.6125873045, 0.1); + 1, 4, 6.6125873045, ut_settings(0.1)); test_one("ggl_list_20140223_shalabuda", ggl_list_20140223_shalabuda[0], ggl_list_20140223_shalabuda[1], - 1, 4, 3.77106, 0.001); + 1, 4, 3.77106, ut_settings(0.001)); // Mailed to the Boost.Geometry list on 2014/03/21 by 7415963@gmail.com test_one("ggl_list_20140321_7415963", ggl_list_20140321_7415963[0], ggl_list_20140321_7415963[1], - 0, 0, 0, 0.1); + 0, 0, 0, ut_settings(0.1)); #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1], - 1, 4, 0.00029437899183903937, 0.01); + 1, 4, 0.00029437899183903937, ut_settings(0.01)); #endif test_one("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1], @@ -308,6 +308,10 @@ void test_areal() ticket_10747_e[0], ticket_10747_e[1], 1, 4, 7.0368748575710959e-15); + test_one("ticket_11576", + ticket_11576[0], ticket_11576[1], + 1, 0, 5.585617332907136e-07); + #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_9563", ticket_9563[0], ticket_9563[1], 1, 8, 129.90381); diff --git a/test/algorithms/set_operations/intersection/intersection_multi.cpp b/test/algorithms/set_operations/intersection/intersection_multi.cpp index ca49a8496..20c5cd4af 100644 --- a/test/algorithms/set_operations/intersection/intersection_multi.cpp +++ b/test/algorithms/set_operations/intersection/intersection_multi.cpp @@ -248,6 +248,10 @@ void test_areal() test_one("ticket_9081", ticket_9081[0], ticket_9081[1], 2, 10, 0.0019812556); + + test_one("ticket_11018", + ticket_11018[0], ticket_11018[1], + 1, 4, 1.7791170511070893e-14); } template diff --git a/test/algorithms/set_operations/intersection/test_intersection.hpp b/test/algorithms/set_operations/intersection/test_intersection.hpp index 512bc9c95..c074e924e 100644 --- a/test/algorithms/set_operations/intersection/test_intersection.hpp +++ b/test/algorithms/set_operations/intersection/test_intersection.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -34,15 +35,28 @@ #include +struct ut_settings +{ + double percentage; + bool test_validity; + bool debug; + + ut_settings(double p = 0.0001) + : percentage(p) + , test_validity(false) + , debug(false) + {} + +}; + template typename bg::default_area_result::type check_result( std::vector const& intersection_output, std::string const& caseid, - std::size_t expected_count = 0, int expected_point_count = 0, - double expected_length_or_area = 0, - double percentage = 0.0001, - bool debug = false) + std::size_t expected_count, int expected_point_count, + double expected_length_or_area, + ut_settings const& settings) { bool const is_line = bg::geometry_id::type::value == 2; @@ -64,10 +78,18 @@ check_result( ? bg::length(*it) : bg::area(*it); - if (debug) + if (settings.debug) { std::cout << std::setprecision(20) << bg::wkt(*it) << std::endl; } + + if (settings.test_validity) + { + std::string message; + bool const valid = bg::is_valid(*it, message); + BOOST_CHECK_MESSAGE(valid, + "intersection: " << caseid << " not valid " << message); + } } #if ! defined(BOOST_GEOMETRY_NO_BOOST_TEST) @@ -94,9 +116,9 @@ check_result( } double const detected_length_or_area = boost::numeric_cast(length_or_area); - if (percentage > 0.0) + if (settings.percentage > 0.0) { - BOOST_CHECK_CLOSE(detected_length_or_area, expected_length_or_area, percentage); + BOOST_CHECK_CLOSE(detected_length_or_area, expected_length_or_area, settings.percentage); } else { @@ -115,17 +137,16 @@ typename bg::default_area_result::type test_intersection(std::string const& G1 const& g1, G2 const& g2, std::size_t expected_count = 0, int expected_point_count = 0, double expected_length_or_area = 0, - double percentage = 0.0001, - bool debug = false) + ut_settings const& settings = ut_settings()) { - if (debug) + if (settings.debug) { std::cout << std::endl << "case " << caseid << std::endl; } typedef typename bg::point_type::type point_type; - if (! debug) + if (! settings.debug) { // Check _inserter behaviour with stratey typedef bg::strategy_intersection @@ -148,26 +169,26 @@ typename bg::default_area_result::type test_intersection(std::string const& bg::intersection(g1, g2, intersection_output); check_result(intersection_output, caseid, expected_count, expected_point_count, - expected_length_or_area, percentage, debug); + expected_length_or_area, settings); // Check variant behaviour intersection_output.clear(); bg::intersection(boost::variant(g1), g2, intersection_output); check_result(intersection_output, caseid, expected_count, expected_point_count, - expected_length_or_area, percentage, debug); + expected_length_or_area, settings); intersection_output.clear(); bg::intersection(g1, boost::variant(g2), intersection_output); check_result(intersection_output, caseid, expected_count, expected_point_count, - expected_length_or_area, percentage, debug); + expected_length_or_area, settings); intersection_output.clear(); bg::intersection(boost::variant(g1), boost::variant(g2), intersection_output); check_result(intersection_output, caseid, expected_count, expected_point_count, - expected_length_or_area, percentage, debug); + expected_length_or_area, settings); #if defined(TEST_WITH_SVG) { @@ -217,7 +238,7 @@ typename bg::default_area_result::type test_intersection(std::string const& #endif - if (debug) + if (settings.debug) { std::cout << "end case " << caseid << std::endl; } @@ -230,8 +251,7 @@ typename bg::default_area_result::type test_one(std::string const& caseid, std::string const& wkt1, std::string const& wkt2, std::size_t expected_count = 0, int expected_point_count = 0, double expected_length_or_area = 0, - double percentage = 0.0001, - bool debug = false) + ut_settings const& settings = ut_settings()) { G1 g1; bg::read_wkt(wkt1, g1); @@ -245,8 +265,7 @@ typename bg::default_area_result::type test_one(std::string const& caseid, return test_intersection(caseid, g1, g2, expected_count, expected_point_count, - expected_length_or_area, percentage, - debug); + expected_length_or_area, settings); } template @@ -254,8 +273,7 @@ void test_one_lp(std::string const& caseid, std::string const& wkt_areal, std::string const& wkt_linear, std::size_t expected_count = 0, int expected_point_count = 0, double expected_length = 0, - double percentage = 0.0001, - bool debug1 = false, bool debug2 = false) + ut_settings const& settings = ut_settings()) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << caseid << " -- start" << std::endl; @@ -269,14 +287,14 @@ void test_one_lp(std::string const& caseid, test_intersection(caseid, areal, linear, expected_count, expected_point_count, - expected_length, percentage, debug1); + expected_length, settings); // A linestring reversed should deliver exactly the same. bg::reverse(linear); test_intersection(caseid + "_rev", areal, linear, expected_count, expected_point_count, - expected_length, percentage, debug2); + expected_length, settings); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << caseid << " -- end" << std::endl; #endif diff --git a/test/algorithms/set_operations/union/test_union.hpp b/test/algorithms/set_operations/union/test_union.hpp index 67ef15b19..b5f87e79a 100644 --- a/test/algorithms/set_operations/union/test_union.hpp +++ b/test/algorithms/set_operations/union/test_union.hpp @@ -133,15 +133,6 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2, << std::endl; #endif -#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) - BOOST_CHECK_MESSAGE(expected_point_count < 0 || std::abs(int(n) - expected_point_count) < 3, - "union: " << caseid - << " #points expected: " << expected_point_count - << " detected: " << n - << " type: " << (type_for_assert_message()) - ); -#endif - BOOST_CHECK_MESSAGE(expected_count < 0 || int(clip.size()) == expected_count, "union: " << caseid << " #clips expected: " << expected_count @@ -156,6 +147,15 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2, << " type: " << (type_for_assert_message()) ); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + BOOST_CHECK_MESSAGE(expected_point_count < 0 || std::abs(int(n) - expected_point_count) < 3, + "union: " << caseid + << " #points expected: " << expected_point_count + << " detected: " << n + << " type: " << (type_for_assert_message()) + ); +#endif + BOOST_CHECK_CLOSE(area, expected_area, settings.percentage); #if defined(TEST_WITH_SVG) diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 4fefb35ee..26cae7284 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -1,9 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test -// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// Copyright (c) 2008-2015 Bruno Lalande, Paris, France. -// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. +// Copyright (c) 2007-2016 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2016 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2016 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -189,6 +189,43 @@ void test_areal() test_one("81", case_81[0], case_81[1], 1, 2, 15, 163.5); + test_one("82", + case_82[0], case_82[1], 1, 1, 21, 19.75); + + test_one("83", + case_83[0], case_83[1], 1, 0, 7, 20.0); + + test_one("90", + case_90[0], case_90[1], 1, 2, 17, 221.3688); + + test_one("91", + case_91[0], case_91[1], 1, 1, 9, 147.5); + + test_one("92", + case_92[0], case_92[1], 2, 0, 9, 175.0); + + test_one("93", + case_93[0], case_93[1], 1, 2, 12, 172.9167); + + test_one("94", + case_94[0], case_94[1], 2, 0, 12, 170.0); + + // Has two separate but touching interior rings + test_one("95", + case_95[0], case_95[1], 1, 2, 15, 1320.0); + + test_one("96", + case_96[0], case_96[1], 1, 1, 10, 1500.0); + + test_one("97", + case_97[0], case_97[1], 1, 0, 10, 286.799); + + test_one("98", + case_98[0], case_98[1], 1, 1, 14, 653.067); + + test_one("99", + case_99[0], case_99[1], 1, 0, 5, 1600.0); + /* test_one(102, simplex_normal[0], simplex_reversed[1], @@ -313,6 +350,12 @@ void test_areal() 1, 0, 10, 2424.3449); #endif + test_one("ticket_10866", ticket_10866[0], ticket_10866[1], + 1, 0, 14, 332760303.5); + + test_one("ticket_11725", ticket_11725[0], ticket_11725[1], + 1, 1, 10, 7.5); + test_one("geos_1", geos_1[0], geos_1[1], 1, 0, -1, 3461.3203125); test_one("geos_2", geos_2[0], geos_2[1], @@ -390,13 +433,7 @@ void test_areal() 1, 0, if_typed_tt(93, 91), 22.815); test_one("buffer_mp2", buffer_mp2[0], buffer_mp2[1], - 1, 0, 217, 36.752837); - -#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS - test_one("ticket_11725", - ticket_11725[0], ticket_11725[1], - 1, 1, -1, 7.5); -#endif + 1, 1, 217, 36.752837); // #holes should be 1 (for the 3 cases below) test_one("mysql_21964079_1", diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index bdb0e3683..8fe68de59 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -95,7 +95,7 @@ void test_areal() 5, 0, 25, 5.0); test_one("case_76_multi", case_76_multi[0], case_76_multi[1], - 5, 0, 31, 8.0); + 4, 0, 31, 8.0); test_one("case_89_multi", case_89_multi[0], case_89_multi[1], 1, 0, 13, 6); @@ -111,6 +111,25 @@ void test_areal() test_one("case_105_multi", case_105_multi[0], case_105_multi[1], 1, 0, 5, 25); + test_one("case_106_multi", + case_106_multi[0], case_106_multi[1], + 1, 0, 12, 25); + test_one("case_107_multi", + case_107_multi[0], case_107_multi[1], + 1, 0, 15, 6.75); + test_one("case_108_multi", + case_108_multi[0], case_108_multi[1], + 1, 0, 20, 22.75); + + // Should have 2 holes + test_one("case_109_multi", + case_109_multi[0], case_109_multi[1], + 1, 1, 14, 1400); + + // Should have 9 holes, they are all separate and touching + test_one("case_110_multi", + case_110_multi[0], case_110_multi[1], + 1, 1, 37, 1250); test_one("case_recursive_boxes_1", case_recursive_boxes_1[0], case_recursive_boxes_1[1], @@ -120,7 +139,7 @@ void test_areal() 1, 0, 14, 100.0); // Area from SQL Server test_one("case_recursive_boxes_3", case_recursive_boxes_3[0], case_recursive_boxes_3[1], - 17, 0, 159, 56.5); // Area from SQL Server + 14, 0, 159, 56.5); // Area from SQL Server test_one("case_recursive_boxes_4", case_recursive_boxes_4[0], case_recursive_boxes_4[1], @@ -154,22 +173,22 @@ void test_areal() 1, 0, -1, 8.0); test_one("case_recursive_boxes_12", case_recursive_boxes_12[0], case_recursive_boxes_12[1], - 6, 0, -1, 6.0); + 3, 0, -1, 6.0); test_one("case_recursive_boxes_13", case_recursive_boxes_13[0], case_recursive_boxes_13[1], 3, 0, -1, 10.25); test_one("case_recursive_boxes_14", case_recursive_boxes_14[0], case_recursive_boxes_14[1], - 5, 0, -1, 4.5); + 4, 0, -1, 4.5); test_one("case_recursive_boxes_15", case_recursive_boxes_15[0], case_recursive_boxes_15[1], - 3, 0, -1, 6.0); + 2, 0, -1, 6.0); test_one("case_recursive_boxes_16", case_recursive_boxes_16[0], case_recursive_boxes_16[1], - 1, 0, -1, 22.0); + 1, 1, -1, 22.0); test_one("case_recursive_boxes_17", case_recursive_boxes_17[0], case_recursive_boxes_17[1], - 5, 1, -1, 21.0); + 3, 1, -1, 21.0); test_one("case_recursive_boxes_18", case_recursive_boxes_18[0], case_recursive_boxes_18[1], 3, 0, -1, 2.5); @@ -205,10 +224,10 @@ void test_areal() 2, 0, -1, 6.5); test_one("case_recursive_boxes_29", case_recursive_boxes_29[0], case_recursive_boxes_29[1], - 2, 0, -1, 15.5); + 1, 0, -1, 15.5); test_one("case_recursive_boxes_30", case_recursive_boxes_30[0], case_recursive_boxes_30[1], - 1, 1, -1, 17.5); + 1, 2, -1, 17.5); test_one("case_recursive_boxes_31", case_recursive_boxes_31[0], case_recursive_boxes_31[1], 3, 0, -1, 5.0); @@ -226,7 +245,7 @@ void test_areal() 1, 1, -1, 24.5); test_one("case_recursive_boxes_36", case_recursive_boxes_36[0], case_recursive_boxes_36[1], - 3, 0, -1, 3.0); + 2, 0, -1, 3.0); test_one("case_recursive_boxes_37", case_recursive_boxes_37[0], case_recursive_boxes_37[1], 2, 1, -1, 7.75); @@ -254,6 +273,9 @@ void test_areal() test_one("ticket_10803", ticket_10803[0], ticket_10803[1], 1, 0, 9, 2663736.07038); + test_one("ticket_11984", + ticket_11984[0], ticket_11984[1], + 1, 2, 134, 60071.08077); } // Test cases (generic)