Chris@102
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@102
|
2
|
Chris@102
|
3 // Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@102
|
4 // Copyright (c) 2008-2013 Bruno Lalande, Paris, France.
|
Chris@102
|
5 // Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
|
Chris@102
|
6 // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
|
Chris@102
|
7
|
Chris@102
|
8 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@102
|
9 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@102
|
10 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
11
|
Chris@102
|
12 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
|
Chris@102
|
13 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
|
Chris@102
|
14
|
Chris@102
|
15
|
Chris@102
|
16 #include <cstddef>
|
Chris@102
|
17
|
Chris@102
|
18 #include <boost/range.hpp>
|
Chris@102
|
19
|
Chris@102
|
20 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
|
Chris@102
|
21
|
Chris@102
|
22 #include <boost/geometry/core/cs.hpp>
|
Chris@102
|
23 #include <boost/geometry/core/point_type.hpp>
|
Chris@102
|
24 #include <boost/geometry/core/ring_type.hpp>
|
Chris@102
|
25 #include <boost/geometry/core/tags.hpp>
|
Chris@102
|
26
|
Chris@102
|
27 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@102
|
28 #include <boost/geometry/iterators/ever_circling_iterator.hpp>
|
Chris@102
|
29
|
Chris@102
|
30 #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
|
Chris@102
|
31
|
Chris@102
|
32 #include <boost/geometry/strategies/side.hpp>
|
Chris@102
|
33
|
Chris@102
|
34 #include <boost/geometry/util/math.hpp>
|
Chris@102
|
35
|
Chris@102
|
36
|
Chris@102
|
37 namespace boost { namespace geometry
|
Chris@102
|
38 {
|
Chris@102
|
39
|
Chris@102
|
40
|
Chris@102
|
41 #ifndef DOXYGEN_NO_DETAIL
|
Chris@102
|
42 namespace detail { namespace extreme_points
|
Chris@102
|
43 {
|
Chris@102
|
44
|
Chris@102
|
45 template <std::size_t Dimension>
|
Chris@102
|
46 struct compare
|
Chris@102
|
47 {
|
Chris@102
|
48 template <typename Point>
|
Chris@102
|
49 inline bool operator()(Point const& lhs, Point const& rhs)
|
Chris@102
|
50 {
|
Chris@102
|
51 return geometry::get<Dimension>(lhs) < geometry::get<Dimension>(rhs);
|
Chris@102
|
52 }
|
Chris@102
|
53 };
|
Chris@102
|
54
|
Chris@102
|
55
|
Chris@102
|
56 template <std::size_t Dimension, typename PointType, typename CoordinateType>
|
Chris@102
|
57 inline void move_along_vector(PointType& point, PointType const& extreme, CoordinateType const& base_value)
|
Chris@102
|
58 {
|
Chris@102
|
59 // Moves a point along the vector (point, extreme) in the direction of the extreme point
|
Chris@102
|
60 // This adapts the possibly uneven legs of the triangle (or trapezium-like shape)
|
Chris@102
|
61 // _____extreme _____
|
Chris@102
|
62 // / \ / \ .
|
Chris@102
|
63 // /base \ => / \ point .
|
Chris@102
|
64 // \ point .
|
Chris@102
|
65 //
|
Chris@102
|
66 // For so-called intruders, it can be used to adapt both legs to the level of "base"
|
Chris@102
|
67 // For the base, it can be used to adapt both legs to the level of the max-value of the intruders
|
Chris@102
|
68 // If there are 2 or more extreme values, use the one close to 'point' to have a correct vector
|
Chris@102
|
69
|
Chris@102
|
70 CoordinateType const value = geometry::get<Dimension>(point);
|
Chris@102
|
71 //if (geometry::math::equals(value, base_value))
|
Chris@102
|
72 if (value >= base_value)
|
Chris@102
|
73 {
|
Chris@102
|
74 return;
|
Chris@102
|
75 }
|
Chris@102
|
76
|
Chris@102
|
77 PointType vector = point;
|
Chris@102
|
78 subtract_point(vector, extreme);
|
Chris@102
|
79
|
Chris@102
|
80 CoordinateType const diff = geometry::get<Dimension>(vector);
|
Chris@102
|
81
|
Chris@102
|
82 // diff should never be zero
|
Chris@102
|
83 // because of the way our triangle/trapezium is build.
|
Chris@102
|
84 // We just return if it would be the case.
|
Chris@102
|
85 if (geometry::math::equals(diff, 0))
|
Chris@102
|
86 {
|
Chris@102
|
87 return;
|
Chris@102
|
88 }
|
Chris@102
|
89
|
Chris@102
|
90 CoordinateType const base_diff = base_value - geometry::get<Dimension>(extreme);
|
Chris@102
|
91
|
Chris@102
|
92 multiply_value(vector, base_diff);
|
Chris@102
|
93 divide_value(vector, diff);
|
Chris@102
|
94
|
Chris@102
|
95 // The real move:
|
Chris@102
|
96 point = extreme;
|
Chris@102
|
97 add_point(point, vector);
|
Chris@102
|
98 }
|
Chris@102
|
99
|
Chris@102
|
100
|
Chris@102
|
101 template <std::size_t Dimension, typename Range, typename CoordinateType>
|
Chris@102
|
102 inline void move_along_vector(Range& range, CoordinateType const& base_value)
|
Chris@102
|
103 {
|
Chris@102
|
104 if (range.size() >= 3)
|
Chris@102
|
105 {
|
Chris@102
|
106 move_along_vector<Dimension>(range.front(), *(range.begin() + 1), base_value);
|
Chris@102
|
107 move_along_vector<Dimension>(range.back(), *(range.rbegin() + 1), base_value);
|
Chris@102
|
108 }
|
Chris@102
|
109 }
|
Chris@102
|
110
|
Chris@102
|
111
|
Chris@102
|
112 template<typename Ring, std::size_t Dimension>
|
Chris@102
|
113 struct extreme_points_on_ring
|
Chris@102
|
114 {
|
Chris@102
|
115
|
Chris@102
|
116 typedef typename geometry::coordinate_type<Ring>::type coordinate_type;
|
Chris@102
|
117 typedef typename boost::range_iterator<Ring const>::type range_iterator;
|
Chris@102
|
118 typedef typename geometry::point_type<Ring>::type point_type;
|
Chris@102
|
119
|
Chris@102
|
120 typedef typename geometry::strategy::side::services::default_strategy
|
Chris@102
|
121 <
|
Chris@102
|
122 typename geometry::cs_tag<point_type>::type
|
Chris@102
|
123 >::type side_strategy;
|
Chris@102
|
124
|
Chris@102
|
125
|
Chris@102
|
126 template <typename CirclingIterator, typename Points>
|
Chris@102
|
127 static inline bool extend(CirclingIterator& it,
|
Chris@102
|
128 std::size_t n,
|
Chris@102
|
129 coordinate_type max_coordinate_value,
|
Chris@102
|
130 Points& points, int direction)
|
Chris@102
|
131 {
|
Chris@102
|
132 std::size_t safe_index = 0;
|
Chris@102
|
133 do
|
Chris@102
|
134 {
|
Chris@102
|
135 it += direction;
|
Chris@102
|
136
|
Chris@102
|
137 points.push_back(*it);
|
Chris@102
|
138
|
Chris@102
|
139 if (safe_index++ >= n)
|
Chris@102
|
140 {
|
Chris@102
|
141 // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
|
Chris@102
|
142 return false;
|
Chris@102
|
143 }
|
Chris@102
|
144 } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
|
Chris@102
|
145
|
Chris@102
|
146 return true;
|
Chris@102
|
147 }
|
Chris@102
|
148
|
Chris@102
|
149 // Overload without adding to poinst
|
Chris@102
|
150 template <typename CirclingIterator>
|
Chris@102
|
151 static inline bool extend(CirclingIterator& it,
|
Chris@102
|
152 std::size_t n,
|
Chris@102
|
153 coordinate_type max_coordinate_value,
|
Chris@102
|
154 int direction)
|
Chris@102
|
155 {
|
Chris@102
|
156 std::size_t safe_index = 0;
|
Chris@102
|
157 do
|
Chris@102
|
158 {
|
Chris@102
|
159 it += direction;
|
Chris@102
|
160
|
Chris@102
|
161 if (safe_index++ >= n)
|
Chris@102
|
162 {
|
Chris@102
|
163 // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop)
|
Chris@102
|
164 return false;
|
Chris@102
|
165 }
|
Chris@102
|
166 } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value));
|
Chris@102
|
167
|
Chris@102
|
168 return true;
|
Chris@102
|
169 }
|
Chris@102
|
170
|
Chris@102
|
171 template <typename CirclingIterator>
|
Chris@102
|
172 static inline bool extent_both_sides(Ring const& ring,
|
Chris@102
|
173 point_type extreme,
|
Chris@102
|
174 CirclingIterator& left,
|
Chris@102
|
175 CirclingIterator& right)
|
Chris@102
|
176 {
|
Chris@102
|
177 std::size_t const n = boost::size(ring);
|
Chris@102
|
178 coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
|
Chris@102
|
179
|
Chris@102
|
180 if (! extend(left, n, max_coordinate_value, -1))
|
Chris@102
|
181 {
|
Chris@102
|
182 return false;
|
Chris@102
|
183 }
|
Chris@102
|
184 if (! extend(right, n, max_coordinate_value, +1))
|
Chris@102
|
185 {
|
Chris@102
|
186 return false;
|
Chris@102
|
187 }
|
Chris@102
|
188
|
Chris@102
|
189 return true;
|
Chris@102
|
190 }
|
Chris@102
|
191
|
Chris@102
|
192 template <typename Collection, typename CirclingIterator>
|
Chris@102
|
193 static inline bool collect(Ring const& ring,
|
Chris@102
|
194 point_type extreme,
|
Chris@102
|
195 Collection& points,
|
Chris@102
|
196 CirclingIterator& left,
|
Chris@102
|
197 CirclingIterator& right)
|
Chris@102
|
198 {
|
Chris@102
|
199 std::size_t const n = boost::size(ring);
|
Chris@102
|
200 coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme);
|
Chris@102
|
201
|
Chris@102
|
202 // Collects first left, which is reversed (if more than one point) then adds the top itself, then right
|
Chris@102
|
203 if (! extend(left, n, max_coordinate_value, points, -1))
|
Chris@102
|
204 {
|
Chris@102
|
205 return false;
|
Chris@102
|
206 }
|
Chris@102
|
207 std::reverse(points.begin(), points.end());
|
Chris@102
|
208 points.push_back(extreme);
|
Chris@102
|
209 if (! extend(right, n, max_coordinate_value, points, +1))
|
Chris@102
|
210 {
|
Chris@102
|
211 return false;
|
Chris@102
|
212 }
|
Chris@102
|
213
|
Chris@102
|
214 return true;
|
Chris@102
|
215 }
|
Chris@102
|
216
|
Chris@102
|
217 template <typename Extremes, typename Intruders, typename CirclingIterator>
|
Chris@102
|
218 static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
|
Chris@102
|
219 Extremes const& extremes,
|
Chris@102
|
220 Intruders& intruders)
|
Chris@102
|
221 {
|
Chris@102
|
222 if (boost::size(extremes) < 3)
|
Chris@102
|
223 {
|
Chris@102
|
224 return;
|
Chris@102
|
225 }
|
Chris@102
|
226 coordinate_type const min_value = geometry::get<Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<Dimension>()));
|
Chris@102
|
227
|
Chris@102
|
228 // Also select left/right (if Dimension=1)
|
Chris@102
|
229 coordinate_type const other_min = geometry::get<1 - Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
|
Chris@102
|
230 coordinate_type const other_max = geometry::get<1 - Dimension>(*std::max_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>()));
|
Chris@102
|
231
|
Chris@102
|
232 std::size_t defensive_check_index = 0; // in case we skip over left/right check, collect modifies right too
|
Chris@102
|
233 std::size_t const n = boost::size(ring);
|
Chris@102
|
234 while (left != right && defensive_check_index < n)
|
Chris@102
|
235 {
|
Chris@102
|
236 coordinate_type const coordinate = geometry::get<Dimension>(*right);
|
Chris@102
|
237 coordinate_type const other_coordinate = geometry::get<1 - Dimension>(*right);
|
Chris@102
|
238 if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
|
Chris@102
|
239 {
|
Chris@102
|
240 int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
|
Chris@102
|
241 int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
|
Chris@102
|
242 int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
|
Chris@102
|
243
|
Chris@102
|
244 // If not lying left from any of the extemes side
|
Chris@102
|
245 if (first_side != 1 && last_side != 1)
|
Chris@102
|
246 {
|
Chris@102
|
247 //std::cout << "first " << first_side << " last " << last_side << std::endl;
|
Chris@102
|
248
|
Chris@102
|
249 // we start at this intrusion until it is handled, and don't affect our initial left iterator
|
Chris@102
|
250 CirclingIterator left_intrusion_it = right;
|
Chris@102
|
251 typename boost::range_value<Intruders>::type intruder;
|
Chris@102
|
252 collect(ring, *right, intruder, left_intrusion_it, right);
|
Chris@102
|
253
|
Chris@102
|
254 // Also moves these to base-level, makes sorting possible which can be done in case of self-tangencies
|
Chris@102
|
255 // (we might postpone this action, it is often not necessary. However it is not time-consuming)
|
Chris@102
|
256 move_along_vector<Dimension>(intruder, min_value);
|
Chris@102
|
257 intruders.push_back(intruder);
|
Chris@102
|
258 --right;
|
Chris@102
|
259 }
|
Chris@102
|
260 }
|
Chris@102
|
261 ++right;
|
Chris@102
|
262 defensive_check_index++;
|
Chris@102
|
263 }
|
Chris@102
|
264 }
|
Chris@102
|
265
|
Chris@102
|
266 template <typename Extremes, typename Intruders>
|
Chris@102
|
267 static inline void get_intruders(Ring const& ring,
|
Chris@102
|
268 Extremes const& extremes,
|
Chris@102
|
269 Intruders& intruders)
|
Chris@102
|
270 {
|
Chris@102
|
271 std::size_t const n = boost::size(ring);
|
Chris@102
|
272 if (n >= 3)
|
Chris@102
|
273 {
|
Chris@102
|
274 geometry::ever_circling_range_iterator<Ring const> left(ring);
|
Chris@102
|
275 geometry::ever_circling_range_iterator<Ring const> right(ring);
|
Chris@102
|
276 ++right;
|
Chris@102
|
277
|
Chris@102
|
278 get_intruders(ring, left, right, extremes, intruders);
|
Chris@102
|
279 }
|
Chris@102
|
280 }
|
Chris@102
|
281
|
Chris@102
|
282 template <typename Iterator>
|
Chris@102
|
283 static inline bool right_turn(Ring const& ring, Iterator it)
|
Chris@102
|
284 {
|
Chris@102
|
285 typename std::iterator_traits<Iterator>::difference_type const index
|
Chris@102
|
286 = std::distance(boost::begin(ring), it);
|
Chris@102
|
287 geometry::ever_circling_range_iterator<Ring const> left(ring);
|
Chris@102
|
288 geometry::ever_circling_range_iterator<Ring const> right(ring);
|
Chris@102
|
289 left += index;
|
Chris@102
|
290 right += index;
|
Chris@102
|
291
|
Chris@102
|
292 if (! extent_both_sides(ring, *it, left, right))
|
Chris@102
|
293 {
|
Chris@102
|
294 return false;
|
Chris@102
|
295 }
|
Chris@102
|
296
|
Chris@102
|
297 int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
|
Chris@102
|
298 int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor;
|
Chris@102
|
299 int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor;
|
Chris@102
|
300
|
Chris@102
|
301 //std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
|
Chris@102
|
302
|
Chris@102
|
303 // Turn should not be left (actually, it should be right because extent removes horizontal/collinear cases)
|
Chris@102
|
304 return first_side != 1 && last_side != 1;
|
Chris@102
|
305 }
|
Chris@102
|
306
|
Chris@102
|
307
|
Chris@102
|
308 // Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring
|
Chris@102
|
309 template <typename Extremes, typename Intruders>
|
Chris@102
|
310 static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders)
|
Chris@102
|
311 {
|
Chris@102
|
312 std::size_t const n = boost::size(ring);
|
Chris@102
|
313 if (n < 3)
|
Chris@102
|
314 {
|
Chris@102
|
315 return false;
|
Chris@102
|
316 }
|
Chris@102
|
317
|
Chris@102
|
318 // Get all maxima, usually one. In case of self-tangencies, or self-crossings,
|
Chris@102
|
319 // the max might be is not valid. A valid max should make a right turn
|
Chris@102
|
320 range_iterator max_it = boost::begin(ring);
|
Chris@102
|
321 compare<Dimension> smaller;
|
Chris@102
|
322 for (range_iterator it = max_it + 1; it != boost::end(ring); ++it)
|
Chris@102
|
323 {
|
Chris@102
|
324 if (smaller(*max_it, *it) && right_turn(ring, it))
|
Chris@102
|
325 {
|
Chris@102
|
326 max_it = it;
|
Chris@102
|
327 }
|
Chris@102
|
328 }
|
Chris@102
|
329
|
Chris@102
|
330 if (max_it == boost::end(ring))
|
Chris@102
|
331 {
|
Chris@102
|
332 return false;
|
Chris@102
|
333 }
|
Chris@102
|
334
|
Chris@102
|
335 typename std::iterator_traits<range_iterator>::difference_type const
|
Chris@102
|
336 index = std::distance(boost::begin(ring), max_it);
|
Chris@102
|
337 //std::cout << "Extreme point lies at " << index << " having " << geometry::wkt(*max_it) << std::endl;
|
Chris@102
|
338
|
Chris@102
|
339 geometry::ever_circling_range_iterator<Ring const> left(ring);
|
Chris@102
|
340 geometry::ever_circling_range_iterator<Ring const> right(ring);
|
Chris@102
|
341 left += index;
|
Chris@102
|
342 right += index;
|
Chris@102
|
343
|
Chris@102
|
344 // Collect all points (often 3) in a temporary vector
|
Chris@102
|
345 std::vector<point_type> points;
|
Chris@102
|
346 points.reserve(3);
|
Chris@102
|
347 if (! collect(ring, *max_it, points, left, right))
|
Chris@102
|
348 {
|
Chris@102
|
349 return false;
|
Chris@102
|
350 }
|
Chris@102
|
351
|
Chris@102
|
352 //std::cout << "Built vector of " << points.size() << std::endl;
|
Chris@102
|
353
|
Chris@102
|
354 coordinate_type const front_value = geometry::get<Dimension>(points.front());
|
Chris@102
|
355 coordinate_type const back_value = geometry::get<Dimension>(points.back());
|
Chris@102
|
356 coordinate_type const base_value = (std::max)(front_value, back_value);
|
Chris@102
|
357 if (front_value < back_value)
|
Chris@102
|
358 {
|
Chris@102
|
359 move_along_vector<Dimension>(points.front(), *(points.begin() + 1), base_value);
|
Chris@102
|
360 }
|
Chris@102
|
361 else
|
Chris@102
|
362 {
|
Chris@102
|
363 move_along_vector<Dimension>(points.back(), *(points.rbegin() + 1), base_value);
|
Chris@102
|
364 }
|
Chris@102
|
365
|
Chris@102
|
366 std::copy(points.begin(), points.end(), std::back_inserter(extremes));
|
Chris@102
|
367
|
Chris@102
|
368 get_intruders(ring, left, right, extremes, intruders);
|
Chris@102
|
369
|
Chris@102
|
370 return true;
|
Chris@102
|
371 }
|
Chris@102
|
372 };
|
Chris@102
|
373
|
Chris@102
|
374
|
Chris@102
|
375
|
Chris@102
|
376
|
Chris@102
|
377
|
Chris@102
|
378 }} // namespace detail::extreme_points
|
Chris@102
|
379 #endif // DOXYGEN_NO_DETAIL
|
Chris@102
|
380
|
Chris@102
|
381
|
Chris@102
|
382 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@102
|
383 namespace dispatch
|
Chris@102
|
384 {
|
Chris@102
|
385
|
Chris@102
|
386
|
Chris@102
|
387 template
|
Chris@102
|
388 <
|
Chris@102
|
389 typename Geometry,
|
Chris@102
|
390 std::size_t Dimension,
|
Chris@102
|
391 typename GeometryTag = typename tag<Geometry>::type
|
Chris@102
|
392 >
|
Chris@102
|
393 struct extreme_points
|
Chris@102
|
394 {};
|
Chris@102
|
395
|
Chris@102
|
396
|
Chris@102
|
397 template<typename Ring, std::size_t Dimension>
|
Chris@102
|
398 struct extreme_points<Ring, Dimension, ring_tag>
|
Chris@102
|
399 : detail::extreme_points::extreme_points_on_ring<Ring, Dimension>
|
Chris@102
|
400 {};
|
Chris@102
|
401
|
Chris@102
|
402
|
Chris@102
|
403 template<typename Polygon, std::size_t Dimension>
|
Chris@102
|
404 struct extreme_points<Polygon, Dimension, polygon_tag>
|
Chris@102
|
405 {
|
Chris@102
|
406 template <typename Extremes, typename Intruders>
|
Chris@102
|
407 static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders)
|
Chris@102
|
408 {
|
Chris@102
|
409 typedef typename geometry::ring_type<Polygon>::type ring_type;
|
Chris@102
|
410 typedef detail::extreme_points::extreme_points_on_ring
|
Chris@102
|
411 <
|
Chris@102
|
412 ring_type, Dimension
|
Chris@102
|
413 > ring_implementation;
|
Chris@102
|
414
|
Chris@102
|
415 if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
|
Chris@102
|
416 {
|
Chris@102
|
417 return false;
|
Chris@102
|
418 }
|
Chris@102
|
419
|
Chris@102
|
420 // For a polygon, its interior rings can contain intruders
|
Chris@102
|
421 typename interior_return_type<Polygon const>::type
|
Chris@102
|
422 rings = interior_rings(polygon);
|
Chris@102
|
423 for (typename detail::interior_iterator<Polygon const>::type
|
Chris@102
|
424 it = boost::begin(rings); it != boost::end(rings); ++it)
|
Chris@102
|
425 {
|
Chris@102
|
426 ring_implementation::get_intruders(*it, extremes, intruders);
|
Chris@102
|
427 }
|
Chris@102
|
428
|
Chris@102
|
429 return true;
|
Chris@102
|
430 }
|
Chris@102
|
431 };
|
Chris@102
|
432
|
Chris@102
|
433 template<typename Box>
|
Chris@102
|
434 struct extreme_points<Box, 1, box_tag>
|
Chris@102
|
435 {
|
Chris@102
|
436 template <typename Extremes, typename Intruders>
|
Chris@102
|
437 static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
|
Chris@102
|
438 {
|
Chris@102
|
439 extremes.resize(4);
|
Chris@102
|
440 geometry::detail::assign_box_corners_oriented<false>(box, extremes);
|
Chris@102
|
441 // ll,ul,ur,lr, contains too exactly the right info
|
Chris@102
|
442 return true;
|
Chris@102
|
443 }
|
Chris@102
|
444 };
|
Chris@102
|
445
|
Chris@102
|
446 template<typename Box>
|
Chris@102
|
447 struct extreme_points<Box, 0, box_tag>
|
Chris@102
|
448 {
|
Chris@102
|
449 template <typename Extremes, typename Intruders>
|
Chris@102
|
450 static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
|
Chris@102
|
451 {
|
Chris@102
|
452 extremes.resize(4);
|
Chris@102
|
453 geometry::detail::assign_box_corners_oriented<false>(box, extremes);
|
Chris@102
|
454 // ll,ul,ur,lr, rotate one to start with UL and end with LL
|
Chris@102
|
455 std::rotate(extremes.begin(), extremes.begin() + 1, extremes.end());
|
Chris@102
|
456 return true;
|
Chris@102
|
457 }
|
Chris@102
|
458 };
|
Chris@102
|
459
|
Chris@102
|
460 template<typename MultiPolygon, std::size_t Dimension>
|
Chris@102
|
461 struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
|
Chris@102
|
462 {
|
Chris@102
|
463 template <typename Extremes, typename Intruders>
|
Chris@102
|
464 static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders)
|
Chris@102
|
465 {
|
Chris@102
|
466 // Get one for the very first polygon, that is (for the moment) enough.
|
Chris@102
|
467 // It is not guaranteed the "extreme" then, but for the current purpose
|
Chris@102
|
468 // (point_on_surface) it can just be this point.
|
Chris@102
|
469 if (boost::size(multi) >= 1)
|
Chris@102
|
470 {
|
Chris@102
|
471 return extreme_points
|
Chris@102
|
472 <
|
Chris@102
|
473 typename boost::range_value<MultiPolygon const>::type,
|
Chris@102
|
474 Dimension,
|
Chris@102
|
475 polygon_tag
|
Chris@102
|
476 >::apply(*boost::begin(multi), extremes, intruders);
|
Chris@102
|
477 }
|
Chris@102
|
478
|
Chris@102
|
479 return false;
|
Chris@102
|
480 }
|
Chris@102
|
481 };
|
Chris@102
|
482
|
Chris@102
|
483 } // namespace dispatch
|
Chris@102
|
484 #endif // DOXYGEN_NO_DISPATCH
|
Chris@102
|
485
|
Chris@102
|
486
|
Chris@102
|
487 /*!
|
Chris@102
|
488 \brief Returns extreme points (for Edge=1 in dimension 1, so the top,
|
Chris@102
|
489 for Edge=0 in dimension 0, the right side)
|
Chris@102
|
490 \note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that.
|
Chris@102
|
491 */
|
Chris@102
|
492 template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders>
|
Chris@102
|
493 inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders)
|
Chris@102
|
494 {
|
Chris@102
|
495 concept::check<Geometry const>();
|
Chris@102
|
496
|
Chris@102
|
497 // Extremes is not required to follow a geometry concept (but it should support an output iterator),
|
Chris@102
|
498 // but its elements should fulfil the point-concept
|
Chris@102
|
499 concept::check<typename boost::range_value<Extremes>::type>();
|
Chris@102
|
500
|
Chris@102
|
501 // Intruders should contain collections which value type is point-concept
|
Chris@102
|
502 // Extremes might be anything (supporting an output iterator), but its elements should fulfil the point-concept
|
Chris@102
|
503 concept::check
|
Chris@102
|
504 <
|
Chris@102
|
505 typename boost::range_value
|
Chris@102
|
506 <
|
Chris@102
|
507 typename boost::range_value<Intruders>::type
|
Chris@102
|
508 >::type
|
Chris@102
|
509 const
|
Chris@102
|
510 >();
|
Chris@102
|
511
|
Chris@102
|
512 return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
|
Chris@102
|
513 }
|
Chris@102
|
514
|
Chris@102
|
515
|
Chris@102
|
516
|
Chris@102
|
517 }} // namespace boost::geometry
|
Chris@102
|
518
|
Chris@102
|
519
|
Chris@102
|
520 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP
|