distance_cross_track_point_box.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
  3. // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
  4. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
  5. // This file was modified by Oracle on 2014-2017.
  6. // Modifications copyright (c) 2014-2017, Oracle and/or its affiliates.
  7. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
  8. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  9. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  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. #ifndef BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
  14. #define BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP
  15. #include <boost/config.hpp>
  16. #include <boost/concept_check.hpp>
  17. #include <boost/mpl/if.hpp>
  18. #include <boost/type_traits/is_void.hpp>
  19. #include <boost/geometry/core/access.hpp>
  20. #include <boost/geometry/core/assert.hpp>
  21. #include <boost/geometry/core/point_type.hpp>
  22. #include <boost/geometry/core/radian_access.hpp>
  23. #include <boost/geometry/core/tags.hpp>
  24. #include <boost/geometry/strategies/distance.hpp>
  25. #include <boost/geometry/strategies/concepts/distance_concept.hpp>
  26. #include <boost/geometry/strategies/spherical/distance_cross_track.hpp>
  27. #include <boost/geometry/util/math.hpp>
  28. #include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
  29. namespace boost { namespace geometry
  30. {
  31. namespace strategy { namespace distance
  32. {
  33. namespace details
  34. {
  35. template <typename ReturnType>
  36. class cross_track_point_box_generic
  37. {
  38. public :
  39. template
  40. <
  41. typename Point,
  42. typename Box,
  43. typename Strategy
  44. >
  45. ReturnType static inline apply (Point const& point,
  46. Box const& box,
  47. Strategy ps_strategy)
  48. {
  49. // this method assumes that the coordinates of the point and
  50. // the box are normalized
  51. typedef typename point_type<Box>::type box_point_type;
  52. box_point_type bottom_left, bottom_right, top_left, top_right;
  53. geometry::detail::assign_box_corners(box,
  54. bottom_left, bottom_right,
  55. top_left, top_right);
  56. ReturnType const plon = geometry::get_as_radian<0>(point);
  57. ReturnType const plat = geometry::get_as_radian<1>(point);
  58. ReturnType const lon_min = geometry::get_as_radian<0>(bottom_left);
  59. ReturnType const lat_min = geometry::get_as_radian<1>(bottom_left);
  60. ReturnType const lon_max = geometry::get_as_radian<0>(top_right);
  61. ReturnType const lat_max = geometry::get_as_radian<1>(top_right);
  62. ReturnType const pi = math::pi<ReturnType>();
  63. ReturnType const two_pi = math::two_pi<ReturnType>();
  64. typedef typename point_type<Box>::type box_point_type;
  65. // First check if the point is within the band defined by the
  66. // minimum and maximum longitude of the box; if yes, determine
  67. // if the point is above, below or inside the box and compute
  68. // the distance (easy in this case)
  69. //
  70. // Notice that the point may not be inside the longitude range
  71. // of the box, but the shifted point may be inside the
  72. // longitude range of the box; in this case the point is still
  73. // considered as inside the longitude range band of the box
  74. if ((plon >= lon_min && plon <= lon_max) || plon + two_pi <= lon_max)
  75. {
  76. if (plat > lat_max)
  77. {
  78. return geometry::strategy::distance::services::result_from_distance
  79. <
  80. Strategy, Point, box_point_type
  81. >::apply(ps_strategy, ps_strategy
  82. .vertical_or_meridian(plat, lat_max));
  83. }
  84. else if (plat < lat_min)
  85. {
  86. return geometry::strategy::distance::services::result_from_distance
  87. <
  88. Strategy, Point, box_point_type
  89. >::apply(ps_strategy, ps_strategy
  90. .vertical_or_meridian(lat_min, plat));
  91. }
  92. else
  93. {
  94. BOOST_GEOMETRY_ASSERT(plat >= lat_min && plat <= lat_max);
  95. return ReturnType(0);
  96. }
  97. }
  98. // Otherwise determine which among the two medirian segments of the
  99. // box the point is closest to, and compute the distance of
  100. // the point to this closest segment
  101. // Below lon_midway is the longitude of the meridian that:
  102. // (1) is midway between the meridians of the left and right
  103. // meridians of the box, and
  104. // (2) does not intersect the box
  105. ReturnType const two = 2.0;
  106. bool use_left_segment;
  107. if (lon_max > pi)
  108. {
  109. // the box crosses the antimeridian
  110. // midway longitude = lon_min - (lon_min + (lon_max - 2 * pi)) / 2;
  111. ReturnType const lon_midway = (lon_min - lon_max) / two + pi;
  112. BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
  113. use_left_segment = plon > lon_midway;
  114. }
  115. else
  116. {
  117. // the box does not cross the antimeridian
  118. ReturnType const lon_sum = lon_min + lon_max;
  119. if (math::equals(lon_sum, ReturnType(0)))
  120. {
  121. // special case: the box is symmetric with respect to
  122. // the prime meridian; the midway meridian is the antimeridian
  123. use_left_segment = plon < lon_min;
  124. }
  125. else
  126. {
  127. // midway long. = lon_min - (2 * pi - (lon_max - lon_min)) / 2;
  128. ReturnType lon_midway = (lon_min + lon_max) / two - pi;
  129. // normalize the midway longitude
  130. if (lon_midway > pi)
  131. {
  132. lon_midway -= two_pi;
  133. }
  134. else if (lon_midway < -pi)
  135. {
  136. lon_midway += two_pi;
  137. }
  138. BOOST_GEOMETRY_ASSERT(lon_midway >= -pi && lon_midway <= pi);
  139. // if lon_sum is positive the midway meridian is left
  140. // of the box, or right of the box otherwise
  141. use_left_segment = lon_sum > 0
  142. ? (plon < lon_min && plon >= lon_midway)
  143. : (plon <= lon_max || plon > lon_midway);
  144. }
  145. }
  146. return use_left_segment
  147. ? ps_strategy.apply(point, bottom_left, top_left)
  148. : ps_strategy.apply(point, bottom_right, top_right);
  149. }
  150. };
  151. } //namespace details
  152. /*!
  153. \brief Strategy functor for distance point to box calculation
  154. \ingroup strategies
  155. \details Class which calculates the distance of a point to a box, for
  156. points and boxes on a sphere or globe
  157. \tparam CalculationType \tparam_calculation
  158. \tparam Strategy underlying point-point distance strategy
  159. \qbk{
  160. [heading See also]
  161. [link geometry.reference.algorithms.distance.distance_3_with_strategy distance (with strategy)]
  162. }
  163. */
  164. template
  165. <
  166. typename CalculationType = void,
  167. typename Strategy = haversine<double, CalculationType>
  168. >
  169. class cross_track_point_box
  170. {
  171. public:
  172. template <typename Point, typename Box>
  173. struct return_type
  174. : services::return_type<Strategy, Point, typename point_type<Box>::type>
  175. {};
  176. typedef typename Strategy::radius_type radius_type;
  177. // strategy getters
  178. // point-segment strategy getters
  179. struct distance_ps_strategy
  180. {
  181. typedef cross_track<CalculationType, Strategy> type;
  182. };
  183. typedef typename strategy::distance::services::comparable_type
  184. <
  185. Strategy
  186. >::type pp_comparable_strategy;
  187. typedef typename boost::mpl::if_
  188. <
  189. boost::is_same
  190. <
  191. pp_comparable_strategy,
  192. Strategy
  193. >,
  194. typename strategy::distance::services::comparable_type
  195. <
  196. typename distance_ps_strategy::type
  197. >::type,
  198. typename distance_ps_strategy::type
  199. >::type ps_strategy_type;
  200. // constructors
  201. inline cross_track_point_box()
  202. {}
  203. explicit inline cross_track_point_box(typename Strategy::radius_type const& r)
  204. : m_strategy(r)
  205. {}
  206. inline cross_track_point_box(Strategy const& s)
  207. : m_strategy(s)
  208. {}
  209. // methods
  210. // It might be useful in the future
  211. // to overload constructor with strategy info.
  212. // crosstrack(...) {}
  213. template <typename Point, typename Box>
  214. inline typename return_type<Point, Box>::type
  215. apply(Point const& point, Box const& box) const
  216. {
  217. #if !defined(BOOST_MSVC)
  218. BOOST_CONCEPT_ASSERT
  219. (
  220. (concepts::PointDistanceStrategy
  221. <
  222. Strategy, Point, typename point_type<Box>::type
  223. >)
  224. );
  225. #endif
  226. typedef typename return_type<Point, Box>::type return_type;
  227. return details::cross_track_point_box_generic
  228. <return_type>::apply(point, box,
  229. ps_strategy_type(m_strategy));
  230. }
  231. inline typename Strategy::radius_type radius() const
  232. {
  233. return m_strategy.radius();
  234. }
  235. private:
  236. Strategy m_strategy;
  237. };
  238. #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  239. namespace services
  240. {
  241. template <typename CalculationType, typename Strategy>
  242. struct tag<cross_track_point_box<CalculationType, Strategy> >
  243. {
  244. typedef strategy_tag_distance_point_box type;
  245. };
  246. template <typename CalculationType, typename Strategy, typename P, typename Box>
  247. struct return_type<cross_track_point_box<CalculationType, Strategy>, P, Box>
  248. : cross_track_point_box
  249. <
  250. CalculationType, Strategy
  251. >::template return_type<P, Box>
  252. {};
  253. template <typename CalculationType, typename Strategy>
  254. struct comparable_type<cross_track_point_box<CalculationType, Strategy> >
  255. {
  256. typedef cross_track_point_box
  257. <
  258. CalculationType, typename comparable_type<Strategy>::type
  259. > type;
  260. };
  261. template <typename CalculationType, typename Strategy>
  262. struct get_comparable<cross_track_point_box<CalculationType, Strategy> >
  263. {
  264. typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
  265. typedef typename comparable_type<this_strategy>::type comparable_type;
  266. public:
  267. static inline comparable_type apply(this_strategy const& strategy)
  268. {
  269. return comparable_type(strategy.radius());
  270. }
  271. };
  272. template <typename CalculationType, typename Strategy, typename P, typename Box>
  273. struct result_from_distance
  274. <
  275. cross_track_point_box<CalculationType, Strategy>, P, Box
  276. >
  277. {
  278. private:
  279. typedef cross_track_point_box<CalculationType, Strategy> this_strategy;
  280. typedef typename this_strategy::template return_type
  281. <
  282. P, Box
  283. >::type return_type;
  284. public:
  285. template <typename T>
  286. static inline return_type apply(this_strategy const& strategy,
  287. T const& distance)
  288. {
  289. Strategy s(strategy.radius());
  290. return result_from_distance
  291. <
  292. Strategy, P, typename point_type<Box>::type
  293. >::apply(s, distance);
  294. }
  295. };
  296. // define cross_track_point_box<default_point_segment_strategy> as
  297. // default point-box strategy for the spherical equatorial coordinate system
  298. template <typename Point, typename Box, typename Strategy>
  299. struct default_strategy
  300. <
  301. point_tag, box_tag, Point, Box,
  302. spherical_equatorial_tag, spherical_equatorial_tag,
  303. Strategy
  304. >
  305. {
  306. typedef cross_track_point_box
  307. <
  308. void,
  309. typename boost::mpl::if_
  310. <
  311. boost::is_void<Strategy>,
  312. typename default_strategy
  313. <
  314. point_tag, point_tag,
  315. Point, typename point_type<Box>::type,
  316. spherical_equatorial_tag, spherical_equatorial_tag
  317. >::type,
  318. Strategy
  319. >::type
  320. > type;
  321. };
  322. template <typename Box, typename Point, typename Strategy>
  323. struct default_strategy
  324. <
  325. box_tag, point_tag, Box, Point,
  326. spherical_equatorial_tag, spherical_equatorial_tag,
  327. Strategy
  328. >
  329. {
  330. typedef typename default_strategy
  331. <
  332. point_tag, box_tag, Point, Box,
  333. spherical_equatorial_tag, spherical_equatorial_tag,
  334. Strategy
  335. >::type type;
  336. };
  337. } // namespace services
  338. #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
  339. }} // namespace strategy::distance
  340. }} // namespace boost::geometry
  341. #endif // BOOST_GEOMETRY_STRATEGIES_SPHERICAL_DISTANCE_CROSS_TRACK_POINT_BOX_HPP