distance_haversine.hpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Use, modification and distribution is subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP
  7. #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP
  8. #include <boost/geometry/core/cs.hpp>
  9. #include <boost/geometry/core/access.hpp>
  10. #include <boost/geometry/core/radian_access.hpp>
  11. #include <boost/geometry/util/select_calculation_type.hpp>
  12. #include <boost/geometry/util/promote_floating_point.hpp>
  13. #include <boost/geometry/strategies/distance.hpp>
  14. namespace boost { namespace geometry
  15. {
  16. namespace strategy { namespace distance
  17. {
  18. namespace comparable
  19. {
  20. // Comparable haversine.
  21. // To compare distances, we can avoid:
  22. // - multiplication with radius and 2.0
  23. // - applying sqrt
  24. // - applying asin (which is strictly (monotone) increasing)
  25. template
  26. <
  27. typename RadiusType,
  28. typename CalculationType = void
  29. >
  30. class haversine
  31. {
  32. public :
  33. template <typename Point1, typename Point2>
  34. struct calculation_type
  35. : promote_floating_point
  36. <
  37. typename select_calculation_type
  38. <
  39. Point1,
  40. Point2,
  41. CalculationType
  42. >::type
  43. >
  44. {};
  45. typedef RadiusType radius_type;
  46. explicit inline haversine(RadiusType const& r = 1.0)
  47. : m_radius(r)
  48. {}
  49. template <typename Point1, typename Point2>
  50. static inline typename calculation_type<Point1, Point2>::type
  51. apply(Point1 const& p1, Point2 const& p2)
  52. {
  53. return calculate<typename calculation_type<Point1, Point2>::type>(
  54. get_as_radian<0>(p1), get_as_radian<1>(p1),
  55. get_as_radian<0>(p2), get_as_radian<1>(p2)
  56. );
  57. }
  58. inline RadiusType radius() const
  59. {
  60. return m_radius;
  61. }
  62. private :
  63. template <typename R, typename T1, typename T2>
  64. static inline R calculate(T1 const& lon1, T1 const& lat1,
  65. T2 const& lon2, T2 const& lat2)
  66. {
  67. return math::hav(lat2 - lat1)
  68. + cos(lat1) * cos(lat2) * math::hav(lon2 - lon1);
  69. }
  70. RadiusType m_radius;
  71. };
  72. } // namespace comparable
  73. /*!
  74. \brief Distance calculation for spherical coordinates
  75. on a perfect sphere using haversine
  76. \ingroup strategies
  77. \tparam RadiusType \tparam_radius
  78. \tparam CalculationType \tparam_calculation
  79. \author Adapted from: http://williams.best.vwh.net/avform.htm
  80. \see http://en.wikipedia.org/wiki/Great-circle_distance
  81. \note (from Wiki:) The great circle distance d between two
  82. points with coordinates {lat1,lon1} and {lat2,lon2} is given by:
  83. d=acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2))
  84. A mathematically equivalent formula, which is less subject
  85. to rounding error for short distances is:
  86. d=2*asin(sqrt((sin((lat1-lat2) / 2))^2
  87. + cos(lat1)*cos(lat2)*(sin((lon1-lon2) / 2))^2))
  88. \qbk{
  89. [heading See also]
  90. [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
  91. }
  92. */
  93. template
  94. <
  95. typename RadiusType,
  96. typename CalculationType = void
  97. >
  98. class haversine
  99. {
  100. typedef comparable::haversine<RadiusType, CalculationType> comparable_type;
  101. public :
  102. template <typename Point1, typename Point2>
  103. struct calculation_type
  104. : services::return_type<comparable_type, Point1, Point2>
  105. {};
  106. typedef RadiusType radius_type;
  107. /*!
  108. \brief Constructor
  109. \param radius radius of the sphere, defaults to 1.0 for the unit sphere
  110. */
  111. inline haversine(RadiusType const& radius = 1.0)
  112. : m_radius(radius)
  113. {}
  114. /*!
  115. \brief applies the distance calculation
  116. \return the calculated distance (including multiplying with radius)
  117. \param p1 first point
  118. \param p2 second point
  119. */
  120. template <typename Point1, typename Point2>
  121. inline typename calculation_type<Point1, Point2>::type
  122. apply(Point1 const& p1, Point2 const& p2) const
  123. {
  124. typedef typename calculation_type<Point1, Point2>::type calculation_type;
  125. calculation_type const a = comparable_type::apply(p1, p2);
  126. calculation_type const c = calculation_type(2.0) * asin(sqrt(a));
  127. return m_radius * c;
  128. }
  129. /*!
  130. \brief access to radius value
  131. \return the radius
  132. */
  133. inline RadiusType radius() const
  134. {
  135. return m_radius;
  136. }
  137. private :
  138. RadiusType m_radius;
  139. };
  140. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  141. namespace services
  142. {
  143. template <typename RadiusType, typename CalculationType>
  144. struct tag<haversine<RadiusType, CalculationType> >
  145. {
  146. typedef strategy_tag_distance_point_point type;
  147. };
  148. template <typename RadiusType, typename CalculationType, typename P1, typename P2>
  149. struct return_type<haversine<RadiusType, CalculationType>, P1, P2>
  150. : haversine<RadiusType, CalculationType>::template calculation_type<P1, P2>
  151. {};
  152. template <typename RadiusType, typename CalculationType>
  153. struct comparable_type<haversine<RadiusType, CalculationType> >
  154. {
  155. typedef comparable::haversine<RadiusType, CalculationType> type;
  156. };
  157. template <typename RadiusType, typename CalculationType>
  158. struct get_comparable<haversine<RadiusType, CalculationType> >
  159. {
  160. private :
  161. typedef haversine<RadiusType, CalculationType> this_type;
  162. typedef comparable::haversine<RadiusType, CalculationType> comparable_type;
  163. public :
  164. static inline comparable_type apply(this_type const& input)
  165. {
  166. return comparable_type(input.radius());
  167. }
  168. };
  169. template <typename RadiusType, typename CalculationType, typename P1, typename P2>
  170. struct result_from_distance<haversine<RadiusType, CalculationType>, P1, P2>
  171. {
  172. private :
  173. typedef haversine<RadiusType, CalculationType> this_type;
  174. typedef typename return_type<this_type, P1, P2>::type return_type;
  175. public :
  176. template <typename T>
  177. static inline return_type apply(this_type const& , T const& value)
  178. {
  179. return return_type(value);
  180. }
  181. };
  182. // Specializations for comparable::haversine
  183. template <typename RadiusType, typename CalculationType>
  184. struct tag<comparable::haversine<RadiusType, CalculationType> >
  185. {
  186. typedef strategy_tag_distance_point_point type;
  187. };
  188. template <typename RadiusType, typename CalculationType, typename P1, typename P2>
  189. struct return_type<comparable::haversine<RadiusType, CalculationType>, P1, P2>
  190. : comparable::haversine<RadiusType, CalculationType>::template calculation_type<P1, P2>
  191. {};
  192. template <typename RadiusType, typename CalculationType>
  193. struct comparable_type<comparable::haversine<RadiusType, CalculationType> >
  194. {
  195. typedef comparable::haversine<RadiusType, CalculationType> type;
  196. };
  197. template <typename RadiusType, typename CalculationType>
  198. struct get_comparable<comparable::haversine<RadiusType, CalculationType> >
  199. {
  200. private :
  201. typedef comparable::haversine<RadiusType, CalculationType> this_type;
  202. public :
  203. static inline this_type apply(this_type const& input)
  204. {
  205. return input;
  206. }
  207. };
  208. template <typename RadiusType, typename CalculationType, typename P1, typename P2>
  209. struct result_from_distance<comparable::haversine<RadiusType, CalculationType>, P1, P2>
  210. {
  211. private :
  212. typedef comparable::haversine<RadiusType, CalculationType> strategy_type;
  213. typedef typename return_type<strategy_type, P1, P2>::type return_type;
  214. public :
  215. template <typename T>
  216. static inline return_type apply(strategy_type const& strategy, T const& distance)
  217. {
  218. return_type const s = sin((distance / strategy.radius()) / return_type(2));
  219. return s * s;
  220. }
  221. };
  222. // Register it as the default for point-types
  223. // in a spherical equatorial coordinate system
  224. template <typename Point1, typename Point2>
  225. struct default_strategy<point_tag, Point1, Point2, spherical_equatorial_tag, spherical_equatorial_tag>
  226. {
  227. typedef strategy::distance::haversine<typename select_coordinate_type<Point1, Point2>::type> type;
  228. };
  229. // Note: spherical polar coordinate system requires "get_as_radian_equatorial"
  230. } // namespace services
  231. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  232. }} // namespace strategy::distance
  233. }} // namespace boost::geometry
  234. #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_HAVERSINE_HPP