buffer_join_miter.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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_JOIN_MITER_HPP
  7. #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_JOIN_MITER_HPP
  8. #include <boost/range/value_type.hpp>
  9. #include <boost/geometry/core/radian_access.hpp>
  10. #include <boost/geometry/srs/spheroid.hpp>
  11. #include <boost/geometry/strategies/buffer.hpp>
  12. #include <boost/geometry/strategies/geographic/buffer_helper.hpp>
  13. #include <boost/geometry/strategies/geographic/parameters.hpp>
  14. #include <boost/geometry/util/math.hpp>
  15. #include <boost/geometry/util/select_calculation_type.hpp>
  16. namespace boost { namespace geometry
  17. {
  18. namespace strategy { namespace buffer
  19. {
  20. template
  21. <
  22. typename FormulaPolicy = strategy::andoyer,
  23. typename Spheroid = srs::spheroid<double>,
  24. typename CalculationType = void
  25. >
  26. class geographic_join_miter
  27. {
  28. public :
  29. //! \brief Constructs the strategy with a spheroid
  30. //! \param spheroid The spheroid to be used
  31. //! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners
  32. explicit inline geographic_join_miter(Spheroid const& spheroid,
  33. double miter_limit = 5.0)
  34. : m_spheroid(spheroid)
  35. , m_miter_limit(valid_limit(miter_limit))
  36. {}
  37. //! \brief Constructs the strategy
  38. //! \param miter_limit The miter limit, to avoid excessively long miters around sharp corners
  39. explicit inline geographic_join_miter(double miter_limit = 5.0)
  40. : m_miter_limit(valid_limit(miter_limit))
  41. {}
  42. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  43. //! Fills output_range with a sharp shape around a vertex
  44. template <typename Point, typename DistanceType, typename RangeOut>
  45. inline bool apply(Point const& , Point const& vertex,
  46. Point const& perp1, Point const& perp2,
  47. DistanceType const& buffer_distance,
  48. RangeOut& range_out) const
  49. {
  50. using calc_t = typename select_calculation_type
  51. <
  52. Point,
  53. typename boost::range_value<RangeOut>::type,
  54. CalculationType
  55. >::type;
  56. using helper = geographic_buffer_helper<FormulaPolicy, calc_t>;
  57. calc_t const lon_rad = get_as_radian<0>(vertex);
  58. calc_t const lat_rad = get_as_radian<1>(vertex);
  59. calc_t first_azimuth;
  60. calc_t angle_diff;
  61. if (! helper::calculate_angles(lon_rad, lat_rad, perp1, perp2, m_spheroid,
  62. angle_diff, first_azimuth))
  63. {
  64. return false;
  65. }
  66. calc_t const half = 0.5;
  67. calc_t const half_angle_diff = half * angle_diff;
  68. calc_t const azi = math::wrap_azimuth_in_radian(first_azimuth + half_angle_diff);
  69. calc_t const cos_angle = std::cos(half_angle_diff);
  70. if (cos_angle == 0)
  71. {
  72. // It is opposite, perp1==perp2, do not generate a miter cap
  73. return false;
  74. }
  75. // If it is sharp (angle close to 0), the distance will become too high and will be capped.
  76. calc_t const max_distance = m_miter_limit * geometry::math::abs(buffer_distance);
  77. calc_t const distance = (std::min)(max_distance, buffer_distance / cos_angle);
  78. range_out.push_back(perp1);
  79. helper::append_point(lon_rad, lat_rad, distance, azi, m_spheroid, range_out);
  80. range_out.push_back(perp2);
  81. return true;
  82. }
  83. template <typename NumericType>
  84. inline NumericType max_distance(NumericType const& distance) const
  85. {
  86. return distance * m_miter_limit;
  87. }
  88. #endif // DOXYGEN_SHOULD_SKIP_THIS
  89. private :
  90. double valid_limit(double miter_limit) const
  91. {
  92. if (miter_limit < 1.0)
  93. {
  94. // It should always exceed the buffer distance
  95. miter_limit = 1.0;
  96. }
  97. return miter_limit;
  98. }
  99. Spheroid m_spheroid;
  100. double m_miter_limit;
  101. };
  102. }} // namespace strategy::buffer
  103. }} // namespace boost::geometry
  104. #endif // BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_JOIN_MITER_HPP