From 076f17c241644061dcea28a4b2db089073bf3070 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 9 Aug 2014 23:05:57 +0200 Subject: [PATCH 01/18] [buffer][test] change usage of join strategies for robustness check --- .../robustness/overlay/buffer/recursive_polygons_buffer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp b/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp index d62e83a2b..737f22c2e 100644 --- a/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp +++ b/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp @@ -200,6 +200,8 @@ bool test_buffer(MultiPolygon& result, int& index, bg::strategy::buffer::end_round end_strategy; bg::strategy::buffer::point_circle point_strategy; bg::strategy::buffer::side_straight side_strategy; + bg::strategy::buffer::join_round join_round_strategy(100); // Compatible with unit tests + bg::strategy::buffer::join_miter join_miter_strategy; try { @@ -208,13 +210,13 @@ bool test_buffer(MultiPolygon& result, int& index, case 1 : bg::buffer(mp, buffered, distance_strategy, side_strategy, - bg::strategy::buffer::join_round(), + join_round_strategy, end_strategy, point_strategy); break; case 2 : bg::buffer(mp, buffered, distance_strategy, side_strategy, - bg::strategy::buffer::join_miter(), + join_miter_strategy, end_strategy, point_strategy); break; default : From 536f6a6974aba7830a2e64604a702f01a258e30d Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 9 Aug 2014 23:06:15 +0200 Subject: [PATCH 02/18] [buffer] remove unused variable --- .../algorithms/detail/buffer/buffered_piece_collection.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 5cca314df..2039c1bd0 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -147,7 +147,6 @@ struct buffered_piece_collection int m_first_piece_index; buffered_ring_collection > offsetted_rings; // indexed by multi_index - std::vector< std::vector < robust_point_type > > robust_offsetted_rings; buffered_ring_collection traversed_rings; segment_identifier current_segment_id; From bdcdb5717ebc12cfc3dd0d8c35a831775f8d84d2 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 9 Aug 2014 23:18:48 +0200 Subject: [PATCH 03/18] [buffer] don't check neighbor for on-border --- .../algorithms/detail/buffer/turn_in_piece_visitor.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index 182f5af6a..b4acb0d11 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -167,9 +167,13 @@ public: { return; } + if (geometry_code == 0 && neighbour) + { + return; + } Turn& mutable_turn = m_turns[turn.turn_index]; - if (geometry_code == 0 && ! neighbour) + if (geometry_code) { // If it is on the border and they are neighbours, it should be // on the offsetted ring From 6cf72447d1c4f981198b0cacc532eba1881b0c7f Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 9 Aug 2014 23:33:15 +0200 Subject: [PATCH 04/18] [buffer][test] remove unused variable --- test/algorithms/buffer/multi_polygon_buffer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index aa0f42890..5fa0a3a68 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -338,7 +338,6 @@ void test_all() test_one("rt_t", rt_t, join_miter, end_flat, 15.6569, 1.0); } -int point_buffer_count; int test_main(int, char* []) { From a46e2603d8437969ed3f60ecfd09e1af48fb5f29 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 9 Aug 2014 23:51:42 +0200 Subject: [PATCH 05/18] [buffer][fix] In rare cases an extra ring was traversed and created. Fixed, that ring is discarded now. This fixes behaviour of assign_parents with positive-rings in positive-rings (when check_for_orientation is true; normally (for overlay) it is false) It also reverses a negative-only ring so fixes a linestring_buffer testcase. For multi-polygon it fixes new testcase rt_u2 found by recursive-polygon-buffer test --- .../buffer/buffered_piece_collection.hpp | 2 +- .../detail/overlay/assign_parents.hpp | 52 +++++++++++-------- test/algorithms/buffer/linestring_buffer.cpp | 6 +-- .../buffer/multi_polygon_buffer.cpp | 9 +++- 4 files changed, 43 insertions(+), 26 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 2039c1bd0..e657ff978 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -826,7 +826,7 @@ struct buffered_piece_collection selected[id] = properties(*it, true); } - detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, false); + detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true); return detail::overlay::add_rings(selected, offsetted_rings, traversed_rings, out); } diff --git a/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp index a7cbd038d..67b48cc47 100644 --- a/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/assign_parents.hpp @@ -127,30 +127,30 @@ struct assign_visitor template inline void apply(Item const& outer, Item const& inner, bool first = true) { - if (first && outer.real_area < 0) + if (first && outer.abs_area < inner.abs_area) { - // Reverse arguments + // Apply with reversed arguments apply(inner, outer, false); return; } - if (math::larger(outer.real_area, 0)) + if (m_check_for_orientation + || (math::larger(outer.real_area, 0) + && math::smaller(inner.real_area, 0))) { - if (inner.real_area < 0 || m_check_for_orientation) - { - ring_info_type& inner_in_map = m_ring_map[inner.id]; + ring_info_type& inner_in_map = m_ring_map[inner.id]; - if (geometry::within(inner_in_map.point, outer.envelope) - && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection) - ) + if (geometry::within(inner_in_map.point, outer.envelope) + && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection) + ) + { + // Assign a parent if there was no earlier parent, or the newly + // found parent is smaller than the previous one + if (inner_in_map.parent.source_index == -1 + || outer.abs_area < inner_in_map.parent_area) { - // Only assign parent if that parent is smaller (or if it is the first) - if (inner_in_map.parent.source_index == -1 - || outer.abs_area < inner_in_map.parent_area) - { - inner_in_map.parent = outer.id; - inner_in_map.parent_area = outer.abs_area; - } + inner_in_map.parent = outer.id; + inner_in_map.parent_area = outer.abs_area; } } } @@ -288,13 +288,21 @@ inline void assign_parents(Geometry1 const& geometry1, { it->second.discarded = true; } - else if (it->second.parent.source_index >= 0 && it->second.get_area() > 0) + else if (it->second.parent.source_index >= 0 + && math::larger(it->second.get_area(), 0)) { - // Discard positive inner ring with parent - it->second.discarded = true; + const ring_info_type& parent = ring_map[it->second.parent]; + + if (math::larger(parent.area, 0)) + { + // Discard positive inner ring with positive parent + it->second.discarded = true; + } + // Remove parent ID from any positive inner ring it->second.parent.source_index = -1; } - else if (it->second.parent.source_index < 0 && it->second.get_area() < 0) + else if (it->second.parent.source_index < 0 + && math::smaller(it->second.get_area(), 0)) { // Reverse negative ring without parent it->second.reversed = true; @@ -313,6 +321,8 @@ inline void assign_parents(Geometry1 const& geometry1, } } + +// Version for one geometry (called by buffer) template < typename Geometry, @@ -324,7 +334,7 @@ inline void assign_parents(Geometry const& geometry, RingMap& ring_map, bool check_for_orientation) { - // Call it with an empty geometry + // Call it with an empty geometry as second geometry (source_id == 1) // (ring_map should be empty for source_id==1) Geometry empty; diff --git a/test/algorithms/buffer/linestring_buffer.cpp b/test/algorithms/buffer/linestring_buffer.cpp index eaff55e67..bdca6e3d0 100644 --- a/test/algorithms/buffer/linestring_buffer.cpp +++ b/test/algorithms/buffer/linestring_buffer.cpp @@ -64,9 +64,9 @@ void test_all() // test_one("simplex_asym_neg", simplex, join_miter, end_round, 3.202, +1.5, -1.0); // test_one("simplex_asym_pos", simplex, join_miter, end_round, 3.202, -1.0, +1.5); - // Generates a reverse polygon, with a negative area, which will be made empty TODO decide about this - test_one("simplex_asym_neg_rev", simplex, join_miter, end_flat, 0, +1.0, -1.5); - test_one("simplex_asym_pos_rev", simplex, join_miter, end_flat, 0, -1.5, +1.0); + // Generates (initially) a reversed polygon, with a negative area, which is reversed afterwards in assign_parents + test_one("simplex_asym_neg_rev", simplex, join_miter, end_flat, 3.202, +1.0, -1.5); + test_one("simplex_asym_pos_rev", simplex, join_miter, end_flat, 3.202, -1.5, +1.0); test_one("straight", straight, join_round, end_flat, 38.4187, 1.5, 1.5); test_one("straight", straight, join_miter, end_flat, 38.4187, 1.5, 1.5); diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 5fa0a3a68..5001b8ef7 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -217,7 +217,12 @@ static std::string const rt_s2 static std::string const rt_t = "MULTIPOLYGON(((1 3,1 4,2 3,1 3)),((1 4,0 3,0 4,0 5,1 4)))"; +// Creates traversed ring +static std::string const rt_u1 + = "MULTIPOLYGON(((7 6,8 7,8 6,7 6)),((8 9,9 10,9 9,8 9)),((2 8,3 9,3 8,2 8)),((6 5,6 6,7 6,6 5)),((6 7,7 7,6 6,5 6,6 7)),((7 7,7 8,8 7,7 7)),((6 7,6 8,7 8,6 7)),((8 7,8 8,9 8,9 7,8 7)))"; +static std::string const rt_u2 + = "MULTIPOLYGON(((4 2,5 3,5 2,4 2)),((6 4,6 5,7 5,6 4)),((7 4,7 5,8 5,7 4)),((7 3,7 4,8 3,7 3)),((7 10,8 10,7 9,6 9,7 10)),((0 7,0 8,1 7,0 7)),((6 1,6 2,7 2,7 1,6 1)),((5 7,5 8,6 9,6 8,7 9,7 8,7 7,6 6,6 7,5 7)),((5 4,6 4,6 3,5 3,4 3,4 4,5 4)),((5 2,6 2,5 1,4 0,3 0,4 1,3 1,3 2,3 3,4 3,4 2,4.5 1.5,5 2)),((5 6,5 5,4 5,4 6,4 7,5 7,5 6)),((5 0,5 1,5.5 0.5,6 1,6 0,5 0)),((5 9,5 8,4 8,3 8,2 8,1 8,0 8,1 9,1 10,2 9,2 10,3 10,4 10,5 10,5 9)),((4 5,4 4,3 4,3 3,2 3,1 3,0 3,0 4,0 5,0 6,1 6,2 5,1 5,1 4,2 4,3 5,2 5,2 6,2.5 5.5,3 6,4 5)),((3 2,2 2,2 3,3 2)),((2 0,1 0,2 1,3 0,2 0)),((1 1,0 1,0 2,0 3,1 2,1.5 1.5,2 2,3 1,2 1,1 1)),((2 6,1 6,1 7,2 7,3 7,2 6)),((4 8,4 7,3 7,4 8)),((9 6,8 6,7 6,7 7,8 7,8.5 6.5,9 7,8 7,8 8,8.5 7.5,9 8,8 8,8 9,9 9,9 10,10 10,10 9,10 8,10 7,10 6,10 5,9 4,9 5,8 5,9 6)),((7 0,6 0,7 1,8 1,7 0)),((8 3,9 2,8 2,7 2,8 3)),((10 2,10 1,10 0,9 0,9 1,8 1,8 2,8.5 1.5,9 2,9 3,10 4,10 3,10 2)),((9 4,9 3,8 3,8 4,9 4)))"; template @@ -336,8 +341,10 @@ void test_all() test_one("rt_s1", rt_s1, join_miter, end_flat, 20.4853, 1.0); test_one("rt_s2", rt_s2, join_miter, end_flat, 24.6495, 1.0); test_one("rt_t", rt_t, join_miter, end_flat, 15.6569, 1.0); -} + test_one("rt_u1", rt_u1, join_round, end_flat, 33.2032, 1.0); + test_one("rt_u2", rt_u2, join_round, end_flat, 138.8001, 1.0); +} int test_main(int, char* []) { From 468c3dd36a9a38370ed715c74c7fa7513f5886a7 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 00:03:15 +0200 Subject: [PATCH 06/18] [buffer][test] clean up old comments/cases --- test/algorithms/buffer/multi_polygon_buffer.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 5001b8ef7..06feebee2 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -249,9 +249,6 @@ void test_all() test_one("multi_simplex_50", simplex, join_round, end_flat, 174.46, 5.0); test_one("multi_simplex_50", simplex, join_miter, end_flat, 298.797, 5.0); - // This one does not work: - // test_one("multi_simplex_50", simplex, 'd', 174.46, 5.0); - test_one("zonethru_05", zonethru, join_round, end_flat, 67.4627, 0.5); test_one("zonethru_05", zonethru, join_miter, end_flat, 68.0000, 0.5); test_one("zonethru_10", zonethru, join_round, end_flat, 93.8508, 1.0); @@ -265,9 +262,7 @@ void test_all() test_one("wrapped_15", wrapped, join_round, end_flat, 167.066, 1.5); test_one("wrapped_15", wrapped, join_miter, end_flat, 169.000, 1.5); - // TODO: there is still an undetected hole inside rt_a test_one("rt_a", rt_a, join_round, end_flat, 34.5381, 1.0); - test_one("rt_a", rt_a, join_miter, end_flat, 36, 1.0); test_one("rt_b", rt_b, join_round, end_flat, 31.4186, 1.0); test_one("rt_b", rt_b, join_miter, end_flat, 34, 1.0); @@ -277,7 +272,6 @@ void test_all() test_one("rt_d", rt_d, join_miter, end_flat, 19.8823, 0.3); test_one("rt_e", rt_e, join_round, end_flat, 14.1866, 0.3); test_one("rt_e", rt_e, join_miter, end_flat, 15.1198, 0.3); - // This does not add anything: test_one("rt_f", rt_f, join_round, end_flat, 4.28937, 0.3); test_one("rt_f", rt_f, join_miter, end_flat, 4.60853, 0.3); @@ -294,13 +288,11 @@ void test_all() test_one("rt_j", rt_j, join_miter, end_flat, 35.1421, 1.0); test_one("rt_k", rt_k, join_round, end_flat, 42.0092, 1.0); test_one("rt_k", rt_k, join_miter, end_flat, 48.0563, 1.0); - // This does not add anything: test_one("rt_l", rt_l, join_round, end_flat, 14.1074, 1.0); test_one("rt_l", rt_l, join_miter, end_flat, 19.3995, 1.0); test_one("rt_m1", rt_m1, join_round, end_flat, 14.1074, 1.0); test_one("rt_m1", rt_m1, join_miter, end_flat, 19.4853, 1.0); test_one("rt_m2", rt_m2, join_miter, end_flat, 21.4853, 1.0); - // This does not add anything: test_one("rt_n", rt_n, join_round, end_flat, 14.1074, 1.0); test_one("rt_n", rt_n, join_miter, end_flat, 18.4853, 1.0); test_one("rt_o1", rt_o1, join_round, end_flat, 17.536, 1.0); From b469509bd09fcc4753a75db0752d260c3d371b4e Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 12:48:22 +0200 Subject: [PATCH 07/18] [buffer][fix] Fix accidental removal of == 0 --- .../algorithms/detail/buffer/turn_in_piece_visitor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index b4acb0d11..9e652bec5 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -173,9 +173,9 @@ public: } Turn& mutable_turn = m_turns[turn.turn_index]; - if (geometry_code) + if (geometry_code == 0) { - // If it is on the border and they are neighbours, it should be + // If it is on the border and they are not neighbours, it should be // on the offsetted ring if (! on_offsetted(turn.robust_point, piece)) From 6df7738d3a0ec85ab76764381d47ec4829b97973 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 12:49:37 +0200 Subject: [PATCH 08/18] [buffer][fix] Fix turns which were only on helper-segments, they can be discarded. This fixes rt_u3 and rt_u4 where a false interior ring was generated --- .../detail/buffer/buffered_piece_collection.hpp | 5 +++++ test/algorithms/buffer/multi_polygon_buffer.cpp | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index e657ff978..425f14168 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -338,6 +338,10 @@ struct buffered_piece_collection for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { + if (it->count_on_helper > 0) + { + it->location = inside_buffer; + } if (it->count_within > 0) { // Within can have in rare cases a rounding issue. We don't discard this @@ -345,6 +349,7 @@ struct buffered_piece_collection // will never start a new ring from this type of points. it->selectable_start = false; } + } } diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 06feebee2..8bdc8900f 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -224,6 +224,12 @@ static std::string const rt_u1 static std::string const rt_u2 = "MULTIPOLYGON(((4 2,5 3,5 2,4 2)),((6 4,6 5,7 5,6 4)),((7 4,7 5,8 5,7 4)),((7 3,7 4,8 3,7 3)),((7 10,8 10,7 9,6 9,7 10)),((0 7,0 8,1 7,0 7)),((6 1,6 2,7 2,7 1,6 1)),((5 7,5 8,6 9,6 8,7 9,7 8,7 7,6 6,6 7,5 7)),((5 4,6 4,6 3,5 3,4 3,4 4,5 4)),((5 2,6 2,5 1,4 0,3 0,4 1,3 1,3 2,3 3,4 3,4 2,4.5 1.5,5 2)),((5 6,5 5,4 5,4 6,4 7,5 7,5 6)),((5 0,5 1,5.5 0.5,6 1,6 0,5 0)),((5 9,5 8,4 8,3 8,2 8,1 8,0 8,1 9,1 10,2 9,2 10,3 10,4 10,5 10,5 9)),((4 5,4 4,3 4,3 3,2 3,1 3,0 3,0 4,0 5,0 6,1 6,2 5,1 5,1 4,2 4,3 5,2 5,2 6,2.5 5.5,3 6,4 5)),((3 2,2 2,2 3,3 2)),((2 0,1 0,2 1,3 0,2 0)),((1 1,0 1,0 2,0 3,1 2,1.5 1.5,2 2,3 1,2 1,1 1)),((2 6,1 6,1 7,2 7,3 7,2 6)),((4 8,4 7,3 7,4 8)),((9 6,8 6,7 6,7 7,8 7,8.5 6.5,9 7,8 7,8 8,8.5 7.5,9 8,8 8,8 9,9 9,9 10,10 10,10 9,10 8,10 7,10 6,10 5,9 4,9 5,8 5,9 6)),((7 0,6 0,7 1,8 1,7 0)),((8 3,9 2,8 2,7 2,8 3)),((10 2,10 1,10 0,9 0,9 1,8 1,8 2,8.5 1.5,9 2,9 3,10 4,10 3,10 2)),((9 4,9 3,8 3,8 4,9 4)))"; +static std::string const rt_u3 + = "MULTIPOLYGON(((3 0,4 1,4 0,3 0)),((2 0,2 1,3 1,2 0)),((6 7,7 8,7 7,6 7)),((1 2,2 3,2 2,1 2)),((9 1,10 2,10 1,9 1)),((0 2,0 3,1 3,1 2,0 2)),((5 0,5 1,6 1,6 0,5 0)),((1 1,2 2,2 1,1 1)),((0 7,0 8,1 7,0 7)),((9 0,10 1,10 0,9 0)),((0 5,0 6,1 6,1 5,0 5)),((1 6,2 7,2 6,1 6)),((7 0,8 1,8 0,7 0)),((8 6,9 7,9 6,8 6)),((9 6,10 7,10 6,9 6)),((1 4,1 5,2 5,1 4)),((5 6,4 5,4 6,5 7,5 6)),((5 4,4.5 3.5,5 3,4 3,4 2,3 1,3 2,3 3,2 3,2 4,3 4,4 4,5 5,5 4)),((4 7,3 7,3 8,4 9,5 10,6 10,6 9,5 9,4 8,5 8,4 7)),((6 3,5 3,5 4,5.5 3.5,6 4,7 4,7 3,8 3,8 2,8 1,7 1,6 1,6 2,6 3)),((3 5,2 4,2 5,2 6,3 5)),((1 1,1 0,0 0,0 1,1 2,1 1)),((2 9,2 8,1 8,0 8,1 9,1 10,1.5 9.5,2 10,2.5 9.5,3 10,3 9,2 9)),((6 5,6 6,7 7,8 7,8 6,7 6,7 5,6 4,6 5)),((7 8,6 8,6 9,7 9,8 8,7 8)),((9 10,10 10,10 9,10 8,9 7,9 8,8 8,9 9,8 9,8 10,9 10)))"; + +static std::string const rt_u4 + = "MULTIPOLYGON(((5 0,6 1,6 0,5 0)),((6 1,6 2,7 2,7 1,6 1)),((6 6,7 7,7 6,6 6)),((4 7,4 8,5 8,4 7)),((1 6,1 7,2 7,1 6)),((3 4,3 5,4 5,3 4)),((2 0,2 1,3 0,2 0)),((7 2,7 3,8 3,7 2)),((3 3,4 4,4 3,3 3)),((5 9,5 10,6 10,7 10,6 9,5 8,5 9)),((5 4,5 5,6 4,5 4)),((3 1,4 2,4 1,3 1)),((3 0,3 1,4 0,3 0)),((2 7,2 8,3 8,3 7,2 7)),((9 2,9 3,10 2,9 2)),((6 2,6 3,7 3,6 2)),((8 8,9 9,9 8,8 8)),((2 1,2 2,3 2,3 1,2 1)),((4 3,5 4,5 3,4 3)),((4 6,5 7,5 6,4 6)),((1 8,1 9,2 8,1 7,1 8)),((8 8,9 7,8 7,7 7,7 8,8 8)),((8 1,8 2,9 2,9 1,10 1,9 0,8 0,8 1)),((5 2,4 2,4 3,5 2)),((2 5,1 5,1 6,2 6,3 5,2 5)),((1 3,2 4,2 3,2 2,1 1,0 1,1 2,1 3)),((1 0,0 0,1 1,2 1,1.5 0.5,2 0,1 0)),((2 10,3 10,4 10,4 9,3 9,2 8,2 9,1 9,0 9,1 10,2 10)),((9 5,9 6,10 6,10 5,10 4,9 4,8.5 3.5,9 3,8 3,8 4,7 4,7 5,8 5,9 5)),((7 0,6 0,7 1,8 1,7 0)),((7 9,7 8,6 8,6 9,7 9)))"; + template void test_all() @@ -336,6 +342,8 @@ void test_all() test_one("rt_u1", rt_u1, join_round, end_flat, 33.2032, 1.0); test_one("rt_u2", rt_u2, join_round, end_flat, 138.8001, 1.0); + test_one("rt_u3", rt_u3, join_round, end_flat, 133.4526, 1.0); + test_one("rt_u4", rt_u4, join_round, end_flat, 126.9268, 1.0); } int test_main(int, char* []) From 31abd20829dc4dbd394ad10b4cfdac34aa06f40f Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 14:15:04 +0200 Subject: [PATCH 09/18] [buffer][fix] Distinguish between "within" and "within_near_offsetted" The last one might be offsetted by 1 due to integer rounding. It is not selectable as a starting point but may be used for traversal --- .../detail/buffer/buffer_policies.hpp | 4 + .../buffer/buffered_piece_collection.hpp | 4 +- .../detail/buffer/turn_in_piece_visitor.hpp | 87 +++++++++++++++++-- .../buffer/multi_polygon_buffer.cpp | 4 + test/algorithms/buffer/test_buffer.hpp | 6 +- 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp index c37f32fd7..43d54fecf 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_policies.hpp @@ -126,6 +126,9 @@ struct buffer_turn_info int count_within; int count_on_offsetted; int count_on_helper; + int count_within_near_offsetted; + + // Obsolete: int count_on_occupied; int count_on_multi; @@ -135,6 +138,7 @@ struct buffer_turn_info , count_within(0) , count_on_offsetted(0) , count_on_helper(0) + , count_within_near_offsetted(0) , count_on_occupied(0) , count_on_multi(0) {} diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 425f14168..1c082ac98 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -338,11 +338,11 @@ struct buffered_piece_collection for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { - if (it->count_on_helper > 0) + if (it->count_within > 0) { it->location = inside_buffer; } - if (it->count_within > 0) + if (it->count_within_near_offsetted > 0) { // Within can have in rare cases a rounding issue. We don't discard this // point, so it can be used to continue started rings in traversal. But diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index 9e652bec5..d43a01dcf 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -83,6 +83,44 @@ class turn_in_piece_visitor return true; } + // TODO: see comment below, this adaption of distance_projected_point can be removed + template + static inline boost::long_long_type distance_from_segment(Point const& subject, Point const& p, Point const& q) + { + typedef Point vector_type; + typedef typename geometry::coordinate_type::type coordinate_type; + + vector_type v = q; + vector_type w = subject; + subtract_point(v, p); + subtract_point(w, p); + + coordinate_type const zero = coordinate_type(); + coordinate_type const c1 = dot_product(w, v); + + if (c1 < zero) + { + // Any value above 2 is fine in this case + return 99999; + } + coordinate_type const c2 = dot_product(v, v); + if (c2 < c1 || c2 <= zero) + { + return 99999; + } + + multiply_value(v, c1); + divide_value(v, c2); + + Point projected = p; + subtract_point(v, projected); + subtract_point(w, projected); + + add_point(projected, v); + + return dot_product(subject, projected); + } + template inline bool on_offsetted(Point const& point, Piece const& piece) const @@ -105,11 +143,37 @@ class turn_in_piece_visitor return true; } } - } return false; } + template + inline boost::long_long_type + comparable_distance_from_offsetted(Point const& point, Piece const& piece) const + { + // TODO: replace this by the code below if that is fixed for boost::long_long_type + // with these contents of values + boost::long_long_type result = 0; + for (int i = 1; i < piece.offsetted_count; i++) + { + Point const& previous = piece.robust_ring[i - 1]; + Point const& current = piece.robust_ring[i]; + boost::long_long_type dist = distance_from_segment(point, previous, current); + if (i == 1 || dist < result) + { + result = dist; + } + } + return result; + + /* + geometry::model::linestring ls; + std::copy(piece.robust_ring.begin(), piece.robust_ring.begin() + piece.offsetted_count, std::back_inserter(ls)); + typename default_comparable_distance_result::type + const result = geometry::comparable_distance(point, ls); + return result; + */ + } public: @@ -184,14 +248,27 @@ public: // Then it is somewhere on the helper-segments // Classify it as inside geometry_code = 1; - mutable_turn.count_on_helper++; + mutable_turn.count_on_helper++; // can still become "near_offsetted" + } + else + { + mutable_turn.count_on_offsetted++; // value is not used anymore } } - switch (geometry_code) + if (geometry_code == 1) { - case 1 : mutable_turn.count_within++; break; - case 0 : mutable_turn.count_on_offsetted++; break; + if (comparable_distance_from_offsetted(turn.robust_point, piece) >= 2) + { + // This is too far from the border, it counts as really inside + mutable_turn.count_within++; + } + else + { + // Other points count as still "on border" because they might be + // travelled through, but not used as starting point + mutable_turn.count_within_near_offsetted++; + } } } }; diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 8bdc8900f..4e1a73cfb 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -230,6 +230,9 @@ static std::string const rt_u3 static std::string const rt_u4 = "MULTIPOLYGON(((5 0,6 1,6 0,5 0)),((6 1,6 2,7 2,7 1,6 1)),((6 6,7 7,7 6,6 6)),((4 7,4 8,5 8,4 7)),((1 6,1 7,2 7,1 6)),((3 4,3 5,4 5,3 4)),((2 0,2 1,3 0,2 0)),((7 2,7 3,8 3,7 2)),((3 3,4 4,4 3,3 3)),((5 9,5 10,6 10,7 10,6 9,5 8,5 9)),((5 4,5 5,6 4,5 4)),((3 1,4 2,4 1,3 1)),((3 0,3 1,4 0,3 0)),((2 7,2 8,3 8,3 7,2 7)),((9 2,9 3,10 2,9 2)),((6 2,6 3,7 3,6 2)),((8 8,9 9,9 8,8 8)),((2 1,2 2,3 2,3 1,2 1)),((4 3,5 4,5 3,4 3)),((4 6,5 7,5 6,4 6)),((1 8,1 9,2 8,1 7,1 8)),((8 8,9 7,8 7,7 7,7 8,8 8)),((8 1,8 2,9 2,9 1,10 1,9 0,8 0,8 1)),((5 2,4 2,4 3,5 2)),((2 5,1 5,1 6,2 6,3 5,2 5)),((1 3,2 4,2 3,2 2,1 1,0 1,1 2,1 3)),((1 0,0 0,1 1,2 1,1.5 0.5,2 0,1 0)),((2 10,3 10,4 10,4 9,3 9,2 8,2 9,1 9,0 9,1 10,2 10)),((9 5,9 6,10 6,10 5,10 4,9 4,8.5 3.5,9 3,8 3,8 4,7 4,7 5,8 5,9 5)),((7 0,6 0,7 1,8 1,7 0)),((7 9,7 8,6 8,6 9,7 9)))"; +static std::string const rt_u5 + = "MULTIPOLYGON(((4 3,4 4,5 4,5 3,4 3)),((6 5,6 6,7 6,6 5)),((5 4,6 5,6 4,5 4)),((4 0,4 1,5 1,5 0,4 0)),((7 8,8 9,8 8,7 8)),((8 2,8 3,9 3,8 2)),((2 1,2 2,3 1,2 1)),((5 7,5 8,6 8,5 7)),((4 5,4 6,5 5,4 5)),((7 0,8 1,8 0,7 0)),((7 2,8 1,7 1,6 1,7 2)),((3 3,4 3,4 2,3 2,3 3)),((3 9,3 10,4 9,3 9)),((1 2,2 3,2 2,1 2)),((2 4,2 5,3 4,2 3,2 4)),((3 7,4 7,3 6,2 6,3 7)))"; + template void test_all() @@ -344,6 +347,7 @@ void test_all() test_one("rt_u2", rt_u2, join_round, end_flat, 138.8001, 1.0); test_one("rt_u3", rt_u3, join_round, end_flat, 133.4526, 1.0); test_one("rt_u4", rt_u4, join_round, end_flat, 126.9268, 1.0); + test_one("rt_u5", rt_u5, join_round, end_flat, 78.4906, 1.0); } int test_main(int, char* []) diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index cd6685d95..16b76d144 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -138,10 +138,10 @@ struct svg_visitor out << " " << bg::method_char(it->method) << ":" << bg::operation_char(it->operations[0].operation) << "/" << bg::operation_char(it->operations[1].operation); - out << " " << (!it->selectable_start ? "w" : "") - << (it->count_on_multi > 0 ? "m" : "") - << (it->count_on_occupied > 0 ? "o" : "") + out << " " << (it->count_on_offsetted > 0 ? "b" : "") // b: offsetted border + << (it->count_within_near_offsetted > 0 ? "n" : "") + << (it->count_within > 0 ? "w" : "") << (it->count_on_helper > 0 ? "h" : "") ; From a7764c1b9ea9455a77b55b49f9ae024adbbfda1a Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 15:32:07 +0200 Subject: [PATCH 10/18] [buffer][fix] use taxicab distance instead of comparable distance This is faster and avoids overflows. This fixes rt_u6 --- .../detail/buffer/turn_in_piece_visitor.hpp | 40 +++++++++++++------ .../buffer/multi_polygon_buffer.cpp | 5 +++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index d43a01dcf..fa08c9cd2 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -56,6 +56,8 @@ class turn_in_piece_visitor Turns& m_turns; // because partition is currently operating on const input only Pieces const& m_pieces; // to check for piece-type + typedef boost::long_long_type calculation_type; + template static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q) { @@ -83,9 +85,17 @@ class turn_in_piece_visitor return true; } + template + static inline calculation_type taxicab_distance(Point const& p, Point const& q) + { + return math::abs(geometry::get<0>(p) - geometry::get<0>(q)) + + math::abs(geometry::get<1>(p) - geometry::get<1>(q)); + } + + // TODO: see comment below, this adaption of distance_projected_point can be removed template - static inline boost::long_long_type distance_from_segment(Point const& subject, Point const& p, Point const& q) + static inline calculation_type taxicab_distance_from_segment(Point const& subject, Point const& p, Point const& q) { typedef Point vector_type; typedef typename geometry::coordinate_type::type coordinate_type; @@ -98,15 +108,14 @@ class turn_in_piece_visitor coordinate_type const zero = coordinate_type(); coordinate_type const c1 = dot_product(w, v); - if (c1 < zero) + if (c1 <= zero) { - // Any value above 2 is fine in this case - return 99999; + return taxicab_distance(subject, p); } coordinate_type const c2 = dot_product(v, v); - if (c2 < c1 || c2 <= zero) + if (c2 <= c1) { - return 99999; + return taxicab_distance(subject, q); } multiply_value(v, c1); @@ -118,7 +127,9 @@ class turn_in_piece_visitor add_point(projected, v); - return dot_product(subject, projected); + // The dot-product still overflows for boost::long_long_type with + // these values (should not occur, TODO: fix this) + return taxicab_distance(subject, projected); } @@ -148,17 +159,18 @@ class turn_in_piece_visitor } template - inline boost::long_long_type - comparable_distance_from_offsetted(Point const& point, Piece const& piece) const + inline calculation_type + taxicab_distance_from_offsetted(Point const& point, Piece const& piece) const { // TODO: replace this by the code below if that is fixed for boost::long_long_type // with these contents of values - boost::long_long_type result = 0; + calculation_type result = 0; for (int i = 1; i < piece.offsetted_count; i++) { Point const& previous = piece.robust_ring[i - 1]; Point const& current = piece.robust_ring[i]; - boost::long_long_type dist = distance_from_segment(point, previous, current); + calculation_type const dist + = taxicab_distance_from_segment(point, previous, current); if (i == 1 || dist < result) { result = dist; @@ -258,9 +270,11 @@ public: if (geometry_code == 1) { - if (comparable_distance_from_offsetted(turn.robust_point, piece) >= 2) + calculation_type const distance + = taxicab_distance_from_offsetted(turn.robust_point, piece); + if (distance >= 2) { - // This is too far from the border, it counts as really inside + // This is too far from the border, it counts as "really within" mutable_turn.count_within++; } else diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 4e1a73cfb..e6293b62f 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -233,6 +233,10 @@ static std::string const rt_u4 static std::string const rt_u5 = "MULTIPOLYGON(((4 3,4 4,5 4,5 3,4 3)),((6 5,6 6,7 6,6 5)),((5 4,6 5,6 4,5 4)),((4 0,4 1,5 1,5 0,4 0)),((7 8,8 9,8 8,7 8)),((8 2,8 3,9 3,8 2)),((2 1,2 2,3 1,2 1)),((5 7,5 8,6 8,5 7)),((4 5,4 6,5 5,4 5)),((7 0,8 1,8 0,7 0)),((7 2,8 1,7 1,6 1,7 2)),((3 3,4 3,4 2,3 2,3 3)),((3 9,3 10,4 9,3 9)),((1 2,2 3,2 2,1 2)),((2 4,2 5,3 4,2 3,2 4)),((3 7,4 7,3 6,2 6,3 7)))"; +static std::string const rt_u6 + = "MULTIPOLYGON(((2 2,3 3,3 2,2 2)),((9 8,9 9,10 9,10 8,9 8)),((5 3,6 4,6 3,5 3)),((5 5,5 6,6 6,5 5)),((5 1,6 2,6 1,5 1)),((6 5,7 6,7 5,6 5)),((3 0,4 1,4 0,3 0)),((6 6,6 7,7 6,6 6)),((9 2,10 2,10 1,9 1,9 2)),((6 8,6 9,7 9,7 8,6 8)),((7 0,7 1,8 0,7 0)),((4 4,4 5,5 5,4 4)),((0 7,0 8,1 8,0 7)),((5 9,6 10,6 9,5 9)),((4 9,4 10,5 10,5 9,4 9)),((3 7,4 7,3 6,2 6,3 7)),((9 7,10 6,9 6,8 6,9 7)),((5 3,5 2,4 2,4 3,4 4,5 4,5 3)),((1 1,2 0,1 0,0 0,1 1)),((2 10,3 10,3 9,2 9,1 9,1 10,2 10)),((8.5 4.5,9 4,8 4,7 4,8 5,9 5,8.5 4.5)),((8 3,9 3,9 2,8 2,8 3)))"; + + template void test_all() @@ -348,6 +352,7 @@ void test_all() test_one("rt_u3", rt_u3, join_round, end_flat, 133.4526, 1.0); test_one("rt_u4", rt_u4, join_round, end_flat, 126.9268, 1.0); test_one("rt_u5", rt_u5, join_round, end_flat, 78.4906, 1.0); + test_one("rt_u6", rt_u6, join_round, end_flat, 115.4461, 1.0); } int test_main(int, char* []) From 9c3ca1e69abef49b5b6f973de646bfb56600a870 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 15:32:46 +0200 Subject: [PATCH 11/18] [buffer][test] improve piece labelling on round joins --- test/algorithms/buffer/test_buffer.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index 16b76d144..a7d629779 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -208,10 +208,11 @@ struct svg_visitor std::ostringstream out; out << piece.index << "/" << int(piece.type) << "/" << piece.first_seg_id.segment_index << ".." << piece.last_segment_index - 1; point_type label_point = corner.front(); - if (corner.size() >= 2) + int const mid_offset = piece.offsetted_count / 2 - 1; + if (mid_offset >= 0 && mid_offset + 1 < corner.size()) { - bg::set<0>(label_point, (bg::get<0>(corner[0]) + bg::get<0>(corner[1])) / 2.0); - bg::set<1>(label_point, (bg::get<1>(corner[0]) + bg::get<1>(corner[1])) / 2.0); + bg::set<0>(label_point, (bg::get<0>(corner[mid_offset]) + bg::get<0>(corner[mid_offset + 1])) / 2.0); + bg::set<1>(label_point, (bg::get<1>(corner[mid_offset]) + bg::get<1>(corner[mid_offset + 1])) / 2.0); } m_mapper.text(label_point, out.str(), "fill:rgb(255,0,0);font-family='Arial';font-size:10px;", 5, 5); } From f98549f82d0278b982cbeed27dd506acc03bca17 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 15:34:33 +0200 Subject: [PATCH 12/18] [buffer][test] Minor change in comments/whitespace --- test/algorithms/buffer/multi_polygon_buffer.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index e6293b62f..94fdd18dc 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -24,7 +24,7 @@ static std::string const wrapped static std::string const triangles = "MULTIPOLYGON(((0 4,3 0,-2.5 -1,0 4)),((3 8,5.5 13,8 8,3 8)),((11 4,13.5 -1,8 0,11 4)))"; -// From robustness tests +// From robustness tests (rt) // Case with duplicate points (due to chained boxes) (round) static std::string const rt_a @@ -89,7 +89,6 @@ static std::string const rt_m1 static std::string const rt_m2 = "MULTIPOLYGON(((0 3,1 4,1 3,0 3)),((3 6,4 7,4 6,4 5,3 5,3 6)))"; - // Segment-intersection problem (disjoint nearly collinear segments were reported as intersecting), fixed. static std::string const rt_n = "MULTIPOLYGON(((0 0,1 1,1 0,0 0)),((3 3,4 4,4 3,3 3)))"; @@ -188,11 +187,9 @@ static std::string const rt_p20 static std::string const rt_p21 = "MULTIPOLYGON(((4 2,4 3,5 3,4 2)),((4 1,5 2,5 1,4 1)),((5 2,6 3,6 2,5 2)))"; - static std::string const rt_p22 = "MULTIPOLYGON(((4 8,5 9,5 8,4 8)),((5 9,6 10,6 9,5 9)),((1 7,1 8,2 8,2 7,1 7)),((2 6,3 7,3 6,2 6)))"; - // Occupation map with a uu-turn static std::string const rt_q1 = "MULTIPOLYGON(((4 6,4 7,5 7,5 6,4 6)),((1 6,1 7,2 7,2 6,1 6)),((1 9,1 10,2 10,2 9,1 9)))"; From 1830208b74822f88ec83714ce3aba2578dd9680b Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 19:21:21 +0200 Subject: [PATCH 13/18] [buffer][test] Add rt_u7 which is currently failing because of tripled IP, needing get_left_turn info again. Added debug info --- .../buffer/multi_polygon_buffer.cpp | 13 +++++++++++- test/algorithms/buffer/test_buffer.hpp | 20 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 94fdd18dc..c86c75a6a 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -233,7 +233,10 @@ static std::string const rt_u5 static std::string const rt_u6 = "MULTIPOLYGON(((2 2,3 3,3 2,2 2)),((9 8,9 9,10 9,10 8,9 8)),((5 3,6 4,6 3,5 3)),((5 5,5 6,6 6,5 5)),((5 1,6 2,6 1,5 1)),((6 5,7 6,7 5,6 5)),((3 0,4 1,4 0,3 0)),((6 6,6 7,7 6,6 6)),((9 2,10 2,10 1,9 1,9 2)),((6 8,6 9,7 9,7 8,6 8)),((7 0,7 1,8 0,7 0)),((4 4,4 5,5 5,4 4)),((0 7,0 8,1 8,0 7)),((5 9,6 10,6 9,5 9)),((4 9,4 10,5 10,5 9,4 9)),((3 7,4 7,3 6,2 6,3 7)),((9 7,10 6,9 6,8 6,9 7)),((5 3,5 2,4 2,4 3,4 4,5 4,5 3)),((1 1,2 0,1 0,0 0,1 1)),((2 10,3 10,3 9,2 9,1 9,1 10,2 10)),((8.5 4.5,9 4,8 4,7 4,8 5,9 5,8.5 4.5)),((8 3,9 3,9 2,8 2,8 3)))"; - +// For this case (and more), get_left_turns or using a more specific sort order is essential +static std::string const rt_u7 + = "MULTIPOLYGON(((4 5,4 6,5 5,4 5)),((9 2,9 3,10 3,10 2,9 2)),((7 3,7 4,8 4,8 3,7 3)),((5 5,6 6,6 5,5 5)),((3 6,4 7,4 6,3 6)),((0 5,0 6,1 5,0 5)))"; + // = "MULTIPOLYGON(((4 5,4 6,5 5,4 5)),((9 2,9 3,10 3,10 2,9 2)),((7 3,7 4,8 4,8 3,7 3)),((5 5,6 6,6 5,5 5)),((3 6,4 7,4 6,3 6)))"; //removing the leftmost uninvolved polygon solves somehow the problem... template void test_all() @@ -350,6 +353,12 @@ void test_all() test_one("rt_u4", rt_u4, join_round, end_flat, 126.9268, 1.0); test_one("rt_u5", rt_u5, join_round, end_flat, 78.4906, 1.0); test_one("rt_u6", rt_u6, join_round, end_flat, 115.4461, 1.0); +#if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS) + { + bg::strategy::buffer::join_round join_round_rough(12); // temporary + test_one("rt_u7", rt_u7, join_round_rough, end_flat, 999, 1.0); + } +#endif } int test_main(int, char* []) @@ -360,3 +369,5 @@ int test_main(int, char* []) return 0; } +// intersecting: +//= "MULTIPOLYGON(((8 6,9 7,9 6,8 6)),((0 6,0 7,1 6,0 6)),((1 6,1 7,2 7,2 6,1 6)),((2 0,2 1,3 0,2 0)),((9 2,10 3,10 2,9 2)),((7 0,7 1,8 1,7 0)),((4 6,5 7,5 6,4 6)),((7 1,7 2,8 2,7 1)),((0 8,0 9,1 8,0 8)),((0 1,0 2,1 2,0 1)),((7 2,7 3,8 3,7 2)),((9 8,9 9,10 8,9 8)),((5 2,5 3,6 3,6 2,5 2)),((1 1,1 2,2 2,2 1,1 1)),((5 3,4 2,4 3,5 4,6 5,6 6,6 7,7 7,7 6,8 6,7 5,8 4,7 4,6 4,5 3)),((3 4,2 4,2 5,2 6,3 6,3 5,4 5,3 4)),((3 7,2 7,2 8,3 8,4 8,5 8,4 7,3 7)))"; diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index a7d629779..6a8b9932d 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -111,8 +111,9 @@ struct svg_visitor std::map > offsets; + int index = 0; for (typename boost::range_iterator::type it = - boost::begin(turns); it != boost::end(turns); ++it) + boost::begin(turns); it != boost::end(turns); ++it, index++) { char color = 'g'; std::string fill = "fill:rgb(0,255,0);"; @@ -132,8 +133,22 @@ struct svg_visitor fill += "fill-opacity:0.7;"; std::ostringstream out; - out << it->operations[0].piece_index << "/" << it->operations[1].piece_index + out << index + << " " << it->operations[0].piece_index << "/" << it->operations[1].piece_index << " " << si(it->operations[0].seg_id) << "/" << si(it->operations[1].seg_id) + +// If you want to see travel information + << std::endl + << " nxt " << it->operations[0].enriched.travels_to_ip_index + << "/" << it->operations[1].enriched.travels_to_ip_index + << " or " << it->operations[0].enriched.next_ip_index + << "/" << it->operations[1].enriched.next_ip_index + //<< " frac " << it->operations[0].fraction + +// If you want to see robust-point coordinates (e.g. to find duplicates) +// << std::endl +// << " " << bg::get<0>(it->robust_point) << " , " << bg::get<1>(it->robust_point) + << std::endl; out << " " << bg::method_char(it->method) << ":" << bg::operation_char(it->operations[0].operation) @@ -143,6 +158,7 @@ struct svg_visitor << (it->count_within_near_offsetted > 0 ? "n" : "") << (it->count_within > 0 ? "w" : "") << (it->count_on_helper > 0 ? "h" : "") + << (it->count_on_multi > 0 ? "m" : "") ; offsets[it->get_robust_point()] += 10; From 024b131f1ecfdcd595f6eddc30e213b10d093268 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Mon, 11 Aug 2014 12:19:33 +0200 Subject: [PATCH 14/18] [buffer] removed wrong comments --- .../algorithms/detail/buffer/turn_in_piece_visitor.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index fa08c9cd2..ce8783adf 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -127,8 +127,6 @@ class turn_in_piece_visitor add_point(projected, v); - // The dot-product still overflows for boost::long_long_type with - // these values (should not occur, TODO: fix this) return taxicab_distance(subject, projected); } @@ -162,8 +160,6 @@ class turn_in_piece_visitor inline calculation_type taxicab_distance_from_offsetted(Point const& point, Piece const& piece) const { - // TODO: replace this by the code below if that is fixed for boost::long_long_type - // with these contents of values calculation_type result = 0; for (int i = 1; i < piece.offsetted_count; i++) { From 446b4494cfee5e715fecb5d29667290938d0db02 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Mon, 11 Aug 2014 12:25:05 +0200 Subject: [PATCH 15/18] [buffer] remove taxicab distance, comparable distance is OK --- .../detail/buffer/turn_in_piece_visitor.hpp | 84 ++++--------------- 1 file changed, 15 insertions(+), 69 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index ce8783adf..97463cacd 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -19,6 +19,9 @@ #include #include +#include +#include + namespace boost { namespace geometry { @@ -85,52 +88,6 @@ class turn_in_piece_visitor return true; } - template - static inline calculation_type taxicab_distance(Point const& p, Point const& q) - { - return math::abs(geometry::get<0>(p) - geometry::get<0>(q)) - + math::abs(geometry::get<1>(p) - geometry::get<1>(q)); - } - - - // TODO: see comment below, this adaption of distance_projected_point can be removed - template - static inline calculation_type taxicab_distance_from_segment(Point const& subject, Point const& p, Point const& q) - { - typedef Point vector_type; - typedef typename geometry::coordinate_type::type coordinate_type; - - vector_type v = q; - vector_type w = subject; - subtract_point(v, p); - subtract_point(w, p); - - coordinate_type const zero = coordinate_type(); - coordinate_type const c1 = dot_product(w, v); - - if (c1 <= zero) - { - return taxicab_distance(subject, p); - } - coordinate_type const c2 = dot_product(v, v); - if (c2 <= c1) - { - return taxicab_distance(subject, q); - } - - multiply_value(v, c1); - divide_value(v, c2); - - Point projected = p; - subtract_point(v, projected); - subtract_point(w, projected); - - add_point(projected, v); - - return taxicab_distance(subject, projected); - } - - template inline bool on_offsetted(Point const& point, Piece const& piece) const { @@ -157,30 +114,19 @@ class turn_in_piece_visitor } template - inline calculation_type - taxicab_distance_from_offsetted(Point const& point, Piece const& piece) const + static inline + calculation_type comparable_distance_from_offsetted(Point const& point, + Piece const& piece) { - calculation_type result = 0; - for (int i = 1; i < piece.offsetted_count; i++) - { - Point const& previous = piece.robust_ring[i - 1]; - Point const& current = piece.robust_ring[i]; - calculation_type const dist - = taxicab_distance_from_segment(point, previous, current); - if (i == 1 || dist < result) - { - result = dist; - } - } - return result; - - /* + // TODO: pass subrange to dispatch to avoid making copy geometry::model::linestring ls; - std::copy(piece.robust_ring.begin(), piece.robust_ring.begin() + piece.offsetted_count, std::back_inserter(ls)); + std::copy(piece.robust_ring.begin(), + piece.robust_ring.begin() + piece.offsetted_count, + std::back_inserter(ls)); typename default_comparable_distance_result::type - const result = geometry::comparable_distance(point, ls); - return result; - */ + const comp = geometry::comparable_distance(point, ls); + + return static_cast(comp); } public: @@ -267,8 +213,8 @@ public: if (geometry_code == 1) { calculation_type const distance - = taxicab_distance_from_offsetted(turn.robust_point, piece); - if (distance >= 2) + = comparable_distance_from_offsetted(turn.robust_point, piece); + if (distance >= 4) { // This is too far from the border, it counts as "really within" mutable_turn.count_within++; From c42aeb44472b76d849c792d0b8922e406ab83210 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 27 Aug 2014 12:27:57 +0200 Subject: [PATCH 16/18] [buffer][fix] fix neighbour check in calculating turns. This fixes ticket 10398 --- .../detail/buffer/get_piece_turns.hpp | 11 ++------ test/algorithms/buffer/polygon_buffer.cpp | 27 +++++++++---------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp index e3c41a2a4..b2b974806 100644 --- a/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -56,7 +56,6 @@ class piece_turn_visitor Rings const& m_rings; Turns& m_turns; RobustPolicy const& m_robust_policy; - int m_last_piece_index; template inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const @@ -66,14 +65,8 @@ class piece_turn_visitor return false; } - if (std::abs(piece1.index - piece2.index) == 1) - { - return true; - } - - return (piece1.index == 0 && piece2.index == m_last_piece_index) - || (piece1.index == m_last_piece_index && piece2.index == 0) - ; + return piece1.index == piece2.left_index + || piece1.index == piece2.right_index; } template diff --git a/test/algorithms/buffer/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index 173c4316b..514a019ca 100644 --- a/test/algorithms/buffer/polygon_buffer.cpp +++ b/test/algorithms/buffer/polygon_buffer.cpp @@ -324,24 +324,21 @@ void test_all() test_one("donut_simplex6", donut_simplex, join_miter, end_flat, 12.8920, -0.6); test_one("donut_simplex6", donut_simplex, join_round, end_flat, 12.9157, -0.6); -#if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS) - // Areas yet to be changed - test_one("ticket_10398_1_5", ticket_10398_1, join_miter, end_flat, 99, 0.5); - test_one("ticket_10398_1_25", ticket_10398_1, join_miter, end_flat, 99, 2.5); - test_one("ticket_10398_1_84", ticket_10398_1, join_miter, end_flat, 99, 8.4); + test_one("ticket_10398_1_5", ticket_10398_1, join_miter, end_flat, 494.7192, 0.5, -999, false); + test_one("ticket_10398_1_25", ticket_10398_1, join_miter, end_flat, 697.7798, 2.5, -999, false); + test_one("ticket_10398_1_84", ticket_10398_1, join_miter, end_flat, 1470.8096, 8.4, -999, false); - test_one("ticket_10398_2_45", ticket_10398_2, join_miter, end_flat, 99, 4.5); - test_one("ticket_10398_2_62", ticket_10398_2, join_miter, end_flat, 99, 6.2); - test_one("ticket_10398_2_73", ticket_10398_2, join_miter, end_flat, 99, 7.3); + test_one("ticket_10398_2_45", ticket_10398_2, join_miter, end_flat, 535.4780, 4.5, -999, false); + test_one("ticket_10398_2_62", ticket_10398_2, join_miter, end_flat, 705.2046, 6.2, -999, false); + test_one("ticket_10398_2_73", ticket_10398_2, join_miter, end_flat, 827.3394, 7.3, -999, false); - test_one("ticket_10398_3_12", ticket_10398_3, join_miter, end_flat, 99, 1.2); - test_one("ticket_10398_3_35", ticket_10398_3, join_miter, end_flat, 99, 3.5); - test_one("ticket_10398_3_54", ticket_10398_3, join_miter, end_flat, 99, 5.4); + test_one("ticket_10398_3_12", ticket_10398_3, join_miter, end_flat, 122.9443, 1.2, -999, false); + test_one("ticket_10398_3_35", ticket_10398_3, join_miter, end_flat, 258.2729, 3.5, -999, false); + test_one("ticket_10398_3_54", ticket_10398_3, join_miter, end_flat, 402.0571, 5.4, -999, false); - test_one("ticket_10398_4_30", ticket_10398_4, join_miter, end_flat, 99, 3.0); - test_one("ticket_10398_4_66", ticket_10398_4, join_miter, end_flat, 99, 6.6); - test_one("ticket_10398_4_91", ticket_10398_4, join_miter, end_flat, 99, 9.1); -#endif + test_one("ticket_10398_4_30", ticket_10398_4, join_miter, end_flat, 257.9482, 3.0, -999, false); + test_one("ticket_10398_4_66", ticket_10398_4, join_miter, end_flat, 553.0112, 6.6, -999, false); + test_one("ticket_10398_4_91", ticket_10398_4, join_miter, end_flat, 819.1406, 9.1, -999, false); } From 02ae40805c55c43835adea70ae666f6dcd5e1cf4 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 27 Aug 2014 12:28:44 +0200 Subject: [PATCH 17/18] [buffer] remove now redundant member m_last_piece_index --- .../algorithms/detail/buffer/buffered_piece_collection.hpp | 2 +- .../geometry/algorithms/detail/buffer/get_piece_turns.hpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 1c082ac98..97a20ebe2 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -529,7 +529,7 @@ struct buffered_piece_collection buffered_ring_collection >, turn_vector_type, RobustPolicy - > visitor(offsetted_rings, m_turns, m_robust_policy, m_pieces.size()); + > visitor(offsetted_rings, m_turns, m_robust_policy); geometry::partition < diff --git a/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp index b2b974806..23b09e1c8 100644 --- a/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -164,12 +164,10 @@ public: piece_turn_visitor(Rings const& ring_collection, Turns& turns, - RobustPolicy const& robust_policy, - int last_piece_index) + RobustPolicy const& robust_policy) : m_rings(ring_collection) , m_turns(turns) , m_robust_policy(robust_policy) - , m_last_piece_index(last_piece_index) {} template From 14c31c31f09ea337c9c4130a50a66670e5465d42 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 27 Aug 2014 12:33:48 +0200 Subject: [PATCH 18/18] [doc] add fixed ticket to release notes --- doc/release_notes.qbk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 19f9187c4..40f4939be 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -23,6 +23,8 @@ [*Solved tickets] +* [@https://svn.boost.org/trac/boost/ticket/10398 10398] Wrong neighbour check in buffer, calculating turns + [*Bugfixes] [/=================]