File indexing completed on 2025-09-18 08:42:38
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
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
0069
0070
0071
0072
0073
0074
0075
0076
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
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
0143
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
0153
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
0176
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;
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
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
0270
0271
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 }}
0390 #endif
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
0441
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
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
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
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
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
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
0639
0640
0641
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
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
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
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
0780
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 }
0884 #endif
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
0946
0947
0948
0949 visit_pieces_policy.apply(const_collection, 0);
0950
0951 collection.discard_rings();
0952 collection.block_turns();
0953 collection.enrich();
0954
0955
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
0966
0967
0968
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
0990
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
1021
1022 }}
1023
1024 }}
1025
1026 #endif