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