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