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