1 // Boost.Geometry (aka GGL, Generic Geometry Library)
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.
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.
11 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
12 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
14 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
15 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
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)
21 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
22 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
27 #include <boost/concept/requires.hpp>
28 #include <boost/core/ignore_unused.hpp>
29 #include <boost/mpl/assert.hpp>
30 #include <boost/mpl/vector_c.hpp>
31 #include <boost/range.hpp>
32 #include <boost/static_assert.hpp>
33 #include <boost/type_traits/is_same.hpp>
34 #include <boost/type_traits/is_fundamental.hpp>
36 #include <boost/geometry/core/config.hpp>
38 #include <boost/geometry/algorithms/assign.hpp>
39 #include <boost/geometry/algorithms/envelope.hpp>
40 #include <boost/geometry/algorithms/expand.hpp>
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>
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>
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>
61 #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
62 #include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp>
64 #include <boost/geometry/strategies/envelope.hpp>
65 #include <boost/geometry/strategies/expand.hpp>
67 namespace boost { namespace geometry
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
79 \tparam DimensionCount number of dimensions for this section
85 std::size_t DimensionCount
90 static std::size_t const dimension_count = DimensionCount;
92 int directions[DimensionCount];
93 ring_identifier ring_id;
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;
101 std::size_t range_count;
103 signed_size_type non_duplicate_index;
105 bool is_non_duplicate_first;
106 bool is_non_duplicate_last;
114 , non_duplicate_index(-1)
115 , is_non_duplicate_first(false)
116 , is_non_duplicate_last(false)
118 assign_inverse(bounding_box);
119 for (std::size_t i = 0; i < DimensionCount; i++)
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
133 template <typename Box, std::size_t DimensionCount>
134 struct sections : std::vector<section<Box, DimensionCount> >
136 typedef Box box_type;
137 static std::size_t const value = DimensionCount;
141 #ifndef DOXYGEN_NO_DETAIL
142 namespace detail { namespace sectionalize
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.
152 typename DimensionVector,
155 typename CastedCSTag = typename tag_cast
157 typename cs_tag<Point>::type,
161 struct get_direction_loop
163 typedef typename boost::mpl::at_c<DimensionVector, Index>::type dimension;
165 template <typename Segment>
166 static inline void apply(Segment const& seg,
167 int directions[Count])
169 typedef typename coordinate_type<Segment>::type coordinate_type;
171 coordinate_type const c0 = geometry::get<0, dimension::value>(seg);
172 coordinate_type const c1 = geometry::get<1, dimension::value>(seg);
174 directions[Index] = c1 > c0 ? 1 : c1 < c0 ? -1 : 0;
183 >::apply(seg, directions);
190 typename DimensionVector,
193 struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag>
195 typedef typename boost::mpl::at_c<DimensionVector, 0>::type dimension;
197 template <typename Segment>
198 static inline void apply(Segment const& seg,
199 int directions[Count])
201 typedef typename coordinate_type<Segment>::type coordinate_type;
202 typedef typename coordinate_system<Point>::type::units units_t;
204 coordinate_type const diff = math::longitude_distance_signed
206 units_t, coordinate_type
207 >(geometry::get<0, 0>(seg),
208 geometry::get<1, 0>(seg));
210 coordinate_type zero = coordinate_type();
211 directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0;
220 >::apply(seg, directions);
227 typename DimensionVector,
231 struct get_direction_loop<Point, DimensionVector, Count, Count, CastedCSTag>
233 template <typename Segment>
234 static inline void apply(Segment const&, int [Count])
239 //! Copy one static array to another
240 template <typename T, std::size_t Index, std::size_t Count>
243 static inline void apply(T const source[Count], T target[Count])
245 target[Index] = source[Index];
246 copy_loop<T, Index + 1, Count>::apply(source, target);
250 template <typename T, std::size_t Count>
251 struct copy_loop<T, Count, Count>
253 static inline void apply(T const [Count], T [Count])
257 //! Compare two static arrays
258 template <typename T, std::size_t Index, std::size_t Count>
261 static inline bool apply(T const array1[Count], T const array2[Count])
263 return array1[Index] != array2[Index]
268 >::apply(array1, array2);
272 template <typename T, std::size_t Count>
273 struct compare_loop<T, Count, Count>
275 static inline bool apply(T const [Count], T const [Count])
283 template <std::size_t Dimension, std::size_t DimensionCount>
284 struct check_duplicate_loop
286 template <typename Segment>
287 static inline bool apply(Segment const& seg)
289 if (! geometry::math::equals
291 geometry::get<0, Dimension>(seg),
292 geometry::get<1, Dimension>(seg)
299 return check_duplicate_loop
301 Dimension + 1, DimensionCount
306 template <std::size_t DimensionCount>
307 struct check_duplicate_loop<DimensionCount, DimensionCount>
309 template <typename Segment>
310 static inline bool apply(Segment const&)
316 //! Assign a value to a static array
317 template <typename T, std::size_t Index, std::size_t Count>
320 static inline void apply(T dims[Count], T const value)
323 assign_loop<T, Index + 1, Count>::apply(dims, value);
327 template <typename T, std::size_t Count>
328 struct assign_loop<T, Count, Count>
330 static inline void apply(T [Count], T const)
335 template <typename CSTag>
336 struct box_first_in_section
338 template <typename Box, typename Point, typename EnvelopeStrategy>
339 static inline void apply(Box & box, Point const& prev, Point const& curr,
340 EnvelopeStrategy const& strategy)
342 geometry::model::referring_segment<Point const> seg(prev, curr);
343 geometry::envelope(seg, box, strategy);
348 struct box_first_in_section<cartesian_tag>
350 template <typename Box, typename Point, typename ExpandStrategy>
351 static inline void apply(Box & box, Point const& prev, Point const& curr,
352 ExpandStrategy const& )
354 geometry::envelope(prev, box);
355 geometry::expand(box, curr);
359 template <typename CSTag>
360 struct box_next_in_section
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)
366 geometry::model::referring_segment<Point const> seg(prev, curr);
367 geometry::expand(box, seg, strategy);
372 struct box_next_in_section<cartesian_tag>
374 template <typename Box, typename Point, typename Strategy>
375 static inline void apply(Box & box, Point const& , Point const& curr,
378 geometry::expand(box, curr);
382 /// @brief Helper class to create sections of a part of a range, on the fly
386 typename DimensionVector
388 struct sectionalize_part
390 static const std::size_t dimension_count
391 = boost::mpl::size<DimensionVector>::value;
396 typename RobustPolicy,
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)
405 typedef typename strategy::envelope::services::default_strategy
408 typename cs_tag<typename Sections::box_type>::type
409 >::type envelope_strategy_type;
411 typedef typename strategy::expand::services::default_strategy
414 typename cs_tag<typename Sections::box_type>::type
415 >::type expand_strategy_type;
417 apply(sections, begin, end,
419 envelope_strategy_type(),
420 expand_strategy_type(),
427 typename RobustPolicy,
429 typename EnvelopeStrategy,
430 typename ExpandStrategy
432 static inline void apply(Sections& sections,
433 Iterator begin, Iterator end,
434 RobustPolicy const& robust_policy,
435 EnvelopeStrategy const& envelope_strategy,
436 ExpandStrategy const& expand_strategy,
437 ring_identifier ring_id,
438 std::size_t max_count)
440 boost::ignore_unused(robust_policy);
442 typedef typename boost::range_value<Sections>::type section_type;
445 (static_cast<std::size_t>(section_type::dimension_count)
446 == static_cast<std::size_t>(boost::mpl::size<DimensionVector>::value))
449 typedef typename geometry::robust_point_type
453 >::type robust_point_type;
455 std::size_t const count = std::distance(begin, end);
461 signed_size_type index = 0;
462 signed_size_type ndi = 0; // non duplicate index
463 section_type section;
465 bool mark_first_non_duplicated = true;
466 std::size_t last_non_duplicate_index = sections.size();
469 robust_point_type previous_robust_point;
470 geometry::recalculate(previous_robust_point, *it, robust_policy);
472 for(Iterator previous = it++;
474 ++previous, ++it, index++)
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);
481 int direction_classes[dimension_count] = {0};
484 Point, DimensionVector, 0, dimension_count
485 >::apply(robust_segment, direction_classes);
487 // if "dir" == 0 for all point-dimensions, it is duplicate.
488 // Those sections might be omitted, if wished, lateron
489 bool duplicate = false;
491 if (direction_classes[0] == 0)
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
498 0, geometry::dimension<Point>::type::value
499 >::apply(robust_segment)
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
510 int, 0, dimension_count
511 >::apply(direction_classes, -99);
515 if (section.count > 0
518 int, 0, dimension_count
519 >::apply(direction_classes, section.directions)
520 || section.count > max_count)
523 if (! section.duplicate)
525 last_non_duplicate_index = sections.size();
528 sections.push_back(section);
529 section = section_type();
532 if (section.count == 0)
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;
540 if (mark_first_non_duplicated && ! duplicate)
542 section.is_non_duplicate_first = true;
543 mark_first_non_duplicated = false;
548 int, 0, dimension_count
549 >::apply(direction_classes, section.directions);
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>
554 ::apply(section.bounding_box, previous_robust_point, current_robust_point, envelope_strategy);
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>
561 ::apply(section.bounding_box, previous_robust_point, current_robust_point, expand_strategy);
564 section.end_index = index + 1;
570 previous_robust_point = current_robust_point;
573 // Add last section if applicable
574 if (section.count > 0)
576 if (! section.duplicate)
578 last_non_duplicate_index = sections.size();
581 sections.push_back(section);
584 if (last_non_duplicate_index < sections.size()
585 && ! sections[last_non_duplicate_index].duplicate)
587 sections[last_non_duplicate_index].is_non_duplicate_last = true;
595 closure_selector Closure,
598 typename DimensionVector
600 struct sectionalize_range
605 typename RobustPolicy,
607 typename EnvelopeStrategy,
608 typename ExpandStrategy
610 static inline void apply(Range const& range,
611 RobustPolicy const& robust_policy,
613 EnvelopeStrategy const& envelope_strategy,
614 ExpandStrategy const& expand_strategy,
615 ring_identifier ring_id,
616 std::size_t max_count)
618 typedef typename closeable_view<Range const, Closure>::type cview_type;
619 typedef typename reversible_view
622 Reverse ? iterate_reverse : iterate_forward
625 cview_type cview(range);
626 view_type view(cview);
628 std::size_t const n = boost::size(view);
631 // Zero points, no section
637 // Line with one point ==> no sections
641 sectionalize_part<Point, DimensionVector>::apply(sections,
642 boost::begin(view), boost::end(view),
643 robust_policy, envelope_strategy, expand_strategy,
651 typename DimensionVector
653 struct sectionalize_polygon
658 typename RobustPolicy,
660 typename EnvelopeStrategy,
661 typename ExpandStrategy
663 static inline void apply(Polygon const& poly,
664 RobustPolicy const& robust_policy,
666 EnvelopeStrategy const& envelope_strategy,
667 ExpandStrategy const& expand_strategy,
668 ring_identifier ring_id,
669 std::size_t max_count)
671 typedef typename point_type<Polygon>::type point_type;
672 typedef sectionalize_range
674 closure<Polygon>::value, Reverse,
675 point_type, DimensionVector
678 ring_id.ring_index = -1;
679 per_range::apply(exterior_ring(poly), robust_policy, sections,
680 envelope_strategy, expand_strategy, ring_id, max_count);
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)
688 per_range::apply(*it, robust_policy, sections,
689 envelope_strategy, expand_strategy, ring_id, max_count);
694 template <typename DimensionVector>
695 struct sectionalize_box
700 typename RobustPolicy,
702 typename EnvelopeStrategy,
703 typename ExpandStrategy
705 static inline void apply(Box const& box,
706 RobustPolicy const& robust_policy,
708 EnvelopeStrategy const& envelope_strategy,
709 ExpandStrategy const& expand_strategy,
710 ring_identifier const& ring_id, std::size_t max_count)
712 typedef typename point_type<Box>::type point_type;
714 assert_dimension<Box, 2>();
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
722 // TODO: might be replaced by assign_box_corners_oriented
724 point_type ll, lr, ul, ur;
725 geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
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);
734 // NOTE: Use cartesian envelope strategy in all coordinate systems
735 // because edges of a box are not geodesic segments
741 >::apply(points, robust_policy, sections,
742 envelope_strategy, expand_strategy,
747 template <typename DimensionVector, typename Policy>
748 struct sectionalize_multi
752 typename MultiGeometry,
753 typename RobustPolicy,
755 typename EnvelopeStrategy,
756 typename ExpandStrategy
758 static inline void apply(MultiGeometry const& multi,
759 RobustPolicy const& robust_policy,
761 EnvelopeStrategy const& envelope_strategy,
762 ExpandStrategy const& expand_strategy,
763 ring_identifier ring_id,
764 std::size_t max_count)
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)
772 Policy::apply(*it, robust_policy, sections,
773 envelope_strategy, expand_strategy,
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.
785 template <typename CSTag>
786 struct expand_by_epsilon
787 : not_implemented<CSTag>
791 struct expand_by_epsilon<cartesian_tag>
793 template <typename Box>
794 static inline void apply(Box & box)
796 detail::expand_by_epsilon(box);
801 struct expand_by_epsilon<spherical_tag>
803 template <typename Box>
804 static inline void apply(Box & box)
806 typedef typename coordinate_type<Box>::type coord_t;
807 static const coord_t eps = boost::is_same<coord_t, float>::value
810 detail::expand_by_epsilon(box, eps);
814 // TODO: In geographic CS it should probably also depend on FormulaPolicy.
816 struct expand_by_epsilon<geographic_tag>
817 : expand_by_epsilon<spherical_tag>
820 template <typename Sections, typename Strategy>
821 inline void enlarge_sections(Sections& sections, Strategy const&)
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.
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.
831 // It makes section a tiny bit too large, which might cause (a small number)
832 // of more comparisons
833 for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
834 it != boost::end(sections);
837 #if defined(BOOST_GEOMETRY_USE_RESCALING)
838 detail::sectionalize::expand_by_epsilon
840 typename Strategy::cs_tag
841 >::apply(it->bounding_box);
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);
854 }} // namespace detail::sectionalize
855 #endif // DOXYGEN_NO_DETAIL
858 #ifndef DOXYGEN_NO_DISPATCH
867 typename DimensionVector
873 false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
882 typename DimensionVector
884 struct sectionalize<box_tag, Box, Reverse, DimensionVector>
885 : detail::sectionalize::sectionalize_box<DimensionVector>
891 typename DimensionVector
900 : detail::sectionalize::sectionalize_range
903 typename point_type<LineString>::type,
912 typename DimensionVector
914 struct sectionalize<ring_tag, Ring, Reverse, DimensionVector>
915 : detail::sectionalize::sectionalize_range
917 geometry::closure<Ring>::value, Reverse,
918 typename point_type<Ring>::type,
927 typename DimensionVector
929 struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector>
930 : detail::sectionalize::sectionalize_polygon
932 Reverse, DimensionVector
938 typename MultiPolygon,
940 typename DimensionVector
942 struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector>
943 : detail::sectionalize::sectionalize_multi
946 detail::sectionalize::sectionalize_polygon
957 typename MultiLinestring,
959 typename DimensionVector
961 struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector>
962 : detail::sectionalize::sectionalize_multi
965 detail::sectionalize::sectionalize_range
968 typename point_type<MultiLinestring>::type,
975 } // namespace dispatch
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
987 \param envelope_strategy strategy for envelope calculation
988 \param expand_strategy strategy for partitions
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)
997 typename DimensionVector,
1000 typename RobustPolicy,
1001 typename EnvelopeStrategy,
1002 typename ExpandStrategy
1004 inline void sectionalize(Geometry const& geometry,
1005 RobustPolicy const& robust_policy,
1007 EnvelopeStrategy const& envelope_strategy,
1008 ExpandStrategy const& expand_strategy,
1009 int source_index = 0,
1010 std::size_t max_count = 10)
1012 BOOST_STATIC_ASSERT((! boost::is_fundamental<EnvelopeStrategy>::value));
1014 concepts::check<Geometry const>();
1016 typedef typename boost::range_value<Sections>::type section_type;
1018 // Compiletime check for point type of section boxes
1019 // and point type related to robust policy
1020 typedef typename geometry::coordinate_type
1022 typename section_type::box_type
1024 typedef typename geometry::coordinate_type
1026 typename geometry::robust_point_type
1028 typename geometry::point_type<Geometry>::type,
1033 BOOST_MPL_ASSERT((boost::is_same<ctype1, ctype2>));
1038 ring_identifier ring_id;
1039 ring_id.source_index = source_index;
1041 dispatch::sectionalize
1043 typename tag<Geometry>::type,
1047 >::apply(geometry, robust_policy, sections,
1048 envelope_strategy, expand_strategy,
1049 ring_id, max_count);
1051 detail::sectionalize::enlarge_sections(sections, envelope_strategy);
1058 typename DimensionVector,
1061 typename RobustPolicy
1063 inline void sectionalize(Geometry const& geometry,
1064 RobustPolicy const& robust_policy,
1066 int source_index = 0,
1067 std::size_t max_count = 10)
1069 typedef typename strategy::envelope::services::default_strategy
1071 typename tag<Geometry>::type,
1072 typename cs_tag<Geometry>::type
1073 >::type envelope_strategy_type;
1075 typedef typename strategy::expand::services::default_strategy
1077 typename boost::mpl::if_c
1079 boost::is_same<typename tag<Geometry>::type, box_tag>::value,
1083 typename cs_tag<Geometry>::type
1084 >::type expand_strategy_type;
1086 boost::geometry::sectionalize
1088 Reverse, DimensionVector
1089 >(geometry, robust_policy, sections,
1090 envelope_strategy_type(),
1091 expand_strategy_type(),
1092 source_index, max_count);
1095 }} // namespace boost::geometry
1098 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP