Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / geometry / algorithms / detail / sections / sectionalize.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
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.
7
8 // This file was modified by Oracle on 2013, 2014.
9 // Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
10
11 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
12 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
13
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)
17
18 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
19
20 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
21 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
22
23 #include <cstddef>
24 #include <vector>
25
26 #include <boost/concept/requires.hpp>
27 #include <boost/mpl/assert.hpp>
28 #include <boost/range.hpp>
29
30 #include <boost/geometry/algorithms/assign.hpp>
31 #include <boost/geometry/algorithms/expand.hpp>
32
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>
36
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>
42
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>
50
51 namespace boost { namespace geometry
52 {
53
54
55 /*!
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
61
62     \tparam Box box-type
63     \tparam DimensionCount number of dimensions for this section
64     \ingroup sectionalize
65  */
66 template <typename Box, std::size_t DimensionCount>
67 struct section
68 {
69     typedef Box box_type;
70
71     int id; // might be obsolete now, BSG 14-03-2011 TODO decide about this
72
73     int directions[DimensionCount];
74     ring_identifier ring_id;
75     Box bounding_box;
76
77     int begin_index;
78     int end_index;
79     std::size_t count;
80     std::size_t range_count;
81     bool duplicate;
82     int non_duplicate_index;
83
84     bool is_non_duplicate_first;
85     bool is_non_duplicate_last;
86
87     inline section()
88         : id(-1)
89         , begin_index(-1)
90         , end_index(-1)
91         , count(0)
92         , range_count(0)
93         , duplicate(false)
94         , non_duplicate_index(-1)
95         , is_non_duplicate_first(false)
96         , is_non_duplicate_last(false)
97     {
98         assign_inverse(bounding_box);
99         for (std::size_t i = 0; i < DimensionCount; i++)
100         {
101             directions[i] = 0;
102         }
103     }
104 };
105
106
107 /*!
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
112  */
113 template <typename Box, std::size_t DimensionCount>
114 struct sections : std::vector<section<Box, DimensionCount> >
115 {
116     typedef Box box_type;
117     static std::size_t const value = DimensionCount;
118 };
119
120
121 #ifndef DOXYGEN_NO_DETAIL
122 namespace detail { namespace sectionalize
123 {
124
125 template <std::size_t Dimension, std::size_t DimensionCount>
126 struct get_direction_loop
127 {
128     template <typename Segment>
129     static inline void apply(Segment const& seg,
130                 int directions[DimensionCount])
131     {
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);
135
136         coordinate_type zero = coordinate_type();
137         directions[Dimension] = diff > zero ? 1 : diff < zero ? -1 : 0;
138
139         get_direction_loop
140             <
141                 Dimension + 1, DimensionCount
142             >::apply(seg, directions);
143     }
144 };
145
146 template <std::size_t DimensionCount>
147 struct get_direction_loop<DimensionCount, DimensionCount>
148 {
149     template <typename Segment>
150     static inline void apply(Segment const&, int [DimensionCount])
151     {}
152 };
153
154 template <typename T, std::size_t Dimension, std::size_t DimensionCount>
155 struct copy_loop
156 {
157     static inline void apply(T const source[DimensionCount],
158                 T target[DimensionCount])
159     {
160         target[Dimension] = source[Dimension];
161         copy_loop<T, Dimension + 1, DimensionCount>::apply(source, target);
162     }
163 };
164
165 template <typename T, std::size_t DimensionCount>
166 struct copy_loop<T, DimensionCount, DimensionCount>
167 {
168     static inline void apply(T const [DimensionCount], T [DimensionCount])
169     {}
170 };
171
172 template <typename T, std::size_t Dimension, std::size_t DimensionCount>
173 struct compare_loop
174 {
175     static inline bool apply(T const source[DimensionCount],
176                 T const target[DimensionCount])
177     {
178         bool const not_equal = target[Dimension] != source[Dimension];
179
180         return not_equal
181             ? false
182             : compare_loop
183                 <
184                     T, Dimension + 1, DimensionCount
185                 >::apply(source, target);
186     }
187 };
188
189 template <typename T, std::size_t DimensionCount>
190 struct compare_loop<T, DimensionCount, DimensionCount>
191 {
192     static inline bool apply(T const [DimensionCount],
193                 T const [DimensionCount])
194     {
195
196         return true;
197     }
198 };
199
200
201 template <std::size_t Dimension, std::size_t DimensionCount>
202 struct check_duplicate_loop
203 {
204     template <typename Segment>
205     static inline bool apply(Segment const& seg)
206     {
207         if (! geometry::math::equals
208                 (
209                     geometry::get<0, Dimension>(seg),
210                     geometry::get<1, Dimension>(seg)
211                 )
212             )
213         {
214             return false;
215         }
216
217         return check_duplicate_loop
218             <
219                 Dimension + 1, DimensionCount
220             >::apply(seg);
221     }
222 };
223
224 template <std::size_t DimensionCount>
225 struct check_duplicate_loop<DimensionCount, DimensionCount>
226 {
227     template <typename Segment>
228     static inline bool apply(Segment const&)
229     {
230         return true;
231     }
232 };
233
234 template <typename T, std::size_t Dimension, std::size_t DimensionCount>
235 struct assign_loop
236 {
237     static inline void apply(T dims[DimensionCount], int const value)
238     {
239         dims[Dimension] = value;
240         assign_loop<T, Dimension + 1, DimensionCount>::apply(dims, value);
241     }
242 };
243
244 template <typename T, std::size_t DimensionCount>
245 struct assign_loop<T, DimensionCount, DimensionCount>
246 {
247     static inline void apply(T [DimensionCount], int const)
248     {
249     }
250 };
251
252 /// @brief Helper class to create sections of a part of a range, on the fly
253 template
254 <
255     typename Point,
256     std::size_t DimensionCount
257 >
258 struct sectionalize_part
259 {
260     template
261     <
262         typename Range,  // Can be closeable_view
263         typename RobustPolicy,
264         typename Sections
265     >
266     static inline void apply(Sections& sections,
267                              Range const& range,
268                              RobustPolicy const& robust_policy,
269                              bool make_rescaled_boxes,
270                              ring_identifier ring_id,
271                              std::size_t max_count)
272     {
273         boost::ignore_unused_variable_warning(robust_policy);
274         boost::ignore_unused_variable_warning(make_rescaled_boxes);
275
276         typedef model::referring_segment<Point const> segment_type;
277         typedef typename boost::range_value<Sections>::type section_type;
278         typedef model::segment
279             <
280                 typename robust_point_type<Point, RobustPolicy>::type
281             > robust_segment_type;
282         typedef typename boost::range_iterator<Range const>::type iterator_type;
283
284         if ( boost::empty(range) )
285         {
286             return;
287         }
288
289         int index = 0;
290         int ndi = 0; // non duplicate index
291         section_type section;
292
293         bool mark_first_non_duplicated = true;
294         std::size_t last_non_duplicate_index = sections.size();
295
296         iterator_type it = boost::begin(range);
297         
298         for(iterator_type previous = it++;
299             it != boost::end(range);
300             ++previous, ++it, index++)
301         {
302             segment_type segment(*previous, *it);
303             robust_segment_type robust_segment;
304             geometry::recalculate(robust_segment, segment, robust_policy);
305
306             int direction_classes[DimensionCount] = {0};
307             get_direction_loop
308                 <
309                     0, DimensionCount
310                 >::apply(robust_segment, direction_classes);
311
312             // if "dir" == 0 for all point-dimensions, it is duplicate.
313             // Those sections might be omitted, if wished, lateron
314             bool duplicate = false;
315
316             if (direction_classes[0] == 0)
317             {
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
322                     <
323                         0, geometry::dimension<Point>::type::value
324                     >::apply(robust_segment)
325                     )
326                 {
327                     duplicate = true;
328
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
333                     assign_loop
334                     <
335                         int, 0, DimensionCount
336                     >::apply(direction_classes, -99);
337                 }
338             }
339
340             if (section.count > 0
341                 && (!compare_loop
342                         <
343                             int, 0, DimensionCount
344                         >::apply(direction_classes, section.directions)
345                     || section.count > max_count
346                     )
347                 )
348             {
349                 if ( !section.duplicate )
350                 {
351                     last_non_duplicate_index = sections.size();
352                 }
353
354                 sections.push_back(section);
355                 section = section_type();
356             }
357
358             if (section.count == 0)
359             {
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);
365
366                 if ( mark_first_non_duplicated && !duplicate )
367                 {
368                     section.is_non_duplicate_first = true;
369                     mark_first_non_duplicated = false;
370                 }
371
372                 copy_loop
373                     <
374                         int, 0, DimensionCount
375                     >::apply(direction_classes, section.directions);
376
377                 expand_box(*previous, robust_policy, section);
378             }
379
380             expand_box(*it, robust_policy, section);
381             section.end_index = index + 1;
382             section.count++;
383             if (! duplicate)
384             {
385                 ndi++;
386             }
387         }
388
389         // Add last section if applicable
390         if (section.count > 0)
391         {
392             if ( !section.duplicate )
393             {
394                 last_non_duplicate_index = sections.size();
395             }
396
397             sections.push_back(section);
398         }
399
400         if ( last_non_duplicate_index < sections.size()
401           && !sections[last_non_duplicate_index].duplicate )
402         {
403             sections[last_non_duplicate_index].is_non_duplicate_last = true;
404         }
405     }
406
407     template <typename InputPoint, typename RobustPolicy, typename Section>
408     static inline void expand_box(InputPoint const& point,
409                         RobustPolicy const& robust_policy,
410                         Section& section)
411     {
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);
415     }
416 };
417
418
419 template
420 <
421     closure_selector Closure, bool Reverse,
422     typename Point,
423     std::size_t DimensionCount
424 >
425 struct sectionalize_range
426 {
427     template
428     <
429         typename Range,
430         typename RobustPolicy,
431         typename Sections
432     >
433     static inline void apply(Range const& range,
434                              RobustPolicy const& robust_policy,
435                              bool make_rescaled_boxes,
436                              Sections& sections,
437                              ring_identifier ring_id,
438                              std::size_t max_count)
439     {
440     typedef typename closeable_view<Range const, Closure>::type cview_type;
441     typedef typename reversible_view
442         <
443             cview_type const,
444             Reverse ? iterate_reverse : iterate_forward
445         >::type view_type;
446
447         cview_type cview(range);
448         view_type view(cview);
449
450         std::size_t const n = boost::size(view);
451         if (n == 0)
452         {
453             // Zero points, no section
454             return;
455         }
456
457         if (n == 1)
458         {
459             // Line with one point ==> no sections
460             return;
461         }
462
463         sectionalize_part<Point, DimensionCount>
464                 ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count);
465     }
466 };
467
468 template
469 <
470     bool Reverse,
471     std::size_t DimensionCount
472 >
473 struct sectionalize_polygon
474 {
475     template
476     <
477         typename Polygon,
478         typename RobustPolicy,
479         typename Sections
480     >
481     static inline void apply(Polygon const& poly,
482                 RobustPolicy const& robust_policy,
483                 bool make_rescaled_boxes,
484                 Sections& sections,
485                 ring_identifier ring_id, std::size_t max_count)
486     {
487         typedef typename point_type<Polygon>::type point_type;
488         //typedef typename ring_type<Polygon>::type ring_type;
489         typedef sectionalize_range
490             <
491                 closure<Polygon>::value, Reverse,
492                 point_type, DimensionCount
493             > per_range;
494
495         ring_id.ring_index = -1;
496         per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
497
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)
503         {
504             per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
505         }
506     }
507 };
508
509 template
510 <
511     std::size_t DimensionCount
512 >
513 struct sectionalize_box
514 {
515     template
516     <
517         typename Box,
518         typename RobustPolicy,
519         typename Sections
520     >
521     static inline void apply(Box const& box,
522                 RobustPolicy const& robust_policy,
523                 bool make_rescaled_boxes,
524                 Sections& sections,
525                 ring_identifier const& ring_id, std::size_t max_count)
526     {
527         typedef typename point_type<Box>::type point_type;
528
529         assert_dimension<Box, 2>();
530
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
536
537         // TODO: might be replaced by assign_box_corners_oriented
538         // or just "convert"
539         point_type ll, lr, ul, ur;
540         geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
541
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);
548
549         sectionalize_range
550             <
551                 closed, false,
552                 point_type,
553                 DimensionCount
554             >::apply(points, robust_policy, make_rescaled_boxes, sections,
555                      ring_id, max_count);
556     }
557 };
558
559 template <std::size_t DimensionCount, typename Policy>
560 struct sectionalize_multi
561 {
562     template
563     <
564         typename MultiGeometry,
565         typename RobustPolicy,
566         typename Sections
567     >
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)
572     {
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)
578         {
579             Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count);
580         }
581     }
582 };
583
584 template <typename Sections>
585 inline void set_section_unique_ids(Sections& sections)
586 {
587     // Set ID's.
588     int index = 0;
589     for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
590         it != boost::end(sections);
591         ++it)
592     {
593         it->id = index++;
594     }
595 }
596
597 template <typename Sections>
598 inline void enlarge_sections(Sections& sections)
599 {
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);
607         ++it)
608     {
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);
617     }
618 }
619
620
621 }} // namespace detail::sectionalize
622 #endif // DOXYGEN_NO_DETAIL
623
624
625 #ifndef DOXYGEN_NO_DISPATCH
626 namespace dispatch
627 {
628
629 template
630 <
631     typename Tag,
632     typename Geometry,
633     bool Reverse,
634     std::size_t DimensionCount
635 >
636 struct sectionalize
637 {
638     BOOST_MPL_ASSERT_MSG
639         (
640             false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
641             , (types<Geometry>)
642         );
643 };
644
645 template
646 <
647     typename Box,
648     bool Reverse,
649     std::size_t DimensionCount
650 >
651 struct sectionalize<box_tag, Box, Reverse, DimensionCount>
652     : detail::sectionalize::sectionalize_box<DimensionCount>
653 {};
654
655 template
656 <
657     typename LineString,
658     std::size_t DimensionCount
659 >
660 struct sectionalize
661     <
662         linestring_tag,
663         LineString,
664         false,
665         DimensionCount
666     >
667     : detail::sectionalize::sectionalize_range
668         <
669             closed, false,
670             typename point_type<LineString>::type,
671             DimensionCount
672         >
673 {};
674
675 template
676 <
677     typename Ring,
678     bool Reverse,
679     std::size_t DimensionCount
680 >
681 struct sectionalize<ring_tag, Ring, Reverse, DimensionCount>
682     : detail::sectionalize::sectionalize_range
683         <
684             geometry::closure<Ring>::value, Reverse,
685             typename point_type<Ring>::type,
686             DimensionCount
687         >
688 {};
689
690 template
691 <
692     typename Polygon,
693     bool Reverse,
694     std::size_t DimensionCount
695 >
696 struct sectionalize<polygon_tag, Polygon, Reverse, DimensionCount>
697     : detail::sectionalize::sectionalize_polygon
698         <
699             Reverse, DimensionCount
700         >
701 {};
702
703 template
704 <
705     typename MultiPolygon,
706     bool Reverse,
707     std::size_t DimensionCount
708 >
709 struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionCount>
710     : detail::sectionalize::sectionalize_multi
711         <
712             DimensionCount,
713             detail::sectionalize::sectionalize_polygon
714                 <
715                     Reverse,
716                     DimensionCount
717                 >
718         >
719
720 {};
721
722 template
723 <
724     typename MultiLinestring,
725     bool Reverse,
726     std::size_t DimensionCount
727 >
728 struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionCount>
729     : detail::sectionalize::sectionalize_multi
730         <
731             DimensionCount,
732             detail::sectionalize::sectionalize_range
733                 <
734                     closed, false,
735                     typename point_type<MultiLinestring>::type,
736                     DimensionCount
737                 >
738         >
739
740 {};
741
742 } // namespace dispatch
743 #endif
744
745
746 /*!
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
757  */
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,
762                 Sections& sections,
763                 int source_index = 0)
764 {
765     concept::check<Geometry const>();
766
767     sections.clear();
768
769     ring_identifier ring_id;
770     ring_id.source_index = source_index;
771
772     // A maximum of 10 segments per section seems to give the fastest results
773     dispatch::sectionalize
774         <
775             typename tag<Geometry>::type,
776             Geometry,
777             Reverse,
778             Sections::value
779         >::apply(geometry, robust_policy, enlarge_secion_boxes, sections, ring_id, 10);
780
781     detail::sectionalize::set_section_unique_ids(sections);
782     if (! enlarge_secion_boxes)
783     {
784         detail::sectionalize::enlarge_sections(sections);
785     }
786 }
787
788
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,
793                          Sections& sections,
794                          int source_index = 0)
795 {
796     return geometry::sectionalize<Reverse>(geometry, detail::no_rescale_policy(),
797                                            false, sections,
798                                            source_index);
799 }
800 #endif
801
802
803 }} // namespace boost::geometry
804
805
806 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP