22 , _ellipthresh(1/real(8))
55 ang bet10(bet1), omg10(omg1);
58 bool flip1 =
t().
AngNorm(bet1, omg1, prolate()),
59 flip2 =
t().
AngNorm(bet2, omg2, prolate());
64 ang tmp1(prolate() ? omg2 : bet1), tmp2(prolate() ? omg1 : bet2);
66 ang tmp12 = tmp2 - tmp1;
67 swap12 = tmp12.
s() > 0;
68 if (!biaxial() && tmp12.
s() == 0) {
70 tmp1 = omg1; tmp2 = omg2;
73 swap12 = tmp12.
s() < 0;
86 }
else if (prolate()) {
93 bool swapomg = swapomg_ &&
95 !(bet1.
c() == 0 && omg2.
s() == 0) &&
96 fabs(omg2.
s()) < fabs(omg1.
s());
97 if (swapomg)
swap(omg1, omg2);
99 bool flipz = bet1.
s() > 0;
105 bool flipy = prolate() ? signbit(bet2.
c()) :
106 signbit(omg1.
s()) || (omg1.
s() == 0 && signbit(omg2.
s()));
116 bool flipx = signbit(omg1.
c());
121 bool flipomg = bet2.
c() == 0 && signbit(omg2.
s());
124 if (flipomg) omg2.
reflect(
true);
126 bool umb1 = bet1.
c() == 0 && omg1.
s() == 0,
127 umb2 = bet2.
c() == 0 && omg2.
s() == 0;
224 TL::fline lf = _umbline->_f;
230 if constexpr (debug_)
231 cout <<
"COORDS " << real(bet1) <<
" " << real(omg1) <<
" " 232 << real(bet2) <<
" " << real(omg2) <<
"\n";
235 bool done =
false, backside =
false;
236 if (bet1.
c() * omg1.
s() == 0 && bet2.
c() * omg2.
s() == 0) {
238 if (umb1 && umb2 && bet2.
s() > 0 && omg2.
c() < 0) {
241 alp1 = biaxial() ?
ang(k(), kp(), 0,
true) :
242 ang(exp(lf.deltashift()/2), 1);
243 fic = TL::fline::fics(lf, bet1, omg1, alp1);
244 bool betp = k2() < kp2();
247 d = lf.ArcPos0(fic,
ang::cardinal(2), bet2a, omg2a, alp2, betp);
248 if constexpr (debug_) msg =
"A.c opposite umbilics";
249 backside = signbit(bet2a.
c());
251 }
else if (bet1.
c() == 0 && bet2.
c() == 0) {
258 fic = TL::fline::fics(lf, bet1, omg1, alp1);
259 ang omg12 = omg2 - omg1;
260 if (omg12.
s() == 0 && omg12.
c() < 0) {
264 TL::fline::disttx{ (biaxial() ? 1 : -1 ) *
Math::pi()/2,
268 TL::fline::disttx{ -BigValue(), BigValue(), 0 };
269 if constexpr (debug_) msg =
"A.c.2 adjacent EW umbilics";
272 d = lf.ArcPos0(fic, omg12.
base(), bet2a, omg2a, alp2,
false);
273 if constexpr (debug_) msg =
"A.c.2 bet1/2 = -90";
284 fic = TL::fline::fics(lf, bet1, omg1, alp1);
286 if (omg1.
s() == 0 && omg2.
s() == 0) {
291 TL::fline::disttx{ BigValue(), -BigValue(), 0 };
293 if constexpr (debug_) msg =
"A.c.3 adjacent NS umbilics";
304 if (omg2a.
s() >= -numeric_limits<real>::epsilon()/2) {
306 ang omg12 = omg2 + omg1;
308 d = lf.ArcPos0(fic, omg12.
base(), bet2a, omg2a, alp2,
false);
309 if (!biaxial() && signbit(omg2a.s()))
311 if constexpr (debug_) msg =
"A.c.3 bet1/2 = -/+90 meridional";
316 (void) lf.ArcPos0(fic,
ang::cardinal(-2), bet2a, omg2a, alp2);
320 if constexpr (debug_)
321 msg =
"A.c.3 general bet1/2 = -/+90, non-meridional";
324 if constexpr (debug_)
326 << real(alpa) <<
" " << fa <<
" " 327 << real(alpb) <<
" " << fb <<
"\n";
337 alp1 = oblate() ? omg2 :
342 (omg1.
s() == 0 && !prolate() ? 0 : -1)) :
343 (omg2.
c() > 0 ? 0 : 2)));
344 fic = TL::fline::fics(lf, bet1, omg1, alp1);
346 lf.ArcPos0(fic, (omg2-omg1).base(), bet2a, omg2a, alp2,
false) :
347 lf.Hybrid(fic, bet2, bet2a, omg2a, alp2);
348 if (prolate() && signbit(bet2a.
c()))
350 if constexpr (debug_) msg =
"A.c.4 other meridional";
351 backside = signbit(bet2a.
c());
354 }
else if (bet1.
s() == 0 && bet2.
s() == 0) {
356 ang omg12 = (omg2 - omg1).base();
357 int E = signbit(omg12.
s()) ? -1 : 1;
361 lf = TL::fline(this->
t(), gamma(bet1, omg1, alp1));
362 fic = TL::fline::fics(lf, bet1, omg1, alp1);
363 (void) lf.ArcPos0(fic,
ang::cardinal(2), bet2a, omg2a, alp2);
365 if (E * omg2a.
s() >= -numeric_limits<real>::epsilon()/2) {
367 d = lf.ArcPos0(fic, omg12.
flipsign(E), bet2a, omg2a, alp2,
false);
368 if constexpr (debug_) msg =
"A.b.1 bet1/2 = 0 equatorial";
374 (E > 0 ? fa : fb) = omg2a.
radians0();
375 (void) lf.ArcPos0(fic,
ang::cardinal(-2), bet2a, omg2a, alp2);
377 (E > 0 ? fb : fa) = omg2a.
radians0();
378 if constexpr (debug_) msg =
"A.b.2 general bet1/2 = 0 non-equatorial";
383 alp2 =
ang(kp() * omg2.
s(), k() * bet2.
c());
386 fic = TL::fline::fics(lf, bet2, omg2, alp2);
389 real delta = (lf.transpolar() ? -1 : 1) * fic.delta;
409 ang(exp(lf.deltashift()/2 - delta), 1));
410 fic = TL::fline::fics(lf, bet1, omg1, alp1);
411 d = lf.ArcPos0(fic, (betp ? bet2 - bet1 : omg2 - omg1).base(),
412 bet2a, omg2a, alp2, betp);
413 if constexpr (debug_) msg =
"B.a umbilic to general";
415 }
else if (bet1.
c() == 0) {
419 if (!signbit(omg2.
s())) {
430 if constexpr (debug_) msg =
"B.b general bet1 = -90";
432 }
else if (omg1.
s() == 0) {
444 alpa =
ang(-numeric_limits<real>::epsilon()/(1<<20), -1, 0,
true);
445 alpb =
ang(-numeric_limits<real>::epsilon()/(1<<20), 1, 0,
true);
449 if constexpr (debug_) msg =
"B.c general omg1 = 0";
454 alpa =
ang( kp() * fabs(omg1.
s()), k() * fabs(bet1.
c()));
457 fic = TL::fline::fics(lf, bet1, omg1, alpb);
458 unsigned qb = 0U, qa = 3U;
459 if constexpr (debug_) msg =
"B.d general";
460 for (; !done && qb <= 4U; ++qb, ++qa) {
466 f[qb] = lf.Hybrid0(fic, bet2, omg2);
467 if constexpr (debug_)
468 cout <<
"f[qb] " << qb <<
" " << f[qb] <<
"\n";
469 if (fabs(f[qb]) < 2*numeric_limits<real>::epsilon()) {
471 d = lf.Hybrid(fic, bet2, bet2a, omg2a, alp2);
472 if constexpr (debug_) msg =
"B.d accidental umbilic";
473 backside = signbit(bet2a.
c());
478 if (qb && (f[qa & 3U] < 0 && f[qb & 3U] > 0) &&
483 f[qb & 3U] - f[qa & 3U] < 4) {
487 if constexpr (debug_)
488 cout <<
"fDD " << done <<
" " << qa <<
" " << qb <<
" " 489 << f[qa & 3U] <<
" " << f[qb & 3U] <<
"\n";
491 fa = f[qa & 3U]; fb = f[qb & 3U];
497 int countn = 0, countb = 0;
500 if constexpr (debug_)
501 cout <<
"X " << done <<
" " << msg <<
"\n";
503 [
this, &bet1, &omg1, &bet2, &omg2]
504 (
const ang& alp) -> real
506 return HybridA(bet1, omg1, alp, bet2, omg2,
true);
511 if constexpr (debug_)
512 cout <<
"ALP1 " << real(alp1) <<
"\n";
513 lf = TL::fline(this->
t(), gamma(bet1, omg1, alp1));
514 fic = TL::fline::fics(lf, bet1, omg1, alp1);
530 if (hybridalt_ && (swapomg_ || omg1.
s() <= fabs(omg2.
s())))
531 betp = (lf.transpolar() ?
532 2 * (aa + lf.gammax()) > (aa + bb) :
533 2 * (bb + lf.gammax()) < (aa + bb));
534 d = lf.Hybrid(fic, betp ? bet2 : omg2, bet2a, omg2a, alp2, betp);
536 backside = (betp || bet2.
c() != 0) && signbit(bet2a.
c());
539 if (!biaxial() && backside) alp2.
reflect(
true,
true);
542 TL::gline lg(this->
t(), lf.gm());
543 TL::gline::gics gic(lg, fic);
544 s12 = lg.dist(gic, d);
546 if constexpr (debug_)
548 << flip1 << flip2 << swap12 << swapomg
549 << flipz << flipy << flipx << flipomg
550 << lf.transpolar() <<
"\n";
551 if constexpr (debug_)
553 << real(bet1) <<
" " << real(omg1) <<
" " << real(alp1) <<
" " 554 << real(bet2) <<
" " << real(omg2) <<
" " << real(alp2) <<
"\n";
562 if constexpr (debug_)
564 << real(bet1) <<
" " << real(omg1) <<
" " << real(alp1) <<
" " 565 << real(bet2) <<
" " << real(omg2) <<
" " << real(alp2) <<
"\n";
573 if constexpr (debug_)
575 << real(bet1) <<
" " << real(omg1) <<
" " << real(alp1) <<
" " 576 << real(bet2) <<
" " << real(omg2) <<
" " << real(alp2) <<
"\n";
591 if constexpr (debug_)
593 << real(bet1) <<
" " << real(omg1) <<
" " << real(alp1) <<
" " 594 << real(bet2) <<
" " << real(omg2) <<
" " << real(alp2) <<
"\n";
602 if constexpr (debug_)
604 << real(bet1) <<
" " << real(omg1) <<
" " << real(alp1) <<
" " 605 << real(bet2) <<
" " << real(omg2) <<
" " << real(alp2) <<
"\n";
608 if (lf.transpolar()) {
610 calp1 = copysign(hypot(k()/kp()*bet1.
c(), lf.nu()), alp1.
c()),
611 calp2 = copysign(hypot(k()/kp()*bet2.
c(), lf.nu()), alp2.
c()),
612 salp1 = (lf.nu() < lf.nup() ?
613 (omg1.
s() - lf.nu()) * (omg1.
s() + lf.nu()) :
614 (lf.nup() - omg1.
c()) * (lf.nup() + omg1.
c())),
615 salp2 = (lf.nu() < lf.nup() ?
616 (omg2.
s() - lf.nu()) * (omg2.
s() + lf.nu()) :
617 (lf.nup() - omg2.
c()) * (lf.nup() + omg2.
c()));
618 salp1 = -copysign(signbit(salp1) ? 0 : sqrt(salp1), alp2.
s());
619 salp2 = -copysign(signbit(salp2) ? 0 : sqrt(salp2), alp1.
s());
620 alp1 =
ang(salp1, calp1);
621 alp2 =
ang(salp2, calp2);
624 salp1 = -copysign(hypot(kp()/k()*omg1.
s(), lf.nu()), alp1.
s()),
625 salp2 = -copysign(hypot(kp()/k()*omg2.
s(), lf.nu()), alp2.
s()),
626 calp1 = (lf.nu() < lf.nup() ?
627 (bet1.
c() - lf.nu()) * (bet1.
c() + lf.nu()) :
628 (lf.nup() - bet1.
s()) * (lf.nup() + bet1.
s())),
629 calp2 = (lf.nu() < lf.nup() ?
630 (bet2.
c() - lf.nu()) * (bet2.
c() + lf.nu()) :
631 (lf.nup() - bet2.
s()) * (lf.nup() + bet2.
s()));
632 calp1 = copysign(signbit(calp1) ? 0 : sqrt(calp1), alp1.
c());
633 calp2 = copysign(signbit(calp2) ? 0 : sqrt(calp2), alp2.
c());
634 alp1 =
ang(salp1, calp1);
635 alp2 =
ang(salp2, calp2);
645 if (umb2 && !biaxial())
651 if constexpr (debug_)
653 << real(bet1) <<
" " << real(omg1) <<
" " << real(alp1) <<
" " 654 << real(bet2) <<
" " << real(omg2) <<
" " << real(alp2) <<
"\n";
655 if (flip1)
t().Flip(bet1, omg1, alp1);
656 if (flip2)
t().Flip(bet2, omg2, alp2);
658 if constexpr (debug_)
660 << real(bet1) <<
" " << real(omg1) <<
" " << real(alp1) <<
" " 661 << real(bet2) <<
" " << real(omg2) <<
" " << real(alp2) <<
"\n";
663 fic = TL::fline::fics(lf, bet10, omg10, alp1);
664 gic = TL::gline::gics(lg, fic);
665 gic.s13 = signbit(s12) ? 0 : s12;
668 return TL(std::move(lf), std::move(fic), std::move(lg), std::move(gic));
674 ang b1{bet1}, o1{omg1}, a1{alp1};
676 gamblk gam = gamma(b1, o1, a1);
677 GeodesicLine3::fline l(this->
t(), gam);
678 GeodesicLine3::fline::fics ic(l, b1, o1, a1);
679 real dang = l.Hybrid0(ic, bet2a, omg2b, betp);
685 Angle Geodesic3::findroot(
const function<
real(
const ang&)>& f,
688 int* countn,
int* countb) {
703 int cntn = 0, cntb = 0;
705 const bool debug = debug_;
721 cout <<
"FA FB " << fa/numeric_limits<real>::epsilon() <<
" " 722 << fb/numeric_limits<real>::epsilon() <<
" " << (fa == fb) <<
"\n";
723 if (fa == fb && fabs(fa) <= 512*numeric_limits<real>::epsilon())
730 return ang(xa.
s() + xb.
s(), xa.
c() + xb.
c());
731 else if (fmin(fabs(fa), fabs(fb)) > 2*numeric_limits<real>::epsilon())
734 (
"Bad inputs Geodesic3::findroot");
737 return fabs(fa) < fabs(fb) ? xa : xb;
740 for (
real t = 1/
real(2), tp =
t, ab = 0, ft = 0, fc = 0;
743 (
"Convergence failure Geodesic3::findroot"),
false));) {
745 ang(xa.
s() + xb.
s(), xa.
c() + xb.
c()) :
747 xb +
ang::radians(tp * ab)),
758 cout <<
"H " << cntn <<
" " <<
real(xt)-x0 <<
" " << ft <<
"\n";
759 if (!(fabs(ft) >= numeric_limits<real>::epsilon())) {
765 if (signbit(ft) == signbit(fa)) {
769 xc = xb; xb = xa; xa = xt;
770 fc = fb; fb = fa; fa = ft;
772 xm = fabs(fb) < fabs(fa) ? xb : xa;
774 ab = (xa-xb).radians0();
776 ca = (xc-xa).radians0(),
779 tl = numeric_limits<real>::epsilon() / fabs(ab);
782 cout <<
"R " << cntn <<
" " << ab <<
" " << cb <<
"\n";
783 trip = !(2 * tl < 1);
785 cout <<
"TRIP " << ab <<
"\n";
789 tl = fmin(1/
real(32), 16*tl);
793 phi = (fa-fb) / (fc-fb),
794 phip = (fc-fa) / (fc-fb);
796 t = fa/(fb-fa) * fc/(fb-fc) - ca/ab * fa/(fc-fa) * fb/(fc-fb);
798 cout <<
"J1 " << cntn <<
" " <<
t <<
" " << 1 -
t <<
"\n";
802 tp = fb/(fb-fa) * fc/(fc-fa) + cb/ab * fa/(fc-fa) * fb/(fc-fb);
811 cout <<
"J2 " << cntn <<
" " <<
t <<
" " << 1 -
t <<
"\n";
814 if (countn) *countn += cntn;
815 if (countb) *countb += cntb;
819 Geodesic3::gamblk::gamblk(
const Geodesic3& tg,
821 real a = tg.k() * bet.
c() * alp.
s(), b = tg.kp() * omg.
s() * alp.
c();
822 gamma = (a - b) * (a + b);
831 if (!(tg.k2() == 0 || tg.kp2() == 0)) {
834 alpdiff = 2 * alp.
c() * alp.
s()
836 betdiff = -2 * bet.
c() * bet.
s() * tg.k2() *
Math::sq(alp.
s()),
837 omgdiff = -2 * omg.
c() * omg.
s() * tg.kp2() *
Math::sq(alp.
c());
838 maxdiff = fmax( fabs(alpdiff), fmax( fabs(betdiff), fabs(omgdiff) ) );
840 if (fabs(gamma) <= 2 * maxdiff * numeric_limits<real>::epsilon()) {
845 if ((tg.umbalt() && tg.kp2() > 0) || tg.k2() == 0) gamma = -gamma;
847 transpolar = signbit(gamma);
848 gammax = fabs(gamma);
849 kx2 = !transpolar ? tg.k2() : tg.kp2();
850 kxp2 = transpolar ? tg.k2() : tg.kp2();
851 kx = !transpolar ? tg.k() : tg.kp();
852 kxp = transpolar ? tg.k() : tg.kp();
856 hypot(kx * hypot(bet.
s(), alp.
c()*bet.
c()),
857 kxp * omg.
s()*alp.
c()) :
858 hypot(kxp * bet.
c()*alp.
s(),
859 kx * hypot(omg.
c(), alp.
s()*omg.
s())));
861 nu = sqrt(gammax) / kx;
865 Geodesic3::gamblk::gamblk(
const Geodesic3& tg,
bool neg)
867 , gamma(transpolar ? -
real(0) :
real(0))
871 , kx2(!transpolar ? tg.k2() : tg.kp2())
872 , kxp2(transpolar ? tg.k2() : tg.kp2())
873 , kx(!transpolar ? tg.k() : tg.kp())
874 , kxp(transpolar ? tg.k() : tg.kp())
877 Geodesic3::gamblk Geodesic3::gamma(
ang bet,
ang omg,
ang alp)
const {
878 return gamblk(*
this, bet, omg, alp);
894 real& s12, real& alp1, real& alp2)
const {
898 alp1 = real(alp1a); alp2 = real(alp2a);
907 real& bet2, real& omg2, real& alp2)
909 ang bet2a, omg2a, alp2a;
911 bet2a, omg2a, alp2a);
912 bet2 = real(bet2a); omg2 = real(omg2a); alp2 = real(alp2a);
const Ellipsoid3 & t() const
static AngleT radians(T rad)
AngleT & reflect(bool flips, bool flipc=false, bool swapp=false)
AngleT< Math::real > Angle
static AngleT cardinal(Math::real q)
GeodesicLine3 Direct(Angle bet1, Angle omg1, Angle alp1, real s12, Angle &bet2, Angle &omg2, Angle &alp2) const
Header for GeographicLib::Triaxial::Geodesic3 class.
Math::real radians() const
AngleT & setquadrant(unsigned q)
The direct geodesic problem for a triaxial ellipsoid.
static bool AngNorm(Angle &bet, Angle &omg, Angle &alp, bool alt=false)
Geodesic3(const Ellipsoid3 &t=Ellipsoid3{})
GeodesicLine3 Line(Angle bet1, Angle omg1, Angle alp1) const
Namespace for GeographicLib.
AngleT flipsign(T mult) const
GeographicLib::Math::real real
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
The solution of the geodesic problem for a triaxial ellipsoid.
Exception handling for GeographicLib.
GeodesicLine3 Inverse(Angle bet1, Angle omg1, Angle bet2, Angle omg2, real &s12, Angle &alp1, Angle &alp2) const
void Position(real s12, Angle &bet2, Angle &omg2, Angle &alp2) const