gnomonic_intersection.hpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Boost.Geometry
  2. // Copyright (c) 2016 Oracle and/or its affiliates.
  3. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  4. // Use, modification and distribution is subject to the Boost Software License,
  5. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_GEOMETRY_FORMULAS_GNOMONIC_INTERSECTION_HPP
  8. #define BOOST_GEOMETRY_FORMULAS_GNOMONIC_INTERSECTION_HPP
  9. #include <boost/geometry/core/access.hpp>
  10. #include <boost/geometry/core/cs.hpp>
  11. #include <boost/geometry/arithmetic/cross_product.hpp>
  12. #include <boost/geometry/formulas/gnomonic_spheroid.hpp>
  13. #include <boost/geometry/geometries/point.hpp>
  14. #include <boost/geometry/util/math.hpp>
  15. namespace boost { namespace geometry { namespace formula
  16. {
  17. /*!
  18. \brief The intersection of two geodesics using spheroidal gnomonic projection
  19. as proposed by Karney.
  20. \author See
  21. - Charles F.F Karney, Algorithms for geodesics, 2011
  22. https://arxiv.org/pdf/1109.4448.pdf
  23. - GeographicLib forum thread: Intersection between two geodesic lines
  24. https://sourceforge.net/p/geographiclib/discussion/1026621/thread/21aaff9f/
  25. */
  26. template
  27. <
  28. typename CT,
  29. template <typename, bool, bool, bool, bool, bool> class Inverse,
  30. template <typename, bool, bool, bool, bool> class Direct
  31. >
  32. class gnomonic_intersection
  33. {
  34. public:
  35. template <typename T1, typename T2, typename Spheroid>
  36. static inline bool apply(T1 const& lona1, T1 const& lata1,
  37. T1 const& lona2, T1 const& lata2,
  38. T2 const& lonb1, T2 const& latb1,
  39. T2 const& lonb2, T2 const& latb2,
  40. CT & lon, CT & lat,
  41. Spheroid const& spheroid)
  42. {
  43. CT const lon_a1 = lona1;
  44. CT const lat_a1 = lata1;
  45. CT const lon_a2 = lona2;
  46. CT const lat_a2 = lata2;
  47. CT const lon_b1 = lonb1;
  48. CT const lat_b1 = latb1;
  49. CT const lon_b2 = lonb2;
  50. CT const lat_b2 = latb2;
  51. return apply(lon_a1, lat_a1, lon_a2, lat_a2, lon_b1, lat_b1, lon_b2, lat_b2, lon, lat, spheroid);
  52. }
  53. template <typename Spheroid>
  54. static inline bool apply(CT const& lona1, CT const& lata1,
  55. CT const& lona2, CT const& lata2,
  56. CT const& lonb1, CT const& latb1,
  57. CT const& lonb2, CT const& latb2,
  58. CT & lon, CT & lat,
  59. Spheroid const& spheroid)
  60. {
  61. typedef gnomonic_spheroid<CT, Inverse, Direct> gnom_t;
  62. lon = (lona1 + lona2 + lonb1 + lonb2) / 4;
  63. lat = (lata1 + lata2 + latb1 + latb2) / 4;
  64. // TODO: consider normalizing lon
  65. for (int i = 0; i < 10; ++i)
  66. {
  67. CT xa1, ya1, xa2, ya2;
  68. CT xb1, yb1, xb2, yb2;
  69. CT x, y;
  70. double lat1, lon1;
  71. bool ok = gnom_t::forward(lon, lat, lona1, lata1, xa1, ya1, spheroid)
  72. && gnom_t::forward(lon, lat, lona2, lata2, xa2, ya2, spheroid)
  73. && gnom_t::forward(lon, lat, lonb1, latb1, xb1, yb1, spheroid)
  74. && gnom_t::forward(lon, lat, lonb2, latb2, xb2, yb2, spheroid)
  75. && intersect(xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2, x, y)
  76. && gnom_t::inverse(lon, lat, x, y, lon1, lat1, spheroid);
  77. if (! ok)
  78. {
  79. return false;
  80. }
  81. if (math::equals(lat1, lat) && math::equals(lon1, lon))
  82. {
  83. break;
  84. }
  85. lat = lat1;
  86. lon = lon1;
  87. }
  88. // NOTE: true is also returned if the number of iterations is too great
  89. // which means that the accuracy of the result is low
  90. return true;
  91. }
  92. private:
  93. static inline bool intersect(CT const& xa1, CT const& ya1, CT const& xa2, CT const& ya2,
  94. CT const& xb1, CT const& yb1, CT const& xb2, CT const& yb2,
  95. CT & x, CT & y)
  96. {
  97. typedef model::point<CT, 3, cs::cartesian> v3d_t;
  98. CT const c0 = 0;
  99. CT const c1 = 1;
  100. v3d_t const va1(xa1, ya1, c1);
  101. v3d_t const va2(xa2, ya2, c1);
  102. v3d_t const vb1(xb1, yb1, c1);
  103. v3d_t const vb2(xb2, yb2, c1);
  104. v3d_t const la = cross_product(va1, va2);
  105. v3d_t const lb = cross_product(vb1, vb2);
  106. v3d_t const p = cross_product(la, lb);
  107. CT const z = get<2>(p);
  108. if (math::equals(z, c0))
  109. {
  110. // degenerated or collinear segments
  111. return false;
  112. }
  113. x = get<0>(p) / z;
  114. y = get<1>(p) / z;
  115. return true;
  116. }
  117. };
  118. }}} // namespace boost::geometry::formula
  119. #endif // BOOST_GEOMETRY_FORMULAS_GNOMONIC_INTERSECTION_HPP