1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
8 // This file was modified by Oracle on 2013, 2014.
9 // Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
11 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
12 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
14 // Use, modification and distribution is subject to the Boost Software License,
15 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
16 // http://www.boost.org/LICENSE_1_0.txt)
18 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
20 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
21 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
26 #include <boost/concept/requires.hpp>
27 #include <boost/mpl/assert.hpp>
28 #include <boost/range.hpp>
30 #include <boost/geometry/algorithms/assign.hpp>
31 #include <boost/geometry/algorithms/expand.hpp>
33 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
34 #include <boost/geometry/algorithms/detail/recalculate.hpp>
35 #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
37 #include <boost/geometry/core/access.hpp>
38 #include <boost/geometry/core/closure.hpp>
39 #include <boost/geometry/core/exterior_ring.hpp>
40 #include <boost/geometry/core/point_order.hpp>
41 #include <boost/geometry/core/tags.hpp>
43 #include <boost/geometry/geometries/concepts/check.hpp>
44 #include <boost/geometry/util/math.hpp>
45 #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
46 #include <boost/geometry/policies/robustness/robust_point_type.hpp>
47 #include <boost/geometry/views/closeable_view.hpp>
48 #include <boost/geometry/views/reversible_view.hpp>
49 #include <boost/geometry/geometries/segment.hpp>
51 namespace boost { namespace geometry
56 \brief Structure containing section information
57 \details Section information consists of a bounding box, direction
58 information (if it is increasing or decreasing, per dimension),
59 index information (begin-end, ring, multi) and the number of
60 segments in this section
63 \tparam DimensionCount number of dimensions for this section
66 template <typename Box, std::size_t DimensionCount>
71 int id; // might be obsolete now, BSG 14-03-2011 TODO decide about this
73 int directions[DimensionCount];
74 ring_identifier ring_id;
80 std::size_t range_count;
82 int non_duplicate_index;
84 bool is_non_duplicate_first;
85 bool is_non_duplicate_last;
94 , non_duplicate_index(-1)
95 , is_non_duplicate_first(false)
96 , is_non_duplicate_last(false)
98 assign_inverse(bounding_box);
99 for (std::size_t i = 0; i < DimensionCount; i++)
108 \brief Structure containing a collection of sections
109 \note Derived from a vector, proves to be faster than of deque
110 \note vector might be templated in the future
111 \ingroup sectionalize
113 template <typename Box, std::size_t DimensionCount>
114 struct sections : std::vector<section<Box, DimensionCount> >
116 typedef Box box_type;
117 static std::size_t const value = DimensionCount;
121 #ifndef DOXYGEN_NO_DETAIL
122 namespace detail { namespace sectionalize
125 template <std::size_t Dimension, std::size_t DimensionCount>
126 struct get_direction_loop
128 template <typename Segment>
129 static inline void apply(Segment const& seg,
130 int directions[DimensionCount])
132 typedef typename coordinate_type<Segment>::type coordinate_type;
133 coordinate_type const diff =
134 geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg);
136 coordinate_type zero = coordinate_type();
137 directions[Dimension] = diff > zero ? 1 : diff < zero ? -1 : 0;
141 Dimension + 1, DimensionCount
142 >::apply(seg, directions);
146 template <std::size_t DimensionCount>
147 struct get_direction_loop<DimensionCount, DimensionCount>
149 template <typename Segment>
150 static inline void apply(Segment const&, int [DimensionCount])
154 template <typename T, std::size_t Dimension, std::size_t DimensionCount>
157 static inline void apply(T const source[DimensionCount],
158 T target[DimensionCount])
160 target[Dimension] = source[Dimension];
161 copy_loop<T, Dimension + 1, DimensionCount>::apply(source, target);
165 template <typename T, std::size_t DimensionCount>
166 struct copy_loop<T, DimensionCount, DimensionCount>
168 static inline void apply(T const [DimensionCount], T [DimensionCount])
172 template <typename T, std::size_t Dimension, std::size_t DimensionCount>
175 static inline bool apply(T const source[DimensionCount],
176 T const target[DimensionCount])
178 bool const not_equal = target[Dimension] != source[Dimension];
184 T, Dimension + 1, DimensionCount
185 >::apply(source, target);
189 template <typename T, std::size_t DimensionCount>
190 struct compare_loop<T, DimensionCount, DimensionCount>
192 static inline bool apply(T const [DimensionCount],
193 T const [DimensionCount])
201 template <std::size_t Dimension, std::size_t DimensionCount>
202 struct check_duplicate_loop
204 template <typename Segment>
205 static inline bool apply(Segment const& seg)
207 if (! geometry::math::equals
209 geometry::get<0, Dimension>(seg),
210 geometry::get<1, Dimension>(seg)
217 return check_duplicate_loop
219 Dimension + 1, DimensionCount
224 template <std::size_t DimensionCount>
225 struct check_duplicate_loop<DimensionCount, DimensionCount>
227 template <typename Segment>
228 static inline bool apply(Segment const&)
234 template <typename T, std::size_t Dimension, std::size_t DimensionCount>
237 static inline void apply(T dims[DimensionCount], int const value)
239 dims[Dimension] = value;
240 assign_loop<T, Dimension + 1, DimensionCount>::apply(dims, value);
244 template <typename T, std::size_t DimensionCount>
245 struct assign_loop<T, DimensionCount, DimensionCount>
247 static inline void apply(T [DimensionCount], int const)
252 /// @brief Helper class to create sections of a part of a range, on the fly
256 std::size_t DimensionCount
258 struct sectionalize_part
262 typename Range, // Can be closeable_view
263 typename RobustPolicy,
266 static inline void apply(Sections& sections,
268 RobustPolicy const& robust_policy,
269 bool make_rescaled_boxes,
270 ring_identifier ring_id,
271 std::size_t max_count)
273 boost::ignore_unused_variable_warning(robust_policy);
274 boost::ignore_unused_variable_warning(make_rescaled_boxes);
276 typedef model::referring_segment<Point const> segment_type;
277 typedef typename boost::range_value<Sections>::type section_type;
278 typedef model::segment
280 typename robust_point_type<Point, RobustPolicy>::type
281 > robust_segment_type;
282 typedef typename boost::range_iterator<Range const>::type iterator_type;
284 if ( boost::empty(range) )
290 int ndi = 0; // non duplicate index
291 section_type section;
293 bool mark_first_non_duplicated = true;
294 std::size_t last_non_duplicate_index = sections.size();
296 iterator_type it = boost::begin(range);
298 for(iterator_type previous = it++;
299 it != boost::end(range);
300 ++previous, ++it, index++)
302 segment_type segment(*previous, *it);
303 robust_segment_type robust_segment;
304 geometry::recalculate(robust_segment, segment, robust_policy);
306 int direction_classes[DimensionCount] = {0};
310 >::apply(robust_segment, direction_classes);
312 // if "dir" == 0 for all point-dimensions, it is duplicate.
313 // Those sections might be omitted, if wished, lateron
314 bool duplicate = false;
316 if (direction_classes[0] == 0)
318 // Recheck because ALL dimensions should be checked,
319 // not only first one.
320 // (DimensionCount might be < dimension<P>::value)
321 if (check_duplicate_loop
323 0, geometry::dimension<Point>::type::value
324 >::apply(robust_segment)
329 // Change direction-info to force new section
330 // Note that wo consecutive duplicate segments will generate
331 // only one duplicate-section.
332 // Actual value is not important as long as it is not -1,0,1
335 int, 0, DimensionCount
336 >::apply(direction_classes, -99);
340 if (section.count > 0
343 int, 0, DimensionCount
344 >::apply(direction_classes, section.directions)
345 || section.count > max_count
349 if ( !section.duplicate )
351 last_non_duplicate_index = sections.size();
354 sections.push_back(section);
355 section = section_type();
358 if (section.count == 0)
360 section.begin_index = index;
361 section.ring_id = ring_id;
362 section.duplicate = duplicate;
363 section.non_duplicate_index = ndi;
364 section.range_count = boost::size(range);
366 if ( mark_first_non_duplicated && !duplicate )
368 section.is_non_duplicate_first = true;
369 mark_first_non_duplicated = false;
374 int, 0, DimensionCount
375 >::apply(direction_classes, section.directions);
377 expand_box(*previous, robust_policy, section);
380 expand_box(*it, robust_policy, section);
381 section.end_index = index + 1;
389 // Add last section if applicable
390 if (section.count > 0)
392 if ( !section.duplicate )
394 last_non_duplicate_index = sections.size();
397 sections.push_back(section);
400 if ( last_non_duplicate_index < sections.size()
401 && !sections[last_non_duplicate_index].duplicate )
403 sections[last_non_duplicate_index].is_non_duplicate_last = true;
407 template <typename InputPoint, typename RobustPolicy, typename Section>
408 static inline void expand_box(InputPoint const& point,
409 RobustPolicy const& robust_policy,
412 typename geometry::point_type<typename Section::box_type>::type robust_point;
413 geometry::recalculate(robust_point, point, robust_policy);
414 geometry::expand(section.bounding_box, robust_point);
421 closure_selector Closure, bool Reverse,
423 std::size_t DimensionCount
425 struct sectionalize_range
430 typename RobustPolicy,
433 static inline void apply(Range const& range,
434 RobustPolicy const& robust_policy,
435 bool make_rescaled_boxes,
437 ring_identifier ring_id,
438 std::size_t max_count)
440 typedef typename closeable_view<Range const, Closure>::type cview_type;
441 typedef typename reversible_view
444 Reverse ? iterate_reverse : iterate_forward
447 cview_type cview(range);
448 view_type view(cview);
450 std::size_t const n = boost::size(view);
453 // Zero points, no section
459 // Line with one point ==> no sections
463 sectionalize_part<Point, DimensionCount>
464 ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count);
471 std::size_t DimensionCount
473 struct sectionalize_polygon
478 typename RobustPolicy,
481 static inline void apply(Polygon const& poly,
482 RobustPolicy const& robust_policy,
483 bool make_rescaled_boxes,
485 ring_identifier ring_id, std::size_t max_count)
487 typedef typename point_type<Polygon>::type point_type;
488 //typedef typename ring_type<Polygon>::type ring_type;
489 typedef sectionalize_range
491 closure<Polygon>::value, Reverse,
492 point_type, DimensionCount
495 ring_id.ring_index = -1;
496 per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
498 ring_id.ring_index++;
499 typename interior_return_type<Polygon const>::type
500 rings = interior_rings(poly);
501 for (typename detail::interior_iterator<Polygon const>::type
502 it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
504 per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
511 std::size_t DimensionCount
513 struct sectionalize_box
518 typename RobustPolicy,
521 static inline void apply(Box const& box,
522 RobustPolicy const& robust_policy,
523 bool make_rescaled_boxes,
525 ring_identifier const& ring_id, std::size_t max_count)
527 typedef typename point_type<Box>::type point_type;
529 assert_dimension<Box, 2>();
531 // Add all four sides of the 2D-box as separate section.
532 // Easiest is to convert it to a polygon.
533 // However, we don't have the polygon type
534 // (or polygon would be a helper-type).
535 // Therefore we mimic a linestring/std::vector of 5 points
537 // TODO: might be replaced by assign_box_corners_oriented
539 point_type ll, lr, ul, ur;
540 geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
542 std::vector<point_type> points;
543 points.push_back(ll);
544 points.push_back(ul);
545 points.push_back(ur);
546 points.push_back(lr);
547 points.push_back(ll);
554 >::apply(points, robust_policy, make_rescaled_boxes, sections,
559 template <std::size_t DimensionCount, typename Policy>
560 struct sectionalize_multi
564 typename MultiGeometry,
565 typename RobustPolicy,
568 static inline void apply(MultiGeometry const& multi,
569 RobustPolicy const& robust_policy,
570 bool make_rescaled_boxes,
571 Sections& sections, ring_identifier ring_id, std::size_t max_count)
573 ring_id.multi_index = 0;
574 for (typename boost::range_iterator<MultiGeometry const>::type
575 it = boost::begin(multi);
576 it != boost::end(multi);
577 ++it, ++ring_id.multi_index)
579 Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
584 template <typename Sections>
585 inline void set_section_unique_ids(Sections& sections)
589 for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
590 it != boost::end(sections);
597 template <typename Sections>
598 inline void enlarge_sections(Sections& sections)
600 // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border)
601 // Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1")
602 // Drawback: not really, range is now completely inside the section. Section is a tiny bit too large,
603 // which might cause (a small number) of more comparisons
604 // TODO: make dimension-agnostic
605 for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
606 it != boost::end(sections);
609 typedef typename boost::range_value<Sections>::type section_type;
610 typedef typename section_type::box_type box_type;
611 typedef typename geometry::coordinate_type<box_type>::type coordinate_type;
612 coordinate_type const reps = math::relaxed_epsilon(10.0);
613 geometry::set<0, 0>(it->bounding_box, geometry::get<0, 0>(it->bounding_box) - reps);
614 geometry::set<0, 1>(it->bounding_box, geometry::get<0, 1>(it->bounding_box) - reps);
615 geometry::set<1, 0>(it->bounding_box, geometry::get<1, 0>(it->bounding_box) + reps);
616 geometry::set<1, 1>(it->bounding_box, geometry::get<1, 1>(it->bounding_box) + reps);
621 }} // namespace detail::sectionalize
622 #endif // DOXYGEN_NO_DETAIL
625 #ifndef DOXYGEN_NO_DISPATCH
634 std::size_t DimensionCount
640 false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
649 std::size_t DimensionCount
651 struct sectionalize<box_tag, Box, Reverse, DimensionCount>
652 : detail::sectionalize::sectionalize_box<DimensionCount>
658 std::size_t DimensionCount
667 : detail::sectionalize::sectionalize_range
670 typename point_type<LineString>::type,
679 std::size_t DimensionCount
681 struct sectionalize<ring_tag, Ring, Reverse, DimensionCount>
682 : detail::sectionalize::sectionalize_range
684 geometry::closure<Ring>::value, Reverse,
685 typename point_type<Ring>::type,
694 std::size_t DimensionCount
696 struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount>
697 : detail::sectionalize::sectionalize_polygon
699 Reverse, DimensionCount
705 typename MultiPolygon,
707 std::size_t DimensionCount
709 struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionCount>
710 : detail::sectionalize::sectionalize_multi
713 detail::sectionalize::sectionalize_polygon
724 typename MultiLinestring,
726 std::size_t DimensionCount
728 struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCount>
729 : detail::sectionalize::sectionalize_multi
732 detail::sectionalize::sectionalize_range
735 typename point_type<MultiLinestring>::type,
742 } // namespace dispatch
747 \brief Split a geometry into monotonic sections
748 \ingroup sectionalize
749 \tparam Geometry type of geometry to check
750 \tparam Sections type of sections to create
751 \param geometry geometry to create sections from
752 \param robust_policy policy to handle robustness issues
753 \param enlarge_secion_boxes if true, boxes are enlarged a tiny bit to be sure
754 they really contain all geometries (w.r.t. robustness)
755 \param sections structure with sections
756 \param source_index index to assign to the ring_identifiers
758 template<bool Reverse, typename Geometry, typename Sections, typename RobustPolicy>
759 inline void sectionalize(Geometry const& geometry,
760 RobustPolicy const& robust_policy,
761 bool enlarge_secion_boxes,
763 int source_index = 0)
765 concept::check<Geometry const>();
769 ring_identifier ring_id;
770 ring_id.source_index = source_index;
772 // A maximum of 10 segments per section seems to give the fastest results
773 dispatch::sectionalize
775 typename tag<Geometry>::type,
779 >::apply(geometry, robust_policy, enlarge_secion_boxes, sections, ring_id, 10);
781 detail::sectionalize::set_section_unique_ids(sections);
782 if (! enlarge_secion_boxes)
784 detail::sectionalize::enlarge_sections(sections);
789 #if defined(BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE)
790 // Backwards compatibility
791 template<bool Reverse, typename Geometry, typename Sections>
792 inline void sectionalize(Geometry const& geometry,
794 int source_index = 0)
796 return geometry::sectionalize<Reverse>(geometry, detail::no_rescale_policy(),
803 }} // namespace boost::geometry
806 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP