File indexing completed on 2025-09-16 08:34:28
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 return lonj - asin_tj_t0j + dLj;
0570 }
0571
0572 CT d_lambda(CT const& sin_beta) const
0573 {
0574 return sjoberg_d_lambda_e_sqr<Order>(sin_betaj, sin_beta, Cj, sqrt_1_Cj_sqr, e_sqr);
0575 }
0576
0577
0578
0579
0580
0581
0582
0583 CT lonj;
0584 CT latj;
0585 CT alphaj;
0586
0587 CT one_minus_f;
0588 CT e_sqr;
0589
0590 CT tan_latj;
0591 CT tan_betaj;
0592 CT betaj;
0593 CT sin_betaj;
0594 CT cos_betaj;
0595 CT sin_alphaj;
0596 CT Cj;
0597 CT Cj_sqr;
0598 CT sqrt_1_Cj_sqr;
0599
0600 int sign_lon_diff;
0601
0602 bool is_on_equator;
0603 bool is_Cj_zero;
0604
0605 CT t0j;
0606 CT asin_tj_t0j;
0607 };
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621 template
0622 <
0623 typename CT,
0624 template <typename, bool, bool, bool, bool, bool> class Inverse,
0625 unsigned int Order = 4
0626 >
0627 class sjoberg_intersection
0628 {
0629 typedef sjoberg_geodesic<CT, Order> geodesic_type;
0630 typedef Inverse<CT, false, true, false, false, false> inverse_type;
0631 typedef typename inverse_type::result_type inverse_result;
0632
0633 static bool const enable_02 = true;
0634 static int const max_iterations_02 = 10;
0635 static int const max_iterations_07 = 20;
0636
0637 public:
0638 template <typename T1, typename T2, typename Spheroid>
0639 static inline bool apply(T1 const& lona1, T1 const& lata1,
0640 T1 const& lona2, T1 const& lata2,
0641 T2 const& lonb1, T2 const& latb1,
0642 T2 const& lonb2, T2 const& latb2,
0643 CT & lon, CT & lat,
0644 Spheroid const& spheroid)
0645 {
0646 CT const lon_a1 = lona1;
0647 CT const lat_a1 = lata1;
0648 CT const lon_a2 = lona2;
0649 CT const lat_a2 = lata2;
0650 CT const lon_b1 = lonb1;
0651 CT const lat_b1 = latb1;
0652 CT const lon_b2 = lonb2;
0653 CT const lat_b2 = latb2;
0654
0655 inverse_result const res1 = inverse_type::apply(lon_a1, lat_a1, lon_a2, lat_a2, spheroid);
0656 inverse_result const res2 = inverse_type::apply(lon_b1, lat_b1, lon_b2, lat_b2, spheroid);
0657
0658 return apply(lon_a1, lat_a1, lon_a2, lat_a2, res1.azimuth,
0659 lon_b1, lat_b1, lon_b2, lat_b2, res2.azimuth,
0660 lon, lat, spheroid);
0661 }
0662
0663
0664 template <typename Spheroid>
0665 static inline bool apply(CT const& lon_a1, CT const& lat_a1, CT const& lon_a2, CT const& lat_a2, CT const& alpha_a1,
0666 CT const& lon_b1, CT const& lat_b1, CT const& lon_b2, CT const& lat_b2, CT const& alpha_b1,
0667 CT & lon, CT & lat,
0668 Spheroid const& spheroid)
0669 {
0670
0671
0672 CT const c0 = 0;
0673 CT const c1 = 1;
0674
0675 CT const f = formula::flattening<CT>(spheroid);
0676 CT const one_minus_f = c1 - f;
0677
0678 geodesic_type const geod1(lon_a1, lat_a1, alpha_a1, f);
0679 geodesic_type const geod2(lon_b1, lat_b1, alpha_b1, f);
0680
0681
0682
0683
0684 if (geod1.is_on_equator && geod2.is_on_equator)
0685 {
0686 return false;
0687 }
0688 else if (geod1.is_on_equator)
0689 {
0690 lon = geod2.lon_of_equator_intersection();
0691 lat = c0;
0692 return true;
0693 }
0694 else if (geod2.is_on_equator)
0695 {
0696 lon = geod1.lon_of_equator_intersection();
0697 lat = c0;
0698 return true;
0699 }
0700
0701
0702 CT const lon1_minus_lon2 = math::longitude_distance_signed<radian>(geod2.lonj, geod1.lonj);
0703
0704
0705 if (geod1.is_Cj_zero && geod2.is_Cj_zero)
0706 {
0707 CT const pi = math::pi<CT>();
0708
0709
0710 if ( math::equals(lon1_minus_lon2, c0)
0711 || math::equals(lon1_minus_lon2 + (lon1_minus_lon2 < c0 ? pi : -pi), c0) )
0712 {
0713 return false;
0714 }
0715
0716 lon = c0;
0717
0718
0719 CT const pi_half = pi / CT(2);
0720 CT const abs_lat_a1 = math::abs(lat_a1);
0721 CT const abs_lat_a2 = math::abs(lat_a2);
0722 if (math::equals(abs_lat_a1, abs_lat_a2))
0723 {
0724 lat = pi_half;
0725 }
0726 else
0727 {
0728
0729 CT const& closer_lat = abs_lat_a1 > abs_lat_a2 ? lat_a1 : lat_a2;
0730 lat = closer_lat >= 0 ? pi_half : -pi_half;
0731 }
0732
0733 return true;
0734 }
0735
0736 CT lon_sph = 0;
0737
0738
0739 CT t = 0;
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754 {
0755
0756
0757 CT tan_lat_sph = 0;
0758 sjoberg_intersection_spherical_02<CT>::apply_alt(lon_a1, lat_a1, lon_a2, lat_a2,
0759 lon_b1, lat_b1, lon_b2, lat_b2,
0760 lon_sph, tan_lat_sph);
0761
0762
0763 if (math::equals(f, c0))
0764 {
0765 lon = lon_sph;
0766 lat = atan(tan_lat_sph);
0767 return true;
0768 }
0769
0770 t = one_minus_f * tan_lat_sph;
0771 }
0772
0773
0774
0775 CT const beta = atan(t);
0776
0777 if (enable_02 && newton_method(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat))
0778 {
0779
0780
0781
0782
0783
0784
0785
0786 if ( is_result_longitude_ok(geod1, lon_a1, lon_a2, lon)
0787 && is_result_longitude_ok(geod2, lon_b1, lon_b2, lon) )
0788 {
0789 return true;
0790 }
0791 }
0792
0793 return converge_07(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat);
0794 }
0795
0796 private:
0797 static inline bool newton_method(geodesic_type const& geod1, geodesic_type const& geod2,
0798 CT beta, CT t, CT const& lon1_minus_lon2, CT const& lon_sph,
0799 CT & lon, CT & lat)
0800 {
0801 CT const c0 = 0;
0802 CT const c1 = 1;
0803
0804 CT const e_sqr = geod1.e_sqr;
0805
0806 CT lon1_diff = 0;
0807 CT lon2_diff = 0;
0808
0809
0810
0811 if (geod1.is_Cj_zero && math::abs(geod1.lonj - lon_sph) > math::half_pi<CT>())
0812 return false;
0813 if (geod2.is_Cj_zero && math::abs(geod2.lonj - lon_sph) > math::half_pi<CT>())
0814 return false;
0815
0816 CT abs_dbeta_last = 0;
0817
0818
0819
0820 for (int i = 0; i < max_iterations_02; ++i)
0821 {
0822 CT const cos_beta = cos(beta);
0823
0824 if (math::equals(cos_beta, c0))
0825 {
0826 return false;
0827 }
0828
0829 CT const sin_beta = sin(beta);
0830 CT const cos_beta_sqr = math::sqr(cos_beta);
0831 CT const G = c1 - e_sqr * cos_beta_sqr;
0832
0833 CT f1 = 0;
0834 CT f2 = 0;
0835
0836 if (!geod1.is_Cj_zero)
0837 {
0838 bool is_beta_ok = geod1.lon_diff(sin_beta, t, lon1_diff);
0839
0840 if (is_beta_ok)
0841 {
0842 CT const H = cos_beta_sqr - geod1.Cj_sqr;
0843 if (math::equals(H, c0))
0844 {
0845 return false;
0846 }
0847 f1 = geod1.Cj / cos_beta * math::sqrt(G / H);
0848 }
0849 else
0850 {
0851 return false;
0852 }
0853 }
0854
0855 if (!geod2.is_Cj_zero)
0856 {
0857 bool is_beta_ok = geod2.lon_diff(sin_beta, t, lon2_diff);
0858
0859 if (is_beta_ok)
0860 {
0861 CT const H = cos_beta_sqr - geod2.Cj_sqr;
0862 if (math::equals(H, c0))
0863 {
0864
0865
0866
0867
0868
0869 return false;
0870 }
0871 f2 = geod2.Cj / cos_beta * math::sqrt(G / H);
0872 }
0873 else
0874 {
0875 return false;
0876 }
0877 }
0878
0879
0880
0881
0882
0883
0884
0885
0886
0887
0888
0889 CT const dbeta_denom = f1 - f2;
0890
0891
0892 if (math::equals(dbeta_denom, c0))
0893 {
0894 return false;
0895 }
0896
0897
0898 CT const dbeta = (lon1_minus_lon2 + lon1_diff - lon2_diff) / dbeta_denom;
0899
0900 CT const abs_dbeta = math::abs(dbeta);
0901 if (i > 0 && abs_dbeta > abs_dbeta_last)
0902 {
0903
0904
0905 return false;
0906 }
0907 abs_dbeta_last = abs_dbeta;
0908
0909 if (math::equals(dbeta, c0))
0910 {
0911
0912 break;
0913 }
0914
0915
0916 beta = beta - dbeta;
0917
0918 t = tan(beta);
0919 }
0920
0921 lat = geod1.lat(t);
0922
0923 lon = ! geod1.is_Cj_zero
0924 ? geod1.lon(lon1_diff)
0925 : geod2.lon(lon2_diff);
0926
0927 return true;
0928 }
0929
0930 static inline bool is_result_longitude_ok(geodesic_type const& geod,
0931 CT const& lon1, CT const& lon2, CT const& lon)
0932 {
0933 CT const c0 = 0;
0934
0935 if (geod.is_Cj_zero)
0936 return true;
0937
0938 CT dist1p = math::longitude_distance_signed<radian>(lon1, lon);
0939 CT dist12 = math::longitude_distance_signed<radian>(lon1, lon2);
0940
0941 if (dist12 < c0)
0942 {
0943 dist1p = -dist1p;
0944 dist12 = -dist12;
0945 }
0946
0947 return (c0 <= dist1p && dist1p <= dist12)
0948 || math::equals(dist1p, c0)
0949 || math::equals(dist1p, dist12);
0950 }
0951
0952 struct geodesics_type
0953 {
0954 geodesics_type(geodesic_type const& g1, geodesic_type const& g2)
0955 : geod1(g1)
0956 , geod2(g2)
0957 , vertex1(geod1.get_vertex_data())
0958 , vertex2(geod2.get_vertex_data())
0959 {}
0960
0961 geodesic_type const& geod1;
0962 geodesic_type const& geod2;
0963 typename geodesic_type::vertex_data vertex1;
0964 typename geodesic_type::vertex_data vertex2;
0965 };
0966
0967 struct converge_07_result
0968 {
0969 converge_07_result()
0970 : lon1(0), lon2(0), k1_diff(0), k2_diff(0), t1(0), t2(0)
0971 {}
0972
0973 CT lon1, lon2;
0974 CT k1_diff, k2_diff;
0975 CT t1, t2;
0976 };
0977
0978 static inline bool converge_07(geodesic_type const& geod1, geodesic_type const& geod2,
0979 CT beta, CT t,
0980 CT const& lon1_minus_lon2, CT const& lon_sph,
0981 CT & lon, CT & lat)
0982 {
0983
0984
0985
0986
0987
0988 geodesics_type geodesics(geod1, geod2);
0989 converge_07_result result;
0990
0991
0992 if (!converge_07_step_one(CT(sin(beta)), t, lon1_minus_lon2, geodesics, lon_sph, result, false))
0993 {
0994 return false;
0995 }
0996
0997 int t_direction = 0;
0998
0999 CT lon_diff_prev = math::longitude_difference<radian>(result.lon1, result.lon2);
1000
1001
1002 for (int i = 2; i < max_iterations_07; ++i)
1003 {
1004
1005 CT t_cand1 = result.t1;
1006 CT t_cand2 = result.t2;
1007
1008 if (t_direction < 0)
1009 {
1010 t_cand1 = (std::min)(result.t1, result.t2);
1011 t_cand2 = (std::max)(result.t1, result.t2);
1012 }
1013 else if (t_direction > 0)
1014 {
1015 t_cand1 = (std::max)(result.t1, result.t2);
1016 t_cand2 = (std::min)(result.t1, result.t2);
1017 }
1018 else
1019 {
1020 t_direction = t_cand1 < t_cand2 ? -1 : 1;
1021 }
1022
1023 CT t1 = t;
1024 CT beta1 = beta;
1025
1026 if (converge_07_update(t1, beta1, t_cand1))
1027 {
1028 break;
1029 }
1030
1031 bool try_t2 = false;
1032 converge_07_result result_curr;
1033 if (converge_07_step_one(CT(sin(beta1)), t1, lon1_minus_lon2, geodesics, lon_sph, result_curr))
1034 {
1035 CT const lon_diff1 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2);
1036 if (lon_diff_prev > lon_diff1)
1037 {
1038 t = t1;
1039 beta = beta1;
1040 lon_diff_prev = lon_diff1;
1041 result = result_curr;
1042 }
1043 else if (t_cand1 != t_cand2)
1044 {
1045 try_t2 = true;
1046 }
1047 else
1048 {
1049
1050 break;
1051 }
1052 }
1053
1054 else
1055 {
1056 if (t_cand1 != t_cand2)
1057 {
1058 try_t2 = true;
1059 }
1060 else
1061 {
1062 return false;
1063 }
1064 }
1065
1066
1067 if (try_t2)
1068 {
1069 CT t2 = t;
1070 CT beta2 = beta;
1071
1072 if (converge_07_update(t2, beta2, t_cand2))
1073 {
1074 break;
1075 }
1076
1077 if (! converge_07_step_one(CT(sin(beta2)), t2, lon1_minus_lon2, geodesics, lon_sph, result_curr))
1078 {
1079 return false;
1080 }
1081
1082 CT const lon_diff2 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2);
1083 if (lon_diff_prev > lon_diff2)
1084 {
1085 t_direction *= -1;
1086 t = t2;
1087 beta = beta2;
1088 lon_diff_prev = lon_diff2;
1089 result = result_curr;
1090 }
1091 else
1092 {
1093
1094 break;
1095 }
1096 }
1097 }
1098
1099 lat = geod1.lat(t);
1100 lon = ! geod1.is_Cj_zero ? result.lon1 : result.lon2;
1101 math::normalize_longitude<radian>(lon);
1102
1103 return true;
1104 }
1105
1106 static inline bool converge_07_update(CT & t, CT & beta, CT const& t_new)
1107 {
1108 CT const c0 = 0;
1109
1110 CT const beta_new = atan(t_new);
1111 CT const dbeta = beta_new - beta;
1112 beta = beta_new;
1113 t = t_new;
1114
1115 return math::equals(dbeta, c0);
1116 }
1117
1118 static inline CT const& pick_t(CT const& t1, CT const& t2, int direction)
1119 {
1120 return direction < 0 ? (std::min)(t1, t2) : (std::max)(t1, t2);
1121 }
1122
1123 static inline bool converge_07_step_one(CT const& sin_beta,
1124 CT const& t,
1125 CT const& lon1_minus_lon2,
1126 geodesics_type const& geodesics,
1127 CT const& lon_sph,
1128 converge_07_result & result,
1129 bool check_sin_beta = true)
1130 {
1131 bool ok = converge_07_one_geod(sin_beta, t, geodesics.geod1, geodesics.vertex1, lon_sph,
1132 result.lon1, result.k1_diff, check_sin_beta)
1133 && converge_07_one_geod(sin_beta, t, geodesics.geod2, geodesics.vertex2, lon_sph,
1134 result.lon2, result.k2_diff, check_sin_beta);
1135
1136 if (!ok)
1137 {
1138 return false;
1139 }
1140
1141 CT const k = lon1_minus_lon2 + result.k1_diff - result.k2_diff;
1142
1143
1144
1145 calc_ts(t, k, geodesics.geod1, geodesics.geod2, result.t1, result.t2);
1146
1147 return true;
1148 }
1149
1150 static inline bool converge_07_one_geod(CT const& sin_beta, CT const& t,
1151 geodesic_type const& geod,
1152 typename geodesic_type::vertex_data const& vertex,
1153 CT const& lon_sph,
1154 CT & lon, CT & k_diff,
1155 bool check_sin_beta)
1156 {
1157 using math::detail::bounded;
1158 CT const c1 = 1;
1159
1160 CT k_diff_before = 0;
1161 CT k_diff_behind = 0;
1162
1163 bool is_beta_ok = geod.k_diffs(sin_beta, vertex, k_diff_before, k_diff_behind, check_sin_beta);
1164
1165 if (! is_beta_ok)
1166 {
1167 return false;
1168 }
1169
1170 CT const asin_t_t0j = ! geod.is_Cj_zero ? asin(bounded(t / geod.t0j, -c1, c1)) : 0;
1171 CT const sign_asin_t_t0j = geod.sign_lon_diff * asin_t_t0j;
1172
1173 CT const lon_before = geod.lonj + sign_asin_t_t0j + k_diff_before;
1174 CT const lon_behind = geod.lonj - sign_asin_t_t0j + k_diff_behind;
1175
1176 CT const lon_dist_before = math::longitude_distance_signed<radian>(lon_before, lon_sph);
1177 CT const lon_dist_behind = math::longitude_distance_signed<radian>(lon_behind, lon_sph);
1178 if (math::abs(lon_dist_before) <= math::abs(lon_dist_behind))
1179 {
1180 k_diff = k_diff_before;
1181 lon = lon_before;
1182 }
1183 else
1184 {
1185 k_diff = k_diff_behind;
1186 lon = lon_behind;
1187 }
1188
1189 return true;
1190 }
1191
1192 static inline void calc_ts(CT const& t, CT const& k,
1193 geodesic_type const& geod1, geodesic_type const& geod2,
1194 CT & t1, CT& t2)
1195 {
1196 CT const c0 = 0;
1197 CT const c1 = 1;
1198 CT const c2 = 2;
1199
1200 CT const K = sin(k);
1201
1202 BOOST_GEOMETRY_ASSERT(!geod1.is_Cj_zero || !geod2.is_Cj_zero);
1203 if (geod1.is_Cj_zero)
1204 {
1205 t1 = K * geod2.t0j;
1206 t2 = -t1;
1207 }
1208 else if (geod2.is_Cj_zero)
1209 {
1210 t1 = -K * geod1.t0j;
1211 t2 = -t1;
1212 }
1213 else
1214 {
1215 CT const A = math::sqr(geod1.t0j) + math::sqr(geod2.t0j);
1216 CT const B = c2 * geod1.t0j * geod2.t0j * math::sqrt(c1 - math::sqr(K));
1217
1218 CT const K_t01_t02 = K * geod1.t0j * geod2.t0j;
1219 CT const D1 = math::sqrt(A + B);
1220 CT const D2 = math::sqrt(A - B);
1221 CT const t_new1 = math::equals(D1, c0) ? c0 : K_t01_t02 / D1;
1222 CT const t_new2 = math::equals(D2, c0) ? c0 : K_t01_t02 / D2;
1223 CT const t_new3 = -t_new1;
1224 CT const t_new4 = -t_new2;
1225
1226
1227 CT const abs_t_new1 = math::abs(t_new1);
1228 CT const abs_t_new2 = math::abs(t_new2);
1229 CT const abs_t_max = (std::max)(abs_t_new1, abs_t_new2);
1230 t1 = -abs_t_max;
1231 t2 = abs_t_max;
1232 if (t1 < t)
1233 {
1234 if (t_new1 < t && t_new1 > t1)
1235 t1 = t_new1;
1236 if (t_new2 < t && t_new2 > t1)
1237 t1 = t_new2;
1238 if (t_new3 < t && t_new3 > t1)
1239 t1 = t_new3;
1240 if (t_new4 < t && t_new4 > t1)
1241 t1 = t_new4;
1242 }
1243 if (t2 > t)
1244 {
1245 if (t_new1 > t && t_new1 < t2)
1246 t2 = t_new1;
1247 if (t_new2 > t && t_new2 < t2)
1248 t2 = t_new2;
1249 if (t_new3 > t && t_new3 < t2)
1250 t2 = t_new3;
1251 if (t_new4 > t && t_new4 < t2)
1252 t2 = t_new4;
1253 }
1254 }
1255
1256
1257 if (math::abs(t - t2) < math::abs(t - t1))
1258 {
1259 std::swap(t2, t1);
1260 }
1261 }
1262
1263 static inline CT fj(CT const& cos_beta, CT const& cos2_beta, CT const& Cj, CT const& e_sqr)
1264 {
1265 CT const c1 = 1;
1266 CT const Cj_sqr = math::sqr(Cj);
1267 return Cj / cos_beta * math::sqrt((c1 - e_sqr * cos2_beta) / (cos2_beta - Cj_sqr));
1268 }
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282 };
1283
1284 }}}
1285
1286
1287 #endif