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