]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/geometry/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / geometry / include / boost / geometry / algorithms / detail / buffer / buffer_inserter.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
3// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
4
5// Use, modification and distribution is subject to the Boost Software License,
6// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8
9#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
10#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP
11
12#include <cstddef>
13#include <iterator>
14
15
16#include <boost/core/ignore_unused.hpp>
17#include <boost/numeric/conversion/cast.hpp>
18#include <boost/range.hpp>
19
20#include <boost/geometry/core/assert.hpp>
21#include <boost/geometry/core/closure.hpp>
22#include <boost/geometry/core/exterior_ring.hpp>
23#include <boost/geometry/core/interior_rings.hpp>
24
25#include <boost/geometry/util/condition.hpp>
26#include <boost/geometry/util/math.hpp>
27
28#include <boost/geometry/strategies/buffer.hpp>
29#include <boost/geometry/strategies/side.hpp>
30#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
31#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
32#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
33
34#include <boost/geometry/algorithms/assign.hpp>
35#include <boost/geometry/algorithms/num_interior_rings.hpp>
36#include <boost/geometry/algorithms/simplify.hpp>
37
38#include <boost/geometry/views/detail/normalized_view.hpp>
39
40#if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
41#include <boost/geometry/strategies/cartesian/distance_projected_point_ax.hpp>
42#endif
43
44
45namespace boost { namespace geometry
46{
47
48#ifndef DOXYGEN_NO_DETAIL
49namespace detail { namespace buffer
50{
51
52template <typename Range, typename DistanceStrategy>
53inline void simplify_input(Range const& range,
54 DistanceStrategy const& distance,
55 Range& simplified)
56{
57 // We have to simplify the ring before to avoid very small-scaled
58 // features in the original (convex/concave/convex) being enlarged
59 // in a very large scale and causing issues (IP's within pieces).
60 // This might be reconsidered later. Simplifying with a very small
61 // distance (1%% of the buffer) will never be visible in the result,
62 // if it is using round joins. For miter joins they are even more
63 // sensitive to small scale input features, however the result will
64 // look better.
65 // It also gets rid of duplicate points
66#if ! defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX)
67 geometry::simplify(range, simplified, distance.simplify_distance());
68#else
69
70 typedef typename boost::range_value<Range>::type point_type;
71 typedef strategy::distance::detail::projected_point_ax<> ax_type;
72 typedef typename strategy::distance::services::return_type
73 <
74 strategy::distance::detail::projected_point_ax<>,
75 point_type,
76 point_type
77 >::type return_type;
78
79 typedef strategy::distance::detail::projected_point_ax_less
80 <
81 return_type
82 > comparator_type;
83
84 typedef strategy::simplify::detail::douglas_peucker
85 <
86 point_type,
87 strategy::distance::detail::projected_point_ax<>,
88 comparator_type
89 > dp_ax;
90
91 return_type max_distance(distance.simplify_distance() * 2.0,
92 distance.simplify_distance());
93 comparator_type comparator(max_distance);
94 dp_ax strategy(comparator);
95
96 geometry::simplify(range, simplified, max_distance, strategy);
97#endif
98
99 if (boost::size(simplified) == 2
100 && geometry::equals(geometry::range::front(simplified),
101 geometry::range::back(simplified)))
102 {
103 traits::resize<Range>::apply(simplified, 1);
104 }
105}
106
107
108template <typename RingOutput>
109struct buffer_range
110{
111 typedef typename point_type<RingOutput>::type output_point_type;
112 typedef typename coordinate_type<RingOutput>::type coordinate_type;
113
114 template
115 <
116 typename Collection,
117 typename Point,
118 typename DistanceStrategy,
119 typename JoinStrategy,
120 typename EndStrategy,
121 typename RobustPolicy
122 >
123 static inline
124 void add_join(Collection& collection,
125 Point const& penultimate_input,
126 Point const& previous_input,
127 output_point_type const& prev_perp1,
128 output_point_type const& prev_perp2,
129 Point const& input,
130 output_point_type const& perp1,
131 output_point_type const& perp2,
132 strategy::buffer::buffer_side_selector side,
133 DistanceStrategy const& distance,
134 JoinStrategy const& join_strategy,
135 EndStrategy const& end_strategy,
136 RobustPolicy const& )
137 {
138 output_point_type intersection_point;
139 geometry::assign_zero(intersection_point);
140
141 strategy::buffer::join_selector join
142 = get_join_type(penultimate_input, previous_input, input);
143 if (join == strategy::buffer::join_convex)
144 {
145 // Calculate the intersection-point formed by the two sides.
146 // It might be that the two sides are not convex, but continue
147 // or spikey, we then change the join-type
148 join = line_line_intersection::apply(
149 perp1, perp2, prev_perp1, prev_perp2,
150 intersection_point);
151
152 }
153
154 switch(join)
155 {
156 case strategy::buffer::join_continue :
157 // No join, we get two consecutive sides
158 break;
159 case strategy::buffer::join_concave :
160 {
161 std::vector<output_point_type> range_out;
162 range_out.push_back(prev_perp2);
163 range_out.push_back(previous_input);
164 collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
165
166 range_out.clear();
167 range_out.push_back(previous_input);
168 range_out.push_back(perp1);
169 collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
170 }
171 break;
172 case strategy::buffer::join_spike :
173 {
174 // For linestrings, only add spike at one side to avoid
175 // duplicates
176 std::vector<output_point_type> range_out;
177 end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out);
178 collection.add_endcap(end_strategy, range_out, previous_input);
179 collection.set_current_ring_concave();
180 }
181 break;
182 case strategy::buffer::join_convex :
183 {
184 // The corner is convex, we create a join
185 // TODO (future) - avoid a separate vector, add the piece directly
186 std::vector<output_point_type> range_out;
187 if (join_strategy.apply(intersection_point,
188 previous_input, prev_perp2, perp1,
189 distance.apply(previous_input, input, side),
190 range_out))
191 {
192 collection.add_piece(strategy::buffer::buffered_join,
193 previous_input, range_out);
194 }
195 }
196 break;
197 }
198 }
199
200 static inline strategy::buffer::join_selector get_join_type(
201 output_point_type const& p0,
202 output_point_type const& p1,
203 output_point_type const& p2)
204 {
205 typedef typename strategy::side::services::default_strategy
206 <
207 typename cs_tag<output_point_type>::type
208 >::type side_strategy;
209
210 int const side = side_strategy::apply(p0, p1, p2);
211 return side == -1 ? strategy::buffer::join_convex
212 : side == 1 ? strategy::buffer::join_concave
213 : parallel_continue
214 (
215 get<0>(p2) - get<0>(p1),
216 get<1>(p2) - get<1>(p1),
217 get<0>(p1) - get<0>(p0),
218 get<1>(p1) - get<1>(p0)
219 ) ? strategy::buffer::join_continue
220 : strategy::buffer::join_spike;
221 }
222
223 template
224 <
225 typename Collection,
226 typename Iterator,
227 typename DistanceStrategy,
228 typename SideStrategy,
229 typename JoinStrategy,
230 typename EndStrategy,
231 typename RobustPolicy
232 >
233 static inline strategy::buffer::result_code iterate(Collection& collection,
234 Iterator begin, Iterator end,
235 strategy::buffer::buffer_side_selector side,
236 DistanceStrategy const& distance_strategy,
237 SideStrategy const& side_strategy,
238 JoinStrategy const& join_strategy,
239 EndStrategy const& end_strategy,
240 RobustPolicy const& robust_policy,
241 output_point_type& first_p1,
242 output_point_type& first_p2,
243 output_point_type& last_p1,
244 output_point_type& last_p2)
245 {
246 boost::ignore_unused(side_strategy);
247
248 typedef typename std::iterator_traits
249 <
250 Iterator
251 >::value_type point_type;
252
253 point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end
254
255 /*
256 * last.p1 last.p2 these are the "previous (last) perpendicular points"
257 * --------------
258 * | |
259 * *------------*____ <- *prev
260 * pup | | p1 "current perpendicular point 1"
261 * | |
262 * | | this forms a "side", a side is a piece
263 * | |
264 * *____| p2
265 *
266 * ^
267 * *it
268 *
269 * pup: penultimate_point
270 */
271
272 strategy::buffer::result_code result = strategy::buffer::result_no_output;
273 bool first = true;
274
275 Iterator it = begin;
276
277 std::vector<output_point_type> generated_side;
278 generated_side.reserve(2);
279
280 for (Iterator prev = it++; it != end; ++it)
281 {
282 generated_side.clear();
283 strategy::buffer::result_code error_code
284 = side_strategy.apply(*prev, *it, side,
285 distance_strategy, generated_side);
286
287 if (error_code == strategy::buffer::result_no_output)
288 {
289 // Because input is simplified, this is improbable,
290 // but it can happen for degenerate geometries
291 // Further handling of this side is skipped
292 continue;
293 }
294 else if (error_code == strategy::buffer::result_error_numerical)
295 {
296 return error_code;
297 }
298
299 BOOST_GEOMETRY_ASSERT(! generated_side.empty());
300
301 result = strategy::buffer::result_normal;
302
303 if (! first)
304 {
305 add_join(collection,
306 penultimate_point,
307 *prev, last_p1, last_p2,
308 *it, generated_side.front(), generated_side.back(),
309 side,
310 distance_strategy, join_strategy, end_strategy,
311 robust_policy);
312 }
313
314 collection.add_side_piece(*prev, *it, generated_side, first);
315
316 penultimate_point = *prev;
317 ultimate_point = *it;
318 last_p1 = generated_side.front();
319 last_p2 = generated_side.back();
320 prev = it;
321 if (first)
322 {
323 first = false;
324 second_point = *it;
325 first_p1 = generated_side.front();
326 first_p2 = generated_side.back();
327 }
328 }
329 return result;
330 }
331};
332
333template
334<
335 typename Multi,
336 typename PolygonOutput,
337 typename Policy
338>
339struct buffer_multi
340{
341 template
342 <
343 typename Collection,
344 typename DistanceStrategy,
345 typename SideStrategy,
346 typename JoinStrategy,
347 typename EndStrategy,
348 typename PointStrategy,
349 typename RobustPolicy
350 >
351 static inline void apply(Multi const& multi,
352 Collection& collection,
353 DistanceStrategy const& distance_strategy,
354 SideStrategy const& side_strategy,
355 JoinStrategy const& join_strategy,
356 EndStrategy const& end_strategy,
357 PointStrategy const& point_strategy,
358 RobustPolicy const& robust_policy)
359 {
360 for (typename boost::range_iterator<Multi const>::type
361 it = boost::begin(multi);
362 it != boost::end(multi);
363 ++it)
364 {
365 Policy::apply(*it, collection,
366 distance_strategy, side_strategy,
367 join_strategy, end_strategy, point_strategy,
368 robust_policy);
369 }
370 }
371};
372
373struct visit_pieces_default_policy
374{
375 template <typename Collection>
376 static inline void apply(Collection const&, int)
377 {}
378};
379
380template
381<
382 typename OutputPointType,
383 typename Point,
384 typename Collection,
385 typename DistanceStrategy,
386 typename PointStrategy
387>
388inline void buffer_point(Point const& point, Collection& collection,
389 DistanceStrategy const& distance_strategy,
390 PointStrategy const& point_strategy)
391{
392 collection.start_new_ring();
393 std::vector<OutputPointType> range_out;
394 point_strategy.apply(point, distance_strategy, range_out);
395 collection.add_piece(strategy::buffer::buffered_point, range_out, false);
396 collection.set_piece_center(point);
397 collection.finish_ring(strategy::buffer::result_normal);
398}
399
400
401}} // namespace detail::buffer
402#endif // DOXYGEN_NO_DETAIL
403
404
405#ifndef DOXYGEN_NO_DISPATCH
406namespace dispatch
407{
408
409template
410<
411 typename Tag,
412 typename RingInput,
413 typename RingOutput
414>
415struct buffer_inserter
416{};
417
418
419
420template
421<
422 typename Point,
423 typename RingOutput
424>
425struct buffer_inserter<point_tag, Point, RingOutput>
426{
427 template
428 <
429 typename Collection,
430 typename DistanceStrategy,
431 typename SideStrategy,
432 typename JoinStrategy,
433 typename EndStrategy,
434 typename PointStrategy,
435 typename RobustPolicy
436 >
437 static inline void apply(Point const& point, Collection& collection,
438 DistanceStrategy const& distance_strategy,
439 SideStrategy const& ,
440 JoinStrategy const& ,
441 EndStrategy const& ,
442 PointStrategy const& point_strategy,
443 RobustPolicy const& )
444 {
445 detail::buffer::buffer_point
446 <
447 typename point_type<RingOutput>::type
448 >(point, collection, distance_strategy, point_strategy);
449 }
450};
451
452
453template
454<
455 typename RingInput,
456 typename RingOutput
457>
458struct buffer_inserter<ring_tag, RingInput, RingOutput>
459{
460 typedef typename point_type<RingOutput>::type output_point_type;
461
462 template
463 <
464 typename Collection,
465 typename Iterator,
466 typename DistanceStrategy,
467 typename SideStrategy,
468 typename JoinStrategy,
469 typename EndStrategy,
470 typename RobustPolicy
471 >
472 static inline strategy::buffer::result_code iterate(Collection& collection,
473 Iterator begin, Iterator end,
474 strategy::buffer::buffer_side_selector side,
475 DistanceStrategy const& distance_strategy,
476 SideStrategy const& side_strategy,
477 JoinStrategy const& join_strategy,
478 EndStrategy const& end_strategy,
479 RobustPolicy const& robust_policy)
480 {
481 output_point_type first_p1, first_p2, last_p1, last_p2;
482
483 typedef detail::buffer::buffer_range<RingOutput> buffer_range;
484
485 strategy::buffer::result_code result
486 = buffer_range::iterate(collection, begin, end,
487 side,
488 distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
489 first_p1, first_p2, last_p1, last_p2);
490
491 // Generate closing join
492 if (result == strategy::buffer::result_normal)
493 {
494 buffer_range::add_join(collection,
495 *(end - 2),
496 *(end - 1), last_p1, last_p2,
497 *(begin + 1), first_p1, first_p2,
498 side,
499 distance_strategy, join_strategy, end_strategy,
500 robust_policy);
501 }
502
503 // Buffer is closed automatically by last closing corner
504 return result;
505 }
506
507 template
508 <
509 typename Collection,
510 typename DistanceStrategy,
511 typename SideStrategy,
512 typename JoinStrategy,
513 typename EndStrategy,
514 typename PointStrategy,
515 typename RobustPolicy
516 >
517 static inline strategy::buffer::result_code apply(RingInput const& ring,
518 Collection& collection,
519 DistanceStrategy const& distance,
520 SideStrategy const& side_strategy,
521 JoinStrategy const& join_strategy,
522 EndStrategy const& end_strategy,
523 PointStrategy const& point_strategy,
524 RobustPolicy const& robust_policy)
525 {
526 RingInput simplified;
527 detail::buffer::simplify_input(ring, distance, simplified);
528
529 strategy::buffer::result_code code = strategy::buffer::result_no_output;
530
531 std::size_t n = boost::size(simplified);
532 std::size_t const min_points = core_detail::closure::minimum_ring_size
533 <
534 geometry::closure<RingInput>::value
535 >::value;
536
537 if (n >= min_points)
538 {
539 detail::normalized_view<RingInput const> view(simplified);
540 if (distance.negative())
541 {
542 // Walk backwards (rings will be reversed afterwards)
543 code = iterate(collection, boost::rbegin(view), boost::rend(view),
544 strategy::buffer::buffer_side_right,
545 distance, side_strategy, join_strategy, end_strategy, robust_policy);
546 }
547 else
548 {
549 code = iterate(collection, boost::begin(view), boost::end(view),
550 strategy::buffer::buffer_side_left,
551 distance, side_strategy, join_strategy, end_strategy, robust_policy);
552 }
553 }
554
555 if (code == strategy::buffer::result_no_output && n >= 1)
556 {
557 // Use point_strategy to buffer degenerated ring
558 detail::buffer::buffer_point<output_point_type>
559 (
560 geometry::range::front(simplified),
561 collection, distance, point_strategy
562 );
563 }
564 return code;
565 }
566};
567
568
569template
570<
571 typename Linestring,
572 typename Polygon
573>
574struct buffer_inserter<linestring_tag, Linestring, Polygon>
575{
576 typedef typename ring_type<Polygon>::type output_ring_type;
577 typedef typename point_type<output_ring_type>::type output_point_type;
578 typedef typename point_type<Linestring>::type input_point_type;
579
580 template
581 <
582 typename Collection,
583 typename Iterator,
584 typename DistanceStrategy,
585 typename SideStrategy,
586 typename JoinStrategy,
587 typename EndStrategy,
588 typename RobustPolicy
589 >
590 static inline strategy::buffer::result_code iterate(Collection& collection,
591 Iterator begin, Iterator end,
592 strategy::buffer::buffer_side_selector side,
593 DistanceStrategy const& distance_strategy,
594 SideStrategy const& side_strategy,
595 JoinStrategy const& join_strategy,
596 EndStrategy const& end_strategy,
597 RobustPolicy const& robust_policy,
598 output_point_type& first_p1)
599 {
600 input_point_type const& ultimate_point = *(end - 1);
601 input_point_type const& penultimate_point = *(end - 2);
602
603 // For the end-cap, we need to have the last perpendicular point on the
604 // other side of the linestring. If it is the second pass (right),
605 // we have it already from the first phase (left).
606 // But for the first pass, we have to generate it
607 output_point_type reverse_p1;
608 if (side == strategy::buffer::buffer_side_right)
609 {
610 reverse_p1 = first_p1;
611 }
612 else
613 {
614 std::vector<output_point_type> generated_side;
615 strategy::buffer::result_code code
616 = side_strategy.apply(ultimate_point, penultimate_point,
617 strategy::buffer::buffer_side_right,
618 distance_strategy, generated_side);
619 if (code != strategy::buffer::result_normal)
620 {
621 // No output or numerical error
622 return code;
623 }
624 reverse_p1 = generated_side.front();
625 }
626
627 output_point_type first_p2, last_p1, last_p2;
628
629 strategy::buffer::result_code result
630 = detail::buffer::buffer_range<output_ring_type>::iterate(collection,
631 begin, end, side,
632 distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
633 first_p1, first_p2, last_p1, last_p2);
634
635 if (result == strategy::buffer::result_normal)
636 {
637 std::vector<output_point_type> range_out;
638 end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
639 collection.add_endcap(end_strategy, range_out, ultimate_point);
640 }
641 return result;
642 }
643
644 template
645 <
646 typename Collection,
647 typename DistanceStrategy,
648 typename SideStrategy,
649 typename JoinStrategy,
650 typename EndStrategy,
651 typename PointStrategy,
652 typename RobustPolicy
653 >
654 static inline strategy::buffer::result_code apply(Linestring const& linestring, Collection& collection,
655 DistanceStrategy const& distance,
656 SideStrategy const& side_strategy,
657 JoinStrategy const& join_strategy,
658 EndStrategy const& end_strategy,
659 PointStrategy const& point_strategy,
660 RobustPolicy const& robust_policy)
661 {
662 Linestring simplified;
663 detail::buffer::simplify_input(linestring, distance, simplified);
664
665 strategy::buffer::result_code code = strategy::buffer::result_no_output;
666 std::size_t n = boost::size(simplified);
667 if (n > 1)
668 {
669 collection.start_new_ring();
670 output_point_type first_p1;
671 code = iterate(collection,
672 boost::begin(simplified), boost::end(simplified),
673 strategy::buffer::buffer_side_left,
674 distance, side_strategy, join_strategy, end_strategy, robust_policy,
675 first_p1);
676
677 if (code == strategy::buffer::result_normal)
678 {
679 code = iterate(collection,
680 boost::rbegin(simplified), boost::rend(simplified),
681 strategy::buffer::buffer_side_right,
682 distance, side_strategy, join_strategy, end_strategy, robust_policy,
683 first_p1);
684 }
685 collection.finish_ring(code);
686 }
687 if (code == strategy::buffer::result_no_output && n >= 1)
688 {
689 // Use point_strategy to buffer degenerated linestring
690 detail::buffer::buffer_point<output_point_type>
691 (
692 geometry::range::front(simplified),
693 collection, distance, point_strategy
694 );
695 }
696 return code;
697 }
698};
699
700
701template
702<
703 typename PolygonInput,
704 typename PolygonOutput
705>
706struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
707{
708private:
709 typedef typename ring_type<PolygonInput>::type input_ring_type;
710 typedef typename ring_type<PolygonOutput>::type output_ring_type;
711
712 typedef buffer_inserter<ring_tag, input_ring_type, output_ring_type> policy;
713
714
715 template
716 <
717 typename Iterator,
718 typename Collection,
719 typename DistanceStrategy,
720 typename SideStrategy,
721 typename JoinStrategy,
722 typename EndStrategy,
723 typename PointStrategy,
724 typename RobustPolicy
725 >
726 static inline
727 void iterate(Iterator begin, Iterator end,
728 Collection& collection,
729 DistanceStrategy const& distance,
730 SideStrategy const& side_strategy,
731 JoinStrategy const& join_strategy,
732 EndStrategy const& end_strategy,
733 PointStrategy const& point_strategy,
734 RobustPolicy const& robust_policy,
735 bool is_interior)
736 {
737 for (Iterator it = begin; it != end; ++it)
738 {
739 collection.start_new_ring();
740 strategy::buffer::result_code const code
741 = policy::apply(*it, collection, distance, side_strategy,
742 join_strategy, end_strategy, point_strategy,
743 robust_policy);
744
745 collection.finish_ring(code, is_interior);
746 }
747 }
748
749 template
750 <
751 typename InteriorRings,
752 typename Collection,
753 typename DistanceStrategy,
754 typename SideStrategy,
755 typename JoinStrategy,
756 typename EndStrategy,
757 typename PointStrategy,
758 typename RobustPolicy
759 >
760 static inline
761 void apply_interior_rings(InteriorRings const& interior_rings,
762 Collection& collection,
763 DistanceStrategy const& distance,
764 SideStrategy const& side_strategy,
765 JoinStrategy const& join_strategy,
766 EndStrategy const& end_strategy,
767 PointStrategy const& point_strategy,
768 RobustPolicy const& robust_policy)
769 {
770 iterate(boost::begin(interior_rings), boost::end(interior_rings),
771 collection, distance, side_strategy,
772 join_strategy, end_strategy, point_strategy,
773 robust_policy, true);
774 }
775
776public:
777 template
778 <
779 typename Collection,
780 typename DistanceStrategy,
781 typename SideStrategy,
782 typename JoinStrategy,
783 typename EndStrategy,
784 typename PointStrategy,
785 typename RobustPolicy
786 >
787 static inline void apply(PolygonInput const& polygon,
788 Collection& collection,
789 DistanceStrategy const& distance,
790 SideStrategy const& side_strategy,
791 JoinStrategy const& join_strategy,
792 EndStrategy const& end_strategy,
793 PointStrategy const& point_strategy,
794 RobustPolicy const& robust_policy)
795 {
796 {
797 collection.start_new_ring();
798
799 strategy::buffer::result_code const code
800 = policy::apply(exterior_ring(polygon), collection,
801 distance, side_strategy,
802 join_strategy, end_strategy, point_strategy,
803 robust_policy);
804
805 collection.finish_ring(code, false,
806 geometry::num_interior_rings(polygon) > 0u);
807 }
808
809 apply_interior_rings(interior_rings(polygon),
810 collection, distance, side_strategy,
811 join_strategy, end_strategy, point_strategy,
812 robust_policy);
813 }
814};
815
816
817template
818<
819 typename Multi,
820 typename PolygonOutput
821>
822struct buffer_inserter<multi_tag, Multi, PolygonOutput>
823 : public detail::buffer::buffer_multi
824 <
825 Multi,
826 PolygonOutput,
827 dispatch::buffer_inserter
828 <
829 typename single_tag_of
830 <
831 typename tag<Multi>::type
832 >::type,
833 typename boost::range_value<Multi const>::type,
834 typename geometry::ring_type<PolygonOutput>::type
835 >
836 >
837{};
838
839
840} // namespace dispatch
841#endif // DOXYGEN_NO_DISPATCH
842
843#ifndef DOXYGEN_NO_DETAIL
844namespace detail { namespace buffer
845{
846
847template
848<
849 typename GeometryOutput,
850 typename GeometryInput,
851 typename OutputIterator,
852 typename DistanceStrategy,
853 typename SideStrategy,
854 typename JoinStrategy,
855 typename EndStrategy,
856 typename PointStrategy,
857 typename RobustPolicy,
858 typename VisitPiecesPolicy
859>
860inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
861 DistanceStrategy const& distance_strategy,
862 SideStrategy const& side_strategy,
863 JoinStrategy const& join_strategy,
864 EndStrategy const& end_strategy,
865 PointStrategy const& point_strategy,
866 RobustPolicy const& robust_policy,
867 VisitPiecesPolicy& visit_pieces_policy
868 )
869{
870 boost::ignore_unused(visit_pieces_policy);
871
872 typedef detail::buffer::buffered_piece_collection
873 <
874 typename geometry::ring_type<GeometryOutput>::type,
875 RobustPolicy
876 > collection_type;
877 collection_type collection(robust_policy);
878 collection_type const& const_collection = collection;
879
880 bool const areal = boost::is_same
881 <
882 typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
883 areal_tag
884 >::type::value;
885 bool const linear = boost::is_same
886 <
887 typename tag_cast<typename tag<GeometryInput>::type, linear_tag>::type,
888 linear_tag
889 >::type::value;
890
891 dispatch::buffer_inserter
892 <
893 typename tag_cast
894 <
895 typename tag<GeometryInput>::type,
896 multi_tag
897 >::type,
898 GeometryInput,
899 GeometryOutput
900 >::apply(geometry_input, collection,
901 distance_strategy, side_strategy, join_strategy,
902 end_strategy, point_strategy,
903 robust_policy);
904
905 collection.get_turns();
906 collection.classify_turns(linear);
907 if (BOOST_GEOMETRY_CONDITION(areal))
908 {
909 collection.check_remaining_points(distance_strategy);
910 }
911
912 // Visit the piece collection. This does nothing (by default), but
913 // optionally a debugging tool can be attached (e.g. console or svg),
914 // or the piece collection can be unit-tested
915 // phase 0: turns (before discarded)
916 visit_pieces_policy.apply(const_collection, 0);
917
918 collection.discard_rings();
919 collection.block_turns();
920 collection.enrich();
921
922 // phase 1: turns (after enrichment/clustering)
923 visit_pieces_policy.apply(const_collection, 1);
924
925 collection.traverse();
926
927 // Reverse all offsetted rings / traversed rings if:
928 // - they were generated on the negative side (deflate) of polygons
929 // - the output is counter clockwise
930 // and avoid reversing twice
931 bool reverse = distance_strategy.negative() && areal;
932 if (BOOST_GEOMETRY_CONDITION(
933 geometry::point_order<GeometryOutput>::value == counterclockwise))
934 {
935 reverse = ! reverse;
936 }
937 if (reverse)
938 {
939 collection.reverse();
940 }
941
942 if (BOOST_GEOMETRY_CONDITION(distance_strategy.negative() && areal))
943 {
944 collection.discard_nonintersecting_deflated_rings();
945 }
946
947 collection.template assign<GeometryOutput>(out);
948
949 // Visit collection again
950 // phase 2: rings (after traversing)
951 visit_pieces_policy.apply(const_collection, 2);
952}
953
954template
955<
956 typename GeometryOutput,
957 typename GeometryInput,
958 typename OutputIterator,
959 typename DistanceStrategy,
960 typename SideStrategy,
961 typename JoinStrategy,
962 typename EndStrategy,
963 typename PointStrategy,
964 typename RobustPolicy
965>
966inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
967 DistanceStrategy const& distance_strategy,
968 SideStrategy const& side_strategy,
969 JoinStrategy const& join_strategy,
970 EndStrategy const& end_strategy,
971 PointStrategy const& point_strategy,
972 RobustPolicy const& robust_policy)
973{
974 detail::buffer::visit_pieces_default_policy visitor;
975 buffer_inserter<GeometryOutput>(geometry_input, out,
976 distance_strategy, side_strategy, join_strategy,
977 end_strategy, point_strategy,
978 robust_policy, visitor);
979}
980#endif // DOXYGEN_NO_DETAIL
981
982}} // namespace detail::buffer
983
984}} // namespace boost::geometry
985
986#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP