| // 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/core/ignore_unused.hpp> |
| #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/condition.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/num_interior_rings.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 |
| break; |
| case strategy::buffer::join_concave : |
| { |
| std::vector<output_point_type> range_out; |
| range_out.push_back(prev_perp2); |
| range_out.push_back(previous_input); |
| collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out); |
| |
| range_out.clear(); |
| range_out.push_back(previous_input); |
| range_out.push_back(perp1); |
| collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out); |
| } |
| break; |
| 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); |
| collection.set_current_ring_concave(); |
| } |
| break; |
| case strategy::buffer::join_convex : |
| { |
| // 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); |
| } |
| } |
| break; |
| } |
| } |
| |
| 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) |
| { |
| boost::ignore_unused(side_strategy); |
| |
| typedef typename std::iterator_traits |
| < |
| Iterator |
| >::value_type point_type; |
| |
| 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; |
| |
| std::vector<output_point_type> generated_side; |
| generated_side.reserve(2); |
| |
| for (Iterator prev = it++; it != end; ++it) |
| { |
| generated_side.clear(); |
| side_strategy.apply(*prev, *it, side, |
| distance_strategy, generated_side); |
| |
| if (generated_side.empty()) |
| { |
| // Because input is simplified, this is improbable, |
| // but it can happen for degenerate geometries |
| // Further handling of this side is skipped |
| continue; |
| } |
| |
| 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(); |
| } |
| } |
| 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(false, geometry::num_interior_rings(polygon) > 0u); |
| } |
| |
| 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 |
| ) |
| { |
| boost::ignore_unused(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; |
| bool const linear = boost::is_same |
| < |
| typename tag_cast<typename tag<GeometryInput>::type, linear_tag>::type, |
| linear_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(); |
| collection.classify_turns(linear); |
| if (BOOST_GEOMETRY_CONDITION(areal)) |
| { |
| collection.check_remaining_points(distance_strategy); |
| } |
| |
| // 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 (BOOST_GEOMETRY_CONDITION( |
| geometry::point_order<GeometryOutput>::value == counterclockwise)) |
| { |
| reverse = ! reverse; |
| } |
| if (reverse) |
| { |
| collection.reverse(); |
| } |
| |
| if (distance_strategy.negative() && areal) |
| { |
| collection.discard_nonintersecting_deflated_rings(); |
| } |
| |
| 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 |