From 27b7b9d8031947e3ce97cf1c160941f6fd9b074b Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 11:09:33 +0100 Subject: [PATCH 01/14] [union][test] add cases from branch handle_touch and put UT report in argument order --- test/algorithms/overlay/overlay_cases.hpp | 72 +++++++++++++++++++ .../set_operations/union/test_union.hpp | 18 ++--- .../algorithms/set_operations/union/union.cpp | 45 +++++++++++- 3 files changed, 123 insertions(+), 12 deletions(-) diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index d8272fc0b..3a8e2a135 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" 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..fe7524868 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,45 @@ 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, 1, 17, 221.3688); + + test_one("91", + case_91[0], case_91[1], 1, 0, 9, 147.5); + + test_one("92", + case_92[0], case_92[1], 2, 0, 9, 175.0); + + // Should have 0 holes + test_one("93", + case_93[0], case_93[1], 1, 1, 12, 172.9167); + + test_one("94", + case_94[0], case_94[1], 2, 0, 12, 170.0); + + // Has 2 separate but touching interior rings, which is OK + test_one("95", + case_95[0], case_95[1], 1, 2, 15, 1320.0); + + // Should have 0 holes + 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], From 1439c479d6bbde82d453915f2c4122435b6f21ec Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 11:22:47 +0100 Subject: [PATCH 02/14] [union][test] multi: add cases from branch handle_touch --- .../overlay/multi_overlay_cases.hpp | 12 ++++++++++++ .../set_operations/union/union_multi.cpp | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index c4ee6be4b..b6fc4bb76 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 diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index bdb0e3683..eeecae17a 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -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], From 999f3c96a895ad5a6d9e5c6d69e141fd73c6fb0f Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 12:00:08 +0100 Subject: [PATCH 03/14] [traverse] move iteration to traversal class, to later split it more and reuse it --- .../algorithms/detail/overlay/traverse.hpp | 139 ++++++++++-------- 1 file changed, 74 insertions(+), 65 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index ebf74c5ef..cc7088f60 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 { @@ -671,6 +672,73 @@ struct traversal return traverse_error_endless_loop; } + template + void iterate(Rings& rings, std::size_t& finalized_ring_size, + typename Backtrack::state_type& state) + { + typedef typename boost::range_value::type ring_type; + + std::size_t const min_num_points + = core_detail::closure::minimum_ring_size + < + geometry::closure::value + >::value; + + // 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]; + + // Skip discarded ones + if (start_turn.discarded + || start_turn.blocked()) + { + continue; + } + + for (int op_index = 0; op_index < 2; op_index++) + { + 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)) + { + continue; + } + + ring_type ring; + traverse_error_type traverse_error = 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, 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); + } + } + } + } + private : Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; @@ -691,7 +759,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,80 +780,21 @@ 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) - { - 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); } }; From 7186c46f028b288a4990e88f053dc45a55dbf143 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 12:09:12 +0100 Subject: [PATCH 04/14] [traverse] split new method iterate into two parts --- .../algorithms/detail/overlay/traverse.hpp | 96 ++++++++++--------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index cc7088f60..8a69dc791 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -673,17 +673,60 @@ struct traversal } template - void iterate(Rings& rings, std::size_t& finalized_ring_size, - typename Backtrack::state_type& state) + 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; - std::size_t const min_num_points - = core_detail::closure::minimum_ring_size - < - geometry::closure::value - >::value; + 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) + { // Iterate through all unvisited points for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) { @@ -698,43 +741,8 @@ struct traversal for (int op_index = 0; op_index < 2; op_index++) { - 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)) - { - continue; - } - - ring_type ring; - traverse_error_type traverse_error = 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, 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); - } + traverse_with_operation(start_turn, turn_index, op_index, + rings, finalized_ring_size, state); } } } From 85e0755ccdc37c44d3f6f4b6c8d415794a0b4025 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 13:25:30 +0100 Subject: [PATCH 05/14] [traverse][fix] use two passes, in first pass avoid uu turns to get the interior rings right at starting points. Second pass use uu, but only switch source if there are only uu turns found. This fixes most of the simple cases (complex cases can still go wrong) --- .../algorithms/detail/overlay/traverse.hpp | 61 ++++++++++++++++--- .../set_operations/difference/difference.cpp | 4 +- .../difference/difference_multi.cpp | 28 ++++----- .../algorithms/set_operations/union/union.cpp | 12 ++-- .../set_operations/union/union_multi.cpp | 20 +++--- 5 files changed, 85 insertions(+), 40 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index 8a69dc791..a8f423212 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -118,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) {} @@ -148,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; } @@ -725,19 +731,53 @@ struct traversal template void iterate(Rings& rings, std::size_t& finalized_ring_size, - typename Backtrack::state_type& state) + 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]; - // Skip discarded ones - if (start_turn.discarded - || start_turn.blocked()) + 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++) { @@ -754,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; +}; /*! @@ -802,7 +846,10 @@ public : typename Backtrack::state_type state; - trav.iterate(rings, finalized_ring_size, state); + for (int pass = 0; pass < 2; pass++) + { + trav.iterate(rings, finalized_ring_size, state, pass); + } } }; diff --git a/test/algorithms/set_operations/difference/difference.cpp b/test/algorithms/set_operations/difference/difference.cpp index 7865c704b..21cc0f950 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], @@ -508,7 +508,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/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index fe7524868..7b3da866a 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -196,26 +196,24 @@ void test_areal() case_83[0], case_83[1], 1, 0, 7, 20.0); test_one("90", - case_90[0], case_90[1], 1, 1, 17, 221.3688); + case_90[0], case_90[1], 1, 2, 17, 221.3688); test_one("91", - case_91[0], case_91[1], 1, 0, 9, 147.5); + 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); - // Should have 0 holes test_one("93", - case_93[0], case_93[1], 1, 1, 12, 172.9167); + 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 2 separate but touching interior rings, which is OK + // Has two separate but touching interior rings test_one("95", case_95[0], case_95[1], 1, 2, 15, 1320.0); - // Should have 0 holes test_one("96", case_96[0], case_96[1], 1, 1, 10, 1500.0); @@ -429,7 +427,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); + 1, 1, 217, 36.752837); #ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS test_one("ticket_11725", diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index eeecae17a..2f51e1082 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); @@ -139,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], @@ -173,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); @@ -224,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); @@ -245,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); From 7818ce879365551486119604d284ba4702ff344c Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 16:05:01 +0100 Subject: [PATCH 06/14] [test] add testcase for ticket_11984 which is solved now by last commit --- test/algorithms/overlay/multi_overlay_cases.hpp | 8 ++++++++ test/algorithms/set_operations/union/union_multi.cpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index b6fc4bb76..497420e38 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -772,6 +772,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/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index 2f51e1082..2f6b31537 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -273,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, 3, 134, 60071.08077); } // Test cases (generic) From 2f785c09e526d01bd80a32fbbb86fafd8ac16dde Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 16:27:15 +0100 Subject: [PATCH 07/14] [test] add testcase for ticket_11725 which is solved now by sometimes switching source in u/u (the yet simple approach) --- test/algorithms/overlay/overlay_cases.hpp | 7 ------- test/algorithms/set_operations/difference/difference.cpp | 9 ++++++--- test/algorithms/set_operations/union/union.cpp | 9 +++------ 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 3a8e2a135..437d26266 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -963,19 +963,12 @@ static std::string ticket_11121[2] = "POLYGON((-7901 -1485,-7901 529,-7901 529,15802 544,15802 -1485,-7901 -1485))" }; - 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 21cc0f950..953b72b49 100644 --- a/test/algorithms/set_operations/difference/difference.cpp +++ b/test/algorithms/set_operations/difference/difference.cpp @@ -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); diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 7b3da866a..08ef4c1a8 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -350,6 +350,9 @@ void test_areal() 1, 0, 10, 2424.3449); #endif + 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], @@ -429,12 +432,6 @@ void test_areal() test_one("buffer_mp2", buffer_mp2[0], buffer_mp2[1], 1, 1, 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 - // #holes should be 1 (for the 3 cases below) test_one("mysql_21964079_1", mysql_21964079_1[0], mysql_21964079_1[1], From 0d10b7596647fc21484f0619befa2da5cc321413 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 16:44:52 +0100 Subject: [PATCH 08/14] [test] add testcase for ticket 11576, which is fixed --- test/algorithms/overlay/overlay_cases.hpp | 7 +++++++ .../set_operations/intersection/intersection.cpp | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 437d26266..8b8e6139a 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -963,6 +963,13 @@ static std::string ticket_11121[2] = "POLYGON((-7901 -1485,-7901 529,-7901 529,15802 544,15802 -1485,-7901 -1485))" }; + +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))", diff --git a/test/algorithms/set_operations/intersection/intersection.cpp b/test/algorithms/set_operations/intersection/intersection.cpp index 3e9c1a10c..cd5b5bffe 100644 --- a/test/algorithms/set_operations/intersection/intersection.cpp +++ b/test/algorithms/set_operations/intersection/intersection.cpp @@ -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); From 9c33e3764749472075e8370744eda1d3af560cf4 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 23 Mar 2016 16:58:45 +0100 Subject: [PATCH 09/14] [test] add test for ticket 10866 which is apparently fixed --- test/algorithms/overlay/overlay_cases.hpp | 6 ++++++ test/algorithms/set_operations/union/union.cpp | 3 +++ 2 files changed, 9 insertions(+) diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index 8b8e6139a..d27c4d0ae 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -951,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))", diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index 08ef4c1a8..26cae7284 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -350,6 +350,9 @@ 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); From 79408be8724c93149ba3afdfbf43d9b177eea6f7 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 26 Mar 2016 15:32:47 +0100 Subject: [PATCH 10/14] [doc] update release notes --- doc/release_notes.qbk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index f7b0ed28e..9d340c192 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -36,10 +36,12 @@ * [@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/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. From 4a9b2ba167c99e1b56c832b02bfbb206e4692906 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 26 Mar 2016 16:14:22 +0100 Subject: [PATCH 11/14] [test] add possibility to check validity to intersection tests --- .../intersection/intersection.cpp | 22 +++---- .../intersection/test_intersection.hpp | 66 ++++++++++++------- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/test/algorithms/set_operations/intersection/intersection.cpp b/test/algorithms/set_operations/intersection/intersection.cpp index cd5b5bffe..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], 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 From a1a16084ec277529d6e33ef6957e77307793a802 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 26 Mar 2016 16:16:50 +0100 Subject: [PATCH 12/14] [test] add testcase for ticket 11018 (fixed) --- doc/release_notes.qbk | 1 + test/algorithms/overlay/multi_overlay_cases.hpp | 7 +++++++ .../set_operations/intersection/intersection_multi.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 9d340c192..f39b70ed5 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -34,6 +34,7 @@ [*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 diff --git a/test/algorithms/overlay/multi_overlay_cases.hpp b/test/algorithms/overlay/multi_overlay_cases.hpp index 497420e38..382da538a 100644 --- a/test/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/algorithms/overlay/multi_overlay_cases.hpp @@ -765,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] = { 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 From c3b4cba7ffe43864d38c1bac6a8b1840265ccb10 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 26 Mar 2016 16:32:17 +0100 Subject: [PATCH 13/14] [test] add testcase for ticket 11580 (not yet fixed) --- test/algorithms/buffer/buffer_polygon.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) 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); From ebd3b6a4b9ad2992b2c0c3cb34b3e8bb1e8da782 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 27 Mar 2016 10:58:46 +0200 Subject: [PATCH 14/14] [test] fix #exected holes --- test/algorithms/set_operations/union/union_multi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/algorithms/set_operations/union/union_multi.cpp b/test/algorithms/set_operations/union/union_multi.cpp index 2f6b31537..8fe68de59 100644 --- a/test/algorithms/set_operations/union/union_multi.cpp +++ b/test/algorithms/set_operations/union/union_multi.cpp @@ -275,7 +275,7 @@ void test_areal() 1, 0, 9, 2663736.07038); test_one("ticket_11984", ticket_11984[0], ticket_11984[1], - 1, 3, 134, 60071.08077); + 1, 2, 134, 60071.08077); } // Test cases (generic)