File indexing completed on 2025-01-18 09:35:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_GEOMETRY_FORMULAS_SJOBERG_INTERSECTION_HPP
0013 #define BOOST_GEOMETRY_FORMULAS_SJOBERG_INTERSECTION_HPP
0014
0015
0016 #include <boost/math/constants/constants.hpp>
0017
0018 #include <boost/geometry/core/radius.hpp>
0019
0020 #include <boost/geometry/util/condition.hpp>
0021 #include <boost/geometry/util/math.hpp>
0022 #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
0023
0024 #include <boost/geometry/formulas/flattening.hpp>
0025 #include <boost/geometry/formulas/spherical.hpp>
0026
0027
0028 namespace boost { namespace geometry { namespace formula
0029 {
0030
0031
0032
0033
0034
0035
0036
0037 template <typename CT>
0038 struct sjoberg_intersection_spherical_02
0039 {
0040
0041
0042
0043 static inline bool apply(CT const& lon1, CT const& lat1, CT const& lon_a2, CT const& lat_a2,
0044 CT const& lon2, CT const& lat2, CT const& lon_b2, CT const& lat_b2,
0045 CT & lon, CT & lat)
0046 {
0047 CT tan_lat = 0;
0048 bool res = apply_alt(lon1, lat1, lon_a2, lat_a2,
0049 lon2, lat2, lon_b2, lat_b2,
0050 lon, tan_lat);
0051
0052 if (res)
0053 {
0054 lat = atan(tan_lat);
0055 }
0056
0057 return res;
0058 }
0059
0060 static inline bool apply_alt(CT const& lon1, CT const& lat1, CT const& lon_a2, CT const& lat_a2,
0061 CT const& lon2, CT const& lat2, CT const& lon_b2, CT const& lat_b2,
0062 CT & lon, CT & tan_lat)
0063 {
0064 CT const cos_lon1 = cos(lon1);
0065 CT const sin_lon1 = sin(lon1);
0066 CT const cos_lon2 = cos(lon2);
0067 CT const sin_lon2 = sin(lon2);
0068 CT const sin_lat1 = sin(lat1);
0069 CT const sin_lat2 = sin(lat2);
0070 CT const cos_lat1 = cos(lat1);
0071 CT const cos_lat2 = cos(lat2);
0072
0073 CT const tan_lat_a2 = tan(lat_a2);
0074 CT const tan_lat_b2 = tan(lat_b2);
0075
0076 return apply(lon1, lon_a2, lon2, lon_b2,
0077 sin_lon1, cos_lon1, sin_lat1, cos_lat1,
0078 sin_lon2, cos_lon2, sin_lat2, cos_lat2,
0079 tan_lat_a2, tan_lat_b2,
0080 lon, tan_lat);
0081 }
0082
0083 private:
0084 static inline bool apply(CT const& lon1, CT const& lon_a2, CT const& lon2, CT const& lon_b2,
0085 CT const& sin_lon1, CT const& cos_lon1, CT const& sin_lat1, CT const& cos_lat1,
0086 CT const& sin_lon2, CT const& cos_lon2, CT const& sin_lat2, CT const& cos_lat2,
0087 CT const& tan_lat_a2, CT const& tan_lat_b2,
0088 CT & lon, CT & tan_lat)
0089 {
0090
0091
0092
0093
0094 CT const tan_lat1 = sin_lat1 / cos_lat1;
0095 CT const tan_lat2 = sin_lat2 / cos_lat2;
0096
0097 CT const dlon1 = lon_a2 - lon1;
0098 CT const sin_dlon1 = sin(dlon1);
0099 CT const dlon2 = lon_b2 - lon2;
0100 CT const sin_dlon2 = sin(dlon2);
0101
0102 CT const cos_dlon1 = cos(dlon1);
0103 CT const cos_dlon2 = cos(dlon2);
0104
0105 CT const tan_alpha1_x = cos_lat1 * tan_lat_a2 - sin_lat1 * cos_dlon1;
0106 CT const tan_alpha2_x = cos_lat2 * tan_lat_b2 - sin_lat2 * cos_dlon2;
0107
0108 CT const c0 = 0;
0109 bool const is_vertical1 = math::equals(sin_dlon1, c0) || math::equals(tan_alpha1_x, c0);
0110 bool const is_vertical2 = math::equals(sin_dlon2, c0) || math::equals(tan_alpha2_x, c0);
0111
0112 CT tan_alpha1 = 0;
0113 CT tan_alpha2 = 0;
0114
0115 if (is_vertical1 && is_vertical2)
0116 {
0117
0118 return false;
0119 }
0120 else if (is_vertical1)
0121 {
0122 tan_alpha2 = sin_dlon2 / tan_alpha2_x;
0123
0124 lon = lon1;
0125 }
0126 else if (is_vertical2)
0127 {
0128 tan_alpha1 = sin_dlon1 / tan_alpha1_x;
0129
0130 lon = lon2;
0131 }
0132 else
0133 {
0134 tan_alpha1 = sin_dlon1 / tan_alpha1_x;
0135 tan_alpha2 = sin_dlon2 / tan_alpha2_x;
0136
0137 CT const T1 = tan_alpha1 * cos_lat1;
0138 CT const T2 = tan_alpha2 * cos_lat2;
0139 CT const T1T2 = T1*T2;
0140 CT const tan_lon_y = T1 * sin_lon2 - T2 * sin_lon1 + T1T2 * (tan_lat1 * cos_lon1 - tan_lat2 * cos_lon2);
0141 CT const tan_lon_x = T1 * cos_lon2 - T2 * cos_lon1 - T1T2 * (tan_lat1 * sin_lon1 - tan_lat2 * sin_lon2);
0142
0143 lon = atan2(tan_lon_y, tan_lon_x);
0144 }
0145
0146
0147 CT const pi = math::pi<CT>();
0148 CT const lon_2 = lon > c0 ? lon - pi : lon + pi;
0149 CT const lon_dist1 = (std::max)((std::min)(math::longitude_difference<radian>(lon1, lon),
0150 math::longitude_difference<radian>(lon_a2, lon)),
0151 (std::min)(math::longitude_difference<radian>(lon2, lon),
0152 math::longitude_difference<radian>(lon_b2, lon)));
0153 CT const lon_dist2 = (std::max)((std::min)(math::longitude_difference<radian>(lon1, lon_2),
0154 math::longitude_difference<radian>(lon_a2, lon_2)),
0155 (std::min)(math::longitude_difference<radian>(lon2, lon_2),
0156 math::longitude_difference<radian>(lon_b2, lon_2)));
0157 if (lon_dist2 < lon_dist1)
0158 {
0159 lon = lon_2;
0160 }
0161
0162 CT const sin_lon = sin(lon);
0163 CT const cos_lon = cos(lon);
0164
0165 if (math::abs(tan_alpha1) >= math::abs(tan_alpha2))
0166 {
0167 CT const sin_dlon_1 = sin_lon * cos_lon1 - cos_lon * sin_lon1;
0168 CT const cos_dlon_1 = cos_lon * cos_lon1 + sin_lon * sin_lon1;
0169 CT const lat_y_1 = sin_dlon_1 + tan_alpha1 * sin_lat1 * cos_dlon_1;
0170 CT const lat_x_1 = tan_alpha1 * cos_lat1;
0171 tan_lat = lat_y_1 / lat_x_1;
0172 }
0173 else
0174 {
0175 CT const sin_dlon_2 = sin_lon * cos_lon2 - cos_lon * sin_lon2;
0176 CT const cos_dlon_2 = cos_lon * cos_lon2 + sin_lon * sin_lon2;
0177 CT const lat_y_2 = sin_dlon_2 + tan_alpha2 * sin_lat2 * cos_dlon_2;
0178 CT const lat_x_2 = tan_alpha2 * cos_lat2;
0179 tan_lat = lat_y_2 / lat_x_2;
0180 }
0181
0182 return true;
0183 }
0184 };
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203 template <unsigned int Order, typename CT>
0204 inline CT sjoberg_d_lambda_e_sqr(CT const& sin_betaj, CT const& sin_beta,
0205 CT const& Cj, CT const& sqrt_1_Cj_sqr,
0206 CT const& e_sqr)
0207 {
0208 using math::detail::bounded;
0209
0210 if (BOOST_GEOMETRY_CONDITION(Order == 0))
0211 {
0212 return 0;
0213 }
0214
0215 CT const c1 = 1;
0216 CT const c2 = 2;
0217
0218 CT const asin_B = asin(bounded(sin_beta / sqrt_1_Cj_sqr, -c1, c1));
0219 CT const asin_Bj = asin(sin_betaj / sqrt_1_Cj_sqr);
0220 CT const L0 = (asin_B - asin_Bj) / c2;
0221
0222 if (BOOST_GEOMETRY_CONDITION(Order == 1))
0223 {
0224 return -Cj * e_sqr * L0;
0225 }
0226
0227 CT const c0 = 0;
0228 CT const c16 = 16;
0229
0230 CT const X = sin_beta;
0231 CT const Xj = sin_betaj;
0232 CT const X_sqr = math::sqr(X);
0233 CT const Xj_sqr = math::sqr(Xj);
0234 CT const Cj_sqr = math::sqr(Cj);
0235 CT const Cj_sqr_plus_one = Cj_sqr + c1;
0236 CT const one_minus_Cj_sqr = c1 - Cj_sqr;
0237 CT const sqrt_Y = math::sqrt(bounded(-X_sqr + one_minus_Cj_sqr, c0));
0238 CT const sqrt_Yj = math::sqrt(-Xj_sqr + one_minus_Cj_sqr);
0239 CT const L1 = (Cj_sqr_plus_one * (asin_B - asin_Bj) + X * sqrt_Y - Xj * sqrt_Yj) / c16;
0240
0241 if (BOOST_GEOMETRY_CONDITION(Order == 2))
0242 {
0243 return -Cj * e_sqr * (L0 + e_sqr * L1);
0244 }
0245
0246 CT const c3 = 3;
0247 CT const c5 = 5;
0248 CT const c128 = 128;
0249
0250 CT const E = Cj_sqr * (c3 * Cj_sqr + c2) + c3;
0251 CT const F = X * (-c2 * X_sqr + c3 * Cj_sqr + c5);
0252 CT const Fj = Xj * (-c2 * Xj_sqr + c3 * Cj_sqr + c5);
0253 CT const L2 = (E * (asin_B - asin_Bj) + F * sqrt_Y - Fj * sqrt_Yj) / c128;
0254
0255 if (BOOST_GEOMETRY_CONDITION(Order == 3))
0256 {
0257 return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * L2));
0258 }
0259
0260 CT const c8 = 8;
0261 CT const c9 = 9;
0262 CT const c10 = 10;
0263 CT const c15 = 15;
0264 CT const c24 = 24;
0265 CT const c26 = 26;
0266 CT const c33 = 33;
0267 CT const c6144 = 6144;
0268
0269 CT const G = Cj_sqr * (Cj_sqr * (Cj_sqr * c15 + c9) + c9) + c15;
0270 CT const H = -c10 * Cj_sqr - c26;
0271 CT const I = Cj_sqr * (Cj_sqr * c15 + c24) + c33;
0272 CT const J = X_sqr * (X * (c8 * X_sqr + H)) + X * I;
0273 CT const Jj = Xj_sqr * (Xj * (c8 * Xj_sqr + H)) + Xj * I;
0274 CT const L3 = (G * (asin_B - asin_Bj) + J * sqrt_Y - Jj * sqrt_Yj) / c6144;
0275
0276
0277 return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * (L2 + e_sqr * L3)));
0278 }
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289 template <typename CT, unsigned int Order>
0290 class sjoberg_geodesic
0291 {
0292 sjoberg_geodesic() {}
0293
0294 static int sign_C(CT const& alphaj)
0295 {
0296 CT const c0 = 0;
0297 CT const c2 = 2;
0298 CT const pi = math::pi<CT>();
0299 CT const pi_half = pi / c2;
0300
0301 return (pi_half < alphaj && alphaj < pi) || (-pi_half < alphaj && alphaj < c0) ? -1 : 1;
0302 }
0303
0304 public:
0305 sjoberg_geodesic(CT const& lon, CT const& lat, CT const& alpha, CT const& f)
0306 : lonj(lon)
0307 , latj(lat)
0308 , alphaj(alpha)
0309 {
0310 CT const c0 = 0;
0311 CT const c1 = 1;
0312 CT const c2 = 2;
0313
0314
0315
0316 one_minus_f = c1 - f;
0317 e_sqr = f * (c2 - f);
0318
0319 tan_latj = tan(lat);
0320 tan_betaj = one_minus_f * tan_latj;
0321 betaj = atan(tan_betaj);
0322 sin_betaj = sin(betaj);
0323
0324 cos_betaj = cos(betaj);
0325 sin_alphaj = sin(alphaj);
0326
0327 Cj = sign_C(alphaj) * cos_betaj * sin_alphaj;
0328 Cj_sqr = math::sqr(Cj);
0329 sqrt_1_Cj_sqr = math::sqrt(c1 - Cj_sqr);
0330
0331 sign_lon_diff = alphaj >= 0 ? 1 : -1;
0332
0333
0334 is_on_equator = math::equals(sqrt_1_Cj_sqr, c0);
0335 is_Cj_zero = math::equals(Cj, c0);
0336
0337 t0j = c0;
0338 asin_tj_t0j = c0;
0339
0340 if (! is_Cj_zero)
0341 {
0342 t0j = sqrt_1_Cj_sqr / Cj;
0343 }
0344
0345 if (! is_on_equator)
0346 {
0347
0348 asin_tj_t0j = asin(tan_betaj * Cj / sqrt_1_Cj_sqr);
0349 }
0350 }
0351
0352 struct vertex_data
0353 {
0354
0355 CT sin_beta0j;
0356 CT dL0j;
0357 CT lon0j;
0358 };
0359
0360 vertex_data get_vertex_data() const
0361 {
0362 CT const c2 = 2;
0363 CT const pi = math::pi<CT>();
0364 CT const pi_half = pi / c2;
0365
0366 vertex_data res;
0367
0368 if (! is_Cj_zero)
0369 {
0370
0371
0372 res.sin_beta0j = math::sign(t0j) * sqrt_1_Cj_sqr;
0373 res.dL0j = d_lambda(res.sin_beta0j);
0374 res.lon0j = lonj + sign_lon_diff * (pi_half - asin_tj_t0j + res.dL0j);
0375 }
0376 else
0377 {
0378
0379
0380 res.sin_beta0j = 1;
0381 res.dL0j = 0;
0382 res.lon0j = lonj;
0383 }
0384
0385 return res;
0386 }
0387
0388 bool is_sin_beta_ok(CT const& sin_beta) const
0389 {
0390 CT const c1 = 1;
0391 return math::abs(sin_beta / sqrt_1_Cj_sqr) <= c1;
0392 }
0393
0394 bool k_diff(CT const& sin_beta,
0395 CT & delta_k) const
0396 {
0397 if (is_Cj_zero)
0398 {
0399 delta_k = 0;
0400 return true;
0401 }
0402
0403
0404 if (! (is_sin_beta_ok(sin_beta)
0405 || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) )
0406 {
0407 return false;
0408 }
0409
0410
0411 CT const dLj = d_lambda(sin_beta);
0412 delta_k = sign_lon_diff * ( - asin_tj_t0j + dLj);
0413
0414 return true;
0415 }
0416
0417 bool lon_diff(CT const& sin_beta, CT const& t,
0418 CT & delta_lon) const
0419 {
0420 using math::detail::bounded;
0421 CT const c1 = 1;
0422
0423 if (is_Cj_zero)
0424 {
0425 delta_lon = 0;
0426 return true;
0427 }
0428
0429 CT delta_k = 0;
0430 if (! k_diff(sin_beta, delta_k))
0431 {
0432 return false;
0433 }
0434
0435 CT const t_t0j = t / t0j;
0436
0437 CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1));
0438 delta_lon = sign_lon_diff * asin_t_t0j + delta_k;
0439
0440 return true;
0441 }
0442
0443 bool k_diffs(CT const& sin_beta, vertex_data const& vd,
0444 CT & delta_k_before, CT & delta_k_behind,
0445 bool check_sin_beta = true) const
0446 {
0447 CT const pi = math::pi<CT>();
0448
0449 if (is_Cj_zero)
0450 {
0451 delta_k_before = 0;
0452 delta_k_behind = sign_lon_diff * pi;
0453 return true;
0454 }
0455
0456
0457 if (check_sin_beta
0458 && ! (is_sin_beta_ok(sin_beta)
0459 || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) )
0460 {
0461 return false;
0462 }
0463
0464
0465 CT const dLj = d_lambda(sin_beta);
0466 delta_k_before = sign_lon_diff * ( - asin_tj_t0j + dLj);
0467
0468
0469 delta_k_behind = sign_lon_diff * (pi - asin_tj_t0j + vd.dL0j + (vd.dL0j - dLj));
0470
0471
0472
0473
0474
0475
0476
0477 return true;
0478 }
0479
0480 bool lon_diffs(CT const& sin_beta, CT const& t, vertex_data const& vd,
0481 CT & delta_lon_before, CT & delta_lon_behind) const
0482 {
0483 using math::detail::bounded;
0484 CT const c1 = 1;
0485 CT const pi = math::pi<CT>();
0486
0487 if (is_Cj_zero)
0488 {
0489 delta_lon_before = 0;
0490 delta_lon_behind = sign_lon_diff * pi;
0491 return true;
0492 }
0493
0494 CT delta_k_before = 0, delta_k_behind = 0;
0495 if (! k_diffs(sin_beta, vd, delta_k_before, delta_k_behind))
0496 {
0497 return false;
0498 }
0499
0500 CT const t_t0j = t / t0j;
0501
0502 CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1));
0503 CT const sign_asin_t_t0j = sign_lon_diff * asin_t_t0j;
0504 delta_lon_before = sign_asin_t_t0j + delta_k_before;
0505 delta_lon_behind = -sign_asin_t_t0j + delta_k_behind;
0506
0507 return true;
0508 }
0509
0510 bool lon(CT const& sin_beta, CT const& t, vertex_data const& vd,
0511 CT & lon_before, CT & lon_behind) const
0512 {
0513 using math::detail::bounded;
0514 CT const c1 = 1;
0515 CT const pi = math::pi<CT>();
0516
0517 if (is_Cj_zero)
0518 {
0519 lon_before = lonj;
0520 lon_behind = lonj + sign_lon_diff * pi;
0521 return true;
0522 }
0523
0524 if (! (is_sin_beta_ok(sin_beta)
0525 || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) )
0526 {
0527 return false;
0528 }
0529
0530 CT const t_t0j = t / t0j;
0531 CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1));
0532 CT const dLj = d_lambda(sin_beta);
0533 lon_before = lonj + sign_lon_diff * (asin_t_t0j - asin_tj_t0j + dLj);
0534 lon_behind = vd.lon0j + (vd.lon0j - lon_before);
0535
0536 return true;
0537 }
0538
0539
0540 CT lon(CT const& delta_lon) const
0541 {
0542 return lonj + delta_lon;
0543 }
0544
0545 CT lat(CT const& t) const
0546 {
0547
0548 return atan(t / one_minus_f);
0549 }
0550
0551 void vertex(CT & lon, CT & lat) const
0552 {
0553 lon = get_vertex_data().lon0j;
0554 if (! is_Cj_zero)
0555 {
0556 lat = sjoberg_geodesic::lat(t0j);
0557 }
0558 else
0559 {
0560 CT const c2 = 2;
0561 lat = math::pi<CT>() / c2;
0562 }
0563 }
0564
0565 CT lon_of_equator_intersection() const
0566 {
0567 CT const c0 = 0;
0568 CT const dLj = d_lambda(c0);
0569 CT const asin_tj_t0j = asin(Cj * tan_betaj / sqrt_1_Cj_sqr);
0570 return lonj - asin_tj_t0j + dLj;
0571 }
0572
0573 CT d_lambda(CT const& sin_beta) const
0574 {
0575 return sjoberg_d_lambda_e_sqr<Order>(sin_betaj, sin_beta, Cj, sqrt_1_Cj_sqr, e_sqr);
0576 }
0577
0578
0579
0580
0581
0582
0583
0584 CT lonj;
0585 CT latj;
0586 CT alphaj;
0587
0588 CT one_minus_f;
0589 CT e_sqr;
0590
0591 CT tan_latj;
0592 CT tan_betaj;
0593 CT betaj;
0594 CT sin_betaj;
0595 CT cos_betaj;
0596 CT sin_alphaj;
0597 CT Cj;
0598 CT Cj_sqr;
0599 CT sqrt_1_Cj_sqr;
0600
0601 int sign_lon_diff;
0602
0603 bool is_on_equator;
0604 bool is_Cj_zero;
0605
0606 CT t0j;
0607 CT asin_tj_t0j;
0608 };
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622 template
0623 <
0624 typename CT,
0625 template <typename, bool, bool, bool, bool, bool> class Inverse,
0626 unsigned int Order = 4
0627 >
0628 class sjoberg_intersection
0629 {
0630 typedef sjoberg_geodesic<CT, Order> geodesic_type;
0631 typedef Inverse<CT, false, true, false, false, false> inverse_type;
0632 typedef typename inverse_type::result_type inverse_result;
0633
0634 static bool const enable_02 = true;
0635 static int const max_iterations_02 = 10;
0636 static int const max_iterations_07 = 20;
0637
0638 public:
0639 template <typename T1, typename T2, typename Spheroid>
0640 static inline bool apply(T1 const& lona1, T1 const& lata1,
0641 T1 const& lona2, T1 const& lata2,
0642 T2 const& lonb1, T2 const& latb1,
0643 T2 const& lonb2, T2 const& latb2,
0644 CT & lon, CT & lat,
0645 Spheroid const& spheroid)
0646 {
0647 CT const lon_a1 = lona1;
0648 CT const lat_a1 = lata1;
0649 CT const lon_a2 = lona2;
0650 CT const lat_a2 = lata2;
0651 CT const lon_b1 = lonb1;
0652 CT const lat_b1 = latb1;
0653 CT const lon_b2 = lonb2;
0654 CT const lat_b2 = latb2;
0655
0656 inverse_result const res1 = inverse_type::apply(lon_a1, lat_a1, lon_a2, lat_a2, spheroid);
0657 inverse_result const res2 = inverse_type::apply(lon_b1, lat_b1, lon_b2, lat_b2, spheroid);
0658
0659 return apply(lon_a1, lat_a1, lon_a2, lat_a2, res1.azimuth,
0660 lon_b1, lat_b1, lon_b2, lat_b2, res2.azimuth,
0661 lon, lat, spheroid);
0662 }
0663
0664
0665 template <typename Spheroid>
0666 static inline bool apply(CT const& lon_a1, CT const& lat_a1, CT const& lon_a2, CT const& lat_a2, CT const& alpha_a1,
0667 CT const& lon_b1, CT const& lat_b1, CT const& lon_b2, CT const& lat_b2, CT const& alpha_b1,
0668 CT & lon, CT & lat,
0669 Spheroid const& spheroid)
0670 {
0671
0672
0673 CT const c0 = 0;
0674 CT const c1 = 1;
0675
0676 CT const f = formula::flattening<CT>(spheroid);
0677 CT const one_minus_f = c1 - f;
0678
0679 geodesic_type geod1(lon_a1, lat_a1, alpha_a1, f);
0680 geodesic_type geod2(lon_b1, lat_b1, alpha_b1, f);
0681
0682
0683
0684
0685 if (geod1.is_on_equator && geod2.is_on_equator)
0686 {
0687 return false;
0688 }
0689 else if (geod1.is_on_equator)
0690 {
0691 lon = geod2.lon_of_equator_intersection();
0692 lat = c0;
0693 return true;
0694 }
0695 else if (geod2.is_on_equator)
0696 {
0697 lon = geod1.lon_of_equator_intersection();
0698 lat = c0;
0699 return true;
0700 }
0701
0702
0703 CT const lon1_minus_lon2 = math::longitude_distance_signed<radian>(geod2.lonj, geod1.lonj);
0704
0705
0706 if (geod1.is_Cj_zero && geod2.is_Cj_zero)
0707 {
0708 CT const pi = math::pi<CT>();
0709
0710
0711 if ( math::equals(lon1_minus_lon2, c0)
0712 || math::equals(lon1_minus_lon2 + (lon1_minus_lon2 < c0 ? pi : -pi), c0) )
0713 {
0714 return false;
0715 }
0716
0717 lon = c0;
0718
0719
0720 CT const pi_half = pi / CT(2);
0721 CT const abs_lat_a1 = math::abs(lat_a1);
0722 CT const abs_lat_a2 = math::abs(lat_a2);
0723 if (math::equals(abs_lat_a1, abs_lat_a2))
0724 {
0725 lat = pi_half;
0726 }
0727 else
0728 {
0729
0730 CT const& closer_lat = abs_lat_a1 > abs_lat_a2 ? lat_a1 : lat_a2;
0731 lat = closer_lat >= 0 ? pi_half : -pi_half;
0732 }
0733
0734 return true;
0735 }
0736
0737 CT lon_sph = 0;
0738
0739
0740 CT t = 0;
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755 {
0756
0757
0758 CT tan_lat_sph = 0;
0759 sjoberg_intersection_spherical_02<CT>::apply_alt(lon_a1, lat_a1, lon_a2, lat_a2,
0760 lon_b1, lat_b1, lon_b2, lat_b2,
0761 lon_sph, tan_lat_sph);
0762
0763
0764 if (math::equals(f, c0))
0765 {
0766 lon = lon_sph;
0767 lat = atan(tan_lat_sph);
0768 return true;
0769 }
0770
0771 t = one_minus_f * tan_lat_sph;
0772 }
0773
0774
0775
0776 CT const beta = atan(t);
0777
0778 if (enable_02 && newton_method(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat))
0779 {
0780
0781
0782
0783
0784
0785
0786
0787 if ( is_result_longitude_ok(geod1, lon_a1, lon_a2, lon)
0788 && is_result_longitude_ok(geod2, lon_b1, lon_b2, lon) )
0789 {
0790 return true;
0791 }
0792 }
0793
0794 return converge_07(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat);
0795 }
0796
0797 private:
0798 static inline bool newton_method(geodesic_type const& geod1, geodesic_type const& geod2,
0799 CT beta, CT t, CT const& lon1_minus_lon2, CT const& lon_sph,
0800 CT & lon, CT & lat)
0801 {
0802 CT const c0 = 0;
0803 CT const c1 = 1;
0804
0805 CT const e_sqr = geod1.e_sqr;
0806
0807 CT lon1_diff = 0;
0808 CT lon2_diff = 0;
0809
0810
0811
0812 if (geod1.is_Cj_zero && math::abs(geod1.lonj - lon_sph) > math::half_pi<CT>())
0813 return false;
0814 if (geod2.is_Cj_zero && math::abs(geod2.lonj - lon_sph) > math::half_pi<CT>())
0815 return false;
0816
0817 CT abs_dbeta_last = 0;
0818
0819
0820
0821 for (int i = 0; i < max_iterations_02; ++i)
0822 {
0823 CT const cos_beta = cos(beta);
0824
0825 if (math::equals(cos_beta, c0))
0826 {
0827 return false;
0828 }
0829
0830 CT const sin_beta = sin(beta);
0831 CT const cos_beta_sqr = math::sqr(cos_beta);
0832 CT const G = c1 - e_sqr * cos_beta_sqr;
0833
0834 CT f1 = 0;
0835 CT f2 = 0;
0836
0837 if (!geod1.is_Cj_zero)
0838 {
0839 bool is_beta_ok = geod1.lon_diff(sin_beta, t, lon1_diff);
0840
0841 if (is_beta_ok)
0842 {
0843 CT const H = cos_beta_sqr - geod1.Cj_sqr;
0844 if (math::equals(H, c0))
0845 {
0846 return false;
0847 }
0848 f1 = geod1.Cj / cos_beta * math::sqrt(G / H);
0849 }
0850 else
0851 {
0852 return false;
0853 }
0854 }
0855
0856 if (!geod2.is_Cj_zero)
0857 {
0858 bool is_beta_ok = geod2.lon_diff(sin_beta, t, lon2_diff);
0859
0860 if (is_beta_ok)
0861 {
0862 CT const H = cos_beta_sqr - geod2.Cj_sqr;
0863 if (math::equals(H, c0))
0864 {
0865
0866
0867
0868
0869
0870 return false;
0871 }
0872 f2 = geod2.Cj / cos_beta * math::sqrt(G / H);
0873 }
0874 else
0875 {
0876 return false;
0877 }
0878 }
0879
0880
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890 CT const dbeta_denom = f1 - f2;
0891
0892
0893 if (math::equals(dbeta_denom, c0))
0894 {
0895 return false;
0896 }
0897
0898
0899 CT const dbeta = (lon1_minus_lon2 + lon1_diff - lon2_diff) / dbeta_denom;
0900
0901 CT const abs_dbeta = math::abs(dbeta);
0902 if (i > 0 && abs_dbeta > abs_dbeta_last)
0903 {
0904
0905
0906 return false;
0907 }
0908 abs_dbeta_last = abs_dbeta;
0909
0910 if (math::equals(dbeta, c0))
0911 {
0912
0913 break;
0914 }
0915
0916
0917 beta = beta - dbeta;
0918
0919 t = tan(beta);
0920 }
0921
0922 lat = geod1.lat(t);
0923
0924 lon = ! geod1.is_Cj_zero
0925 ? geod1.lon(lon1_diff)
0926 : geod2.lon(lon2_diff);
0927
0928 return true;
0929 }
0930
0931 static inline bool is_result_longitude_ok(geodesic_type const& geod,
0932 CT const& lon1, CT const& lon2, CT const& lon)
0933 {
0934 CT const c0 = 0;
0935
0936 if (geod.is_Cj_zero)
0937 return true;
0938
0939 CT dist1p = math::longitude_distance_signed<radian>(lon1, lon);
0940 CT dist12 = math::longitude_distance_signed<radian>(lon1, lon2);
0941
0942 if (dist12 < c0)
0943 {
0944 dist1p = -dist1p;
0945 dist12 = -dist12;
0946 }
0947
0948 return (c0 <= dist1p && dist1p <= dist12)
0949 || math::equals(dist1p, c0)
0950 || math::equals(dist1p, dist12);
0951 }
0952
0953 struct geodesics_type
0954 {
0955 geodesics_type(geodesic_type const& g1, geodesic_type const& g2)
0956 : geod1(g1)
0957 , geod2(g2)
0958 , vertex1(geod1.get_vertex_data())
0959 , vertex2(geod2.get_vertex_data())
0960 {}
0961
0962 geodesic_type const& geod1;
0963 geodesic_type const& geod2;
0964 typename geodesic_type::vertex_data vertex1;
0965 typename geodesic_type::vertex_data vertex2;
0966 };
0967
0968 struct converge_07_result
0969 {
0970 converge_07_result()
0971 : lon1(0), lon2(0), k1_diff(0), k2_diff(0), t1(0), t2(0)
0972 {}
0973
0974 CT lon1, lon2;
0975 CT k1_diff, k2_diff;
0976 CT t1, t2;
0977 };
0978
0979 static inline bool converge_07(geodesic_type const& geod1, geodesic_type const& geod2,
0980 CT beta, CT t,
0981 CT const& lon1_minus_lon2, CT const& lon_sph,
0982 CT & lon, CT & lat)
0983 {
0984
0985
0986
0987
0988
0989 geodesics_type geodesics(geod1, geod2);
0990 converge_07_result result;
0991
0992
0993 if (!converge_07_step_one(CT(sin(beta)), t, lon1_minus_lon2, geodesics, lon_sph, result, false))
0994 {
0995 return false;
0996 }
0997
0998 int t_direction = 0;
0999
1000 CT lon_diff_prev = math::longitude_difference<radian>(result.lon1, result.lon2);
1001
1002
1003 for (int i = 2; i < max_iterations_07; ++i)
1004 {
1005
1006 CT t_cand1 = result.t1;
1007 CT t_cand2 = result.t2;
1008
1009 if (t_direction < 0)
1010 {
1011 t_cand1 = (std::min)(result.t1, result.t2);
1012 t_cand2 = (std::max)(result.t1, result.t2);
1013 }
1014 else if (t_direction > 0)
1015 {
1016 t_cand1 = (std::max)(result.t1, result.t2);
1017 t_cand2 = (std::min)(result.t1, result.t2);
1018 }
1019 else
1020 {
1021 t_direction = t_cand1 < t_cand2 ? -1 : 1;
1022 }
1023
1024 CT t1 = t;
1025 CT beta1 = beta;
1026
1027 if (converge_07_update(t1, beta1, t_cand1))
1028 {
1029 break;
1030 }
1031
1032 bool try_t2 = false;
1033 converge_07_result result_curr;
1034 if (converge_07_step_one(CT(sin(beta1)), t1, lon1_minus_lon2, geodesics, lon_sph, result_curr))
1035 {
1036 CT const lon_diff1 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2);
1037 if (lon_diff_prev > lon_diff1)
1038 {
1039 t = t1;
1040 beta = beta1;
1041 lon_diff_prev = lon_diff1;
1042 result = result_curr;
1043 }
1044 else if (t_cand1 != t_cand2)
1045 {
1046 try_t2 = true;
1047 }
1048 else
1049 {
1050
1051 break;
1052 }
1053 }
1054
1055 else
1056 {
1057 if (t_cand1 != t_cand2)
1058 {
1059 try_t2 = true;
1060 }
1061 else
1062 {
1063 return false;
1064 }
1065 }
1066
1067
1068 if (try_t2)
1069 {
1070 CT t2 = t;
1071 CT beta2 = beta;
1072
1073 if (converge_07_update(t2, beta2, t_cand2))
1074 {
1075 break;
1076 }
1077
1078 if (! converge_07_step_one(CT(sin(beta2)), t2, lon1_minus_lon2, geodesics, lon_sph, result_curr))
1079 {
1080 return false;
1081 }
1082
1083 CT const lon_diff2 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2);
1084 if (lon_diff_prev > lon_diff2)
1085 {
1086 t_direction *= -1;
1087 t = t2;
1088 beta = beta2;
1089 lon_diff_prev = lon_diff2;
1090 result = result_curr;
1091 }
1092 else
1093 {
1094
1095 break;
1096 }
1097 }
1098 }
1099
1100 lat = geod1.lat(t);
1101 lon = ! geod1.is_Cj_zero ? result.lon1 : result.lon2;
1102 math::normalize_longitude<radian>(lon);
1103
1104 return true;
1105 }
1106
1107 static inline bool converge_07_update(CT & t, CT & beta, CT const& t_new)
1108 {
1109 CT const c0 = 0;
1110
1111 CT const beta_new = atan(t_new);
1112 CT const dbeta = beta_new - beta;
1113 beta = beta_new;
1114 t = t_new;
1115
1116 return math::equals(dbeta, c0);
1117 }
1118
1119 static inline CT const& pick_t(CT const& t1, CT const& t2, int direction)
1120 {
1121 return direction < 0 ? (std::min)(t1, t2) : (std::max)(t1, t2);
1122 }
1123
1124 static inline bool converge_07_step_one(CT const& sin_beta,
1125 CT const& t,
1126 CT const& lon1_minus_lon2,
1127 geodesics_type const& geodesics,
1128 CT const& lon_sph,
1129 converge_07_result & result,
1130 bool check_sin_beta = true)
1131 {
1132 bool ok = converge_07_one_geod(sin_beta, t, geodesics.geod1, geodesics.vertex1, lon_sph,
1133 result.lon1, result.k1_diff, check_sin_beta)
1134 && converge_07_one_geod(sin_beta, t, geodesics.geod2, geodesics.vertex2, lon_sph,
1135 result.lon2, result.k2_diff, check_sin_beta);
1136
1137 if (!ok)
1138 {
1139 return false;
1140 }
1141
1142 CT const k = lon1_minus_lon2 + result.k1_diff - result.k2_diff;
1143
1144
1145
1146 calc_ts(t, k, geodesics.geod1, geodesics.geod2, result.t1, result.t2);
1147
1148 return true;
1149 }
1150
1151 static inline bool converge_07_one_geod(CT const& sin_beta, CT const& t,
1152 geodesic_type const& geod,
1153 typename geodesic_type::vertex_data const& vertex,
1154 CT const& lon_sph,
1155 CT & lon, CT & k_diff,
1156 bool check_sin_beta)
1157 {
1158 using math::detail::bounded;
1159 CT const c1 = 1;
1160
1161 CT k_diff_before = 0;
1162 CT k_diff_behind = 0;
1163
1164 bool is_beta_ok = geod.k_diffs(sin_beta, vertex, k_diff_before, k_diff_behind, check_sin_beta);
1165
1166 if (! is_beta_ok)
1167 {
1168 return false;
1169 }
1170
1171 CT const asin_t_t0j = ! geod.is_Cj_zero ? asin(bounded(t / geod.t0j, -c1, c1)) : 0;
1172 CT const sign_asin_t_t0j = geod.sign_lon_diff * asin_t_t0j;
1173
1174 CT const lon_before = geod.lonj + sign_asin_t_t0j + k_diff_before;
1175 CT const lon_behind = geod.lonj - sign_asin_t_t0j + k_diff_behind;
1176
1177 CT const lon_dist_before = math::longitude_distance_signed<radian>(lon_before, lon_sph);
1178 CT const lon_dist_behind = math::longitude_distance_signed<radian>(lon_behind, lon_sph);
1179 if (math::abs(lon_dist_before) <= math::abs(lon_dist_behind))
1180 {
1181 k_diff = k_diff_before;
1182 lon = lon_before;
1183 }
1184 else
1185 {
1186 k_diff = k_diff_behind;
1187 lon = lon_behind;
1188 }
1189
1190 return true;
1191 }
1192
1193 static inline void calc_ts(CT const& t, CT const& k,
1194 geodesic_type const& geod1, geodesic_type const& geod2,
1195 CT & t1, CT& t2)
1196 {
1197 CT const c0 = 0;
1198 CT const c1 = 1;
1199 CT const c2 = 2;
1200
1201 CT const K = sin(k);
1202
1203 BOOST_GEOMETRY_ASSERT(!geod1.is_Cj_zero || !geod2.is_Cj_zero);
1204 if (geod1.is_Cj_zero)
1205 {
1206 t1 = K * geod2.t0j;
1207 t2 = -t1;
1208 }
1209 else if (geod2.is_Cj_zero)
1210 {
1211 t1 = -K * geod1.t0j;
1212 t2 = -t1;
1213 }
1214 else
1215 {
1216 CT const A = math::sqr(geod1.t0j) + math::sqr(geod2.t0j);
1217 CT const B = c2 * geod1.t0j * geod2.t0j * math::sqrt(c1 - math::sqr(K));
1218
1219 CT const K_t01_t02 = K * geod1.t0j * geod2.t0j;
1220 CT const D1 = math::sqrt(A + B);
1221 CT const D2 = math::sqrt(A - B);
1222 CT const t_new1 = math::equals(D1, c0) ? c0 : K_t01_t02 / D1;
1223 CT const t_new2 = math::equals(D2, c0) ? c0 : K_t01_t02 / D2;
1224 CT const t_new3 = -t_new1;
1225 CT const t_new4 = -t_new2;
1226
1227
1228 CT const abs_t_new1 = math::abs(t_new1);
1229 CT const abs_t_new2 = math::abs(t_new2);
1230 CT const abs_t_max = (std::max)(abs_t_new1, abs_t_new2);
1231 t1 = -abs_t_max;
1232 t2 = abs_t_max;
1233 if (t1 < t)
1234 {
1235 if (t_new1 < t && t_new1 > t1)
1236 t1 = t_new1;
1237 if (t_new2 < t && t_new2 > t1)
1238 t1 = t_new2;
1239 if (t_new3 < t && t_new3 > t1)
1240 t1 = t_new3;
1241 if (t_new4 < t && t_new4 > t1)
1242 t1 = t_new4;
1243 }
1244 if (t2 > t)
1245 {
1246 if (t_new1 > t && t_new1 < t2)
1247 t2 = t_new1;
1248 if (t_new2 > t && t_new2 < t2)
1249 t2 = t_new2;
1250 if (t_new3 > t && t_new3 < t2)
1251 t2 = t_new3;
1252 if (t_new4 > t && t_new4 < t2)
1253 t2 = t_new4;
1254 }
1255 }
1256
1257
1258 if (math::abs(t - t2) < math::abs(t - t1))
1259 {
1260 std::swap(t2, t1);
1261 }
1262 }
1263
1264 static inline CT fj(CT const& cos_beta, CT const& cos2_beta, CT const& Cj, CT const& e_sqr)
1265 {
1266 CT const c1 = 1;
1267 CT const Cj_sqr = math::sqr(Cj);
1268 return Cj / cos_beta * math::sqrt((c1 - e_sqr * cos2_beta) / (cos2_beta - Cj_sqr));
1269 }
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283 };
1284
1285 }}}
1286
1287
1288 #endif