1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
4 // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 
7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
9 
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
13 
14 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP
15 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP
16 
17 
18 #include <boost/geometry/core/access.hpp>
19 
20 #include <boost/geometry/strategies/distance.hpp>
21 
22 #include <boost/geometry/util/math.hpp>
23 #include <boost/geometry/util/calculation_type.hpp>
24 
25 
26 namespace boost { namespace geometry
27 {
28 
29 namespace strategy { namespace distance
30 {
31 
32 #ifndef DOXYGEN_NO_DETAIL
33 namespace detail
34 {
35 
36 template <size_t I, typename T>
37 struct compute_pythagoras
38 {
39     template <typename Point1, typename Point2>
applyboost::geometry::strategy::distance::detail::compute_pythagoras40     static inline T apply(Point1 const& p1, Point2 const& p2)
41     {
42         T const c1 = boost::numeric_cast<T>(get<I-1>(p1));
43         T const c2 = boost::numeric_cast<T>(get<I-1>(p2));
44         T const d = c1 - c2;
45         return d * d + compute_pythagoras<I-1, T>::apply(p1, p2);
46     }
47 };
48 
49 template <typename T>
50 struct compute_pythagoras<0, T>
51 {
52     template <typename Point1, typename Point2>
applyboost::geometry::strategy::distance::detail::compute_pythagoras53     static inline T apply(Point1 const&, Point2 const&)
54     {
55         return boost::numeric_cast<T>(0);
56     }
57 };
58 
59 }
60 #endif // DOXYGEN_NO_DETAIL
61 
62 
63 namespace comparable
64 {
65 
66 /*!
67 \brief Strategy to calculate comparable distance between two points
68 \ingroup strategies
69 \tparam Point1 \tparam_first_point
70 \tparam Point2 \tparam_second_point
71 \tparam CalculationType \tparam_calculation
72 */
73 template <typename CalculationType = void>
74 class pythagoras
75 {
76 public :
77 
78     template <typename Point1, typename Point2>
79     struct calculation_type
80         : util::calculation_type::geometric::binary
81           <
82               Point1,
83               Point2,
84               CalculationType,
85               double,
86               double
87           >
88     {};
89 
90     template <typename Point1, typename Point2>
91     static inline typename calculation_type<Point1, Point2>::type
apply(Point1 const & p1,Point2 const & p2)92     apply(Point1 const& p1, Point2 const& p2)
93     {
94         BOOST_CONCEPT_ASSERT( (concepts::ConstPoint<Point1>) );
95         BOOST_CONCEPT_ASSERT( (concepts::ConstPoint<Point2>) );
96 
97         // Calculate distance using Pythagoras
98         // (Leave comment above for Doxygen)
99 
100         assert_dimension_equal<Point1, Point2>();
101 
102         return detail::compute_pythagoras
103             <
104                 dimension<Point1>::value,
105                 typename calculation_type<Point1, Point2>::type
106             >::apply(p1, p2);
107     }
108 };
109 
110 } // namespace comparable
111 
112 
113 /*!
114 \brief Strategy to calculate the distance between two points
115 \ingroup strategies
116 \tparam CalculationType \tparam_calculation
117 
118 \qbk{
119 [heading Notes]
120 [note Can be used for points with two\, three or more dimensions]
121 [heading See also]
122 [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
123 }
124 
125 */
126 template
127 <
128     typename CalculationType = void
129 >
130 class pythagoras
131 {
132 public :
133 
134     template <typename P1, typename P2>
135     struct calculation_type
136         : util::calculation_type::geometric::binary
137           <
138               P1,
139               P2,
140               CalculationType,
141               double,
142               double // promote integer to double
143           >
144     {};
145 
146     /*!
147     \brief applies the distance calculation using pythagoras
148     \return the calculated distance (including taking the square root)
149     \param p1 first point
150     \param p2 second point
151     */
152     template <typename P1, typename P2>
153     static inline typename calculation_type<P1, P2>::type
apply(P1 const & p1,P2 const & p2)154     apply(P1 const& p1, P2 const& p2)
155     {
156         // The cast is necessary for MSVC which considers sqrt __int64 as an ambiguous call
157         return math::sqrt
158             (
159                  boost::numeric_cast<typename calculation_type<P1, P2>::type>
160                     (
161                         comparable::pythagoras<CalculationType>::apply(p1, p2)
162                     )
163             );
164     }
165 };
166 
167 
168 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
169 namespace services
170 {
171 
172 template <typename CalculationType>
173 struct tag<pythagoras<CalculationType> >
174 {
175     typedef strategy_tag_distance_point_point type;
176 };
177 
178 
179 template <typename CalculationType, typename P1, typename P2>
180 struct return_type<distance::pythagoras<CalculationType>, P1, P2>
181     : pythagoras<CalculationType>::template calculation_type<P1, P2>
182 {};
183 
184 
185 template <typename CalculationType>
186 struct comparable_type<pythagoras<CalculationType> >
187 {
188     typedef comparable::pythagoras<CalculationType> type;
189 };
190 
191 
192 template <typename CalculationType>
193 struct get_comparable<pythagoras<CalculationType> >
194 {
195     typedef comparable::pythagoras<CalculationType> comparable_type;
196 public :
applyboost::geometry::strategy::distance::services::get_comparable197     static inline comparable_type apply(pythagoras<CalculationType> const& )
198     {
199         return comparable_type();
200     }
201 };
202 
203 
204 template <typename CalculationType, typename Point1, typename Point2>
205 struct result_from_distance<pythagoras<CalculationType>, Point1, Point2>
206 {
207 private :
208     typedef typename return_type<pythagoras<CalculationType>, Point1, Point2>::type return_type;
209 public :
210     template <typename T>
applyboost::geometry::strategy::distance::services::result_from_distance211     static inline return_type apply(pythagoras<CalculationType> const& , T const& value)
212     {
213         return return_type(value);
214     }
215 };
216 
217 
218 // Specializations for comparable::pythagoras
219 template <typename CalculationType>
220 struct tag<comparable::pythagoras<CalculationType> >
221 {
222     typedef strategy_tag_distance_point_point type;
223 };
224 
225 
226 template <typename CalculationType, typename P1, typename P2>
227 struct return_type<comparable::pythagoras<CalculationType>, P1, P2>
228     : comparable::pythagoras<CalculationType>::template calculation_type<P1, P2>
229 {};
230 
231 
232 
233 
234 template <typename CalculationType>
235 struct comparable_type<comparable::pythagoras<CalculationType> >
236 {
237     typedef comparable::pythagoras<CalculationType> type;
238 };
239 
240 
241 template <typename CalculationType>
242 struct get_comparable<comparable::pythagoras<CalculationType> >
243 {
244     typedef comparable::pythagoras<CalculationType> comparable_type;
245 public :
applyboost::geometry::strategy::distance::services::get_comparable246     static inline comparable_type apply(comparable::pythagoras<CalculationType> const& )
247     {
248         return comparable_type();
249     }
250 };
251 
252 
253 template <typename CalculationType, typename Point1, typename Point2>
254 struct result_from_distance<comparable::pythagoras<CalculationType>, Point1, Point2>
255 {
256 private :
257     typedef typename return_type<comparable::pythagoras<CalculationType>, Point1, Point2>::type return_type;
258 public :
259     template <typename T>
applyboost::geometry::strategy::distance::services::result_from_distance260     static inline return_type apply(comparable::pythagoras<CalculationType> const& , T const& value)
261     {
262         return_type const v = value;
263         return v * v;
264     }
265 };
266 
267 
268 template <typename Point1, typename Point2>
269 struct default_strategy
270     <
271         point_tag, point_tag, Point1, Point2, cartesian_tag, cartesian_tag
272     >
273 {
274     typedef pythagoras<> type;
275 };
276 
277 
278 } // namespace services
279 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
280 
281 
282 }} // namespace strategy::distance
283 
284 
285 }} // namespace boost::geometry
286 
287 
288 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_DISTANCE_PYTHAGORAS_HPP
289