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* []) {