diff options
Diffstat (limited to 'boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp')
-rw-r--r-- | boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp | 940 |
1 files changed, 940 insertions, 0 deletions
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp new file mode 100644 index 0000000000..c959ee849b --- /dev/null +++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -0,0 +1,940 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. + +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP + +#include <cstddef> +#include <iterator> + +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/range.hpp> + +#include <boost/geometry/core/closure.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/interior_rings.hpp> + +#include <boost/geometry/util/math.hpp> + +#include <boost/geometry/strategies/buffer.hpp> +#include <boost/geometry/strategies/side.hpp> +#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp> +#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp> +#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp> + +#include <boost/geometry/algorithms/simplify.hpp> + +#include <boost/geometry/views/detail/normalized_view.hpp> + +#if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX) +#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp> +#endif + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +template <typename Range, typename DistanceStrategy> +inline void simplify_input(Range const& range, + DistanceStrategy const& distance, + Range& simplified) +{ + // We have to simplify the ring before to avoid very small-scaled + // features in the original (convex/concave/convex) being enlarged + // in a very large scale and causing issues (IP's within pieces). + // This might be reconsidered later. Simplifying with a very small + // distance (1%% of the buffer) will never be visible in the result, + // if it is using round joins. For miter joins they are even more + // sensitive to small scale input features, however the result will + // look better. + // It also gets rid of duplicate points +#if ! defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX) + geometry::simplify(range, simplified, distance.simplify_distance()); +#else + + typedef typename boost::range_value<Range>::type point_type; + typedef strategy::distance::detail::projected_point_ax<> ax_type; + typedef typename strategy::distance::services::return_type + < + strategy::distance::detail::projected_point_ax<>, + point_type, + point_type + >::type return_type; + + typedef strategy::distance::detail::projected_point_ax_less + < + return_type + > comparator_type; + + typedef strategy::simplify::detail::douglas_peucker + < + point_type, + strategy::distance::detail::projected_point_ax<>, + comparator_type + > dp_ax; + + return_type max_distance(distance.simplify_distance() * 2.0, + distance.simplify_distance()); + comparator_type comparator(max_distance); + dp_ax strategy(comparator); + + geometry::simplify(range, simplified, max_distance, strategy); +#endif + + if (boost::size(simplified) == 2 + && geometry::equals(geometry::range::front(simplified), + geometry::range::back(simplified))) + { + traits::resize<Range>::apply(simplified, 1); + } +} + + +template <typename RingOutput> +struct buffer_range +{ + typedef typename point_type<RingOutput>::type output_point_type; + typedef typename coordinate_type<RingOutput>::type coordinate_type; + + template + < + typename Collection, + typename Point, + typename DistanceStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline + void add_join(Collection& collection, + Point const& penultimate_input, + Point const& previous_input, + output_point_type const& prev_perp1, + output_point_type const& prev_perp2, + Point const& input, + output_point_type const& perp1, + output_point_type const& perp2, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& ) + { + output_point_type intersection_point; + + strategy::buffer::join_selector join + = get_join_type(penultimate_input, previous_input, input); + if (join == strategy::buffer::join_convex) + { + // Calculate the intersection-point formed by the two sides. + // It might be that the two sides are not convex, but continue + // or spikey, we then change the join-type + join = line_line_intersection::apply( + perp1, perp2, prev_perp1, prev_perp2, + intersection_point); + + } + switch(join) + { + case strategy::buffer::join_continue : + // No join, we get two consecutive sides + return; + case strategy::buffer::join_concave : + collection.add_piece(strategy::buffer::buffered_concave, + previous_input, prev_perp2, perp1); + return; + case strategy::buffer::join_spike : + { + // For linestrings, only add spike at one side to avoid + // duplicates + std::vector<output_point_type> range_out; + end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out); + collection.add_endcap(end_strategy, range_out, previous_input); + } + return; + case strategy::buffer::join_convex : + break; // All code below handles this + } + + // The corner is convex, we create a join + // TODO (future) - avoid a separate vector, add the piece directly + std::vector<output_point_type> range_out; + if (join_strategy.apply(intersection_point, + previous_input, prev_perp2, perp1, + distance.apply(previous_input, input, side), + range_out)) + { + collection.add_piece(strategy::buffer::buffered_join, + previous_input, range_out); + } + } + + static inline strategy::buffer::join_selector get_join_type( + output_point_type const& p0, + output_point_type const& p1, + output_point_type const& p2) + { + typedef typename strategy::side::services::default_strategy + < + typename cs_tag<output_point_type>::type + >::type side_strategy; + + int const side = side_strategy::apply(p0, p1, p2); + return side == -1 ? strategy::buffer::join_convex + : side == 1 ? strategy::buffer::join_concave + : parallel_continue + ( + get<0>(p2) - get<0>(p1), + get<1>(p2) - get<1>(p1), + get<0>(p1) - get<0>(p0), + get<1>(p1) - get<1>(p0) + ) ? strategy::buffer::join_continue + : strategy::buffer::join_spike; + } + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline bool iterate(Collection& collection, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + RobustPolicy const& robust_policy, + 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 + < + Iterator + >::value_type point_type; + + typedef typename robust_point_type + < + point_type, + RobustPolicy + >::type robust_point_type; + + robust_point_type previous_robust_input; + point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end + + /* + * last.p1 last.p2 these are the "previous (last) perpendicular points" + * -------------- + * | | + * *------------*____ <- *prev + * pup | | p1 "current perpendicular point 1" + * | | + * | | this forms a "side", a side is a piece + * | | + * *____| p2 + * + * ^ + * *it + * + * pup: penultimate_point + */ + + bool result = false; + bool first = true; + + Iterator it = begin; + + geometry::recalculate(previous_robust_input, *begin, robust_policy); + + std::vector<output_point_type> generated_side; + generated_side.reserve(2); + + for (Iterator prev = it++; it != end; ++it) + { + robust_point_type robust_input; + geometry::recalculate(robust_input, *it, robust_policy); + // Check on equality - however, if input is simplified, this is + // unlikely (though possible by rescaling or for degenerated pointlike polygons) + if (! detail::equals::equals_point_point(previous_robust_input, robust_input)) + { + generated_side.clear(); + side_strategy.apply(*prev, *it, side, + distance_strategy, generated_side); + + if (generated_side.empty()) + { + break; + } + + result = true; + + if (! first) + { + add_join(collection, + penultimate_point, + *prev, last_p1, last_p2, + *it, generated_side.front(), generated_side.back(), + side, + distance_strategy, join_strategy, end_strategy, + robust_policy); + } + + collection.add_side_piece(*prev, *it, generated_side, first); + + penultimate_point = *prev; + ultimate_point = *it; + last_p1 = generated_side.front(); + last_p2 = generated_side.back(); + prev = it; + if (first) + { + first = false; + second_point = *it; + first_p1 = generated_side.front(); + first_p2 = generated_side.back(); + } + } + previous_robust_input = robust_input; + } + return result; + } +}; + +template +< + typename Multi, + typename PolygonOutput, + typename Policy +> +struct buffer_multi +{ + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(Multi const& multi, + Collection& collection, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + for (typename boost::range_iterator<Multi const>::type + it = boost::begin(multi); + it != boost::end(multi); + ++it) + { + Policy::apply(*it, collection, + distance_strategy, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + } + } +}; + +struct visit_pieces_default_policy +{ + template <typename Collection> + static inline void apply(Collection const&, int) + {} +}; + +template +< + typename OutputPointType, + typename Point, + typename Collection, + typename DistanceStrategy, + typename PointStrategy +> +inline void buffer_point(Point const& point, Collection& collection, + DistanceStrategy const& distance_strategy, + PointStrategy const& point_strategy) +{ + collection.start_new_ring(); + std::vector<OutputPointType> range_out; + point_strategy.apply(point, distance_strategy, range_out); + collection.add_piece(strategy::buffer::buffered_point, range_out, false); + collection.finish_ring(); +} + + +}} // namespace detail::buffer +#endif // DOXYGEN_NO_DETAIL + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template +< + typename Tag, + typename RingInput, + typename RingOutput +> +struct buffer_inserter +{}; + + + +template +< + typename Point, + typename RingOutput +> +struct buffer_inserter<point_tag, Point, RingOutput> +{ + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(Point const& point, Collection& collection, + DistanceStrategy const& distance_strategy, + SideStrategy const& , + JoinStrategy const& , + EndStrategy const& , + PointStrategy const& point_strategy, + RobustPolicy const& ) + { + detail::buffer::buffer_point + < + typename point_type<RingOutput>::type + >(point, collection, distance_strategy, point_strategy); + } +}; + + +template +< + typename RingInput, + typename RingOutput +> +struct buffer_inserter<ring_tag, RingInput, RingOutput> +{ + typedef typename point_type<RingOutput>::type output_point_type; + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline bool iterate(Collection& collection, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_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<RingOutput> buffer_range; + + bool result = buffer_range::iterate(collection, begin, end, + side, + distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1, first_p2, last_p1, last_p2); + + // Generate closing join + if (result) + { + buffer_range::add_join(collection, + *(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 + return result; + } + + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(RingInput const& ring, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + RingInput simplified; + detail::buffer::simplify_input(ring, distance, simplified); + + bool has_output = false; + + std::size_t n = boost::size(simplified); + std::size_t const min_points = core_detail::closure::minimum_ring_size + < + geometry::closure<RingInput>::value + >::value; + + if (n >= min_points) + { + detail::normalized_view<RingInput const> view(simplified); + if (distance.negative()) + { + // Walk backwards (rings will be reversed afterwards) + // It might be that this will be changed later. + // TODO: decide this. + has_output = iterate(collection, boost::rbegin(view), boost::rend(view), + strategy::buffer::buffer_side_right, + distance, side_strategy, join_strategy, end_strategy, robust_policy); + } + else + { + has_output = iterate(collection, boost::begin(view), boost::end(view), + strategy::buffer::buffer_side_left, + distance, side_strategy, join_strategy, end_strategy, robust_policy); + } + } + + if (! has_output && n >= 1) + { + // Use point_strategy to buffer degenerated ring + detail::buffer::buffer_point<output_point_type> + ( + geometry::range::front(simplified), + collection, distance, point_strategy + ); + } + } +}; + + +template +< + typename Linestring, + typename Polygon +> +struct buffer_inserter<linestring_tag, Linestring, Polygon> +{ + typedef typename ring_type<Polygon>::type output_ring_type; + typedef typename point_type<output_ring_type>::type output_point_type; + typedef typename point_type<Linestring>::type input_point_type; + + template + < + typename Collection, + typename Iterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename RobustPolicy + > + static inline bool iterate(Collection& collection, + Iterator begin, Iterator end, + strategy::buffer::buffer_side_selector side, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_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; + if (side == strategy::buffer::buffer_side_right) + { + reverse_p1 = first_p1; + } + else + { + std::vector<output_point_type> generated_side; + side_strategy.apply(ultimate_point, penultimate_point, + strategy::buffer::buffer_side_right, + distance_strategy, generated_side); + if (generated_side.empty()) + { + return false; + } + reverse_p1 = generated_side.front(); + } + + output_point_type first_p2, last_p1, last_p2; + + detail::buffer::buffer_range<output_ring_type>::iterate(collection, + begin, end, side, + distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1, first_p2, last_p1, last_p2); + + std::vector<output_point_type> 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); + return true; + } + + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(Linestring const& linestring, Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + Linestring simplified; + detail::buffer::simplify_input(linestring, distance, simplified); + + bool has_output = false; + std::size_t n = boost::size(simplified); + if (n > 1) + { + collection.start_new_ring(); + output_point_type first_p1; + has_output = iterate(collection, + boost::begin(simplified), boost::end(simplified), + strategy::buffer::buffer_side_left, + distance, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1); + + if (has_output) + { + iterate(collection, boost::rbegin(simplified), boost::rend(simplified), + strategy::buffer::buffer_side_right, + distance, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1); + } + collection.finish_ring(); + } + if (! has_output && n >= 1) + { + // Use point_strategy to buffer degenerated linestring + detail::buffer::buffer_point<output_point_type> + ( + geometry::range::front(simplified), + collection, distance, point_strategy + ); + } + } +}; + + +template +< + typename PolygonInput, + typename PolygonOutput +> +struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput> +{ +private: + typedef typename ring_type<PolygonInput>::type input_ring_type; + typedef typename ring_type<PolygonOutput>::type output_ring_type; + + typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy; + + + template + < + typename Iterator, + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline + void iterate(Iterator begin, Iterator end, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy, + bool is_interior) + { + for (Iterator it = begin; it != end; ++it) + { + collection.start_new_ring(); + policy::apply(*it, collection, distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + collection.finish_ring(is_interior); + } + } + + template + < + typename InteriorRings, + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline + void apply_interior_rings(InteriorRings const& interior_rings, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + iterate(boost::begin(interior_rings), boost::end(interior_rings), + collection, distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy, true); + } + +public: + template + < + typename Collection, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy + > + static inline void apply(PolygonInput const& polygon, + Collection& collection, + DistanceStrategy const& distance, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) + { + { + collection.start_new_ring(); + policy::apply(exterior_ring(polygon), collection, + distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + collection.finish_ring(); + } + + apply_interior_rings(interior_rings(polygon), + collection, distance, side_strategy, + join_strategy, end_strategy, point_strategy, + robust_policy); + } +}; + + +template +< + typename Multi, + typename PolygonOutput +> +struct buffer_inserter<multi_tag, Multi, PolygonOutput> + : public detail::buffer::buffer_multi + < + Multi, + PolygonOutput, + dispatch::buffer_inserter + < + typename single_tag_of + < + typename tag<Multi>::type + >::type, + typename boost::range_value<Multi const>::type, + typename geometry::ring_type<PolygonOutput>::type + > + > +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace buffer +{ + +template +< + typename GeometryOutput, + typename GeometryInput, + typename OutputIterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy, + typename VisitPiecesPolicy +> +inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy, + VisitPiecesPolicy& visit_pieces_policy + ) +{ + typedef detail::buffer::buffered_piece_collection + < + typename geometry::ring_type<GeometryOutput>::type, + RobustPolicy + > collection_type; + collection_type collection(robust_policy); + collection_type const& const_collection = collection; + + bool const areal = boost::is_same + < + typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type, + areal_tag + >::type::value; + + dispatch::buffer_inserter + < + typename tag_cast + < + typename tag<GeometryInput>::type, + multi_tag + >::type, + GeometryInput, + GeometryOutput + >::apply(geometry_input, collection, + distance_strategy, side_strategy, join_strategy, + end_strategy, point_strategy, + robust_policy); + + 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), + // or the piece collection can be unit-tested + // phase 0: turns (before discarded) + visit_pieces_policy.apply(const_collection, 0); + + collection.discard_rings(); + collection.block_turns(); + collection.enrich(); + collection.traverse(); + + // Reverse all offsetted rings / traversed rings if: + // - they were generated on the negative side (deflate) of polygons + // - the output is counter clockwise + // and avoid reversing twice + bool reverse = distance_strategy.negative() && areal; + if (geometry::point_order<GeometryOutput>::value == counterclockwise) + { + reverse = ! reverse; + } + if (reverse) + { + collection.reverse(); + } + + collection.template assign<GeometryOutput>(out); + + // Visit collection again + // phase 1: rings (after discarding and traversing) + visit_pieces_policy.apply(const_collection, 1); +} + +template +< + typename GeometryOutput, + typename GeometryInput, + typename OutputIterator, + typename DistanceStrategy, + typename SideStrategy, + typename JoinStrategy, + typename EndStrategy, + typename PointStrategy, + typename RobustPolicy +> +inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, + DistanceStrategy const& distance_strategy, + SideStrategy const& side_strategy, + JoinStrategy const& join_strategy, + EndStrategy const& end_strategy, + PointStrategy const& point_strategy, + RobustPolicy const& robust_policy) +{ + detail::buffer::visit_pieces_default_policy visitor; + buffer_inserter<GeometryOutput>(geometry_input, out, + distance_strategy, side_strategy, join_strategy, + end_strategy, point_strategy, + robust_policy, visitor); +} +#endif // DOXYGEN_NO_DETAIL + +}} // namespace detail::buffer + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP |