GeographicLib: EllipticFunction.cpp Source File

GeographicLib 2.7

Loading...
Searching...
No Matches
EllipticFunction.cpp
Go to the documentation of this file.
1/**
2 * \file EllipticFunction.cpp
3 * \brief Implementation for GeographicLib::EllipticFunction class
4 *
5 * Copyright (c) Charles Karney (2008-2024) <karney@alum.mit.edu> and licensed
6 * under the MIT/X11 License. For more information, see
7 * https://geographiclib.sourceforge.io/
8 **********************************************************************/
9
10#include <GeographicLib/EllipticFunction.hpp>
11
12namespace GeographicLib {
13
14 using namespace std;
15
16 /*
17 * Implementation of methods given in
18 *
19 * B. C. Carlson
20 * Computation of elliptic integrals
21 * Numerical Algorithms 10, 13-26 (1995)
22 */
23
24 Math::real EllipticFunction::RF(real x, real y, real z) {
25 // Carlson, eqs 2.2 - 2.7
26 static const real tolRF =
27 pow(3 * numeric_limits<real>::epsilon() * real(0.01), 1/real(8));
28 real
29 A0 = (x + y + z)/3,
30 An = A0,
31 Q = fmax(fmax(fabs(A0-x), fabs(A0-y)), fabs(A0-z)) / tolRF,
32 x0 = x,
33 y0 = y,
34 z0 = z,
35 mul = 1;
36 while (Q >= mul * fabs(An)) {
37 // Max 6 trips
38 real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0);
39 An = (An + lam)/4;
40 x0 = (x0 + lam)/4;
41 y0 = (y0 + lam)/4;
42 z0 = (z0 + lam)/4;
43 mul *= 4;
44 }
45 real
46 X = (A0 - x) / (mul * An),
47 Y = (A0 - y) / (mul * An),
48 Z = - (X + Y),
49 E2 = X*Y - Z*Z,
50 E3 = X*Y*Z;
51 // https://dlmf.nist.gov/19.36.E1
52 // Polynomial is
53 // (1 - E2/10 + E3/14 + E2^2/24 - 3*E2*E3/44
54 // - 5*E2^3/208 + 3*E3^2/104 + E2^2*E3/16)
55 // convert to Horner form...
56 return (E3 * (6930 * E3 + E2 * (15015 * E2 - 16380) + 17160) +
57 E2 * ((10010 - 5775 * E2) * E2 - 24024) + 240240) /
58 (240240 * sqrt(An));
59 }
60
61 Math::real EllipticFunction::RF(real x, real y) {
62 // Carlson, eqs 2.36 - 2.38
63 static const real tolRG0 =
64 real(2.7) * sqrt((numeric_limits<real>::epsilon() * real(0.01)));
65 real xn = sqrt(x), yn = sqrt(y);
66 if (xn < yn) swap(xn, yn);
67 while (fabs(xn-yn) > tolRG0 * xn) {
68 // Max 4 trips
69 real t = (xn + yn) /2;
70 yn = sqrt(xn * yn);
71 xn = t;
72 }
73 return Math::pi() / (xn + yn);
74 }
75
76 Math::real EllipticFunction::RC(real x, real y) {
77 // Defined only for y != 0 and x >= 0.
78 return ( !(x >= y) ? // x < y and catch nans
79 // https://dlmf.nist.gov/19.2.E18
80 atan(sqrt((y - x) / x)) / sqrt(y - x) :
81 ( x == y ? 1 / sqrt(y) :
82 asinh( y > 0 ?
83 // https://dlmf.nist.gov/19.2.E19
84 // atanh(sqrt((x - y) / x))
85 sqrt((x - y) / y) :
86 // https://dlmf.nist.gov/19.2.E20
87 // atanh(sqrt(x / (x - y)))
88 sqrt(-x / y) ) / sqrt(x - y) ) );
89 }
90
91 Math::real EllipticFunction::RG(real x, real y, real z) {
92 return (x == 0 ? RG(y, z) :
93 (y == 0 ? RG(z, x) :
94 (z == 0 ? RG(x, y) :
95 // Carlson, eq 1.7
96 (z * RF(x, y, z) - (x-z) * (y-z) * RD(x, y, z) / 3
97 + sqrt(x * y / z)) / 2 )));
98 }
99
100 Math::real EllipticFunction::RG(real x, real y) {
101 // Carlson, eqs 2.36 - 2.39
102 static const real tolRG0 =
103 real(2.7) * sqrt((numeric_limits<real>::epsilon() * real(0.01)));
104 real
105 x0 = sqrt(fmax(x, y)),
106 y0 = sqrt(fmin(x, y)),
107 xn = x0,
108 yn = y0,
109 s = 0,
110 mul = real(0.25);
111 while (fabs(xn-yn) > tolRG0 * xn) {
112 // Max 4 trips
113 real t = (xn + yn) /2;
114 yn = sqrt(xn * yn);
115 xn = t;
116 mul *= 2;
117 t = xn - yn;
118 s += mul * t * t;
119 }
120 return (Math::sq( (x0 + y0)/2 ) - s) * Math::pi() / (2 * (xn + yn));
121 }
122
123 Math::real EllipticFunction::RJ(real x, real y, real z, real p) {
124 // Carlson, eqs 2.17 - 2.25
125 static const real
126 tolRD = pow(real(0.2) * (numeric_limits<real>::epsilon() * real(0.01)),
127 1/real(8));
128 real
129 A0 = (x + y + z + 2*p)/5,
130 An = A0,
131 delta = (p-x) * (p-y) * (p-z),
132 Q = fmax(fmax(fabs(A0-x), fabs(A0-y)),
133 fmax(fabs(A0-z), fabs(A0-p))) / tolRD,
134 x0 = x,
135 y0 = y,
136 z0 = z,
137 p0 = p,
138 mul = 1,
139 mul3 = 1,
140 s = 0;
141 while (Q >= mul * fabs(An)) {
142 // Max 7 trips
143 real
144 lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0),
145 d0 = (sqrt(p0)+sqrt(x0)) * (sqrt(p0)+sqrt(y0)) * (sqrt(p0)+sqrt(z0)),
146 e0 = delta/(mul3 * Math::sq(d0));
147 s += RC(1, 1 + e0)/(mul * d0);
148 An = (An + lam)/4;
149 x0 = (x0 + lam)/4;
150 y0 = (y0 + lam)/4;
151 z0 = (z0 + lam)/4;
152 p0 = (p0 + lam)/4;
153 mul *= 4;
154 mul3 *= 64;
155 }
156 real
157 X = (A0 - x) / (mul * An),
158 Y = (A0 - y) / (mul * An),
159 Z = (A0 - z) / (mul * An),
160 P = -(X + Y + Z) / 2,
161 E2 = X*Y + X*Z + Y*Z - 3*P*P,
162 E3 = X*Y*Z + 2*P * (E2 + 2*P*P),
163 E4 = (2*X*Y*Z + P * (E2 + 3*P*P)) * P,
164 E5 = X*Y*Z*P*P;
165 // https://dlmf.nist.gov/19.36.E2
166 // Polynomial is
167 // (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26
168 // - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272
169 // - 9*(E3*E4+E2*E5)/68)
170 return ((471240 - 540540 * E2) * E5 +
171 (612612 * E2 - 540540 * E3 - 556920) * E4 +
172 E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) +
173 E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) /
174 (4084080 * mul * An * sqrt(An)) + 6 * s;
175 }
176
177 Math::real EllipticFunction::RD(real x, real y, real z) {
178 // Carlson, eqs 2.28 - 2.34
179 static const real
180 tolRD = pow(real(0.2) * (numeric_limits<real>::epsilon() * real(0.01)),
181 1/real(8));
182 real
183 A0 = (x + y + 3*z)/5,
184 An = A0,
185 Q = fmax(fmax(fabs(A0-x), fabs(A0-y)), fabs(A0-z)) / tolRD,
186 x0 = x,
187 y0 = y,
188 z0 = z,
189 mul = 1,
190 s = 0;
191 while (Q >= mul * fabs(An)) {
192 // Max 7 trips
193 real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0);
194 s += 1/(mul * sqrt(z0) * (z0 + lam));
195 An = (An + lam)/4;
196 x0 = (x0 + lam)/4;
197 y0 = (y0 + lam)/4;
198 z0 = (z0 + lam)/4;
199 mul *= 4;
200 }
201 real
202 X = (A0 - x) / (mul * An),
203 Y = (A0 - y) / (mul * An),
204 Z = -(X + Y) / 3,
205 E2 = X*Y - 6*Z*Z,
206 E3 = (3*X*Y - 8*Z*Z)*Z,
207 E4 = 3 * (X*Y - Z*Z) * Z*Z,
208 E5 = X*Y*Z*Z*Z;
209 // https://dlmf.nist.gov/19.36.E2
210 // Polynomial is
211 // (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26
212 // - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272
213 // - 9*(E3*E4+E2*E5)/68)
214 return ((471240 - 540540 * E2) * E5 +
215 (612612 * E2 - 540540 * E3 - 556920) * E4 +
216 E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) +
217 E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) /
218 (4084080 * mul * An * sqrt(An)) + 3 * s;
219 }
220
221 void EllipticFunction::Reset(real k2, real alpha2,
222 real kp2, real alphap2) {
223 // Accept nans here (needed for GeodesicExact)
224 if (k2 > 1)
225 throw GeographicErr("Parameter k2 is not in (-inf, 1]");
226 if (alpha2 > 1)
227 throw GeographicErr("Parameter alpha2 is not in (-inf, 1]");
228 if (kp2 < 0)
229 throw GeographicErr("Parameter kp2 is not in [0, inf)");
230 if (alphap2 < 0)
231 throw GeographicErr("Parameter alphap2 is not in [0, inf)");
232 _k2 = k2;
233 _kp2 = kp2;
234 _alpha2 = alpha2;
235 _alphap2 = alphap2;
236 _eps = _k2/Math::sq(sqrt(_kp2) + 1);
237 // Values of complete elliptic integrals for k = 0,1 and alpha = 0,1
238 // K E D
239 // k = 0: pi/2 pi/2 pi/4
240 // k = 1: inf 1 inf
241 // Pi G H
242 // k = 0, alpha = 0: pi/2 pi/2 pi/4
243 // k = 1, alpha = 0: inf 1 1
244 // k = 0, alpha = 1: inf inf pi/2
245 // k = 1, alpha = 1: inf inf inf
246 //
247 // Pi(0, k) = K(k)
248 // G(0, k) = E(k)
249 // H(0, k) = K(k) - D(k)
250 // Pi(0, k) = K(k)
251 // G(0, k) = E(k)
252 // H(0, k) = K(k) - D(k)
253 // Pi(alpha2, 0) = pi/(2*sqrt(1-alpha2))
254 // G(alpha2, 0) = pi/(2*sqrt(1-alpha2))
255 // H(alpha2, 0) = pi/(2*(1 + sqrt(1-alpha2)))
256 // Pi(alpha2, 1) = inf
257 // H(1, k) = K(k)
258 // G(alpha2, 1) = H(alpha2, 1) = RC(1, alphap2)
259 if (_k2 != 0) {
260 // Complete elliptic integral K(k), Carlson eq. 4.1
261 // https://dlmf.nist.gov/19.25.E1
262 _kKc = _kp2 != 0 ? RF(_kp2, 1) : Math::infinity();
263 // Complete elliptic integral E(k), Carlson eq. 4.2
264 // https://dlmf.nist.gov/19.25.E1
265 _eEc = _kp2 != 0 ? 2 * RG(_kp2, 1) : 1;
266 // D(k) = (K(k) - E(k))/k^2, Carlson eq.4.3
267 // https://dlmf.nist.gov/19.25.E1
268 _dDc = _kp2 != 0 ? RD(0, _kp2, 1) / 3 : Math::infinity();
269 } else {
270 _kKc = _eEc = Math::pi()/2; _dDc = _kKc/2;
271 }
272 if (_alpha2 != 0) {
273 // https://dlmf.nist.gov/19.25.E2
274 real rj = (_kp2 != 0 && _alphap2 != 0) ? RJ(0, _kp2, 1, _alphap2) :
275 Math::infinity(),
276 // Only use rc if _kp2 = 0.
277 rc = _kp2 != 0 ? 0 :
278 (_alphap2 != 0 ? RC(1, _alphap2) : Math::infinity());
279 // Pi(alpha^2, k)
280 _pPic = _kp2 != 0 ? _kKc + _alpha2 * rj / 3 : Math::infinity();
281 // G(alpha^2, k)
282 _gGc = _kp2 != 0 ? _kKc + (_alpha2 - _k2) * rj / 3 : rc;
283 // H(alpha^2, k)
284 _hHc = _kp2 != 0 ? _kKc - (_alphap2 != 0 ? _alphap2 * rj : 0) / 3 : rc;
285 } else {
286 _pPic = _kKc; _gGc = _eEc;
287 // Hc = Kc - Dc but this involves large cancellations if k2 is close to
288 // 1. So write (for alpha2 = 0)
289 // Hc = int(cos(phi)^2/sqrt(1-k2*sin(phi)^2),phi,0,pi/2)
290 // = 1/sqrt(1-k2) * int(sin(phi)^2/sqrt(1-k2/kp2*sin(phi)^2,...)
291 // = 1/kp * D(i*k/kp)
292 // and use D(k) = RD(0, kp2, 1) / 3
293 // so Hc = 1/kp * RD(0, 1/kp2, 1) / 3
294 // = kp2 * RD(0, 1, kp2) / 3
295 // using https://dlmf.nist.gov/19.20.E18
296 // Equivalently
297 // RF(x, 1) - RD(0, x, 1)/3 = x * RD(0, 1, x)/3 for x > 0
298 // For k2 = 0 and alpha2 = 0, we have
299 // Hc = int(cos(phi)^2,...) = pi/4
300 // For k2 = 1 and alpha2 = 0, we have
301 // Hc = int(cos(phi),...) = 1
302 _hHc = _kp2 == 1 ? Math::pi()/4 :
303 (_kp2 == 0 ? 1 : _kp2 * RD(0, 1, _kp2) / 3);
304 }
305 }
306
307 /*
308 * Implementation of methods given in
309 *
310 * R. Bulirsch
311 * Numerical Calculation of Elliptic Integrals and Elliptic Functions
312 * Numericshe Mathematik 7, 78-90 (1965)
313 */
314
315 void EllipticFunction::sncndn(real x, real& sn, real& cn, real& dn) const {
316 // Bulirsch's sncndn routine, p 89.
317 static const real tolJAC =
318 sqrt(numeric_limits<real>::epsilon() * real(0.01));
319 if (_kp2 != 0) {
320 real mc = _kp2, d = 0;
321 if (signbit(_kp2)) {
322 // This implements DLMF Eqs 22.17.2 - 22.17.4. But this only
323 // accomodates kp2 < 0 or k2 > 1 and these are outside the advertized
324 // ranges for the contructor for this class.
325 d = 1 - mc;
326 mc /= -d;
327 d = sqrt(d);
328 x *= d;
329 }
330 real c = 0; // To suppress warning about uninitialized variable
331 real m[num_], n[num_];
332 unsigned l = 0;
333 for (real a = 1;
334 l < num_ ||
335 GEOGRAPHICLIB_PANIC
336 ("Convergence failure in EllipticFunction::sncndn");
337 ++l) {
338 // This converges quadratically. Max 5 trips
339 m[l] = a;
340 n[l] = mc = sqrt(mc);
341 c = (a + mc) / 2;
342 if (!(fabs(a - mc) > tolJAC * a)) {
343 ++l;
344 break;
345 }
346 mc *= a;
347 a = c;
348 }
349 x *= c;
350 sn = sin(x);
351 cn = cos(x);
352 dn = 1;
353 if (sn != 0) {
354 real a = cn / sn;
355 c *= a;
356 while (l--) {
357 real b = m[l];
358 a *= c;
359 c *= dn;
360 dn = (n[l] + a) / (b + a);
361 a = c / b;
362 }
363 a = 1 / sqrt(c*c + 1);
364 sn = signbit(sn) ? -a : a;
365 cn = c * sn;
366 if (signbit(_kp2)) {
367 // See DLMF Eqs 22.17.2 - 22.17.4
368 swap(cn, dn);
369 sn /= d;
370 }
371 }
372 } else {
373 sn = tanh(x);
374 dn = cn = 1 / cosh(x);
375 }
376 }
377
378 Math::real EllipticFunction::am(real x) const {
379 // This implements DLMF Sec 22.20(ii).
380 // See also Sala (1989), https://doi.org/10.1137/0520100, Sec 5.
381 static const real tolJAC =
382 pow(numeric_limits<real>::epsilon(), real(0.75));
383 real k2 = _k2, kp2 = _kp2;
384 if (_k2 == 0)
385 return x;
386 else if (_kp2 == 0) {
387 return atan(sinh(x)); // gd(x)
388 } else if (_k2 < 0) {
389 // Sala Eq. 5.8
390 k2 = -_k2 / _kp2; kp2 = 1 / _kp2;
391 x *= sqrt(_kp2);
392 }
393 real a[num_], b, c[num_];
394 a[0] = 1; b = sqrt(kp2); c[0] = sqrt(k2);
395 int l = 1;
396 for (; l < num_ ||
397 GEOGRAPHICLIB_PANIC
398 ("Convergence failure in EllipticFunction::am");) {
399 a[l] = (a[l-1] + b) / 2;
400 c[l] = (a[l-1] - b) / 2;
401 b = sqrt(a[l-1] * b);
402 if (!(c[l] > tolJAC * a[l])) break;
403 ++l;
404 }
405 // Now a[l] = pi/(2*K)
406 // Need to initialize phi1 to stop Visual Studio complaining
407 real phi = a[l] * x * real(1 << l), phi1 = 0;
408 for (; l > 0; --l) {
409 phi1 = phi;
410 phi = (phi + asin(c[l] * sin(phi) / a[l])) / 2;
411 }
412 // For k2 < 0, see Sala Eq. 5.8
413 return _k2 < 0 ? phi1 - phi : phi;
414 }
415
416 Math::real EllipticFunction::am(real x, real& sn, real& cn, real& dn) const {
417 real phi = am(x);
418 if (_kp2 == 0) {
419 // Could rely on sin(gd(x)) = tanh(x) and cos(gd(x)) = 1 / cosh(x). But
420 // this is more accurate for large |x|.
421 sn = tanh(x); cn = dn = 1 / cosh(x);
422 } else {
423 sn = sin(phi); cn = cos(phi);
424 // See comment following DLMF Eq. 22.20.5
425 // dn = cn / cos(phi1 - phi)
426 dn = Delta(sn, cn);
427 }
428 return phi;
429 }
430
431 Math::real EllipticFunction::F(real sn, real cn, real dn) const {
432 // Carlson, eq. 4.5 and
433 // https://dlmf.nist.gov/19.25.E5
434 real cn2 = cn*cn, dn2 = dn*dn,
435 fi = cn2 != 0 ? fabs(sn) * RF(cn2, dn2, 1) : K();
436 // Enforce usual trig-like symmetries
437 if (signbit(cn))
438 fi = 2 * K() - fi;
439 return copysign(fi, sn);
440 }
441
442 Math::real EllipticFunction::E(real sn, real cn, real dn) const {
443 real
444 cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
445 ei = cn2 != 0 ?
446 fabs(sn) * ( _k2 <= 0 ?
447 // Carlson, eq. 4.6 and
448 // https://dlmf.nist.gov/19.25.E9
449 RF(cn2, dn2, 1) - _k2 * sn2 * RD(cn2, dn2, 1) / 3 :
450 ( _kp2 >= 0 ?
451 // https://dlmf.nist.gov/19.25.E10
452 _kp2 * RF(cn2, dn2, 1) +
453 _k2 * _kp2 * sn2 * RD(cn2, 1, dn2) / 3 +
454 _k2 * fabs(cn) / dn :
455 // https://dlmf.nist.gov/19.25.E11
456 - _kp2 * sn2 * RD(dn2, 1, cn2) / 3 +
457 dn / fabs(cn) ) ) :
458 E();
459 // Enforce usual trig-like symmetries
460 if (signbit(cn))
461 ei = 2 * E() - ei;
462 return copysign(ei, sn);
463 }
464
465 Math::real EllipticFunction::D(real sn, real cn, real dn) const {
466 // Carlson, eq. 4.8 and
467 // https://dlmf.nist.gov/19.25.E13
468 real
469 cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
470 di = cn2 != 0 ? fabs(sn) * sn2 * RD(cn2, dn2, 1) / 3 : D();
471 // Enforce usual trig-like symmetries
472 if (signbit(cn))
473 di = 2 * D() - di;
474 return copysign(di, sn);
475 }
476
477 Math::real EllipticFunction::Pi(real sn, real cn, real dn) const {
478 // Carlson, eq. 4.7 and
479 // https://dlmf.nist.gov/19.25.E14
480 real
481 cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
482 pii = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) +
483 _alpha2 * sn2 *
484 RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) :
485 Pi();
486 // Enforce usual trig-like symmetries
487 if (signbit(cn))
488 pii = 2 * Pi() - pii;
489 return copysign(pii, sn);
490 }
491
492 Math::real EllipticFunction::G(real sn, real cn, real dn) const {
493 real
494 cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
495 gi = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) +
496 (_alpha2 - _k2) * sn2 *
497 RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) :
498 G();
499 // Enforce usual trig-like symmetries
500 if (signbit(cn))
501 gi = 2 * G() - gi;
502 return copysign(gi, sn);
503 }
504
505 Math::real EllipticFunction::H(real sn, real cn, real dn) const {
506 real
507 cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn,
508 // WARNING: large cancellation if k2 = 1, alpha2 = 0, and phi near pi/2
509 hi = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) -
510 _alphap2 * sn2 *
511 RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) :
512 H();
513 // Enforce usual trig-like symmetries
514 if (signbit(cn))
515 hi = 2 * H() - hi;
516 return copysign(hi, sn);
517 }
518
519 Math::real EllipticFunction::deltaF(real sn, real cn, real dn) const {
520 // Function is periodic with period pi
521 if (signbit(cn)) { cn = -cn; sn = -sn; }
522 return F(sn, cn, dn) * (Math::pi()/2) / K() - atan2(sn, cn);
523 }
524
525 Math::real EllipticFunction::deltaE(real sn, real cn, real dn) const {
526 // Function is periodic with period pi
527 if (signbit(cn)) { cn = -cn; sn = -sn; }
528 return E(sn, cn, dn) * (Math::pi()/2) / E() - atan2(sn, cn);
529 }
530
531 Math::real EllipticFunction::deltaPi(real sn, real cn, real dn) const {
532 // Function is periodic with period pi
533 if (signbit(cn)) { cn = -cn; sn = -sn; }
534 return Pi(sn, cn, dn) * (Math::pi()/2) / Pi() - atan2(sn, cn);
535 }
536
537 Math::real EllipticFunction::deltaD(real sn, real cn, real dn) const {
538 // Function is periodic with period pi
539 if (signbit(cn)) { cn = -cn; sn = -sn; }
540 return D(sn, cn, dn) * (Math::pi()/2) / D() - atan2(sn, cn);
541 }
542
543 Math::real EllipticFunction::deltaG(real sn, real cn, real dn) const {
544 // Function is periodic with period pi
545 if (signbit(cn)) { cn = -cn; sn = -sn; }
546 return G(sn, cn, dn) * (Math::pi()/2) / G() - atan2(sn, cn);
547 }
548
549 Math::real EllipticFunction::deltaH(real sn, real cn, real dn) const {
550 // Function is periodic with period pi
551 if (signbit(cn)) { cn = -cn; sn = -sn; }
552 return H(sn, cn, dn) * (Math::pi()/2) / H() - atan2(sn, cn);
553 }
554
555 Math::real EllipticFunction::F(real phi) const {
556 if (_k2 == 0)
557 return phi;
558 else if (_kp2 == 0)
559 return asinh(tan(phi));
560 real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
561 return fabs(phi) < Math::pi() ? F(sn, cn, dn) :
562 (deltaF(sn, cn, dn) + phi) * K() / (Math::pi()/2);
563 }
564
565 Math::real EllipticFunction::E(real phi) const {
566 if (_k2 == 0)
567 return phi;
568 // else if (_kp2 == 0)
569 // Despite DLMF Eq 19.6.9 this is probably wrong, since
570 // sqrt(1 - k^2*sin(phi)^2) -> abs(cos(phi)) in the limit k -> 1.
571 // return sin(phi);
572 real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
573 return fabs(phi) < Math::pi() ? E(sn, cn, dn) :
574 (deltaE(sn, cn, dn) + phi) * E() / (Math::pi()/2);
575 }
576
577 Math::real EllipticFunction::Ed(real ang) const {
578 // ang - Math::AngNormalize(ang) is (nearly) an exact multiple of 360
579 real n = round((ang - Math::AngNormalize(ang))/Math::td);
580 real sn, cn;
581 Math::sincosd(ang, sn, cn);
582 return E(sn, cn, Delta(sn, cn)) + 4 * E() * n;
583 }
584
585 Math::real EllipticFunction::Pi(real phi) const {
586 real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
587 return fabs(phi) < Math::pi() ? Pi(sn, cn, dn) :
588 (deltaPi(sn, cn, dn) + phi) * Pi() / (Math::pi()/2);
589 }
590
591 Math::real EllipticFunction::D(real phi) const {
592 real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
593 return fabs(phi) < Math::pi() ? D(sn, cn, dn) :
594 (deltaD(sn, cn, dn) + phi) * D() / (Math::pi()/2);
595 }
596
597 Math::real EllipticFunction::G(real phi) const {
598 real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
599 return fabs(phi) < Math::pi() ? G(sn, cn, dn) :
600 (deltaG(sn, cn, dn) + phi) * G() / (Math::pi()/2);
601 }
602
603 Math::real EllipticFunction::H(real phi) const {
604 real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn);
605 return fabs(phi) < Math::pi() ? H(sn, cn, dn) :
606 (deltaH(sn, cn, dn) + phi) * H() / (Math::pi()/2);
607 }
608
609 Math::real EllipticFunction::Einv(real x) const {
610 static const real tolJAC =
611 sqrt(numeric_limits<real>::epsilon() / real(100));
612 real n = floor(x / (2 * _eEc) + real(0.5));
613 x -= 2 * _eEc * n; // x now in [-ec, ec)
614 // Linear approximation
615 real phi = Math::pi() * x / (2 * _eEc); // phi in [-pi/2, pi/2)
616 // First order correction
617 phi -= _eps * sin(2 * phi) / 2;
618 // For kp2 close to zero use asin(x/_eEc) or
619 // J. P. Boyd, Applied Math. and Computation 218, 7005-7013 (2012)
620 // https://doi.org/10.1016/j.amc.2011.12.021
621 for (int i = 0;
622 i < num_ ||
623 GEOGRAPHICLIB_PANIC("Convergence failure in EllipticFunction::Einv");
624 ++i) {
625 real
626 sn = sin(phi),
627 cn = cos(phi),
628 dn = Delta(sn, cn),
629 err = (E(sn, cn, dn) - x)/dn;
630 phi -= err;
631 if (!(fabs(err) > tolJAC))
632 break;
633 }
634 return n * Math::pi() + phi;
635 }
636
637 Math::real EllipticFunction::deltaEinv(real stau, real ctau) const {
638 // Function is periodic with period pi
639 if (signbit(ctau)) { ctau = -ctau; stau = -stau; }
640 real tau = atan2(stau, ctau);
641 return Einv( tau * E() / (Math::pi()/2) ) - tau;
642 }
643
644} // namespace GeographicLib
EllipticFunction.hpp
Header for GeographicLib::EllipticFunction class.
ang
GeographicLib::Angle ang
Definition Geod3Solve.cpp:26
real
GeographicLib::Math::real real
Definition Geod3Solve.cpp:25
GEOGRAPHICLIB_PANIC
#define GEOGRAPHICLIB_PANIC(msg)
Definition Math.hpp:67
GeographicLib::EllipticFunction::G
Math::real G() const
Definition EllipticFunction.hpp:251
GeographicLib::EllipticFunction::sncndn
void sncndn(real x, real &sn, real &cn, real &dn) const
Definition EllipticFunction.cpp:315
GeographicLib::EllipticFunction::RJ
static real RJ(real x, real y, real z, real p)
Definition EllipticFunction.cpp:123
GeographicLib::EllipticFunction::H
Math::real H() const
Definition EllipticFunction.hpp:265
GeographicLib::EllipticFunction::deltaG
Math::real deltaG(real sn, real cn, real dn) const
Definition EllipticFunction.cpp:543
GeographicLib::EllipticFunction::RG
static real RG(real x, real y, real z)
Definition EllipticFunction.cpp:91
GeographicLib::EllipticFunction::deltaE
Math::real deltaE(real sn, real cn, real dn) const
Definition EllipticFunction.cpp:525
GeographicLib::EllipticFunction::F
Math::real F(real phi) const
Definition EllipticFunction.cpp:555
GeographicLib::EllipticFunction::RC
static real RC(real x, real y)
Definition EllipticFunction.cpp:76
GeographicLib::EllipticFunction::Einv
Math::real Einv(real x) const
Definition EllipticFunction.cpp:609
GeographicLib::EllipticFunction::RD
static real RD(real x, real y, real z)
Definition EllipticFunction.cpp:177
GeographicLib::EllipticFunction::Pi
Math::real Pi() const
Definition EllipticFunction.hpp:238
GeographicLib::EllipticFunction::E
Math::real E() const
Definition EllipticFunction.hpp:203
GeographicLib::EllipticFunction::k2
Math::real k2() const
Definition EllipticFunction.hpp:158
GeographicLib::EllipticFunction::alphap2
Math::real alphap2() const
Definition EllipticFunction.hpp:175
GeographicLib::EllipticFunction::Reset
void Reset(real k2=0, real alpha2=0)
Definition EllipticFunction.hpp:126
GeographicLib::EllipticFunction::am
Math::real am(real x) const
Definition EllipticFunction.cpp:378
GeographicLib::EllipticFunction::Delta
Math::real Delta(real sn, real cn) const
Definition EllipticFunction.hpp:607
GeographicLib::EllipticFunction::deltaD
Math::real deltaD(real sn, real cn, real dn) const
Definition EllipticFunction.cpp:537
GeographicLib::EllipticFunction::Ed
Math::real Ed(real ang) const
Definition EllipticFunction.cpp:577
GeographicLib::EllipticFunction::K
Math::real K() const
Definition EllipticFunction.hpp:191
GeographicLib::EllipticFunction::kp2
Math::real kp2() const
Definition EllipticFunction.hpp:164
GeographicLib::EllipticFunction::deltaH
Math::real deltaH(real sn, real cn, real dn) const
Definition EllipticFunction.cpp:549
GeographicLib::EllipticFunction::deltaF
Math::real deltaF(real sn, real cn, real dn) const
Definition EllipticFunction.cpp:519
GeographicLib::EllipticFunction::RF
static real RF(real x, real y, real z)
Definition EllipticFunction.cpp:24
GeographicLib::EllipticFunction::deltaPi
Math::real deltaPi(real sn, real cn, real dn) const
Definition EllipticFunction.cpp:531
GeographicLib::EllipticFunction::deltaEinv
Math::real deltaEinv(real stau, real ctau) const
Definition EllipticFunction.cpp:637
GeographicLib::EllipticFunction::alpha2
Math::real alpha2() const
Definition EllipticFunction.hpp:169
GeographicLib::EllipticFunction::D
Math::real D() const
Definition EllipticFunction.hpp:216
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition Constants.hpp:344
GeographicLib::Math::sincosd
static void sincosd(T x, T &sinx, T &cosx)
Definition Math.cpp:104
GeographicLib::Math::sq
static T sq(T x)
Definition Math.hpp:209
GeographicLib::Math::AngNormalize
static T AngNormalize(T x)
Definition Math.cpp:69
GeographicLib::Math::infinity
static T infinity()
Definition Math.cpp:308
GeographicLib::Math::td
static constexpr int td
degrees per turn
Definition Math.hpp:146
GeographicLib::Math::pi
static T pi()
Definition Math.hpp:187
GeographicLib::Math::real
double real
Definition Math.hpp:115
GeographicLib
Namespace for GeographicLib.
Definition Accumulator.cpp:12
std::swap
void swap(GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &a, GeographicLib::NearestNeighbor< dist_t, pos_t, distfun_t > &b)
Definition NearestNeighbor.hpp:819