Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
Chris@16
|
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
Chris@101
|
6 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
|
Chris@101
|
7
|
Chris@101
|
8 // This file was modified by Oracle on 2013, 2014.
|
Chris@101
|
9 // Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
|
Chris@101
|
10
|
Chris@101
|
11 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
|
Chris@101
|
12 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
|
Chris@16
|
13
|
Chris@16
|
14 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
Chris@16
|
15 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
Chris@16
|
16
|
Chris@16
|
17 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
18 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
19 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
20
|
Chris@16
|
21 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
|
Chris@16
|
22 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
|
Chris@16
|
23
|
Chris@16
|
24 #include <cstddef>
|
Chris@16
|
25 #include <vector>
|
Chris@16
|
26
|
Chris@101
|
27 #include <boost/concept/requires.hpp>
|
Chris@16
|
28 #include <boost/mpl/assert.hpp>
|
Chris@101
|
29 #include <boost/mpl/vector_c.hpp>
|
Chris@16
|
30 #include <boost/range.hpp>
|
Chris@101
|
31 #include <boost/static_assert.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 #include <boost/geometry/algorithms/assign.hpp>
|
Chris@16
|
34 #include <boost/geometry/algorithms/expand.hpp>
|
Chris@16
|
35
|
Chris@101
|
36 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
|
Chris@101
|
37 #include <boost/geometry/algorithms/detail/recalculate.hpp>
|
Chris@16
|
38 #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
|
Chris@16
|
39
|
Chris@16
|
40 #include <boost/geometry/core/access.hpp>
|
Chris@16
|
41 #include <boost/geometry/core/closure.hpp>
|
Chris@16
|
42 #include <boost/geometry/core/exterior_ring.hpp>
|
Chris@16
|
43 #include <boost/geometry/core/point_order.hpp>
|
Chris@101
|
44 #include <boost/geometry/core/tags.hpp>
|
Chris@16
|
45
|
Chris@16
|
46 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@16
|
47 #include <boost/geometry/util/math.hpp>
|
Chris@101
|
48 #include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
|
Chris@101
|
49 #include <boost/geometry/policies/robustness/robust_point_type.hpp>
|
Chris@16
|
50 #include <boost/geometry/views/closeable_view.hpp>
|
Chris@16
|
51 #include <boost/geometry/views/reversible_view.hpp>
|
Chris@16
|
52 #include <boost/geometry/geometries/segment.hpp>
|
Chris@16
|
53
|
Chris@16
|
54 namespace boost { namespace geometry
|
Chris@16
|
55 {
|
Chris@16
|
56
|
Chris@16
|
57
|
Chris@16
|
58 /*!
|
Chris@16
|
59 \brief Structure containing section information
|
Chris@16
|
60 \details Section information consists of a bounding box, direction
|
Chris@16
|
61 information (if it is increasing or decreasing, per dimension),
|
Chris@16
|
62 index information (begin-end, ring, multi) and the number of
|
Chris@16
|
63 segments in this section
|
Chris@16
|
64
|
Chris@16
|
65 \tparam Box box-type
|
Chris@16
|
66 \tparam DimensionCount number of dimensions for this section
|
Chris@16
|
67 \ingroup sectionalize
|
Chris@16
|
68 */
|
Chris@101
|
69 template
|
Chris@101
|
70 <
|
Chris@101
|
71 typename Box,
|
Chris@101
|
72 std::size_t DimensionCount
|
Chris@101
|
73 >
|
Chris@16
|
74 struct section
|
Chris@16
|
75 {
|
Chris@16
|
76 typedef Box box_type;
|
Chris@101
|
77 static std::size_t const dimension_count = DimensionCount;
|
Chris@16
|
78
|
Chris@16
|
79 int directions[DimensionCount];
|
Chris@16
|
80 ring_identifier ring_id;
|
Chris@16
|
81 Box bounding_box;
|
Chris@16
|
82
|
Chris@16
|
83 int begin_index;
|
Chris@16
|
84 int end_index;
|
Chris@16
|
85 std::size_t count;
|
Chris@16
|
86 std::size_t range_count;
|
Chris@16
|
87 bool duplicate;
|
Chris@16
|
88 int non_duplicate_index;
|
Chris@16
|
89
|
Chris@101
|
90 bool is_non_duplicate_first;
|
Chris@101
|
91 bool is_non_duplicate_last;
|
Chris@101
|
92
|
Chris@16
|
93 inline section()
|
Chris@101
|
94 : begin_index(-1)
|
Chris@16
|
95 , end_index(-1)
|
Chris@16
|
96 , count(0)
|
Chris@16
|
97 , range_count(0)
|
Chris@16
|
98 , duplicate(false)
|
Chris@16
|
99 , non_duplicate_index(-1)
|
Chris@101
|
100 , is_non_duplicate_first(false)
|
Chris@101
|
101 , is_non_duplicate_last(false)
|
Chris@16
|
102 {
|
Chris@16
|
103 assign_inverse(bounding_box);
|
Chris@16
|
104 for (std::size_t i = 0; i < DimensionCount; i++)
|
Chris@16
|
105 {
|
Chris@16
|
106 directions[i] = 0;
|
Chris@16
|
107 }
|
Chris@16
|
108 }
|
Chris@16
|
109 };
|
Chris@16
|
110
|
Chris@16
|
111
|
Chris@16
|
112 /*!
|
Chris@16
|
113 \brief Structure containing a collection of sections
|
Chris@16
|
114 \note Derived from a vector, proves to be faster than of deque
|
Chris@16
|
115 \note vector might be templated in the future
|
Chris@16
|
116 \ingroup sectionalize
|
Chris@16
|
117 */
|
Chris@16
|
118 template <typename Box, std::size_t DimensionCount>
|
Chris@16
|
119 struct sections : std::vector<section<Box, DimensionCount> >
|
Chris@16
|
120 {
|
Chris@16
|
121 typedef Box box_type;
|
Chris@16
|
122 static std::size_t const value = DimensionCount;
|
Chris@16
|
123 };
|
Chris@16
|
124
|
Chris@16
|
125
|
Chris@16
|
126 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
127 namespace detail { namespace sectionalize
|
Chris@16
|
128 {
|
Chris@16
|
129
|
Chris@101
|
130 template
|
Chris@101
|
131 <
|
Chris@101
|
132 typename DimensionVector,
|
Chris@101
|
133 std::size_t Index,
|
Chris@101
|
134 std::size_t Count
|
Chris@101
|
135 >
|
Chris@16
|
136 struct get_direction_loop
|
Chris@16
|
137 {
|
Chris@101
|
138 typedef typename boost::mpl::at_c<DimensionVector, Index>::type dimension;
|
Chris@16
|
139
|
Chris@101
|
140 template <typename Segment>
|
Chris@16
|
141 static inline void apply(Segment const& seg,
|
Chris@101
|
142 int directions[Count])
|
Chris@16
|
143 {
|
Chris@101
|
144 typedef typename coordinate_type<Segment>::type coordinate_type;
|
Chris@101
|
145
|
Chris@16
|
146 coordinate_type const diff =
|
Chris@101
|
147 geometry::get<1, dimension::value>(seg)
|
Chris@101
|
148 - geometry::get<0, dimension::value>(seg);
|
Chris@16
|
149
|
Chris@16
|
150 coordinate_type zero = coordinate_type();
|
Chris@101
|
151 directions[Index] = diff > zero ? 1 : diff < zero ? -1 : 0;
|
Chris@16
|
152
|
Chris@16
|
153 get_direction_loop
|
Chris@101
|
154 <
|
Chris@101
|
155 DimensionVector,
|
Chris@101
|
156 Index + 1,
|
Chris@101
|
157 Count
|
Chris@101
|
158 >::apply(seg, directions);
|
Chris@16
|
159 }
|
Chris@16
|
160 };
|
Chris@16
|
161
|
Chris@101
|
162 template <typename DimensionVector, std::size_t Count>
|
Chris@101
|
163 struct get_direction_loop<DimensionVector, Count, Count>
|
Chris@16
|
164 {
|
Chris@101
|
165 template <typename Segment>
|
Chris@101
|
166 static inline void apply(Segment const&, int [Count])
|
Chris@16
|
167 {}
|
Chris@16
|
168 };
|
Chris@16
|
169
|
Chris@101
|
170 //! Copy one static array to another
|
Chris@101
|
171 template <typename T, std::size_t Index, std::size_t Count>
|
Chris@16
|
172 struct copy_loop
|
Chris@16
|
173 {
|
Chris@101
|
174 static inline void apply(T const source[Count], T target[Count])
|
Chris@16
|
175 {
|
Chris@101
|
176 target[Index] = source[Index];
|
Chris@101
|
177 copy_loop<T, Index + 1, Count>::apply(source, target);
|
Chris@16
|
178 }
|
Chris@16
|
179 };
|
Chris@16
|
180
|
Chris@101
|
181 template <typename T, std::size_t Count>
|
Chris@101
|
182 struct copy_loop<T, Count, Count>
|
Chris@16
|
183 {
|
Chris@101
|
184 static inline void apply(T const [Count], T [Count])
|
Chris@16
|
185 {}
|
Chris@16
|
186 };
|
Chris@16
|
187
|
Chris@101
|
188 //! Compare two static arrays
|
Chris@101
|
189 template <typename T, std::size_t Index, std::size_t Count>
|
Chris@16
|
190 struct compare_loop
|
Chris@16
|
191 {
|
Chris@101
|
192 static inline bool apply(T const array1[Count], T const array2[Count])
|
Chris@16
|
193 {
|
Chris@101
|
194 return array1[Index] != array2[Index]
|
Chris@16
|
195 ? false
|
Chris@16
|
196 : compare_loop
|
Chris@16
|
197 <
|
Chris@101
|
198 T, Index + 1, Count
|
Chris@101
|
199 >::apply(array1, array2);
|
Chris@16
|
200 }
|
Chris@16
|
201 };
|
Chris@16
|
202
|
Chris@101
|
203 template <typename T, std::size_t Count>
|
Chris@101
|
204 struct compare_loop<T, Count, Count>
|
Chris@16
|
205 {
|
Chris@101
|
206 static inline bool apply(T const [Count], T const [Count])
|
Chris@16
|
207 {
|
Chris@16
|
208
|
Chris@16
|
209 return true;
|
Chris@16
|
210 }
|
Chris@16
|
211 };
|
Chris@16
|
212
|
Chris@16
|
213
|
Chris@101
|
214 template <std::size_t Dimension, std::size_t DimensionCount>
|
Chris@16
|
215 struct check_duplicate_loop
|
Chris@16
|
216 {
|
Chris@101
|
217 template <typename Segment>
|
Chris@16
|
218 static inline bool apply(Segment const& seg)
|
Chris@16
|
219 {
|
Chris@16
|
220 if (! geometry::math::equals
|
Chris@16
|
221 (
|
Chris@101
|
222 geometry::get<0, Dimension>(seg),
|
Chris@16
|
223 geometry::get<1, Dimension>(seg)
|
Chris@16
|
224 )
|
Chris@16
|
225 )
|
Chris@16
|
226 {
|
Chris@16
|
227 return false;
|
Chris@16
|
228 }
|
Chris@16
|
229
|
Chris@16
|
230 return check_duplicate_loop
|
Chris@101
|
231 <
|
Chris@101
|
232 Dimension + 1, DimensionCount
|
Chris@101
|
233 >::apply(seg);
|
Chris@16
|
234 }
|
Chris@16
|
235 };
|
Chris@16
|
236
|
Chris@101
|
237 template <std::size_t DimensionCount>
|
Chris@101
|
238 struct check_duplicate_loop<DimensionCount, DimensionCount>
|
Chris@16
|
239 {
|
Chris@101
|
240 template <typename Segment>
|
Chris@16
|
241 static inline bool apply(Segment const&)
|
Chris@16
|
242 {
|
Chris@16
|
243 return true;
|
Chris@16
|
244 }
|
Chris@16
|
245 };
|
Chris@16
|
246
|
Chris@101
|
247 //! Assign a value to a static array
|
Chris@101
|
248 template <typename T, std::size_t Index, std::size_t Count>
|
Chris@16
|
249 struct assign_loop
|
Chris@16
|
250 {
|
Chris@101
|
251 static inline void apply(T dims[Count], int const value)
|
Chris@16
|
252 {
|
Chris@101
|
253 dims[Index] = value;
|
Chris@101
|
254 assign_loop<T, Index + 1, Count>::apply(dims, value);
|
Chris@16
|
255 }
|
Chris@16
|
256 };
|
Chris@16
|
257
|
Chris@101
|
258 template <typename T, std::size_t Count>
|
Chris@101
|
259 struct assign_loop<T, Count, Count>
|
Chris@16
|
260 {
|
Chris@101
|
261 static inline void apply(T [Count], int const)
|
Chris@16
|
262 {
|
Chris@16
|
263 }
|
Chris@16
|
264 };
|
Chris@16
|
265
|
Chris@16
|
266 /// @brief Helper class to create sections of a part of a range, on the fly
|
Chris@16
|
267 template
|
Chris@16
|
268 <
|
Chris@16
|
269 typename Point,
|
Chris@101
|
270 typename DimensionVector
|
Chris@16
|
271 >
|
Chris@16
|
272 struct sectionalize_part
|
Chris@16
|
273 {
|
Chris@101
|
274 static const std::size_t dimension_count
|
Chris@101
|
275 = boost::mpl::size<DimensionVector>::value;
|
Chris@16
|
276
|
Chris@101
|
277 template
|
Chris@101
|
278 <
|
Chris@101
|
279 typename Iterator,
|
Chris@101
|
280 typename RobustPolicy,
|
Chris@101
|
281 typename Sections
|
Chris@101
|
282 >
|
Chris@101
|
283 static inline void apply(Sections& sections,
|
Chris@101
|
284 Iterator begin, Iterator end,
|
Chris@101
|
285 RobustPolicy const& robust_policy,
|
Chris@101
|
286 ring_identifier ring_id,
|
Chris@101
|
287 std::size_t max_count)
|
Chris@101
|
288 {
|
Chris@101
|
289 boost::ignore_unused_variable_warning(robust_policy);
|
Chris@16
|
290
|
Chris@101
|
291 typedef typename boost::range_value<Sections>::type section_type;
|
Chris@101
|
292 BOOST_STATIC_ASSERT
|
Chris@101
|
293 (
|
Chris@101
|
294 (static_cast<int>(section_type::dimension_count)
|
Chris@101
|
295 == static_cast<int>(boost::mpl::size<DimensionVector>::value))
|
Chris@101
|
296 );
|
Chris@101
|
297
|
Chris@101
|
298 typedef typename geometry::robust_point_type
|
Chris@101
|
299 <
|
Chris@101
|
300 Point,
|
Chris@101
|
301 RobustPolicy
|
Chris@101
|
302 >::type robust_point_type;
|
Chris@101
|
303
|
Chris@101
|
304 std::size_t const count = std::distance(begin, end);
|
Chris@101
|
305 if (count == 0)
|
Chris@16
|
306 {
|
Chris@16
|
307 return;
|
Chris@16
|
308 }
|
Chris@16
|
309
|
Chris@101
|
310 int index = 0;
|
Chris@101
|
311 int ndi = 0; // non duplicate index
|
Chris@101
|
312 section_type section;
|
Chris@16
|
313
|
Chris@101
|
314 bool mark_first_non_duplicated = true;
|
Chris@101
|
315 std::size_t last_non_duplicate_index = sections.size();
|
Chris@16
|
316
|
Chris@101
|
317 Iterator it = begin;
|
Chris@101
|
318 robust_point_type previous_robust_point;
|
Chris@101
|
319 geometry::recalculate(previous_robust_point, *it, robust_policy);
|
Chris@101
|
320
|
Chris@101
|
321 for(Iterator previous = it++;
|
Chris@101
|
322 it != end;
|
Chris@16
|
323 ++previous, ++it, index++)
|
Chris@16
|
324 {
|
Chris@101
|
325 robust_point_type current_robust_point;
|
Chris@101
|
326 geometry::recalculate(current_robust_point, *it, robust_policy);
|
Chris@101
|
327 model::referring_segment<robust_point_type> robust_segment(
|
Chris@101
|
328 previous_robust_point, current_robust_point);
|
Chris@16
|
329
|
Chris@101
|
330 int direction_classes[dimension_count] = {0};
|
Chris@16
|
331 get_direction_loop
|
Chris@101
|
332 <
|
Chris@101
|
333 DimensionVector, 0, dimension_count
|
Chris@101
|
334 >::apply(robust_segment, direction_classes);
|
Chris@16
|
335
|
Chris@16
|
336 // if "dir" == 0 for all point-dimensions, it is duplicate.
|
Chris@16
|
337 // Those sections might be omitted, if wished, lateron
|
Chris@16
|
338 bool duplicate = false;
|
Chris@16
|
339
|
Chris@16
|
340 if (direction_classes[0] == 0)
|
Chris@16
|
341 {
|
Chris@16
|
342 // Recheck because ALL dimensions should be checked,
|
Chris@16
|
343 // not only first one.
|
Chris@101
|
344 // (dimension_count might be < dimension<P>::value)
|
Chris@16
|
345 if (check_duplicate_loop
|
Chris@16
|
346 <
|
Chris@101
|
347 0, geometry::dimension<Point>::type::value
|
Chris@101
|
348 >::apply(robust_segment)
|
Chris@16
|
349 )
|
Chris@16
|
350 {
|
Chris@16
|
351 duplicate = true;
|
Chris@16
|
352
|
Chris@16
|
353 // Change direction-info to force new section
|
Chris@16
|
354 // Note that wo consecutive duplicate segments will generate
|
Chris@16
|
355 // only one duplicate-section.
|
Chris@16
|
356 // Actual value is not important as long as it is not -1,0,1
|
Chris@16
|
357 assign_loop
|
Chris@16
|
358 <
|
Chris@101
|
359 int, 0, dimension_count
|
Chris@16
|
360 >::apply(direction_classes, -99);
|
Chris@16
|
361 }
|
Chris@16
|
362 }
|
Chris@16
|
363
|
Chris@16
|
364 if (section.count > 0
|
Chris@101
|
365 && (! compare_loop
|
Chris@16
|
366 <
|
Chris@101
|
367 int, 0, dimension_count
|
Chris@16
|
368 >::apply(direction_classes, section.directions)
|
Chris@101
|
369 || section.count > max_count)
|
Chris@16
|
370 )
|
Chris@16
|
371 {
|
Chris@101
|
372 if (! section.duplicate)
|
Chris@101
|
373 {
|
Chris@101
|
374 last_non_duplicate_index = sections.size();
|
Chris@101
|
375 }
|
Chris@101
|
376
|
Chris@16
|
377 sections.push_back(section);
|
Chris@16
|
378 section = section_type();
|
Chris@16
|
379 }
|
Chris@16
|
380
|
Chris@16
|
381 if (section.count == 0)
|
Chris@16
|
382 {
|
Chris@16
|
383 section.begin_index = index;
|
Chris@16
|
384 section.ring_id = ring_id;
|
Chris@16
|
385 section.duplicate = duplicate;
|
Chris@16
|
386 section.non_duplicate_index = ndi;
|
Chris@101
|
387 section.range_count = count;
|
Chris@101
|
388
|
Chris@101
|
389 if (mark_first_non_duplicated && ! duplicate)
|
Chris@101
|
390 {
|
Chris@101
|
391 section.is_non_duplicate_first = true;
|
Chris@101
|
392 mark_first_non_duplicated = false;
|
Chris@101
|
393 }
|
Chris@16
|
394
|
Chris@16
|
395 copy_loop
|
Chris@16
|
396 <
|
Chris@101
|
397 int, 0, dimension_count
|
Chris@16
|
398 >::apply(direction_classes, section.directions);
|
Chris@101
|
399
|
Chris@101
|
400 geometry::expand(section.bounding_box, previous_robust_point);
|
Chris@16
|
401 }
|
Chris@16
|
402
|
Chris@101
|
403 geometry::expand(section.bounding_box, current_robust_point);
|
Chris@16
|
404 section.end_index = index + 1;
|
Chris@16
|
405 section.count++;
|
Chris@16
|
406 if (! duplicate)
|
Chris@16
|
407 {
|
Chris@16
|
408 ndi++;
|
Chris@16
|
409 }
|
Chris@101
|
410 previous_robust_point = current_robust_point;
|
Chris@101
|
411 }
|
Chris@101
|
412
|
Chris@101
|
413 // Add last section if applicable
|
Chris@101
|
414 if (section.count > 0)
|
Chris@101
|
415 {
|
Chris@101
|
416 if (! section.duplicate)
|
Chris@101
|
417 {
|
Chris@101
|
418 last_non_duplicate_index = sections.size();
|
Chris@101
|
419 }
|
Chris@101
|
420
|
Chris@101
|
421 sections.push_back(section);
|
Chris@101
|
422 }
|
Chris@101
|
423
|
Chris@101
|
424 if (last_non_duplicate_index < sections.size()
|
Chris@101
|
425 && ! sections[last_non_duplicate_index].duplicate)
|
Chris@101
|
426 {
|
Chris@101
|
427 sections[last_non_duplicate_index].is_non_duplicate_last = true;
|
Chris@16
|
428 }
|
Chris@16
|
429 }
|
Chris@16
|
430 };
|
Chris@16
|
431
|
Chris@16
|
432
|
Chris@16
|
433 template
|
Chris@16
|
434 <
|
Chris@101
|
435 closure_selector Closure,
|
Chris@101
|
436 bool Reverse,
|
Chris@16
|
437 typename Point,
|
Chris@101
|
438 typename DimensionVector
|
Chris@16
|
439 >
|
Chris@16
|
440 struct sectionalize_range
|
Chris@16
|
441 {
|
Chris@101
|
442 template
|
Chris@101
|
443 <
|
Chris@101
|
444 typename Range,
|
Chris@101
|
445 typename RobustPolicy,
|
Chris@101
|
446 typename Sections
|
Chris@101
|
447 >
|
Chris@101
|
448 static inline void apply(Range const& range,
|
Chris@101
|
449 RobustPolicy const& robust_policy,
|
Chris@101
|
450 Sections& sections,
|
Chris@101
|
451 ring_identifier ring_id,
|
Chris@101
|
452 std::size_t max_count)
|
Chris@101
|
453 {
|
Chris@101
|
454 typedef typename closeable_view<Range const, Closure>::type cview_type;
|
Chris@101
|
455 typedef typename reversible_view
|
Chris@16
|
456 <
|
Chris@16
|
457 cview_type const,
|
Chris@16
|
458 Reverse ? iterate_reverse : iterate_forward
|
Chris@16
|
459 >::type view_type;
|
Chris@16
|
460
|
Chris@16
|
461 cview_type cview(range);
|
Chris@16
|
462 view_type view(cview);
|
Chris@16
|
463
|
Chris@16
|
464 std::size_t const n = boost::size(view);
|
Chris@16
|
465 if (n == 0)
|
Chris@16
|
466 {
|
Chris@16
|
467 // Zero points, no section
|
Chris@16
|
468 return;
|
Chris@16
|
469 }
|
Chris@16
|
470
|
Chris@16
|
471 if (n == 1)
|
Chris@16
|
472 {
|
Chris@16
|
473 // Line with one point ==> no sections
|
Chris@16
|
474 return;
|
Chris@16
|
475 }
|
Chris@16
|
476
|
Chris@101
|
477 sectionalize_part<Point, DimensionVector>::apply(sections,
|
Chris@101
|
478 boost::begin(view), boost::end(view),
|
Chris@101
|
479 robust_policy, ring_id, max_count);
|
Chris@16
|
480 }
|
Chris@16
|
481 };
|
Chris@16
|
482
|
Chris@16
|
483 template
|
Chris@16
|
484 <
|
Chris@16
|
485 bool Reverse,
|
Chris@101
|
486 typename DimensionVector
|
Chris@16
|
487 >
|
Chris@16
|
488 struct sectionalize_polygon
|
Chris@16
|
489 {
|
Chris@101
|
490 template
|
Chris@101
|
491 <
|
Chris@101
|
492 typename Polygon,
|
Chris@101
|
493 typename RobustPolicy,
|
Chris@101
|
494 typename Sections
|
Chris@101
|
495 >
|
Chris@101
|
496 static inline void apply(Polygon const& poly,
|
Chris@101
|
497 RobustPolicy const& robust_policy,
|
Chris@101
|
498 Sections& sections,
|
Chris@101
|
499 ring_identifier ring_id, std::size_t max_count)
|
Chris@16
|
500 {
|
Chris@16
|
501 typedef typename point_type<Polygon>::type point_type;
|
Chris@16
|
502 typedef sectionalize_range
|
Chris@101
|
503 <
|
Chris@101
|
504 closure<Polygon>::value, Reverse,
|
Chris@101
|
505 point_type, DimensionVector
|
Chris@101
|
506 > per_range;
|
Chris@16
|
507
|
Chris@16
|
508 ring_id.ring_index = -1;
|
Chris@101
|
509 per_range::apply(exterior_ring(poly), robust_policy, sections, ring_id, max_count);
|
Chris@16
|
510
|
Chris@16
|
511 ring_id.ring_index++;
|
Chris@101
|
512 typename interior_return_type<Polygon const>::type
|
Chris@101
|
513 rings = interior_rings(poly);
|
Chris@101
|
514 for (typename detail::interior_iterator<Polygon const>::type
|
Chris@101
|
515 it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
|
Chris@16
|
516 {
|
Chris@101
|
517 per_range::apply(*it, robust_policy, sections, ring_id, max_count);
|
Chris@16
|
518 }
|
Chris@16
|
519 }
|
Chris@16
|
520 };
|
Chris@16
|
521
|
Chris@101
|
522 template <typename DimensionVector>
|
Chris@16
|
523 struct sectionalize_box
|
Chris@16
|
524 {
|
Chris@101
|
525 template
|
Chris@101
|
526 <
|
Chris@101
|
527 typename Box,
|
Chris@101
|
528 typename RobustPolicy,
|
Chris@101
|
529 typename Sections
|
Chris@101
|
530 >
|
Chris@101
|
531 static inline void apply(Box const& box,
|
Chris@101
|
532 RobustPolicy const& robust_policy,
|
Chris@101
|
533 Sections& sections,
|
Chris@101
|
534 ring_identifier const& ring_id, std::size_t max_count)
|
Chris@16
|
535 {
|
Chris@16
|
536 typedef typename point_type<Box>::type point_type;
|
Chris@16
|
537
|
Chris@16
|
538 assert_dimension<Box, 2>();
|
Chris@16
|
539
|
Chris@16
|
540 // Add all four sides of the 2D-box as separate section.
|
Chris@16
|
541 // Easiest is to convert it to a polygon.
|
Chris@16
|
542 // However, we don't have the polygon type
|
Chris@16
|
543 // (or polygon would be a helper-type).
|
Chris@16
|
544 // Therefore we mimic a linestring/std::vector of 5 points
|
Chris@16
|
545
|
Chris@101
|
546 // TODO: might be replaced by assign_box_corners_oriented
|
Chris@16
|
547 // or just "convert"
|
Chris@16
|
548 point_type ll, lr, ul, ur;
|
Chris@16
|
549 geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
|
Chris@16
|
550
|
Chris@16
|
551 std::vector<point_type> points;
|
Chris@16
|
552 points.push_back(ll);
|
Chris@16
|
553 points.push_back(ul);
|
Chris@16
|
554 points.push_back(ur);
|
Chris@16
|
555 points.push_back(lr);
|
Chris@16
|
556 points.push_back(ll);
|
Chris@16
|
557
|
Chris@16
|
558 sectionalize_range
|
Chris@101
|
559 <
|
Chris@101
|
560 closed, false,
|
Chris@101
|
561 point_type,
|
Chris@101
|
562 DimensionVector
|
Chris@101
|
563 >::apply(points, robust_policy, sections,
|
Chris@101
|
564 ring_id, max_count);
|
Chris@101
|
565 }
|
Chris@101
|
566 };
|
Chris@101
|
567
|
Chris@101
|
568 template <typename DimensionVector, typename Policy>
|
Chris@101
|
569 struct sectionalize_multi
|
Chris@101
|
570 {
|
Chris@101
|
571 template
|
Chris@101
|
572 <
|
Chris@101
|
573 typename MultiGeometry,
|
Chris@101
|
574 typename RobustPolicy,
|
Chris@101
|
575 typename Sections
|
Chris@101
|
576 >
|
Chris@101
|
577 static inline void apply(MultiGeometry const& multi,
|
Chris@101
|
578 RobustPolicy const& robust_policy,
|
Chris@101
|
579 Sections& sections, ring_identifier ring_id, std::size_t max_count)
|
Chris@101
|
580 {
|
Chris@101
|
581 ring_id.multi_index = 0;
|
Chris@101
|
582 for (typename boost::range_iterator<MultiGeometry const>::type
|
Chris@101
|
583 it = boost::begin(multi);
|
Chris@101
|
584 it != boost::end(multi);
|
Chris@101
|
585 ++it, ++ring_id.multi_index)
|
Chris@101
|
586 {
|
Chris@101
|
587 Policy::apply(*it, robust_policy, sections, ring_id, max_count);
|
Chris@101
|
588 }
|
Chris@16
|
589 }
|
Chris@16
|
590 };
|
Chris@16
|
591
|
Chris@16
|
592 template <typename Sections>
|
Chris@101
|
593 inline void enlarge_sections(Sections& sections)
|
Chris@16
|
594 {
|
Chris@16
|
595 // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border)
|
Chris@16
|
596 // Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1")
|
Chris@16
|
597 // Drawback: not really, range is now completely inside the section. Section is a tiny bit too large,
|
Chris@16
|
598 // which might cause (a small number) of more comparisons
|
Chris@16
|
599 // TODO: make dimension-agnostic
|
Chris@16
|
600 for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
|
Chris@16
|
601 it != boost::end(sections);
|
Chris@16
|
602 ++it)
|
Chris@16
|
603 {
|
Chris@16
|
604 typedef typename boost::range_value<Sections>::type section_type;
|
Chris@16
|
605 typedef typename section_type::box_type box_type;
|
Chris@16
|
606 typedef typename geometry::coordinate_type<box_type>::type coordinate_type;
|
Chris@16
|
607 coordinate_type const reps = math::relaxed_epsilon(10.0);
|
Chris@16
|
608 geometry::set<0, 0>(it->bounding_box, geometry::get<0, 0>(it->bounding_box) - reps);
|
Chris@16
|
609 geometry::set<0, 1>(it->bounding_box, geometry::get<0, 1>(it->bounding_box) - reps);
|
Chris@16
|
610 geometry::set<1, 0>(it->bounding_box, geometry::get<1, 0>(it->bounding_box) + reps);
|
Chris@16
|
611 geometry::set<1, 1>(it->bounding_box, geometry::get<1, 1>(it->bounding_box) + reps);
|
Chris@16
|
612 }
|
Chris@16
|
613 }
|
Chris@16
|
614
|
Chris@16
|
615
|
Chris@16
|
616 }} // namespace detail::sectionalize
|
Chris@16
|
617 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
618
|
Chris@16
|
619
|
Chris@16
|
620 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@16
|
621 namespace dispatch
|
Chris@16
|
622 {
|
Chris@16
|
623
|
Chris@16
|
624 template
|
Chris@16
|
625 <
|
Chris@16
|
626 typename Tag,
|
Chris@16
|
627 typename Geometry,
|
Chris@16
|
628 bool Reverse,
|
Chris@101
|
629 typename DimensionVector
|
Chris@16
|
630 >
|
Chris@16
|
631 struct sectionalize
|
Chris@16
|
632 {
|
Chris@16
|
633 BOOST_MPL_ASSERT_MSG
|
Chris@16
|
634 (
|
Chris@16
|
635 false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
|
Chris@16
|
636 , (types<Geometry>)
|
Chris@16
|
637 );
|
Chris@16
|
638 };
|
Chris@16
|
639
|
Chris@16
|
640 template
|
Chris@16
|
641 <
|
Chris@16
|
642 typename Box,
|
Chris@16
|
643 bool Reverse,
|
Chris@101
|
644 typename DimensionVector
|
Chris@16
|
645 >
|
Chris@101
|
646 struct sectionalize<box_tag, Box, Reverse, DimensionVector>
|
Chris@101
|
647 : detail::sectionalize::sectionalize_box<DimensionVector>
|
Chris@16
|
648 {};
|
Chris@16
|
649
|
Chris@16
|
650 template
|
Chris@16
|
651 <
|
Chris@16
|
652 typename LineString,
|
Chris@101
|
653 typename DimensionVector
|
Chris@16
|
654 >
|
Chris@16
|
655 struct sectionalize
|
Chris@16
|
656 <
|
Chris@16
|
657 linestring_tag,
|
Chris@16
|
658 LineString,
|
Chris@16
|
659 false,
|
Chris@101
|
660 DimensionVector
|
Chris@16
|
661 >
|
Chris@16
|
662 : detail::sectionalize::sectionalize_range
|
Chris@16
|
663 <
|
Chris@101
|
664 closed, false,
|
Chris@16
|
665 typename point_type<LineString>::type,
|
Chris@101
|
666 DimensionVector
|
Chris@16
|
667 >
|
Chris@16
|
668 {};
|
Chris@16
|
669
|
Chris@16
|
670 template
|
Chris@16
|
671 <
|
Chris@16
|
672 typename Ring,
|
Chris@16
|
673 bool Reverse,
|
Chris@101
|
674 typename DimensionVector
|
Chris@16
|
675 >
|
Chris@101
|
676 struct sectionalize<ring_tag, Ring, Reverse, DimensionVector>
|
Chris@16
|
677 : detail::sectionalize::sectionalize_range
|
Chris@16
|
678 <
|
Chris@101
|
679 geometry::closure<Ring>::value, Reverse,
|
Chris@16
|
680 typename point_type<Ring>::type,
|
Chris@101
|
681 DimensionVector
|
Chris@16
|
682 >
|
Chris@16
|
683 {};
|
Chris@16
|
684
|
Chris@16
|
685 template
|
Chris@16
|
686 <
|
Chris@16
|
687 typename Polygon,
|
Chris@16
|
688 bool Reverse,
|
Chris@101
|
689 typename DimensionVector
|
Chris@16
|
690 >
|
Chris@101
|
691 struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector>
|
Chris@16
|
692 : detail::sectionalize::sectionalize_polygon
|
Chris@16
|
693 <
|
Chris@101
|
694 Reverse, DimensionVector
|
Chris@16
|
695 >
|
Chris@16
|
696 {};
|
Chris@16
|
697
|
Chris@101
|
698 template
|
Chris@101
|
699 <
|
Chris@101
|
700 typename MultiPolygon,
|
Chris@101
|
701 bool Reverse,
|
Chris@101
|
702 typename DimensionVector
|
Chris@101
|
703 >
|
Chris@101
|
704 struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector>
|
Chris@101
|
705 : detail::sectionalize::sectionalize_multi
|
Chris@101
|
706 <
|
Chris@101
|
707 DimensionVector,
|
Chris@101
|
708 detail::sectionalize::sectionalize_polygon
|
Chris@101
|
709 <
|
Chris@101
|
710 Reverse,
|
Chris@101
|
711 DimensionVector
|
Chris@101
|
712 >
|
Chris@101
|
713 >
|
Chris@101
|
714
|
Chris@101
|
715 {};
|
Chris@101
|
716
|
Chris@101
|
717 template
|
Chris@101
|
718 <
|
Chris@101
|
719 typename MultiLinestring,
|
Chris@101
|
720 bool Reverse,
|
Chris@101
|
721 typename DimensionVector
|
Chris@101
|
722 >
|
Chris@101
|
723 struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector>
|
Chris@101
|
724 : detail::sectionalize::sectionalize_multi
|
Chris@101
|
725 <
|
Chris@101
|
726 DimensionVector,
|
Chris@101
|
727 detail::sectionalize::sectionalize_range
|
Chris@101
|
728 <
|
Chris@101
|
729 closed, false,
|
Chris@101
|
730 typename point_type<MultiLinestring>::type,
|
Chris@101
|
731 DimensionVector
|
Chris@101
|
732 >
|
Chris@101
|
733 >
|
Chris@101
|
734
|
Chris@101
|
735 {};
|
Chris@101
|
736
|
Chris@16
|
737 } // namespace dispatch
|
Chris@16
|
738 #endif
|
Chris@16
|
739
|
Chris@16
|
740
|
Chris@16
|
741 /*!
|
Chris@16
|
742 \brief Split a geometry into monotonic sections
|
Chris@16
|
743 \ingroup sectionalize
|
Chris@16
|
744 \tparam Geometry type of geometry to check
|
Chris@16
|
745 \tparam Sections type of sections to create
|
Chris@16
|
746 \param geometry geometry to create sections from
|
Chris@101
|
747 \param robust_policy policy to handle robustness issues
|
Chris@16
|
748 \param sections structure with sections
|
Chris@16
|
749 \param source_index index to assign to the ring_identifiers
|
Chris@101
|
750 \param max_count maximal number of points per section
|
Chris@101
|
751 (defaults to 10, this seems to give the fastest results)
|
Chris@101
|
752
|
Chris@16
|
753 */
|
Chris@101
|
754 template
|
Chris@101
|
755 <
|
Chris@101
|
756 bool Reverse,
|
Chris@101
|
757 typename DimensionVector,
|
Chris@101
|
758 typename Geometry,
|
Chris@101
|
759 typename Sections,
|
Chris@101
|
760 typename RobustPolicy
|
Chris@101
|
761 >
|
Chris@101
|
762 inline void sectionalize(Geometry const& geometry,
|
Chris@101
|
763 RobustPolicy const& robust_policy,
|
Chris@101
|
764 Sections& sections,
|
Chris@101
|
765 int source_index = 0,
|
Chris@101
|
766 std::size_t max_count = 10)
|
Chris@16
|
767 {
|
Chris@16
|
768 concept::check<Geometry const>();
|
Chris@16
|
769
|
Chris@101
|
770 typedef typename boost::range_value<Sections>::type section_type;
|
Chris@101
|
771
|
Chris@101
|
772 // Compiletime check for point type of section boxes
|
Chris@101
|
773 // and point type related to robust policy
|
Chris@101
|
774 typedef typename geometry::coordinate_type
|
Chris@101
|
775 <
|
Chris@101
|
776 typename section_type::box_type
|
Chris@101
|
777 >::type ctype1;
|
Chris@101
|
778 typedef typename geometry::coordinate_type
|
Chris@101
|
779 <
|
Chris@101
|
780 typename geometry::robust_point_type
|
Chris@101
|
781 <
|
Chris@101
|
782 typename geometry::point_type<Geometry>::type,
|
Chris@101
|
783 RobustPolicy
|
Chris@101
|
784 >::type
|
Chris@101
|
785 >::type ctype2;
|
Chris@101
|
786
|
Chris@101
|
787 BOOST_MPL_ASSERT((boost::is_same<ctype1, ctype2>));
|
Chris@101
|
788
|
Chris@101
|
789
|
Chris@101
|
790 sections.clear();
|
Chris@101
|
791
|
Chris@101
|
792 ring_identifier ring_id;
|
Chris@101
|
793 ring_id.source_index = source_index;
|
Chris@101
|
794
|
Chris@101
|
795 dispatch::sectionalize
|
Chris@16
|
796 <
|
Chris@16
|
797 typename tag<Geometry>::type,
|
Chris@16
|
798 Geometry,
|
Chris@16
|
799 Reverse,
|
Chris@101
|
800 DimensionVector
|
Chris@101
|
801 >::apply(geometry, robust_policy, sections, ring_id, max_count);
|
Chris@16
|
802 }
|
Chris@16
|
803
|
Chris@16
|
804
|
Chris@16
|
805 }} // namespace boost::geometry
|
Chris@16
|
806
|
Chris@16
|
807
|
Chris@16
|
808 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
|