123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
- // Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland.
- // This file was modified by Oracle on 2017-2022.
- // Modifications copyright (c) 2017-2022 Oracle and/or its affiliates.
- // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
- // 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/range/begin.hpp>
- #include <boost/range/end.hpp>
- #include <boost/range/rbegin.hpp>
- #include <boost/range/rend.hpp>
- #include <boost/range/size.hpp>
- #include <boost/range/value_type.hpp>
- #include <boost/geometry/algorithms/detail/direction_code.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/num_interior_rings.hpp>
- #include <boost/geometry/algorithms/simplify.hpp>
- #include <boost/geometry/core/assert.hpp>
- #include <boost/geometry/core/closure.hpp>
- #include <boost/geometry/core/exterior_ring.hpp>
- #include <boost/geometry/core/interior_rings.hpp>
- #include <boost/geometry/geometries/linestring.hpp>
- #include <boost/geometry/geometries/ring.hpp>
- #include <boost/geometry/strategies/buffer.hpp>
- #include <boost/geometry/strategies/side.hpp>
- #include <boost/geometry/util/constexpr.hpp>
- #include <boost/geometry/util/math.hpp>
- #include <boost/geometry/util/type_traits.hpp>
- #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
- namespace boost { namespace geometry
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail { namespace buffer
- {
- template <typename RangeIn, typename DistanceStrategy, typename RangeOut, typename Strategies>
- inline void simplify_input(RangeIn const& range,
- DistanceStrategy const& distance,
- RangeOut& simplified,
- Strategies const& strategies)
- {
- // 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
- geometry::detail::simplify::simplify_range<2>::apply(range,
- simplified, distance.simplify_distance(),
- detail::simplify::douglas_peucker(),
- strategies);
- }
- 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 SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- 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,
- geometry::strategy::buffer::buffer_side_selector side,
- DistanceStrategy const& distance,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& ,
- Strategies const& strategies)
- {
- geometry::strategy::buffer::join_selector const join
- = get_join_type(penultimate_input, previous_input, input,
- strategies);
- switch(join)
- {
- case geometry::strategy::buffer::join_continue :
- // No join, we get two consecutive sides
- break;
- case geometry::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(geometry::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(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
- }
- break;
- case geometry::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 geometry::strategy::buffer::join_convex :
- {
- // The corner is convex, we create a join
- // TODO (future) - avoid a separate vector, add the piece directly
- output_point_type intersection_point;
- if (line_line_intersection::apply(prev_perp1, prev_perp2,
- perp1, perp2, previous_input,
- segment_strategy.equidistant(),
- intersection_point))
- {
- 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(geometry::strategy::buffer::buffered_join,
- previous_input, range_out);
- }
- }
- }
- break;
- }
- }
- // Returns true if collinear point p2 continues after p0 and p1.
- // If it turns back (spike), it returns false.
- static inline bool same_direction(output_point_type const& p0,
- output_point_type const& p1,
- output_point_type const& p2)
- {
- typedef typename cs_tag<output_point_type>::type cs_tag;
- return direction_code<cs_tag>(p0, p1, p2) == 1;
- }
- template <typename Strategies>
- static inline geometry::strategy::buffer::join_selector get_join_type(
- output_point_type const& p0,
- output_point_type const& p1,
- output_point_type const& p2,
- Strategies const& strategies)
- {
- int const side = strategies.side().apply(p0, p1, p2);
- return side == -1 ? geometry::strategy::buffer::join_convex
- : side == 1 ? geometry::strategy::buffer::join_concave
- : same_direction(p0, p1, p2) ? geometry::strategy::buffer::join_continue
- : geometry::strategy::buffer::join_spike;
- }
- template
- <
- typename Collection,
- typename Iterator,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
- Iterator begin, Iterator end,
- geometry::strategy::buffer::buffer_side_selector side,
- DistanceStrategy const& distance_strategy,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies,
- bool linear,
- output_point_type& first_p1,
- output_point_type& first_p2,
- output_point_type& last_p1,
- output_point_type& last_p2)
- {
- boost::ignore_unused(segment_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 const mark_flat
- = linear
- && end_strategy.get_piece_type() == geometry::strategy::buffer::buffered_flat_end;
- geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
- 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();
- geometry::strategy::buffer::result_code error_code
- = segment_strategy.apply(*prev, *it, side,
- distance_strategy, generated_side);
- if (error_code == geometry::strategy::buffer::result_no_output)
- {
- // Because input is simplified, this is improbable,
- // but it can happen for degenerate geometries
- // Further handling of this side is skipped
- continue;
- }
- else if (error_code == geometry::strategy::buffer::result_error_numerical)
- {
- return error_code;
- }
- BOOST_GEOMETRY_ASSERT(! generated_side.empty());
- result = geometry::strategy::buffer::result_normal;
- if (! first)
- {
- add_join(collection,
- penultimate_point,
- *prev, last_p1, last_p2,
- *it, generated_side.front(), generated_side.back(),
- side,
- distance_strategy, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies);
- }
- collection.add_side_piece(*prev, *it, generated_side, first, distance_strategy.empty(side));
- if (first && mark_flat)
- {
- collection.mark_flat_start(*prev);
- }
- 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();
- }
- }
- if (mark_flat)
- {
- collection.mark_flat_end(ultimate_point);
- }
- return result;
- }
- };
- template
- <
- typename Multi,
- typename PolygonOutput,
- typename Policy
- >
- struct buffer_multi
- {
- template
- <
- typename Collection,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline void apply(Multi const& multi,
- Collection& collection,
- DistanceStrategy const& distance_strategy,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies)
- {
- for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
- {
- Policy::apply(*it, collection,
- distance_strategy, segment_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategies);
- }
- }
- };
- 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(false);
- std::vector<OutputPointType> range_out;
- point_strategy.apply(point, distance_strategy, range_out);
- collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
- collection.set_piece_center(point);
- collection.finish_ring(geometry::strategy::buffer::result_normal);
- }
- }} // 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 SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline void apply(Point const& point, Collection& collection,
- DistanceStrategy const& distance_strategy,
- SegmentStrategy const& ,
- JoinStrategy const& ,
- EndStrategy const& ,
- PointStrategy const& point_strategy,
- RobustPolicy const& ,
- Strategies const& )
- {
- detail::buffer::buffer_point
- <
- typename point_type<RingOutput>::type
- >(point, collection, distance_strategy, point_strategy);
- }
- };
- // Not a specialization, but called from specializations of ring and of polygon.
- // Calling code starts/finishes ring before/after apply
- template
- <
- typename RingInput,
- typename RingOutput
- >
- struct buffer_inserter_ring
- {
- using output_point_type = typename point_type<RingOutput>::type;
- template
- <
- typename Collection,
- typename Iterator,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
- Iterator begin, Iterator end,
- geometry::strategy::buffer::buffer_side_selector side,
- DistanceStrategy const& distance_strategy,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies)
- {
- output_point_type first_p1, first_p2, last_p1, last_p2;
- typedef detail::buffer::buffer_range<RingOutput> buffer_range;
- geometry::strategy::buffer::result_code result
- = buffer_range::iterate(collection, begin, end,
- side,
- distance_strategy, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies,
- false, first_p1, first_p2, last_p1, last_p2);
- // Generate closing join
- if (result == geometry::strategy::buffer::result_normal)
- {
- buffer_range::add_join(collection,
- *(end - 2),
- *(end - 1), last_p1, last_p2,
- *(begin + 1), first_p1, first_p2,
- side,
- distance_strategy, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies);
- }
- // Buffer is closed automatically by last closing corner
- return result;
- }
- template
- <
- typename Collection,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
- Collection& collection,
- DistanceStrategy const& distance,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies)
- {
- // Use helper geometry to support non-mutable input Rings
- using simplified_ring_t = model::ring
- <
- output_point_type,
- point_order<RingInput>::value != counterclockwise,
- closure<RingInput>::value != open
- >;
- simplified_ring_t simplified;
- detail::buffer::simplify_input(ring, distance, simplified, strategies);
- geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
- std::size_t n = boost::size(simplified);
- std::size_t const min_points = core_detail::closure::minimum_ring_size
- <
- geometry::closure<simplified_ring_t>::value
- >::value;
- if (n >= min_points)
- {
- detail::closed_clockwise_view<simplified_ring_t const> view(simplified);
- if (distance.negative())
- {
- // Walk backwards (rings will be reversed afterwards)
- code = iterate(collection, boost::rbegin(view), boost::rend(view),
- geometry::strategy::buffer::buffer_side_right,
- distance, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies);
- }
- else
- {
- code = iterate(collection, boost::begin(view), boost::end(view),
- geometry::strategy::buffer::buffer_side_left,
- distance, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies);
- }
- }
- if (code == geometry::strategy::buffer::result_no_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
- );
- }
- return code;
- }
- };
- template
- <
- typename RingInput,
- typename RingOutput
- >
- struct buffer_inserter<ring_tag, RingInput, RingOutput>
- {
- template
- <
- typename Collection,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
- Collection& collection,
- DistanceStrategy const& distance,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies)
- {
- collection.start_new_ring(distance.negative());
- geometry::strategy::buffer::result_code const code
- = buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
- collection, distance,
- segment_strategy, join_strategy, end_strategy, point_strategy,
- robust_policy, strategies);
- collection.finish_ring(code, ring, false, false);
- return code;
- }
- };
- template
- <
- typename Linestring,
- typename Polygon
- >
- struct buffer_inserter<linestring_tag, Linestring, Polygon>
- {
- using output_ring_type = typename ring_type<Polygon>::type;
- using output_point_type = typename point_type<output_ring_type>::type;
- template
- <
- typename Collection,
- typename Iterator,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
- Iterator begin, Iterator end,
- geometry::strategy::buffer::buffer_side_selector side,
- DistanceStrategy const& distance_strategy,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies,
- output_point_type& first_p1)
- {
- output_point_type const& ultimate_point = *(end - 1);
- output_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 == geometry::strategy::buffer::buffer_side_right)
- {
- reverse_p1 = first_p1;
- }
- else
- {
- std::vector<output_point_type> generated_side;
- geometry::strategy::buffer::result_code code
- = segment_strategy.apply(ultimate_point, penultimate_point,
- geometry::strategy::buffer::buffer_side_right,
- distance_strategy, generated_side);
- if (code != geometry::strategy::buffer::result_normal)
- {
- // No output or numerical error
- return code;
- }
- reverse_p1 = generated_side.front();
- }
- output_point_type first_p2, last_p1, last_p2;
- geometry::strategy::buffer::result_code result
- = detail::buffer::buffer_range<output_ring_type>::iterate(collection,
- begin, end, side,
- distance_strategy, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies,
- true, first_p1, first_p2, last_p1, last_p2);
- if (result == geometry::strategy::buffer::result_normal)
- {
- 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 result;
- }
- template
- <
- typename Collection,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
- Collection& collection,
- DistanceStrategy const& distance,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies)
- {
- // Use helper geometry to support non-mutable input Linestrings
- model::linestring<output_point_type> simplified;
- detail::buffer::simplify_input(linestring, distance, simplified, strategies);
- geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
- std::size_t n = boost::size(simplified);
- if (n > 1)
- {
- collection.start_new_ring(false);
- output_point_type first_p1;
- code = iterate(collection,
- boost::begin(simplified), boost::end(simplified),
- geometry::strategy::buffer::buffer_side_left,
- distance, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies,
- first_p1);
- if (code == geometry::strategy::buffer::result_normal)
- {
- code = iterate(collection,
- boost::rbegin(simplified), boost::rend(simplified),
- geometry::strategy::buffer::buffer_side_right,
- distance, segment_strategy, join_strategy, end_strategy,
- robust_policy, strategies,
- first_p1);
- }
- collection.finish_ring(code);
- }
- if (code == geometry::strategy::buffer::result_no_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
- );
- }
- return code;
- }
- };
- 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<input_ring_type, output_ring_type> policy;
- template
- <
- typename Iterator,
- typename Collection,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline
- void iterate(Iterator begin, Iterator end,
- Collection& collection,
- DistanceStrategy const& distance,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies,
- bool is_interior)
- {
- for (Iterator it = begin; it != end; ++it)
- {
- // For exterior rings, it deflates if distance is negative.
- // For interior rings, it is vice versa
- bool const deflate = is_interior
- ? ! distance.negative()
- : distance.negative();
- collection.start_new_ring(deflate);
- geometry::strategy::buffer::result_code const code
- = policy::apply(*it, collection, distance, segment_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategies);
- collection.finish_ring(code, *it, is_interior, false);
- }
- }
- template
- <
- typename InteriorRings,
- typename Collection,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline
- void apply_interior_rings(InteriorRings const& interior_rings,
- Collection& collection,
- DistanceStrategy const& distance,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies)
- {
- iterate(boost::begin(interior_rings), boost::end(interior_rings),
- collection, distance, segment_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategies, true);
- }
- public:
- template
- <
- typename Collection,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategies
- >
- static inline void apply(PolygonInput const& polygon,
- Collection& collection,
- DistanceStrategy const& distance,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy,
- Strategies const& strategies)
- {
- {
- collection.start_new_ring(distance.negative());
- geometry::strategy::buffer::result_code const code
- = policy::apply(exterior_ring(polygon), collection,
- distance, segment_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategies);
- collection.finish_ring(code, exterior_ring(polygon), false,
- geometry::num_interior_rings(polygon) > 0u);
- }
- apply_interior_rings(interior_rings(polygon),
- collection, distance, segment_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategies);
- }
- };
- 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 SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename Strategies,
- typename RobustPolicy,
- typename VisitPiecesPolicy
- >
- inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
- DistanceStrategy const& distance_strategy,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- Strategies const& strategies,
- RobustPolicy const& robust_policy,
- VisitPiecesPolicy& visit_pieces_policy
- )
- {
- boost::ignore_unused(visit_pieces_policy);
- using collection_type = detail::buffer::buffered_piece_collection
- <
- typename geometry::ring_type<GeometryOutput>::type,
- Strategies,
- DistanceStrategy,
- RobustPolicy
- >;
- collection_type collection(strategies, distance_strategy, robust_policy);
- collection_type const& const_collection = collection;
- static constexpr bool areal = util::is_areal<GeometryInput>::value;
- dispatch::buffer_inserter
- <
- typename tag_cast
- <
- typename tag<GeometryInput>::type,
- multi_tag
- >::type,
- GeometryInput,
- GeometryOutput
- >::apply(geometry_input, collection,
- distance_strategy, segment_strategy, join_strategy,
- end_strategy, point_strategy,
- robust_policy, strategies);
- collection.get_turns();
- if BOOST_GEOMETRY_CONSTEXPR (areal)
- {
- collection.check_turn_in_original();
- }
- collection.handle_colocations();
- collection.check_turn_in_pieces();
- collection.make_traversable_consistent_per_cluster();
- // 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();
- // phase 1: turns (after enrichment/clustering)
- visit_pieces_policy.apply(const_collection, 1);
- if BOOST_GEOMETRY_CONSTEXPR (areal)
- {
- collection.deflate_check_turns();
- }
- 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_CONSTEXPR (geometry::point_order<GeometryOutput>::value == counterclockwise)
- {
- reverse = ! reverse;
- }
- if (reverse)
- {
- collection.reverse();
- }
- if BOOST_GEOMETRY_CONSTEXPR (areal)
- {
- if (distance_strategy.negative())
- {
- collection.discard_nonintersecting_deflated_rings();
- }
- }
- collection.template assign<GeometryOutput>(out);
- // Visit collection again
- // phase 2: rings (after traversing)
- visit_pieces_policy.apply(const_collection, 2);
- }
- template
- <
- typename GeometryOutput,
- typename GeometryInput,
- typename OutputIterator,
- typename DistanceStrategy,
- typename SegmentStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename Strategies,
- typename RobustPolicy
- >
- inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
- DistanceStrategy const& distance_strategy,
- SegmentStrategy const& segment_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- PointStrategy const& point_strategy,
- Strategies const& strategies,
- RobustPolicy const& robust_policy)
- {
- detail::buffer::visit_pieces_default_policy visitor;
- buffer_inserter<GeometryOutput>(geometry_input, out,
- distance_strategy, segment_strategy, join_strategy,
- end_strategy, point_strategy,
- strategies, robust_policy, visitor);
- }
- #endif // DOXYGEN_NO_DETAIL
- }} // namespace detail::buffer
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
|