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