• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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