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/geometries/concepts/check.hpp>
24 #include <boost/geometry/util/range.hpp>
25 #include <boost/geometry/views/detail/normalized_view.hpp>
26
27
28 namespace boost { namespace geometry
29 {
30
31
32 #ifndef DOXYGEN_NO_DETAIL
33 namespace detail { namespace copy_segments
34 {
35
36
37 template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
38 struct copy_segment_point_range
39 {
applyboost::geometry::detail::copy_segments::copy_segment_point_range40 static inline bool apply(Range const& range,
41 SegmentIdentifier const& seg_id, bool second,
42 PointOut& point)
43 {
44 detail::normalized_view<Range const> view(range);
45
46 signed_size_type const n = boost::size(view);
47 signed_size_type index = seg_id.segment_index;
48 if (second)
49 {
50 index++;
51 if (index >= n)
52 {
53 index = 0;
54 }
55 }
56
57 BOOST_GEOMETRY_ASSERT(index >= 0 && index < n);
58
59 geometry::convert(*(boost::begin(view) + index), point);
60 return true;
61 }
62 };
63
64
65 template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
66 struct copy_segment_point_polygon
67 {
applyboost::geometry::detail::copy_segments::copy_segment_point_polygon68 static inline bool apply(Polygon const& polygon,
69 SegmentIdentifier const& seg_id, bool second,
70 PointOut& point)
71 {
72 // Call ring-version with the right ring
73 return copy_segment_point_range
74 <
75 typename geometry::ring_type<Polygon>::type,
76 Reverse,
77 SegmentIdentifier,
78 PointOut
79 >::apply
80 (
81 seg_id.ring_index < 0
82 ? geometry::exterior_ring(polygon)
83 : range::at(geometry::interior_rings(polygon), seg_id.ring_index),
84 seg_id, second,
85 point
86 );
87 }
88 };
89
90
91 template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
92 struct copy_segment_point_box
93 {
applyboost::geometry::detail::copy_segments::copy_segment_point_box94 static inline bool apply(Box const& box,
95 SegmentIdentifier const& seg_id, bool second,
96 PointOut& point)
97 {
98 signed_size_type index = seg_id.segment_index;
99 if (second)
100 {
101 index++;
102 }
103
104 boost::array<typename point_type<Box>::type, 4> bp;
105 assign_box_corners_oriented<Reverse>(box, bp);
106 point = bp[index % 4];
107 return true;
108 }
109 };
110
111
112 template
113 <
114 typename MultiGeometry,
115 typename SegmentIdentifier,
116 typename PointOut,
117 typename Policy
118 >
119 struct copy_segment_point_multi
120 {
applyboost::geometry::detail::copy_segments::copy_segment_point_multi121 static inline bool apply(MultiGeometry const& multi,
122 SegmentIdentifier const& seg_id, bool second,
123 PointOut& point)
124 {
125
126 BOOST_GEOMETRY_ASSERT
127 (
128 seg_id.multi_index >= 0
129 && seg_id.multi_index < int(boost::size(multi))
130 );
131
132 // Call the single-version
133 return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, second, point);
134 }
135 };
136
137
138 }} // namespace detail::copy_segments
139 #endif // DOXYGEN_NO_DETAIL
140
141
142 #ifndef DOXYGEN_NO_DISPATCH
143 namespace dispatch
144 {
145
146
147 template
148 <
149 typename Tag,
150 typename GeometryIn,
151 bool Reverse,
152 typename SegmentIdentifier,
153 typename PointOut
154 >
155 struct copy_segment_point
156 {
157 BOOST_MPL_ASSERT_MSG
158 (
159 false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
160 , (types<GeometryIn>)
161 );
162 };
163
164
165 template <typename LineString, bool Reverse, typename SegmentIdentifier, typename PointOut>
166 struct copy_segment_point<linestring_tag, LineString, Reverse, SegmentIdentifier, PointOut>
167 : detail::copy_segments::copy_segment_point_range
168 <
169 LineString, Reverse, SegmentIdentifier, PointOut
170 >
171 {};
172
173
174 template <typename Ring, bool Reverse, typename SegmentIdentifier, typename PointOut>
175 struct copy_segment_point<ring_tag, Ring, Reverse, SegmentIdentifier, PointOut>
176 : detail::copy_segments::copy_segment_point_range
177 <
178 Ring, Reverse, SegmentIdentifier, PointOut
179 >
180 {};
181
182 template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
183 struct copy_segment_point<polygon_tag, Polygon, Reverse, SegmentIdentifier, PointOut>
184 : detail::copy_segments::copy_segment_point_polygon
185 <
186 Polygon, Reverse, SegmentIdentifier, PointOut
187 >
188 {};
189
190
191 template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
192 struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
193 : detail::copy_segments::copy_segment_point_box
194 <
195 Box, Reverse, SegmentIdentifier, PointOut
196 >
197 {};
198
199
200 template
201 <
202 typename MultiGeometry,
203 bool Reverse,
204 typename SegmentIdentifier,
205 typename PointOut
206 >
207 struct copy_segment_point
208 <
209 multi_polygon_tag,
210 MultiGeometry,
211 Reverse,
212 SegmentIdentifier,
213 PointOut
214 >
215 : detail::copy_segments::copy_segment_point_multi
216 <
217 MultiGeometry,
218 SegmentIdentifier,
219 PointOut,
220 detail::copy_segments::copy_segment_point_polygon
221 <
222 typename boost::range_value<MultiGeometry>::type,
223 Reverse,
224 SegmentIdentifier,
225 PointOut
226 >
227 >
228 {};
229
230 template
231 <
232 typename MultiGeometry,
233 bool Reverse,
234 typename SegmentIdentifier,
235 typename PointOut
236 >
237 struct copy_segment_point
238 <
239 multi_linestring_tag,
240 MultiGeometry,
241 Reverse,
242 SegmentIdentifier,
243 PointOut
244 >
245 : detail::copy_segments::copy_segment_point_multi
246 <
247 MultiGeometry,
248 SegmentIdentifier,
249 PointOut,
250 detail::copy_segments::copy_segment_point_range
251 <
252 typename boost::range_value<MultiGeometry>::type,
253 Reverse,
254 SegmentIdentifier,
255 PointOut
256 >
257 >
258 {};
259
260
261 } // namespace dispatch
262 #endif // DOXYGEN_NO_DISPATCH
263
264
265
266
267
268 /*!
269 \brief Helper function, copies a point from a segment
270 \ingroup overlay
271 */
272 template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
copy_segment_point(Geometry const & geometry,SegmentIdentifier const & seg_id,bool second,PointOut & point_out)273 inline bool copy_segment_point(Geometry const& geometry,
274 SegmentIdentifier const& seg_id, bool second,
275 PointOut& point_out)
276 {
277 concept::check<Geometry const>();
278
279 return dispatch::copy_segment_point
280 <
281 typename tag<Geometry>::type,
282 Geometry,
283 Reverse,
284 SegmentIdentifier,
285 PointOut
286 >::apply(geometry, seg_id, second, point_out);
287 }
288
289
290 /*!
291 \brief Helper function, to avoid the same construct several times,
292 copies a point, based on a source-index and two geometries
293 \ingroup overlay
294 */
295 template
296 <
297 bool Reverse1, bool Reverse2,
298 typename Geometry1, typename Geometry2,
299 typename SegmentIdentifier,
300 typename PointOut
301 >
copy_segment_point(Geometry1 const & geometry1,Geometry2 const & geometry2,SegmentIdentifier const & seg_id,bool second,PointOut & point_out)302 inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
303 SegmentIdentifier const& seg_id, bool second,
304 PointOut& point_out)
305 {
306 concept::check<Geometry1 const>();
307 concept::check<Geometry2 const>();
308
309 BOOST_GEOMETRY_ASSERT(seg_id.source_index == 0 || seg_id.source_index == 1);
310
311 if (seg_id.source_index == 0)
312 {
313 return dispatch::copy_segment_point
314 <
315 typename tag<Geometry1>::type,
316 Geometry1,
317 Reverse1,
318 SegmentIdentifier,
319 PointOut
320 >::apply(geometry1, seg_id, second, point_out);
321 }
322 else if (seg_id.source_index == 1)
323 {
324 return dispatch::copy_segment_point
325 <
326 typename tag<Geometry2>::type,
327 Geometry2,
328 Reverse2,
329 SegmentIdentifier,
330 PointOut
331 >::apply(geometry2, seg_id, second, point_out);
332 }
333 // Exception?
334 return false;
335 }
336
337
338 /*!
339 \brief Helper function, to avoid the same construct several times,
340 copies a point, based on a source-index and two geometries
341 \ingroup overlay
342 */
343 template
344 <
345 bool Reverse1, bool Reverse2,
346 typename Geometry1, typename Geometry2,
347 typename SegmentIdentifier,
348 typename PointOut
349 >
copy_segment_points(Geometry1 const & geometry1,Geometry2 const & geometry2,SegmentIdentifier const & seg_id,PointOut & point1,PointOut & point2)350 inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
351 SegmentIdentifier const& seg_id,
352 PointOut& point1, PointOut& point2)
353 {
354 concept::check<Geometry1 const>();
355 concept::check<Geometry2 const>();
356
357 return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, false, point1)
358 && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, true, point2);
359 }
360
361
362
363
364 }} // namespace boost::geometry
365
366 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
367