diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 943a62869..7207d0dc5 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -39,11 +39,7 @@ namespace detail { namespace buffer { -template -< - typename RingOutput, - typename Tag -> +template struct buffer_range { typedef typename point_type::type output_point_type; @@ -162,7 +158,10 @@ struct buffer_range JoinStrategy const& join_strategy, EndStrategy const& end_strategy, RobustPolicy const& robust_policy, - bool /*close*/ = false) + output_point_type& first_p1, + output_point_type& first_p2, + output_point_type& last_p1, + output_point_type& last_p2) { typedef typename std::iterator_traits < @@ -176,16 +175,14 @@ struct buffer_range >::type robust_point_type; robust_point_type previous_robust_input; - output_point_type previous_p1, previous_p2; - output_point_type first_p1, first_p2; point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end /* - * prev.p1 prev.p2 these are the "previous perpendicular points" + * last.p1 last.p2 these are the "previous (last) perpendicular points" * -------------- * | | * *------------*____ <- *prev - * pup | | p1 "current perpendiculat point 1" + * pup | | p1 "current perpendicular point 1" * | | * | | this forms a "side", a side is a piece * | | @@ -222,7 +219,7 @@ struct buffer_range { add_join(collection, phase, penultimate_point, - *prev, previous_p1, previous_p2, + *prev, last_p1, last_p2, *it, generated_side.front(), generated_side.back(), side, distance_strategy, join_strategy, end_strategy, @@ -234,8 +231,8 @@ struct buffer_range penultimate_point = *prev; ultimate_point = *it; - previous_p1 = generated_side.front(); - previous_p2 = generated_side.back(); + last_p1 = generated_side.front(); + last_p2 = generated_side.back(); prev = it; if (first) { @@ -247,39 +244,6 @@ struct buffer_range } previous_robust_input = robust_input; } - - // Might be replaced by specialization - if(boost::is_same::value) - { - // Generate closing corner - add_join(collection, phase, - penultimate_point, - *(end - 1), previous_p1, previous_p2, - *(begin + 1), first_p1, first_p2, - side, - distance_strategy, join_strategy, end_strategy, - robust_policy); - - // Buffer is closed automatically by last closing corner (NOT FOR OPEN POLYGONS - TODO) - } - else if (boost::is_same::value) - { - - // Generate perpendicular points to the reverse side, - // these points are necessary for all end-cap strategies - // TODO fix this (approach) for one-side buffer (1.5 - -1.0) - generated_side.clear(); - strategy::buffer::buffer_side::apply(ultimate_point, - penultimate_point, - side == strategy::buffer::buffer_side_left - ? strategy::buffer::buffer_side_right - : strategy::buffer::buffer_side_left, - distance_strategy, generated_side); - - std::vector range_out; - end_strategy.apply(penultimate_point, previous_p2, ultimate_point, generated_side.front(), side, distance_strategy, range_out); - collection.add_endcap(end_strategy, range_out, ultimate_point); - } } }; @@ -456,17 +420,47 @@ template typename RingOutput > struct buffer_inserter - : public detail::buffer::buffer_range - < - RingOutput, - ring_tag - > { - typedef detail::buffer::buffer_range - < - RingOutput, - ring_tag - > base; + typedef typename point_type::type output_point_type; + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline void iterate(Collection& collection, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& robust_policy) + { + output_point_type first_p1, first_p2, last_p1, last_p2; + + typedef detail::buffer::buffer_range buffer_range; + + buffer_range::iterate(collection, 0, begin, end, + side, + distance_strategy, join_strategy, end_strategy, robust_policy, + first_p1, first_p2, last_p1, last_p2); + + // Generate closing join + buffer_range::add_join(collection, 0, + *(end - 2), + *(end - 1), last_p1, last_p2, + *(begin + 1), first_p1, first_p2, + side, + distance_strategy, join_strategy, end_strategy, + robust_policy); + + // Buffer is closed automatically by last closing corner + // (OPEN IT FOR OPEN POLYGONS - TODO) + } template < @@ -502,16 +496,17 @@ struct buffer_inserter // Walk backwards (rings will be reversed afterwards) // It might be that this will be changed later. // TODO: decide this. - base::iterate(collection, 0, boost::rbegin(simplified), boost::rend(simplified), + iterate(collection, boost::rbegin(simplified), boost::rend(simplified), strategy::buffer::buffer_side_right, distance, join_strategy, end_strategy, robust_policy); } else { - base::iterate(collection, 0, boost::begin(simplified), boost::end(simplified), + iterate(collection, boost::begin(simplified), boost::end(simplified), strategy::buffer::buffer_side_left, distance, join_strategy, end_strategy, robust_policy); } + } } }; @@ -523,17 +518,64 @@ template typename Polygon > struct buffer_inserter - : public detail::buffer::buffer_range - < - typename ring_type::type, - linestring_tag - > { - typedef detail::buffer::buffer_range - < - typename ring_type::type, - linestring_tag - > base; + typedef typename ring_type::type output_ring_type; + typedef typename point_type::type output_point_type; + typedef typename point_type::type input_point_type; + + template + static inline output_point_type first_perpendicular_point( + input_point_type const& p1, input_point_type const& p2, + DistanceStrategy const& distance_strategy) + { + std::vector generated_side; + strategy::buffer::buffer_side::apply(p1, p2, + strategy::buffer::buffer_side_right, + distance_strategy, generated_side); + return generated_side.front(); + } + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline void iterate(Collection& collection, int phase, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& robust_policy, + output_point_type& first_p1) + { + input_point_type const& ultimate_point = *(end - 1); + input_point_type const& penultimate_point = *(end - 2); + + // For the end-cap, we need to have the last perpendicular point on the + // other side of the linestring. If it is the second pass (right), + // we have it already from the first phase (left). + // But for the first pass, we have to generate it + output_point_type reverse_p1 + = side == strategy::buffer::buffer_side_right + ? first_p1 + : first_perpendicular_point(ultimate_point, penultimate_point, distance_strategy); + + output_point_type first_p2, last_p1, last_p2; + + detail::buffer::buffer_range::iterate(collection, + phase, begin, end, side, + distance_strategy, join_strategy, end_strategy, robust_policy, + first_p1, first_p2, last_p1, last_p2); + + std::vector range_out; + end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out); + collection.add_endcap(end_strategy, range_out, ultimate_point); + } template < @@ -555,13 +597,16 @@ struct buffer_inserter geometry::simplify(linestring, simplified, distance.simplify_distance()); collection.start_new_ring(); - base::iterate(collection, 0, boost::begin(simplified), boost::end(simplified), + output_point_type first_p1; + iterate(collection, 0, boost::begin(simplified), boost::end(simplified), strategy::buffer::buffer_side_left, - distance, join_strategy, end_strategy, robust_policy); + distance, join_strategy, end_strategy, robust_policy, + first_p1); - base::iterate(collection, 1, boost::rbegin(simplified), boost::rend(simplified), + iterate(collection, 1, boost::rbegin(simplified), boost::rend(simplified), strategy::buffer::buffer_side_right, - distance, join_strategy, end_strategy, robust_policy, true); + distance, join_strategy, end_strategy, robust_policy, + first_p1); } }