File indexing completed on 2025-01-18 09:35:24
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_GEOMETRY_FORMULAS_INVERSE_DIFFERENTIAL_QUANTITIES_HPP
0013 #define BOOST_GEOMETRY_FORMULAS_INVERSE_DIFFERENTIAL_QUANTITIES_HPP
0014
0015 #include <boost/geometry/core/assert.hpp>
0016
0017 #include <boost/geometry/util/condition.hpp>
0018 #include <boost/geometry/util/math.hpp>
0019
0020
0021 namespace boost { namespace geometry { namespace formula
0022 {
0023
0024
0025
0026
0027
0028
0029
0030 template <
0031 typename CT,
0032 bool EnableReducedLength,
0033 bool EnableGeodesicScale,
0034 unsigned int Order = 2,
0035 bool ApproxF = true
0036 >
0037 class differential_quantities
0038 {
0039 public:
0040 static inline void apply(CT const& lon1, CT const& lat1,
0041 CT const& lon2, CT const& lat2,
0042 CT const& azimuth, CT const& reverse_azimuth,
0043 CT const& b, CT const& f,
0044 CT & reduced_length, CT & geodesic_scale)
0045 {
0046 CT const dlon = lon2 - lon1;
0047 CT const sin_lat1 = sin(lat1);
0048 CT const cos_lat1 = cos(lat1);
0049 CT const sin_lat2 = sin(lat2);
0050 CT const cos_lat2 = cos(lat2);
0051
0052 apply(dlon, sin_lat1, cos_lat1, sin_lat2, cos_lat2,
0053 azimuth, reverse_azimuth,
0054 b, f,
0055 reduced_length, geodesic_scale);
0056 }
0057
0058 static inline void apply(CT const& dlon,
0059 CT const& sin_lat1, CT const& cos_lat1,
0060 CT const& sin_lat2, CT const& cos_lat2,
0061 CT const& azimuth, CT const& reverse_azimuth,
0062 CT const& b, CT const& f,
0063 CT & reduced_length, CT & geodesic_scale)
0064 {
0065 CT const c0 = 0;
0066 CT const c1 = 1;
0067 CT const one_minus_f = c1 - f;
0068
0069 CT sin_bet1 = one_minus_f * sin_lat1;
0070 CT sin_bet2 = one_minus_f * sin_lat2;
0071
0072
0073 if (math::equals(sin_bet1, c0) && math::equals(sin_bet2, c0))
0074 {
0075 CT const sig_12 = dlon / one_minus_f;
0076 if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
0077 {
0078 BOOST_GEOMETRY_ASSERT((-math::pi<CT>() <= azimuth && azimuth <= math::pi<CT>()));
0079
0080 int azi_sign = math::sign(azimuth) >= 0 ? 1 : -1;
0081 CT m12 = azi_sign * sin(sig_12) * b;
0082 reduced_length = m12;
0083 }
0084
0085 if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
0086 {
0087 CT M12 = cos(sig_12);
0088 geodesic_scale = M12;
0089 }
0090 }
0091 else
0092 {
0093 CT const c2 = 2;
0094 CT const e2 = f * (c2 - f);
0095 CT const ep2 = e2 / math::sqr(one_minus_f);
0096
0097 CT const sin_alp1 = sin(azimuth);
0098 CT const cos_alp1 = cos(azimuth);
0099
0100 CT const cos_alp2 = cos(reverse_azimuth);
0101
0102 CT cos_bet1 = cos_lat1;
0103 CT cos_bet2 = cos_lat2;
0104
0105 normalize(sin_bet1, cos_bet1);
0106 normalize(sin_bet2, cos_bet2);
0107
0108 CT sin_sig1 = sin_bet1;
0109 CT cos_sig1 = cos_alp1 * cos_bet1;
0110 CT sin_sig2 = sin_bet2;
0111 CT cos_sig2 = cos_alp2 * cos_bet2;
0112
0113 normalize(sin_sig1, cos_sig1);
0114 normalize(sin_sig2, cos_sig2);
0115
0116 CT const sin_alp0 = sin_alp1 * cos_bet1;
0117 CT const cos_alp0_sqr = c1 - math::sqr(sin_alp0);
0118
0119 CT const J12 = BOOST_GEOMETRY_CONDITION(ApproxF) ?
0120 J12_f(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, f) :
0121 J12_ep_sqr(sin_sig1, cos_sig1, sin_sig2, cos_sig2, cos_alp0_sqr, ep2) ;
0122
0123 CT const dn1 = math::sqrt(c1 + ep2 * math::sqr(sin_bet1));
0124 CT const dn2 = math::sqrt(c1 + ep2 * math::sqr(sin_bet2));
0125
0126 if (BOOST_GEOMETRY_CONDITION(EnableReducedLength))
0127 {
0128 CT const m12_b = dn2 * (cos_sig1 * sin_sig2)
0129 - dn1 * (sin_sig1 * cos_sig2)
0130 - cos_sig1 * cos_sig2 * J12;
0131 CT const m12 = m12_b * b;
0132
0133 reduced_length = m12;
0134 }
0135
0136 if (BOOST_GEOMETRY_CONDITION(EnableGeodesicScale))
0137 {
0138 CT const cos_sig12 = cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2;
0139 CT const t = ep2 * (cos_bet1 - cos_bet2) * (cos_bet1 + cos_bet2) / (dn1 + dn2);
0140 CT const M12 = cos_sig12 + (t * sin_sig2 - cos_sig2 * J12) * sin_sig1 / dn1;
0141
0142 geodesic_scale = M12;
0143 }
0144 }
0145 }
0146
0147 private:
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 static inline CT J12_f(CT const& sin_sig1, CT const& cos_sig1,
0163 CT const& sin_sig2, CT const& cos_sig2,
0164 CT const& cos_alp0_sqr, CT const& f)
0165 {
0166 if (BOOST_GEOMETRY_CONDITION(Order == 0))
0167 {
0168 return 0;
0169 }
0170
0171 CT const c2 = 2;
0172
0173 CT const sig_12 = atan2(cos_sig1 * sin_sig2 - sin_sig1 * cos_sig2,
0174 cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2);
0175 CT const sin_2sig1 = c2 * cos_sig1 * sin_sig1;
0176 CT const sin_2sig2 = c2 * cos_sig2 * sin_sig2;
0177 CT const sin_2sig_12 = sin_2sig2 - sin_2sig1;
0178 CT const L1 = sig_12 - sin_2sig_12 / c2;
0179
0180 if (BOOST_GEOMETRY_CONDITION(Order == 1))
0181 {
0182 return cos_alp0_sqr * f * L1;
0183 }
0184
0185 CT const sin_4sig1 = c2 * sin_2sig1 * (math::sqr(cos_sig1) - math::sqr(sin_sig1));
0186 CT const sin_4sig2 = c2 * sin_2sig2 * (math::sqr(cos_sig2) - math::sqr(sin_sig2));
0187 CT const sin_4sig_12 = sin_4sig2 - sin_4sig1;
0188
0189 CT const c8 = 8;
0190 CT const c12 = 12;
0191 CT const c16 = 16;
0192 CT const c24 = 24;
0193
0194 CT const L2 = -( cos_alp0_sqr * sin_4sig_12
0195 + (-c8 * cos_alp0_sqr + c12) * sin_2sig_12
0196 + (c12 * cos_alp0_sqr - c24) * sig_12)
0197 / c16;
0198
0199 if (BOOST_GEOMETRY_CONDITION(Order == 2))
0200 {
0201 return cos_alp0_sqr * f * (L1 + f * L2);
0202 }
0203
0204 CT const c4 = 4;
0205 CT const c9 = 9;
0206 CT const c48 = 48;
0207 CT const c60 = 60;
0208 CT const c64 = 64;
0209 CT const c96 = 96;
0210 CT const c128 = 128;
0211 CT const c144 = 144;
0212
0213 CT const cos_alp0_quad = math::sqr(cos_alp0_sqr);
0214 CT const sin3_2sig1 = math::sqr(sin_2sig1) * sin_2sig1;
0215 CT const sin3_2sig2 = math::sqr(sin_2sig2) * sin_2sig2;
0216 CT const sin3_2sig_12 = sin3_2sig2 - sin3_2sig1;
0217
0218 CT const A = (c9 * cos_alp0_quad - c12 * cos_alp0_sqr) * sin_4sig_12;
0219 CT const B = c4 * cos_alp0_quad * sin3_2sig_12;
0220 CT const C = (-c48 * cos_alp0_quad + c96 * cos_alp0_sqr - c64) * sin_2sig_12;
0221 CT const D = (c60 * cos_alp0_quad - c144 * cos_alp0_sqr + c128) * sig_12;
0222
0223 CT const L3 = (A + B + C + D) / c64;
0224
0225
0226 return cos_alp0_sqr * f * (L1 + f * (L2 + f * L3));
0227 }
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 static inline CT J12_ep_sqr(CT const& sin_sig1, CT const& cos_sig1,
0242 CT const& sin_sig2, CT const& cos_sig2,
0243 CT const& cos_alp0_sqr, CT const& ep_sqr)
0244 {
0245 if (BOOST_GEOMETRY_CONDITION(Order == 0))
0246 {
0247 return 0;
0248 }
0249
0250 CT const c2 = 2;
0251 CT const c4 = 4;
0252
0253 CT const c2a0ep2 = cos_alp0_sqr * ep_sqr;
0254
0255 CT const sig_12 = atan2(cos_sig1 * sin_sig2 - sin_sig1 * cos_sig2,
0256 cos_sig1 * cos_sig2 + sin_sig1 * sin_sig2);
0257 CT const sin_2sig1 = c2 * cos_sig1 * sin_sig1;
0258 CT const sin_2sig2 = c2 * cos_sig2 * sin_sig2;
0259 CT const sin_2sig_12 = sin_2sig2 - sin_2sig1;
0260
0261 CT const L1 = (c2 * sig_12 - sin_2sig_12) / c4;
0262
0263 if (BOOST_GEOMETRY_CONDITION(Order == 1))
0264 {
0265 return c2a0ep2 * L1;
0266 }
0267
0268 CT const c8 = 8;
0269 CT const c64 = 64;
0270
0271 CT const sin_4sig1 = c2 * sin_2sig1 * (math::sqr(cos_sig1) - math::sqr(sin_sig1));
0272 CT const sin_4sig2 = c2 * sin_2sig2 * (math::sqr(cos_sig2) - math::sqr(sin_sig2));
0273 CT const sin_4sig_12 = sin_4sig2 - sin_4sig1;
0274
0275 CT const L2 = (sin_4sig_12 - c8 * sin_2sig_12 + 12 * sig_12) / c64;
0276
0277 if (BOOST_GEOMETRY_CONDITION(Order == 2))
0278 {
0279 return c2a0ep2 * (L1 + c2a0ep2 * L2);
0280 }
0281
0282 CT const sin3_2sig1 = math::sqr(sin_2sig1) * sin_2sig1;
0283 CT const sin3_2sig2 = math::sqr(sin_2sig2) * sin_2sig2;
0284 CT const sin3_2sig_12 = sin3_2sig2 - sin3_2sig1;
0285
0286 CT const c9 = 9;
0287 CT const c48 = 48;
0288 CT const c60 = 60;
0289 CT const c512 = 512;
0290
0291 CT const L3 = (c9 * sin_4sig_12 + c4 * sin3_2sig_12 - c48 * sin_2sig_12 + c60 * sig_12) / c512;
0292
0293
0294 return c2a0ep2 * (L1 + c2a0ep2 * (L2 + c2a0ep2 * L3));
0295 }
0296
0297 static inline void normalize(CT & x, CT & y)
0298 {
0299 CT const len = math::sqrt(math::sqr(x) + math::sqr(y));
0300 x /= len;
0301 y /= len;
0302 }
0303 };
0304
0305 }}}
0306
0307
0308 #endif