21 GeodesicLine3::GeodesicLine3(fline f, fline::fics fic,
22 gline g, gline::gics gic)
30 GeodesicLine3::GeodesicLine3(
const Geodesic3& tg)
31 : _f(tg, Geodesic3::gamblk(tg, (tg._umbalt &&
32 tg.kp2() > 0) || tg.k2() == 0))
42 Geodesic3::gamblk gam = _tg.gamma(bet1, omg1, alp1);
50 real bet1, real omg1, real alp1)
51 : GeodesicLine3(tg, ang(bet1), ang(omg1), ang(alp1))
55 _fic.pos1(_f.transpolar(), bet1, omg1, alp1);
60 ang bet1a, omg1a, alp1a;
61 pos1(bet1a, omg1a, alp1a);
74 real sig2 = _gic.sig1 + s12/_tg.b();
75 ang &phi2a = bet2a, &tht2a = omg2a;
76 int *countn =
nullptr, *countb =
nullptr;
77 if (_f.gammax() > 0) {
79 if constexpr (
false && biaxspecial(_tg, _g.gammax())) {
80 u2 = gpsi().inv(sig2, countn, countb);
81 v2 = ftht().inv(fpsi()(u2) - _fic.delta, countn, countb);
85 solve2(_fic.delta, sig2, fpsi(), ftht(), gpsi(), gtht(), u2, v2,
90 phi2a =
ang(_f.gm().nup * psi2.
s(),
91 _fic.phi0.c() * hypot(psi2.
c(), _f.gm().nu * psi2.
s()),
92 0,
true).
rebase(_fic.phi0);
93 alp2a =
ang(_fic.Ex * hypot(_f.kx() * _f.gm().nu, _f.kxp() * tht2a.c()),
94 _fic.phi0.c() * _f.kx() * _f.gm().nup * psi2.
c());
95 }
else if (_f.gammax() == 0) {
96 pair<real, real> sig2n = remx(sig2, 2*_g.s0);
106 solve2(_fic.delta, sig2n.first,
107 fpsi(), ftht(), gpsi(), gtht(), u2, v2,
113 if (signbit(phi2a.
c()))
114 phi2a =
ang(copysign(
real(1), phi2a.
s()),
115 numeric_limits<real>::epsilon()/(1<<11), 0,
true);
117 int parity = fmod(sig2n.second, real(2)) != 0 ? -1 : 1;
118 int Ny = _fic.Nx * parity;
119 phi2a = phi2a.
reflect(signbit(_fic.phi0.c() * Ny),
120 signbit(_fic.phi0.c())).
rebase(_fic.phi0);
122 alp2a =
ang(_fic.Ex * real(0), _fic.Nx * parity, 0,
true);
124 if (sig2n.first - _g.s0 >= -5 * numeric_limits<real>::epsilon()) {
125 sig2n.first = -_g.s0;
128 real deltax = bigclamp(_fic.delta + sig2n.second * _f.deltashift(), 1);
129 solve2u(deltax, sig2n.first, fpsi(), ftht(), gpsi(), gtht(), u2, v2,
132 phi2a = anglam(u2, _f.kxp());
134 tht2a = anglam(v2, _f.kx());
135 int parity = fmod(sig2n.second, real(2)) != 0 ? -1 : 1;
137 int Ny = _fic.Nx * parity;
139 tht2a = tht2a + _fic.tht0;
140 phi2a = phi2a.
reflect(signbit(_fic.phi0.c() * Ny),
141 signbit(_fic.phi0.c())).
rebase(_fic.phi0);
143 alp2a =
ang(_fic.Ex * _f.kxp() / mcosh(v2, _f.kx()),
144 _f.kx() * Ny / mcosh(u2, _f.kxp()));
153 if (_f.transpolar()) {
155 alp2a.
reflect(
false,
false,
true);
157 alp2a = alp2a.
rebase(_fic.alp0);
162 real& bet2, real& omg2, real& alp2,
164 ang bet2a, omg2a, alp2a;
175 void GeodesicLine3::solve2(
real f0,
real g0,
176 const hfun& fx,
const hfun& fy,
177 const hfun& gx,
const hfun& gy,
179 int* countn,
int* countb) {
188 const bool check =
false;
189 real fxm = fx.MaxPlus(), fym = fy.MaxPlus(),
190 gxm = gx.MaxPlus(), gym = gy.MaxPlus(),
191 fxs = fx.Slope(), fys = fy.Slope(), gxs = gx.Slope(), gys = gy.Slope(),
196 den = fxs * gys + fys * gxs,
197 qf = fxm + fym, qg = gxm + gym,
198 Dx = (qf * gys + qg * fys) / den,
199 Dy = (qf * gxs + qg * fxs) / den,
200 x0 = (fys * g0 + gys * f0) / den,
201 y0 = (fxs * g0 - gxs * f0) / den,
202 xp = x0 + Dx, xm = x0 - Dx,
203 yp = y0 + Dy, ym = y0 - Dy,
205 if constexpr (check) {
206 real DxA = (-qf * gys + qg * fys) / den,
207 DyA = (-qf * gxs + qg * fxs) / den;
209 fA = (fx(x0 - Dx) - fy(y0 - DyA)) - f0,
210 gA = (gx(x0 - Dx) + gy(y0 - DyA)) - g0,
211 fB = (fx(x0 - DxA) - fy(y0 - Dy)) - f0,
212 gB = (gx(x0 - DxA) + gy(y0 - Dy)) - g0,
213 fC = (fx(x0 + Dx) - fy(y0 + DyA)) - f0,
214 gC = (gx(x0 + Dx) + gy(y0 + DyA)) - g0,
215 fD = (fx(x0 + DxA) - fy(y0 + Dy)) - f0,
216 gD = (gx(x0 + DxA) + gy(y0 + Dy)) - g0;
217 if (!( fabs(DxA) <= Dx && fabs(DyA) <= Dy ))
219 if (!( fA <= 0 && gA <= 0 )) {
220 cout << scientific <<
"midA " << fA <<
" " << gA <<
"\n";
221 cout <<
"DA " << Dx <<
" " << DxA <<
" " << Dy <<
" " << DyA <<
"\n";
223 (
"Bad initial midpoints A GeodesicLine3::newt2");
225 if (!( fB >= 0 && gB <= 0 )) {
226 cout << scientific <<
"midB " << fB <<
" " << gB <<
"\n";
228 (
"Bad initial midpoints B GeodesicLine3::newt2");
230 if (!( fC >= 0 && gC >= 0 )) {
231 cout << scientific <<
"midC " << fC <<
" " << gC <<
"\n";
233 (
"Bad initial midpoints C GeodesicLine3::newt2");
235 if (!( fD <= 0 && gD >= 0 )) {
236 cout << scientific <<
"midD " << fD <<
" " << gD <<
"\n";
237 throw GeographicLib::GeographicErr
238 (
"Bad initial midpoints D GeodesicLine3::newt2");
241 newt2(f0, g0, fx, fy, gx, gy,
242 xm-mm*Dx, xp+mm*Dx, fx.HalfPeriod(),
243 ym-mm*Dy, yp+mm*Dy, fy.HalfPeriod(),
244 (fx.HalfPeriod() * fxs + fy.HalfPeriod() * fys) / 2,
245 (gx.HalfPeriod() * gxs + gy.HalfPeriod() * gys) / 2,
246 x, y, countn, countb);
249 void GeodesicLine3::solve2u(
real d0,
real s0,
250 const hfun& fx,
const hfun& fy,
251 const hfun& gx,
const hfun& gy,
253 int* countn,
int* countb) {
261 real pi2 = Geodesic3::BigValue(),
262 sbet = gx.Max(), somg = gy.Max(), stot = sbet + somg,
263 dbet = fx.Max(), domg = fy.Max(), del = dbet - domg;
264 if (fabs(s0) - stot >= -5 * numeric_limits<real>::epsilon()) {
272 real t0 = copysign(pi2, s0),
273 t1 = (d0 + (1 - 2 * signbit(s0)) * del) / 2;
274 u = t0 + t1; v = t0 - t1;
275 }
else if (fabs(d0) > 2*pi2/3 &&
276 fabs((1 - 2 * signbit(d0)) * s0 - (sbet - somg)) <=
277 7 * numeric_limits<real>::epsilon()) {
279 u = 2*d0/3; v = -1*d0/3;
281 u = 1*d0/3; v = -2*d0/3;
285 newt2(d0, s0, fx, fy, gx, gy,
286 -mm * pi2, mm * pi2, pi2,
287 -mm * pi2, mm * pi2, pi2,
288 pi2, pi2, u, v, countn, countb);
292 void GeodesicLine3::newt2(
real f0,
real g0,
293 const hfun& fx,
const hfun& fy,
294 const hfun& gx,
const hfun& gy,
299 int* countn,
int* countb) {
307 static const real tol = numeric_limits<real>::epsilon();
308 const bool debug = Geodesic3::debug_, check =
false;
314 ftol = tol * fscale/10,
315 gtol = tol * gscale/10,
316 xtol = pow(tol,
real(0.75)) * xscale,
317 ytol = pow(tol,
real(0.75)) * yscale,
323 int cntn = 0, cntb = 0;
324 real oldf =
Math::infinity(), oldg = oldf, olddx = oldf, olddy = oldf;
325 zset xset(zvals(xa, fx(xa), gx(xa)),
326 zvals(xb, fx(xb), gx(xb))),
327 yset(zvals(ya, fy(ya), gy(ya)),
328 zvals(yb, fy(yb), gy(yb)));
330 auto p = zsetsbisect(xset, yset, f0, g0,
false);
331 x = p.first; y = p.second;
332 if constexpr (check) {
337 f01 = (xset.min().fz - yset.max().fz) - f0,
338 f10 = (xset.max().fz - yset.min().fz) - f0,
339 g00 = (xset.min().gz + yset.min().gz) - g0,
340 g11 = (xset.max().gz + yset.max().gz) - g0;
342 if (!( f01 <= 0 && 0 <= f10 && g00 <= 0 && 0 <= g11 ))
343 throw GeographicLib::GeographicErr
344 (
"Bad initial points GeodesicLine3::newt2");
345 zvals xv(x, fx(x), gx(x)), yv(y, fy(y), gy(y));
353 bool bis =
false, degen =
false;
354 int ibis = -1, i = 0;
356 (Geodesic3::throw_ && (
throw GeographicLib::GeographicErr
357 (
"Convergence failure GeodesicLine3::newt2"),
361 if (!degen && nextafter(xset.min().z, xset.max().z) == xset.max().z &&
362 yset.min().gz == yset.max().gz) {
364 real ga = (xset.min().gz + yset.min().gz) - g0,
365 gb = (xset.max().gz + yset.max().gz) - g0;
366 x = gb < -ga ? xset.max().z : xset.min().z;
369 g0 = xset.max().gz + yset.max().gz;
370 zvals xx = xset.max();
373 g0 = xset.min().gz + yset.min().gz;
374 zvals xx = xset.min();
378 zvals xv(x, fx(x), gx(x)), yv(y, fy(y), gy(y));
380 zsetsinsert(xset, yset, xv, yv, f0, g0);
381 real f = (xv.fz - yv.fz) - f0, g = (xv.gz + yv.gz) - g0;
382 if ((fabs(f) <= ftol && fabs(g) <= gtol) || isnan(f) || isnan(g)) {
384 cout <<
"break0 " << scientific << f <<
" " << g <<
"\n";
388 fxp = fx.deriv(x), fyp = fy.deriv(y),
389 gxp = gx.deriv(x), gyp = gy.deriv(y),
390 den = fxp * gyp + fyp * gxp,
391 dx = -( gyp * f + fyp * g) / den,
392 dy = -(-gxp * f + fxp * g) / den,
393 xn = x + dx, yn = y + dy,
395 xa = xset.min().z; xb = xset.max().z;
396 ya = yset.min().z; yb = yset.max().z;
397 if constexpr (debug) {
398 bool bb = gyp == 0 &&
399 nextafter(xset.min().z, xset.max().z) == xset.max().z;
400 cout <<
"DERIV " << i <<
" " << fxp <<
" " << fyp <<
" " << gxp <<
" " << gyp <<
" " << bb <<
"\n";
401 cout <<
"DY " << i <<
" " << -gxp * f <<
" " << fxp * g <<
"\n";
402 cout <<
"FG " << i <<
" " << f <<
" " << g <<
"\n";
403 cout <<
"DXY " << i <<
" " << degen <<
" " << dx <<
" " << dy <<
"\n";
405 if constexpr (check) {
406 if (!( fxp >= 0 && fyp >= 0 && gxp >= 0 && gyp >= 0 && den > 0 )) {
407 cout <<
"DERIVS " << x <<
" " << y <<
" "
408 << fxp <<
" " << fyp <<
" "
409 << gxp <<
" " << gyp <<
" " << den <<
"\n";
410 throw GeographicLib::GeographicErr
411 (
"Bad derivatives GeodesicLine3::newt2");
414 bool cond1 = den > 0 &&
416 ((2*fabs(f) < oldf || 2*fabs(g) < oldg) ||
417 (2*fabs(dx) < olddx || 2*fabs(dy) < olddy))),
418 cond2 = xn >= xa-xtol*tolmult && xn <= xb+xtol*tolmult &&
419 yn >= ya-ytol*tolmult && yn <= yb+ytol*tolmult;
420 if (cond1 && cond2) {
421 oldf = fabs(f); oldg = fabs(g); olddx = fabs(dx); olddy = fabs(dy);
424 if (!(fabs(dx) > xtol || fabs(dy) > ytol)) {
426 cout <<
"break1 " << scientific << dx <<
" " << dy <<
" "
427 << f <<
" " << g <<
"\n";
432 p = zsetsbisect(xset, yset, f0, g0,
false);
433 xn = p.first; yn = p.second;
435 if (x == xn && y == yn) {
437 cout <<
"break2 " << f <<
" " << g <<
"\n";
440 dxa = xn - x; dya = yn - y;
447 cout <<
"AA " << scientific << setprecision(4)
448 << x-xa <<
" " << xb-x <<
" "
449 << y-ya <<
" " << yb-y <<
"\n";
451 cout <<
"CC " << i <<
" "
452 << bis <<
" " << cond1 <<
" " << cond2 <<
" "
453 << scientific << setprecision(2) << f <<
" " << g <<
" "
454 << dx <<
" " << dy <<
" " << dxa <<
" " << dya <<
" "
455 << xb-xa <<
" " << yb-ya <<
"\n";
457 cout <<
"BOX " << i <<
" " << bis <<
" "
458 << xset.num() <<
" " << yset.num() <<
" "
459 << scientific << setprecision(3)
460 << xset.max().z - xset.min().z <<
" "
461 << yset.max().z - yset.min().z <<
"\n";
467 if constexpr (debug) {
468 cout <<
"CNT " << cntn <<
" " << cntb <<
"\n";
469 cout <<
"XY " << setprecision(18) << x <<
" " << y <<
"\n";
473 int GeodesicLine3::zset::insert(zvals& t,
int flag) {
483 const bool monotonic =
true;
485 if (isnan(t.z))
return ind;
487 if constexpr (monotonic) {
488 t.fz = fmin(t.fz, min().fz);
489 t.gz = fmin(t.gz, min().gz);
491 }
else if (t == min()) {
493 if (flag > 0) _s.resize(1);
495 }
else if (t == max()) {
497 if (flag < 0) { _s[0] = _s.back(); _s.resize(1); }
499 }
else if (max() < t) {
500 if constexpr (monotonic) {
501 t.fz = fmax(t.fz, max().fz);
502 t.gz = fmax(t.gz, max().gz);
505 if (!(min() < t && t < max()))
508 auto p = std::lower_bound(_s.begin(), _s.end(), t);
509 if (p == _s.end())
return ind;
511 bool ins = !(*p == t);
512 if constexpr (monotonic) {
520 _s.erase(_s.begin(), p);
522 _s.insert(_s.begin(), t);
525 }
else if (flag > 0) {
527 _s.erase(p, _s.end());
529 ind = int(_s.size()) - 1;
531 _s.erase(p+1, _s.end());
533 ind = int(p - _s.begin());
540 void GeodesicLine3::zsetsinsert(zset& xset, zset& yset,
541 zvals& xfg, zvals& yfg,
543 const bool debug = Geodesic3::debug_;
545 int xind = xset.insert(xfg), yind = yset.insert(yfg);
546 if constexpr (debug) {
547 cout <<
"BOXA " << xset.num() <<
" " << yset.num() <<
" "
548 << xind <<
" " << yind <<
" "
549 << xset.min().z - x0 <<
" " << xset.max().z - x0 <<
" "
550 << yset.min().z - y0 <<
" " << yset.max().z - y0 <<
" "
551 << xset.max().z - xset.min().z <<
" "
552 << yset.max().z - yset.min().z <<
"\n";
553 zsetsdiag(xset, yset, f0, g0);
555 if (xind < 0 && yind < 0)
return;
559 zvals xa[2] = {xset.min(), xset.min()},
560 xb[2] = {xset.max(), xset.max()},
561 ya[2] = {yset.min(), yset.min()},
562 yb[2] = {yset.max(), yset.max()};
563 for (
int i = 0; i < xset.num(); ++i) {
564 const zvals& x = xset.val(i);
565 for (
int j = 0; j < yset.num(); ++j) {
566 if (i == xind || j == yind) {
567 const zvals& y = yset.val(j);
568 real f = (x.fz - y.fz) - f0, g = (x.gz + y.gz) - g0;
610 if (g <= 0 && xa[0] < x) xa[0] = x;
611 if (g >= 0 && y < yb[0]) yb[0] = y;
612 if (i == xind && j == yind) {
613 if (g <= 0 && xa[1] < x) xa[1] = x;
614 if (g >= 0 && y < yb[1]) yb[1] = y;
618 if (g <= 0 && ya[0] < y) ya[0] = y;
619 if (g >= 0 && x < xb[0]) xb[0] = x;
620 if (i == xind && j == yind) {
621 if (g <= 0 && ya[1] < y) ya[1] = y;
622 if (g >= 0 && x < xb[1]) xb[1] = x;
631 if ((xa[k].fz - yb[k].fz) - f0 <= 0 &&
632 (xb[k].fz - ya[k].fz) - f0 >= 0 &&
633 (xa[k].gz + ya[k].gz) - g0 <= 0 &&
634 (xb[k].gz + yb[k].gz) - g0 >= 0)
640 cout <<
"BOXK " << k <<
" " << xind <<
" " << yind <<
"\n";
641 xset.insert(xa[kk], -1);
642 xset.insert(xb[kk], +1);
643 yset.insert(ya[kk], -1);
644 yset.insert(yb[kk], +1);
645 if constexpr (debug) {
646 cout <<
"BOXB " << xset.num() <<
" " << yset.num() <<
" "
647 << xset.min().z - x0 <<
" " << xset.max().z - x0 <<
" "
648 << yset.min().z - y0 <<
" " << yset.max().z - y0 <<
" "
649 << xa[kk].z - x0 <<
" " << xb[kk].z - x0 <<
" "
650 << ya[kk].z - y0 <<
" " << yb[kk].z - y0 <<
"\n";
651 zsetsdiag(xset, yset, f0, g0);
654 throw GeographicLib::GeographicErr
655 (
"Bad corner points GeodesicLine3::zsetsinsert");
658 void GeodesicLine3::zsetsdiag(
const zset& xset,
const zset& yset,
660 ostringstream fs, gs;
661 for (
int j = yset.num() - 1; j >= 0; --j) {
662 const zvals& y = yset.val(j);
665 for (
int i = 0; i < xset.num(); ++i) {
666 const zvals& x = xset.val(i);
667 real f = (x.fz - y.fz) - f0, g = (x.gz + y.gz) - g0;
668 fs << (f == 0 ?
'.' : f < 0 ?
'-' :
'+');
669 gs << (g == 0 ?
'.' : g < 0 ?
'-' :
'+');
674 cout << fs.str() << gs.str();
677 pair<Math::real, Math::real>
678 GeodesicLine3::zsetsbisect(
const zset& xset,
const zset& yset,
679 real f0, real g0,
bool secant) {
681 return pair<real, real>(xset.bisect(), yset.bisect());
682 else if (secant && xset.num() <= 2 && yset.num() <= 2) {
685 dx = xset.max().z - xset.min().z,
686 dy = yset.max().z - yset.min().z,
687 fx1 = (xset.max().fz - xset.min().fz) / (dx == 0 ? 1 : dx),
688 fy1 = (yset.max().fz - yset.min().fz) / (dy == 0 ? 1 : dy),
689 gx1 = (xset.max().gz - xset.min().gz) / (dx == 0 ? 1 : dx),
690 gy1 = (yset.max().gz - yset.min().gz) / (dy == 0 ? 1 : dy),
691 den = fx1*gy1 + fy1*gx1,
692 f00 = (xset.min().fz + yset.min().fz) - f0,
693 g00 = (xset.min().gz + yset.min().gz) - g0,
694 x = -gy1*f00 - fy1*g00,
695 y = gx1*f00 - fx1*g00;
696 if (den <= 0) den = 1;
699 if (x <= 0 || x >= 1) x = 1/
real(2);
700 if (y <= 0 || y >= 1) y = 1/
real(2);
701 x = xset.min().z + x * dx;
702 y = yset.min().z + y * dy;
703 return pair<real, real>(x, y);
710 for (
int i = 0; i < max(1, xset.num() - 1); ++i) {
711 int i1 = min(i + 1, xset.num() - 1);
712 real xgap1 = xset.val(i1).z - xset.val(i).z,
713 xmean = (xset.val(i1).z + xset.val(i).z) / 2;
714 for (
int j = 0; j < max(1, yset.num() - 1); ++j) {
715 int j1 = min(j + 1, yset.num() - 1);
716 real ygap1 = yset.val(j1).z - yset.val(j).z,
717 ymean = (yset.val(j1).z + yset.val(j).z) / 2;
719 f01 = (xset.val(i ).fz - yset.val(j1).fz) - f0,
720 f10 = (xset.val(i1).fz - yset.val(j ).fz) - f0,
721 g00 = (xset.val(i ).gz + yset.val(j ).gz) - g0,
722 g11 = (xset.val(i1).gz + yset.val(j1).gz) - g0;
723 if (f01 <= 0 && 0 <= f10 && g00 <= 0 && 0 <= g11) {
725 if (xgap1 > xgap) { xgap = xgap1; x = xmean; }
726 if (ygap1 > ygap) { ygap = ygap1; y = ymean; }
731 throw GeographicLib::GeographicErr
732 (
"No legal box GeodesicLine3::zsetsbisect");
733 return pair<real, real>(x, y);
737 void GeodesicLine3::Hybrid(ang betomg2,
738 ang& bet2a, ang& omg2a, ang& alp2a,
739 real& s12,
bool betp)
const {
740 fline::disttx d = _f.Hybrid(_fic, betomg2, bet2a, omg2a, alp2a, betp);
741 s12 = _g.dist(_gic, d);
744 GeodesicLine3::fline::disttx
745 GeodesicLine3::fline::Hybrid(
const fics& fic, ang betomg2,
746 ang& bet2a, ang& omg2a, ang& alp2a,
749 bool psip = !transpolar() ? betp : !betp;
755 real spsi = phi2.
s(),
759 cpsi = nu() < nup() ?
760 (phi2.
c() - nu()) * (phi2.
c() + nu()) :
761 (nup() - phi2.
s()) * (nup() + phi2.
s());
764 cpsi = !(cpsi > -numeric_limits<real>::epsilon()) ?
Math::NaN() :
765 (signbit(cpsi) ? 0 : sqrt(cpsi));
767 ang psi12 = (
ang(spsi, cpsi) - fic.psi1).base();
769 if (signbit(psi12.
s()))
770 psi12 =
ang(0, copysign(
real(1), psi12.
c()), 0,
true);
772 }
else if (gammax() == 0) {
773 tau12 = (fic.Nx > 0 ? phi2 - fic.phi1 :
778 ang tht2 = betomg2.
flipsign(fic.Ex);
783 ang tht2b = tht2; tht2b.
reflect(
false, betp && fic.Ex < 0);
784 ang tht12 = tht2b - fic.tht1;
786 if (signbit(tht12.
s()))
787 tht12 =
ang(0, copysign(
real(1), tht12.
c()), 0,
true);
792 disttx ret = ArcPos0(fic, tau12.
base(), bet2a, omg2a, alp2a, betp);
796 GeodesicLine3::fline::fline(
const Geodesic3& tg,
bool neg)
801 GeodesicLine3::fline::fline(
const Geodesic3& tg, Geodesic3::gamblk gam)
804 , _fpsi(false, _gm.kx2 , _gm.kxp2,
805 +(_gm.transpolar ? -1 : 1) * _tg.e2(),
806 -(_gm.transpolar ? -1 : 1) * _gm.gamma, _tg)
807 , _ftht(false, _gm.kxp2 , _gm.kx2,
808 -(_gm.transpolar ? -1 : 1) * _tg.e2(),
809 +(_gm.transpolar ? -1 : 1) * _gm.gamma, _tg)
812 _deltashift = _gm.gamma == 0 ?
813 (_tg.k2() > 0 && _tg.kp2() > 0 ? 2 * (_fpsi.Max() - _ftht.Max()) : 0) :
817 GeodesicLine3::gline::gline(
const Geodesic3& tg,
bool neg)
822 GeodesicLine3::gline::gline(
const Geodesic3& tg,
const Geodesic3::gamblk& gm)
825 , _gpsi(true, _gm.kx2 , _gm.kxp2,
826 +(_gm.transpolar ? -1 : 1) * _tg.e2(),
827 -(_gm.transpolar ? -1 : 1) * _gm.gamma, _tg)
828 , _gtht(true, _gm.kxp2 , _gm.kx2,
829 -(_gm.transpolar ? -1 : 1) * _tg.e2(),
830 +(_gm.transpolar ? -1 : 1) * _gm.gamma, _tg)
831 , s0(_gm.gammax == 0 ? _gpsi.Max() + _gtht.Max() : 0)
834 Math::real GeodesicLine3::fline::Hybrid0(
const fics& fic,
ang bet2,
ang omg2,
836 ang bet2a, omg2a, alp2a;
837 (void) Hybrid(fic, betp ? bet2 : omg2, bet2a, omg2a, alp2a, betp);
838 bool angnorm =
true || betp;
850 GeodesicLine3::fline::disttx
851 GeodesicLine3::fline::ArcPos0(
const fics& fic, ang tau12,
852 ang& bet2a, ang& omg2a, ang& alp2a,
856 bool psip = transpolar() ? !betp : betp;
857 ang &phi2a = bet2a, &tht2a = omg2a;
860 real u2, v2, u2x = 0;
862 psi2 = tau12 + fic.psi1;
863 v2 = fpsi().fwd(psi2.
radians());
864 u2 = ftht().inv(fpsi()(v2) - fic.delta);
867 tht2a = fic.tht1 + tau12;
868 u2 = ftht().fwd(tht2a.radians());
869 u2x = ftht()(u2) + fic.delta;
870 v2 = fpsi().inv(u2x);
874 phi2a =
ang(nup() * psi2.
s(),
875 fic.phi0.c() * hypot(psi2.
c(), nu() * psi2.
s()),
876 0,
true).
rebase(fic.phi0);
877 real s = fic.Ex * hypot(kx() * nu(), kxp() * tht2a.c()),
878 c = fic.phi0.
c() * kx() * nup() * psi2.
c();
879 if (s == 0 && c == 0)
880 (transpolar() ? s : c) = 1;
884 }
else if (gammax() == 0) {
888 phi2a = fic.phi1 + tau12.
flipsign(fic.Nx);
890 pair<real, real> phi2n =
892 remx((phi2a - fic.phi0).flipsign(fic.Nx));
893 u2 = fpsi().fwd(phi2n.first);
894 int parity = fmod(phi2n.second, real(2)) != 0 ? -1 : 1;
902 real deltax = bigclamp(fic.delta + phi2n.second * _deltashift, 2);
903 v2 = ftht().inv(fpsi()(u2) - deltax);
909 alp2a =
ang(kxp() * fic.Ex * parity / mcosh(v2, kx()),
910 fic.Nx * kx() / mcosh(u2, kxp()));
914 ii = int(phi2n.second);
916 tht2a = fic.tht1 + tau12;
918 pair<real, real> tht2n =
920 remx(tht2a - fic.tht0);
921 v2 = ftht().fwd(tht2n.first);
923 int parity = fmod(tht2n.second, real(2)) != 0 ? -1 : 1;
925 if (fic.phi1.c() != 0 && tau12 == tau12.
nearest(2U)) {
930 real npi = (tau12.
ncardinal() + fic.phi1.nearest(2U).ncardinal())
946 real c = fic.Nx * (fic.phi1.t() - fpsi().df(fic.phi1.radians())),
947 l = exp(Geodesic3::BigValue()),
948 tpsi2 = Trigfun::root(Trigfun::ARCPOS0,
949 [
this, npi] (real tpsi) -> pair<real, real>
951 real psi = atan(tpsi);
952 return pair<real, real>
953 (tpsi - fpsi().df(npi + psi),
954 1 - fpsi().dfp(psi) /
957 c, fic.psi1.t(), -l, l);
959 phi2a = (
ang(tpsi2, 1) + fic.phi1.
nearest(2U))
960 .flipsign(parity*fic.Nx).
rebase(fic.phi0);
963 u2 = v2 == 0 ? 0 : copysign(
Math::pi()/2, tht2n.first);
965 ? 0 : copysign(
real(1), v2 * fic.Nx))
968 fic.alp1.nearest(2U) +
969 ang::cardinal(parity == 1 ? 0 : 2) +
970 ang::radians(v2).flipsign(parity * phi2a.s());
973 real deltax = bigclamp(fic.delta + tht2n.second * _deltashift, 2);
974 u2 = fpsi().inv(ftht()(v2) + deltax);
975 real phi2 = fic.Nx * parity * fpsi().rev(u2);
977 alp2a =
ang(fic.Ex * kxp() / mcosh(v2, kx()),
978 kx() * fic.Nx * parity / mcosh(u2, kxp()));
981 ii = int(tht2n.second);
994 alp2a.
reflect(
false,
false,
true);
997 alp2a = alp2a.
rebase(fic.alp0);
1003 :
tht1(omg10 - ang::cardinal(1))
1007 static const real eps = numeric_limits<real>::epsilon();
1008 alp0 =
alp1.nearest(f.transpolar() ? 2U : 1U);
1009 if (f.transpolar()) {
1011 alp1.reflect(
false,
false,
true);
1016 Ex = signbit(
alp1.s()) ? -1 : 1;
1017 Nx = signbit(
alp1.c()) ? -1 : 1;
1019 if (f.gammax() > 0) {
1023 hypot(f.kx() *
phi1.c(), f.kxp() *
tht1.c()));
1028 u0 = f.fpsi().fwd(
psi1.radians());
1029 v0 = f.ftht().fwd(
tht1.radians());
1030 delta = (biaxspecial(tg, f.gammax()) ?
1032 - sqrt(f.gammax()) * f.fpsi().df(
u0)
1033 : f.fpsi()(
u0)) - f.ftht()(
v0);
1034 }
else if (f.gammax() == 0) {
1035 if (f.kxp2() == 0) {
1055 if (
phi1.c() == 0) {
1065 if (fabs(
phi1.c()) < 8*eps && fabs(
tht1.c()) < 8*eps) {
1068 delta = f.deltashift()/2 - log(fabs(
alp1.t()));
1073 f.ftht()(lamang(
tht1 -
tht0, tg.k()));
1082 ang& bet10, ang& omg10, ang& alp10)
1088 alp10.
reflect(
false,
false,
true);
1094 ang bet1, omg1, alp1x;
1095 pos1(f.transpolar(), bet1, omg1, alp1x);
1097 *
this =
fics(f, bet1, omg1, alp1x);
1101 if (g.gammax() > 0) {
1102 sig1 = g.gpsi()(fic.
u0) + g.gtht()(fic.
v0);
1103 }
else if (g.gammax() == 0) {
1104 sig1 = g.kxp2() == 0 ? fic.
Nx * g.gpsi()(fic.
u0) :
1105 fic.
Nx * g.gpsi()(lamang(fic.
phi1 - fic.
phi0, g.kxp())) +
1106 g.gtht()(lamang(fic.
tht1 - fic.
tht0, g.kx()));
1114 return (sig2 - ic.
sig1) * tg().b();
1117 GeodesicLine3::hfun::hfun(
bool distp, real kap, real kapp, real eps, real mu,
1123 , _sqrtmu(sqrt(fabs(_mu)))
1124 , _sqrtkap(sqrt(_kap))
1125 , _sqrtkapp(sqrt(_kapp))
1127 , _umb(!tg.biaxial() && _mu == 0)
1128 , _meridr(_kap == 0 && _mu == 0)
1129 , _meridl(_kapp == 0 && _mu == 0)
1130 , _biaxr(biaxspecial(tg, _mu) && _kap == 0)
1131 , _biaxl(biaxspecial(tg, _mu) && _kapp == 0)
1135 if (_meridr || _biaxr) {
1141 [eps = _eps, mu = _mu]
1144 {
return fthtbiax(tht, eps, mu); },
1146 }
else if (_meridl || _biaxl) {
1154 [eps = _eps, mu = _mu]
1156 {
return dfpsibiax(sin(psi), cos(psi), eps, mu); },
1158 }
else if (_mu > 0) {
1159 _tx = _mu / (_kap + _mu) < tg._ellipthresh;
1161 _ell = EllipticFunction(_kap / (_kap + _mu), 0,
1162 _mu / (_kap + _mu), 1);
1164 [kap = _kap, kapp = _kapp,
1165 eps = _eps, mu = _mu, ell = _ell]
1167 {
real sn, cn, dn; (void) ell.am(u, sn, cn, dn);
1168 return fup(cn, kap, kapp, eps, mu); },
1172 [kap = _kap, kapp = _kapp, eps = _eps, mu = _mu]
1174 {
return fthtp(cos(tht), kap, kapp, eps, mu); },
1176 }
else if (_mu < 0) {
1177 _tx = -_mu / _kap < tg._ellipthresh;
1179 _ell = EllipticFunction((_kap + _mu) / _kap, 0, -_mu / _kap, 1);
1181 [kap = _kap, kapp = _kapp,
1182 eps = _eps, mu = _mu, ell = _ell]
1184 {
real sn, cn, dn; (void) ell.am(v, sn, cn, dn);
1185 return fvp(dn, kap, kapp, eps, mu); },
1189 [kap = _kap, kapp = _kapp, eps = _eps, mu = _mu]
1191 {
return fpsip(sin(psi), cos(psi),
1192 kap, kapp, eps, mu); },
1195 _tx = _kapp < tg._ellipthresh;
1200 _ell = EllipticFunction(_kap, 0, _kapp, 1);
1202 [kap = _kap, kapp = _kapp,
1203 eps = _eps, ell = _ell]
1205 {
real sn, cn, dn; (void) ell.am(v, sn, cn, dn);
1206 return dfvp(cn, dn, kap, kapp, eps); },
1207 2 * _ell.K(),
true, 1);
1211#
if defined(_MSC_VER)
1216 kap = _kap, kapp = _kapp, eps = _eps]
1218 {
return dfp(cos(tht), kap, kapp, eps); },
1225 if (_meridr || _biaxr) {
1230 [eps = _eps, mu = _mu]
1233 {
return gthtbiax(tht, eps, mu); },
1235 }
else if (_meridl || _biaxl) {
1241 [eps = _eps, mu = _mu]
1243 {
return gpsibiax(sin(psi), cos(psi), eps, mu); },
1245 }
else if (_mu > 0) {
1246 _tx = _mu / (_kap + _mu) < tg._ellipthresh;
1248 _ell = EllipticFunction(_kap / (_kap + _mu), 0,
1249 _mu / (_kap + _mu), 1);
1251 [kap = _kap, kapp = _kapp,
1252 eps = _eps, mu = _mu, ell = _ell]
1254 {
real sn, cn, dn; (void) ell.am(u, sn, cn, dn);
1255 return gup(cn, dn, kap, kapp, eps, mu); },
1259 [kap = _kap, kapp = _kapp, eps = _eps, mu = _mu]
1261 {
return gthtp(cos(tht), kap, kapp, eps, mu); },
1263 }
else if (_mu < 0) {
1264 _tx = -_mu / _kap < tg._ellipthresh;
1266 _ell = EllipticFunction((_kap + _mu) / _kap, 0, -_mu / _kap, 1);
1268 [kap = _kap, kapp = _kapp,
1269 eps = _eps, mu = _mu, ell = _ell]
1271 {
real sn, cn, dn; (void) ell.am(v, sn, cn, dn);
1272 return gvp(cn, dn, kap, kapp, eps, mu); },
1276 [kap = _kap, kapp = _kapp, eps = _eps, mu = _mu]
1278 {
return gpsip(sin(psi), cos(psi),
1279 kap, kapp, eps, mu); },
1282 _tx = _kapp < tg._ellipthresh;
1284 _ell = EllipticFunction(_kap, 0, _kapp, 1);
1286 [kap = _kap, kapp = _kapp, eps = _eps, ell = _ell]
1288 {
real sn, cn, dn; (void) ell.am(v, sn, cn, dn);
1289 return g0vp(cn, kap, kapp, eps); },
1293 [kap = _kap, kapp = _kapp, eps = _eps]
1295 {
return g0p(cos(tht), kap, kapp, eps); },
1303 _max = _umb ? _fun(_tx ? _ell.K() :
Math::pi()/2) :
1304 !_distp ? ( _biaxl ? Math::pi()/2 + _sqrtmu * _fun.Max() :
1306 _meridl ? _fun(Math::pi()/2) : _fun.Max();
1313 return modang(u, _sqrtmu) - _sqrtmu * _fun(u);
1318 real phi = gd(u, _sqrtkapp);
1319 return u - _fun(_tx ? _ell.F(phi) : phi);
1324 real phi = gd(u, _sqrtkapp);
1325 return _fun(_tx ? _ell.F(phi) : phi);
1336 - _sqrtmu * _fun.deriv(u);
1341 real phi = gd(u, _sqrtkapp),
1349 return 1 - _fun.deriv(_tx ? _ell.F(phi) : phi) /
1350 ( _tx ? sqrt(t) : t / (_sqrtkapp * cosh(u)) );
1352 return _fun.deriv(u);
1355 real phi = gd(u, _sqrtkapp),
1358 return _fun.deriv(_tx ? _ell.F(phi) : phi) /
1359 ( _tx ? sqrt(t) : t / (_sqrtkapp * cosh(u)) );
1361 return _fun.deriv(u);
1366 int* countn,
int* countb,
real tol)
1369 if (!isfinite(z))
return z;
1383 ua = (z - d) / Slope(),
1384 ub = (z + d) / Slope();
1385 u0 = fmin(ub, fmax(ua, u0));
1386 return Trigfun::root(Trigfun::FFUNROOT,
1388 (
real u) -> pair<real, real>
1389 {
return pair<real, real>((*
this)(u), deriv(u)); },
1392 HalfPeriod(), HalfPeriod()/Slope(), 1,
1393 countn, countb, tol);
1395 real d = fabs(Max())
1396 + 2 * numeric_limits<real>::epsilon() * fmax(
real(1), fabs(z)),
1399 u0 = fmin(ub, fmax(ua, u0));
1400 return Trigfun::root(Trigfun::FFUNROOT,
1402 (
real u) -> pair<real, real>
1403 {
return pair<real, real>((*
this)(u), deriv(u)); },
1407 countn, countb, tol);
1413 if (!(isfinite(z) && _umb))
1416 if (fabs(z) >= Max())
1417 return copysign(Geodesic3::BigValue(), z);
1418 real ua = -Geodesic3::BigValue(), ub = -ua;
1419 u0 = fmin(ub, fmax(ua, u0));
1421 return Trigfun::root(Trigfun::GFUNROOT,
1423 (
real u) -> pair<real, real>
1424 {
return pair<real, real>((*
this)(u), deriv(u)); },
1432 Math::real GeodesicLine3::hfun::inv(
real z,
int* countn,
int* countb)
1435 return _umb ? root(z, z, countn, countb) :
1436 _biaxl ? root(z, modang(z/Slope(), 1/_sqrtmu), countn, countb) :
1437 _fun.inv1(z, countn, countb);
1461 real u0 = atanh(_sqrtkapp/_sqrtkap *
1462 tan(atan(_sqrtkap/_sqrtkapp) / _max * z)) /
1463 (sqrt(1 - _eps*_kap) * atan(_sqrtkap/_sqrtkapp) / _max);
1464 return root(z, u0, countn, countb);
1466 return _fun.inv1(z, countn, countb);
1474 return sqrt((1 - eps * c2) / ((kapp + c2) * (c2 + mu)) );
1480 return c2 * sqrt((1 - eps * c2) / ((kapp + c2) * (c2 + mu)) );
1487 return sqrt( (1 - eps * c2) / ((kapp + c2) * (kap + mu)) );
1493 return c2 * sqrt( (1 - eps * c2) / ((kapp + c2) * (kap + mu)) );
1502 return eps*kap * sqrt(kapp) * c / (s * (1 + sqrt(1 - eps*c2)));
1506 return sqrt( kap * (1 - eps * c2) / (kapp + c2) ) * c;
1514 return eps*kap * sqrt(kapp) * cn /
1515 (1 + sqrt(1 - eps*kap *
Math::sq(cn)));
1520 return sqrt( kap * (1 - eps * c2) ) * cn;
1527 return sqrt( (1 - eps * c2) / ((kapp + c2) * c2) ) ;
1533 return sqrt(c2 * (1 - eps * c2) / (kapp + c2)) ;
1540 return sqrt( (1 - eps * c2) / ((kapp + c2) * kap) );
1547 return dn2 * sqrt( kap * (1 - eps * c2) / (kapp + c2) );
1552 GeodesicLine3::hfun::fthtbiax(
real ,
real ,
1559 GeodesicLine3::hfun::gthtbiax(
real ,
real ,
1572 return eps / (1 + sqrt(1 - eps * c2));
1578 return sqrt(1 - eps * c2);
GeographicLib::Math::real real
Header for GeographicLib::Triaxial::GeodesicLine3 class.
AngleT rebase(const AngleT &c) const
static AngleT cardinal(Math::real q)
AngleT flipsign(T mult) const
static AngleT radians(T rad)
Math::real radians() const
AngleT & setquadrant(unsigned q)
AngleT nearest(unsigned ind=0U) const
AngleT & reflect(bool flips, bool flipc=false, bool swapp=false)
Exception handling for GeographicLib.
static T clamp(T x, T a, T b)
static bool AngNorm(Angle &bet, Angle &omg, Angle &alp, bool alt=false)
The solution of the geodesic problem for a triaxial ellipsoid.
void setquadrant(const fline &f, unsigned q)
void pos1(bool transpolar, ang &bet10, ang &omg10, ang &alp10) const
void pos1(Angle &bet1, Angle &omg1, Angle &alp1) const
void Position(real s12, Angle &bet2, Angle &omg2, Angle &alp2) const
A function defined by its derivative and its inverse.
Namespace for operations on triaxial ellipsoids.
Namespace for GeographicLib.
AngleT< Math::real > Angle
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)