]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / 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
b32b8144
FG
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
7c673cae
FG
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>
92f5a8d4 34#include <boost/geometry/algorithms/detail/make/make.hpp>
7c673cae
FG
35#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
36#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
7c673cae
FG
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
92f5a8d4
TL
42#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
43
7c673cae
FG
44#include <boost/geometry/views/detail/normalized_view.hpp>
45
7c673cae
FG
46
47namespace boost { namespace geometry
48{
49
50#ifndef DOXYGEN_NO_DETAIL
51namespace detail { namespace buffer
52{
53
54template <typename Range, typename DistanceStrategy>
55inline 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
7c673cae 68
11fdf7f2
TL
69 typedef typename geometry::point_type<Range>::type point_type;
70 typedef typename strategy::distance::services::default_strategy
7c673cae 71 <
11fdf7f2
TL
72 point_tag, segment_tag, point_type
73 >::type ds_strategy_type;
74 typedef strategy::simplify::douglas_peucker
7c673cae 75 <
11fdf7f2
TL
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());
7c673cae 82
7c673cae
FG
83}
84
85
86template <typename RingOutput>
87struct 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,
b32b8144 99 typename RobustPolicy,
92f5a8d4 100 typename SideStrategy
7c673cae
FG
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,
b32b8144 111 geometry::strategy::buffer::buffer_side_selector side,
7c673cae
FG
112 DistanceStrategy const& distance,
113 JoinStrategy const& join_strategy,
114 EndStrategy const& end_strategy,
b32b8144 115 RobustPolicy const& ,
92f5a8d4 116 SideStrategy const& side_strategy) // side strategy
7c673cae
FG
117 {
118 output_point_type intersection_point;
119 geometry::assign_zero(intersection_point);
120
b32b8144 121 geometry::strategy::buffer::join_selector join
92f5a8d4 122 = get_join_type(penultimate_input, previous_input, input, side_strategy);
b32b8144 123 if (join == geometry::strategy::buffer::join_convex)
7c673cae
FG
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 {
b32b8144 136 case geometry::strategy::buffer::join_continue :
7c673cae
FG
137 // No join, we get two consecutive sides
138 break;
b32b8144 139 case geometry::strategy::buffer::join_concave :
7c673cae
FG
140 {
141 std::vector<output_point_type> range_out;
142 range_out.push_back(prev_perp2);
143 range_out.push_back(previous_input);
b32b8144 144 collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
7c673cae
FG
145
146 range_out.clear();
147 range_out.push_back(previous_input);
148 range_out.push_back(perp1);
b32b8144 149 collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
7c673cae
FG
150 }
151 break;
b32b8144 152 case geometry::strategy::buffer::join_spike :
7c673cae
FG
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;
b32b8144 162 case geometry::strategy::buffer::join_convex :
7c673cae
FG
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 {
b32b8144 172 collection.add_piece(geometry::strategy::buffer::buffered_join,
7c673cae
FG
173 previous_input, range_out);
174 }
175 }
176 break;
177 }
178 }
179
92f5a8d4
TL
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>
b32b8144 191 static inline geometry::strategy::buffer::join_selector get_join_type(
7c673cae
FG
192 output_point_type const& p0,
193 output_point_type const& p1,
b32b8144 194 output_point_type const& p2,
92f5a8d4 195 SideStrategy const& side_strategy)
7c673cae 196 {
92f5a8d4 197 int const side = side_strategy.apply(p0, p1, p2);
b32b8144
FG
198 return side == -1 ? geometry::strategy::buffer::join_convex
199 : side == 1 ? geometry::strategy::buffer::join_concave
92f5a8d4
TL
200 : similar_direction(p0, p1, p2)
201 ? geometry::strategy::buffer::join_continue
b32b8144 202 : geometry::strategy::buffer::join_spike;
7c673cae
FG
203 }
204
205 template
206 <
207 typename Collection,
208 typename Iterator,
209 typename DistanceStrategy,
210 typename SideStrategy,
211 typename JoinStrategy,
212 typename EndStrategy,
b32b8144
FG
213 typename RobustPolicy,
214 typename Strategy
7c673cae 215 >
b32b8144 216 static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
7c673cae 217 Iterator begin, Iterator end,
b32b8144 218 geometry::strategy::buffer::buffer_side_selector side,
7c673cae
FG
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,
b32b8144
FG
224 Strategy const& strategy, // side strategy
225 bool linear,
7c673cae
FG
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
b32b8144
FG
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;
7c673cae
FG
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();
b32b8144 272 geometry::strategy::buffer::result_code error_code
7c673cae
FG
273 = side_strategy.apply(*prev, *it, side,
274 distance_strategy, generated_side);
275
b32b8144 276 if (error_code == geometry::strategy::buffer::result_no_output)
7c673cae
FG
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 }
b32b8144 283 else if (error_code == geometry::strategy::buffer::result_error_numerical)
7c673cae
FG
284 {
285 return error_code;
286 }
287
288 BOOST_GEOMETRY_ASSERT(! generated_side.empty());
289
b32b8144 290 result = geometry::strategy::buffer::result_normal;
7c673cae
FG
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,
b32b8144 300 robust_policy, strategy);
7c673cae
FG
301 }
302
303 collection.add_side_piece(*prev, *it, generated_side, first);
304
b32b8144
FG
305 if (first && mark_flat)
306 {
307 collection.mark_flat_start();
308 }
309
7c673cae
FG
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 }
b32b8144
FG
323
324 if (mark_flat)
325 {
326 collection.mark_flat_end();
327 }
328
7c673cae
FG
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,
b32b8144
FG
349 typename RobustPolicy,
350 typename Strategy
7c673cae
FG
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,
b32b8144
FG
359 RobustPolicy const& robust_policy,
360 Strategy const& strategy) // side strategy
7c673cae
FG
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,
b32b8144 370 robust_policy, strategy);
7c673cae
FG
371 }
372 }
373};
374
375struct visit_pieces_default_policy
376{
377 template <typename Collection>
378 static inline void apply(Collection const&, int)
379 {}
380};
381
382template
383<
384 typename OutputPointType,
385 typename Point,
386 typename Collection,
387 typename DistanceStrategy,
388 typename PointStrategy
389>
390inline void buffer_point(Point const& point, Collection& collection,
391 DistanceStrategy const& distance_strategy,
392 PointStrategy const& point_strategy)
393{
b32b8144 394 collection.start_new_ring(false);
7c673cae
FG
395 std::vector<OutputPointType> range_out;
396 point_strategy.apply(point, distance_strategy, range_out);
b32b8144 397 collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
7c673cae 398 collection.set_piece_center(point);
b32b8144 399 collection.finish_ring(geometry::strategy::buffer::result_normal);
7c673cae
FG
400}
401
402
403}} // namespace detail::buffer
404#endif // DOXYGEN_NO_DETAIL
405
406
407#ifndef DOXYGEN_NO_DISPATCH
408namespace dispatch
409{
410
411template
412<
413 typename Tag,
414 typename RingInput,
415 typename RingOutput
416>
417struct buffer_inserter
418{};
419
420
421
422template
423<
424 typename Point,
425 typename RingOutput
426>
427struct 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,
b32b8144
FG
437 typename RobustPolicy,
438 typename Strategy
7c673cae
FG
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,
b32b8144
FG
446 RobustPolicy const& ,
447 Strategy const& ) // side strategy
7c673cae
FG
448 {
449 detail::buffer::buffer_point
450 <
451 typename point_type<RingOutput>::type
452 >(point, collection, distance_strategy, point_strategy);
453 }
454};
455
b32b8144
FG
456// Not a specialization, but called from specializations of ring and of polygon.
457// Calling code starts/finishes ring before/after apply
7c673cae
FG
458template
459<
460 typename RingInput,
461 typename RingOutput
462>
b32b8144 463struct buffer_inserter_ring
7c673cae
FG
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,
b32b8144
FG
475 typename RobustPolicy,
476 typename Strategy
7c673cae 477 >
b32b8144 478 static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
7c673cae 479 Iterator begin, Iterator end,
b32b8144 480 geometry::strategy::buffer::buffer_side_selector side,
7c673cae
FG
481 DistanceStrategy const& distance_strategy,
482 SideStrategy const& side_strategy,
483 JoinStrategy const& join_strategy,
484 EndStrategy const& end_strategy,
b32b8144
FG
485 RobustPolicy const& robust_policy,
486 Strategy const& strategy) // side strategy
7c673cae
FG
487 {
488 output_point_type first_p1, first_p2, last_p1, last_p2;
489
490 typedef detail::buffer::buffer_range<RingOutput> buffer_range;
491
b32b8144 492 geometry::strategy::buffer::result_code result
7c673cae
FG
493 = buffer_range::iterate(collection, begin, end,
494 side,
b32b8144
FG
495 distance_strategy, side_strategy, join_strategy, end_strategy,
496 robust_policy, strategy,
497 false, first_p1, first_p2, last_p1, last_p2);
7c673cae
FG
498
499 // Generate closing join
b32b8144 500 if (result == geometry::strategy::buffer::result_normal)
7c673cae
FG
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,
b32b8144 508 robust_policy, strategy);
7c673cae
FG
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,
b32b8144
FG
523 typename RobustPolicy,
524 typename Strategy
7c673cae 525 >
b32b8144 526 static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
7c673cae
FG
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,
b32b8144
FG
533 RobustPolicy const& robust_policy,
534 Strategy const& strategy) // side strategy
7c673cae
FG
535 {
536 RingInput simplified;
537 detail::buffer::simplify_input(ring, distance, simplified);
538
b32b8144 539 geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
7c673cae
FG
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),
b32b8144
FG
554 geometry::strategy::buffer::buffer_side_right,
555 distance, side_strategy, join_strategy, end_strategy,
556 robust_policy, strategy);
7c673cae
FG
557 }
558 else
559 {
560 code = iterate(collection, boost::begin(view), boost::end(view),
b32b8144
FG
561 geometry::strategy::buffer::buffer_side_left,
562 distance, side_strategy, join_strategy, end_strategy,
563 robust_policy, strategy);
7c673cae
FG
564 }
565 }
566
b32b8144 567 if (code == geometry::strategy::buffer::result_no_output && n >= 1)
7c673cae
FG
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
b32b8144
FG
581template
582<
583 typename RingInput,
584 typename RingOutput
585>
586struct 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);
616 return code;
617 }
618};
619
7c673cae
FG
620template
621<
622 typename Linestring,
623 typename Polygon
624>
625struct 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,
b32b8144
FG
639 typename RobustPolicy,
640 typename Strategy
7c673cae 641 >
b32b8144 642 static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
7c673cae 643 Iterator begin, Iterator end,
b32b8144 644 geometry::strategy::buffer::buffer_side_selector side,
7c673cae
FG
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,
b32b8144 650 Strategy const& strategy, // side strategy
7c673cae
FG
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;
b32b8144 661 if (side == geometry::strategy::buffer::buffer_side_right)
7c673cae
FG
662 {
663 reverse_p1 = first_p1;
664 }
665 else
666 {
667 std::vector<output_point_type> generated_side;
b32b8144 668 geometry::strategy::buffer::result_code code
7c673cae 669 = side_strategy.apply(ultimate_point, penultimate_point,
b32b8144 670 geometry::strategy::buffer::buffer_side_right,
7c673cae 671 distance_strategy, generated_side);
b32b8144 672 if (code != geometry::strategy::buffer::result_normal)
7c673cae
FG
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
b32b8144 682 geometry::strategy::buffer::result_code result
7c673cae
FG
683 = detail::buffer::buffer_range<output_ring_type>::iterate(collection,
684 begin, end, side,
b32b8144
FG
685 distance_strategy, side_strategy, join_strategy, end_strategy,
686 robust_policy, strategy,
687 true, first_p1, first_p2, last_p1, last_p2);
7c673cae 688
b32b8144 689 if (result == geometry::strategy::buffer::result_normal)
7c673cae
FG
690 {
691 std::vector<output_point_type> range_out;
b32b8144
FG
692 end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1,
693 side, distance_strategy, range_out);
7c673cae
FG
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,
b32b8144
FG
707 typename RobustPolicy,
708 typename Strategy
7c673cae 709 >
b32b8144
FG
710 static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
711 Collection& collection,
7c673cae
FG
712 DistanceStrategy const& distance,
713 SideStrategy const& side_strategy,
714 JoinStrategy const& join_strategy,
715 EndStrategy const& end_strategy,
716 PointStrategy const& point_strategy,
b32b8144
FG
717 RobustPolicy const& robust_policy,
718 Strategy const& strategy) // side strategy
7c673cae
FG
719 {
720 Linestring simplified;
721 detail::buffer::simplify_input(linestring, distance, simplified);
722
b32b8144 723 geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
7c673cae
FG
724 std::size_t n = boost::size(simplified);
725 if (n > 1)
726 {
b32b8144 727 collection.start_new_ring(false);
7c673cae
FG
728 output_point_type first_p1;
729 code = iterate(collection,
730 boost::begin(simplified), boost::end(simplified),
b32b8144
FG
731 geometry::strategy::buffer::buffer_side_left,
732 distance, side_strategy, join_strategy, end_strategy,
733 robust_policy, strategy,
7c673cae
FG
734 first_p1);
735
b32b8144 736 if (code == geometry::strategy::buffer::result_normal)
7c673cae
FG
737 {
738 code = iterate(collection,
739 boost::rbegin(simplified), boost::rend(simplified),
b32b8144
FG
740 geometry::strategy::buffer::buffer_side_right,
741 distance, side_strategy, join_strategy, end_strategy,
742 robust_policy, strategy,
7c673cae
FG
743 first_p1);
744 }
745 collection.finish_ring(code);
746 }
b32b8144 747 if (code == geometry::strategy::buffer::result_no_output && n >= 1)
7c673cae
FG
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
761template
762<
763 typename PolygonInput,
764 typename PolygonOutput
765>
766struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput>
767{
768private:
769 typedef typename ring_type<PolygonInput>::type input_ring_type;
770 typedef typename ring_type<PolygonOutput>::type output_ring_type;
771
b32b8144 772 typedef buffer_inserter_ring<input_ring_type, output_ring_type> policy;
7c673cae
FG
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,
b32b8144
FG
784 typename RobustPolicy,
785 typename Strategy
7c673cae
FG
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,
b32b8144 796 Strategy const& strategy, // side strategy
7c673cae
FG
797 bool is_interior)
798 {
799 for (Iterator it = begin; it != end; ++it)
800 {
b32b8144
FG
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
7c673cae
FG
809 = policy::apply(*it, collection, distance, side_strategy,
810 join_strategy, end_strategy, point_strategy,
b32b8144 811 robust_policy, strategy);
7c673cae
FG
812
813 collection.finish_ring(code, is_interior);
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,
b32b8144
FG
826 typename RobustPolicy,
827 typename Strategy
7c673cae
FG
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,
b32b8144
FG
837 RobustPolicy const& robust_policy,
838 Strategy const& strategy) // side strategy
7c673cae
FG
839 {
840 iterate(boost::begin(interior_rings), boost::end(interior_rings),
841 collection, distance, side_strategy,
842 join_strategy, end_strategy, point_strategy,
b32b8144 843 robust_policy, strategy, true);
7c673cae
FG
844 }
845
846public:
847 template
848 <
849 typename Collection,
850 typename DistanceStrategy,
851 typename SideStrategy,
852 typename JoinStrategy,
853 typename EndStrategy,
854 typename PointStrategy,
b32b8144
FG
855 typename RobustPolicy,
856 typename Strategy
7c673cae
FG
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,
b32b8144
FG
865 RobustPolicy const& robust_policy,
866 Strategy const& strategy) // side strategy
7c673cae
FG
867 {
868 {
b32b8144 869 collection.start_new_ring(distance.negative());
7c673cae 870
b32b8144 871 geometry::strategy::buffer::result_code const code
7c673cae
FG
872 = policy::apply(exterior_ring(polygon), collection,
873 distance, side_strategy,
874 join_strategy, end_strategy, point_strategy,
b32b8144 875 robust_policy, strategy);
7c673cae
FG
876
877 collection.finish_ring(code, 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,
b32b8144 884 robust_policy, strategy);
7c673cae
FG
885 }
886};
887
888
889template
890<
891 typename Multi,
892 typename PolygonOutput
893>
894struct 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
916namespace detail { namespace buffer
917{
918
919template
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,
b32b8144 929 typename IntersectionStrategy,
7c673cae
FG
930 typename RobustPolicy,
931 typename VisitPiecesPolicy
932>
933inline 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,
b32b8144 939 IntersectionStrategy const& intersection_strategy,
7c673cae
FG
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,
b32b8144 949 IntersectionStrategy,
7c673cae
FG
950 RobustPolicy
951 > collection_type;
b32b8144 952 collection_type collection(intersection_strategy, robust_policy);
7c673cae
FG
953 collection_type const& const_collection = collection;
954
955 bool const areal = boost::is_same
956 <
957 typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
958 areal_tag
959 >::type::value;
7c673cae
FG
960
961 dispatch::buffer_inserter
962 <
963 typename tag_cast
964 <
965 typename tag<GeometryInput>::type,
966 multi_tag
967 >::type,
968 GeometryInput,
969 GeometryOutput
970 >::apply(geometry_input, collection,
971 distance_strategy, side_strategy, join_strategy,
972 end_strategy, point_strategy,
b32b8144 973 robust_policy, intersection_strategy.get_side_strategy());
7c673cae 974
92f5a8d4 975 collection.get_turns(distance_strategy);
b32b8144 976 collection.classify_turns();
7c673cae
FG
977 if (BOOST_GEOMETRY_CONDITION(areal))
978 {
979 collection.check_remaining_points(distance_strategy);
980 }
981
982 // Visit the piece collection. This does nothing (by default), but
983 // optionally a debugging tool can be attached (e.g. console or svg),
984 // or the piece collection can be unit-tested
985 // phase 0: turns (before discarded)
986 visit_pieces_policy.apply(const_collection, 0);
987
988 collection.discard_rings();
989 collection.block_turns();
990 collection.enrich();
991
992 // phase 1: turns (after enrichment/clustering)
993 visit_pieces_policy.apply(const_collection, 1);
994
995 collection.traverse();
996
997 // Reverse all offsetted rings / traversed rings if:
998 // - they were generated on the negative side (deflate) of polygons
999 // - the output is counter clockwise
1000 // and avoid reversing twice
1001 bool reverse = distance_strategy.negative() && areal;
1002 if (BOOST_GEOMETRY_CONDITION(
1003 geometry::point_order<GeometryOutput>::value == counterclockwise))
1004 {
1005 reverse = ! reverse;
1006 }
1007 if (reverse)
1008 {
1009 collection.reverse();
1010 }
1011
1012 if (BOOST_GEOMETRY_CONDITION(distance_strategy.negative() && areal))
1013 {
1014 collection.discard_nonintersecting_deflated_rings();
1015 }
1016
1017 collection.template assign<GeometryOutput>(out);
1018
1019 // Visit collection again
1020 // phase 2: rings (after traversing)
1021 visit_pieces_policy.apply(const_collection, 2);
1022}
1023
1024template
1025<
1026 typename GeometryOutput,
1027 typename GeometryInput,
1028 typename OutputIterator,
1029 typename DistanceStrategy,
1030 typename SideStrategy,
1031 typename JoinStrategy,
1032 typename EndStrategy,
1033 typename PointStrategy,
b32b8144 1034 typename IntersectionStrategy,
7c673cae
FG
1035 typename RobustPolicy
1036>
1037inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
1038 DistanceStrategy const& distance_strategy,
1039 SideStrategy const& side_strategy,
1040 JoinStrategy const& join_strategy,
1041 EndStrategy const& end_strategy,
1042 PointStrategy const& point_strategy,
b32b8144 1043 IntersectionStrategy const& intersection_strategy,
7c673cae
FG
1044 RobustPolicy const& robust_policy)
1045{
1046 detail::buffer::visit_pieces_default_policy visitor;
1047 buffer_inserter<GeometryOutput>(geometry_input, out,
1048 distance_strategy, side_strategy, join_strategy,
1049 end_strategy, point_strategy,
b32b8144 1050 intersection_strategy, robust_policy, visitor);
7c673cae
FG
1051}
1052#endif // DOXYGEN_NO_DETAIL
1053
1054}} // namespace detail::buffer
1055
1056}} // namespace boost::geometry
1057
1058#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP