sjoberg_intersection.hpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287
  1. // Boost.Geometry
  2. // Copyright (c) 2016-2019 Oracle and/or its affiliates.
  3. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  4. // Use, modification and distribution is subject to the Boost Software License,
  5. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_GEOMETRY_FORMULAS_SJOBERG_INTERSECTION_HPP
  8. #define BOOST_GEOMETRY_FORMULAS_SJOBERG_INTERSECTION_HPP
  9. #include <boost/math/constants/constants.hpp>
  10. #include <boost/geometry/core/radius.hpp>
  11. #include <boost/geometry/util/condition.hpp>
  12. #include <boost/geometry/util/math.hpp>
  13. #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
  14. #include <boost/geometry/formulas/flattening.hpp>
  15. #include <boost/geometry/formulas/spherical.hpp>
  16. namespace boost { namespace geometry { namespace formula
  17. {
  18. /*!
  19. \brief The intersection of two great circles as proposed by Sjoberg.
  20. \see See
  21. - [Sjoberg02] Lars E. Sjoberg, Intersections on the sphere and ellipsoid, 2002
  22. http://link.springer.com/article/10.1007/s00190-001-0230-9
  23. */
  24. template <typename CT>
  25. struct sjoberg_intersection_spherical_02
  26. {
  27. // TODO: if it will be used as standalone formula
  28. // support segments on equator and endpoints on poles
  29. static inline bool apply(CT const& lon1, CT const& lat1, CT const& lon_a2, CT const& lat_a2,
  30. CT const& lon2, CT const& lat2, CT const& lon_b2, CT const& lat_b2,
  31. CT & lon, CT & lat)
  32. {
  33. CT tan_lat = 0;
  34. bool res = apply_alt(lon1, lat1, lon_a2, lat_a2,
  35. lon2, lat2, lon_b2, lat_b2,
  36. lon, tan_lat);
  37. if (res)
  38. {
  39. lat = atan(tan_lat);
  40. }
  41. return res;
  42. }
  43. static inline bool apply_alt(CT const& lon1, CT const& lat1, CT const& lon_a2, CT const& lat_a2,
  44. CT const& lon2, CT const& lat2, CT const& lon_b2, CT const& lat_b2,
  45. CT & lon, CT & tan_lat)
  46. {
  47. CT const cos_lon1 = cos(lon1);
  48. CT const sin_lon1 = sin(lon1);
  49. CT const cos_lon2 = cos(lon2);
  50. CT const sin_lon2 = sin(lon2);
  51. CT const sin_lat1 = sin(lat1);
  52. CT const sin_lat2 = sin(lat2);
  53. CT const cos_lat1 = cos(lat1);
  54. CT const cos_lat2 = cos(lat2);
  55. CT const tan_lat_a2 = tan(lat_a2);
  56. CT const tan_lat_b2 = tan(lat_b2);
  57. return apply(lon1, lon_a2, lon2, lon_b2,
  58. sin_lon1, cos_lon1, sin_lat1, cos_lat1,
  59. sin_lon2, cos_lon2, sin_lat2, cos_lat2,
  60. tan_lat_a2, tan_lat_b2,
  61. lon, tan_lat);
  62. }
  63. private:
  64. static inline bool apply(CT const& lon1, CT const& lon_a2, CT const& lon2, CT const& lon_b2,
  65. CT const& sin_lon1, CT const& cos_lon1, CT const& sin_lat1, CT const& cos_lat1,
  66. CT const& sin_lon2, CT const& cos_lon2, CT const& sin_lat2, CT const& cos_lat2,
  67. CT const& tan_lat_a2, CT const& tan_lat_b2,
  68. CT & lon, CT & tan_lat)
  69. {
  70. // NOTE:
  71. // cos_lat_ = 0 <=> segment on equator
  72. // tan_alpha_ = 0 <=> segment vertical
  73. CT const tan_lat1 = sin_lat1 / cos_lat1; //tan(lat1);
  74. CT const tan_lat2 = sin_lat2 / cos_lat2; //tan(lat2);
  75. CT const dlon1 = lon_a2 - lon1;
  76. CT const sin_dlon1 = sin(dlon1);
  77. CT const dlon2 = lon_b2 - lon2;
  78. CT const sin_dlon2 = sin(dlon2);
  79. CT const cos_dlon1 = cos(dlon1);
  80. CT const cos_dlon2 = cos(dlon2);
  81. CT const tan_alpha1_x = cos_lat1 * tan_lat_a2 - sin_lat1 * cos_dlon1;
  82. CT const tan_alpha2_x = cos_lat2 * tan_lat_b2 - sin_lat2 * cos_dlon2;
  83. CT const c0 = 0;
  84. bool const is_vertical1 = math::equals(sin_dlon1, c0) || math::equals(tan_alpha1_x, c0);
  85. bool const is_vertical2 = math::equals(sin_dlon2, c0) || math::equals(tan_alpha2_x, c0);
  86. CT tan_alpha1 = 0;
  87. CT tan_alpha2 = 0;
  88. if (is_vertical1 && is_vertical2)
  89. {
  90. // circles intersect at one of the poles or are collinear
  91. return false;
  92. }
  93. else if (is_vertical1)
  94. {
  95. tan_alpha2 = sin_dlon2 / tan_alpha2_x;
  96. lon = lon1;
  97. }
  98. else if (is_vertical2)
  99. {
  100. tan_alpha1 = sin_dlon1 / tan_alpha1_x;
  101. lon = lon2;
  102. }
  103. else
  104. {
  105. tan_alpha1 = sin_dlon1 / tan_alpha1_x;
  106. tan_alpha2 = sin_dlon2 / tan_alpha2_x;
  107. CT const T1 = tan_alpha1 * cos_lat1;
  108. CT const T2 = tan_alpha2 * cos_lat2;
  109. CT const T1T2 = T1*T2;
  110. CT const tan_lon_y = T1 * sin_lon2 - T2 * sin_lon1 + T1T2 * (tan_lat1 * cos_lon1 - tan_lat2 * cos_lon2);
  111. CT const tan_lon_x = T1 * cos_lon2 - T2 * cos_lon1 - T1T2 * (tan_lat1 * sin_lon1 - tan_lat2 * sin_lon2);
  112. lon = atan2(tan_lon_y, tan_lon_x);
  113. }
  114. // choose closer result
  115. CT const pi = math::pi<CT>();
  116. CT const lon_2 = lon > c0 ? lon - pi : lon + pi;
  117. CT const lon_dist1 = (std::max)((std::min)(math::longitude_difference<radian>(lon1, lon),
  118. math::longitude_difference<radian>(lon_a2, lon)),
  119. (std::min)(math::longitude_difference<radian>(lon2, lon),
  120. math::longitude_difference<radian>(lon_b2, lon)));
  121. CT const lon_dist2 = (std::max)((std::min)(math::longitude_difference<radian>(lon1, lon_2),
  122. math::longitude_difference<radian>(lon_a2, lon_2)),
  123. (std::min)(math::longitude_difference<radian>(lon2, lon_2),
  124. math::longitude_difference<radian>(lon_b2, lon_2)));
  125. if (lon_dist2 < lon_dist1)
  126. {
  127. lon = lon_2;
  128. }
  129. CT const sin_lon = sin(lon);
  130. CT const cos_lon = cos(lon);
  131. if (math::abs(tan_alpha1) >= math::abs(tan_alpha2)) // pick less vertical segment
  132. {
  133. CT const sin_dlon_1 = sin_lon * cos_lon1 - cos_lon * sin_lon1;
  134. CT const cos_dlon_1 = cos_lon * cos_lon1 + sin_lon * sin_lon1;
  135. CT const lat_y_1 = sin_dlon_1 + tan_alpha1 * sin_lat1 * cos_dlon_1;
  136. CT const lat_x_1 = tan_alpha1 * cos_lat1;
  137. tan_lat = lat_y_1 / lat_x_1;
  138. }
  139. else
  140. {
  141. CT const sin_dlon_2 = sin_lon * cos_lon2 - cos_lon * sin_lon2;
  142. CT const cos_dlon_2 = cos_lon * cos_lon2 + sin_lon * sin_lon2;
  143. CT const lat_y_2 = sin_dlon_2 + tan_alpha2 * sin_lat2 * cos_dlon_2;
  144. CT const lat_x_2 = tan_alpha2 * cos_lat2;
  145. tan_lat = lat_y_2 / lat_x_2;
  146. }
  147. return true;
  148. }
  149. };
  150. /*! Approximation of dLambda_j [Sjoberg07], expanded into taylor series in e^2
  151. Maxima script:
  152. dLI_j(c_j, sinB_j, sinB) := integrate(1 / (sqrt(1 - c_j ^ 2 - x ^ 2)*(1 + sqrt(1 - e2*(1 - x ^ 2)))), x, sinB_j, sinB);
  153. dL_j(c_j, B_j, B) := -e2 * c_j * dLI_j(c_j, B_j, B);
  154. S: taylor(dLI_j(c_j, sinB_j, sinB), e2, 0, 3);
  155. assume(c_j < 1);
  156. assume(c_j > 0);
  157. L1: factor(integrate(sqrt(-x ^ 2 - c_j ^ 2 + 1) / (x ^ 2 + c_j ^ 2 - 1), x));
  158. L2: factor(integrate(((x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x));
  159. L3: factor(integrate(((x ^ 4 - 2 * x ^ 2 + 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x));
  160. L4: factor(integrate(((x ^ 6 - 3 * x ^ 4 + 3 * x ^ 2 - 1)*sqrt(-x ^ 2 - c_j ^ 2 + 1)) / (x ^ 2 + c_j ^ 2 - 1), x));
  161. \see See
  162. - [Sjoberg07] Lars E. Sjoberg, Geodetic intersection on the ellipsoid, 2007
  163. http://link.springer.com/article/10.1007/s00190-007-0204-7
  164. */
  165. template <unsigned int Order, typename CT>
  166. inline CT sjoberg_d_lambda_e_sqr(CT const& sin_betaj, CT const& sin_beta,
  167. CT const& Cj, CT const& sqrt_1_Cj_sqr,
  168. CT const& e_sqr)
  169. {
  170. using math::detail::bounded;
  171. if (Order == 0)
  172. {
  173. return 0;
  174. }
  175. CT const c1 = 1;
  176. CT const c2 = 2;
  177. CT const asin_B = asin(bounded(sin_beta / sqrt_1_Cj_sqr, -c1, c1));
  178. CT const asin_Bj = asin(sin_betaj / sqrt_1_Cj_sqr);
  179. CT const L0 = (asin_B - asin_Bj) / c2;
  180. if (Order == 1)
  181. {
  182. return -Cj * e_sqr * L0;
  183. }
  184. CT const c0 = 0;
  185. CT const c16 = 16;
  186. CT const X = sin_beta;
  187. CT const Xj = sin_betaj;
  188. CT const X_sqr = math::sqr(X);
  189. CT const Xj_sqr = math::sqr(Xj);
  190. CT const Cj_sqr = math::sqr(Cj);
  191. CT const Cj_sqr_plus_one = Cj_sqr + c1;
  192. CT const one_minus_Cj_sqr = c1 - Cj_sqr;
  193. CT const sqrt_Y = math::sqrt(bounded(-X_sqr + one_minus_Cj_sqr, c0));
  194. CT const sqrt_Yj = math::sqrt(-Xj_sqr + one_minus_Cj_sqr);
  195. CT const L1 = (Cj_sqr_plus_one * (asin_B - asin_Bj) + X * sqrt_Y - Xj * sqrt_Yj) / c16;
  196. if (Order == 2)
  197. {
  198. return -Cj * e_sqr * (L0 + e_sqr * L1);
  199. }
  200. CT const c3 = 3;
  201. CT const c5 = 5;
  202. CT const c128 = 128;
  203. CT const E = Cj_sqr * (c3 * Cj_sqr + c2) + c3;
  204. CT const F = X * (-c2 * X_sqr + c3 * Cj_sqr + c5);
  205. CT const Fj = Xj * (-c2 * Xj_sqr + c3 * Cj_sqr + c5);
  206. CT const L2 = (E * (asin_B - asin_Bj) + F * sqrt_Y - Fj * sqrt_Yj) / c128;
  207. if (Order == 3)
  208. {
  209. return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * L2));
  210. }
  211. CT const c8 = 8;
  212. CT const c9 = 9;
  213. CT const c10 = 10;
  214. CT const c15 = 15;
  215. CT const c24 = 24;
  216. CT const c26 = 26;
  217. CT const c33 = 33;
  218. CT const c6144 = 6144;
  219. CT const G = Cj_sqr * (Cj_sqr * (Cj_sqr * c15 + c9) + c9) + c15;
  220. CT const H = -c10 * Cj_sqr - c26;
  221. CT const I = Cj_sqr * (Cj_sqr * c15 + c24) + c33;
  222. CT const J = X_sqr * (X * (c8 * X_sqr + H)) + X * I;
  223. CT const Jj = Xj_sqr * (Xj * (c8 * Xj_sqr + H)) + Xj * I;
  224. CT const L3 = (G * (asin_B - asin_Bj) + J * sqrt_Y - Jj * sqrt_Yj) / c6144;
  225. // Order 4 and higher
  226. return -Cj * e_sqr * (L0 + e_sqr * (L1 + e_sqr * (L2 + e_sqr * L3)));
  227. }
  228. /*!
  229. \brief The representation of geodesic as proposed by Sjoberg.
  230. \see See
  231. - [Sjoberg07] Lars E. Sjoberg, Geodetic intersection on the ellipsoid, 2007
  232. http://link.springer.com/article/10.1007/s00190-007-0204-7
  233. - [Sjoberg12] Lars E. Sjoberg, Solutions to the ellipsoidal Clairaut constant
  234. and the inverse geodetic problem by numerical integration, 2012
  235. https://www.degruyter.com/view/j/jogs.2012.2.issue-3/v10156-011-0037-4/v10156-011-0037-4.xml
  236. */
  237. template <typename CT, unsigned int Order>
  238. class sjoberg_geodesic
  239. {
  240. sjoberg_geodesic() {}
  241. static int sign_C(CT const& alphaj)
  242. {
  243. CT const c0 = 0;
  244. CT const c2 = 2;
  245. CT const pi = math::pi<CT>();
  246. CT const pi_half = pi / c2;
  247. return (pi_half < alphaj && alphaj < pi) || (-pi_half < alphaj && alphaj < c0) ? -1 : 1;
  248. }
  249. public:
  250. sjoberg_geodesic(CT const& lon, CT const& lat, CT const& alpha, CT const& f)
  251. : lonj(lon)
  252. , latj(lat)
  253. , alphaj(alpha)
  254. {
  255. CT const c0 = 0;
  256. CT const c1 = 1;
  257. CT const c2 = 2;
  258. //CT const pi = math::pi<CT>();
  259. //CT const pi_half = pi / c2;
  260. one_minus_f = c1 - f;
  261. e_sqr = f * (c2 - f);
  262. tan_latj = tan(lat);
  263. tan_betaj = one_minus_f * tan_latj;
  264. betaj = atan(tan_betaj);
  265. sin_betaj = sin(betaj);
  266. cos_betaj = cos(betaj);
  267. sin_alphaj = sin(alphaj);
  268. // Clairaut constant (lower-case in the paper)
  269. Cj = sign_C(alphaj) * cos_betaj * sin_alphaj;
  270. Cj_sqr = math::sqr(Cj);
  271. sqrt_1_Cj_sqr = math::sqrt(c1 - Cj_sqr);
  272. sign_lon_diff = alphaj >= 0 ? 1 : -1; // || alphaj == -pi ?
  273. //sign_lon_diff = 1;
  274. is_on_equator = math::equals(sqrt_1_Cj_sqr, c0);
  275. is_Cj_zero = math::equals(Cj, c0);
  276. t0j = c0;
  277. asin_tj_t0j = c0;
  278. if (! is_Cj_zero)
  279. {
  280. t0j = sqrt_1_Cj_sqr / Cj;
  281. }
  282. if (! is_on_equator)
  283. {
  284. //asin_tj_t0j = asin(tan_betaj / t0j);
  285. asin_tj_t0j = asin(tan_betaj * Cj / sqrt_1_Cj_sqr);
  286. }
  287. }
  288. struct vertex_data
  289. {
  290. //CT beta0j;
  291. CT sin_beta0j;
  292. CT dL0j;
  293. CT lon0j;
  294. };
  295. vertex_data get_vertex_data() const
  296. {
  297. CT const c2 = 2;
  298. CT const pi = math::pi<CT>();
  299. CT const pi_half = pi / c2;
  300. vertex_data res;
  301. if (! is_Cj_zero)
  302. {
  303. //res.beta0j = atan(t0j);
  304. //res.sin_beta0j = sin(res.beta0j);
  305. res.sin_beta0j = math::sign(t0j) * sqrt_1_Cj_sqr;
  306. res.dL0j = d_lambda(res.sin_beta0j);
  307. res.lon0j = lonj + sign_lon_diff * (pi_half - asin_tj_t0j + res.dL0j);
  308. }
  309. else
  310. {
  311. //res.beta0j = pi_half;
  312. //res.sin_beta0j = betaj >= 0 ? 1 : -1;
  313. res.sin_beta0j = 1;
  314. res.dL0j = 0;
  315. res.lon0j = lonj;
  316. }
  317. return res;
  318. }
  319. bool is_sin_beta_ok(CT const& sin_beta) const
  320. {
  321. CT const c1 = 1;
  322. return math::abs(sin_beta / sqrt_1_Cj_sqr) <= c1;
  323. }
  324. bool k_diff(CT const& sin_beta,
  325. CT & delta_k) const
  326. {
  327. if (is_Cj_zero)
  328. {
  329. delta_k = 0;
  330. return true;
  331. }
  332. // beta out of bounds and not close
  333. if (! (is_sin_beta_ok(sin_beta)
  334. || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) )
  335. {
  336. return false;
  337. }
  338. // NOTE: beta may be slightly out of bounds here but d_lambda handles that
  339. CT const dLj = d_lambda(sin_beta);
  340. delta_k = sign_lon_diff * (/*asin_t_t0j*/ - asin_tj_t0j + dLj);
  341. return true;
  342. }
  343. bool lon_diff(CT const& sin_beta, CT const& t,
  344. CT & delta_lon) const
  345. {
  346. using math::detail::bounded;
  347. CT const c1 = 1;
  348. if (is_Cj_zero)
  349. {
  350. delta_lon = 0;
  351. return true;
  352. }
  353. CT delta_k = 0;
  354. if (! k_diff(sin_beta, delta_k))
  355. {
  356. return false;
  357. }
  358. CT const t_t0j = t / t0j;
  359. // NOTE: t may be slightly out of bounds here
  360. CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1));
  361. delta_lon = sign_lon_diff * asin_t_t0j + delta_k;
  362. return true;
  363. }
  364. bool k_diffs(CT const& sin_beta, vertex_data const& vd,
  365. CT & delta_k_before, CT & delta_k_behind,
  366. bool check_sin_beta = true) const
  367. {
  368. CT const pi = math::pi<CT>();
  369. if (is_Cj_zero)
  370. {
  371. delta_k_before = 0;
  372. delta_k_behind = sign_lon_diff * pi;
  373. return true;
  374. }
  375. // beta out of bounds and not close
  376. if (check_sin_beta
  377. && ! (is_sin_beta_ok(sin_beta)
  378. || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) )
  379. {
  380. return false;
  381. }
  382. // NOTE: beta may be slightly out of bounds here but d_lambda handles that
  383. CT const dLj = d_lambda(sin_beta);
  384. delta_k_before = sign_lon_diff * (/*asin_t_t0j*/ - asin_tj_t0j + dLj);
  385. // This version require no additional dLj calculation
  386. delta_k_behind = sign_lon_diff * (pi /*- asin_t_t0j*/ - asin_tj_t0j + vd.dL0j + (vd.dL0j - dLj));
  387. // [Sjoberg12]
  388. //CT const dL101 = d_lambda(sin_betaj, vd.sin_beta0j);
  389. // WARNING: the following call might not work if beta was OoB because only the second argument is bounded
  390. //CT const dL_01 = d_lambda(sin_beta, vd.sin_beta0j);
  391. //delta_k_behind = sign_lon_diff * (pi /*- asin_t_t0j*/ - asin_tj_t0j + dL101 + dL_01);
  392. return true;
  393. }
  394. bool lon_diffs(CT const& sin_beta, CT const& t, vertex_data const& vd,
  395. CT & delta_lon_before, CT & delta_lon_behind) const
  396. {
  397. using math::detail::bounded;
  398. CT const c1 = 1;
  399. CT const pi = math::pi<CT>();
  400. if (is_Cj_zero)
  401. {
  402. delta_lon_before = 0;
  403. delta_lon_behind = sign_lon_diff * pi;
  404. return true;
  405. }
  406. CT delta_k_before = 0, delta_k_behind = 0;
  407. if (! k_diffs(sin_beta, vd, delta_k_before, delta_k_behind))
  408. {
  409. return false;
  410. }
  411. CT const t_t0j = t / t0j;
  412. // NOTE: t may be slightly out of bounds here
  413. CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1));
  414. CT const sign_asin_t_t0j = sign_lon_diff * asin_t_t0j;
  415. delta_lon_before = sign_asin_t_t0j + delta_k_before;
  416. delta_lon_behind = -sign_asin_t_t0j + delta_k_behind;
  417. return true;
  418. }
  419. bool lon(CT const& sin_beta, CT const& t, vertex_data const& vd,
  420. CT & lon_before, CT & lon_behind) const
  421. {
  422. using math::detail::bounded;
  423. CT const c1 = 1;
  424. CT const pi = math::pi<CT>();
  425. if (is_Cj_zero)
  426. {
  427. lon_before = lonj;
  428. lon_behind = lonj + sign_lon_diff * pi;
  429. return true;
  430. }
  431. if (! (is_sin_beta_ok(sin_beta)
  432. || math::equals(math::abs(sin_beta), sqrt_1_Cj_sqr)) )
  433. {
  434. return false;
  435. }
  436. CT const t_t0j = t / t0j;
  437. CT const asin_t_t0j = asin(bounded(t_t0j, -c1, c1));
  438. CT const dLj = d_lambda(sin_beta);
  439. lon_before = lonj + sign_lon_diff * (asin_t_t0j - asin_tj_t0j + dLj);
  440. lon_behind = vd.lon0j + (vd.lon0j - lon_before);
  441. return true;
  442. }
  443. CT lon(CT const& delta_lon) const
  444. {
  445. return lonj + delta_lon;
  446. }
  447. CT lat(CT const& t) const
  448. {
  449. // t = tan(beta) = (1-f)tan(lat)
  450. return atan(t / one_minus_f);
  451. }
  452. void vertex(CT & lon, CT & lat) const
  453. {
  454. lon = get_vertex_data().lon0j;
  455. if (! is_Cj_zero)
  456. {
  457. lat = sjoberg_geodesic::lat(t0j);
  458. }
  459. else
  460. {
  461. CT const c2 = 2;
  462. lat = math::pi<CT>() / c2;
  463. }
  464. }
  465. CT lon_of_equator_intersection() const
  466. {
  467. CT const c0 = 0;
  468. CT const dLj = d_lambda(c0);
  469. CT const asin_tj_t0j = asin(Cj * tan_betaj / sqrt_1_Cj_sqr);
  470. return lonj - asin_tj_t0j + dLj;
  471. }
  472. CT d_lambda(CT const& sin_beta) const
  473. {
  474. return sjoberg_d_lambda_e_sqr<Order>(sin_betaj, sin_beta, Cj, sqrt_1_Cj_sqr, e_sqr);
  475. }
  476. // [Sjoberg12]
  477. /*CT d_lambda(CT const& sin_beta1, CT const& sin_beta2) const
  478. {
  479. return sjoberg_d_lambda_e_sqr<Order>(sin_beta1, sin_beta2, Cj, sqrt_1_Cj_sqr, e_sqr);
  480. }*/
  481. CT lonj;
  482. CT latj;
  483. CT alphaj;
  484. CT one_minus_f;
  485. CT e_sqr;
  486. CT tan_latj;
  487. CT tan_betaj;
  488. CT betaj;
  489. CT sin_betaj;
  490. CT cos_betaj;
  491. CT sin_alphaj;
  492. CT Cj;
  493. CT Cj_sqr;
  494. CT sqrt_1_Cj_sqr;
  495. int sign_lon_diff;
  496. bool is_on_equator;
  497. bool is_Cj_zero;
  498. CT t0j;
  499. CT asin_tj_t0j;
  500. };
  501. /*!
  502. \brief The intersection of two geodesics as proposed by Sjoberg.
  503. \see See
  504. - [Sjoberg02] Lars E. Sjoberg, Intersections on the sphere and ellipsoid, 2002
  505. http://link.springer.com/article/10.1007/s00190-001-0230-9
  506. - [Sjoberg07] Lars E. Sjoberg, Geodetic intersection on the ellipsoid, 2007
  507. http://link.springer.com/article/10.1007/s00190-007-0204-7
  508. - [Sjoberg12] Lars E. Sjoberg, Solutions to the ellipsoidal Clairaut constant
  509. and the inverse geodetic problem by numerical integration, 2012
  510. https://www.degruyter.com/view/j/jogs.2012.2.issue-3/v10156-011-0037-4/v10156-011-0037-4.xml
  511. */
  512. template
  513. <
  514. typename CT,
  515. template <typename, bool, bool, bool, bool, bool> class Inverse,
  516. unsigned int Order = 4
  517. >
  518. class sjoberg_intersection
  519. {
  520. typedef sjoberg_geodesic<CT, Order> geodesic_type;
  521. typedef Inverse<CT, false, true, false, false, false> inverse_type;
  522. typedef typename inverse_type::result_type inverse_result;
  523. static bool const enable_02 = true;
  524. static int const max_iterations_02 = 10;
  525. static int const max_iterations_07 = 20;
  526. public:
  527. template <typename T1, typename T2, typename Spheroid>
  528. static inline bool apply(T1 const& lona1, T1 const& lata1,
  529. T1 const& lona2, T1 const& lata2,
  530. T2 const& lonb1, T2 const& latb1,
  531. T2 const& lonb2, T2 const& latb2,
  532. CT & lon, CT & lat,
  533. Spheroid const& spheroid)
  534. {
  535. CT const lon_a1 = lona1;
  536. CT const lat_a1 = lata1;
  537. CT const lon_a2 = lona2;
  538. CT const lat_a2 = lata2;
  539. CT const lon_b1 = lonb1;
  540. CT const lat_b1 = latb1;
  541. CT const lon_b2 = lonb2;
  542. CT const lat_b2 = latb2;
  543. inverse_result const res1 = inverse_type::apply(lon_a1, lat_a1, lon_a2, lat_a2, spheroid);
  544. inverse_result const res2 = inverse_type::apply(lon_b1, lat_b1, lon_b2, lat_b2, spheroid);
  545. return apply(lon_a1, lat_a1, lon_a2, lat_a2, res1.azimuth,
  546. lon_b1, lat_b1, lon_b2, lat_b2, res2.azimuth,
  547. lon, lat, spheroid);
  548. }
  549. // TODO: Currently may not work correctly if one of the endpoints is the pole
  550. template <typename Spheroid>
  551. static inline bool apply(CT const& lon_a1, CT const& lat_a1, CT const& lon_a2, CT const& lat_a2, CT const& alpha_a1,
  552. CT const& lon_b1, CT const& lat_b1, CT const& lon_b2, CT const& lat_b2, CT const& alpha_b1,
  553. CT & lon, CT & lat,
  554. Spheroid const& spheroid)
  555. {
  556. // coordinates in radians
  557. CT const c0 = 0;
  558. CT const c1 = 1;
  559. CT const f = formula::flattening<CT>(spheroid);
  560. CT const one_minus_f = c1 - f;
  561. geodesic_type geod1(lon_a1, lat_a1, alpha_a1, f);
  562. geodesic_type geod2(lon_b1, lat_b1, alpha_b1, f);
  563. // Cj = 1 if on equator <=> sqrt_1_Cj_sqr = 0
  564. // Cj = 0 if vertical <=> sqrt_1_Cj_sqr = 1
  565. if (geod1.is_on_equator && geod2.is_on_equator)
  566. {
  567. return false;
  568. }
  569. else if (geod1.is_on_equator)
  570. {
  571. lon = geod2.lon_of_equator_intersection();
  572. lat = c0;
  573. return true;
  574. }
  575. else if (geod2.is_on_equator)
  576. {
  577. lon = geod1.lon_of_equator_intersection();
  578. lat = c0;
  579. return true;
  580. }
  581. // (lon1 - lon2) normalized to (-180, 180]
  582. CT const lon1_minus_lon2 = math::longitude_distance_signed<radian>(geod2.lonj, geod1.lonj);
  583. // vertical segments
  584. if (geod1.is_Cj_zero && geod2.is_Cj_zero)
  585. {
  586. CT const pi = math::pi<CT>();
  587. // the geodesics are parallel, the intersection point cannot be calculated
  588. if ( math::equals(lon1_minus_lon2, c0)
  589. || math::equals(lon1_minus_lon2 + (lon1_minus_lon2 < c0 ? pi : -pi), c0) )
  590. {
  591. return false;
  592. }
  593. lon = c0;
  594. // the geodesics intersect at one of the poles
  595. CT const pi_half = pi / CT(2);
  596. CT const abs_lat_a1 = math::abs(lat_a1);
  597. CT const abs_lat_a2 = math::abs(lat_a2);
  598. if (math::equals(abs_lat_a1, abs_lat_a2))
  599. {
  600. lat = pi_half;
  601. }
  602. else
  603. {
  604. // pick the pole closest to one of the points of the first segment
  605. CT const& closer_lat = abs_lat_a1 > abs_lat_a2 ? lat_a1 : lat_a2;
  606. lat = closer_lat >= 0 ? pi_half : -pi_half;
  607. }
  608. return true;
  609. }
  610. CT lon_sph = 0;
  611. // Starting tan(beta)
  612. CT t = 0;
  613. /*if (geod1.is_Cj_zero)
  614. {
  615. CT const k_base = lon1_minus_lon2 + geod2.sign_lon_diff * geod2.asin_tj_t0j;
  616. t = sin(k_base) * geod2.t0j;
  617. lon_sph = vertical_intersection_longitude(geod1.lonj, lon_b1, lon_b2);
  618. }
  619. else if (geod2.is_Cj_zero)
  620. {
  621. CT const k_base = lon1_minus_lon2 - geod1.sign_lon_diff * geod1.asin_tj_t0j;
  622. t = sin(-k_base) * geod1.t0j;
  623. lon_sph = vertical_intersection_longitude(geod2.lonj, lon_a1, lon_a2);
  624. }
  625. else*/
  626. {
  627. // TODO: Consider using betas instead of latitudes.
  628. // Some function calls might be saved this way.
  629. CT tan_lat_sph = 0;
  630. sjoberg_intersection_spherical_02<CT>::apply_alt(lon_a1, lat_a1, lon_a2, lat_a2,
  631. lon_b1, lat_b1, lon_b2, lat_b2,
  632. lon_sph, tan_lat_sph);
  633. // Return for sphere
  634. if (math::equals(f, c0))
  635. {
  636. lon = lon_sph;
  637. lat = atan(tan_lat_sph);
  638. return true;
  639. }
  640. t = one_minus_f * tan_lat_sph; // tan(beta)
  641. }
  642. // TODO: no need to calculate atan here if reduced latitudes were used
  643. // instead of latitudes above, in sjoberg_intersection_spherical_02
  644. CT const beta = atan(t);
  645. if (enable_02 && newton_method(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat))
  646. {
  647. // TODO: Newton's method may return wrong result in some specific cases
  648. // Detected for sphere and nearly sphere, e.g. A=6371228, B=6371227
  649. // and segments s1=(-121 -19,37 8) and s2=(-19 -15,-104 -58)
  650. // It's unclear if this is a bug or a characteristic of this method
  651. // so until this is investigated check if the resulting longitude is
  652. // between endpoints of the segments. It should be since before calling
  653. // this formula sides of endpoints WRT other segments are checked.
  654. if ( is_result_longitude_ok(geod1, lon_a1, lon_a2, lon)
  655. && is_result_longitude_ok(geod2, lon_b1, lon_b2, lon) )
  656. {
  657. return true;
  658. }
  659. }
  660. return converge_07(geod1, geod2, beta, t, lon1_minus_lon2, lon_sph, lon, lat);
  661. }
  662. private:
  663. static inline bool newton_method(geodesic_type const& geod1, geodesic_type const& geod2, // in
  664. CT beta, CT t, CT const& lon1_minus_lon2, CT const& lon_sph, // in
  665. CT & lon, CT & lat) // out
  666. {
  667. CT const c0 = 0;
  668. CT const c1 = 1;
  669. CT const e_sqr = geod1.e_sqr;
  670. CT lon1_diff = 0;
  671. CT lon2_diff = 0;
  672. // The segment is vertical and intersection point is behind the vertex
  673. // this method is unable to calculate correct result
  674. if (geod1.is_Cj_zero && math::abs(geod1.lonj - lon_sph) > math::half_pi<CT>())
  675. return false;
  676. if (geod2.is_Cj_zero && math::abs(geod2.lonj - lon_sph) > math::half_pi<CT>())
  677. return false;
  678. CT abs_dbeta_last = 0;
  679. // [Sjoberg02] converges faster than solution in [Sjoberg07]
  680. // Newton-Raphson method
  681. for (int i = 0; i < max_iterations_02; ++i)
  682. {
  683. CT const cos_beta = cos(beta);
  684. if (math::equals(cos_beta, c0))
  685. {
  686. return false;
  687. }
  688. CT const sin_beta = sin(beta);
  689. CT const cos_beta_sqr = math::sqr(cos_beta);
  690. CT const G = c1 - e_sqr * cos_beta_sqr;
  691. CT f1 = 0;
  692. CT f2 = 0;
  693. if (!geod1.is_Cj_zero)
  694. {
  695. bool is_beta_ok = geod1.lon_diff(sin_beta, t, lon1_diff);
  696. if (is_beta_ok)
  697. {
  698. CT const H = cos_beta_sqr - geod1.Cj_sqr;
  699. if (math::equals(H, c0))
  700. {
  701. return false;
  702. }
  703. f1 = geod1.Cj / cos_beta * math::sqrt(G / H);
  704. }
  705. else
  706. {
  707. return false;
  708. }
  709. }
  710. if (!geod2.is_Cj_zero)
  711. {
  712. bool is_beta_ok = geod2.lon_diff(sin_beta, t, lon2_diff);
  713. if (is_beta_ok)
  714. {
  715. CT const H = cos_beta_sqr - geod2.Cj_sqr;
  716. if (math::equals(H, c0))
  717. {
  718. // NOTE: This may happen for segment nearly
  719. // at the equator. Detected for (radian):
  720. // (-0.0872665 -0.0872665, -0.0872665 0.0872665)
  721. // x
  722. // (0 1.57e-07, -0.392699 1.57e-07)
  723. return false;
  724. }
  725. f2 = geod2.Cj / cos_beta * math::sqrt(G / H);
  726. }
  727. else
  728. {
  729. return false;
  730. }
  731. }
  732. // NOTE: Things may go wrong if the IP is near the vertex
  733. // 1. May converge into the wrong direction (from the other way around).
  734. // This happens when the starting point is on the other side than the vertex
  735. // 2. During converging may "jump" into the other side of the vertex.
  736. // In this case sin_beta/sqrt_1_Cj_sqr and t/t0j is not in [-1, 1]
  737. // 3. f1-f2 may be 0 which means that the intermediate point is on the vertex
  738. // In this case it's not possible to check if this is the correct result
  739. // 4. f1-f2 may also be 0 in other cases, e.g.
  740. // geodesics are symmetrical wrt equator and longitude directions are different
  741. CT const dbeta_denom = f1 - f2;
  742. //CT const dbeta_denom = math::abs(f1) + math::abs(f2);
  743. if (math::equals(dbeta_denom, c0))
  744. {
  745. return false;
  746. }
  747. // The sign of dbeta is changed WRT [Sjoberg02]
  748. CT const dbeta = (lon1_minus_lon2 + lon1_diff - lon2_diff) / dbeta_denom;
  749. CT const abs_dbeta = math::abs(dbeta);
  750. if (i > 0 && abs_dbeta > abs_dbeta_last)
  751. {
  752. // The algorithm is not converging
  753. // The intersection may be on the other side of the vertex
  754. return false;
  755. }
  756. abs_dbeta_last = abs_dbeta;
  757. if (math::equals(dbeta, c0))
  758. {
  759. // Result found
  760. break;
  761. }
  762. // Because the sign of dbeta is changed WRT [Sjoberg02] dbeta is subtracted here
  763. beta = beta - dbeta;
  764. t = tan(beta);
  765. }
  766. lat = geod1.lat(t);
  767. // NOTE: if Cj is 0 then the result is lonj or lonj+180
  768. lon = ! geod1.is_Cj_zero
  769. ? geod1.lon(lon1_diff)
  770. : geod2.lon(lon2_diff);
  771. return true;
  772. }
  773. static inline bool is_result_longitude_ok(geodesic_type const& geod,
  774. CT const& lon1, CT const& lon2, CT const& lon)
  775. {
  776. CT const c0 = 0;
  777. if (geod.is_Cj_zero)
  778. return true; // don't check vertical segment
  779. CT dist1p = math::longitude_distance_signed<radian>(lon1, lon);
  780. CT dist12 = math::longitude_distance_signed<radian>(lon1, lon2);
  781. if (dist12 < c0)
  782. {
  783. dist1p = -dist1p;
  784. dist12 = -dist12;
  785. }
  786. return (c0 <= dist1p && dist1p <= dist12)
  787. || math::equals(dist1p, c0)
  788. || math::equals(dist1p, dist12);
  789. }
  790. struct geodesics_type
  791. {
  792. geodesics_type(geodesic_type const& g1, geodesic_type const& g2)
  793. : geod1(g1)
  794. , geod2(g2)
  795. , vertex1(geod1.get_vertex_data())
  796. , vertex2(geod2.get_vertex_data())
  797. {}
  798. geodesic_type const& geod1;
  799. geodesic_type const& geod2;
  800. typename geodesic_type::vertex_data vertex1;
  801. typename geodesic_type::vertex_data vertex2;
  802. };
  803. struct converge_07_result
  804. {
  805. converge_07_result()
  806. : lon1(0), lon2(0), k1_diff(0), k2_diff(0), t1(0), t2(0)
  807. {}
  808. CT lon1, lon2;
  809. CT k1_diff, k2_diff;
  810. CT t1, t2;
  811. };
  812. static inline bool converge_07(geodesic_type const& geod1, geodesic_type const& geod2,
  813. CT beta, CT t,
  814. CT const& lon1_minus_lon2, CT const& lon_sph,
  815. CT & lon, CT & lat)
  816. {
  817. //CT const c0 = 0;
  818. //CT const c1 = 1;
  819. //CT const c2 = 2;
  820. //CT const pi = math::pi<CT>();
  821. geodesics_type geodesics(geod1, geod2);
  822. converge_07_result result;
  823. // calculate first pair of longitudes
  824. if (!converge_07_step_one(CT(sin(beta)), t, lon1_minus_lon2, geodesics, lon_sph, result, false))
  825. {
  826. return false;
  827. }
  828. int t_direction = 0;
  829. CT lon_diff_prev = math::longitude_difference<radian>(result.lon1, result.lon2);
  830. // [Sjoberg07]
  831. for (int i = 2; i < max_iterations_07; ++i)
  832. {
  833. // pick t candidates from previous result based on dir
  834. CT t_cand1 = result.t1;
  835. CT t_cand2 = result.t2;
  836. // if direction is 0 the closer one is the first
  837. if (t_direction < 0)
  838. {
  839. t_cand1 = (std::min)(result.t1, result.t2);
  840. t_cand2 = (std::max)(result.t1, result.t2);
  841. }
  842. else if (t_direction > 0)
  843. {
  844. t_cand1 = (std::max)(result.t1, result.t2);
  845. t_cand2 = (std::min)(result.t1, result.t2);
  846. }
  847. else
  848. {
  849. t_direction = t_cand1 < t_cand2 ? -1 : 1;
  850. }
  851. CT t1 = t;
  852. CT beta1 = beta;
  853. // check if the further calculation is needed
  854. if (converge_07_update(t1, beta1, t_cand1))
  855. {
  856. break;
  857. }
  858. bool try_t2 = false;
  859. converge_07_result result_curr;
  860. if (converge_07_step_one(CT(sin(beta1)), t1, lon1_minus_lon2, geodesics, lon_sph, result_curr))
  861. {
  862. CT const lon_diff1 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2);
  863. if (lon_diff_prev > lon_diff1)
  864. {
  865. t = t1;
  866. beta = beta1;
  867. lon_diff_prev = lon_diff1;
  868. result = result_curr;
  869. }
  870. else if (t_cand1 != t_cand2)
  871. {
  872. try_t2 = true;
  873. }
  874. else
  875. {
  876. // the result is not fully correct but it won't be more accurate
  877. break;
  878. }
  879. }
  880. // ! converge_07_step_one
  881. else
  882. {
  883. if (t_cand1 != t_cand2)
  884. {
  885. try_t2 = true;
  886. }
  887. else
  888. {
  889. return false;
  890. }
  891. }
  892. if (try_t2)
  893. {
  894. CT t2 = t;
  895. CT beta2 = beta;
  896. // check if the further calculation is needed
  897. if (converge_07_update(t2, beta2, t_cand2))
  898. {
  899. break;
  900. }
  901. if (! converge_07_step_one(CT(sin(beta2)), t2, lon1_minus_lon2, geodesics, lon_sph, result_curr))
  902. {
  903. return false;
  904. }
  905. CT const lon_diff2 = math::longitude_difference<radian>(result_curr.lon1, result_curr.lon2);
  906. if (lon_diff_prev > lon_diff2)
  907. {
  908. t_direction *= -1;
  909. t = t2;
  910. beta = beta2;
  911. lon_diff_prev = lon_diff2;
  912. result = result_curr;
  913. }
  914. else
  915. {
  916. // the result is not fully correct but it won't be more accurate
  917. break;
  918. }
  919. }
  920. }
  921. lat = geod1.lat(t);
  922. lon = ! geod1.is_Cj_zero ? result.lon1 : result.lon2;
  923. math::normalize_longitude<radian>(lon);
  924. return true;
  925. }
  926. static inline bool converge_07_update(CT & t, CT & beta, CT const& t_new)
  927. {
  928. CT const c0 = 0;
  929. CT const beta_new = atan(t_new);
  930. CT const dbeta = beta_new - beta;
  931. beta = beta_new;
  932. t = t_new;
  933. return math::equals(dbeta, c0);
  934. }
  935. static inline CT const& pick_t(CT const& t1, CT const& t2, int direction)
  936. {
  937. return direction < 0 ? (std::min)(t1, t2) : (std::max)(t1, t2);
  938. }
  939. static inline bool converge_07_step_one(CT const& sin_beta,
  940. CT const& t,
  941. CT const& lon1_minus_lon2,
  942. geodesics_type const& geodesics,
  943. CT const& lon_sph,
  944. converge_07_result & result,
  945. bool check_sin_beta = true)
  946. {
  947. bool ok = converge_07_one_geod(sin_beta, t, geodesics.geod1, geodesics.vertex1, lon_sph,
  948. result.lon1, result.k1_diff, check_sin_beta)
  949. && converge_07_one_geod(sin_beta, t, geodesics.geod2, geodesics.vertex2, lon_sph,
  950. result.lon2, result.k2_diff, check_sin_beta);
  951. if (!ok)
  952. {
  953. return false;
  954. }
  955. CT const k = lon1_minus_lon2 + result.k1_diff - result.k2_diff;
  956. // get 2 possible ts one lesser and one greater than t
  957. // t1 is the closer one
  958. calc_ts(t, k, geodesics.geod1, geodesics.geod2, result.t1, result.t2);
  959. return true;
  960. }
  961. static inline bool converge_07_one_geod(CT const& sin_beta, CT const& t,
  962. geodesic_type const& geod,
  963. typename geodesic_type::vertex_data const& vertex,
  964. CT const& lon_sph,
  965. CT & lon, CT & k_diff,
  966. bool check_sin_beta)
  967. {
  968. using math::detail::bounded;
  969. CT const c1 = 1;
  970. CT k_diff_before = 0;
  971. CT k_diff_behind = 0;
  972. bool is_beta_ok = geod.k_diffs(sin_beta, vertex, k_diff_before, k_diff_behind, check_sin_beta);
  973. if (! is_beta_ok)
  974. {
  975. return false;
  976. }
  977. CT const asin_t_t0j = ! geod.is_Cj_zero ? asin(bounded(t / geod.t0j, -c1, c1)) : 0;
  978. CT const sign_asin_t_t0j = geod.sign_lon_diff * asin_t_t0j;
  979. CT const lon_before = geod.lonj + sign_asin_t_t0j + k_diff_before;
  980. CT const lon_behind = geod.lonj - sign_asin_t_t0j + k_diff_behind;
  981. CT const lon_dist_before = math::longitude_distance_signed<radian>(lon_before, lon_sph);
  982. CT const lon_dist_behind = math::longitude_distance_signed<radian>(lon_behind, lon_sph);
  983. if (math::abs(lon_dist_before) <= math::abs(lon_dist_behind))
  984. {
  985. k_diff = k_diff_before;
  986. lon = lon_before;
  987. }
  988. else
  989. {
  990. k_diff = k_diff_behind;
  991. lon = lon_behind;
  992. }
  993. return true;
  994. }
  995. static inline void calc_ts(CT const& t, CT const& k,
  996. geodesic_type const& geod1, geodesic_type const& geod2,
  997. CT & t1, CT& t2)
  998. {
  999. CT const c0 = 0;
  1000. CT const c1 = 1;
  1001. CT const c2 = 2;
  1002. CT const K = sin(k);
  1003. BOOST_GEOMETRY_ASSERT(!geod1.is_Cj_zero || !geod2.is_Cj_zero);
  1004. if (geod1.is_Cj_zero)
  1005. {
  1006. t1 = K * geod2.t0j;
  1007. t2 = -t1;
  1008. }
  1009. else if (geod2.is_Cj_zero)
  1010. {
  1011. t1 = -K * geod1.t0j;
  1012. t2 = -t1;
  1013. }
  1014. else
  1015. {
  1016. CT const A = math::sqr(geod1.t0j) + math::sqr(geod2.t0j);
  1017. CT const B = c2 * geod1.t0j * geod2.t0j * math::sqrt(c1 - math::sqr(K));
  1018. CT const K_t01_t02 = K * geod1.t0j * geod2.t0j;
  1019. CT const D1 = math::sqrt(A + B);
  1020. CT const D2 = math::sqrt(A - B);
  1021. CT const t_new1 = math::equals(D1, c0) ? c0 : K_t01_t02 / D1;
  1022. CT const t_new2 = math::equals(D2, c0) ? c0 : K_t01_t02 / D2;
  1023. CT const t_new3 = -t_new1;
  1024. CT const t_new4 = -t_new2;
  1025. // Pick 2 nearest t_new, one greater and one lesser than current t
  1026. CT const abs_t_new1 = math::abs(t_new1);
  1027. CT const abs_t_new2 = math::abs(t_new2);
  1028. CT const abs_t_max = (std::max)(abs_t_new1, abs_t_new2);
  1029. t1 = -abs_t_max; // lesser
  1030. t2 = abs_t_max; // greater
  1031. if (t1 < t)
  1032. {
  1033. if (t_new1 < t && t_new1 > t1)
  1034. t1 = t_new1;
  1035. if (t_new2 < t && t_new2 > t1)
  1036. t1 = t_new2;
  1037. if (t_new3 < t && t_new3 > t1)
  1038. t1 = t_new3;
  1039. if (t_new4 < t && t_new4 > t1)
  1040. t1 = t_new4;
  1041. }
  1042. if (t2 > t)
  1043. {
  1044. if (t_new1 > t && t_new1 < t2)
  1045. t2 = t_new1;
  1046. if (t_new2 > t && t_new2 < t2)
  1047. t2 = t_new2;
  1048. if (t_new3 > t && t_new3 < t2)
  1049. t2 = t_new3;
  1050. if (t_new4 > t && t_new4 < t2)
  1051. t2 = t_new4;
  1052. }
  1053. }
  1054. // the first one is the closer one
  1055. if (math::abs(t - t2) < math::abs(t - t1))
  1056. {
  1057. std::swap(t2, t1);
  1058. }
  1059. }
  1060. static inline CT fj(CT const& cos_beta, CT const& cos2_beta, CT const& Cj, CT const& e_sqr)
  1061. {
  1062. CT const c1 = 1;
  1063. CT const Cj_sqr = math::sqr(Cj);
  1064. return Cj / cos_beta * math::sqrt((c1 - e_sqr * cos2_beta) / (cos2_beta - Cj_sqr));
  1065. }
  1066. /*static inline CT vertical_intersection_longitude(CT const& ip_lon, CT const& seg_lon1, CT const& seg_lon2)
  1067. {
  1068. CT const c0 = 0;
  1069. CT const lon_2 = ip_lon > c0 ? ip_lon - pi : ip_lon + pi;
  1070. return (std::min)(math::longitude_difference<radian>(ip_lon, seg_lon1),
  1071. math::longitude_difference<radian>(ip_lon, seg_lon2))
  1072. <=
  1073. (std::min)(math::longitude_difference<radian>(lon_2, seg_lon1),
  1074. math::longitude_difference<radian>(lon_2, seg_lon2))
  1075. ? ip_lon : lon_2;
  1076. }*/
  1077. };
  1078. }}} // namespace boost::geometry::formula
  1079. #endif // BOOST_GEOMETRY_FORMULAS_SJOBERG_INTERSECTION_HPP