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