direction_code.hpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
  3. // This file was modified by Oracle on 2015, 2017.
  4. // Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
  5. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
  6. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  7. // Use, modification and distribution is subject to the Boost Software License,
  8. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
  11. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
  12. #include <boost/geometry/core/access.hpp>
  13. #include <boost/geometry/util/math.hpp>
  14. #include <boost/geometry/util/select_coordinate_type.hpp>
  15. #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
  16. #include <boost/mpl/assert.hpp>
  17. namespace boost { namespace geometry
  18. {
  19. #ifndef DOXYGEN_NO_DETAIL
  20. namespace detail
  21. {
  22. // TODO: remove
  23. template <std::size_t Index, typename Point1, typename Point2>
  24. inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
  25. {
  26. return
  27. math::equals(geometry::get<Index>(point1), geometry::get<Index>(point2))
  28. ?
  29. 0
  30. :
  31. (geometry::get<Index>(point1) > geometry::get<Index>(point2) ? 1 : -1);
  32. }
  33. template <typename Point, typename CSTag = typename cs_tag<Point>::type>
  34. struct direction_code_impl
  35. {
  36. BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag));
  37. };
  38. template <typename Point>
  39. struct direction_code_impl<Point, cartesian_tag>
  40. {
  41. template <typename Point1, typename Point2>
  42. static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
  43. Point2 const& p)
  44. {
  45. typedef typename geometry::select_coordinate_type
  46. <
  47. Point1, Point2
  48. >::type calc_t;
  49. if ( (math::equals(geometry::get<0>(segment_b), geometry::get<0>(segment_a))
  50. && math::equals(geometry::get<1>(segment_b), geometry::get<1>(segment_a)))
  51. || (math::equals(geometry::get<0>(segment_b), geometry::get<0>(p))
  52. && math::equals(geometry::get<1>(segment_b), geometry::get<1>(p))) )
  53. {
  54. return 0;
  55. }
  56. calc_t x1 = geometry::get<0>(segment_b) - geometry::get<0>(segment_a);
  57. calc_t y1 = geometry::get<1>(segment_b) - geometry::get<1>(segment_a);
  58. calc_t x2 = geometry::get<0>(segment_b) - geometry::get<0>(p);
  59. calc_t y2 = geometry::get<1>(segment_b) - geometry::get<1>(p);
  60. calc_t ax = (std::min)(math::abs(x1), math::abs(x2));
  61. calc_t ay = (std::min)(math::abs(y1), math::abs(y2));
  62. int s1 = 0, s2 = 0;
  63. if (ax >= ay)
  64. {
  65. s1 = x1 > 0 ? 1 : -1;
  66. s2 = x2 > 0 ? 1 : -1;
  67. }
  68. else
  69. {
  70. s1 = y1 > 0 ? 1 : -1;
  71. s2 = y2 > 0 ? 1 : -1;
  72. }
  73. return s1 == s2 ? -1 : 1;
  74. }
  75. };
  76. template <typename Point>
  77. struct direction_code_impl<Point, spherical_equatorial_tag>
  78. {
  79. template <typename Point1, typename Point2>
  80. static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
  81. Point2 const& p)
  82. {
  83. typedef typename coordinate_type<Point1>::type coord1_t;
  84. typedef typename coordinate_type<Point2>::type coord2_t;
  85. typedef typename coordinate_system<Point1>::type::units units_t;
  86. typedef typename coordinate_system<Point2>::type::units units2_t;
  87. BOOST_MPL_ASSERT_MSG((boost::is_same<units_t, units2_t>::value),
  88. NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS,
  89. (units_t, units2_t));
  90. typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t;
  91. typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1;
  92. typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2;
  93. static coord1_t const pi_half1 = constants1::max_latitude();
  94. static coord2_t const pi_half2 = constants2::max_latitude();
  95. static calc_t const c0 = 0;
  96. coord1_t const a0 = geometry::get<0>(segment_a);
  97. coord1_t const a1 = geometry::get<1>(segment_a);
  98. coord1_t const b0 = geometry::get<0>(segment_b);
  99. coord1_t const b1 = geometry::get<1>(segment_b);
  100. coord2_t const p0 = geometry::get<0>(p);
  101. coord2_t const p1 = geometry::get<1>(p);
  102. if ( (math::equals(b0, a0) && math::equals(b1, a1))
  103. || (math::equals(b0, p0) && math::equals(b1, p1)) )
  104. {
  105. return 0;
  106. }
  107. bool const is_a_pole = math::equals(pi_half1, math::abs(a1));
  108. bool const is_b_pole = math::equals(pi_half1, math::abs(b1));
  109. bool const is_p_pole = math::equals(pi_half2, math::abs(p1));
  110. if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1))
  111. || (is_p_pole && math::sign(b1) == math::sign(p1))) )
  112. {
  113. return 0;
  114. }
  115. // NOTE: as opposed to the implementation for cartesian CS
  116. // here point b is the origin
  117. calc_t const dlon1 = math::longitude_distance_signed<units_t, calc_t>(b0, a0);
  118. calc_t const dlon2 = math::longitude_distance_signed<units_t, calc_t>(b0, p0);
  119. bool is_antilon1 = false, is_antilon2 = false;
  120. calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1);
  121. calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2);
  122. calc_t mx = is_a_pole || is_b_pole || is_p_pole ?
  123. c0 :
  124. (std::min)(is_antilon1 ? c0 : math::abs(dlon1),
  125. is_antilon2 ? c0 : math::abs(dlon2));
  126. calc_t my = (std::min)(math::abs(dlat1),
  127. math::abs(dlat2));
  128. int s1 = 0, s2 = 0;
  129. if (mx >= my)
  130. {
  131. s1 = dlon1 > 0 ? 1 : -1;
  132. s2 = dlon2 > 0 ? 1 : -1;
  133. }
  134. else
  135. {
  136. s1 = dlat1 > 0 ? 1 : -1;
  137. s2 = dlat2 > 0 ? 1 : -1;
  138. }
  139. return s1 == s2 ? -1 : 1;
  140. }
  141. template <typename Units, typename T>
  142. static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon)
  143. {
  144. typedef math::detail::constants_on_spheroid<T, Units> constants;
  145. static T const pi = constants::half_period();
  146. static T const c0 = 0;
  147. T res = lat2 - lat1;
  148. is_antilon = math::equals(math::abs(lon_ds), pi);
  149. if (is_antilon)
  150. {
  151. res = lat2 + lat1;
  152. if (res >= c0)
  153. res = pi - res;
  154. else
  155. res = -pi - res;
  156. }
  157. return res;
  158. }
  159. };
  160. template <typename Point>
  161. struct direction_code_impl<Point, spherical_polar_tag>
  162. {
  163. template <typename Point1, typename Point2>
  164. static inline int apply(Point1 segment_a, Point1 segment_b,
  165. Point2 p)
  166. {
  167. typedef math::detail::constants_on_spheroid
  168. <
  169. typename coordinate_type<Point1>::type,
  170. typename coordinate_system<Point1>::type::units
  171. > constants1;
  172. typedef math::detail::constants_on_spheroid
  173. <
  174. typename coordinate_type<Point2>::type,
  175. typename coordinate_system<Point2>::type::units
  176. > constants2;
  177. geometry::set<1>(segment_a,
  178. constants1::max_latitude() - geometry::get<1>(segment_a));
  179. geometry::set<1>(segment_b,
  180. constants1::max_latitude() - geometry::get<1>(segment_b));
  181. geometry::set<1>(p,
  182. constants2::max_latitude() - geometry::get<1>(p));
  183. return direction_code_impl
  184. <
  185. Point, spherical_equatorial_tag
  186. >::apply(segment_a, segment_b, p);
  187. }
  188. };
  189. template <typename Point>
  190. struct direction_code_impl<Point, geographic_tag>
  191. : direction_code_impl<Point, spherical_equatorial_tag>
  192. {};
  193. // Gives sense of direction for point p, collinear w.r.t. segment (a,b)
  194. // Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
  195. // Returns 1 if p goes forward, so extends (a,b)
  196. // Returns 0 if p is equal with b, or if (a,b) is degenerate
  197. // Note that it does not do any collinearity test, that should be done before
  198. template <typename Point1, typename Point2>
  199. inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
  200. Point2 const& p)
  201. {
  202. return direction_code_impl<Point1>::apply(segment_a, segment_b, p);
  203. }
  204. } // namespace detail
  205. #endif //DOXYGEN_NO_DETAIL
  206. }} // namespace boost::geometry
  207. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP