File indexing completed on 2025-01-18 09:35:25
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #ifndef BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP
0032 #define BOOST_GEOMETRY_FORMULAS_KARNEY_DIRECT_HPP
0033
0034
0035 #include <boost/math/constants/constants.hpp>
0036 #include <boost/math/special_functions/hypot.hpp>
0037
0038 #include <boost/geometry/formulas/flattening.hpp>
0039 #include <boost/geometry/formulas/result_direct.hpp>
0040
0041 #include <boost/geometry/util/condition.hpp>
0042 #include <boost/geometry/util/math.hpp>
0043 #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
0044 #include <boost/geometry/util/series_expansion.hpp>
0045
0046
0047 namespace boost { namespace geometry { namespace formula
0048 {
0049
0050 namespace se = series_expansion;
0051
0052
0053
0054
0055
0056
0057
0058
0059 template <
0060 typename CT,
0061 bool EnableCoordinates = true,
0062 bool EnableReverseAzimuth = false,
0063 bool EnableReducedLength = false,
0064 bool EnableGeodesicScale = false,
0065 size_t SeriesOrder = 8
0066 >
0067 class karney_direct
0068 {
0069 static const bool CalcQuantities = EnableReducedLength || EnableGeodesicScale;
0070 static const bool CalcCoordinates = EnableCoordinates || CalcQuantities;
0071 static const bool CalcRevAzimuth = EnableReverseAzimuth || CalcCoordinates || CalcQuantities;
0072
0073 public:
0074 typedef result_direct<CT> result_type;
0075
0076 template <typename T, typename Dist, typename Azi, typename Spheroid>
0077 static inline result_type apply(T const& lo1,
0078 T const& la1,
0079 Dist const& distance,
0080 Azi const& azimuth12,
0081 Spheroid const& spheroid)
0082 {
0083 result_type result;
0084
0085 CT lon1 = lo1 * math::r2d<CT>();
0086 CT const lat1 = la1 * math::r2d<CT>();
0087
0088 Azi azi12 = azimuth12 * math::r2d<CT>();
0089 math::normalize_azimuth<degree, Azi>(azi12);
0090
0091 CT const c0 = 0;
0092 CT const c1 = 1;
0093 CT const c2 = 2;
0094
0095 CT const b = CT(get_radius<2>(spheroid));
0096 CT const f = formula::flattening<CT>(spheroid);
0097 CT const one_minus_f = c1 - f;
0098 CT const two_minus_f = c2 - f;
0099
0100 CT const n = f / two_minus_f;
0101 CT const e2 = f * two_minus_f;
0102 CT const ep2 = e2 / math::sqr(one_minus_f);
0103
0104 CT sin_alpha1, cos_alpha1;
0105 math::sin_cos_degrees<CT>(azi12, sin_alpha1, cos_alpha1);
0106
0107
0108 CT sin_beta1, cos_beta1;
0109 math::sin_cos_degrees<CT>(lat1, sin_beta1, cos_beta1);
0110 sin_beta1 *= one_minus_f;
0111
0112 math::normalize_unit_vector<CT>(sin_beta1, cos_beta1);
0113
0114 cos_beta1 = (std::max)(c0, cos_beta1);
0115
0116
0117 CT const sin_alpha0 = sin_alpha1 * cos_beta1;
0118 CT const cos_alpha0 = boost::math::hypot(cos_alpha1, sin_alpha1 * sin_beta1);
0119
0120 CT const k2 = math::sqr(cos_alpha0) * ep2;
0121
0122 CT const epsilon = k2 / (c2 * (c1 + math::sqrt(c1 + k2)) + k2);
0123
0124
0125
0126 CT const expansion_A1 = se::evaluate_A1<SeriesOrder>(epsilon);
0127
0128
0129 se::coeffs_C1<SeriesOrder, CT> const coeffs_C1(epsilon);
0130
0131
0132 CT const tau12 = distance / (b * (c1 + expansion_A1));
0133
0134 CT const sin_tau12 = sin(tau12);
0135 CT const cos_tau12 = cos(tau12);
0136
0137 CT sin_sigma1 = sin_beta1;
0138 CT sin_omega1 = sin_alpha0 * sin_beta1;
0139
0140 CT cos_sigma1, cos_omega1;
0141 cos_sigma1 = cos_omega1 = sin_beta1 != c0 || cos_alpha1 != c0 ? cos_beta1 * cos_alpha1 : c1;
0142 math::normalize_unit_vector<CT>(sin_sigma1, cos_sigma1);
0143
0144 CT const B11 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C1);
0145 CT const sin_B11 = sin(B11);
0146 CT const cos_B11 = cos(B11);
0147
0148 CT const sin_tau1 = sin_sigma1 * cos_B11 + cos_sigma1 * sin_B11;
0149 CT const cos_tau1 = cos_sigma1 * cos_B11 - sin_sigma1 * sin_B11;
0150
0151
0152 se::coeffs_C1p<SeriesOrder, CT> const coeffs_C1p(epsilon);
0153
0154 CT const B12 = - se::sin_cos_series(sin_tau1 * cos_tau12 + cos_tau1 * sin_tau12,
0155 cos_tau1 * cos_tau12 - sin_tau1 * sin_tau12,
0156 coeffs_C1p);
0157
0158 CT const sigma12 = tau12 - (B12 - B11);
0159 CT const sin_sigma12 = sin(sigma12);
0160 CT const cos_sigma12 = cos(sigma12);
0161
0162 CT const sin_sigma2 = sin_sigma1 * cos_sigma12 + cos_sigma1 * sin_sigma12;
0163 CT const cos_sigma2 = cos_sigma1 * cos_sigma12 - sin_sigma1 * sin_sigma12;
0164
0165 if (BOOST_GEOMETRY_CONDITION(CalcRevAzimuth))
0166 {
0167 CT const sin_alpha2 = sin_alpha0;
0168 CT const cos_alpha2 = cos_alpha0 * cos_sigma2;
0169
0170 result.reverse_azimuth = atan2(sin_alpha2, cos_alpha2);
0171 }
0172
0173 if (BOOST_GEOMETRY_CONDITION(CalcCoordinates))
0174 {
0175
0176 CT const sin_beta2 = cos_alpha0 * sin_sigma2;
0177 CT const cos_beta2 = boost::math::hypot(sin_alpha0, cos_alpha0 * cos_sigma2);
0178
0179 result.lat2 = atan2(sin_beta2, one_minus_f * cos_beta2);
0180
0181
0182 CT const sin_omega2 = sin_alpha0 * sin_sigma2;
0183 CT const cos_omega2 = cos_sigma2;
0184
0185 CT const omega12 = atan2(sin_omega2 * cos_omega1 - cos_omega2 * sin_omega1,
0186 cos_omega2 * cos_omega1 + sin_omega2 * sin_omega1);
0187
0188 se::coeffs_A3<SeriesOrder, CT> const coeffs_A3(n);
0189
0190 CT const A3 = math::horner_evaluate(epsilon, coeffs_A3.begin(), coeffs_A3.end());
0191 CT const A3c = -f * sin_alpha0 * A3;
0192
0193 se::coeffs_C3<SeriesOrder, CT> const coeffs_C3(n, epsilon);
0194
0195 CT const B31 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C3);
0196
0197 CT const sin_cos_res = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C3);
0198 CT const lam12 = omega12 + A3c * (sigma12 + (sin_cos_res - B31));
0199
0200
0201 CT lon12 = lam12 * math::r2d<CT>();
0202
0203
0204
0205 math::normalize_longitude<degree, CT>(lon1);
0206 math::normalize_longitude<degree, CT>(lon12);
0207
0208 result.lon2 = lon1 + lon12;
0209
0210
0211
0212
0213
0214
0215 math::normalize_longitude<degree, CT>(result.lon2);
0216
0217 result.lon2 *= math::d2r<CT>();
0218 }
0219
0220 if (BOOST_GEOMETRY_CONDITION(CalcQuantities))
0221 {
0222
0223
0224 se::coeffs_C2<SeriesOrder, CT> const coeffs_C2(epsilon);
0225
0226 CT const B21 = se::sin_cos_series(sin_sigma1, cos_sigma1, coeffs_C2);
0227 CT const B22 = se::sin_cos_series(sin_sigma2, cos_sigma2, coeffs_C2);
0228
0229
0230
0231 CT const expansion_A2 = se::evaluate_A2<SeriesOrder>(epsilon);
0232
0233 CT const AB1 = (c1 + expansion_A1) * (B12 - B11);
0234 CT const AB2 = (c1 + expansion_A2) * (B22 - B21);
0235 CT const J12 = (expansion_A1 - expansion_A2) * sigma12 + (AB1 - AB2);
0236
0237 CT const dn1 = math::sqrt(c1 + ep2 * math::sqr(sin_beta1));
0238 CT const dn2 = math::sqrt(c1 + k2 * math::sqr(sin_sigma2));
0239
0240
0241 result.reduced_length = b * ((dn2 * (cos_sigma1 * sin_sigma2) -
0242 dn1 * (sin_sigma1 * cos_sigma2)) -
0243 cos_sigma1 * cos_sigma2 * J12);
0244
0245
0246 CT const t = k2 * (sin_sigma2 - sin_sigma1) * (sin_sigma2 + sin_sigma1) / (dn1 + dn2);
0247
0248 result.geodesic_scale = cos_sigma12 + (t * sin_sigma2 - cos_sigma2 * J12) *
0249 sin_sigma1 / dn1;
0250 }
0251
0252 return result;
0253 }
0254 };
0255
0256 }}}
0257
0258
0259 #endif