File indexing completed on 2025-01-18 09:36:45
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_END_ROUND_HPP
0010 #define BOOST_GEOMETRY_STRATEGIES_GEOGRAPHIC_BUFFER_END_ROUND_HPP
0011
0012 #include <boost/range/value_type.hpp>
0013
0014 #include <boost/geometry/core/radian_access.hpp>
0015
0016 #include <boost/geometry/srs/spheroid.hpp>
0017 #include <boost/geometry/strategies/buffer.hpp>
0018 #include <boost/geometry/strategies/geographic/buffer_helper.hpp>
0019 #include <boost/geometry/strategies/geographic/parameters.hpp>
0020 #include <boost/geometry/util/math.hpp>
0021 #include <boost/geometry/util/select_calculation_type.hpp>
0022
0023
0024 namespace boost { namespace geometry
0025 {
0026
0027 namespace strategy { namespace buffer
0028 {
0029
0030 template
0031 <
0032 typename FormulaPolicy = strategy::andoyer,
0033 typename Spheroid = srs::spheroid<double>,
0034 typename CalculationType = void
0035 >
0036 class geographic_end_round
0037 {
0038 public :
0039
0040
0041
0042
0043 explicit inline geographic_end_round(Spheroid const& spheroid,
0044 std::size_t points_per_circle = default_points_per_circle)
0045 : m_spheroid(spheroid)
0046 , m_points_per_circle(get_point_count_for_end(points_per_circle))
0047 {}
0048
0049
0050
0051 explicit inline geographic_end_round(std::size_t points_per_circle = default_points_per_circle)
0052 : m_points_per_circle(get_point_count_for_end(points_per_circle))
0053 {}
0054
0055 #ifndef DOXYGEN_SHOULD_SKIP_THIS
0056 template <typename T, typename RangeOut>
0057 inline void generate(T lon_rad, T lat_rad, T distance, T azimuth, RangeOut& range_out) const
0058 {
0059 using helper = geographic_buffer_helper<FormulaPolicy, T>;
0060 std::size_t const n = m_points_per_circle / 2;
0061 T const angle_diff = geometry::math::pi<T>() / n;
0062 T azi = math::wrap_azimuth_in_radian(azimuth + angle_diff);
0063
0064
0065
0066 for (std::size_t i = 1; i < n; i++)
0067 {
0068 helper::append_point(lon_rad, lat_rad, distance, azi, m_spheroid, range_out);
0069 azi = math::wrap_azimuth_in_radian(azi + angle_diff);
0070 }
0071 }
0072
0073
0074 template <typename Point, typename DistanceStrategy, typename RangeOut>
0075 inline void apply(Point const& penultimate_point, Point const& perp_left_point,
0076 Point const& ultimate_point, Point const& perp_right_point,
0077 buffer_side_selector side, DistanceStrategy const& distance,
0078 RangeOut& range_out) const
0079 {
0080 using calc_t = typename select_calculation_type
0081 <
0082 Point,
0083 typename boost::range_value<RangeOut>::type,
0084 CalculationType
0085 >::type;
0086
0087 using helper = geographic_buffer_helper<FormulaPolicy, calc_t>;
0088
0089 calc_t const lon_rad = get_as_radian<0>(ultimate_point);
0090 calc_t const lat_rad = get_as_radian<1>(ultimate_point);
0091
0092 auto const azimuth = helper::azimuth(lon_rad, lat_rad, perp_left_point, m_spheroid);
0093
0094 calc_t const dist_left = distance.apply(penultimate_point, ultimate_point, buffer_side_left);
0095 calc_t const dist_right = distance.apply(penultimate_point, ultimate_point, buffer_side_right);
0096
0097 bool const reversed = (side == buffer_side_left && dist_right < 0 && -dist_right > dist_left)
0098 || (side == buffer_side_right && dist_left < 0 && -dist_left > dist_right)
0099 ;
0100
0101 if (reversed)
0102 {
0103 range_out.push_back(perp_right_point);
0104
0105 range_out.push_back(perp_left_point);
0106 }
0107 else
0108 {
0109 range_out.push_back(perp_left_point);
0110
0111 if (geometry::math::equals(dist_left, dist_right))
0112 {
0113 generate(lon_rad, lat_rad, dist_left, azimuth, range_out);
0114 }
0115 else
0116 {
0117 static calc_t const two = 2.0;
0118 calc_t const dist_average = (dist_left + dist_right) / two;
0119 calc_t const dist_half
0120 = (side == buffer_side_right
0121 ? (dist_right - dist_left)
0122 : (dist_left - dist_right)) / two;
0123 auto const shifted = helper::direct::apply(lon_rad, lat_rad, dist_half, azimuth, m_spheroid);
0124 generate(shifted.lon2, shifted.lat2, dist_average, azimuth, range_out);
0125 }
0126
0127 range_out.push_back(perp_right_point);
0128 }
0129 }
0130
0131 template <typename NumericType>
0132 static inline NumericType max_distance(NumericType const& distance)
0133 {
0134 return distance;
0135 }
0136
0137
0138 static inline piece_type get_piece_type()
0139 {
0140 return buffered_round_end;
0141 }
0142 #endif
0143
0144 private :
0145 Spheroid m_spheroid;
0146 std::size_t m_points_per_circle;
0147 };
0148
0149 }}
0150
0151 }}
0152
0153 #endif