]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
3 | // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. | |
4 | ||
5 | // This file was modified by Oracle on 2014. | |
6 | // Modifications copyright (c) 2014 Oracle and/or its affiliates. | |
7 | ||
8 | // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle | |
9 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
10 | ||
11 | // Use, modification and distribution is subject to the Boost Software License, | |
12 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
13 | // http://www.boost.org/LICENSE_1_0.txt) | |
14 | ||
15 | #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP | |
16 | #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP | |
17 | ||
18 | ||
19 | #include <vector> | |
20 | ||
21 | #include <boost/array.hpp> | |
22 | #include <boost/mpl/assert.hpp> | |
23 | #include <boost/range.hpp> | |
24 | #include <boost/type_traits/integral_constant.hpp> | |
25 | ||
26 | #include <boost/geometry/core/assert.hpp> | |
27 | #include <boost/geometry/core/exterior_ring.hpp> | |
28 | #include <boost/geometry/core/interior_rings.hpp> | |
29 | #include <boost/geometry/core/ring_type.hpp> | |
30 | #include <boost/geometry/core/tags.hpp> | |
31 | #include <boost/geometry/algorithms/not_implemented.hpp> | |
32 | #include <boost/geometry/geometries/concepts/check.hpp> | |
33 | #include <boost/geometry/iterators/ever_circling_iterator.hpp> | |
34 | #include <boost/geometry/views/closeable_view.hpp> | |
35 | #include <boost/geometry/views/reversible_view.hpp> | |
36 | ||
37 | #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> | |
38 | #include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp> | |
39 | ||
40 | #include <boost/geometry/util/range.hpp> | |
41 | ||
42 | ||
43 | namespace boost { namespace geometry | |
44 | { | |
45 | ||
46 | ||
47 | #ifndef DOXYGEN_NO_DETAIL | |
48 | namespace detail { namespace copy_segments | |
49 | { | |
50 | ||
51 | ||
52 | template <bool Reverse> | |
53 | struct copy_segments_ring | |
54 | { | |
55 | template | |
56 | < | |
57 | typename Ring, | |
58 | typename SegmentIdentifier, | |
59 | typename RobustPolicy, | |
60 | typename RangeOut | |
61 | > | |
62 | static inline void apply(Ring const& ring, | |
63 | SegmentIdentifier const& seg_id, | |
64 | signed_size_type to_index, | |
65 | RobustPolicy const& robust_policy, | |
66 | RangeOut& current_output) | |
67 | { | |
68 | typedef typename closeable_view | |
69 | < | |
70 | Ring const, | |
71 | closure<Ring>::value | |
72 | >::type cview_type; | |
73 | ||
74 | typedef typename reversible_view | |
75 | < | |
76 | cview_type const, | |
77 | Reverse ? iterate_reverse : iterate_forward | |
78 | >::type rview_type; | |
79 | ||
80 | typedef typename boost::range_iterator<rview_type const>::type iterator; | |
81 | typedef geometry::ever_circling_iterator<iterator> ec_iterator; | |
82 | ||
83 | ||
84 | cview_type cview(ring); | |
85 | rview_type view(cview); | |
86 | ||
87 | // The problem: sometimes we want to from "3" to "2" | |
88 | // -> end = "3" -> end == begin | |
89 | // This is not convenient with iterators. | |
90 | ||
91 | // So we use the ever-circling iterator and determine when to step out | |
92 | ||
93 | signed_size_type const from_index = seg_id.segment_index + 1; | |
94 | ||
95 | // Sanity check | |
96 | BOOST_GEOMETRY_ASSERT(from_index < static_cast<signed_size_type>(boost::size(view))); | |
97 | ||
98 | ec_iterator it(boost::begin(view), boost::end(view), | |
99 | boost::begin(view) + from_index); | |
100 | ||
101 | // [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK | |
102 | // [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK | |
103 | // [1..1], travel the whole ring round | |
104 | signed_size_type const count = from_index <= to_index | |
105 | ? to_index - from_index + 1 | |
106 | : static_cast<signed_size_type>(boost::size(view)) | |
107 | - from_index + to_index + 1; | |
108 | ||
109 | for (signed_size_type i = 0; i < count; ++i, ++it) | |
110 | { | |
111 | detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy); | |
112 | } | |
113 | } | |
114 | }; | |
115 | ||
116 | template <bool Reverse, bool RemoveSpikes = true> | |
117 | class copy_segments_linestring | |
118 | { | |
119 | private: | |
120 | // remove spikes | |
121 | template <typename RangeOut, typename Point, typename RobustPolicy> | |
122 | static inline void append_to_output(RangeOut& current_output, | |
123 | Point const& point, | |
124 | RobustPolicy const& robust_policy, | |
125 | boost::true_type const&) | |
126 | { | |
127 | detail::overlay::append_no_dups_or_spikes(current_output, point, | |
128 | robust_policy); | |
129 | } | |
130 | ||
131 | // keep spikes | |
132 | template <typename RangeOut, typename Point, typename RobustPolicy> | |
133 | static inline void append_to_output(RangeOut& current_output, | |
134 | Point const& point, | |
135 | RobustPolicy const&, | |
136 | boost::false_type const&) | |
137 | { | |
138 | detail::overlay::append_no_duplicates(current_output, point); | |
139 | } | |
140 | ||
141 | public: | |
142 | template | |
143 | < | |
144 | typename LineString, | |
145 | typename SegmentIdentifier, | |
146 | typename RobustPolicy, | |
147 | typename RangeOut | |
148 | > | |
149 | static inline void apply(LineString const& ls, | |
150 | SegmentIdentifier const& seg_id, | |
151 | signed_size_type to_index, | |
152 | RobustPolicy const& robust_policy, | |
153 | RangeOut& current_output) | |
154 | { | |
155 | signed_size_type const from_index = seg_id.segment_index + 1; | |
156 | ||
157 | // Sanity check | |
158 | if ( from_index > to_index | |
159 | || from_index < 0 | |
160 | || to_index >= static_cast<signed_size_type>(boost::size(ls)) ) | |
161 | { | |
162 | return; | |
163 | } | |
164 | ||
165 | signed_size_type const count = to_index - from_index + 1; | |
166 | ||
167 | typename boost::range_iterator<LineString const>::type | |
168 | it = boost::begin(ls) + from_index; | |
169 | ||
170 | for (signed_size_type i = 0; i < count; ++i, ++it) | |
171 | { | |
172 | append_to_output(current_output, *it, robust_policy, | |
173 | boost::integral_constant<bool, RemoveSpikes>()); | |
174 | } | |
175 | } | |
176 | }; | |
177 | ||
178 | template <bool Reverse> | |
179 | struct copy_segments_polygon | |
180 | { | |
181 | template | |
182 | < | |
183 | typename Polygon, | |
184 | typename SegmentIdentifier, | |
185 | typename RobustPolicy, | |
186 | typename RangeOut | |
187 | > | |
188 | static inline void apply(Polygon const& polygon, | |
189 | SegmentIdentifier const& seg_id, | |
190 | signed_size_type to_index, | |
191 | RobustPolicy const& robust_policy, | |
192 | RangeOut& current_output) | |
193 | { | |
194 | // Call ring-version with the right ring | |
195 | copy_segments_ring<Reverse>::apply | |
196 | ( | |
197 | seg_id.ring_index < 0 | |
198 | ? geometry::exterior_ring(polygon) | |
199 | : range::at(geometry::interior_rings(polygon), seg_id.ring_index), | |
200 | seg_id, to_index, | |
201 | robust_policy, | |
202 | current_output | |
203 | ); | |
204 | } | |
205 | }; | |
206 | ||
207 | ||
208 | template <bool Reverse> | |
209 | struct copy_segments_box | |
210 | { | |
211 | template | |
212 | < | |
213 | typename Box, | |
214 | typename SegmentIdentifier, | |
215 | typename RobustPolicy, | |
216 | typename RangeOut | |
217 | > | |
218 | static inline void apply(Box const& box, | |
219 | SegmentIdentifier const& seg_id, | |
220 | signed_size_type to_index, | |
221 | RobustPolicy const& robust_policy, | |
222 | RangeOut& current_output) | |
223 | { | |
224 | signed_size_type index = seg_id.segment_index + 1; | |
225 | BOOST_GEOMETRY_ASSERT(index < 5); | |
226 | ||
227 | signed_size_type const count = index <= to_index | |
228 | ? to_index - index + 1 | |
229 | : 5 - index + to_index + 1; | |
230 | ||
231 | // Create array of points, the fifth one closes it | |
232 | boost::array<typename point_type<Box>::type, 5> bp; | |
233 | assign_box_corners_oriented<Reverse>(box, bp); | |
234 | bp[4] = bp[0]; | |
235 | ||
236 | // (possibly cyclic) copy to output | |
237 | // (see comments in ring-version) | |
238 | for (signed_size_type i = 0; i < count; i++, index++) | |
239 | { | |
240 | detail::overlay::append_no_dups_or_spikes(current_output, | |
241 | bp[index % 5], robust_policy); | |
242 | ||
243 | } | |
244 | } | |
245 | }; | |
246 | ||
247 | ||
248 | template<typename Policy> | |
249 | struct copy_segments_multi | |
250 | { | |
251 | template | |
252 | < | |
253 | typename MultiGeometry, | |
254 | typename SegmentIdentifier, | |
255 | typename RobustPolicy, | |
256 | typename RangeOut | |
257 | > | |
258 | static inline void apply(MultiGeometry const& multi_geometry, | |
259 | SegmentIdentifier const& seg_id, | |
260 | signed_size_type to_index, | |
261 | RobustPolicy const& robust_policy, | |
262 | RangeOut& current_output) | |
263 | { | |
264 | ||
265 | BOOST_GEOMETRY_ASSERT | |
266 | ( | |
267 | seg_id.multi_index >= 0 | |
268 | && static_cast<std::size_t>(seg_id.multi_index) < boost::size(multi_geometry) | |
269 | ); | |
270 | ||
271 | // Call the single-version | |
272 | Policy::apply(range::at(multi_geometry, seg_id.multi_index), | |
273 | seg_id, to_index, | |
274 | robust_policy, | |
275 | current_output); | |
276 | } | |
277 | }; | |
278 | ||
279 | ||
280 | }} // namespace detail::copy_segments | |
281 | #endif // DOXYGEN_NO_DETAIL | |
282 | ||
283 | ||
284 | #ifndef DOXYGEN_NO_DISPATCH | |
285 | namespace dispatch | |
286 | { | |
287 | ||
288 | template | |
289 | < | |
290 | typename Tag, | |
291 | bool Reverse | |
292 | > | |
293 | struct copy_segments : not_implemented<Tag> | |
294 | {}; | |
295 | ||
296 | ||
297 | template <bool Reverse> | |
298 | struct copy_segments<ring_tag, Reverse> | |
299 | : detail::copy_segments::copy_segments_ring<Reverse> | |
300 | {}; | |
301 | ||
302 | ||
303 | template <bool Reverse> | |
304 | struct copy_segments<linestring_tag, Reverse> | |
305 | : detail::copy_segments::copy_segments_linestring<Reverse> | |
306 | {}; | |
307 | ||
308 | template <bool Reverse> | |
309 | struct copy_segments<polygon_tag, Reverse> | |
310 | : detail::copy_segments::copy_segments_polygon<Reverse> | |
311 | {}; | |
312 | ||
313 | ||
314 | template <bool Reverse> | |
315 | struct copy_segments<box_tag, Reverse> | |
316 | : detail::copy_segments::copy_segments_box<Reverse> | |
317 | {}; | |
318 | ||
319 | ||
320 | template<bool Reverse> | |
321 | struct copy_segments<multi_polygon_tag, Reverse> | |
322 | : detail::copy_segments::copy_segments_multi | |
323 | < | |
324 | detail::copy_segments::copy_segments_polygon<Reverse> | |
325 | > | |
326 | {}; | |
327 | ||
328 | ||
329 | } // namespace dispatch | |
330 | #endif // DOXYGEN_NO_DISPATCH | |
331 | ||
332 | ||
333 | /*! | |
334 | \brief Copy segments from a geometry, starting with the specified segment (seg_id) | |
335 | until the specified index (to_index) | |
336 | \ingroup overlay | |
337 | */ | |
338 | template | |
339 | < | |
340 | bool Reverse, | |
341 | typename Geometry, | |
342 | typename SegmentIdentifier, | |
343 | typename RobustPolicy, | |
344 | typename RangeOut | |
345 | > | |
346 | inline void copy_segments(Geometry const& geometry, | |
347 | SegmentIdentifier const& seg_id, | |
348 | signed_size_type to_index, | |
349 | RobustPolicy const& robust_policy, | |
350 | RangeOut& range_out) | |
351 | { | |
352 | concepts::check<Geometry const>(); | |
353 | ||
354 | dispatch::copy_segments | |
355 | < | |
356 | typename tag<Geometry>::type, | |
357 | Reverse | |
358 | >::apply(geometry, seg_id, to_index, robust_policy, range_out); | |
359 | } | |
360 | ||
361 | ||
362 | }} // namespace boost::geometry | |
363 | ||
364 | ||
365 | #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP |