diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index dfa54bf2e..acea1259c 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -639,7 +639,8 @@ private: JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + bool is_interior) { for (Iterator it = begin; it != end; ++it) { @@ -647,7 +648,7 @@ private: policy::apply(*it, collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy); - collection.finish_ring(); + collection.finish_ring(is_interior); } } @@ -675,7 +676,7 @@ private: iterate(boost::begin(interior_rings), boost::end(interior_rings), collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy); + robust_policy, true); } public: @@ -776,6 +777,12 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator collection_type collection(robust_policy); collection_type const& const_collection = collection; + bool const areal = boost::is_same + < + typename tag_cast::type, areal_tag>::type, + areal_tag + >::type::value; + dispatch::buffer_inserter < typename tag_cast @@ -790,7 +797,11 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator end_strategy, point_strategy, robust_policy); - collection.get_turns(geometry_input, distance_strategy); + collection.get_turns(); + if (areal) + { + collection.check_remaining_points(distance_strategy.factor()); + } // Visit the piece collection. This does nothing (by default), but // optionally a debugging tool can be attached (e.g. console or svg), @@ -803,12 +814,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator collection.enrich(); collection.traverse(); - if (distance_strategy.negative() - && boost::is_same - < - typename tag_cast::type, areal_tag>::type, - areal_tag - >::type::value) + if (distance_strategy.negative() && areal) { collection.reverse(); } 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 9a0dee607..c0c5760dc 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -24,12 +24,12 @@ #include #include +#include #include #include #include #include -#include #include #include @@ -74,6 +74,8 @@ struct buffered_piece_collection point_type, RobustPolicy >::type robust_point_type; + typedef geometry::model::ring robust_ring_type; + typedef geometry::model::polygon robust_polygon_type; typedef typename strategy::side::services::default_strategy < @@ -139,7 +141,7 @@ struct buffered_piece_collection // Robust representations // 3: complete ring - geometry::model::ring robust_ring; + robust_ring_type robust_ring; geometry::model::box robust_envelope; @@ -153,6 +155,8 @@ struct buffered_piece_collection int m_first_piece_index; buffered_ring_collection > offsetted_rings; // indexed by multi_index + buffered_ring_collection robust_polygons; // robust representation of the original(s) + robust_ring_type current_robust_ring; buffered_ring_collection traversed_rings; segment_identifier current_segment_id; @@ -359,22 +363,24 @@ struct buffered_piece_collection } } - template - inline void check_remaining_points(Geometry const& input_geometry, DistanceStrategy const& distance_strategy) + inline void check_remaining_points(int factor) { - int const factor = distance_strategy.factor(); - - // This might use partition too (for multi-polygons) + // TODO: use partition for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { if (it->location == location_ok) { - int code = turn_in_input - < - typename geometry::tag::type - >::apply(it->point, input_geometry); + int code = -1; + for (std::size_t i = 0; i < robust_polygons.size(); i++) + { + if (geometry::covered_by(it->robust_point, robust_polygons[i])) + { + code = 1; + break; + } + } if (code * factor == 1) { it->location = inside_original; @@ -476,8 +482,7 @@ struct buffered_piece_collection BOOST_ASSERT(assert_indices_in_robust_rings()); } - template - inline void get_turns(Geometry const& input_geometry, DistanceStrategy const& distance_strategy) + inline void get_turns() { { // Calculate the turns @@ -512,12 +517,7 @@ struct buffered_piece_collection } - - //get_occupation(); - classify_turns(); - - check_remaining_points(input_geometry, distance_strategy); } inline void start_new_ring() @@ -529,11 +529,12 @@ struct buffered_piece_collection current_segment_id.segment_index = 0; offsetted_rings.resize(n + 1); + current_robust_ring.clear(); m_first_piece_index = boost::size(m_pieces); } - inline void finish_ring() + inline void finish_ring(bool is_interior = false) { BOOST_ASSERT(m_first_piece_index != -1); if (m_first_piece_index < static_cast(boost::size(m_pieces))) @@ -545,6 +546,24 @@ struct buffered_piece_collection geometry::range::back(m_pieces).right_index = m_first_piece_index; } m_first_piece_index = -1; + + if (!current_robust_ring.empty()) + { + BOOST_ASSERT(geometry::equals(current_robust_ring.front(), current_robust_ring.back())); + + if (is_interior) + { + if (!robust_polygons.empty()) + { + robust_polygons.back().inners().push_back(current_robust_ring); + } + } + else + { + robust_polygons.resize(robust_polygons.size() + 1); + robust_polygons.back().outer() = current_robust_ring; + } + } } inline int add_point(point_type const& p) @@ -602,7 +621,7 @@ struct buffered_piece_collection } } - inline void add_helper_point(piece& pc, const point_type& point) + inline robust_point_type add_helper_point(piece& pc, const point_type& point) { #if defined(BOOST_GEOMETRY_BUFFER_USE_HELPER_POINTS) pc.helper_points.push_back(point); @@ -611,6 +630,7 @@ struct buffered_piece_collection robust_point_type rob_point; geometry::recalculate(rob_point, point, m_robust_policy); pc.robust_ring.push_back(rob_point); + return rob_point; } inline void calculate_robust_envelope(piece& pc) @@ -632,9 +652,11 @@ struct buffered_piece_collection { init_rescale_piece(pc, 3u); add_helper_point(pc, point1); - add_helper_point(pc, point2); + robust_point_type mid_point = add_helper_point(pc, point2); add_helper_point(pc, point3); calculate_robust_envelope(pc); + + current_robust_ring.push_back(mid_point); } inline void finish_piece(piece& pc, @@ -645,10 +667,14 @@ struct buffered_piece_collection { init_rescale_piece(pc, 4u); add_helper_point(pc, point1); - add_helper_point(pc, point2); - add_helper_point(pc, point3); + robust_point_type mid_point2 = add_helper_point(pc, point2); + robust_point_type mid_point1 = add_helper_point(pc, point3); add_helper_point(pc, point4); calculate_robust_envelope(pc); + + // Add mid-points in other order to current helper_ring + current_robust_ring.push_back(mid_point1); + current_robust_ring.push_back(mid_point2); } inline void add_piece(strategy::buffer::piece_type type, point_type const& p, diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index cf4865e3a..b6c3a9c2d 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -242,6 +242,9 @@ static std::string const rt_u7 static std::string const rt_u8 = "MULTIPOLYGON(((4 3,4 4,5 4,5 3,4 3)),((6 3,6 4,7 4,7 3,6 3)),((9 0,9 1,10 0,9 0)),((9 3,9 4,10 4,10 3,9 3)),((8 2,9 2,9 1,8 1,8 2)),((8 4,8 5,9 4,8 4)),((9 1,10 2,10 1,9 1)),((6 7,7 8,7 7,6 7)),((4 6,4 7,5 7,4 6)),((8 8,8 9,9 9,8 8)),((3 2,3 3,4 3,4 2,3 2)),((7 1,8 1,8 0,7 0,6 0,6 1,7 1)))"; +static std::string const rt_u9 + = "MULTIPOLYGON(((2 3,2 4,3 4,2 3)),((9 8,9 9,10 9,10 8,9 8)),((6 3,6 4,7 4,6 3)),((5 8,5 9,6 9,5 8)),((9 5,9 6,10 6,9 5)),((4 4,4 5,5 5,5 4,4 4)),((7 7,7 8,8 8,7 7)),((8 6,8 7,9 6,8 6)),((6 7,7 7,6 6,5 6,5 7,6 7)))"; + template void test_all() { @@ -364,6 +367,7 @@ void test_all() test_one("rt_u7_rough", rt_u7, join_round_rough, end_flat, 35.0483, 1.0); test_one("rt_u8", rt_u8, join_miter, end_flat, 70.9142, 1.0); + test_one("rt_u9", rt_u9, join_miter, end_flat, 59.3063, 1.0); } int test_main(int, char* [])