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