File indexing completed on 2025-07-09 08:10:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_FORMULAS_VINCENTY_INVERSE_HPP
0015 #define BOOST_GEOMETRY_FORMULAS_VINCENTY_INVERSE_HPP
0016
0017
0018 #include <boost/math/constants/constants.hpp>
0019
0020 #include <boost/geometry/core/radius.hpp>
0021
0022 #include <boost/geometry/util/constexpr.hpp>
0023 #include <boost/geometry/util/math.hpp>
0024
0025 #include <boost/geometry/formulas/differential_quantities.hpp>
0026 #include <boost/geometry/formulas/flattening.hpp>
0027 #include <boost/geometry/formulas/result_inverse.hpp>
0028
0029
0030 #ifndef BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS
0031 #define BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS 1000
0032 #endif
0033
0034
0035 namespace boost { namespace geometry { namespace formula
0036 {
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049 template <
0050 typename CT,
0051 bool EnableDistance,
0052 bool EnableAzimuth,
0053 bool EnableReverseAzimuth = false,
0054 bool EnableReducedLength = false,
0055 bool EnableGeodesicScale = false
0056 >
0057 struct vincenty_inverse
0058 {
0059 static const bool CalcQuantities = EnableReducedLength || EnableGeodesicScale;
0060 static const bool CalcAzimuths = EnableAzimuth || EnableReverseAzimuth || CalcQuantities;
0061 static const bool CalcFwdAzimuth = EnableAzimuth || CalcQuantities;
0062 static const bool CalcRevAzimuth = EnableReverseAzimuth || CalcQuantities;
0063
0064 public:
0065 typedef result_inverse<CT> result_type;
0066
0067 template <typename T1, typename T2, typename Spheroid>
0068 static inline result_type apply(T1 const& lon1,
0069 T1 const& lat1,
0070 T2 const& lon2,
0071 T2 const& lat2,
0072 Spheroid const& spheroid)
0073 {
0074 result_type result;
0075
0076 if (math::equals(lat1, lat2) && math::equals(lon1, lon2))
0077 {
0078 return result;
0079 }
0080
0081 CT const c0 = 0;
0082 CT const c1 = 1;
0083 CT const c2 = 2;
0084 CT const c3 = 3;
0085 CT const c4 = 4;
0086 CT const c16 = 16;
0087 CT const c_e_12 = CT(1e-12);
0088
0089 CT const pi = geometry::math::pi<CT>();
0090 CT const two_pi = c2 * pi;
0091
0092
0093 CT L = lon2 - lon1;
0094 CT lambda = L;
0095
0096 if (L < -pi) L += two_pi;
0097 if (L > pi) L -= two_pi;
0098
0099 CT const radius_a = CT(get_radius<0>(spheroid));
0100 CT const radius_b = CT(get_radius<2>(spheroid));
0101 CT const f = formula::flattening<CT>(spheroid);
0102
0103
0104 CT const one_min_f = c1 - f;
0105 CT const tan_U1 = one_min_f * tan(lat1);
0106 CT const tan_U2 = one_min_f * tan(lat2);
0107
0108
0109 CT const temp_den_U1 = math::sqrt(c1 + math::sqr(tan_U1));
0110 CT const temp_den_U2 = math::sqrt(c1 + math::sqr(tan_U2));
0111
0112 CT const cos_U1 = c1 / temp_den_U1;
0113 CT const cos_U2 = c1 / temp_den_U2;
0114
0115
0116 CT const sin_U1 = tan_U1 * cos_U1;
0117 CT const sin_U2 = tan_U2 * cos_U2;
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127 CT previous_lambda;
0128 CT sin_lambda;
0129 CT cos_lambda;
0130 CT sin_sigma;
0131 CT sin_alpha;
0132 CT cos2_alpha;
0133 CT cos_2sigma_m;
0134 CT cos2_2sigma_m;
0135 CT sigma;
0136
0137 int counter = 0;
0138
0139 do
0140 {
0141 previous_lambda = lambda;
0142 sin_lambda = sin(lambda);
0143 cos_lambda = cos(lambda);
0144 sin_sigma = math::sqrt(math::sqr(cos_U2 * sin_lambda) + math::sqr(cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda));
0145 CT cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda;
0146 sin_alpha = cos_U1 * cos_U2 * sin_lambda / sin_sigma;
0147 cos2_alpha = c1 - math::sqr(sin_alpha);
0148 cos_2sigma_m = math::equals(cos2_alpha, c0) ? c0 : cos_sigma - c2 * sin_U1 * sin_U2 / cos2_alpha;
0149 cos2_2sigma_m = math::sqr(cos_2sigma_m);
0150
0151 CT C = f/c16 * cos2_alpha * (c4 + f * (c4 - c3 * cos2_alpha));
0152 sigma = atan2(sin_sigma, cos_sigma);
0153 lambda = L + (c1 - C) * f * sin_alpha *
0154 (sigma + C * sin_sigma * (cos_2sigma_m + C * cos_sigma * (-c1 + c2 * cos2_2sigma_m)));
0155
0156 ++counter;
0157
0158 } while ( geometry::math::abs(previous_lambda - lambda) > c_e_12
0159 && geometry::math::abs(lambda) < pi
0160 && counter < BOOST_GEOMETRY_DETAIL_VINCENTY_MAX_STEPS );
0161
0162 if BOOST_GEOMETRY_CONSTEXPR (EnableDistance)
0163 {
0164
0165 CT const c6 = 6;
0166 CT const c47 = 47;
0167 CT const c74 = 74;
0168 CT const c128 = 128;
0169 CT const c256 = 256;
0170 CT const c175 = 175;
0171 CT const c320 = 320;
0172 CT const c768 = 768;
0173 CT const c1024 = 1024;
0174 CT const c4096 = 4096;
0175 CT const c16384 = 16384;
0176
0177
0178 CT sqr_u = cos2_alpha * ( math::sqr(radius_a / radius_b) - c1 );
0179
0180 CT A = c1 + sqr_u/c16384 * (c4096 + sqr_u * (-c768 + sqr_u * (c320 - c175 * sqr_u)));
0181 CT B = sqr_u/c1024 * (c256 + sqr_u * ( -c128 + sqr_u * (c74 - c47 * sqr_u)));
0182 CT const cos_sigma = cos(sigma);
0183 CT const sin2_sigma = math::sqr(sin_sigma);
0184 CT delta_sigma = B * sin_sigma * (cos_2sigma_m + (B/c4) * (cos_sigma* (-c1 + c2 * cos2_2sigma_m)
0185 - (B/c6) * cos_2sigma_m * (-c3 + c4 * sin2_sigma) * (-c3 + c4 * cos2_2sigma_m)));
0186
0187 result.distance = radius_b * A * (sigma - delta_sigma);
0188 }
0189
0190 if BOOST_GEOMETRY_CONSTEXPR (CalcAzimuths)
0191 {
0192 if BOOST_GEOMETRY_CONSTEXPR (CalcFwdAzimuth)
0193 {
0194 result.azimuth = atan2(cos_U2 * sin_lambda, cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda);
0195 }
0196
0197 if BOOST_GEOMETRY_CONSTEXPR (CalcRevAzimuth)
0198 {
0199 result.reverse_azimuth = atan2(cos_U1 * sin_lambda, -sin_U1 * cos_U2 + cos_U1 * sin_U2 * cos_lambda);
0200 }
0201 }
0202
0203 if BOOST_GEOMETRY_CONSTEXPR (CalcQuantities)
0204 {
0205 typedef differential_quantities<CT, EnableReducedLength, EnableGeodesicScale, 2> quantities;
0206 quantities::apply(lon1, lat1, lon2, lat2,
0207 result.azimuth, result.reverse_azimuth,
0208 radius_b, f,
0209 result.reduced_length, result.geodesic_scale);
0210 }
0211
0212 return result;
0213 }
0214 };
0215
0216 }}}
0217
0218
0219 #endif