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