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