Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:42:38

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