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_SEGMENT_HPP
11 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
12 
13 #include <algorithm>
14 #include <iterator>
15 
16 #include <boost/core/addressof.hpp>
17 
18 #include <boost/geometry/core/point_type.hpp>
19 #include <boost/geometry/core/tags.hpp>
20 
21 #include <boost/geometry/util/condition.hpp>
22 
23 #include <boost/geometry/strategies/distance.hpp>
24 #include <boost/geometry/strategies/tags.hpp>
25 
26 #include <boost/geometry/algorithms/assign.hpp>
27 #include <boost/geometry/algorithms/intersects.hpp>
28 
29 #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
30 
31 #include <boost/geometry/algorithms/dispatch/distance.hpp>
32 
33 
34 namespace boost { namespace geometry
35 {
36 
37 
38 #ifndef DOXYGEN_NO_DETAIL
39 namespace detail { namespace distance
40 {
41 
42 
43 
44 // compute segment-segment distance
45 template<typename Segment1, typename Segment2, typename Strategy>
46 class segment_to_segment
47 {
48 private:
49     typedef typename strategy::distance::services::comparable_type
50         <
51             Strategy
52         >::type comparable_strategy;
53 
54     typedef typename strategy::distance::services::return_type
55         <
56             comparable_strategy,
57             typename point_type<Segment1>::type,
58             typename point_type<Segment2>::type
59         >::type comparable_return_type;
60 
61 public:
62     typedef typename strategy::distance::services::return_type
63         <
64             Strategy,
65             typename point_type<Segment1>::type,
66             typename point_type<Segment2>::type
67         >::type return_type;
68 
69     static inline return_type
apply(Segment1 const & segment1,Segment2 const & segment2,Strategy const & strategy)70     apply(Segment1 const& segment1, Segment2 const& segment2,
71           Strategy const& strategy)
72     {
73         if (geometry::intersects(segment1, segment2))
74         {
75             return 0;
76         }
77 
78         typename point_type<Segment1>::type p[2];
79         detail::assign_point_from_index<0>(segment1, p[0]);
80         detail::assign_point_from_index<1>(segment1, p[1]);
81 
82         typename point_type<Segment2>::type q[2];
83         detail::assign_point_from_index<0>(segment2, q[0]);
84         detail::assign_point_from_index<1>(segment2, q[1]);
85 
86         comparable_strategy cstrategy =
87             strategy::distance::services::get_comparable
88                 <
89                     Strategy
90                 >::apply(strategy);
91 
92         comparable_return_type d[4];
93         d[0] = cstrategy.apply(q[0], p[0], p[1]);
94         d[1] = cstrategy.apply(q[1], p[0], p[1]);
95         d[2] = cstrategy.apply(p[0], q[0], q[1]);
96         d[3] = cstrategy.apply(p[1], q[0], q[1]);
97 
98         std::size_t imin = std::distance(boost::addressof(d[0]),
99                                          std::min_element(d, d + 4));
100 
101         if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value))
102         {
103             return d[imin];
104         }
105 
106         switch (imin)
107         {
108         case 0:
109             return strategy.apply(q[0], p[0], p[1]);
110         case 1:
111             return strategy.apply(q[1], p[0], p[1]);
112         case 2:
113             return strategy.apply(p[0], q[0], q[1]);
114         default:
115             return strategy.apply(p[1], q[0], q[1]);
116         }
117     }
118 };
119 
120 
121 
122 
123 }} // namespace detail::distance
124 #endif // DOXYGEN_NO_DETAIL
125 
126 
127 #ifndef DOXYGEN_NO_DISPATCH
128 namespace dispatch
129 {
130 
131 
132 
133 // segment-segment
134 template <typename Segment1, typename Segment2, typename Strategy>
135 struct distance
136     <
137         Segment1, Segment2, Strategy, segment_tag, segment_tag,
138         strategy_tag_distance_point_segment, false
139     >
140     : detail::distance::segment_to_segment<Segment1, Segment2, Strategy>
141 {};
142 
143 
144 
145 } // namespace dispatch
146 #endif // DOXYGEN_NO_DISPATCH
147 
148 
149 }} // namespace boost::geometry
150 
151 
152 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
153