buffer_helper.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Boost.Geometry
  2. // Copyright (c) 2022 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_GEOGRAPHIC_BUFFER_HELPER_HPP
  7. #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_HELPER_HPP
  8. #include <boost/geometry/core/assert.hpp>
  9. #include <boost/geometry/core/radian_access.hpp>
  10. #include <boost/geometry/strategies/geographic/parameters.hpp>
  11. #include <boost/geometry/util/math.hpp>
  12. namespace boost { namespace geometry
  13. {
  14. namespace strategy { namespace buffer
  15. {
  16. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  17. template <typename FormulaPolicy, typename CalculationType>
  18. struct geographic_buffer_helper
  19. {
  20. static bool const enable_azimuth = true;
  21. static bool const enable_coordinates = true;
  22. using inverse = typename FormulaPolicy::template inverse
  23. <
  24. CalculationType, false, enable_azimuth, false, false, false
  25. >;
  26. using direct = typename FormulaPolicy::template direct
  27. <
  28. CalculationType, enable_coordinates, false, false, false
  29. >;
  30. // Calculates the azimuth using the inverse formula, where the first point
  31. // is specified by lon/lat (for pragmatic reasons) and the second point as a point.
  32. template <typename T, typename Point, typename Spheroid>
  33. static inline CalculationType azimuth(T const& lon_rad, T const& lat_rad,
  34. Point const& p, Spheroid const& spheroid)
  35. {
  36. return inverse::apply(lon_rad, lat_rad, get_as_radian<0>(p), get_as_radian<1>(p), spheroid).azimuth;
  37. }
  38. // Using specified points, distance and azimuth it calculates a new point
  39. // and appends it to the range
  40. template <typename T, typename Spheroid, typename RangeOut>
  41. static inline void append_point(T const& lon_rad, T const& lat_rad,
  42. T const& distance, T const& angle,
  43. Spheroid const& spheroid, RangeOut& range_out)
  44. {
  45. using point_t = typename boost::range_value<RangeOut>::type;
  46. point_t point;
  47. auto const d = direct::apply(lon_rad, lat_rad, distance, angle, spheroid);
  48. set_from_radian<0>(point, d.lon2);
  49. set_from_radian<1>(point, d.lat2);
  50. range_out.emplace_back(point);
  51. }
  52. // Calculates the angle diff and azimuth of a point (specified as lon/lat)
  53. // and two points, perpendicular in the buffer context.
  54. template <typename T, typename Point, typename Spheroid>
  55. static inline bool calculate_angles(T const& lon_rad, T const& lat_rad, Point const& perp1,
  56. Point const& perp2, Spheroid const& spheroid,
  57. T& angle_diff, T& first_azimuth)
  58. {
  59. T const inv1 = azimuth(lon_rad, lat_rad, perp1, spheroid);
  60. T const inv2 = azimuth(lon_rad, lat_rad, perp2, spheroid);
  61. static CalculationType const two_pi = geometry::math::two_pi<CalculationType>();
  62. static CalculationType const pi = geometry::math::pi<CalculationType>();
  63. // For a sharp corner, perpendicular points are nearly opposite and the
  64. // angle between the two azimuths can be nearly 180, but not more.
  65. angle_diff = inv2 < inv1 ? (two_pi + inv2) - inv1 : inv2 - inv1;
  66. if (angle_diff < 0 || angle_diff > pi)
  67. {
  68. // Defensive check with asserts
  69. BOOST_GEOMETRY_ASSERT(angle_diff >= 0);
  70. BOOST_GEOMETRY_ASSERT(angle_diff <= pi);
  71. return false;
  72. }
  73. first_azimuth = inv1;
  74. return true;
  75. }
  76. };
  77. #endif // DOXYGEN_SHOULD_SKIP_THIS
  78. }} // namespace strategy::buffer
  79. }} // namespace boost::geometry
  80. #endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_HELPER_HPP