12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
- // This file was modified by Oracle on 2017.
- // Modifications copyright (c) 2017 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/numeric/conversion/cast.hpp>
- #include <boost/range.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/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/make/make.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/assign.hpp>
- #include <boost/geometry/algorithms/num_interior_rings.hpp>
- #include <boost/geometry/algorithms/simplify.hpp>
- #include <boost/geometry/arithmetic/infinite_line_functions.hpp>
- #include <boost/geometry/views/detail/normalized_view.hpp>
- 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
- typedef typename geometry::point_type<Range>::type point_type;
- typedef typename strategy::distance::services::default_strategy
- <
- point_tag, segment_tag, point_type
- >::type ds_strategy_type;
- typedef strategy::simplify::douglas_peucker
- <
- point_type, ds_strategy_type
- > strategy_type;
- geometry::detail::simplify::simplify_range<2>::apply(range,
- simplified, distance.simplify_distance(),
- strategy_type());
- }
- 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,
- typename SideStrategy
- >
- 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,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& ,
- SideStrategy const& side_strategy) // side strategy
- {
- output_point_type intersection_point;
- geometry::assign_zero(intersection_point);
- geometry::strategy::buffer::join_selector join
- = get_join_type(penultimate_input, previous_input, input, side_strategy);
- if (join == geometry::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 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
- 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;
- }
- }
- static inline bool similar_direction(output_point_type const& p0,
- output_point_type const& p1,
- output_point_type const& p2)
- {
- typedef model::infinite_line<coordinate_type> line_type;
- line_type const p = detail::make::make_infinite_line<coordinate_type>(p0, p1);
- line_type const q = detail::make::make_infinite_line<coordinate_type>(p1, p2);
- return arithmetic::similar_direction(p, q);
- }
- template <typename SideStrategy>
- 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,
- SideStrategy const& side_strategy)
- {
- int const side = side_strategy.apply(p0, p1, p2);
- return side == -1 ? geometry::strategy::buffer::join_convex
- : side == 1 ? geometry::strategy::buffer::join_concave
- : similar_direction(p0, p1, p2)
- ? geometry::strategy::buffer::join_continue
- : geometry::strategy::buffer::join_spike;
- }
- template
- <
- typename Collection,
- typename Iterator,
- typename DistanceStrategy,
- typename SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- 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,
- SideStrategy const& side_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy,
- Strategy const& strategy, // side strategy
- 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(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 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
- = side_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, join_strategy, end_strategy,
- robust_policy, strategy);
- }
- collection.add_side_piece(*prev, *it, generated_side, first);
- if (first && mark_flat)
- {
- collection.mark_flat_start();
- }
- 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();
- }
- 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,
- typename Strategy
- >
- 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,
- Strategy const& strategy) // side strategy
- {
- 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, strategy);
- }
- }
- };
- 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 SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- 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& ,
- Strategy const& ) // side strategy
- {
- 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
- {
- typedef typename point_type<RingOutput>::type output_point_type;
- template
- <
- typename Collection,
- typename Iterator,
- typename DistanceStrategy,
- typename SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- 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,
- SideStrategy const& side_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy,
- Strategy const& strategy) // side strategy
- {
- 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, side_strategy, join_strategy, end_strategy,
- robust_policy, strategy,
- 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, join_strategy, end_strategy,
- robust_policy, strategy);
- }
- // 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,
- typename Strategy
- >
- static inline geometry::strategy::buffer::result_code 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,
- Strategy const& strategy) // side strategy
- {
- RingInput simplified;
- detail::buffer::simplify_input(ring, distance, simplified);
- 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<RingInput>::value
- >::value;
- if (n >= min_points)
- {
- detail::normalized_view<RingInput 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, side_strategy, join_strategy, end_strategy,
- robust_policy, strategy);
- }
- else
- {
- code = iterate(collection, boost::begin(view), boost::end(view),
- geometry::strategy::buffer::buffer_side_left,
- distance, side_strategy, join_strategy, end_strategy,
- robust_policy, strategy);
- }
- }
- 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 SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- static inline geometry::strategy::buffer::result_code 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,
- Strategy const& strategy) // side strategy
- {
- collection.start_new_ring(distance.negative());
- geometry::strategy::buffer::result_code const code
- = buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
- collection, distance,
- side_strategy, join_strategy, end_strategy, point_strategy,
- robust_policy, strategy);
- collection.finish_ring(code);
- return code;
- }
- };
- 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,
- typename Strategy
- >
- 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,
- SideStrategy const& side_strategy,
- JoinStrategy const& join_strategy,
- EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy,
- Strategy const& strategy, // side strategy
- 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 == geometry::strategy::buffer::buffer_side_right)
- {
- reverse_p1 = first_p1;
- }
- else
- {
- std::vector<output_point_type> generated_side;
- geometry::strategy::buffer::result_code code
- = side_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, side_strategy, join_strategy, end_strategy,
- robust_policy, strategy,
- 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 SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- static inline geometry::strategy::buffer::result_code 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,
- Strategy const& strategy) // side strategy
- {
- Linestring simplified;
- detail::buffer::simplify_input(linestring, distance, simplified);
- 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, side_strategy, join_strategy, end_strategy,
- robust_policy, strategy,
- 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, side_strategy, join_strategy, end_strategy,
- robust_policy, strategy,
- 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 SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- 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,
- Strategy const& strategy, // side strategy
- 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, side_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategy);
- collection.finish_ring(code, is_interior);
- }
- }
- template
- <
- typename InteriorRings,
- typename Collection,
- typename DistanceStrategy,
- typename SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- 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,
- Strategy const& strategy) // side strategy
- {
- iterate(boost::begin(interior_rings), boost::end(interior_rings),
- collection, distance, side_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategy, true);
- }
- public:
- template
- <
- typename Collection,
- typename DistanceStrategy,
- typename SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename RobustPolicy,
- typename Strategy
- >
- 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,
- Strategy const& strategy) // side strategy
- {
- {
- collection.start_new_ring(distance.negative());
- geometry::strategy::buffer::result_code const code
- = policy::apply(exterior_ring(polygon), collection,
- distance, side_strategy,
- join_strategy, end_strategy, point_strategy,
- robust_policy, strategy);
- collection.finish_ring(code, 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, strategy);
- }
- };
- 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 IntersectionStrategy,
- 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,
- IntersectionStrategy const& intersection_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,
- IntersectionStrategy,
- RobustPolicy
- > collection_type;
- collection_type collection(intersection_strategy, 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, intersection_strategy.get_side_strategy());
- collection.get_turns(distance_strategy);
- collection.classify_turns();
- 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();
- // phase 1: turns (after enrichment/clustering)
- visit_pieces_policy.apply(const_collection, 1);
- 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 (BOOST_GEOMETRY_CONDITION(distance_strategy.negative() && areal))
- {
- 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 SideStrategy,
- typename JoinStrategy,
- typename EndStrategy,
- typename PointStrategy,
- typename IntersectionStrategy,
- 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,
- IntersectionStrategy const& intersection_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,
- intersection_strategy, robust_policy, visitor);
- }
- #endif // DOXYGEN_NO_DETAIL
- }} // namespace detail::buffer
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
|