Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:33:47

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland.
0005 
0006 // This file was modified by Oracle on 2017-2022.
0007 // Modifications copyright (c) 2017-2022 Oracle and/or its affiliates.
0008 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0009 
0010 // Use, modification and distribution is subject to the Boost Software License,
0011 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0012 // http://www.boost.org/LICENSE_1_0.txt)
0013 
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
0016 
0017 #include <cstddef>
0018 #include <iterator>
0019 
0020 #include <boost/core/ignore_unused.hpp>
0021 #include <boost/range/begin.hpp>
0022 #include <boost/range/end.hpp>
0023 #include <boost/range/rbegin.hpp>
0024 #include <boost/range/rend.hpp>
0025 #include <boost/range/size.hpp>
0026 #include <boost/range/value_type.hpp>
0027 
0028 #include <boost/geometry/algorithms/detail/direction_code.hpp>
0029 #include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
0030 #include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
0031 
0032 #include <boost/geometry/algorithms/num_interior_rings.hpp>
0033 #include <boost/geometry/algorithms/simplify.hpp>
0034 
0035 #include <boost/geometry/core/assert.hpp>
0036 #include <boost/geometry/core/closure.hpp>
0037 #include <boost/geometry/core/exterior_ring.hpp>
0038 #include <boost/geometry/core/interior_rings.hpp>
0039 
0040 #include <boost/geometry/geometries/linestring.hpp>
0041 #include <boost/geometry/geometries/ring.hpp>
0042 
0043 #include <boost/geometry/strategies/buffer.hpp>
0044 #include <boost/geometry/strategies/side.hpp>
0045 
0046 #include <boost/geometry/util/constexpr.hpp>
0047 #include <boost/geometry/util/math.hpp>
0048 #include <boost/geometry/util/type_traits.hpp>
0049 
0050 #include <boost/geometry/views/detail/closed_clockwise_view.hpp>
0051 
0052 
0053 namespace boost { namespace geometry
0054 {
0055 
0056 #ifndef DOXYGEN_NO_DETAIL
0057 namespace detail { namespace buffer
0058 {
0059 
0060 template <typename RangeIn, typename DistanceStrategy, typename RangeOut, typename Strategies>
0061 inline void simplify_input(RangeIn const& range,
0062                            DistanceStrategy const& distance,
0063                            RangeOut& simplified,
0064                            Strategies const& strategies)
0065 {
0066     // We have to simplify the ring before to avoid very small-scaled
0067     // features in the original (convex/concave/convex) being enlarged
0068     // in a very large scale and causing issues (IP's within pieces).
0069     // This might be reconsidered later. Simplifying with a very small
0070     // distance (1%% of the buffer) will never be visible in the result,
0071     // if it is using round joins. For miter joins they are even more
0072     // sensitive to small scale input features, however the result will
0073     // look better.
0074     // It also gets rid of duplicate points
0075 
0076     geometry::detail::simplify::simplify_range<2>::apply(range,
0077         simplified, distance.simplify_distance(),
0078         detail::simplify::douglas_peucker(),
0079         strategies);
0080 
0081 }
0082 
0083 
0084 template <typename RingOutput>
0085 struct buffer_range
0086 {
0087     typedef typename point_type<RingOutput>::type output_point_type;
0088     typedef typename coordinate_type<RingOutput>::type coordinate_type;
0089 
0090     template
0091     <
0092         typename Collection,
0093         typename Point,
0094         typename DistanceStrategy,
0095         typename SegmentStrategy,
0096         typename JoinStrategy,
0097         typename EndStrategy,
0098         typename RobustPolicy,
0099         typename Strategies
0100     >
0101     static inline
0102     void add_join(Collection& collection,
0103             Point const& penultimate_input,
0104             Point const& previous_input,
0105             output_point_type const& prev_perp1,
0106             output_point_type const& prev_perp2,
0107             Point const& input,
0108             output_point_type const& perp1,
0109             output_point_type const& perp2,
0110             geometry::strategy::buffer::buffer_side_selector side,
0111             DistanceStrategy const& distance,
0112             SegmentStrategy const& segment_strategy,
0113             JoinStrategy const& join_strategy,
0114             EndStrategy const& end_strategy,
0115             RobustPolicy const& ,
0116             Strategies const& strategies)
0117     {
0118         geometry::strategy::buffer::join_selector const join
0119                 = get_join_type(penultimate_input, previous_input, input,
0120                                 strategies);
0121 
0122         switch(join)
0123         {
0124             case geometry::strategy::buffer::join_continue :
0125                 // No join, we get two consecutive sides
0126                 break;
0127             case geometry::strategy::buffer::join_concave :
0128                 {
0129                     std::vector<output_point_type> range_out;
0130                     range_out.push_back(prev_perp2);
0131                     range_out.push_back(previous_input);
0132                     collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
0133 
0134                     range_out.clear();
0135                     range_out.push_back(previous_input);
0136                     range_out.push_back(perp1);
0137                     collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
0138                 }
0139                 break;
0140             case geometry::strategy::buffer::join_spike :
0141                 {
0142                     // For linestrings, only add spike at one side to avoid
0143                     // duplicates
0144                     std::vector<output_point_type> range_out;
0145                     end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out);
0146                     collection.add_endcap(end_strategy, range_out, previous_input);
0147                     collection.set_current_ring_concave();
0148                 }
0149                 break;
0150             case geometry::strategy::buffer::join_convex :
0151                 {
0152                     // The corner is convex, we create a join
0153                     // TODO (future) - avoid a separate vector, add the piece directly
0154                     output_point_type intersection_point;
0155                     if (line_line_intersection::apply(prev_perp1, prev_perp2,
0156                                                       perp1, perp2, previous_input,
0157                                                       segment_strategy.equidistant(),
0158                                                       intersection_point))
0159                     {
0160                         std::vector<output_point_type> range_out;
0161                         if (join_strategy.apply(intersection_point,
0162                                     previous_input, prev_perp2, perp1,
0163                                     distance.apply(previous_input, input, side),
0164                                     range_out))
0165                         {
0166                             collection.add_piece(geometry::strategy::buffer::buffered_join,
0167                                     previous_input, range_out);
0168                         }
0169                     }
0170                 }
0171                 break;
0172         }
0173     }
0174 
0175     // Returns true if collinear point p2 continues after p0 and p1.
0176     // If it turns back (spike), it returns false.
0177     static inline bool same_direction(output_point_type const& p0,
0178             output_point_type const& p1,
0179             output_point_type const& p2)
0180     {
0181         typedef typename cs_tag<output_point_type>::type cs_tag;
0182         return direction_code<cs_tag>(p0, p1, p2) == 1;
0183     }
0184 
0185     template <typename Strategies>
0186     static inline geometry::strategy::buffer::join_selector get_join_type(
0187             output_point_type const& p0,
0188             output_point_type const& p1,
0189             output_point_type const& p2,
0190             Strategies const& strategies)
0191     {
0192         int const side = strategies.side().apply(p0, p1, p2);
0193         return side == -1 ? geometry::strategy::buffer::join_convex
0194             :  side == 1  ? geometry::strategy::buffer::join_concave
0195             :  same_direction(p0, p1, p2) ? geometry::strategy::buffer::join_continue
0196             : geometry::strategy::buffer::join_spike;
0197     }
0198 
0199     template
0200     <
0201         typename Collection,
0202         typename Iterator,
0203         typename DistanceStrategy,
0204         typename SegmentStrategy,
0205         typename JoinStrategy,
0206         typename EndStrategy,
0207         typename RobustPolicy,
0208         typename Strategies
0209     >
0210     static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
0211                 Iterator begin, Iterator end,
0212                 geometry::strategy::buffer::buffer_side_selector side,
0213                 DistanceStrategy const& distance_strategy,
0214                 SegmentStrategy const& segment_strategy,
0215                 JoinStrategy const& join_strategy,
0216                 EndStrategy const& end_strategy,
0217                 RobustPolicy const& robust_policy,
0218                 Strategies const& strategies,
0219                 bool linear,
0220                 output_point_type& first_p1,
0221                 output_point_type& first_p2,
0222                 output_point_type& last_p1,
0223                 output_point_type& last_p2)
0224     {
0225         boost::ignore_unused(segment_strategy);
0226 
0227         typedef typename std::iterator_traits
0228         <
0229             Iterator
0230         >::value_type point_type;
0231 
0232         point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
0233 
0234         /*
0235          * last.p1    last.p2  these are the "previous (last) perpendicular points"
0236          * --------------
0237          * |            |
0238          * *------------*____  <- *prev
0239          * pup          |    | p1           "current perpendicular point 1"
0240          *              |    |
0241          *              |    |       this forms a "side", a side is a piece
0242          *              |    |
0243          *              *____| p2
0244          *
0245          *              ^
0246          *             *it
0247          *
0248          * pup: penultimate_point
0249          */
0250 
0251         bool const mark_flat
0252             = linear
0253                 && end_strategy.get_piece_type() == geometry::strategy::buffer::buffered_flat_end;
0254 
0255         geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
0256         bool first = true;
0257 
0258         Iterator it = begin;
0259 
0260         std::vector<output_point_type> generated_side;
0261         generated_side.reserve(2);
0262 
0263         for (Iterator prev = it++; it != end; ++it)
0264         {
0265             generated_side.clear();
0266             geometry::strategy::buffer::result_code error_code
0267                 = segment_strategy.apply(*prev, *it, side,
0268                                 distance_strategy, generated_side);
0269 
0270             if (error_code == geometry::strategy::buffer::result_no_output)
0271             {
0272                 // Because input is simplified, this is improbable,
0273                 // but it can happen for degenerate geometries
0274                 // Further handling of this side is skipped
0275                 continue;
0276             }
0277             else if (error_code == geometry::strategy::buffer::result_error_numerical)
0278             {
0279                 return error_code;
0280             }
0281 
0282             BOOST_GEOMETRY_ASSERT(! generated_side.empty());
0283 
0284             result = geometry::strategy::buffer::result_normal;
0285 
0286             if (! first)
0287             {
0288                  add_join(collection,
0289                         penultimate_point,
0290                         *prev, last_p1, last_p2,
0291                         *it, generated_side.front(), generated_side.back(),
0292                         side,
0293                         distance_strategy, segment_strategy, join_strategy, end_strategy,
0294                         robust_policy, strategies);
0295             }
0296 
0297             collection.add_side_piece(*prev, *it, generated_side, first, distance_strategy.empty(side));
0298 
0299             if (first && mark_flat)
0300             {
0301                 collection.mark_flat_start(*prev);
0302             }
0303 
0304             penultimate_point = *prev;
0305             ultimate_point = *it;
0306             last_p1 = generated_side.front();
0307             last_p2 = generated_side.back();
0308             prev = it;
0309             if (first)
0310             {
0311                 first = false;
0312                 second_point = *it;
0313                 first_p1 = generated_side.front();
0314                 first_p2 = generated_side.back();
0315             }
0316         }
0317 
0318         if (mark_flat)
0319         {
0320             collection.mark_flat_end(ultimate_point);
0321         }
0322 
0323         return result;
0324     }
0325 };
0326 
0327 template
0328 <
0329     typename Multi,
0330     typename PolygonOutput,
0331     typename Policy
0332 >
0333 struct buffer_multi
0334 {
0335     template
0336     <
0337         typename Collection,
0338         typename DistanceStrategy,
0339         typename SegmentStrategy,
0340         typename JoinStrategy,
0341         typename EndStrategy,
0342         typename PointStrategy,
0343         typename RobustPolicy,
0344         typename Strategies
0345     >
0346     static inline void apply(Multi const& multi,
0347             Collection& collection,
0348             DistanceStrategy const& distance_strategy,
0349             SegmentStrategy const& segment_strategy,
0350             JoinStrategy const& join_strategy,
0351             EndStrategy const& end_strategy,
0352             PointStrategy const& point_strategy,
0353             RobustPolicy const& robust_policy,
0354             Strategies const& strategies)
0355     {
0356         for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
0357         {
0358             Policy::apply(*it, collection,
0359                 distance_strategy, segment_strategy,
0360                 join_strategy, end_strategy, point_strategy,
0361                 robust_policy, strategies);
0362         }
0363     }
0364 };
0365 
0366 struct visit_pieces_default_policy
0367 {
0368     template <typename Collection>
0369     static inline void apply(Collection const&, int)
0370     {}
0371 };
0372 
0373 template
0374 <
0375     typename OutputPointType,
0376     typename Point,
0377     typename Collection,
0378     typename DistanceStrategy,
0379     typename PointStrategy
0380 >
0381 inline void buffer_point(Point const& point, Collection& collection,
0382         DistanceStrategy const& distance_strategy,
0383         PointStrategy const& point_strategy)
0384 {
0385     collection.start_new_ring(false);
0386     std::vector<OutputPointType> range_out;
0387     point_strategy.apply(point, distance_strategy, range_out);
0388     collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
0389     collection.set_piece_center(point);
0390     collection.finish_ring(geometry::strategy::buffer::result_normal);
0391 }
0392 
0393 
0394 }} // namespace detail::buffer
0395 #endif // DOXYGEN_NO_DETAIL
0396 
0397 
0398 #ifndef DOXYGEN_NO_DISPATCH
0399 namespace dispatch
0400 {
0401 
0402 template
0403 <
0404     typename Tag,
0405     typename RingInput,
0406     typename RingOutput
0407 >
0408 struct buffer_inserter
0409 {};
0410 
0411 
0412 
0413 template
0414 <
0415     typename Point,
0416     typename RingOutput
0417 >
0418 struct buffer_inserter<point_tag, Point, RingOutput>
0419 {
0420     template
0421     <
0422         typename Collection,
0423         typename DistanceStrategy,
0424         typename SegmentStrategy,
0425         typename JoinStrategy,
0426         typename EndStrategy,
0427         typename PointStrategy,
0428         typename RobustPolicy,
0429         typename Strategies
0430     >
0431     static inline void apply(Point const& point, Collection& collection,
0432             DistanceStrategy const& distance_strategy,
0433             SegmentStrategy const& ,
0434             JoinStrategy const& ,
0435             EndStrategy const& ,
0436             PointStrategy const& point_strategy,
0437             RobustPolicy const& ,
0438             Strategies const& )
0439     {
0440         detail::buffer::buffer_point
0441         <
0442             typename point_type<RingOutput>::type
0443         >(point, collection, distance_strategy, point_strategy);
0444     }
0445 };
0446 
0447 // Not a specialization, but called from specializations of ring and of polygon.
0448 // Calling code starts/finishes ring before/after apply
0449 template
0450 <
0451     typename RingInput,
0452     typename RingOutput
0453 >
0454 struct buffer_inserter_ring
0455 {
0456     using output_point_type = typename point_type<RingOutput>::type;
0457 
0458     template
0459     <
0460         typename Collection,
0461         typename Iterator,
0462         typename DistanceStrategy,
0463         typename SegmentStrategy,
0464         typename JoinStrategy,
0465         typename EndStrategy,
0466         typename RobustPolicy,
0467         typename Strategies
0468     >
0469     static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
0470                 Iterator begin, Iterator end,
0471                 geometry::strategy::buffer::buffer_side_selector side,
0472                 DistanceStrategy const& distance_strategy,
0473                 SegmentStrategy const& segment_strategy,
0474                 JoinStrategy const& join_strategy,
0475                 EndStrategy const& end_strategy,
0476                 RobustPolicy const& robust_policy,
0477                 Strategies const& strategies)
0478     {
0479         output_point_type first_p1, first_p2, last_p1, last_p2;
0480 
0481         typedef detail::buffer::buffer_range<RingOutput> buffer_range;
0482 
0483         geometry::strategy::buffer::result_code result
0484             = buffer_range::iterate(collection, begin, end,
0485                 side,
0486                 distance_strategy, segment_strategy, join_strategy, end_strategy,
0487                 robust_policy, strategies,
0488                 false, first_p1, first_p2, last_p1, last_p2);
0489 
0490         // Generate closing join
0491         if (result == geometry::strategy::buffer::result_normal)
0492         {
0493             buffer_range::add_join(collection,
0494                 *(end - 2),
0495                 *(end - 1), last_p1, last_p2,
0496                 *(begin + 1), first_p1, first_p2,
0497                 side,
0498                 distance_strategy, segment_strategy, join_strategy, end_strategy,
0499                 robust_policy, strategies);
0500         }
0501 
0502         // Buffer is closed automatically by last closing corner
0503         return result;
0504     }
0505 
0506     template
0507     <
0508         typename Collection,
0509         typename DistanceStrategy,
0510         typename SegmentStrategy,
0511         typename JoinStrategy,
0512         typename EndStrategy,
0513         typename PointStrategy,
0514         typename RobustPolicy,
0515         typename Strategies
0516     >
0517     static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
0518             Collection& collection,
0519             DistanceStrategy const& distance,
0520             SegmentStrategy const& segment_strategy,
0521             JoinStrategy const& join_strategy,
0522             EndStrategy const& end_strategy,
0523             PointStrategy const& point_strategy,
0524             RobustPolicy const& robust_policy,
0525             Strategies const& strategies)
0526     {
0527         // Use helper geometry to support non-mutable input Rings
0528         using simplified_ring_t = model::ring
0529             <
0530                 output_point_type,
0531                 point_order<RingInput>::value != counterclockwise,
0532                 closure<RingInput>::value != open
0533             >;
0534         simplified_ring_t simplified;
0535         detail::buffer::simplify_input(ring, distance, simplified, strategies);
0536 
0537         geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
0538 
0539         std::size_t n = boost::size(simplified);
0540         std::size_t const min_points = core_detail::closure::minimum_ring_size
0541             <
0542                 geometry::closure<simplified_ring_t>::value
0543             >::value;
0544 
0545         if (n >= min_points)
0546         {
0547             detail::closed_clockwise_view<simplified_ring_t const> view(simplified);
0548             if (distance.negative())
0549             {
0550                 // Walk backwards (rings will be reversed afterwards)
0551                 code = iterate(collection, boost::rbegin(view), boost::rend(view),
0552                         geometry::strategy::buffer::buffer_side_right,
0553                         distance, segment_strategy, join_strategy, end_strategy,
0554                         robust_policy, strategies);
0555             }
0556             else
0557             {
0558                 code = iterate(collection, boost::begin(view), boost::end(view),
0559                         geometry::strategy::buffer::buffer_side_left,
0560                         distance, segment_strategy, join_strategy, end_strategy,
0561                         robust_policy, strategies);
0562             }
0563         }
0564 
0565         if (code == geometry::strategy::buffer::result_no_output && n >= 1)
0566         {
0567             // Use point_strategy to buffer degenerated ring
0568             detail::buffer::buffer_point<output_point_type>
0569                 (
0570                     geometry::range::front(simplified),
0571                     collection, distance, point_strategy
0572                 );
0573         }
0574         return code;
0575     }
0576 };
0577 
0578 
0579 template
0580 <
0581     typename RingInput,
0582     typename RingOutput
0583 >
0584 struct buffer_inserter<ring_tag, RingInput, RingOutput>
0585 {
0586     template
0587     <
0588         typename Collection,
0589         typename DistanceStrategy,
0590         typename SegmentStrategy,
0591         typename JoinStrategy,
0592         typename EndStrategy,
0593         typename PointStrategy,
0594         typename RobustPolicy,
0595         typename Strategies
0596     >
0597     static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
0598             Collection& collection,
0599             DistanceStrategy const& distance,
0600             SegmentStrategy const& segment_strategy,
0601             JoinStrategy const& join_strategy,
0602             EndStrategy const& end_strategy,
0603             PointStrategy const& point_strategy,
0604             RobustPolicy const& robust_policy,
0605             Strategies const& strategies)
0606     {
0607         collection.start_new_ring(distance.negative());
0608         geometry::strategy::buffer::result_code const code
0609             = buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
0610                 collection, distance,
0611                 segment_strategy, join_strategy, end_strategy, point_strategy,
0612                 robust_policy, strategies);
0613         collection.finish_ring(code, ring, false, false);
0614         return code;
0615     }
0616 };
0617 
0618 template
0619 <
0620     typename Linestring,
0621     typename Polygon
0622 >
0623 struct buffer_inserter<linestring_tag, Linestring, Polygon>
0624 {
0625     using output_ring_type = typename ring_type<Polygon>::type;
0626     using output_point_type = typename point_type<output_ring_type>::type;
0627 
0628     template
0629     <
0630         typename Collection,
0631         typename Iterator,
0632         typename DistanceStrategy,
0633         typename SegmentStrategy,
0634         typename JoinStrategy,
0635         typename EndStrategy,
0636         typename RobustPolicy,
0637         typename Strategies
0638     >
0639     static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
0640                 Iterator begin, Iterator end,
0641                 geometry::strategy::buffer::buffer_side_selector side,
0642                 DistanceStrategy const& distance_strategy,
0643                 SegmentStrategy const& segment_strategy,
0644                 JoinStrategy const& join_strategy,
0645                 EndStrategy const& end_strategy,
0646                 RobustPolicy const& robust_policy,
0647                 Strategies const& strategies,
0648                 output_point_type& first_p1)
0649     {
0650         output_point_type const& ultimate_point = *(end - 1);
0651         output_point_type const& penultimate_point = *(end - 2);
0652 
0653         // For the end-cap, we need to have the last perpendicular point on the
0654         // other side of the linestring. If it is the second pass (right),
0655         // we have it already from the first phase (left).
0656         // But for the first pass, we have to generate it
0657         output_point_type reverse_p1;
0658         if (side == geometry::strategy::buffer::buffer_side_right)
0659         {
0660             reverse_p1 = first_p1;
0661         }
0662         else
0663         {
0664             std::vector<output_point_type> generated_side;
0665             geometry::strategy::buffer::result_code code
0666                 = segment_strategy.apply(ultimate_point, penultimate_point,
0667                     geometry::strategy::buffer::buffer_side_right,
0668                     distance_strategy, generated_side);
0669             if (code != geometry::strategy::buffer::result_normal)
0670             {
0671                 // No output or numerical error
0672                 return code;
0673             }
0674             reverse_p1 = generated_side.front();
0675         }
0676 
0677         output_point_type first_p2, last_p1, last_p2;
0678 
0679         geometry::strategy::buffer::result_code result
0680             = detail::buffer::buffer_range<output_ring_type>::iterate(collection,
0681                 begin, end, side,
0682                 distance_strategy, segment_strategy, join_strategy, end_strategy,
0683                 robust_policy, strategies,
0684                 true, first_p1, first_p2, last_p1, last_p2);
0685 
0686         if (result == geometry::strategy::buffer::result_normal)
0687         {
0688             std::vector<output_point_type> range_out;
0689             end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1,
0690                                side, distance_strategy, range_out);
0691             collection.add_endcap(end_strategy, range_out, ultimate_point);
0692         }
0693         return result;
0694     }
0695 
0696     template
0697     <
0698         typename Collection,
0699         typename DistanceStrategy,
0700         typename SegmentStrategy,
0701         typename JoinStrategy,
0702         typename EndStrategy,
0703         typename PointStrategy,
0704         typename RobustPolicy,
0705         typename Strategies
0706     >
0707     static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
0708             Collection& collection,
0709             DistanceStrategy const& distance,
0710             SegmentStrategy const& segment_strategy,
0711             JoinStrategy const& join_strategy,
0712             EndStrategy const& end_strategy,
0713             PointStrategy const& point_strategy,
0714             RobustPolicy const& robust_policy,
0715             Strategies const& strategies)
0716     {
0717         // Use helper geometry to support non-mutable input Linestrings
0718         model::linestring<output_point_type> simplified;
0719         detail::buffer::simplify_input(linestring, distance, simplified, strategies);
0720 
0721         geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
0722         std::size_t n = boost::size(simplified);
0723         if (n > 1)
0724         {
0725             collection.start_new_ring(false);
0726             output_point_type first_p1;
0727             code = iterate(collection,
0728                     boost::begin(simplified), boost::end(simplified),
0729                     geometry::strategy::buffer::buffer_side_left,
0730                     distance, segment_strategy, join_strategy, end_strategy,
0731                     robust_policy, strategies,
0732                     first_p1);
0733 
0734             if (code == geometry::strategy::buffer::result_normal)
0735             {
0736                 code = iterate(collection,
0737                         boost::rbegin(simplified), boost::rend(simplified),
0738                         geometry::strategy::buffer::buffer_side_right,
0739                         distance, segment_strategy, join_strategy, end_strategy,
0740                         robust_policy, strategies,
0741                         first_p1);
0742             }
0743             collection.finish_ring(code);
0744         }
0745         if (code == geometry::strategy::buffer::result_no_output && n >= 1)
0746         {
0747             // Use point_strategy to buffer degenerated linestring
0748             detail::buffer::buffer_point<output_point_type>
0749                 (
0750                     geometry::range::front(simplified),
0751                     collection, distance, point_strategy
0752                 );
0753         }
0754         return code;
0755     }
0756 };
0757 
0758 
0759 template
0760 <
0761     typename PolygonInput,
0762     typename PolygonOutput
0763 >
0764 struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
0765 {
0766 private:
0767     typedef typename ring_type<PolygonInput>::type input_ring_type;
0768     typedef typename ring_type<PolygonOutput>::type output_ring_type;
0769 
0770     typedef buffer_inserter_ring<input_ring_type, output_ring_type> policy;
0771 
0772 
0773     template
0774     <
0775         typename Iterator,
0776         typename Collection,
0777         typename DistanceStrategy,
0778         typename SegmentStrategy,
0779         typename JoinStrategy,
0780         typename EndStrategy,
0781         typename PointStrategy,
0782         typename RobustPolicy,
0783         typename Strategies
0784     >
0785     static inline
0786     void iterate(Iterator begin, Iterator end,
0787             Collection& collection,
0788             DistanceStrategy const& distance,
0789             SegmentStrategy const& segment_strategy,
0790             JoinStrategy const& join_strategy,
0791             EndStrategy const& end_strategy,
0792             PointStrategy const& point_strategy,
0793             RobustPolicy const& robust_policy,
0794             Strategies const& strategies,
0795             bool is_interior)
0796     {
0797         for (Iterator it = begin; it != end; ++it)
0798         {
0799             // For exterior rings, it deflates if distance is negative.
0800             // For interior rings, it is vice versa
0801             bool const deflate = is_interior
0802                     ? ! distance.negative()
0803                     : distance.negative();
0804 
0805             collection.start_new_ring(deflate);
0806             geometry::strategy::buffer::result_code const code
0807                     = policy::apply(*it, collection, distance, segment_strategy,
0808                     join_strategy, end_strategy, point_strategy,
0809                     robust_policy, strategies);
0810 
0811             collection.finish_ring(code, *it, is_interior, false);
0812         }
0813     }
0814 
0815     template
0816     <
0817         typename InteriorRings,
0818         typename Collection,
0819         typename DistanceStrategy,
0820         typename SegmentStrategy,
0821         typename JoinStrategy,
0822         typename EndStrategy,
0823         typename PointStrategy,
0824         typename RobustPolicy,
0825         typename Strategies
0826     >
0827     static inline
0828     void apply_interior_rings(InteriorRings const& interior_rings,
0829             Collection& collection,
0830             DistanceStrategy const& distance,
0831             SegmentStrategy const& segment_strategy,
0832             JoinStrategy const& join_strategy,
0833             EndStrategy const& end_strategy,
0834             PointStrategy const& point_strategy,
0835             RobustPolicy const& robust_policy,
0836             Strategies const& strategies)
0837     {
0838         iterate(boost::begin(interior_rings), boost::end(interior_rings),
0839             collection, distance, segment_strategy,
0840             join_strategy, end_strategy, point_strategy,
0841             robust_policy, strategies, true);
0842     }
0843 
0844 public:
0845     template
0846     <
0847         typename Collection,
0848         typename DistanceStrategy,
0849         typename SegmentStrategy,
0850         typename JoinStrategy,
0851         typename EndStrategy,
0852         typename PointStrategy,
0853         typename RobustPolicy,
0854         typename Strategies
0855     >
0856     static inline void apply(PolygonInput const& polygon,
0857             Collection& collection,
0858             DistanceStrategy const& distance,
0859             SegmentStrategy const& segment_strategy,
0860             JoinStrategy const& join_strategy,
0861             EndStrategy const& end_strategy,
0862             PointStrategy const& point_strategy,
0863             RobustPolicy const& robust_policy,
0864             Strategies const& strategies)
0865     {
0866         {
0867             collection.start_new_ring(distance.negative());
0868 
0869             geometry::strategy::buffer::result_code const code
0870                 = policy::apply(exterior_ring(polygon), collection,
0871                     distance, segment_strategy,
0872                     join_strategy, end_strategy, point_strategy,
0873                     robust_policy, strategies);
0874 
0875             collection.finish_ring(code, exterior_ring(polygon), false,
0876                     geometry::num_interior_rings(polygon) > 0u);
0877         }
0878 
0879         apply_interior_rings(interior_rings(polygon),
0880                 collection, distance, segment_strategy,
0881                 join_strategy, end_strategy, point_strategy,
0882                 robust_policy, strategies);
0883     }
0884 };
0885 
0886 
0887 template
0888 <
0889     typename Multi,
0890     typename PolygonOutput
0891 >
0892 struct buffer_inserter<multi_tag, Multi, PolygonOutput>
0893     : public detail::buffer::buffer_multi
0894              <
0895                 Multi,
0896                 PolygonOutput,
0897                 dispatch::buffer_inserter
0898                 <
0899                     typename single_tag_of
0900                                 <
0901                                     typename tag<Multi>::type
0902                                 >::type,
0903                     typename boost::range_value<Multi const>::type,
0904                     typename geometry::ring_type<PolygonOutput>::type
0905                 >
0906             >
0907 {};
0908 
0909 
0910 } // namespace dispatch
0911 #endif // DOXYGEN_NO_DISPATCH
0912 
0913 #ifndef DOXYGEN_NO_DETAIL
0914 namespace detail { namespace buffer
0915 {
0916 
0917 template
0918 <
0919     typename GeometryOutput,
0920     typename GeometryInput,
0921     typename OutputIterator,
0922     typename DistanceStrategy,
0923     typename SegmentStrategy,
0924     typename JoinStrategy,
0925     typename EndStrategy,
0926     typename PointStrategy,
0927     typename Strategies,
0928     typename RobustPolicy,
0929     typename VisitPiecesPolicy
0930 >
0931 inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
0932         DistanceStrategy const& distance_strategy,
0933         SegmentStrategy const& segment_strategy,
0934         JoinStrategy const& join_strategy,
0935         EndStrategy const& end_strategy,
0936         PointStrategy const& point_strategy,
0937         Strategies const& strategies,
0938         RobustPolicy const& robust_policy,
0939         VisitPiecesPolicy& visit_pieces_policy
0940     )
0941 {
0942     boost::ignore_unused(visit_pieces_policy);
0943 
0944     using collection_type = detail::buffer::buffered_piece_collection
0945         <
0946             typename geometry::ring_type<GeometryOutput>::type,
0947             Strategies,
0948             DistanceStrategy,
0949             RobustPolicy
0950         >;
0951     collection_type collection(strategies, distance_strategy, robust_policy);
0952     collection_type const& const_collection = collection;
0953 
0954     static constexpr bool areal = util::is_areal<GeometryInput>::value;
0955 
0956     dispatch::buffer_inserter
0957         <
0958             typename tag_cast
0959                 <
0960                     typename tag<GeometryInput>::type,
0961                     multi_tag
0962                 >::type,
0963             GeometryInput,
0964             GeometryOutput
0965         >::apply(geometry_input, collection,
0966                  distance_strategy, segment_strategy, join_strategy,
0967                  end_strategy, point_strategy,
0968                  robust_policy, strategies);
0969 
0970     collection.get_turns();
0971     if BOOST_GEOMETRY_CONSTEXPR (areal)
0972     {
0973         collection.check_turn_in_original();
0974     }
0975     collection.handle_colocations();
0976     collection.check_turn_in_pieces();
0977     collection.make_traversable_consistent_per_cluster();
0978 
0979     // Visit the piece collection. This does nothing (by default), but
0980     // optionally a debugging tool can be attached (e.g. console or svg),
0981     // or the piece collection can be unit-tested
0982     // phase 0: turns (before discarded)
0983     visit_pieces_policy.apply(const_collection, 0);
0984 
0985     collection.discard_rings();
0986     collection.block_turns();
0987     collection.enrich();
0988 
0989     // phase 1: turns (after enrichment/clustering)
0990     visit_pieces_policy.apply(const_collection, 1);
0991 
0992     if BOOST_GEOMETRY_CONSTEXPR (areal)
0993     {
0994         collection.deflate_check_turns();
0995     }
0996 
0997     collection.traverse();
0998 
0999     // Reverse all offsetted rings / traversed rings if:
1000     // - they were generated on the negative side (deflate) of polygons
1001     // - the output is counter clockwise
1002     // and avoid reversing twice
1003     bool reverse = distance_strategy.negative() && areal;
1004     if BOOST_GEOMETRY_CONSTEXPR (geometry::point_order<GeometryOutput>::value == counterclockwise)
1005     {
1006         reverse = ! reverse;
1007     }
1008     if (reverse)
1009     {
1010         collection.reverse();
1011     }
1012 
1013     if BOOST_GEOMETRY_CONSTEXPR (areal)
1014     {
1015         if (distance_strategy.negative())
1016         {
1017             collection.discard_nonintersecting_deflated_rings();
1018         }
1019     }
1020 
1021     collection.template assign<GeometryOutput>(out);
1022 
1023     // Visit collection again
1024     // phase 2: rings (after traversing)
1025     visit_pieces_policy.apply(const_collection, 2);
1026 }
1027 
1028 template
1029 <
1030     typename GeometryOutput,
1031     typename GeometryInput,
1032     typename OutputIterator,
1033     typename DistanceStrategy,
1034     typename SegmentStrategy,
1035     typename JoinStrategy,
1036     typename EndStrategy,
1037     typename PointStrategy,
1038     typename Strategies,
1039     typename RobustPolicy
1040 >
1041 inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
1042         DistanceStrategy const& distance_strategy,
1043         SegmentStrategy const& segment_strategy,
1044         JoinStrategy const& join_strategy,
1045         EndStrategy const& end_strategy,
1046         PointStrategy const& point_strategy,
1047         Strategies const& strategies,
1048         RobustPolicy const& robust_policy)
1049 {
1050     detail::buffer::visit_pieces_default_policy visitor;
1051     buffer_inserter<GeometryOutput>(geometry_input, out,
1052         distance_strategy, segment_strategy, join_strategy,
1053         end_strategy, point_strategy,
1054         strategies, robust_policy, visitor);
1055 }
1056 #endif // DOXYGEN_NO_DETAIL
1057 
1058 }} // namespace detail::buffer
1059 
1060 }} // namespace boost::geometry
1061 
1062 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP