]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/algorithms/detail/sections/sectionalize.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / sections / sectionalize.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
3// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
5// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
6// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
7
92f5a8d4
TL
8// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018, 2019.
9// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates.
7c673cae
FG
10
11// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
12// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
13
14// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
15// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
16
17// Use, modification and distribution is subject to the Boost Software License,
18// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
19// http://www.boost.org/LICENSE_1_0.txt)
20
21#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
22#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
23
24#include <cstddef>
25#include <vector>
26
27#include <boost/concept/requires.hpp>
92f5a8d4 28#include <boost/core/ignore_unused.hpp>
7c673cae
FG
29#include <boost/mpl/assert.hpp>
30#include <boost/mpl/vector_c.hpp>
31#include <boost/range.hpp>
32#include <boost/static_assert.hpp>
b32b8144
FG
33#include <boost/type_traits/is_same.hpp>
34#include <boost/type_traits/is_fundamental.hpp>
7c673cae 35
92f5a8d4
TL
36#include <boost/geometry/core/config.hpp>
37
7c673cae
FG
38#include <boost/geometry/algorithms/assign.hpp>
39#include <boost/geometry/algorithms/envelope.hpp>
40#include <boost/geometry/algorithms/expand.hpp>
41
42#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
43#include <boost/geometry/algorithms/detail/recalculate.hpp>
44#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
45#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
46
47#include <boost/geometry/core/access.hpp>
48#include <boost/geometry/core/closure.hpp>
49#include <boost/geometry/core/exterior_ring.hpp>
50#include <boost/geometry/core/point_order.hpp>
51#include <boost/geometry/core/tags.hpp>
52
53#include <boost/geometry/geometries/concepts/check.hpp>
54#include <boost/geometry/util/math.hpp>
55#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
56#include <boost/geometry/policies/robustness/robust_point_type.hpp>
57#include <boost/geometry/views/closeable_view.hpp>
58#include <boost/geometry/views/reversible_view.hpp>
59#include <boost/geometry/geometries/segment.hpp>
60
61#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
92f5a8d4
TL
62#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp>
63
b32b8144 64#include <boost/geometry/strategies/envelope.hpp>
92f5a8d4 65#include <boost/geometry/strategies/expand.hpp>
7c673cae
FG
66
67namespace boost { namespace geometry
68{
69
70
71/*!
72 \brief Structure containing section information
73 \details Section information consists of a bounding box, direction
74 information (if it is increasing or decreasing, per dimension),
75 index information (begin-end, ring, multi) and the number of
76 segments in this section
77
78 \tparam Box box-type
79 \tparam DimensionCount number of dimensions for this section
80 \ingroup sectionalize
81 */
82template
83<
84 typename Box,
85 std::size_t DimensionCount
86>
87struct section
88{
89 typedef Box box_type;
90 static std::size_t const dimension_count = DimensionCount;
91
92 int directions[DimensionCount];
93 ring_identifier ring_id;
94 Box bounding_box;
95
96 // NOTE: size_type could be passed as template parameter
97 // NOTE: these probably also could be of type std::size_t
98 signed_size_type begin_index;
99 signed_size_type end_index;
100 std::size_t count;
101 std::size_t range_count;
102 bool duplicate;
103 signed_size_type non_duplicate_index;
104
105 bool is_non_duplicate_first;
106 bool is_non_duplicate_last;
107
108 inline section()
109 : begin_index(-1)
110 , end_index(-1)
111 , count(0)
112 , range_count(0)
113 , duplicate(false)
114 , non_duplicate_index(-1)
115 , is_non_duplicate_first(false)
116 , is_non_duplicate_last(false)
117 {
118 assign_inverse(bounding_box);
119 for (std::size_t i = 0; i < DimensionCount; i++)
120 {
121 directions[i] = 0;
122 }
123 }
124};
125
126
127/*!
128 \brief Structure containing a collection of sections
129 \note Derived from a vector, proves to be faster than of deque
130 \note vector might be templated in the future
131 \ingroup sectionalize
132 */
133template <typename Box, std::size_t DimensionCount>
134struct sections : std::vector<section<Box, DimensionCount> >
135{
136 typedef Box box_type;
137 static std::size_t const value = DimensionCount;
138};
139
140
141#ifndef DOXYGEN_NO_DETAIL
142namespace detail { namespace sectionalize
143{
144
b32b8144
FG
145// NOTE: This utility will NOT work for latitudes, dimension 1 in spherical
146// and geographic coordinate system because in these coordinate systems
147// e.g. a segment on northern hemisphere may go towards greater latitude
148// and then towards lesser latitude.
7c673cae
FG
149template
150<
b32b8144 151 typename Point,
7c673cae
FG
152 typename DimensionVector,
153 std::size_t Index,
b32b8144
FG
154 std::size_t Count,
155 typename CastedCSTag = typename tag_cast
156 <
157 typename cs_tag<Point>::type,
158 spherical_tag
159 >::type
7c673cae
FG
160>
161struct get_direction_loop
162{
163 typedef typename boost::mpl::at_c<DimensionVector, Index>::type dimension;
164
165 template <typename Segment>
166 static inline void apply(Segment const& seg,
167 int directions[Count])
168 {
169 typedef typename coordinate_type<Segment>::type coordinate_type;
170
92f5a8d4
TL
171 coordinate_type const c0 = geometry::get<0, dimension::value>(seg);
172 coordinate_type const c1 = geometry::get<1, dimension::value>(seg);
7c673cae 173
92f5a8d4 174 directions[Index] = c1 > c0 ? 1 : c1 < c0 ? -1 : 0;
7c673cae
FG
175
176 get_direction_loop
177 <
b32b8144 178 Point,
7c673cae
FG
179 DimensionVector,
180 Index + 1,
b32b8144
FG
181 Count,
182 CastedCSTag
183 >::apply(seg, directions);
184 }
185};
186
187template
188<
189 typename Point,
190 typename DimensionVector,
191 std::size_t Count
192>
193struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag>
194{
195 typedef typename boost::mpl::at_c<DimensionVector, 0>::type dimension;
196
197 template <typename Segment>
198 static inline void apply(Segment const& seg,
199 int directions[Count])
200 {
201 typedef typename coordinate_type<Segment>::type coordinate_type;
202 typedef typename coordinate_system<Point>::type::units units_t;
203
204 coordinate_type const diff = math::longitude_distance_signed
205 <
206 units_t, coordinate_type
207 >(geometry::get<0, 0>(seg),
208 geometry::get<1, 0>(seg));
209
210 coordinate_type zero = coordinate_type();
211 directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0;
212
213 get_direction_loop
214 <
215 Point,
216 DimensionVector,
217 1,
218 Count,
219 spherical_tag
7c673cae
FG
220 >::apply(seg, directions);
221 }
222};
223
b32b8144
FG
224template
225<
226 typename Point,
227 typename DimensionVector,
228 std::size_t Count,
229 typename CastedCSTag
230>
231struct get_direction_loop<Point, DimensionVector, Count, Count, CastedCSTag>
7c673cae
FG
232{
233 template <typename Segment>
234 static inline void apply(Segment const&, int [Count])
235 {}
236};
237
b32b8144 238
7c673cae
FG
239//! Copy one static array to another
240template <typename T, std::size_t Index, std::size_t Count>
241struct copy_loop
242{
243 static inline void apply(T const source[Count], T target[Count])
244 {
245 target[Index] = source[Index];
246 copy_loop<T, Index + 1, Count>::apply(source, target);
247 }
248};
249
250template <typename T, std::size_t Count>
251struct copy_loop<T, Count, Count>
252{
253 static inline void apply(T const [Count], T [Count])
254 {}
255};
256
257//! Compare two static arrays
258template <typename T, std::size_t Index, std::size_t Count>
259struct compare_loop
260{
261 static inline bool apply(T const array1[Count], T const array2[Count])
262 {
263 return array1[Index] != array2[Index]
264 ? false
265 : compare_loop
266 <
267 T, Index + 1, Count
268 >::apply(array1, array2);
269 }
270};
271
272template <typename T, std::size_t Count>
273struct compare_loop<T, Count, Count>
274{
275 static inline bool apply(T const [Count], T const [Count])
276 {
277
278 return true;
279 }
280};
281
282
283template <std::size_t Dimension, std::size_t DimensionCount>
284struct check_duplicate_loop
285{
286 template <typename Segment>
287 static inline bool apply(Segment const& seg)
288 {
289 if (! geometry::math::equals
290 (
291 geometry::get<0, Dimension>(seg),
292 geometry::get<1, Dimension>(seg)
293 )
294 )
295 {
296 return false;
297 }
298
299 return check_duplicate_loop
300 <
301 Dimension + 1, DimensionCount
302 >::apply(seg);
303 }
304};
305
306template <std::size_t DimensionCount>
307struct check_duplicate_loop<DimensionCount, DimensionCount>
308{
309 template <typename Segment>
310 static inline bool apply(Segment const&)
311 {
312 return true;
313 }
314};
315
316//! Assign a value to a static array
317template <typename T, std::size_t Index, std::size_t Count>
318struct assign_loop
319{
320 static inline void apply(T dims[Count], T const value)
321 {
322 dims[Index] = value;
323 assign_loop<T, Index + 1, Count>::apply(dims, value);
324 }
325};
326
327template <typename T, std::size_t Count>
328struct assign_loop<T, Count, Count>
329{
330 static inline void apply(T [Count], T const)
331 {
332 }
333};
334
335template <typename CSTag>
336struct box_first_in_section
337{
92f5a8d4 338 template <typename Box, typename Point, typename EnvelopeStrategy>
b32b8144 339 static inline void apply(Box & box, Point const& prev, Point const& curr,
92f5a8d4 340 EnvelopeStrategy const& strategy)
7c673cae
FG
341 {
342 geometry::model::referring_segment<Point const> seg(prev, curr);
b32b8144 343 geometry::envelope(seg, box, strategy);
7c673cae
FG
344 }
345};
346
347template <>
348struct box_first_in_section<cartesian_tag>
349{
92f5a8d4 350 template <typename Box, typename Point, typename ExpandStrategy>
b32b8144 351 static inline void apply(Box & box, Point const& prev, Point const& curr,
92f5a8d4 352 ExpandStrategy const& )
7c673cae
FG
353 {
354 geometry::envelope(prev, box);
355 geometry::expand(box, curr);
356 }
357};
358
359template <typename CSTag>
360struct box_next_in_section
361{
b32b8144
FG
362 template <typename Box, typename Point, typename Strategy>
363 static inline void apply(Box & box, Point const& prev, Point const& curr,
364 Strategy const& strategy)
7c673cae
FG
365 {
366 geometry::model::referring_segment<Point const> seg(prev, curr);
b32b8144 367 geometry::expand(box, seg, strategy);
7c673cae
FG
368 }
369};
370
371template <>
372struct box_next_in_section<cartesian_tag>
373{
b32b8144
FG
374 template <typename Box, typename Point, typename Strategy>
375 static inline void apply(Box & box, Point const& , Point const& curr,
376 Strategy const& )
7c673cae
FG
377 {
378 geometry::expand(box, curr);
379 }
380};
381
382/// @brief Helper class to create sections of a part of a range, on the fly
383template
384<
385 typename Point,
386 typename DimensionVector
387>
388struct sectionalize_part
389{
390 static const std::size_t dimension_count
391 = boost::mpl::size<DimensionVector>::value;
392
393 template
394 <
395 typename Iterator,
396 typename RobustPolicy,
397 typename Sections
398 >
399 static inline void apply(Sections& sections,
400 Iterator begin, Iterator end,
401 RobustPolicy const& robust_policy,
402 ring_identifier ring_id,
403 std::size_t max_count)
b32b8144
FG
404 {
405 typedef typename strategy::envelope::services::default_strategy
406 <
92f5a8d4 407 segment_tag,
b32b8144
FG
408 typename cs_tag<typename Sections::box_type>::type
409 >::type envelope_strategy_type;
410
92f5a8d4
TL
411 typedef typename strategy::expand::services::default_strategy
412 <
413 segment_tag,
414 typename cs_tag<typename Sections::box_type>::type
415 >::type expand_strategy_type;
416
b32b8144 417 apply(sections, begin, end,
92f5a8d4
TL
418 robust_policy,
419 envelope_strategy_type(),
420 expand_strategy_type(),
b32b8144
FG
421 ring_id, max_count);
422 }
423
424 template
425 <
426 typename Iterator,
427 typename RobustPolicy,
428 typename Sections,
92f5a8d4
TL
429 typename EnvelopeStrategy,
430 typename ExpandStrategy
b32b8144
FG
431 >
432 static inline void apply(Sections& sections,
433 Iterator begin, Iterator end,
434 RobustPolicy const& robust_policy,
92f5a8d4
TL
435 EnvelopeStrategy const& envelope_strategy,
436 ExpandStrategy const& expand_strategy,
b32b8144
FG
437 ring_identifier ring_id,
438 std::size_t max_count)
7c673cae 439 {
92f5a8d4 440 boost::ignore_unused(robust_policy);
7c673cae
FG
441
442 typedef typename boost::range_value<Sections>::type section_type;
443 BOOST_STATIC_ASSERT
444 (
445 (static_cast<std::size_t>(section_type::dimension_count)
446 == static_cast<std::size_t>(boost::mpl::size<DimensionVector>::value))
447 );
448
449 typedef typename geometry::robust_point_type
450 <
451 Point,
452 RobustPolicy
453 >::type robust_point_type;
454
455 std::size_t const count = std::distance(begin, end);
456 if (count == 0)
457 {
458 return;
459 }
460
461 signed_size_type index = 0;
462 signed_size_type ndi = 0; // non duplicate index
463 section_type section;
464
465 bool mark_first_non_duplicated = true;
466 std::size_t last_non_duplicate_index = sections.size();
467
468 Iterator it = begin;
469 robust_point_type previous_robust_point;
470 geometry::recalculate(previous_robust_point, *it, robust_policy);
471
472 for(Iterator previous = it++;
473 it != end;
474 ++previous, ++it, index++)
475 {
476 robust_point_type current_robust_point;
477 geometry::recalculate(current_robust_point, *it, robust_policy);
478 model::referring_segment<robust_point_type> robust_segment(
479 previous_robust_point, current_robust_point);
480
481 int direction_classes[dimension_count] = {0};
482 get_direction_loop
483 <
b32b8144 484 Point, DimensionVector, 0, dimension_count
7c673cae
FG
485 >::apply(robust_segment, direction_classes);
486
487 // if "dir" == 0 for all point-dimensions, it is duplicate.
488 // Those sections might be omitted, if wished, lateron
489 bool duplicate = false;
490
491 if (direction_classes[0] == 0)
492 {
493 // Recheck because ALL dimensions should be checked,
494 // not only first one.
495 // (dimension_count might be < dimension<P>::value)
496 if (check_duplicate_loop
497 <
498 0, geometry::dimension<Point>::type::value
499 >::apply(robust_segment)
500 )
501 {
502 duplicate = true;
503
504 // Change direction-info to force new section
505 // Note that wo consecutive duplicate segments will generate
506 // only one duplicate-section.
507 // Actual value is not important as long as it is not -1,0,1
508 assign_loop
509 <
510 int, 0, dimension_count
511 >::apply(direction_classes, -99);
512 }
513 }
514
515 if (section.count > 0
516 && (! compare_loop
517 <
518 int, 0, dimension_count
519 >::apply(direction_classes, section.directions)
520 || section.count > max_count)
521 )
522 {
523 if (! section.duplicate)
524 {
525 last_non_duplicate_index = sections.size();
526 }
527
528 sections.push_back(section);
529 section = section_type();
530 }
531
532 if (section.count == 0)
533 {
534 section.begin_index = index;
535 section.ring_id = ring_id;
536 section.duplicate = duplicate;
537 section.non_duplicate_index = ndi;
538 section.range_count = count;
539
540 if (mark_first_non_duplicated && ! duplicate)
541 {
542 section.is_non_duplicate_first = true;
543 mark_first_non_duplicated = false;
544 }
545
546 copy_loop
547 <
548 int, 0, dimension_count
549 >::apply(direction_classes, section.directions);
550
551 // In cartesian this is envelope of previous point expanded with current point
552 // in non-cartesian this is envelope of a segment
553 box_first_in_section<typename cs_tag<robust_point_type>::type>
92f5a8d4 554 ::apply(section.bounding_box, previous_robust_point, current_robust_point, envelope_strategy);
7c673cae
FG
555 }
556 else
557 {
558 // In cartesian this is expand with current point
559 // in non-cartesian this is expand with a segment
560 box_next_in_section<typename cs_tag<robust_point_type>::type>
92f5a8d4 561 ::apply(section.bounding_box, previous_robust_point, current_robust_point, expand_strategy);
7c673cae
FG
562 }
563
564 section.end_index = index + 1;
565 section.count++;
566 if (! duplicate)
567 {
568 ndi++;
569 }
570 previous_robust_point = current_robust_point;
571 }
572
573 // Add last section if applicable
574 if (section.count > 0)
575 {
576 if (! section.duplicate)
577 {
578 last_non_duplicate_index = sections.size();
579 }
580
581 sections.push_back(section);
582 }
583
584 if (last_non_duplicate_index < sections.size()
585 && ! sections[last_non_duplicate_index].duplicate)
586 {
587 sections[last_non_duplicate_index].is_non_duplicate_last = true;
588 }
589 }
590};
591
592
593template
594<
595 closure_selector Closure,
596 bool Reverse,
597 typename Point,
598 typename DimensionVector
599>
600struct sectionalize_range
601{
602 template
603 <
604 typename Range,
605 typename RobustPolicy,
b32b8144 606 typename Sections,
92f5a8d4
TL
607 typename EnvelopeStrategy,
608 typename ExpandStrategy
7c673cae
FG
609 >
610 static inline void apply(Range const& range,
611 RobustPolicy const& robust_policy,
612 Sections& sections,
92f5a8d4
TL
613 EnvelopeStrategy const& envelope_strategy,
614 ExpandStrategy const& expand_strategy,
7c673cae
FG
615 ring_identifier ring_id,
616 std::size_t max_count)
617 {
618 typedef typename closeable_view<Range const, Closure>::type cview_type;
619 typedef typename reversible_view
620 <
621 cview_type const,
622 Reverse ? iterate_reverse : iterate_forward
623 >::type view_type;
624
625 cview_type cview(range);
626 view_type view(cview);
627
628 std::size_t const n = boost::size(view);
629 if (n == 0)
630 {
631 // Zero points, no section
632 return;
633 }
634
635 if (n == 1)
636 {
637 // Line with one point ==> no sections
638 return;
639 }
640
641 sectionalize_part<Point, DimensionVector>::apply(sections,
642 boost::begin(view), boost::end(view),
92f5a8d4
TL
643 robust_policy, envelope_strategy, expand_strategy,
644 ring_id, max_count);
7c673cae
FG
645 }
646};
647
648template
649<
650 bool Reverse,
651 typename DimensionVector
652>
653struct sectionalize_polygon
654{
655 template
656 <
657 typename Polygon,
658 typename RobustPolicy,
b32b8144 659 typename Sections,
92f5a8d4
TL
660 typename EnvelopeStrategy,
661 typename ExpandStrategy
7c673cae
FG
662 >
663 static inline void apply(Polygon const& poly,
664 RobustPolicy const& robust_policy,
665 Sections& sections,
92f5a8d4
TL
666 EnvelopeStrategy const& envelope_strategy,
667 ExpandStrategy const& expand_strategy,
b32b8144
FG
668 ring_identifier ring_id,
669 std::size_t max_count)
7c673cae
FG
670 {
671 typedef typename point_type<Polygon>::type point_type;
672 typedef sectionalize_range
673 <
674 closure<Polygon>::value, Reverse,
675 point_type, DimensionVector
676 > per_range;
677
678 ring_id.ring_index = -1;
92f5a8d4
TL
679 per_range::apply(exterior_ring(poly), robust_policy, sections,
680 envelope_strategy, expand_strategy, ring_id, max_count);
7c673cae
FG
681
682 ring_id.ring_index++;
683 typename interior_return_type<Polygon const>::type
684 rings = interior_rings(poly);
685 for (typename detail::interior_iterator<Polygon const>::type
686 it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
687 {
92f5a8d4
TL
688 per_range::apply(*it, robust_policy, sections,
689 envelope_strategy, expand_strategy, ring_id, max_count);
7c673cae
FG
690 }
691 }
692};
693
694template <typename DimensionVector>
695struct sectionalize_box
696{
697 template
698 <
699 typename Box,
700 typename RobustPolicy,
b32b8144 701 typename Sections,
92f5a8d4
TL
702 typename EnvelopeStrategy,
703 typename ExpandStrategy
7c673cae
FG
704 >
705 static inline void apply(Box const& box,
706 RobustPolicy const& robust_policy,
707 Sections& sections,
92f5a8d4
TL
708 EnvelopeStrategy const& envelope_strategy,
709 ExpandStrategy const& expand_strategy,
7c673cae
FG
710 ring_identifier const& ring_id, std::size_t max_count)
711 {
712 typedef typename point_type<Box>::type point_type;
713
714 assert_dimension<Box, 2>();
715
716 // Add all four sides of the 2D-box as separate section.
717 // Easiest is to convert it to a polygon.
718 // However, we don't have the polygon type
719 // (or polygon would be a helper-type).
720 // Therefore we mimic a linestring/std::vector of 5 points
721
722 // TODO: might be replaced by assign_box_corners_oriented
723 // or just "convert"
724 point_type ll, lr, ul, ur;
725 geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
726
727 std::vector<point_type> points;
728 points.push_back(ll);
729 points.push_back(ul);
730 points.push_back(ur);
731 points.push_back(lr);
732 points.push_back(ll);
733
b32b8144
FG
734 // NOTE: Use cartesian envelope strategy in all coordinate systems
735 // because edges of a box are not geodesic segments
7c673cae
FG
736 sectionalize_range
737 <
738 closed, false,
739 point_type,
740 DimensionVector
741 >::apply(points, robust_policy, sections,
92f5a8d4 742 envelope_strategy, expand_strategy,
7c673cae
FG
743 ring_id, max_count);
744 }
745};
746
747template <typename DimensionVector, typename Policy>
748struct sectionalize_multi
749{
750 template
751 <
752 typename MultiGeometry,
753 typename RobustPolicy,
b32b8144 754 typename Sections,
92f5a8d4
TL
755 typename EnvelopeStrategy,
756 typename ExpandStrategy
7c673cae
FG
757 >
758 static inline void apply(MultiGeometry const& multi,
759 RobustPolicy const& robust_policy,
b32b8144 760 Sections& sections,
92f5a8d4
TL
761 EnvelopeStrategy const& envelope_strategy,
762 ExpandStrategy const& expand_strategy,
b32b8144
FG
763 ring_identifier ring_id,
764 std::size_t max_count)
7c673cae
FG
765 {
766 ring_id.multi_index = 0;
767 for (typename boost::range_iterator<MultiGeometry const>::type
768 it = boost::begin(multi);
769 it != boost::end(multi);
770 ++it, ++ring_id.multi_index)
771 {
92f5a8d4
TL
772 Policy::apply(*it, robust_policy, sections,
773 envelope_strategy, expand_strategy,
774 ring_id, max_count);
7c673cae
FG
775 }
776 }
777};
778
92f5a8d4
TL
779// TODO: If it depends on CS it should probably be made into strategy.
780// For now implemented here because of ongoing work on robustness
781// the fact that it interferes with detail::buffer::buffer_box
782// and that we probably need a general strategy for defining epsilon in
783// various coordinate systems, e.g. for point comparison, enlargement of
784// bounding boxes, etc.
785template <typename CSTag>
786struct expand_by_epsilon
787 : not_implemented<CSTag>
788{};
789
790template <>
791struct expand_by_epsilon<cartesian_tag>
7c673cae 792{
92f5a8d4
TL
793 template <typename Box>
794 static inline void apply(Box & box)
795 {
796 detail::expand_by_epsilon(box);
797 }
798};
799
800template <>
801struct expand_by_epsilon<spherical_tag>
802{
803 template <typename Box>
804 static inline void apply(Box & box)
805 {
806 typedef typename coordinate_type<Box>::type coord_t;
807 static const coord_t eps = boost::is_same<coord_t, float>::value
808 ? coord_t(1e-6)
809 : coord_t(1e-12);
810 detail::expand_by_epsilon(box, eps);
811 }
812};
813
814// TODO: In geographic CS it should probably also depend on FormulaPolicy.
815template <>
816struct expand_by_epsilon<geographic_tag>
817 : expand_by_epsilon<spherical_tag>
818{};
819
820template <typename Sections, typename Strategy>
821inline void enlarge_sections(Sections& sections, Strategy const&)
822{
823 // Enlarge sections slightly, this should be consistent with math::equals()
824 // and with the tolerances used in general_form intersections.
825 // This avoids missing turns.
7c673cae 826
7c673cae
FG
827 // Points and Segments are equal-compared WRT machine epsilon, but Boxes aren't
828 // Enlarging Boxes ensures that they correspond to the bound objects,
829 // Segments in this case, since Sections are collections of Segments.
92f5a8d4
TL
830
831 // It makes section a tiny bit too large, which might cause (a small number)
832 // of more comparisons
7c673cae
FG
833 for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
834 it != boost::end(sections);
835 ++it)
836 {
92f5a8d4
TL
837#if defined(BOOST_GEOMETRY_USE_RESCALING)
838 detail::sectionalize::expand_by_epsilon
839 <
840 typename Strategy::cs_tag
841 >::apply(it->bounding_box);
842
843#else
844 // Expand the box to avoid missing any intersection. The amount is
845 // should be larger than epsilon. About the value itself: the smaller
846 // it is, the higher the risk to miss intersections. The larger it is,
847 // the more comparisons are made. So it should be on the high side.
848 detail::buffer::buffer_box(it->bounding_box, 0.001, it->bounding_box);
849#endif
7c673cae
FG
850 }
851}
852
853
854}} // namespace detail::sectionalize
855#endif // DOXYGEN_NO_DETAIL
856
857
858#ifndef DOXYGEN_NO_DISPATCH
859namespace dispatch
860{
861
862template
863<
864 typename Tag,
865 typename Geometry,
866 bool Reverse,
867 typename DimensionVector
868>
869struct sectionalize
870{
871 BOOST_MPL_ASSERT_MSG
872 (
873 false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
874 , (types<Geometry>)
875 );
876};
877
878template
879<
880 typename Box,
881 bool Reverse,
882 typename DimensionVector
883>
884struct sectionalize<box_tag, Box, Reverse, DimensionVector>
885 : detail::sectionalize::sectionalize_box<DimensionVector>
886{};
887
888template
889<
890 typename LineString,
891 typename DimensionVector
892>
893struct sectionalize
894 <
895 linestring_tag,
896 LineString,
897 false,
898 DimensionVector
899 >
900 : detail::sectionalize::sectionalize_range
901 <
902 closed, false,
903 typename point_type<LineString>::type,
904 DimensionVector
905 >
906{};
907
908template
909<
910 typename Ring,
911 bool Reverse,
912 typename DimensionVector
913>
914struct sectionalize<ring_tag, Ring, Reverse, DimensionVector>
915 : detail::sectionalize::sectionalize_range
916 <
917 geometry::closure<Ring>::value, Reverse,
918 typename point_type<Ring>::type,
919 DimensionVector
920 >
921{};
922
923template
924<
925 typename Polygon,
926 bool Reverse,
927 typename DimensionVector
928>
929struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector>
930 : detail::sectionalize::sectionalize_polygon
931 <
932 Reverse, DimensionVector
933 >
934{};
935
936template
937<
938 typename MultiPolygon,
939 bool Reverse,
940 typename DimensionVector
941>
942struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector>
943 : detail::sectionalize::sectionalize_multi
944 <
945 DimensionVector,
946 detail::sectionalize::sectionalize_polygon
947 <
948 Reverse,
949 DimensionVector
950 >
951 >
952
953{};
954
955template
956<
957 typename MultiLinestring,
958 bool Reverse,
959 typename DimensionVector
960>
961struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector>
962 : detail::sectionalize::sectionalize_multi
963 <
964 DimensionVector,
965 detail::sectionalize::sectionalize_range
966 <
967 closed, false,
968 typename point_type<MultiLinestring>::type,
969 DimensionVector
970 >
971 >
972
973{};
974
975} // namespace dispatch
976#endif
977
978
979/*!
980 \brief Split a geometry into monotonic sections
981 \ingroup sectionalize
982 \tparam Geometry type of geometry to check
983 \tparam Sections type of sections to create
984 \param geometry geometry to create sections from
985 \param robust_policy policy to handle robustness issues
986 \param sections structure with sections
92f5a8d4
TL
987 \param envelope_strategy strategy for envelope calculation
988 \param expand_strategy strategy for partitions
7c673cae
FG
989 \param source_index index to assign to the ring_identifiers
990 \param max_count maximal number of points per section
991 (defaults to 10, this seems to give the fastest results)
992
993 */
994template
995<
996 bool Reverse,
997 typename DimensionVector,
998 typename Geometry,
999 typename Sections,
b32b8144 1000 typename RobustPolicy,
92f5a8d4
TL
1001 typename EnvelopeStrategy,
1002 typename ExpandStrategy
7c673cae
FG
1003>
1004inline void sectionalize(Geometry const& geometry,
1005 RobustPolicy const& robust_policy,
1006 Sections& sections,
92f5a8d4
TL
1007 EnvelopeStrategy const& envelope_strategy,
1008 ExpandStrategy const& expand_strategy,
7c673cae
FG
1009 int source_index = 0,
1010 std::size_t max_count = 10)
1011{
b32b8144
FG
1012 BOOST_STATIC_ASSERT((! boost::is_fundamental<EnvelopeStrategy>::value));
1013
7c673cae
FG
1014 concepts::check<Geometry const>();
1015
1016 typedef typename boost::range_value<Sections>::type section_type;
1017
1018 // Compiletime check for point type of section boxes
1019 // and point type related to robust policy
1020 typedef typename geometry::coordinate_type
1021 <
1022 typename section_type::box_type
1023 >::type ctype1;
1024 typedef typename geometry::coordinate_type
1025 <
1026 typename geometry::robust_point_type
1027 <
1028 typename geometry::point_type<Geometry>::type,
1029 RobustPolicy
1030 >::type
1031 >::type ctype2;
1032
1033 BOOST_MPL_ASSERT((boost::is_same<ctype1, ctype2>));
1034
1035
1036 sections.clear();
1037
1038 ring_identifier ring_id;
1039 ring_id.source_index = source_index;
1040
1041 dispatch::sectionalize
1042 <
1043 typename tag<Geometry>::type,
1044 Geometry,
1045 Reverse,
1046 DimensionVector
92f5a8d4
TL
1047 >::apply(geometry, robust_policy, sections,
1048 envelope_strategy, expand_strategy,
1049 ring_id, max_count);
7c673cae 1050
92f5a8d4 1051 detail::sectionalize::enlarge_sections(sections, envelope_strategy);
7c673cae
FG
1052}
1053
1054
b32b8144
FG
1055template
1056<
1057 bool Reverse,
1058 typename DimensionVector,
1059 typename Geometry,
1060 typename Sections,
1061 typename RobustPolicy
1062>
1063inline void sectionalize(Geometry const& geometry,
1064 RobustPolicy const& robust_policy,
1065 Sections& sections,
1066 int source_index = 0,
1067 std::size_t max_count = 10)
1068{
1069 typedef typename strategy::envelope::services::default_strategy
1070 <
92f5a8d4 1071 typename tag<Geometry>::type,
b32b8144
FG
1072 typename cs_tag<Geometry>::type
1073 >::type envelope_strategy_type;
1074
92f5a8d4
TL
1075 typedef typename strategy::expand::services::default_strategy
1076 <
1077 typename boost::mpl::if_c
1078 <
1079 boost::is_same<typename tag<Geometry>::type, box_tag>::value,
1080 box_tag,
1081 segment_tag
1082 >::type,
1083 typename cs_tag<Geometry>::type
1084 >::type expand_strategy_type;
1085
b32b8144
FG
1086 boost::geometry::sectionalize
1087 <
1088 Reverse, DimensionVector
1089 >(geometry, robust_policy, sections,
1090 envelope_strategy_type(),
92f5a8d4 1091 expand_strategy_type(),
b32b8144
FG
1092 source_index, max_count);
1093}
1094
7c673cae
FG
1095}} // namespace boost::geometry
1096
1097
1098#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP