1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
11 
12 
13 #include <boost/array.hpp>
14 #include <boost/mpl/assert.hpp>
15 #include <boost/range.hpp>
16 
17 #include <boost/geometry/core/assert.hpp>
18 #include <boost/geometry/core/ring_type.hpp>
19 #include <boost/geometry/core/exterior_ring.hpp>
20 #include <boost/geometry/core/interior_rings.hpp>
21 #include <boost/geometry/core/tags.hpp>
22 #include <boost/geometry/algorithms/convert.hpp>
23 #include <boost/geometry/algorithms/detail/signed_size_type.hpp>
24 #include <boost/geometry/geometries/concepts/check.hpp>
25 #include <boost/geometry/util/range.hpp>
26 #include <boost/geometry/iterators/ever_circling_iterator.hpp>
27 #include <boost/geometry/views/closeable_view.hpp>
28 #include <boost/geometry/views/reversible_view.hpp>
29 
30 
31 namespace boost { namespace geometry
32 {
33 
34 
35 #ifndef DOXYGEN_NO_DETAIL
36 namespace detail { namespace copy_segments
37 {
38 
39 
40 template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
41 struct copy_segment_point_range
42 {
applyboost::geometry::detail::copy_segments::copy_segment_point_range43     static inline bool apply(Range const& range,
44             SegmentIdentifier const& seg_id, int offset,
45             PointOut& point)
46     {
47         typedef typename closeable_view
48         <
49             Range const,
50             closure<Range>::value
51         >::type cview_type;
52 
53         typedef typename reversible_view
54         <
55             cview_type const,
56             Reverse ? iterate_reverse : iterate_forward
57         >::type rview_type;
58 
59         cview_type cview(range);
60         rview_type view(cview);
61 
62         typedef typename boost::range_iterator<rview_type>::type iterator;
63         geometry::ever_circling_iterator<iterator> it(boost::begin(view), boost::end(view),
64                     boost::begin(view) + seg_id.segment_index, true);
65 
66         for (signed_size_type i = 0; i < offset; ++i, ++it)
67         {
68         }
69 
70         geometry::convert(*it, point);
71         return true;
72     }
73 };
74 
75 
76 template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
77 struct copy_segment_point_polygon
78 {
applyboost::geometry::detail::copy_segments::copy_segment_point_polygon79     static inline bool apply(Polygon const& polygon,
80             SegmentIdentifier const& seg_id, int offset,
81             PointOut& point)
82     {
83         // Call ring-version with the right ring
84         return copy_segment_point_range
85             <
86                 typename geometry::ring_type<Polygon>::type,
87                 Reverse,
88                 SegmentIdentifier,
89                 PointOut
90             >::apply
91                 (
92                     seg_id.ring_index < 0
93                         ? geometry::exterior_ring(polygon)
94                         : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
95                     seg_id, offset,
96                     point
97                 );
98     }
99 };
100 
101 
102 template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
103 struct copy_segment_point_box
104 {
applyboost::geometry::detail::copy_segments::copy_segment_point_box105     static inline bool apply(Box const& box,
106             SegmentIdentifier const& seg_id, int offset,
107             PointOut& point)
108     {
109         signed_size_type index = seg_id.segment_index;
110         for (int i = 0; i < offset; i++)
111         {
112             index++;
113         }
114 
115         boost::array<typename point_type<Box>::type, 4> bp;
116         assign_box_corners_oriented<Reverse>(box, bp);
117         point = bp[index % 4];
118         return true;
119     }
120 };
121 
122 
123 template
124 <
125     typename MultiGeometry,
126     typename SegmentIdentifier,
127     typename PointOut,
128     typename Policy
129 >
130 struct copy_segment_point_multi
131 {
applyboost::geometry::detail::copy_segments::copy_segment_point_multi132     static inline bool apply(MultiGeometry const& multi,
133                              SegmentIdentifier const& seg_id, int offset,
134                              PointOut& point)
135     {
136 
137         BOOST_GEOMETRY_ASSERT
138             (
139                 seg_id.multi_index >= 0
140                 && seg_id.multi_index < int(boost::size(multi))
141             );
142 
143         // Call the single-version
144         return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, offset, point);
145     }
146 };
147 
148 
149 }} // namespace detail::copy_segments
150 #endif // DOXYGEN_NO_DETAIL
151 
152 
153 #ifndef DOXYGEN_NO_DISPATCH
154 namespace dispatch
155 {
156 
157 
158 template
159 <
160     typename Tag,
161     typename GeometryIn,
162     bool Reverse,
163     typename SegmentIdentifier,
164     typename PointOut
165 >
166 struct copy_segment_point
167 {
168     BOOST_MPL_ASSERT_MSG
169         (
170             false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
171             , (types<GeometryIn>)
172         );
173 };
174 
175 
176 template <typename LineString, bool Reverse, typename SegmentIdentifier, typename PointOut>
177 struct copy_segment_point<linestring_tag, LineString, Reverse, SegmentIdentifier, PointOut>
178     : detail::copy_segments::copy_segment_point_range
179         <
180             LineString, Reverse, SegmentIdentifier, PointOut
181         >
182 {};
183 
184 
185 template <typename Ring, bool Reverse, typename SegmentIdentifier, typename PointOut>
186 struct copy_segment_point<ring_tag, Ring, Reverse, SegmentIdentifier, PointOut>
187     : detail::copy_segments::copy_segment_point_range
188         <
189             Ring, Reverse, SegmentIdentifier, PointOut
190         >
191 {};
192 
193 template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
194 struct copy_segment_point<polygon_tag, Polygon, Reverse, SegmentIdentifier, PointOut>
195     : detail::copy_segments::copy_segment_point_polygon
196         <
197             Polygon, Reverse, SegmentIdentifier, PointOut
198         >
199 {};
200 
201 
202 template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
203 struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
204     : detail::copy_segments::copy_segment_point_box
205         <
206             Box, Reverse, SegmentIdentifier, PointOut
207         >
208 {};
209 
210 
211 template
212 <
213     typename MultiGeometry,
214     bool Reverse,
215     typename SegmentIdentifier,
216     typename PointOut
217 >
218 struct copy_segment_point
219     <
220         multi_polygon_tag,
221         MultiGeometry,
222         Reverse,
223         SegmentIdentifier,
224         PointOut
225     >
226     : detail::copy_segments::copy_segment_point_multi
227         <
228             MultiGeometry,
229             SegmentIdentifier,
230             PointOut,
231             detail::copy_segments::copy_segment_point_polygon
232                 <
233                     typename boost::range_value<MultiGeometry>::type,
234                     Reverse,
235                     SegmentIdentifier,
236                     PointOut
237                 >
238         >
239 {};
240 
241 template
242 <
243     typename MultiGeometry,
244     bool Reverse,
245     typename SegmentIdentifier,
246     typename PointOut
247 >
248 struct copy_segment_point
249     <
250         multi_linestring_tag,
251         MultiGeometry,
252         Reverse,
253         SegmentIdentifier,
254         PointOut
255     >
256     : detail::copy_segments::copy_segment_point_multi
257         <
258             MultiGeometry,
259             SegmentIdentifier,
260             PointOut,
261             detail::copy_segments::copy_segment_point_range
262                 <
263                     typename boost::range_value<MultiGeometry>::type,
264                     Reverse,
265                     SegmentIdentifier,
266                     PointOut
267                 >
268         >
269 {};
270 
271 
272 } // namespace dispatch
273 #endif // DOXYGEN_NO_DISPATCH
274 
275 
276 
277 
278 
279 /*!
280     \brief Helper function, copies a point from a segment
281     \ingroup overlay
282  */
283 template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
copy_segment_point(Geometry const & geometry,SegmentIdentifier const & seg_id,int offset,PointOut & point_out)284 inline bool copy_segment_point(Geometry const& geometry,
285             SegmentIdentifier const& seg_id, int offset,
286             PointOut& point_out)
287 {
288     concepts::check<Geometry const>();
289 
290     return dispatch::copy_segment_point
291         <
292             typename tag<Geometry>::type,
293             Geometry,
294             Reverse,
295             SegmentIdentifier,
296             PointOut
297         >::apply(geometry, seg_id, offset, point_out);
298 }
299 
300 
301 /*!
302     \brief Helper function, to avoid the same construct several times,
303         copies a point, based on a source-index and two geometries
304     \ingroup overlay
305  */
306 template
307 <
308     bool Reverse1, bool Reverse2,
309     typename Geometry1, typename Geometry2,
310     typename SegmentIdentifier,
311     typename PointOut
312 >
copy_segment_point(Geometry1 const & geometry1,Geometry2 const & geometry2,SegmentIdentifier const & seg_id,int offset,PointOut & point_out)313 inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
314             SegmentIdentifier const& seg_id, int offset,
315             PointOut& point_out)
316 {
317     concepts::check<Geometry1 const>();
318     concepts::check<Geometry2 const>();
319 
320     BOOST_GEOMETRY_ASSERT(seg_id.source_index == 0 || seg_id.source_index == 1);
321 
322     if (seg_id.source_index == 0)
323     {
324         return dispatch::copy_segment_point
325             <
326                 typename tag<Geometry1>::type,
327                 Geometry1,
328                 Reverse1,
329                 SegmentIdentifier,
330                 PointOut
331             >::apply(geometry1, seg_id, offset, point_out);
332     }
333     else if (seg_id.source_index == 1)
334     {
335         return dispatch::copy_segment_point
336             <
337                 typename tag<Geometry2>::type,
338                 Geometry2,
339                 Reverse2,
340                 SegmentIdentifier,
341                 PointOut
342             >::apply(geometry2, seg_id, offset, point_out);
343     }
344     // Exception?
345     return false;
346 }
347 
348 
349 /*!
350     \brief Helper function, to avoid the same construct several times,
351         copies a point, based on a source-index and two geometries
352     \ingroup overlay
353  */
354 template
355 <
356     bool Reverse1, bool Reverse2,
357     typename Geometry1, typename Geometry2,
358     typename SegmentIdentifier,
359     typename PointOut
360 >
copy_segment_points(Geometry1 const & geometry1,Geometry2 const & geometry2,SegmentIdentifier const & seg_id,PointOut & point1,PointOut & point2)361 inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
362             SegmentIdentifier const& seg_id,
363             PointOut& point1, PointOut& point2)
364 {
365     concepts::check<Geometry1 const>();
366     concepts::check<Geometry2 const>();
367 
368     return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 0, point1)
369         && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 1, point2);
370 }
371 
372 /*!
373     \brief Helper function, copies three points: two from the specified segment
374     (from, to) and the next one
375     \ingroup overlay
376  */
377 template
378 <
379     bool Reverse1, bool Reverse2,
380     typename Geometry1, typename Geometry2,
381     typename SegmentIdentifier,
382     typename PointOut
383 >
copy_segment_points(Geometry1 const & geometry1,Geometry2 const & geometry2,SegmentIdentifier const & seg_id,PointOut & point1,PointOut & point2,PointOut & point3)384 inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
385             SegmentIdentifier const& seg_id,
386             PointOut& point1, PointOut& point2, PointOut& point3)
387 {
388     concepts::check<Geometry1 const>();
389     concepts::check<Geometry2 const>();
390 
391     return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 0, point1)
392         && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 1, point2)
393         && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 2, point3);
394 }
395 
396 
397 
398 }} // namespace boost::geometry
399 
400 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
401