]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
1e59de90 | 3 | // Copyright (c) 2014-2021 Oracle and/or its affiliates. |
7c673cae | 4 | |
92f5a8d4 | 5 | // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle |
7c673cae | 6 | // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle |
92f5a8d4 | 7 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle |
7c673cae FG |
8 | |
9 | // Licensed under the Boost Software License version 1.0. | |
10 | // http://www.boost.org/users/license.html | |
11 | ||
12 | #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP | |
13 | #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP | |
14 | ||
15 | #include <cstddef> | |
7c673cae | 16 | #include <functional> |
20effc67 | 17 | #include <type_traits> |
7c673cae FG |
18 | #include <vector> |
19 | ||
20 | #include <boost/core/ignore_unused.hpp> | |
7c673cae | 21 | #include <boost/numeric/conversion/cast.hpp> |
7c673cae | 22 | |
7c673cae FG |
23 | #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> |
24 | #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> | |
92f5a8d4 TL |
25 | #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> |
26 | #include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> | |
7c673cae | 27 | #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> |
1e59de90 TL |
28 | #include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp> |
29 | #include <boost/geometry/algorithms/detail/dummy_geometries.hpp> | |
92f5a8d4 | 30 | #include <boost/geometry/algorithms/detail/equals/point_point.hpp> |
7c673cae | 31 | #include <boost/geometry/algorithms/dispatch/distance.hpp> |
92f5a8d4 | 32 | #include <boost/geometry/algorithms/not_implemented.hpp> |
7c673cae | 33 | |
1e59de90 TL |
34 | #include <boost/geometry/core/access.hpp> |
35 | #include <boost/geometry/core/assert.hpp> | |
36 | #include <boost/geometry/core/closure.hpp> | |
37 | #include <boost/geometry/core/coordinate_dimension.hpp> | |
38 | #include <boost/geometry/core/point_type.hpp> | |
39 | #include <boost/geometry/core/tags.hpp> | |
40 | ||
92f5a8d4 TL |
41 | #include <boost/geometry/policies/compare.hpp> |
42 | ||
43 | #include <boost/geometry/util/calculation_type.hpp> | |
44 | #include <boost/geometry/util/condition.hpp> | |
45 | #include <boost/geometry/util/has_nan_coordinate.hpp> | |
46 | #include <boost/geometry/util/math.hpp> | |
47 | ||
48 | #include <boost/geometry/strategies/disjoint.hpp> | |
49 | #include <boost/geometry/strategies/distance.hpp> | |
50 | #include <boost/geometry/strategies/tags.hpp> | |
7c673cae | 51 | |
7c673cae FG |
52 | namespace boost { namespace geometry |
53 | { | |
54 | ||
55 | ||
56 | #ifndef DOXYGEN_NO_DETAIL | |
57 | namespace detail { namespace distance | |
58 | { | |
59 | ||
60 | ||
1e59de90 TL |
61 | template <typename Segment, typename Box, typename Strategy> |
62 | inline bool intersects_segment_box(Segment const& segment, Box const& box, | |
63 | Strategy const& strategy) | |
92f5a8d4 | 64 | { |
1e59de90 | 65 | return ! detail::disjoint::disjoint_segment_box::apply(segment, box, strategy); |
92f5a8d4 TL |
66 | } |
67 | ||
1e59de90 TL |
68 | // TODO: segment_to_box_2D_generic is not used anymore. Remove? |
69 | ||
70 | // TODO: Furthermore this utility can potentially use different strategy than | |
71 | // the one that was passed into bg::distance() but it seems this is by design. | |
92f5a8d4 | 72 | |
7c673cae FG |
73 | template |
74 | < | |
75 | typename Segment, | |
76 | typename Box, | |
1e59de90 TL |
77 | typename Strategies, |
78 | bool UsePointBoxStrategy = false // use only PointSegment strategy | |
7c673cae FG |
79 | > |
80 | class segment_to_box_2D_generic | |
81 | { | |
82 | private: | |
83 | typedef typename point_type<Segment>::type segment_point; | |
84 | typedef typename point_type<Box>::type box_point; | |
85 | ||
1e59de90 | 86 | typedef distance::strategy_t<box_point, Segment, Strategies> ps_strategy_type; |
7c673cae FG |
87 | |
88 | typedef detail::closest_feature::point_to_point_range | |
89 | < | |
90 | segment_point, | |
91 | std::vector<box_point>, | |
1e59de90 | 92 | open |
7c673cae | 93 | > point_to_point_range; |
7c673cae FG |
94 | |
95 | public: | |
1e59de90 TL |
96 | // TODO: Or should the return type be defined by sb_strategy_type? |
97 | typedef distance::return_t<box_point, Segment, Strategies> return_type; | |
7c673cae FG |
98 | |
99 | static inline return_type apply(Segment const& segment, | |
100 | Box const& box, | |
1e59de90 | 101 | Strategies const& strategies, |
7c673cae FG |
102 | bool check_intersection = true) |
103 | { | |
1e59de90 | 104 | if (check_intersection && intersects_segment_box(segment, box, strategies)) |
7c673cae | 105 | { |
1e59de90 | 106 | return return_type(0); |
7c673cae FG |
107 | } |
108 | ||
7c673cae FG |
109 | // get segment points |
110 | segment_point p[2]; | |
111 | detail::assign_point_from_index<0>(segment, p[0]); | |
112 | detail::assign_point_from_index<1>(segment, p[1]); | |
113 | ||
114 | // get box points | |
115 | std::vector<box_point> box_points(4); | |
116 | detail::assign_box_corners_oriented<true>(box, box_points); | |
117 | ||
1e59de90 TL |
118 | ps_strategy_type const strategy = strategies.distance(dummy_point(), dummy_segment()); |
119 | ||
120 | auto const cstrategy = strategy::distance::services::get_comparable | |
121 | < | |
122 | ps_strategy_type | |
123 | >::apply(strategy); | |
124 | ||
125 | distance::creturn_t<box_point, Segment, Strategies> cd[6]; | |
7c673cae FG |
126 | for (unsigned int i = 0; i < 4; ++i) |
127 | { | |
128 | cd[i] = cstrategy.apply(box_points[i], p[0], p[1]); | |
129 | } | |
130 | ||
131 | std::pair | |
132 | < | |
133 | typename std::vector<box_point>::const_iterator, | |
134 | typename std::vector<box_point>::const_iterator | |
135 | > bit_min[2]; | |
136 | ||
137 | bit_min[0] = point_to_point_range::apply(p[0], | |
138 | box_points.begin(), | |
139 | box_points.end(), | |
140 | cstrategy, | |
141 | cd[4]); | |
142 | bit_min[1] = point_to_point_range::apply(p[1], | |
143 | box_points.begin(), | |
144 | box_points.end(), | |
145 | cstrategy, | |
146 | cd[5]); | |
147 | ||
148 | unsigned int imin = 0; | |
149 | for (unsigned int i = 1; i < 6; ++i) | |
150 | { | |
151 | if (cd[i] < cd[imin]) | |
152 | { | |
153 | imin = i; | |
154 | } | |
155 | } | |
156 | ||
1e59de90 | 157 | if (BOOST_GEOMETRY_CONDITION(is_comparable<ps_strategy_type>::value)) |
7c673cae FG |
158 | { |
159 | return cd[imin]; | |
160 | } | |
161 | ||
162 | if (imin < 4) | |
163 | { | |
1e59de90 | 164 | return strategy.apply(box_points[imin], p[0], p[1]); |
7c673cae FG |
165 | } |
166 | else | |
167 | { | |
168 | unsigned int bimin = imin - 4; | |
1e59de90 | 169 | return strategy.apply(p[bimin], |
7c673cae FG |
170 | *bit_min[bimin].first, |
171 | *bit_min[bimin].second); | |
172 | } | |
173 | } | |
174 | }; | |
175 | ||
176 | ||
177 | template | |
178 | < | |
179 | typename Segment, | |
180 | typename Box, | |
1e59de90 | 181 | typename Strategies |
7c673cae | 182 | > |
1e59de90 | 183 | class segment_to_box_2D_generic<Segment, Box, Strategies, true> // Use both PointSegment and PointBox strategies |
7c673cae FG |
184 | { |
185 | private: | |
186 | typedef typename point_type<Segment>::type segment_point; | |
187 | typedef typename point_type<Box>::type box_point; | |
188 | ||
1e59de90 TL |
189 | typedef distance::strategy_t<box_point, Segment, Strategies> ps_strategy_type; |
190 | typedef distance::strategy_t<segment_point, Box, Strategies> pb_strategy_type; | |
7c673cae FG |
191 | |
192 | public: | |
1e59de90 TL |
193 | // TODO: Or should the return type be defined by sb_strategy_type? |
194 | typedef distance::return_t<box_point, Segment, Strategies> return_type; | |
195 | ||
7c673cae FG |
196 | static inline return_type apply(Segment const& segment, |
197 | Box const& box, | |
1e59de90 | 198 | Strategies const& strategies, |
7c673cae FG |
199 | bool check_intersection = true) |
200 | { | |
1e59de90 | 201 | if (check_intersection && intersects_segment_box(segment, box, strategies)) |
7c673cae | 202 | { |
1e59de90 | 203 | return return_type(0); |
7c673cae FG |
204 | } |
205 | ||
7c673cae FG |
206 | // get segment points |
207 | segment_point p[2]; | |
208 | detail::assign_point_from_index<0>(segment, p[0]); | |
209 | detail::assign_point_from_index<1>(segment, p[1]); | |
210 | ||
211 | // get box points | |
212 | std::vector<box_point> box_points(4); | |
213 | detail::assign_box_corners_oriented<true>(box, box_points); | |
1e59de90 TL |
214 | |
215 | distance::creturn_t<box_point, Segment, Strategies> cd[6]; | |
216 | ||
217 | ps_strategy_type ps_strategy = strategies.distance(dummy_point(), dummy_segment()); | |
218 | auto const ps_cstrategy = strategy::distance::services::get_comparable | |
219 | < | |
220 | ps_strategy_type | |
221 | >::apply(ps_strategy); | |
222 | boost::ignore_unused(ps_strategy, ps_cstrategy); | |
223 | ||
7c673cae FG |
224 | for (unsigned int i = 0; i < 4; ++i) |
225 | { | |
1e59de90 | 226 | cd[i] = ps_cstrategy.apply(box_points[i], p[0], p[1]); |
7c673cae FG |
227 | } |
228 | ||
1e59de90 TL |
229 | pb_strategy_type const pb_strategy = strategies.distance(dummy_point(), dummy_box()); |
230 | auto const pb_cstrategy = strategy::distance::services::get_comparable | |
231 | < | |
232 | pb_strategy_type | |
233 | >::apply(pb_strategy); | |
234 | boost::ignore_unused(pb_strategy, pb_cstrategy); | |
235 | ||
7c673cae FG |
236 | cd[4] = pb_cstrategy.apply(p[0], box); |
237 | cd[5] = pb_cstrategy.apply(p[1], box); | |
238 | ||
239 | unsigned int imin = 0; | |
240 | for (unsigned int i = 1; i < 6; ++i) | |
241 | { | |
242 | if (cd[i] < cd[imin]) | |
243 | { | |
244 | imin = i; | |
245 | } | |
246 | } | |
247 | ||
7c673cae FG |
248 | if (imin < 4) |
249 | { | |
1e59de90 TL |
250 | if (is_comparable<ps_strategy_type>::value) |
251 | { | |
252 | return cd[imin]; | |
253 | } | |
254 | ||
255 | return ps_strategy.apply(box_points[imin], p[0], p[1]); | |
7c673cae FG |
256 | } |
257 | else | |
258 | { | |
1e59de90 TL |
259 | if (is_comparable<pb_strategy_type>::value) |
260 | { | |
261 | return cd[imin]; | |
262 | } | |
263 | ||
264 | return pb_strategy.apply(p[imin - 4], box); | |
7c673cae FG |
265 | } |
266 | } | |
267 | }; | |
268 | ||
269 | ||
270 | ||
271 | ||
272 | template | |
273 | < | |
274 | typename ReturnType, | |
275 | typename SegmentPoint, | |
276 | typename BoxPoint, | |
1e59de90 | 277 | typename Strategies |
7c673cae FG |
278 | > |
279 | class segment_to_box_2D | |
280 | { | |
281 | private: | |
282 | template <typename Result> | |
283 | struct cast_to_result | |
284 | { | |
285 | template <typename T> | |
286 | static inline Result apply(T const& t) | |
287 | { | |
288 | return boost::numeric_cast<Result>(t); | |
289 | } | |
290 | }; | |
291 | ||
292 | ||
293 | template <typename T, bool IsLess /* true */> | |
294 | struct compare_less_equal | |
295 | { | |
296 | typedef compare_less_equal<T, !IsLess> other; | |
297 | ||
298 | template <typename T1, typename T2> | |
299 | inline bool operator()(T1 const& t1, T2 const& t2) const | |
300 | { | |
301 | return std::less_equal<T>()(cast_to_result<T>::apply(t1), | |
302 | cast_to_result<T>::apply(t2)); | |
303 | } | |
304 | }; | |
305 | ||
306 | template <typename T> | |
307 | struct compare_less_equal<T, false> | |
308 | { | |
309 | typedef compare_less_equal<T, true> other; | |
310 | ||
311 | template <typename T1, typename T2> | |
312 | inline bool operator()(T1 const& t1, T2 const& t2) const | |
313 | { | |
314 | return std::greater_equal<T>()(cast_to_result<T>::apply(t1), | |
315 | cast_to_result<T>::apply(t2)); | |
316 | } | |
317 | }; | |
318 | ||
319 | ||
320 | template <typename LessEqual> | |
321 | struct other_compare | |
322 | { | |
323 | typedef typename LessEqual::other type; | |
324 | }; | |
325 | ||
326 | ||
327 | // it is assumed here that p0 lies to the right of the box (so the | |
328 | // entire segment lies to the right of the box) | |
329 | template <typename LessEqual> | |
330 | struct right_of_box | |
331 | { | |
332 | static inline ReturnType apply(SegmentPoint const& p0, | |
333 | SegmentPoint const& p1, | |
334 | BoxPoint const& bottom_right, | |
335 | BoxPoint const& top_right, | |
1e59de90 | 336 | Strategies const& strategies) |
7c673cae | 337 | { |
7c673cae FG |
338 | // the implementation below is written for non-negative slope |
339 | // segments | |
340 | // | |
341 | // for negative slope segments swap the roles of bottom_right | |
342 | // and top_right and use greater_equal instead of less_equal. | |
343 | ||
344 | typedef cast_to_result<ReturnType> cast; | |
345 | ||
346 | LessEqual less_equal; | |
347 | ||
1e59de90 | 348 | auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment()); |
92f5a8d4 TL |
349 | |
350 | if (less_equal(geometry::get<1>(bottom_right), geometry::get<1>(p0))) | |
7c673cae | 351 | { |
92f5a8d4 TL |
352 | //if p0 is in box's band |
353 | if (less_equal(geometry::get<1>(p0), geometry::get<1>(top_right))) | |
354 | { | |
355 | // segment & crosses band (TODO:merge with box-box dist) | |
356 | if (math::equals(geometry::get<0>(p0), geometry::get<0>(p1))) | |
357 | { | |
358 | SegmentPoint high = geometry::get<1>(p1) > geometry::get<1>(p0) ? p1 : p0; | |
359 | if (less_equal(geometry::get<1>(high), geometry::get<1>(top_right))) | |
360 | { | |
361 | return cast::apply(ps_strategy.apply(high, bottom_right, top_right)); | |
362 | } | |
363 | return cast::apply(ps_strategy.apply(top_right, p0, p1)); | |
364 | } | |
365 | return cast::apply(ps_strategy.apply(p0, bottom_right, top_right)); | |
366 | } | |
367 | // distance is realized between the top-right | |
368 | // corner of the box and the segment | |
369 | return cast::apply(ps_strategy.apply(top_right, p0, p1)); | |
7c673cae FG |
370 | } |
371 | else | |
372 | { | |
373 | // distance is realized between the bottom-right | |
374 | // corner of the box and the segment | |
375 | return cast::apply(ps_strategy.apply(bottom_right, p0, p1)); | |
376 | } | |
377 | } | |
378 | }; | |
379 | ||
7c673cae FG |
380 | // it is assumed here that p0 lies above the box (so the |
381 | // entire segment lies above the box) | |
92f5a8d4 | 382 | |
7c673cae FG |
383 | template <typename LessEqual> |
384 | struct above_of_box | |
385 | { | |
92f5a8d4 | 386 | |
7c673cae FG |
387 | static inline ReturnType apply(SegmentPoint const& p0, |
388 | SegmentPoint const& p1, | |
389 | BoxPoint const& top_left, | |
1e59de90 | 390 | Strategies const& strategies) |
7c673cae | 391 | { |
1e59de90 | 392 | return apply(p0, p1, p0, top_left, strategies); |
92f5a8d4 | 393 | } |
7c673cae | 394 | |
92f5a8d4 TL |
395 | static inline ReturnType apply(SegmentPoint const& p0, |
396 | SegmentPoint const& p1, | |
397 | SegmentPoint const& p_max, | |
398 | BoxPoint const& top_left, | |
1e59de90 | 399 | Strategies const& strategies) |
92f5a8d4 | 400 | { |
1e59de90 TL |
401 | auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment()); |
402 | ||
7c673cae | 403 | typedef cast_to_result<ReturnType> cast; |
7c673cae FG |
404 | LessEqual less_equal; |
405 | ||
92f5a8d4 TL |
406 | // p0 is above the upper segment of the box (and inside its band) |
407 | // then compute the vertical (i.e. meridian for spherical) distance | |
408 | if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p_max))) | |
7c673cae | 409 | { |
1e59de90 | 410 | ReturnType diff = ps_strategy.vertical_or_meridian( |
92f5a8d4 TL |
411 | geometry::get_as_radian<1>(p_max), |
412 | geometry::get_as_radian<1>(top_left)); | |
413 | ||
7c673cae FG |
414 | return strategy::distance::services::result_from_distance |
415 | < | |
1e59de90 TL |
416 | std::remove_const_t<decltype(ps_strategy)>, |
417 | SegmentPoint, BoxPoint | |
418 | >::apply(ps_strategy, math::abs(diff)); | |
7c673cae FG |
419 | } |
420 | ||
421 | // p0 is to the left of the box, but p1 is above the box | |
422 | // in this case the distance is realized between the | |
423 | // top-left corner of the box and the segment | |
1e59de90 | 424 | return cast::apply(ps_strategy.apply(top_left, p0, p1)); |
7c673cae FG |
425 | } |
426 | }; | |
427 | ||
7c673cae FG |
428 | template <typename LessEqual> |
429 | struct check_right_left_of_box | |
430 | { | |
431 | static inline bool apply(SegmentPoint const& p0, | |
432 | SegmentPoint const& p1, | |
433 | BoxPoint const& top_left, | |
434 | BoxPoint const& top_right, | |
435 | BoxPoint const& bottom_left, | |
436 | BoxPoint const& bottom_right, | |
1e59de90 | 437 | Strategies const& strategies, |
7c673cae FG |
438 | ReturnType& result) |
439 | { | |
440 | // p0 lies to the right of the box | |
441 | if (geometry::get<0>(p0) >= geometry::get<0>(top_right)) | |
442 | { | |
443 | result = right_of_box | |
444 | < | |
445 | LessEqual | |
446 | >::apply(p0, p1, bottom_right, top_right, | |
1e59de90 | 447 | strategies); |
7c673cae FG |
448 | return true; |
449 | } | |
450 | ||
451 | // p1 lies to the left of the box | |
452 | if (geometry::get<0>(p1) <= geometry::get<0>(bottom_left)) | |
453 | { | |
454 | result = right_of_box | |
455 | < | |
456 | typename other_compare<LessEqual>::type | |
457 | >::apply(p1, p0, top_left, bottom_left, | |
1e59de90 | 458 | strategies); |
7c673cae FG |
459 | return true; |
460 | } | |
461 | ||
462 | return false; | |
463 | } | |
464 | }; | |
465 | ||
7c673cae FG |
466 | template <typename LessEqual> |
467 | struct check_above_below_of_box | |
468 | { | |
469 | static inline bool apply(SegmentPoint const& p0, | |
470 | SegmentPoint const& p1, | |
471 | BoxPoint const& top_left, | |
472 | BoxPoint const& top_right, | |
473 | BoxPoint const& bottom_left, | |
474 | BoxPoint const& bottom_right, | |
1e59de90 | 475 | Strategies const& strategies, |
7c673cae FG |
476 | ReturnType& result) |
477 | { | |
92f5a8d4 TL |
478 | typedef compare_less_equal<ReturnType, false> GreaterEqual; |
479 | ||
7c673cae FG |
480 | // the segment lies below the box |
481 | if (geometry::get<1>(p1) < geometry::get<1>(bottom_left)) | |
482 | { | |
1e59de90 TL |
483 | auto const sb_strategy = strategies.distance(dummy_segment(), dummy_box()); |
484 | ||
485 | // TODO: this strategy calls this algorithm's again, specifically: | |
486 | // geometry::detail::distance::segment_to_box_2D<>::call_above_of_box | |
487 | // If possible rewrite them to avoid this. | |
488 | // For now just pass umbrella strategy. | |
92f5a8d4 TL |
489 | result = sb_strategy.template segment_below_of_box |
490 | < | |
491 | LessEqual, | |
492 | ReturnType | |
493 | >(p0, p1, | |
494 | top_left, top_right, | |
1e59de90 TL |
495 | bottom_left, bottom_right, |
496 | strategies); | |
7c673cae FG |
497 | return true; |
498 | } | |
499 | ||
500 | // the segment lies above the box | |
501 | if (geometry::get<1>(p0) > geometry::get<1>(top_right)) | |
502 | { | |
92f5a8d4 TL |
503 | result = (std::min)(above_of_box |
504 | < | |
505 | LessEqual | |
1e59de90 | 506 | >::apply(p0, p1, top_left, strategies), |
92f5a8d4 TL |
507 | above_of_box |
508 | < | |
509 | GreaterEqual | |
1e59de90 | 510 | >::apply(p1, p0, top_right, strategies)); |
7c673cae FG |
511 | return true; |
512 | } | |
513 | return false; | |
514 | } | |
515 | }; | |
516 | ||
517 | struct check_generic_position | |
518 | { | |
519 | static inline bool apply(SegmentPoint const& p0, | |
520 | SegmentPoint const& p1, | |
7c673cae FG |
521 | BoxPoint const& corner1, |
522 | BoxPoint const& corner2, | |
1e59de90 | 523 | Strategies const& strategies, |
7c673cae FG |
524 | ReturnType& result) |
525 | { | |
1e59de90 TL |
526 | auto const side_strategy = strategies.side(); |
527 | auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment()); | |
7c673cae | 528 | |
92f5a8d4 | 529 | typedef cast_to_result<ReturnType> cast; |
7c673cae | 530 | ReturnType diff1 = cast::apply(geometry::get<1>(p1)) |
92f5a8d4 | 531 | - cast::apply(geometry::get<1>(p0)); |
7c673cae | 532 | |
92f5a8d4 TL |
533 | int sign = diff1 < 0 ? -1 : 1; |
534 | if (side_strategy.apply(p0, p1, corner1) * sign < 0) | |
7c673cae FG |
535 | { |
536 | result = cast::apply(ps_strategy.apply(corner1, p0, p1)); | |
537 | return true; | |
538 | } | |
92f5a8d4 | 539 | if (side_strategy.apply(p0, p1, corner2) * sign > 0) |
7c673cae FG |
540 | { |
541 | result = cast::apply(ps_strategy.apply(corner2, p0, p1)); | |
542 | return true; | |
543 | } | |
544 | return false; | |
545 | } | |
546 | }; | |
547 | ||
548 | static inline ReturnType | |
549 | non_negative_slope_segment(SegmentPoint const& p0, | |
550 | SegmentPoint const& p1, | |
551 | BoxPoint const& top_left, | |
552 | BoxPoint const& top_right, | |
553 | BoxPoint const& bottom_left, | |
554 | BoxPoint const& bottom_right, | |
1e59de90 | 555 | Strategies const& strategies) |
7c673cae FG |
556 | { |
557 | typedef compare_less_equal<ReturnType, true> less_equal; | |
558 | ||
559 | // assert that the segment has non-negative slope | |
560 | BOOST_GEOMETRY_ASSERT( ( math::equals(geometry::get<0>(p0), geometry::get<0>(p1)) | |
561 | && geometry::get<1>(p0) < geometry::get<1>(p1)) | |
562 | || | |
563 | ( geometry::get<0>(p0) < geometry::get<0>(p1) | |
564 | && geometry::get<1>(p0) <= geometry::get<1>(p1) ) | |
565 | || geometry::has_nan_coordinate(p0) | |
566 | || geometry::has_nan_coordinate(p1)); | |
567 | ||
568 | ReturnType result(0); | |
569 | ||
570 | if (check_right_left_of_box | |
571 | < | |
572 | less_equal | |
573 | >::apply(p0, p1, | |
574 | top_left, top_right, bottom_left, bottom_right, | |
1e59de90 | 575 | strategies, result)) |
7c673cae FG |
576 | { |
577 | return result; | |
578 | } | |
579 | ||
580 | if (check_above_below_of_box | |
581 | < | |
582 | less_equal | |
583 | >::apply(p0, p1, | |
584 | top_left, top_right, bottom_left, bottom_right, | |
1e59de90 | 585 | strategies, result)) |
7c673cae FG |
586 | { |
587 | return result; | |
588 | } | |
589 | ||
590 | if (check_generic_position::apply(p0, p1, | |
7c673cae | 591 | top_left, bottom_right, |
1e59de90 | 592 | strategies, result)) |
7c673cae FG |
593 | { |
594 | return result; | |
595 | } | |
596 | ||
597 | // in all other cases the box and segment intersect, so return 0 | |
598 | return result; | |
599 | } | |
600 | ||
601 | ||
602 | static inline ReturnType | |
603 | negative_slope_segment(SegmentPoint const& p0, | |
604 | SegmentPoint const& p1, | |
605 | BoxPoint const& top_left, | |
606 | BoxPoint const& top_right, | |
607 | BoxPoint const& bottom_left, | |
608 | BoxPoint const& bottom_right, | |
1e59de90 | 609 | Strategies const& strategies) |
7c673cae FG |
610 | { |
611 | typedef compare_less_equal<ReturnType, false> greater_equal; | |
612 | ||
613 | // assert that the segment has negative slope | |
614 | BOOST_GEOMETRY_ASSERT( ( geometry::get<0>(p0) < geometry::get<0>(p1) | |
615 | && geometry::get<1>(p0) > geometry::get<1>(p1) ) | |
616 | || geometry::has_nan_coordinate(p0) | |
617 | || geometry::has_nan_coordinate(p1) ); | |
618 | ||
619 | ReturnType result(0); | |
620 | ||
621 | if (check_right_left_of_box | |
622 | < | |
623 | greater_equal | |
624 | >::apply(p0, p1, | |
625 | bottom_left, bottom_right, top_left, top_right, | |
1e59de90 | 626 | strategies, result)) |
7c673cae FG |
627 | { |
628 | return result; | |
629 | } | |
630 | ||
631 | if (check_above_below_of_box | |
632 | < | |
633 | greater_equal | |
634 | >::apply(p1, p0, | |
635 | top_right, top_left, bottom_right, bottom_left, | |
1e59de90 | 636 | strategies, result)) |
7c673cae FG |
637 | { |
638 | return result; | |
639 | } | |
640 | ||
641 | if (check_generic_position::apply(p0, p1, | |
642 | bottom_left, top_right, | |
1e59de90 | 643 | strategies, result)) |
7c673cae FG |
644 | { |
645 | return result; | |
646 | } | |
647 | ||
648 | // in all other cases the box and segment intersect, so return 0 | |
649 | return result; | |
650 | } | |
651 | ||
652 | public: | |
653 | static inline ReturnType apply(SegmentPoint const& p0, | |
654 | SegmentPoint const& p1, | |
655 | BoxPoint const& top_left, | |
656 | BoxPoint const& top_right, | |
657 | BoxPoint const& bottom_left, | |
658 | BoxPoint const& bottom_right, | |
1e59de90 | 659 | Strategies const& strategies) |
7c673cae | 660 | { |
1e59de90 | 661 | BOOST_GEOMETRY_ASSERT( (geometry::less<SegmentPoint, -1, typename Strategies::cs_tag>()(p0, p1)) |
7c673cae FG |
662 | || geometry::has_nan_coordinate(p0) |
663 | || geometry::has_nan_coordinate(p1) ); | |
664 | ||
665 | if (geometry::get<0>(p0) < geometry::get<0>(p1) | |
666 | && geometry::get<1>(p0) > geometry::get<1>(p1)) | |
667 | { | |
668 | return negative_slope_segment(p0, p1, | |
669 | top_left, top_right, | |
670 | bottom_left, bottom_right, | |
1e59de90 | 671 | strategies); |
7c673cae FG |
672 | } |
673 | ||
674 | return non_negative_slope_segment(p0, p1, | |
675 | top_left, top_right, | |
676 | bottom_left, bottom_right, | |
1e59de90 | 677 | strategies); |
7c673cae | 678 | } |
7c673cae | 679 | |
92f5a8d4 TL |
680 | template <typename LessEqual> |
681 | static inline ReturnType call_above_of_box(SegmentPoint const& p0, | |
682 | SegmentPoint const& p1, | |
683 | SegmentPoint const& p_max, | |
684 | BoxPoint const& top_left, | |
1e59de90 | 685 | Strategies const& strategies) |
92f5a8d4 | 686 | { |
1e59de90 | 687 | return above_of_box<LessEqual>::apply(p0, p1, p_max, top_left, strategies); |
92f5a8d4 | 688 | } |
7c673cae | 689 | |
92f5a8d4 TL |
690 | template <typename LessEqual> |
691 | static inline ReturnType call_above_of_box(SegmentPoint const& p0, | |
692 | SegmentPoint const& p1, | |
693 | BoxPoint const& top_left, | |
1e59de90 | 694 | Strategies const& strategies) |
92f5a8d4 | 695 | { |
1e59de90 | 696 | return above_of_box<LessEqual>::apply(p0, p1, top_left, strategies); |
92f5a8d4 TL |
697 | } |
698 | }; | |
7c673cae | 699 | |
92f5a8d4 | 700 | //========================================================================= |
7c673cae FG |
701 | |
702 | template | |
703 | < | |
704 | typename Segment, | |
705 | typename Box, | |
706 | typename std::size_t Dimension, | |
1e59de90 | 707 | typename Strategies |
7c673cae FG |
708 | > |
709 | class segment_to_box | |
710 | : not_implemented<Segment, Box> | |
711 | {}; | |
712 | ||
713 | ||
714 | template | |
715 | < | |
716 | typename Segment, | |
717 | typename Box, | |
1e59de90 | 718 | typename Strategies |
7c673cae | 719 | > |
1e59de90 | 720 | class segment_to_box<Segment, Box, 2, Strategies> |
7c673cae | 721 | { |
1e59de90 | 722 | typedef distance::strategy_t<Segment, Box, Strategies> strategy_type; |
7c673cae | 723 | |
7c673cae | 724 | public: |
1e59de90 | 725 | typedef distance::return_t<Segment, Box, Strategies> return_type; |
7c673cae FG |
726 | |
727 | static inline return_type apply(Segment const& segment, | |
728 | Box const& box, | |
1e59de90 | 729 | Strategies const& strategies) |
7c673cae | 730 | { |
1e59de90 TL |
731 | typedef typename point_type<Segment>::type segment_point; |
732 | typedef typename point_type<Box>::type box_point; | |
733 | ||
7c673cae FG |
734 | segment_point p[2]; |
735 | detail::assign_point_from_index<0>(segment, p[0]); | |
736 | detail::assign_point_from_index<1>(segment, p[1]); | |
737 | ||
1e59de90 | 738 | if (detail::equals::equals_point_point(p[0], p[1], strategies)) |
7c673cae | 739 | { |
7c673cae FG |
740 | return dispatch::distance |
741 | < | |
742 | segment_point, | |
743 | Box, | |
1e59de90 TL |
744 | Strategies |
745 | >::apply(p[0], box, strategies); | |
7c673cae FG |
746 | } |
747 | ||
748 | box_point top_left, top_right, bottom_left, bottom_right; | |
749 | detail::assign_box_corners(box, bottom_left, bottom_right, | |
750 | top_left, top_right); | |
751 | ||
1e59de90 TL |
752 | strategy_type::mirror(p[0], p[1], |
753 | bottom_left, bottom_right, | |
754 | top_left, top_right); | |
92f5a8d4 | 755 | |
1e59de90 | 756 | typedef geometry::less<segment_point, -1, typename Strategies::cs_tag> less_type; |
92f5a8d4 | 757 | if (less_type()(p[0], p[1])) |
7c673cae FG |
758 | { |
759 | return segment_to_box_2D | |
760 | < | |
761 | return_type, | |
762 | segment_point, | |
763 | box_point, | |
1e59de90 | 764 | Strategies |
7c673cae FG |
765 | >::apply(p[0], p[1], |
766 | top_left, top_right, bottom_left, bottom_right, | |
1e59de90 | 767 | strategies); |
7c673cae FG |
768 | } |
769 | else | |
770 | { | |
771 | return segment_to_box_2D | |
772 | < | |
773 | return_type, | |
774 | segment_point, | |
775 | box_point, | |
1e59de90 | 776 | Strategies |
7c673cae FG |
777 | >::apply(p[1], p[0], |
778 | top_left, top_right, bottom_left, bottom_right, | |
1e59de90 | 779 | strategies); |
7c673cae FG |
780 | } |
781 | } | |
782 | }; | |
783 | ||
784 | ||
785 | }} // namespace detail::distance | |
786 | #endif // DOXYGEN_NO_DETAIL | |
787 | ||
788 | ||
789 | #ifndef DOXYGEN_NO_DISPATCH | |
790 | namespace dispatch | |
791 | { | |
792 | ||
793 | ||
1e59de90 | 794 | template <typename Segment, typename Box, typename Strategies> |
7c673cae FG |
795 | struct distance |
796 | < | |
1e59de90 | 797 | Segment, Box, Strategies, segment_tag, box_tag, |
92f5a8d4 | 798 | strategy_tag_distance_segment_box, false |
7c673cae FG |
799 | > |
800 | { | |
1e59de90 TL |
801 | static inline auto apply(Segment const& segment, Box const& box, |
802 | Strategies const& strategies) | |
7c673cae FG |
803 | { |
804 | assert_dimension_equal<Segment, Box>(); | |
805 | ||
7c673cae FG |
806 | return detail::distance::segment_to_box |
807 | < | |
808 | Segment, | |
809 | Box, | |
810 | dimension<Segment>::value, | |
1e59de90 TL |
811 | Strategies |
812 | >::apply(segment, box, strategies); | |
7c673cae FG |
813 | } |
814 | }; | |
815 | ||
816 | ||
817 | ||
818 | } // namespace dispatch | |
819 | #endif // DOXYGEN_NO_DISPATCH | |
820 | ||
821 | ||
822 | }} // namespace boost::geometry | |
823 | ||
824 | ||
825 | #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP |