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