]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
20effc67 | 3 | // Copyright (c) 2014-2020, Oracle and/or its affiliates. |
7c673cae FG |
4 | |
5 | // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle | |
92f5a8d4 | 6 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle |
7c673cae FG |
7 | |
8 | // Licensed under the Boost Software License version 1.0. | |
9 | // http://www.boost.org/users/license.html | |
10 | ||
11 | #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP | |
12 | #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP | |
13 | ||
14 | #include <iterator> | |
15 | ||
20effc67 TL |
16 | #include <boost/range/begin.hpp> |
17 | #include <boost/range/end.hpp> | |
7c673cae FG |
18 | |
19 | #include <boost/geometry/core/point_type.hpp> | |
20 | #include <boost/geometry/core/tag.hpp> | |
21 | #include <boost/geometry/core/tags.hpp> | |
22 | ||
23 | #include <boost/geometry/strategies/distance.hpp> | |
24 | #include <boost/geometry/strategies/tags.hpp> | |
25 | ||
26 | #include <boost/geometry/algorithms/assign.hpp> | |
27 | #include <boost/geometry/algorithms/intersects.hpp> | |
28 | #include <boost/geometry/algorithms/num_points.hpp> | |
29 | ||
30 | #include <boost/geometry/iterators/point_iterator.hpp> | |
31 | #include <boost/geometry/iterators/segment_iterator.hpp> | |
32 | ||
33 | #include <boost/geometry/algorithms/dispatch/distance.hpp> | |
34 | ||
35 | #include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp> | |
36 | #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> | |
37 | ||
38 | #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> | |
39 | ||
40 | #include <boost/geometry/util/condition.hpp> | |
41 | ||
42 | ||
43 | namespace boost { namespace geometry | |
44 | { | |
45 | ||
46 | #ifndef DOXYGEN_NO_DETAIL | |
47 | namespace detail { namespace distance | |
48 | { | |
49 | ||
50 | ||
51 | // closure of segment or box point range | |
52 | template | |
53 | < | |
54 | typename SegmentOrBox, | |
55 | typename Tag = typename tag<SegmentOrBox>::type | |
56 | > | |
57 | struct segment_or_box_point_range_closure | |
58 | : not_implemented<SegmentOrBox> | |
59 | {}; | |
60 | ||
61 | template <typename Segment> | |
62 | struct segment_or_box_point_range_closure<Segment, segment_tag> | |
63 | { | |
64 | static const closure_selector value = closed; | |
65 | }; | |
66 | ||
67 | template <typename Box> | |
68 | struct segment_or_box_point_range_closure<Box, box_tag> | |
69 | { | |
70 | static const closure_selector value = open; | |
71 | }; | |
72 | ||
73 | ||
74 | ||
75 | template | |
76 | < | |
77 | typename Geometry, | |
78 | typename SegmentOrBox, | |
79 | typename Strategy, | |
80 | typename Tag = typename tag<Geometry>::type | |
81 | > | |
82 | class geometry_to_segment_or_box | |
83 | { | |
84 | private: | |
85 | typedef typename point_type<SegmentOrBox>::type segment_or_box_point; | |
86 | ||
87 | typedef typename strategy::distance::services::comparable_type | |
88 | < | |
89 | Strategy | |
90 | >::type comparable_strategy; | |
91 | ||
92 | typedef detail::closest_feature::point_to_point_range | |
93 | < | |
94 | typename point_type<Geometry>::type, | |
95 | std::vector<segment_or_box_point>, | |
96 | segment_or_box_point_range_closure<SegmentOrBox>::value, | |
97 | comparable_strategy | |
98 | > point_to_point_range; | |
99 | ||
100 | typedef detail::closest_feature::geometry_to_range geometry_to_range; | |
101 | ||
102 | typedef typename strategy::distance::services::return_type | |
103 | < | |
104 | comparable_strategy, | |
105 | typename point_type<Geometry>::type, | |
106 | segment_or_box_point | |
107 | >::type comparable_return_type; | |
108 | ||
109 | ||
110 | // assign the new minimum value for an iterator of the point range | |
111 | // of a segment or a box | |
112 | template | |
113 | < | |
114 | typename SegOrBox, | |
115 | typename SegOrBoxTag = typename tag<SegOrBox>::type | |
116 | > | |
117 | struct assign_new_min_iterator | |
118 | : not_implemented<SegOrBox> | |
119 | {}; | |
120 | ||
121 | template <typename Segment> | |
122 | struct assign_new_min_iterator<Segment, segment_tag> | |
123 | { | |
124 | template <typename Iterator> | |
125 | static inline void apply(Iterator&, Iterator) | |
126 | { | |
127 | } | |
128 | }; | |
129 | ||
130 | template <typename Box> | |
131 | struct assign_new_min_iterator<Box, box_tag> | |
132 | { | |
133 | template <typename Iterator> | |
134 | static inline void apply(Iterator& it_min, Iterator it) | |
135 | { | |
136 | it_min = it; | |
137 | } | |
138 | }; | |
139 | ||
140 | ||
141 | // assign the points of a segment or a box to a range | |
142 | template | |
143 | < | |
144 | typename SegOrBox, | |
145 | typename PointRange, | |
146 | typename SegOrBoxTag = typename tag<SegOrBox>::type | |
147 | > | |
148 | struct assign_segment_or_box_points | |
149 | {}; | |
150 | ||
151 | template <typename Segment, typename PointRange> | |
152 | struct assign_segment_or_box_points<Segment, PointRange, segment_tag> | |
153 | { | |
154 | static inline void apply(Segment const& segment, PointRange& range) | |
155 | { | |
156 | detail::assign_point_from_index<0>(segment, range[0]); | |
157 | detail::assign_point_from_index<1>(segment, range[1]); | |
158 | } | |
159 | }; | |
160 | ||
161 | template <typename Box, typename PointRange> | |
162 | struct assign_segment_or_box_points<Box, PointRange, box_tag> | |
163 | { | |
164 | static inline void apply(Box const& box, PointRange& range) | |
165 | { | |
166 | detail::assign_box_corners_oriented<true>(box, range); | |
167 | } | |
168 | }; | |
169 | ||
92f5a8d4 TL |
170 | template |
171 | < | |
172 | typename SegOrBox, | |
173 | typename SegOrBoxTag = typename tag<SegOrBox>::type | |
174 | > | |
175 | struct intersects | |
176 | { | |
177 | static inline bool apply(Geometry const& g1, SegOrBox const& g2, Strategy const&) | |
178 | { | |
179 | return geometry::intersects(g1, g2); | |
180 | } | |
181 | }; | |
182 | ||
183 | template <typename SegOrBox> | |
184 | struct intersects<SegOrBox, segment_tag> | |
185 | { | |
186 | static inline bool apply(Geometry const& g1, SegOrBox const& g2, Strategy const& s) | |
187 | { | |
188 | return geometry::intersects(g1, g2, s.get_relate_segment_segment_strategy()); | |
189 | } | |
190 | }; | |
7c673cae FG |
191 | |
192 | public: | |
193 | typedef typename strategy::distance::services::return_type | |
194 | < | |
195 | Strategy, | |
196 | typename point_type<Geometry>::type, | |
197 | segment_or_box_point | |
198 | >::type return_type; | |
199 | ||
200 | static inline return_type apply(Geometry const& geometry, | |
201 | SegmentOrBox const& segment_or_box, | |
202 | Strategy const& strategy, | |
203 | bool check_intersection = true) | |
204 | { | |
205 | typedef geometry::point_iterator<Geometry const> point_iterator_type; | |
206 | typedef geometry::segment_iterator | |
207 | < | |
208 | Geometry const | |
209 | > segment_iterator_type; | |
210 | ||
211 | typedef typename boost::range_const_iterator | |
212 | < | |
213 | std::vector<segment_or_box_point> | |
214 | >::type seg_or_box_const_iterator; | |
215 | ||
216 | typedef assign_new_min_iterator<SegmentOrBox> assign_new_value; | |
217 | ||
218 | ||
219 | if (check_intersection | |
92f5a8d4 | 220 | && intersects<SegmentOrBox>::apply(geometry, segment_or_box, strategy)) |
7c673cae FG |
221 | { |
222 | return 0; | |
223 | } | |
224 | ||
225 | comparable_strategy cstrategy = | |
226 | strategy::distance::services::get_comparable | |
227 | < | |
228 | Strategy | |
229 | >::apply(strategy); | |
230 | ||
231 | // get all points of the segment or the box | |
232 | std::vector<segment_or_box_point> | |
233 | seg_or_box_points(geometry::num_points(segment_or_box)); | |
234 | ||
235 | assign_segment_or_box_points | |
236 | < | |
237 | SegmentOrBox, | |
238 | std::vector<segment_or_box_point> | |
239 | >::apply(segment_or_box, seg_or_box_points); | |
240 | ||
241 | // consider all distances of the points in the geometry to the | |
242 | // segment or box | |
243 | comparable_return_type cd_min1(0); | |
244 | point_iterator_type pit_min; | |
245 | seg_or_box_const_iterator it_min1 = boost::const_begin(seg_or_box_points); | |
246 | seg_or_box_const_iterator it_min2 = it_min1; | |
247 | ++it_min2; | |
248 | bool first = true; | |
249 | ||
250 | for (point_iterator_type pit = points_begin(geometry); | |
251 | pit != points_end(geometry); ++pit, first = false) | |
252 | { | |
253 | comparable_return_type cd; | |
254 | std::pair | |
255 | < | |
256 | seg_or_box_const_iterator, seg_or_box_const_iterator | |
257 | > it_pair | |
258 | = point_to_point_range::apply(*pit, | |
259 | boost::const_begin(seg_or_box_points), | |
260 | boost::const_end(seg_or_box_points), | |
261 | cstrategy, | |
262 | cd); | |
263 | ||
264 | if (first || cd < cd_min1) | |
265 | { | |
266 | cd_min1 = cd; | |
267 | pit_min = pit; | |
268 | assign_new_value::apply(it_min1, it_pair.first); | |
269 | assign_new_value::apply(it_min2, it_pair.second); | |
270 | } | |
271 | } | |
272 | ||
273 | // consider all distances of the points in the segment or box to the | |
274 | // segments of the geometry | |
275 | comparable_return_type cd_min2(0); | |
276 | segment_iterator_type sit_min; | |
277 | seg_or_box_const_iterator it_min; | |
278 | ||
279 | first = true; | |
280 | for (seg_or_box_const_iterator it = boost::const_begin(seg_or_box_points); | |
281 | it != boost::const_end(seg_or_box_points); ++it, first = false) | |
282 | { | |
283 | comparable_return_type cd; | |
284 | segment_iterator_type sit | |
285 | = geometry_to_range::apply(*it, | |
286 | segments_begin(geometry), | |
287 | segments_end(geometry), | |
288 | cstrategy, | |
289 | cd); | |
290 | ||
291 | if (first || cd < cd_min2) | |
292 | { | |
293 | cd_min2 = cd; | |
294 | it_min = it; | |
295 | sit_min = sit; | |
296 | } | |
297 | } | |
298 | ||
299 | if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) | |
300 | { | |
301 | return (std::min)(cd_min1, cd_min2); | |
302 | } | |
303 | ||
304 | if (cd_min1 < cd_min2) | |
305 | { | |
306 | return strategy.apply(*pit_min, *it_min1, *it_min2); | |
307 | } | |
308 | else | |
309 | { | |
310 | return dispatch::distance | |
311 | < | |
312 | segment_or_box_point, | |
313 | typename std::iterator_traits | |
314 | < | |
315 | segment_iterator_type | |
316 | >::value_type, | |
317 | Strategy | |
318 | >::apply(*it_min, *sit_min, strategy); | |
319 | } | |
320 | } | |
321 | ||
322 | ||
323 | static inline return_type | |
324 | apply(SegmentOrBox const& segment_or_box, Geometry const& geometry, | |
325 | Strategy const& strategy, bool check_intersection = true) | |
326 | { | |
327 | return apply(geometry, segment_or_box, strategy, check_intersection); | |
328 | } | |
329 | }; | |
330 | ||
331 | ||
332 | ||
333 | template <typename MultiPoint, typename SegmentOrBox, typename Strategy> | |
334 | class geometry_to_segment_or_box | |
335 | < | |
336 | MultiPoint, SegmentOrBox, Strategy, multi_point_tag | |
337 | > | |
338 | { | |
339 | private: | |
340 | typedef detail::closest_feature::geometry_to_range base_type; | |
341 | ||
342 | typedef typename boost::range_iterator | |
343 | < | |
344 | MultiPoint const | |
345 | >::type iterator_type; | |
346 | ||
347 | typedef detail::closest_feature::geometry_to_range geometry_to_range; | |
348 | ||
349 | public: | |
350 | typedef typename strategy::distance::services::return_type | |
351 | < | |
352 | Strategy, | |
353 | typename point_type<SegmentOrBox>::type, | |
354 | typename point_type<MultiPoint>::type | |
355 | >::type return_type; | |
356 | ||
357 | static inline return_type apply(MultiPoint const& multipoint, | |
358 | SegmentOrBox const& segment_or_box, | |
359 | Strategy const& strategy) | |
360 | { | |
361 | namespace sds = strategy::distance::services; | |
362 | ||
363 | typename sds::return_type | |
364 | < | |
365 | typename sds::comparable_type<Strategy>::type, | |
366 | typename point_type<SegmentOrBox>::type, | |
367 | typename point_type<MultiPoint>::type | |
368 | >::type cd_min; | |
369 | ||
370 | iterator_type it_min | |
371 | = geometry_to_range::apply(segment_or_box, | |
372 | boost::begin(multipoint), | |
373 | boost::end(multipoint), | |
374 | sds::get_comparable | |
375 | < | |
376 | Strategy | |
377 | >::apply(strategy), | |
378 | cd_min); | |
379 | ||
380 | return | |
381 | is_comparable<Strategy>::value | |
382 | ? | |
383 | cd_min | |
384 | : | |
385 | dispatch::distance | |
386 | < | |
387 | typename point_type<MultiPoint>::type, | |
388 | SegmentOrBox, | |
389 | Strategy | |
390 | >::apply(*it_min, segment_or_box, strategy); | |
391 | } | |
392 | }; | |
393 | ||
394 | ||
395 | ||
396 | }} // namespace detail::distance | |
397 | #endif // DOXYGEN_NO_DETAIL | |
398 | ||
399 | ||
400 | ||
401 | #ifndef DOXYGEN_NO_DISPATCH | |
402 | namespace dispatch | |
403 | { | |
404 | ||
405 | ||
406 | template <typename Linear, typename Segment, typename Strategy> | |
407 | struct distance | |
408 | < | |
409 | Linear, Segment, Strategy, linear_tag, segment_tag, | |
410 | strategy_tag_distance_point_segment, false | |
411 | > : detail::distance::geometry_to_segment_or_box<Linear, Segment, Strategy> | |
412 | {}; | |
413 | ||
414 | ||
415 | template <typename Areal, typename Segment, typename Strategy> | |
416 | struct distance | |
417 | < | |
418 | Areal, Segment, Strategy, areal_tag, segment_tag, | |
419 | strategy_tag_distance_point_segment, false | |
420 | > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> | |
421 | {}; | |
422 | ||
423 | ||
424 | template <typename Segment, typename Areal, typename Strategy> | |
425 | struct distance | |
426 | < | |
427 | Segment, Areal, Strategy, segment_tag, areal_tag, | |
428 | strategy_tag_distance_point_segment, false | |
429 | > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> | |
430 | {}; | |
431 | ||
432 | ||
433 | template <typename Linear, typename Box, typename Strategy> | |
434 | struct distance | |
435 | < | |
436 | Linear, Box, Strategy, linear_tag, box_tag, | |
437 | strategy_tag_distance_point_segment, false | |
438 | > : detail::distance::geometry_to_segment_or_box | |
439 | < | |
440 | Linear, Box, Strategy | |
441 | > | |
442 | {}; | |
443 | ||
444 | ||
445 | template <typename Areal, typename Box, typename Strategy> | |
446 | struct distance | |
447 | < | |
448 | Areal, Box, Strategy, areal_tag, box_tag, | |
449 | strategy_tag_distance_point_segment, false | |
450 | > : detail::distance::geometry_to_segment_or_box<Areal, Box, Strategy> | |
451 | {}; | |
452 | ||
453 | ||
454 | template <typename MultiPoint, typename Segment, typename Strategy> | |
455 | struct distance | |
456 | < | |
457 | MultiPoint, Segment, Strategy, | |
458 | multi_point_tag, segment_tag, | |
459 | strategy_tag_distance_point_segment, false | |
460 | > : detail::distance::geometry_to_segment_or_box | |
461 | < | |
462 | MultiPoint, Segment, Strategy | |
463 | > | |
464 | {}; | |
465 | ||
466 | ||
467 | template <typename MultiPoint, typename Box, typename Strategy> | |
468 | struct distance | |
469 | < | |
470 | MultiPoint, Box, Strategy, | |
471 | multi_point_tag, box_tag, | |
472 | strategy_tag_distance_point_box, false | |
473 | > : detail::distance::geometry_to_segment_or_box | |
474 | < | |
475 | MultiPoint, Box, Strategy | |
476 | > | |
477 | {}; | |
478 | ||
479 | ||
480 | } // namespace dispatch | |
481 | #endif // DOXYGEN_NO_DISPATCH | |
482 | ||
483 | ||
484 | }} // namespace boost::geometry | |
485 | ||
486 | ||
487 | #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP |