1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2014-2021, Oracle and/or its affiliates.
4 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
5 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
6 
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
9 
10 #ifndef BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP
11 #define BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP
12 
13 
14 #include <type_traits>
15 
16 #include <boost/range/begin.hpp>
17 #include <boost/range/end.hpp>
18 
19 #include <boost/geometry/core/exterior_ring.hpp>
20 #include <boost/geometry/core/interior_rings.hpp>
21 #include <boost/geometry/core/tags.hpp>
22 
23 #include <boost/geometry/iterators/detail/point_iterator/inner_range_type.hpp>
24 #include <boost/geometry/iterators/detail/segment_iterator/iterator_type.hpp>
25 
26 #include <boost/geometry/iterators/dispatch/segment_iterator.hpp>
27 
28 
29 namespace boost { namespace geometry
30 {
31 
32 
33 #ifndef DOXYGEN_NO_DISPATCH
34 namespace dispatch
35 {
36 
37 
38 // specializations for segments_begin
39 
40 
41 template <typename Linestring>
42 struct segments_begin<Linestring, linestring_tag>
43 {
44     typedef typename detail::segment_iterator::iterator_type
45         <
46             Linestring
47         >::type return_type;
48 
applyboost::geometry::dispatch::segments_begin49     static inline return_type apply(Linestring& linestring)
50     {
51         return return_type(linestring);
52     }
53 };
54 
55 
56 template <typename Ring>
57 struct segments_begin<Ring, ring_tag>
58 {
59     typedef typename detail::segment_iterator::iterator_type
60         <
61             Ring
62         >::type return_type;
63 
applyboost::geometry::dispatch::segments_begin64     static inline return_type apply(Ring& ring)
65     {
66         return return_type(ring);
67     }
68 };
69 
70 
71 template <typename Polygon>
72 struct segments_begin<Polygon, polygon_tag>
73 {
74     typedef typename detail::point_iterator::inner_range_type
75         <
76             Polygon
77         >::type inner_range;
78 
79     typedef typename detail::segment_iterator::iterator_type
80         <
81             Polygon
82         >::type return_type;
83 
applyboost::geometry::dispatch::segments_begin84     static inline return_type apply(Polygon& polygon)
85     {
86         typedef typename return_type::second_iterator_type flatten_iterator;
87 
88         return return_type
89             (segments_begin
90                  <
91                      inner_range
92                  >::apply(geometry::exterior_ring(polygon)),
93              segments_end
94                  <
95                      inner_range
96                  >::apply(geometry::exterior_ring(polygon)),
97              flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
98                               boost::end(geometry::interior_rings(polygon))
99                               ),
100              flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
101                               boost::end(geometry::interior_rings(polygon))
102                               )
103              );
104     }
105 };
106 
107 
108 template <typename MultiLinestring>
109 struct segments_begin<MultiLinestring, multi_linestring_tag>
110 {
111     typedef typename detail::segment_iterator::iterator_type
112         <
113             MultiLinestring
114         >::type return_type;
115 
applyboost::geometry::dispatch::segments_begin116     static inline return_type apply(MultiLinestring& multilinestring)
117     {
118         return return_type(boost::begin(multilinestring),
119                            boost::end(multilinestring));
120     }
121 };
122 
123 
124 template <typename MultiPolygon>
125 struct segments_begin<MultiPolygon, multi_polygon_tag>
126 {
127     typedef typename detail::segment_iterator::iterator_type
128         <
129             MultiPolygon
130         >::type return_type;
131 
applyboost::geometry::dispatch::segments_begin132     static inline return_type apply(MultiPolygon& multipolygon)
133     {
134         return return_type(boost::begin(multipolygon),
135                            boost::end(multipolygon));
136     }
137 };
138 
139 
140 } // namespace dispatch
141 #endif // DOXYGEN_NO_DISPATCH
142 
143 
144 
145 
146 
147 #ifndef DOXYGEN_NO_DISPATCH
148 namespace dispatch
149 {
150 
151 
152 // specializations for segments_end
153 
154 
155 template <typename Linestring>
156 struct segments_end<Linestring, linestring_tag>
157 {
158     typedef typename detail::segment_iterator::iterator_type
159         <
160             Linestring
161         >::type return_type;
162 
applyboost::geometry::dispatch::segments_end163     static inline return_type apply(Linestring& linestring)
164     {
165         return return_type(linestring, true);
166     }
167 };
168 
169 
170 template <typename Ring>
171 struct segments_end<Ring, ring_tag>
172 {
173     typedef typename detail::segment_iterator::iterator_type
174         <
175             Ring
176         >::type return_type;
177 
applyboost::geometry::dispatch::segments_end178     static inline return_type apply(Ring& ring)
179     {
180         return return_type(ring, true);
181     }
182 };
183 
184 
185 template <typename Polygon>
186 struct segments_end<Polygon, polygon_tag>
187 {
188     typedef typename detail::point_iterator::inner_range_type
189         <
190             Polygon
191         >::type inner_range;
192 
193     typedef typename detail::segment_iterator::iterator_type
194         <
195             Polygon
196         >::type return_type;
197 
applyboost::geometry::dispatch::segments_end198     static inline return_type apply(Polygon& polygon)
199     {
200         typedef typename return_type::second_iterator_type flatten_iterator;
201 
202         return return_type
203             (segments_end
204                  <
205                      inner_range
206                  >::apply(geometry::exterior_ring(polygon)),
207              flatten_iterator(boost::begin(geometry::interior_rings(polygon)),
208                               boost::end(geometry::interior_rings(polygon))
209                               ),
210              flatten_iterator( boost::end(geometry::interior_rings(polygon)) )
211              );
212     }
213 };
214 
215 
216 template <typename MultiLinestring>
217 struct segments_end<MultiLinestring, multi_linestring_tag>
218 {
219     typedef typename detail::segment_iterator::iterator_type
220         <
221             MultiLinestring
222         >::type return_type;
223 
applyboost::geometry::dispatch::segments_end224     static inline return_type apply(MultiLinestring& multilinestring)
225     {
226         return return_type(boost::end(multilinestring));
227     }
228 };
229 
230 
231 template <typename MultiPolygon>
232 struct segments_end<MultiPolygon, multi_polygon_tag>
233 {
234     typedef typename detail::segment_iterator::iterator_type
235         <
236             MultiPolygon
237         >::type return_type;
238 
applyboost::geometry::dispatch::segments_end239     static inline return_type apply(MultiPolygon& multipolygon)
240     {
241         return return_type(boost::end(multipolygon));
242     }
243 };
244 
245 
246 } // namespace dispatch
247 #endif // DOXYGEN_NO_DISPATCH
248 
249 
250 // MK:: need to add doc here
251 template <typename Geometry>
252 class segment_iterator
253     : public detail::segment_iterator::iterator_type<Geometry>::type
254 {
255 private:
256     typedef typename detail::segment_iterator::iterator_type
257         <
258             Geometry
259         >::type base;
260 
base_ptr() const261     inline base const* base_ptr() const
262     {
263         return this;
264     }
265 
266     template <typename OtherGeometry> friend class segment_iterator;
267 
268     template <typename G>
269     friend inline segment_iterator<G const> segments_begin(G const&);
270 
271     template <typename G>
272     friend inline segment_iterator<G const> segments_end(G const&);
273 
segment_iterator(base const & base_it)274     inline segment_iterator(base const& base_it) : base(base_it) {}
275 
276 public:
277     // The following typedef is needed for this iterator to be
278     // bidirectional.
279     // Normally we would not have to define this. However, due to the
280     // fact that the value type of the iterator is not a reference,
281     // the iterator_facade framework (used to define the base class of
282     // this iterator) degrades automatically the iterator's category
283     // to input iterator. With the following typedef we recover the
284     // correct iterator category.
285     typedef std::bidirectional_iterator_tag iterator_category;
286 
287     inline segment_iterator() = default;
288 
289     template
290     <
291         typename OtherGeometry,
292         std::enable_if_t
293             <
294                 std::is_convertible
295                     <
296                         typename detail::segment_iterator::iterator_type<OtherGeometry>::type,
297                         typename detail::segment_iterator::iterator_type<Geometry>::type
298                     >::value,
299                 int
300             > = 0
301     >
segment_iterator(segment_iterator<OtherGeometry> const & other)302     inline segment_iterator(segment_iterator<OtherGeometry> const& other)
303         : base(*other.base_ptr())
304     {}
305 
operator ++()306     inline segment_iterator& operator++() // prefix
307     {
308         base::operator++();
309         return *this;
310     }
311 
operator --()312     inline segment_iterator& operator--() // prefix
313     {
314         base::operator--();
315         return *this;
316     }
317 
operator ++(int)318     inline segment_iterator operator++(int) // postfix
319     {
320         segment_iterator copy(*this);
321         base::operator++();
322         return copy;
323     }
324 
operator --(int)325     inline segment_iterator operator--(int) // postfix
326     {
327         segment_iterator copy(*this);
328         base::operator--();
329         return copy;
330     }
331 };
332 
333 
334 // MK:: need to add doc here
335 template <typename Geometry>
336 inline segment_iterator<Geometry const>
segments_begin(Geometry const & geometry)337 segments_begin(Geometry const& geometry)
338 {
339     return dispatch::segments_begin<Geometry const>::apply(geometry);
340 }
341 
342 
343 // MK:: need to add doc here
344 template <typename Geometry>
345 inline segment_iterator<Geometry const>
segments_end(Geometry const & geometry)346 segments_end(Geometry const& geometry)
347 {
348     return dispatch::segments_end<Geometry const>::apply(geometry);
349 }
350 
351 
352 }} // namespace boost::geometry
353 
354 #endif // BOOST_GEOMETRY_ITERATORS_SEGMENT_ITERATOR_HPP
355