1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2011 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/ring_type.hpp>
18 #include <boost/geometry/core/exterior_ring.hpp>
19 #include <boost/geometry/core/interior_rings.hpp>
20 #include <boost/geometry/algorithms/convert.hpp>
21 #include <boost/geometry/geometries/concepts/check.hpp>
22 #include <boost/geometry/views/closeable_view.hpp>
23 #include <boost/geometry/views/reversible_view.hpp>
24 
25 
26 namespace boost { namespace geometry
27 {
28 
29 
30 #ifndef DOXYGEN_NO_DETAIL
31 namespace detail { namespace copy_segments
32 {
33 
34 
35 template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
36 struct copy_segment_point_range
37 {
38     typedef typename closeable_view
39         <
40             Range const,
41             closure<Range>::value
42         >::type cview_type;
43 
44     typedef typename reversible_view
45         <
46             cview_type const,
47             Reverse ? iterate_reverse : iterate_forward
48         >::type rview_type;
49 
applyboost::geometry::detail::copy_segments::copy_segment_point_range50     static inline bool apply(Range const& range,
51             SegmentIdentifier const& seg_id, bool second,
52             PointOut& point)
53     {
54         int index = seg_id.segment_index;
55         if (second)
56         {
57             index++;
58             if (index >= boost::size(range))
59             {
60                 index = 0;
61             }
62         }
63 
64         // Exception?
65         if (index >= boost::size(range))
66         {
67             return false;
68         }
69 
70         cview_type cview(range);
71         rview_type view(cview);
72 
73 
74         geometry::convert(*(boost::begin(view) + index), point);
75         return true;
76     }
77 };
78 
79 
80 template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
81 struct copy_segment_point_polygon
82 {
applyboost::geometry::detail::copy_segments::copy_segment_point_polygon83     static inline bool apply(Polygon const& polygon,
84             SegmentIdentifier const& seg_id, bool second,
85             PointOut& point)
86     {
87         // Call ring-version with the right ring
88         return copy_segment_point_range
89             <
90                 typename geometry::ring_type<Polygon>::type,
91                 Reverse,
92                 SegmentIdentifier,
93                 PointOut
94             >::apply
95                 (
96                     seg_id.ring_index < 0
97                     ? geometry::exterior_ring(polygon)
98                     : geometry::interior_rings(polygon)[seg_id.ring_index],
99                     seg_id, second,
100                     point
101                 );
102     }
103 };
104 
105 
106 template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
107 struct copy_segment_point_box
108 {
applyboost::geometry::detail::copy_segments::copy_segment_point_box109     static inline bool apply(Box const& box,
110             SegmentIdentifier const& seg_id, bool second,
111             PointOut& point)
112     {
113         int index = seg_id.segment_index;
114         if (second)
115         {
116             index++;
117         }
118 
119         boost::array<typename point_type<Box>::type, 4> bp;
120         assign_box_corners_oriented<Reverse>(box, bp);
121         point = bp[index % 4];
122         return true;
123     }
124 };
125 
126 
127 
128 
129 }} // namespace detail::copy_segments
130 #endif // DOXYGEN_NO_DETAIL
131 
132 
133 #ifndef DOXYGEN_NO_DISPATCH
134 namespace dispatch
135 {
136 
137 
138 template
139 <
140     typename Tag,
141     typename GeometryIn,
142     bool Reverse,
143     typename SegmentIdentifier,
144     typename PointOut
145 >
146 struct copy_segment_point
147 {
148     BOOST_MPL_ASSERT_MSG
149         (
150             false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
151             , (types<GeometryIn>)
152         );
153 };
154 
155 
156 template <typename LineString, bool Reverse, typename SegmentIdentifier, typename PointOut>
157 struct copy_segment_point<linestring_tag, LineString, Reverse, SegmentIdentifier, PointOut>
158     : detail::copy_segments::copy_segment_point_range
159         <
160             LineString, Reverse, SegmentIdentifier, PointOut
161         >
162 {};
163 
164 
165 template <typename Ring, bool Reverse, typename SegmentIdentifier, typename PointOut>
166 struct copy_segment_point<ring_tag, Ring, Reverse, SegmentIdentifier, PointOut>
167     : detail::copy_segments::copy_segment_point_range
168         <
169             Ring, Reverse, SegmentIdentifier, PointOut
170         >
171 {};
172 
173 template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
174 struct copy_segment_point<polygon_tag, Polygon, Reverse, SegmentIdentifier, PointOut>
175     : detail::copy_segments::copy_segment_point_polygon
176         <
177             Polygon, Reverse, SegmentIdentifier, PointOut
178         >
179 {};
180 
181 
182 template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
183 struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
184     : detail::copy_segments::copy_segment_point_box
185         <
186             Box, Reverse, SegmentIdentifier, PointOut
187         >
188 {};
189 
190 
191 
192 } // namespace dispatch
193 #endif // DOXYGEN_NO_DISPATCH
194 
195 
196 
197 
198 
199 /*!
200     \brief Helper function, copies a point from a segment
201     \ingroup overlay
202  */
203 template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
copy_segment_point(Geometry const & geometry,SegmentIdentifier const & seg_id,bool second,PointOut & point_out)204 inline bool copy_segment_point(Geometry const& geometry,
205             SegmentIdentifier const& seg_id, bool second,
206             PointOut& point_out)
207 {
208     concept::check<Geometry const>();
209 
210     return dispatch::copy_segment_point
211         <
212             typename tag<Geometry>::type,
213             Geometry,
214             Reverse,
215             SegmentIdentifier,
216             PointOut
217         >::apply(geometry, seg_id, second, point_out);
218 }
219 
220 
221 /*!
222     \brief Helper function, to avoid the same construct several times,
223         copies a point, based on a source-index and two geometries
224     \ingroup overlay
225  */
226 template
227 <
228     bool Reverse1, bool Reverse2,
229     typename Geometry1, typename Geometry2,
230     typename SegmentIdentifier,
231     typename PointOut
232 >
copy_segment_point(Geometry1 const & geometry1,Geometry2 const & geometry2,SegmentIdentifier const & seg_id,bool second,PointOut & point_out)233 inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
234             SegmentIdentifier const& seg_id, bool second,
235             PointOut& point_out)
236 {
237     concept::check<Geometry1 const>();
238     concept::check<Geometry2 const>();
239 
240     if (seg_id.source_index == 0)
241     {
242         return dispatch::copy_segment_point
243             <
244                 typename tag<Geometry1>::type,
245                 Geometry1,
246                 Reverse1,
247                 SegmentIdentifier,
248                 PointOut
249             >::apply(geometry1, seg_id, second, point_out);
250     }
251     else if (seg_id.source_index == 1)
252     {
253         return dispatch::copy_segment_point
254             <
255                 typename tag<Geometry2>::type,
256                 Geometry2,
257                 Reverse2,
258                 SegmentIdentifier,
259                 PointOut
260             >::apply(geometry2, seg_id, second, point_out);
261     }
262     // Exception?
263     return false;
264 }
265 
266 
267 /*!
268     \brief Helper function, to avoid the same construct several times,
269         copies a point, based on a source-index and two geometries
270     \ingroup overlay
271  */
272 template
273 <
274     bool Reverse1, bool Reverse2,
275     typename Geometry1, typename Geometry2,
276     typename SegmentIdentifier,
277     typename PointOut
278 >
copy_segment_points(Geometry1 const & geometry1,Geometry2 const & geometry2,SegmentIdentifier const & seg_id,PointOut & point1,PointOut & point2)279 inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
280             SegmentIdentifier const& seg_id,
281             PointOut& point1, PointOut& point2)
282 {
283     concept::check<Geometry1 const>();
284     concept::check<Geometry2 const>();
285 
286     return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, false, point1)
287         && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, true,  point2);
288 }
289 
290 
291 
292 
293 }} // namespace boost::geometry
294 
295 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
296