geodesic.c
Go to the documentation of this file.
1 
10 /*
11  * This is a C implementation of the geodesic algorithms described in
12  *
13  * C. F. F. Karney,
14  * Algorithms for geodesics,
15  * J. Geodesy <b>87</b>, 43--55 (2013);
16  * https://doi.org/10.1007/s00190-012-0578-z
17  * Addenda: https://geographiclib.sourceforge.io/geod-addenda.html
18  *
19  * See the comments in geodesic.h for documentation.
20  *
21  * Copyright (c) Charles Karney (2012-2017) <charles@karney.com> and licensed
22  * under the MIT/X11 License. For more information, see
23  * https://geographiclib.sourceforge.io/
24  */
25 
26 #include "geodesic.h"
27 #include <math.h>
28 
29 #if !defined(HAVE_C99_MATH)
30 #define HAVE_C99_MATH 0
31 #endif
32 
33 #define GEOGRAPHICLIB_GEODESIC_ORDER 6
34 #define nA1 GEOGRAPHICLIB_GEODESIC_ORDER
35 #define nC1 GEOGRAPHICLIB_GEODESIC_ORDER
36 #define nC1p GEOGRAPHICLIB_GEODESIC_ORDER
37 #define nA2 GEOGRAPHICLIB_GEODESIC_ORDER
38 #define nC2 GEOGRAPHICLIB_GEODESIC_ORDER
39 #define nA3 GEOGRAPHICLIB_GEODESIC_ORDER
40 #define nA3x nA3
41 #define nC3 GEOGRAPHICLIB_GEODESIC_ORDER
42 #define nC3x ((nC3 * (nC3 - 1)) / 2)
43 #define nC4 GEOGRAPHICLIB_GEODESIC_ORDER
44 #define nC4x ((nC4 * (nC4 + 1)) / 2)
45 #define nC (GEOGRAPHICLIB_GEODESIC_ORDER + 1)
46 
47 typedef double real;
48 typedef int boolx;
49 
50 static unsigned init = 0;
51 static const int FALSE = 0;
52 static const int TRUE = 1;
53 static unsigned digits, maxit1, maxit2;
54 static real epsilon, realmin, pi, degree, NaN,
55  tiny, tol0, tol1, tol2, tolb, xthresh;
56 
57 static void Init() {
58  if (!init) {
59 #if defined(__DBL_MANT_DIG__)
60  digits = __DBL_MANT_DIG__;
61 #else
62  digits = 53;
63 #endif
64 #if defined(__DBL_EPSILON__)
65  epsilon = __DBL_EPSILON__;
66 #else
67  epsilon = pow(0.5, digits - 1);
68 #endif
69 #if defined(__DBL_MIN__)
70  realmin = __DBL_MIN__;
71 #else
72  realmin = pow(0.5, 1022);
73 #endif
74 #if defined(M_PI)
75  pi = M_PI;
76 #else
77  pi = atan2(0.0, -1.0);
78 #endif
79  maxit1 = 20;
80  maxit2 = maxit1 + digits + 10;
81  tiny = sqrt(realmin);
82  tol0 = epsilon;
83  /* Increase multiplier in defn of tol1 from 100 to 200 to fix inverse case
84  * 52.784459512564 0 -52.784459512563990912 179.634407464943777557
85  * which otherwise failed for Visual Studio 10 (Release and Debug) */
86  tol1 = 200 * tol0;
87  tol2 = sqrt(tol0);
88  /* Check on bisection interval */
89  tolb = tol0 * tol2;
90  xthresh = 1000 * tol2;
91  degree = pi/180;
92  {
93  real minus1 = -1;
94  NaN = sqrt(minus1);
95  }
96  init = 1;
97  }
98 }
99 
100 enum captype {
101  CAP_NONE = 0U,
102  CAP_C1 = 1U<<0,
103  CAP_C1p = 1U<<1,
104  CAP_C2 = 1U<<2,
105  CAP_C3 = 1U<<3,
106  CAP_C4 = 1U<<4,
107  CAP_ALL = 0x1FU,
108  OUT_ALL = 0x7F80U
109 };
110 
111 static real sq(real x) { return x * x; }
112 #if HAVE_C99_MATH
113 #define atanhx atanh
114 #define copysignx copysign
115 #define hypotx hypot
116 #define cbrtx cbrt
117 #else
118 static real log1px(real x) {
119  volatile real
120  y = 1 + x,
121  z = y - 1;
122  /* Here's the explanation for this magic: y = 1 + z, exactly, and z
123  * approx x, thus log(y)/z (which is nearly constant near z = 0) returns
124  * a good approximation to the true log(1 + x)/x. The multiplication x *
125  * (log(y)/z) introduces little additional error. */
126  return z == 0 ? x : x * log(y) / z;
127 }
128 
129 static real atanhx(real x) {
130  real y = fabs(x); /* Enforce odd parity */
131  y = log1px(2 * y/(1 - y))/2;
132  return x < 0 ? -y : y;
133 }
134 
135 static real copysignx(real x, real y) {
136  return fabs(x) * (y < 0 || (y == 0 && 1/y < 0) ? -1 : 1);
137 }
138 
139 static real hypotx(real x, real y)
140 { return sqrt(x * x + y * y); }
141 
142 static real cbrtx(real x) {
143  real y = pow(fabs(x), 1/(real)(3)); /* Return the real cube root */
144  return x < 0 ? -y : y;
145 }
146 #endif
147 
148 static real sumx(real u, real v, real* t) {
149  volatile real s = u + v;
150  volatile real up = s - v;
151  volatile real vpp = s - up;
152  up -= u;
153  vpp -= v;
154  if (t) *t = -(up + vpp);
155  /* error-free sum:
156  * u + v = s + t
157  * = round(u + v) + t */
158  return s;
159 }
160 
161 static real polyval(int N, const real p[], real x) {
162  real y = N < 0 ? 0 : *p++;
163  while (--N >= 0) y = y * x + *p++;
164  return y;
165 }
166 
167 /* mimic C++ std::min and std::max */
168 static real minx(real a, real b)
169 { return (b < a) ? b : a; }
170 
171 static real maxx(real a, real b)
172 { return (a < b) ? b : a; }
173 
174 static void swapx(real* x, real* y)
175 { real t = *x; *x = *y; *y = t; }
176 
177 static void norm2(real* sinx, real* cosx) {
178  real r = hypotx(*sinx, *cosx);
179  *sinx /= r;
180  *cosx /= r;
181 }
182 
183 static real AngNormalize(real x) {
184 #if HAVE_C99_MATH
185  x = remainder(x, (real)(360));
186  return x != -180 ? x : 180;
187 #else
188  x = fmod(x, (real)(360));
189  return x <= -180 ? x + 360 : (x <= 180 ? x : x - 360);
190 #endif
191 }
192 
193 static real LatFix(real x)
194 { return fabs(x) > 90 ? NaN : x; }
195 
196 static real AngDiff(real x, real y, real* e) {
197  real t, d = AngNormalize(sumx(AngNormalize(-x), AngNormalize(y), &t));
198  /* Here y - x = d + t (mod 360), exactly, where d is in (-180,180] and
199  * abs(t) <= eps (eps = 2^-45 for doubles). The only case where the
200  * addition of t takes the result outside the range (-180,180] is d = 180
201  * and t > 0. The case, d = -180 + eps, t = -eps, can't happen, since
202  * sum would have returned the exact result in such a case (i.e., given t
203  * = 0). */
204  return sumx(d == 180 && t > 0 ? -180 : d, t, e);
205 }
206 
207 static real AngRound(real x) {
208  const real z = 1/(real)(16);
209  volatile real y;
210  if (x == 0) return 0;
211  y = fabs(x);
212  /* The compiler mustn't "simplify" z - (z - y) to y */
213  y = y < z ? z - (z - y) : y;
214  return x < 0 ? -y : y;
215 }
216 
217 static void sincosdx(real x, real* sinx, real* cosx) {
218  /* In order to minimize round-off errors, this function exactly reduces
219  * the argument to the range [-45, 45] before converting it to radians. */
220  real r, s, c; int q;
221 #if HAVE_C99_MATH && !defined(__GNUC__)
222  /* Disable for gcc because of bug in glibc version < 2.22, see
223  * https://sourceware.org/bugzilla/show_bug.cgi?id=17569 */
224  r = remquo(x, (real)(90), &q);
225 #else
226  r = fmod(x, (real)(360));
227  q = (int)(floor(r / 90 + (real)(0.5)));
228  r -= 90 * q;
229 #endif
230  /* now abs(r) <= 45 */
231  r *= degree;
232  /* Possibly could call the gnu extension sincos */
233  s = sin(r); c = cos(r);
234  switch ((unsigned)q & 3U) {
235  case 0U: *sinx = s; *cosx = c; break;
236  case 1U: *sinx = c; *cosx = -s; break;
237  case 2U: *sinx = -s; *cosx = -c; break;
238  default: *sinx = -c; *cosx = s; break; /* case 3U */
239  }
240  if (x != 0) { *sinx += (real)(0); *cosx += (real)(0); }
241 }
242 
243 static real atan2dx(real y, real x) {
244  /* In order to minimize round-off errors, this function rearranges the
245  * arguments so that result of atan2 is in the range [-pi/4, pi/4] before
246  * converting it to degrees and mapping the result to the correct
247  * quadrant. */
248  int q = 0; real ang;
249  if (fabs(y) > fabs(x)) { swapx(&x, &y); q = 2; }
250  if (x < 0) { x = -x; ++q; }
251  /* here x >= 0 and x >= abs(y), so angle is in [-pi/4, pi/4] */
252  ang = atan2(y, x) / degree;
253  switch (q) {
254  /* Note that atan2d(-0.0, 1.0) will return -0. However, we expect that
255  * atan2d will not be called with y = -0. If need be, include
256  *
257  * case 0: ang = 0 + ang; break;
258  */
259  case 1: ang = (y >= 0 ? 180 : -180) - ang; break;
260  case 2: ang = 90 - ang; break;
261  case 3: ang = -90 + ang; break;
262  }
263  return ang;
264 }
265 
266 static void A3coeff(struct geod_geodesic* g);
267 static void C3coeff(struct geod_geodesic* g);
268 static void C4coeff(struct geod_geodesic* g);
269 static real SinCosSeries(boolx sinp,
270  real sinx, real cosx,
271  const real c[], int n);
272 static void Lengths(const struct geod_geodesic* g,
273  real eps, real sig12,
274  real ssig1, real csig1, real dn1,
275  real ssig2, real csig2, real dn2,
276  real cbet1, real cbet2,
277  real* ps12b, real* pm12b, real* pm0,
278  real* pM12, real* pM21,
279  /* Scratch area of the right size */
280  real Ca[]);
281 static real Astroid(real x, real y);
282 static real InverseStart(const struct geod_geodesic* g,
283  real sbet1, real cbet1, real dn1,
284  real sbet2, real cbet2, real dn2,
285  real lam12, real slam12, real clam12,
286  real* psalp1, real* pcalp1,
287  /* Only updated if return val >= 0 */
288  real* psalp2, real* pcalp2,
289  /* Only updated for short lines */
290  real* pdnm,
291  /* Scratch area of the right size */
292  real Ca[]);
293 static real Lambda12(const struct geod_geodesic* g,
294  real sbet1, real cbet1, real dn1,
295  real sbet2, real cbet2, real dn2,
296  real salp1, real calp1,
297  real slam120, real clam120,
298  real* psalp2, real* pcalp2,
299  real* psig12,
300  real* pssig1, real* pcsig1,
301  real* pssig2, real* pcsig2,
302  real* peps,
303  real* pgomg12,
304  boolx diffp, real* pdlam12,
305  /* Scratch area of the right size */
306  real Ca[]);
307 static real A3f(const struct geod_geodesic* g, real eps);
308 static void C3f(const struct geod_geodesic* g, real eps, real c[]);
309 static void C4f(const struct geod_geodesic* g, real eps, real c[]);
310 static real A1m1f(real eps);
311 static void C1f(real eps, real c[]);
312 static void C1pf(real eps, real c[]);
313 static real A2m1f(real eps);
314 static void C2f(real eps, real c[]);
315 static int transit(real lon1, real lon2);
316 static int transitdirect(real lon1, real lon2);
317 static void accini(real s[]);
318 static void acccopy(const real s[], real t[]);
319 static void accadd(real s[], real y);
320 static real accsum(const real s[], real y);
321 static void accneg(real s[]);
322 
323 void geod_init(struct geod_geodesic* g, real a, real f) {
324  if (!init) Init();
325  g->a = a;
326  g->f = f;
327  g->f1 = 1 - g->f;
328  g->e2 = g->f * (2 - g->f);
329  g->ep2 = g->e2 / sq(g->f1); /* e2 / (1 - e2) */
330  g->n = g->f / ( 2 - g->f);
331  g->b = g->a * g->f1;
332  g->c2 = (sq(g->a) + sq(g->b) *
333  (g->e2 == 0 ? 1 :
334  (g->e2 > 0 ? atanhx(sqrt(g->e2)) : atan(sqrt(-g->e2))) /
335  sqrt(fabs(g->e2))))/2; /* authalic radius squared */
336  /* The sig12 threshold for "really short". Using the auxiliary sphere
337  * solution with dnm computed at (bet1 + bet2) / 2, the relative error in the
338  * azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2. (Error
339  * measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a given f and
340  * sig12, the max error occurs for lines near the pole. If the old rule for
341  * computing dnm = (dn1 + dn2)/2 is used, then the error increases by a
342  * factor of 2.) Setting this equal to epsilon gives sig12 = etol2. Here
343  * 0.1 is a safety factor (error decreased by 100) and max(0.001, abs(f))
344  * stops etol2 getting too large in the nearly spherical case. */
345  g->etol2 = 0.1 * tol2 /
346  sqrt( maxx((real)(0.001), fabs(g->f)) * minx((real)(1), 1 - g->f/2) / 2 );
347 
348  A3coeff(g);
349  C3coeff(g);
350  C4coeff(g);
351 }
352 
353 static void geod_lineinit_int(struct geod_geodesicline* l,
354  const struct geod_geodesic* g,
355  real lat1, real lon1,
356  real azi1, real salp1, real calp1,
357  unsigned caps) {
358  real cbet1, sbet1, eps;
359  l->a = g->a;
360  l->f = g->f;
361  l->b = g->b;
362  l->c2 = g->c2;
363  l->f1 = g->f1;
364  /* If caps is 0 assume the standard direct calculation */
365  l->caps = (caps ? caps : GEOD_DISTANCE_IN | GEOD_LONGITUDE) |
366  /* always allow latitude and azimuth and unrolling of longitude */
368 
369  l->lat1 = LatFix(lat1);
370  l->lon1 = lon1;
371  l->azi1 = azi1;
372  l->salp1 = salp1;
373  l->calp1 = calp1;
374 
375  sincosdx(AngRound(l->lat1), &sbet1, &cbet1); sbet1 *= l->f1;
376  /* Ensure cbet1 = +epsilon at poles */
377  norm2(&sbet1, &cbet1); cbet1 = maxx(tiny, cbet1);
378  l->dn1 = sqrt(1 + g->ep2 * sq(sbet1));
379 
380  /* Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0), */
381  l->salp0 = l->salp1 * cbet1; /* alp0 in [0, pi/2 - |bet1|] */
382  /* Alt: calp0 = hypot(sbet1, calp1 * cbet1). The following
383  * is slightly better (consider the case salp1 = 0). */
384  l->calp0 = hypotx(l->calp1, l->salp1 * sbet1);
385  /* Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1).
386  * sig = 0 is nearest northward crossing of equator.
387  * With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line).
388  * With bet1 = pi/2, alp1 = -pi, sig1 = pi/2
389  * With bet1 = -pi/2, alp1 = 0 , sig1 = -pi/2
390  * Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1).
391  * With alp0 in (0, pi/2], quadrants for sig and omg coincide.
392  * No atan2(0,0) ambiguity at poles since cbet1 = +epsilon.
393  * With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi. */
394  l->ssig1 = sbet1; l->somg1 = l->salp0 * sbet1;
395  l->csig1 = l->comg1 = sbet1 != 0 || l->calp1 != 0 ? cbet1 * l->calp1 : 1;
396  norm2(&l->ssig1, &l->csig1); /* sig1 in (-pi, pi] */
397  /* norm2(somg1, comg1); -- don't need to normalize! */
398 
399  l->k2 = sq(l->calp0) * g->ep2;
400  eps = l->k2 / (2 * (1 + sqrt(1 + l->k2)) + l->k2);
401 
402  if (l->caps & CAP_C1) {
403  real s, c;
404  l->A1m1 = A1m1f(eps);
405  C1f(eps, l->C1a);
406  l->B11 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C1a, nC1);
407  s = sin(l->B11); c = cos(l->B11);
408  /* tau1 = sig1 + B11 */
409  l->stau1 = l->ssig1 * c + l->csig1 * s;
410  l->ctau1 = l->csig1 * c - l->ssig1 * s;
411  /* Not necessary because C1pa reverts C1a
412  * B11 = -SinCosSeries(TRUE, stau1, ctau1, C1pa, nC1p); */
413  }
414 
415  if (l->caps & CAP_C1p)
416  C1pf(eps, l->C1pa);
417 
418  if (l->caps & CAP_C2) {
419  l->A2m1 = A2m1f(eps);
420  C2f(eps, l->C2a);
421  l->B21 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C2a, nC2);
422  }
423 
424  if (l->caps & CAP_C3) {
425  C3f(g, eps, l->C3a);
426  l->A3c = -l->f * l->salp0 * A3f(g, eps);
427  l->B31 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C3a, nC3-1);
428  }
429 
430  if (l->caps & CAP_C4) {
431  C4f(g, eps, l->C4a);
432  /* Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0) */
433  l->A4 = sq(l->a) * l->calp0 * l->salp0 * g->e2;
434  l->B41 = SinCosSeries(FALSE, l->ssig1, l->csig1, l->C4a, nC4);
435  }
436 
437  l->a13 = l->s13 = NaN;
438 }
439 
440 void geod_lineinit(struct geod_geodesicline* l,
441  const struct geod_geodesic* g,
442  real lat1, real lon1, real azi1, unsigned caps) {
443  real salp1, calp1;
444  azi1 = AngNormalize(azi1);
445  /* Guard against underflow in salp0 */
446  sincosdx(AngRound(azi1), &salp1, &calp1);
447  geod_lineinit_int(l, g, lat1, lon1, azi1, salp1, calp1, caps);
448 }
449 
451  const struct geod_geodesic* g,
452  real lat1, real lon1, real azi1,
453  unsigned flags, real a12_s12,
454  unsigned caps) {
455  geod_lineinit(l, g, lat1, lon1, azi1, caps);
456  geod_gensetdistance(l, flags, a12_s12);
457 }
458 
459 void geod_directline(struct geod_geodesicline* l,
460  const struct geod_geodesic* g,
461  real lat1, real lon1, real azi1,
462  real s12, unsigned caps) {
463  geod_gendirectline(l, g, lat1, lon1, azi1, GEOD_NOFLAGS, s12, caps);
464 }
465 
467  unsigned flags, real s12_a12,
468  real* plat2, real* plon2, real* pazi2,
469  real* ps12, real* pm12,
470  real* pM12, real* pM21,
471  real* pS12) {
472  real lat2 = 0, lon2 = 0, azi2 = 0, s12 = 0,
473  m12 = 0, M12 = 0, M21 = 0, S12 = 0;
474  /* Avoid warning about uninitialized B12. */
475  real sig12, ssig12, csig12, B12 = 0, AB1 = 0;
476  real omg12, lam12, lon12;
477  real ssig2, csig2, sbet2, cbet2, somg2, comg2, salp2, calp2, dn2;
478  unsigned outmask =
479  (plat2 ? GEOD_LATITUDE : 0U) |
480  (plon2 ? GEOD_LONGITUDE : 0U) |
481  (pazi2 ? GEOD_AZIMUTH : 0U) |
482  (ps12 ? GEOD_DISTANCE : 0U) |
483  (pm12 ? GEOD_REDUCEDLENGTH : 0U) |
484  (pM12 || pM21 ? GEOD_GEODESICSCALE : 0U) |
485  (pS12 ? GEOD_AREA : 0U);
486 
487  outmask &= l->caps & OUT_ALL;
488  if (!( TRUE /*Init()*/ &&
489  (flags & GEOD_ARCMODE || (l->caps & (GEOD_DISTANCE_IN & OUT_ALL))) ))
490  /* Uninitialized or impossible distance calculation requested */
491  return NaN;
492 
493  if (flags & GEOD_ARCMODE) {
494  /* Interpret s12_a12 as spherical arc length */
495  sig12 = s12_a12 * degree;
496  sincosdx(s12_a12, &ssig12, &csig12);
497  } else {
498  /* Interpret s12_a12 as distance */
499  real
500  tau12 = s12_a12 / (l->b * (1 + l->A1m1)),
501  s = sin(tau12),
502  c = cos(tau12);
503  /* tau2 = tau1 + tau12 */
504  B12 = - SinCosSeries(TRUE,
505  l->stau1 * c + l->ctau1 * s,
506  l->ctau1 * c - l->stau1 * s,
507  l->C1pa, nC1p);
508  sig12 = tau12 - (B12 - l->B11);
509  ssig12 = sin(sig12); csig12 = cos(sig12);
510  if (fabs(l->f) > 0.01) {
511  /* Reverted distance series is inaccurate for |f| > 1/100, so correct
512  * sig12 with 1 Newton iteration. The following table shows the
513  * approximate maximum error for a = WGS_a() and various f relative to
514  * GeodesicExact.
515  * erri = the error in the inverse solution (nm)
516  * errd = the error in the direct solution (series only) (nm)
517  * errda = the error in the direct solution (series + 1 Newton) (nm)
518  *
519  * f erri errd errda
520  * -1/5 12e6 1.2e9 69e6
521  * -1/10 123e3 12e6 765e3
522  * -1/20 1110 108e3 7155
523  * -1/50 18.63 200.9 27.12
524  * -1/100 18.63 23.78 23.37
525  * -1/150 18.63 21.05 20.26
526  * 1/150 22.35 24.73 25.83
527  * 1/100 22.35 25.03 25.31
528  * 1/50 29.80 231.9 30.44
529  * 1/20 5376 146e3 10e3
530  * 1/10 829e3 22e6 1.5e6
531  * 1/5 157e6 3.8e9 280e6 */
532  real serr;
533  ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12;
534  csig2 = l->csig1 * csig12 - l->ssig1 * ssig12;
535  B12 = SinCosSeries(TRUE, ssig2, csig2, l->C1a, nC1);
536  serr = (1 + l->A1m1) * (sig12 + (B12 - l->B11)) - s12_a12 / l->b;
537  sig12 = sig12 - serr / sqrt(1 + l->k2 * sq(ssig2));
538  ssig12 = sin(sig12); csig12 = cos(sig12);
539  /* Update B12 below */
540  }
541  }
542 
543  /* sig2 = sig1 + sig12 */
544  ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12;
545  csig2 = l->csig1 * csig12 - l->ssig1 * ssig12;
546  dn2 = sqrt(1 + l->k2 * sq(ssig2));
548  if (flags & GEOD_ARCMODE || fabs(l->f) > 0.01)
549  B12 = SinCosSeries(TRUE, ssig2, csig2, l->C1a, nC1);
550  AB1 = (1 + l->A1m1) * (B12 - l->B11);
551  }
552  /* sin(bet2) = cos(alp0) * sin(sig2) */
553  sbet2 = l->calp0 * ssig2;
554  /* Alt: cbet2 = hypot(csig2, salp0 * ssig2); */
555  cbet2 = hypotx(l->salp0, l->calp0 * csig2);
556  if (cbet2 == 0)
557  /* I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case */
558  cbet2 = csig2 = tiny;
559  /* tan(alp0) = cos(sig2)*tan(alp2) */
560  salp2 = l->salp0; calp2 = l->calp0 * csig2; /* No need to normalize */
561 
562  if (outmask & GEOD_DISTANCE)
563  s12 = flags & GEOD_ARCMODE ?
564  l->b * ((1 + l->A1m1) * sig12 + AB1) :
565  s12_a12;
566 
567  if (outmask & GEOD_LONGITUDE) {
568  real E = copysignx(1, l->salp0); /* east or west going? */
569  /* tan(omg2) = sin(alp0) * tan(sig2) */
570  somg2 = l->salp0 * ssig2; comg2 = csig2; /* No need to normalize */
571  /* omg12 = omg2 - omg1 */
572  omg12 = flags & GEOD_LONG_UNROLL
573  ? E * (sig12
574  - (atan2( ssig2, csig2) - atan2( l->ssig1, l->csig1))
575  + (atan2(E * somg2, comg2) - atan2(E * l->somg1, l->comg1)))
576  : atan2(somg2 * l->comg1 - comg2 * l->somg1,
577  comg2 * l->comg1 + somg2 * l->somg1);
578  lam12 = omg12 + l->A3c *
579  ( sig12 + (SinCosSeries(TRUE, ssig2, csig2, l->C3a, nC3-1)
580  - l->B31));
581  lon12 = lam12 / degree;
582  lon2 = flags & GEOD_LONG_UNROLL ? l->lon1 + lon12 :
583  AngNormalize(AngNormalize(l->lon1) + AngNormalize(lon12));
584  }
585 
586  if (outmask & GEOD_LATITUDE)
587  lat2 = atan2dx(sbet2, l->f1 * cbet2);
588 
589  if (outmask & GEOD_AZIMUTH)
590  azi2 = atan2dx(salp2, calp2);
591 
592  if (outmask & (GEOD_REDUCEDLENGTH | GEOD_GEODESICSCALE)) {
593  real
594  B22 = SinCosSeries(TRUE, ssig2, csig2, l->C2a, nC2),
595  AB2 = (1 + l->A2m1) * (B22 - l->B21),
596  J12 = (l->A1m1 - l->A2m1) * sig12 + (AB1 - AB2);
597  if (outmask & GEOD_REDUCEDLENGTH)
598  /* Add parens around (csig1 * ssig2) and (ssig1 * csig2) to ensure
599  * accurate cancellation in the case of coincident points. */
600  m12 = l->b * ((dn2 * (l->csig1 * ssig2) - l->dn1 * (l->ssig1 * csig2))
601  - l->csig1 * csig2 * J12);
602  if (outmask & GEOD_GEODESICSCALE) {
603  real t = l->k2 * (ssig2 - l->ssig1) * (ssig2 + l->ssig1) /
604  (l->dn1 + dn2);
605  M12 = csig12 + (t * ssig2 - csig2 * J12) * l->ssig1 / l->dn1;
606  M21 = csig12 - (t * l->ssig1 - l->csig1 * J12) * ssig2 / dn2;
607  }
608  }
609 
610  if (outmask & GEOD_AREA) {
611  real
612  B42 = SinCosSeries(FALSE, ssig2, csig2, l->C4a, nC4);
613  real salp12, calp12;
614  if (l->calp0 == 0 || l->salp0 == 0) {
615  /* alp12 = alp2 - alp1, used in atan2 so no need to normalize */
616  salp12 = salp2 * l->calp1 - calp2 * l->salp1;
617  calp12 = calp2 * l->calp1 + salp2 * l->salp1;
618  } else {
619  /* tan(alp) = tan(alp0) * sec(sig)
620  * tan(alp2-alp1) = (tan(alp2) -tan(alp1)) / (tan(alp2)*tan(alp1)+1)
621  * = calp0 * salp0 * (csig1-csig2) / (salp0^2 + calp0^2 * csig1*csig2)
622  * If csig12 > 0, write
623  * csig1 - csig2 = ssig12 * (csig1 * ssig12 / (1 + csig12) + ssig1)
624  * else
625  * csig1 - csig2 = csig1 * (1 - csig12) + ssig12 * ssig1
626  * No need to normalize */
627  salp12 = l->calp0 * l->salp0 *
628  (csig12 <= 0 ? l->csig1 * (1 - csig12) + ssig12 * l->ssig1 :
629  ssig12 * (l->csig1 * ssig12 / (1 + csig12) + l->ssig1));
630  calp12 = sq(l->salp0) + sq(l->calp0) * l->csig1 * csig2;
631  }
632  S12 = l->c2 * atan2(salp12, calp12) + l->A4 * (B42 - l->B41);
633  }
634 
635  if (outmask & GEOD_LATITUDE)
636  *plat2 = lat2;
637  if (outmask & GEOD_LONGITUDE)
638  *plon2 = lon2;
639  if (outmask & GEOD_AZIMUTH)
640  *pazi2 = azi2;
641  if (outmask & GEOD_DISTANCE)
642  *ps12 = s12;
643  if (outmask & GEOD_REDUCEDLENGTH)
644  *pm12 = m12;
645  if (outmask & GEOD_GEODESICSCALE) {
646  if (pM12) *pM12 = M12;
647  if (pM21) *pM21 = M21;
648  }
649  if (outmask & GEOD_AREA)
650  *pS12 = S12;
651 
652  return flags & GEOD_ARCMODE ? s12_a12 : sig12 / degree;
653 }
654 
655 void geod_setdistance(struct geod_geodesicline* l, real s13) {
656  l->s13 = s13;
657  l->a13 = geod_genposition(l, GEOD_NOFLAGS, l->s13, 0, 0, 0, 0, 0, 0, 0, 0);
658 }
659 
660 static void geod_setarc(struct geod_geodesicline* l, real a13) {
661  l->a13 = a13; l->s13 = NaN;
662  geod_genposition(l, GEOD_ARCMODE, l->a13, 0, 0, 0, &l->s13, 0, 0, 0, 0);
663 }
664 
666  unsigned flags, real s13_a13) {
667  flags & GEOD_ARCMODE ?
668  geod_setarc(l, s13_a13) :
669  geod_setdistance(l, s13_a13);
670 }
671 
672 void geod_position(const struct geod_geodesicline* l, real s12,
673  real* plat2, real* plon2, real* pazi2) {
674  geod_genposition(l, FALSE, s12, plat2, plon2, pazi2, 0, 0, 0, 0, 0);
675 }
676 
677 real geod_gendirect(const struct geod_geodesic* g,
678  real lat1, real lon1, real azi1,
679  unsigned flags, real s12_a12,
680  real* plat2, real* plon2, real* pazi2,
681  real* ps12, real* pm12, real* pM12, real* pM21,
682  real* pS12) {
683  struct geod_geodesicline l;
684  unsigned outmask =
685  (plat2 ? GEOD_LATITUDE : 0U) |
686  (plon2 ? GEOD_LONGITUDE : 0U) |
687  (pazi2 ? GEOD_AZIMUTH : 0U) |
688  (ps12 ? GEOD_DISTANCE : 0U) |
689  (pm12 ? GEOD_REDUCEDLENGTH : 0U) |
690  (pM12 || pM21 ? GEOD_GEODESICSCALE : 0U) |
691  (pS12 ? GEOD_AREA : 0U);
692 
693  geod_lineinit(&l, g, lat1, lon1, azi1,
694  /* Automatically supply GEOD_DISTANCE_IN if necessary */
695  outmask |
696  (flags & GEOD_ARCMODE ? GEOD_NONE : GEOD_DISTANCE_IN));
697  return geod_genposition(&l, flags, s12_a12,
698  plat2, plon2, pazi2, ps12, pm12, pM12, pM21, pS12);
699 }
700 
701 void geod_direct(const struct geod_geodesic* g,
703  real s12,
704  real* plat2, real* plon2, real* pazi2) {
705  geod_gendirect(g, lat1, lon1, azi1, GEOD_NOFLAGS, s12, plat2, plon2, pazi2,
706  0, 0, 0, 0, 0);
707 }
708 
709 static real geod_geninverse_int(const struct geod_geodesic* g,
710  real lat1, real lon1, real lat2, real lon2,
711  real* ps12,
712  real* psalp1, real* pcalp1,
713  real* psalp2, real* pcalp2,
714  real* pm12, real* pM12, real* pM21,
715  real* pS12) {
716  real s12 = 0, m12 = 0, M12 = 0, M21 = 0, S12 = 0;
717  real lon12, lon12s;
718  int latsign, lonsign, swapp;
719  real sbet1, cbet1, sbet2, cbet2, s12x = 0, m12x = 0;
720  real dn1, dn2, lam12, slam12, clam12;
721  real a12 = 0, sig12, calp1 = 0, salp1 = 0, calp2 = 0, salp2 = 0;
722  real Ca[nC];
723  boolx meridian;
724  /* somg12 > 1 marks that it needs to be calculated */
725  real omg12 = 0, somg12 = 2, comg12 = 0;
726 
727  unsigned outmask =
728  (ps12 ? GEOD_DISTANCE : 0U) |
729  (pm12 ? GEOD_REDUCEDLENGTH : 0U) |
730  (pM12 || pM21 ? GEOD_GEODESICSCALE : 0U) |
731  (pS12 ? GEOD_AREA : 0U);
732 
733  outmask &= OUT_ALL;
734  /* Compute longitude difference (AngDiff does this carefully). Result is
735  * in [-180, 180] but -180 is only for west-going geodesics. 180 is for
736  * east-going and meridional geodesics. */
737  lon12 = AngDiff(lon1, lon2, &lon12s);
738  /* Make longitude difference positive. */
739  lonsign = lon12 >= 0 ? 1 : -1;
740  /* If very close to being on the same half-meridian, then make it so. */
741  lon12 = lonsign * AngRound(lon12);
742  lon12s = AngRound((180 - lon12) - lonsign * lon12s);
743  lam12 = lon12 * degree;
744  if (lon12 > 90) {
745  sincosdx(lon12s, &slam12, &clam12);
746  clam12 = -clam12;
747  } else
748  sincosdx(lon12, &slam12, &clam12);
749 
750  /* If really close to the equator, treat as on equator. */
751  lat1 = AngRound(LatFix(lat1));
752  lat2 = AngRound(LatFix(lat2));
753  /* Swap points so that point with higher (abs) latitude is point 1
754  * If one latitude is a nan, then it becomes lat1. */
755  swapp = fabs(lat1) < fabs(lat2) ? -1 : 1;
756  if (swapp < 0) {
757  lonsign *= -1;
758  swapx(&lat1, &lat2);
759  }
760  /* Make lat1 <= 0 */
761  latsign = lat1 < 0 ? 1 : -1;
762  lat1 *= latsign;
763  lat2 *= latsign;
764  /* Now we have
765  *
766  * 0 <= lon12 <= 180
767  * -90 <= lat1 <= 0
768  * lat1 <= lat2 <= -lat1
769  *
770  * longsign, swapp, latsign register the transformation to bring the
771  * coordinates to this canonical form. In all cases, 1 means no change was
772  * made. We make these transformations so that there are few cases to
773  * check, e.g., on verifying quadrants in atan2. In addition, this
774  * enforces some symmetries in the results returned. */
775 
776  sincosdx(lat1, &sbet1, &cbet1); sbet1 *= g->f1;
777  /* Ensure cbet1 = +epsilon at poles */
778  norm2(&sbet1, &cbet1); cbet1 = maxx(tiny, cbet1);
779 
780  sincosdx(lat2, &sbet2, &cbet2); sbet2 *= g->f1;
781  /* Ensure cbet2 = +epsilon at poles */
782  norm2(&sbet2, &cbet2); cbet2 = maxx(tiny, cbet2);
783 
784  /* If cbet1 < -sbet1, then cbet2 - cbet1 is a sensitive measure of the
785  * |bet1| - |bet2|. Alternatively (cbet1 >= -sbet1), abs(sbet2) + sbet1 is
786  * a better measure. This logic is used in assigning calp2 in Lambda12.
787  * Sometimes these quantities vanish and in that case we force bet2 = +/-
788  * bet1 exactly. An example where is is necessary is the inverse problem
789  * 48.522876735459 0 -48.52287673545898293 179.599720456223079643
790  * which failed with Visual Studio 10 (Release and Debug) */
791 
792  if (cbet1 < -sbet1) {
793  if (cbet2 == cbet1)
794  sbet2 = sbet2 < 0 ? sbet1 : -sbet1;
795  } else {
796  if (fabs(sbet2) == -sbet1)
797  cbet2 = cbet1;
798  }
799 
800  dn1 = sqrt(1 + g->ep2 * sq(sbet1));
801  dn2 = sqrt(1 + g->ep2 * sq(sbet2));
802 
803  meridian = lat1 == -90 || slam12 == 0;
804 
805  if (meridian) {
806 
807  /* Endpoints are on a single full meridian, so the geodesic might lie on
808  * a meridian. */
809 
810  real ssig1, csig1, ssig2, csig2;
811  calp1 = clam12; salp1 = slam12; /* Head to the target longitude */
812  calp2 = 1; salp2 = 0; /* At the target we're heading north */
813 
814  /* tan(bet) = tan(sig) * cos(alp) */
815  ssig1 = sbet1; csig1 = calp1 * cbet1;
816  ssig2 = sbet2; csig2 = calp2 * cbet2;
817 
818  /* sig12 = sig2 - sig1 */
819  sig12 = atan2(maxx((real)(0), csig1 * ssig2 - ssig1 * csig2),
820  csig1 * csig2 + ssig1 * ssig2);
821  Lengths(g, g->n, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,
822  cbet1, cbet2, &s12x, &m12x, 0,
823  outmask & GEOD_GEODESICSCALE ? &M12 : 0,
824  outmask & GEOD_GEODESICSCALE ? &M21 : 0,
825  Ca);
826  /* Add the check for sig12 since zero length geodesics might yield m12 <
827  * 0. Test case was
828  *
829  * echo 20.001 0 20.001 0 | GeodSolve -i
830  *
831  * In fact, we will have sig12 > pi/2 for meridional geodesic which is
832  * not a shortest path. */
833  if (sig12 < 1 || m12x >= 0) {
834  /* Need at least 2, to handle 90 0 90 180 */
835  if (sig12 < 3 * tiny)
836  sig12 = m12x = s12x = 0;
837  m12x *= g->b;
838  s12x *= g->b;
839  a12 = sig12 / degree;
840  } else
841  /* m12 < 0, i.e., prolate and too close to anti-podal */
842  meridian = FALSE;
843  }
844 
845  if (!meridian &&
846  sbet1 == 0 && /* and sbet2 == 0 */
847  /* Mimic the way Lambda12 works with calp1 = 0 */
848  (g->f <= 0 || lon12s >= g->f * 180)) {
849 
850  /* Geodesic runs along equator */
851  calp1 = calp2 = 0; salp1 = salp2 = 1;
852  s12x = g->a * lam12;
853  sig12 = omg12 = lam12 / g->f1;
854  m12x = g->b * sin(sig12);
855  if (outmask & GEOD_GEODESICSCALE)
856  M12 = M21 = cos(sig12);
857  a12 = lon12 / g->f1;
858 
859  } else if (!meridian) {
860 
861  /* Now point1 and point2 belong within a hemisphere bounded by a
862  * meridian and geodesic is neither meridional or equatorial. */
863 
864  /* Figure a starting point for Newton's method */
865  real dnm = 0;
866  sig12 = InverseStart(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2,
867  lam12, slam12, clam12,
868  &salp1, &calp1, &salp2, &calp2, &dnm,
869  Ca);
870 
871  if (sig12 >= 0) {
872  /* Short lines (InverseStart sets salp2, calp2, dnm) */
873  s12x = sig12 * g->b * dnm;
874  m12x = sq(dnm) * g->b * sin(sig12 / dnm);
875  if (outmask & GEOD_GEODESICSCALE)
876  M12 = M21 = cos(sig12 / dnm);
877  a12 = sig12 / degree;
878  omg12 = lam12 / (g->f1 * dnm);
879  } else {
880 
881  /* Newton's method. This is a straightforward solution of f(alp1) =
882  * lambda12(alp1) - lam12 = 0 with one wrinkle. f(alp) has exactly one
883  * root in the interval (0, pi) and its derivative is positive at the
884  * root. Thus f(alp) is positive for alp > alp1 and negative for alp <
885  * alp1. During the course of the iteration, a range (alp1a, alp1b) is
886  * maintained which brackets the root and with each evaluation of
887  * f(alp) the range is shrunk, if possible. Newton's method is
888  * restarted whenever the derivative of f is negative (because the new
889  * value of alp1 is then further from the solution) or if the new
890  * estimate of alp1 lies outside (0,pi); in this case, the new starting
891  * guess is taken to be (alp1a + alp1b) / 2. */
892  real ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0, domg12 = 0;
893  unsigned numit = 0;
894  /* Bracketing range */
895  real salp1a = tiny, calp1a = 1, salp1b = tiny, calp1b = -1;
896  boolx tripn, tripb;
897  for (tripn = FALSE, tripb = FALSE; numit < maxit2; ++numit) {
898  /* the WGS84 test set: mean = 1.47, sd = 1.25, max = 16
899  * WGS84 and random input: mean = 2.85, sd = 0.60 */
900  real dv = 0,
901  v = Lambda12(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1,
902  slam12, clam12,
903  &salp2, &calp2, &sig12, &ssig1, &csig1, &ssig2, &csig2,
904  &eps, &domg12, numit < maxit1, &dv, Ca);
905  /* 2 * tol0 is approximately 1 ulp for a number in [0, pi]. */
906  /* Reversed test to allow escape with NaNs */
907  if (tripb || !(fabs(v) >= (tripn ? 8 : 1) * tol0)) break;
908  /* Update bracketing values */
909  if (v > 0 && (numit > maxit1 || calp1/salp1 > calp1b/salp1b))
910  { salp1b = salp1; calp1b = calp1; }
911  else if (v < 0 && (numit > maxit1 || calp1/salp1 < calp1a/salp1a))
912  { salp1a = salp1; calp1a = calp1; }
913  if (numit < maxit1 && dv > 0) {
914  real
915  dalp1 = -v/dv;
916  real
917  sdalp1 = sin(dalp1), cdalp1 = cos(dalp1),
918  nsalp1 = salp1 * cdalp1 + calp1 * sdalp1;
919  if (nsalp1 > 0 && fabs(dalp1) < pi) {
920  calp1 = calp1 * cdalp1 - salp1 * sdalp1;
921  salp1 = nsalp1;
922  norm2(&salp1, &calp1);
923  /* In some regimes we don't get quadratic convergence because
924  * slope -> 0. So use convergence conditions based on epsilon
925  * instead of sqrt(epsilon). */
926  tripn = fabs(v) <= 16 * tol0;
927  continue;
928  }
929  }
930  /* Either dv was not positive or updated value was outside legal
931  * range. Use the midpoint of the bracket as the next estimate.
932  * This mechanism is not needed for the WGS84 ellipsoid, but it does
933  * catch problems with more eccentric ellipsoids. Its efficacy is
934  * such for the WGS84 test set with the starting guess set to alp1 =
935  * 90deg:
936  * the WGS84 test set: mean = 5.21, sd = 3.93, max = 24
937  * WGS84 and random input: mean = 4.74, sd = 0.99 */
938  salp1 = (salp1a + salp1b)/2;
939  calp1 = (calp1a + calp1b)/2;
940  norm2(&salp1, &calp1);
941  tripn = FALSE;
942  tripb = (fabs(salp1a - salp1) + (calp1a - calp1) < tolb ||
943  fabs(salp1 - salp1b) + (calp1 - calp1b) < tolb);
944  }
945  Lengths(g, eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,
946  cbet1, cbet2, &s12x, &m12x, 0,
947  outmask & GEOD_GEODESICSCALE ? &M12 : 0,
948  outmask & GEOD_GEODESICSCALE ? &M21 : 0, Ca);
949  m12x *= g->b;
950  s12x *= g->b;
951  a12 = sig12 / degree;
952  if (outmask & GEOD_AREA) {
953  /* omg12 = lam12 - domg12 */
954  real sdomg12 = sin(domg12), cdomg12 = cos(domg12);
955  somg12 = slam12 * cdomg12 - clam12 * sdomg12;
956  comg12 = clam12 * cdomg12 + slam12 * sdomg12;
957  }
958  }
959  }
960 
961  if (outmask & GEOD_DISTANCE)
962  s12 = 0 + s12x; /* Convert -0 to 0 */
963 
964  if (outmask & GEOD_REDUCEDLENGTH)
965  m12 = 0 + m12x; /* Convert -0 to 0 */
966 
967  if (outmask & GEOD_AREA) {
968  real
969  /* From Lambda12: sin(alp1) * cos(bet1) = sin(alp0) */
970  salp0 = salp1 * cbet1,
971  calp0 = hypotx(calp1, salp1 * sbet1); /* calp0 > 0 */
972  real alp12;
973  if (calp0 != 0 && salp0 != 0) {
974  real
975  /* From Lambda12: tan(bet) = tan(sig) * cos(alp) */
976  ssig1 = sbet1, csig1 = calp1 * cbet1,
977  ssig2 = sbet2, csig2 = calp2 * cbet2,
978  k2 = sq(calp0) * g->ep2,
979  eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2),
980  /* Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0). */
981  A4 = sq(g->a) * calp0 * salp0 * g->e2;
982  real B41, B42;
983  norm2(&ssig1, &csig1);
984  norm2(&ssig2, &csig2);
985  C4f(g, eps, Ca);
986  B41 = SinCosSeries(FALSE, ssig1, csig1, Ca, nC4);
987  B42 = SinCosSeries(FALSE, ssig2, csig2, Ca, nC4);
988  S12 = A4 * (B42 - B41);
989  } else
990  /* Avoid problems with indeterminate sig1, sig2 on equator */
991  S12 = 0;
992 
993  if (!meridian && somg12 > 1) {
994  somg12 = sin(omg12); comg12 = cos(omg12);
995  }
996 
997  if (!meridian &&
998  /* omg12 < 3/4 * pi */
999  comg12 > -(real)(0.7071) && /* Long difference not too big */
1000  sbet2 - sbet1 < (real)(1.75)) { /* Lat difference not too big */
1001  /* Use tan(Gamma/2) = tan(omg12/2)
1002  * * (tan(bet1/2)+tan(bet2/2))/(1+tan(bet1/2)*tan(bet2/2))
1003  * with tan(x/2) = sin(x)/(1+cos(x)) */
1004  real
1005  domg12 = 1 + comg12, dbet1 = 1 + cbet1, dbet2 = 1 + cbet2;
1006  alp12 = 2 * atan2( somg12 * ( sbet1 * dbet2 + sbet2 * dbet1 ),
1007  domg12 * ( sbet1 * sbet2 + dbet1 * dbet2 ) );
1008  } else {
1009  /* alp12 = alp2 - alp1, used in atan2 so no need to normalize */
1010  real
1011  salp12 = salp2 * calp1 - calp2 * salp1,
1012  calp12 = calp2 * calp1 + salp2 * salp1;
1013  /* The right thing appears to happen if alp1 = +/-180 and alp2 = 0, viz
1014  * salp12 = -0 and alp12 = -180. However this depends on the sign
1015  * being attached to 0 correctly. The following ensures the correct
1016  * behavior. */
1017  if (salp12 == 0 && calp12 < 0) {
1018  salp12 = tiny * calp1;
1019  calp12 = -1;
1020  }
1021  alp12 = atan2(salp12, calp12);
1022  }
1023  S12 += g->c2 * alp12;
1024  S12 *= swapp * lonsign * latsign;
1025  /* Convert -0 to 0 */
1026  S12 += 0;
1027  }
1028 
1029  /* Convert calp, salp to azimuth accounting for lonsign, swapp, latsign. */
1030  if (swapp < 0) {
1031  swapx(&salp1, &salp2);
1032  swapx(&calp1, &calp2);
1033  if (outmask & GEOD_GEODESICSCALE)
1034  swapx(&M12, &M21);
1035  }
1036 
1037  salp1 *= swapp * lonsign; calp1 *= swapp * latsign;
1038  salp2 *= swapp * lonsign; calp2 *= swapp * latsign;
1039 
1040  if (psalp1) *psalp1 = salp1;
1041  if (pcalp1) *pcalp1 = calp1;
1042  if (psalp2) *psalp2 = salp2;
1043  if (pcalp2) *pcalp2 = calp2;
1044 
1045  if (outmask & GEOD_DISTANCE)
1046  *ps12 = s12;
1047  if (outmask & GEOD_REDUCEDLENGTH)
1048  *pm12 = m12;
1049  if (outmask & GEOD_GEODESICSCALE) {
1050  if (pM12) *pM12 = M12;
1051  if (pM21) *pM21 = M21;
1052  }
1053  if (outmask & GEOD_AREA)
1054  *pS12 = S12;
1055 
1056  /* Returned value in [0, 180] */
1057  return a12;
1058 }
1059 
1060 real geod_geninverse(const struct geod_geodesic* g,
1061  real lat1, real lon1, real lat2, real lon2,
1062  real* ps12, real* pazi1, real* pazi2,
1063  real* pm12, real* pM12, real* pM21, real* pS12) {
1064  real salp1, calp1, salp2, calp2,
1065  a12 = geod_geninverse_int(g, lat1, lon1, lat2, lon2, ps12,
1066  &salp1, &calp1, &salp2, &calp2,
1067  pm12, pM12, pM21, pS12);
1068  if (pazi1) *pazi1 = atan2dx(salp1, calp1);
1069  if (pazi2) *pazi2 = atan2dx(salp2, calp2);
1070  return a12;
1071 }
1072 
1073 void geod_inverseline(struct geod_geodesicline* l,
1074  const struct geod_geodesic* g,
1075  real lat1, real lon1, real lat2, real lon2,
1076  unsigned caps) {
1077  real salp1, calp1,
1078  a12 = geod_geninverse_int(g, lat1, lon1, lat2, lon2, 0,
1079  &salp1, &calp1, 0, 0,
1080  0, 0, 0, 0),
1081  azi1 = atan2dx(salp1, calp1);
1083  /* Ensure that a12 can be converted to a distance */
1084  if (caps & (OUT_ALL & GEOD_DISTANCE_IN)) caps |= GEOD_DISTANCE;
1085  geod_lineinit_int(l, g, lat1, lon1, azi1, salp1, calp1, caps);
1086  geod_setarc(l, a12);
1087 }
1088 
1089 void geod_inverse(const struct geod_geodesic* g,
1090  real lat1, real lon1, real lat2, real lon2,
1091  real* ps12, real* pazi1, real* pazi2) {
1092  geod_geninverse(g, lat1, lon1, lat2, lon2, ps12, pazi1, pazi2, 0, 0, 0, 0);
1093 }
1094 
1095 real SinCosSeries(boolx sinp, real sinx, real cosx, const real c[], int n) {
1096  /* Evaluate
1097  * y = sinp ? sum(c[i] * sin( 2*i * x), i, 1, n) :
1098  * sum(c[i] * cos((2*i+1) * x), i, 0, n-1)
1099  * using Clenshaw summation. N.B. c[0] is unused for sin series
1100  * Approx operation count = (n + 5) mult and (2 * n + 2) add */
1101  real ar, y0, y1;
1102  c += (n + sinp); /* Point to one beyond last element */
1103  ar = 2 * (cosx - sinx) * (cosx + sinx); /* 2 * cos(2 * x) */
1104  y0 = n & 1 ? *--c : 0; y1 = 0; /* accumulators for sum */
1105  /* Now n is even */
1106  n /= 2;
1107  while (n--) {
1108  /* Unroll loop x 2, so accumulators return to their original role */
1109  y1 = ar * y0 - y1 + *--c;
1110  y0 = ar * y1 - y0 + *--c;
1111  }
1112  return sinp
1113  ? 2 * sinx * cosx * y0 /* sin(2 * x) * y0 */
1114  : cosx * (y0 - y1); /* cos(x) * (y0 - y1) */
1115 }
1116 
1117 void Lengths(const struct geod_geodesic* g,
1118  real eps, real sig12,
1119  real ssig1, real csig1, real dn1,
1120  real ssig2, real csig2, real dn2,
1121  real cbet1, real cbet2,
1122  real* ps12b, real* pm12b, real* pm0,
1123  real* pM12, real* pM21,
1124  /* Scratch area of the right size */
1125  real Ca[]) {
1126  real m0 = 0, J12 = 0, A1 = 0, A2 = 0;
1127  real Cb[nC];
1128 
1129  /* Return m12b = (reduced length)/b; also calculate s12b = distance/b,
1130  * and m0 = coefficient of secular term in expression for reduced length. */
1131  boolx redlp = pm12b || pm0 || pM12 || pM21;
1132  if (ps12b || redlp) {
1133  A1 = A1m1f(eps);
1134  C1f(eps, Ca);
1135  if (redlp) {
1136  A2 = A2m1f(eps);
1137  C2f(eps, Cb);
1138  m0 = A1 - A2;
1139  A2 = 1 + A2;
1140  }
1141  A1 = 1 + A1;
1142  }
1143  if (ps12b) {
1144  real B1 = SinCosSeries(TRUE, ssig2, csig2, Ca, nC1) -
1145  SinCosSeries(TRUE, ssig1, csig1, Ca, nC1);
1146  /* Missing a factor of b */
1147  *ps12b = A1 * (sig12 + B1);
1148  if (redlp) {
1149  real B2 = SinCosSeries(TRUE, ssig2, csig2, Cb, nC2) -
1150  SinCosSeries(TRUE, ssig1, csig1, Cb, nC2);
1151  J12 = m0 * sig12 + (A1 * B1 - A2 * B2);
1152  }
1153  } else if (redlp) {
1154  /* Assume here that nC1 >= nC2 */
1155  int l;
1156  for (l = 1; l <= nC2; ++l)
1157  Cb[l] = A1 * Ca[l] - A2 * Cb[l];
1158  J12 = m0 * sig12 + (SinCosSeries(TRUE, ssig2, csig2, Cb, nC2) -
1159  SinCosSeries(TRUE, ssig1, csig1, Cb, nC2));
1160  }
1161  if (pm0) *pm0 = m0;
1162  if (pm12b)
1163  /* Missing a factor of b.
1164  * Add parens around (csig1 * ssig2) and (ssig1 * csig2) to ensure
1165  * accurate cancellation in the case of coincident points. */
1166  *pm12b = dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) -
1167  csig1 * csig2 * J12;
1168  if (pM12 || pM21) {
1169  real csig12 = csig1 * csig2 + ssig1 * ssig2;
1170  real t = g->ep2 * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2);
1171  if (pM12)
1172  *pM12 = csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1;
1173  if (pM21)
1174  *pM21 = csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2;
1175  }
1176 }
1177 
1178 real Astroid(real x, real y) {
1179  /* Solve k^4+2*k^3-(x^2+y^2-1)*k^2-2*y^2*k-y^2 = 0 for positive root k.
1180  * This solution is adapted from Geocentric::Reverse. */
1181  real k;
1182  real
1183  p = sq(x),
1184  q = sq(y),
1185  r = (p + q - 1) / 6;
1186  if ( !(q == 0 && r <= 0) ) {
1187  real
1188  /* Avoid possible division by zero when r = 0 by multiplying equations
1189  * for s and t by r^3 and r, resp. */
1190  S = p * q / 4, /* S = r^3 * s */
1191  r2 = sq(r),
1192  r3 = r * r2,
1193  /* The discriminant of the quadratic equation for T3. This is zero on
1194  * the evolute curve p^(1/3)+q^(1/3) = 1 */
1195  disc = S * (S + 2 * r3);
1196  real u = r;
1197  real v, uv, w;
1198  if (disc >= 0) {
1199  real T3 = S + r3, T;
1200  /* Pick the sign on the sqrt to maximize abs(T3). This minimizes loss
1201  * of precision due to cancellation. The result is unchanged because
1202  * of the way the T is used in definition of u. */
1203  T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc); /* T3 = (r * t)^3 */
1204  /* N.B. cbrtx always returns the real root. cbrtx(-8) = -2. */
1205  T = cbrtx(T3); /* T = r * t */
1206  /* T can be zero; but then r2 / T -> 0. */
1207  u += T + (T != 0 ? r2 / T : 0);
1208  } else {
1209  /* T is complex, but the way u is defined the result is real. */
1210  real ang = atan2(sqrt(-disc), -(S + r3));
1211  /* There are three possible cube roots. We choose the root which
1212  * avoids cancellation. Note that disc < 0 implies that r < 0. */
1213  u += 2 * r * cos(ang / 3);
1214  }
1215  v = sqrt(sq(u) + q); /* guaranteed positive */
1216  /* Avoid loss of accuracy when u < 0. */
1217  uv = u < 0 ? q / (v - u) : u + v; /* u+v, guaranteed positive */
1218  w = (uv - q) / (2 * v); /* positive? */
1219  /* Rearrange expression for k to avoid loss of accuracy due to
1220  * subtraction. Division by 0 not possible because uv > 0, w >= 0. */
1221  k = uv / (sqrt(uv + sq(w)) + w); /* guaranteed positive */
1222  } else { /* q == 0 && r <= 0 */
1223  /* y = 0 with |x| <= 1. Handle this case directly.
1224  * for y small, positive root is k = abs(y)/sqrt(1-x^2) */
1225  k = 0;
1226  }
1227  return k;
1228 }
1229 
1230 real InverseStart(const struct geod_geodesic* g,
1231  real sbet1, real cbet1, real dn1,
1232  real sbet2, real cbet2, real dn2,
1233  real lam12, real slam12, real clam12,
1234  real* psalp1, real* pcalp1,
1235  /* Only updated if return val >= 0 */
1236  real* psalp2, real* pcalp2,
1237  /* Only updated for short lines */
1238  real* pdnm,
1239  /* Scratch area of the right size */
1240  real Ca[]) {
1241  real salp1 = 0, calp1 = 0, salp2 = 0, calp2 = 0, dnm = 0;
1242 
1243  /* Return a starting point for Newton's method in salp1 and calp1 (function
1244  * value is -1). If Newton's method doesn't need to be used, return also
1245  * salp2 and calp2 and function value is sig12. */
1246  real
1247  sig12 = -1, /* Return value */
1248  /* bet12 = bet2 - bet1 in [0, pi); bet12a = bet2 + bet1 in (-pi, 0] */
1249  sbet12 = sbet2 * cbet1 - cbet2 * sbet1,
1250  cbet12 = cbet2 * cbet1 + sbet2 * sbet1;
1251  real sbet12a;
1252  boolx shortline = cbet12 >= 0 && sbet12 < (real)(0.5) &&
1253  cbet2 * lam12 < (real)(0.5);
1254  real somg12, comg12, ssig12, csig12;
1255 #if defined(__GNUC__) && __GNUC__ == 4 && \
1256  (__GNUC_MINOR__ < 6 || defined(__MINGW32__))
1257  /* Volatile declaration needed to fix inverse cases
1258  * 88.202499451857 0 -88.202499451857 179.981022032992859592
1259  * 89.262080389218 0 -89.262080389218 179.992207982775375662
1260  * 89.333123580033 0 -89.333123580032997687 179.99295812360148422
1261  * which otherwise fail with g++ 4.4.4 x86 -O3 (Linux)
1262  * and g++ 4.4.0 (mingw) and g++ 4.6.1 (tdm mingw). */
1263  {
1264  volatile real xx1 = sbet2 * cbet1;
1265  volatile real xx2 = cbet2 * sbet1;
1266  sbet12a = xx1 + xx2;
1267  }
1268 #else
1269  sbet12a = sbet2 * cbet1 + cbet2 * sbet1;
1270 #endif
1271  if (shortline) {
1272  real sbetm2 = sq(sbet1 + sbet2), omg12;
1273  /* sin((bet1+bet2)/2)^2
1274  * = (sbet1 + sbet2)^2 / ((sbet1 + sbet2)^2 + (cbet1 + cbet2)^2) */
1275  sbetm2 /= sbetm2 + sq(cbet1 + cbet2);
1276  dnm = sqrt(1 + g->ep2 * sbetm2);
1277  omg12 = lam12 / (g->f1 * dnm);
1278  somg12 = sin(omg12); comg12 = cos(omg12);
1279  } else {
1280  somg12 = slam12; comg12 = clam12;
1281  }
1282 
1283  salp1 = cbet2 * somg12;
1284  calp1 = comg12 >= 0 ?
1285  sbet12 + cbet2 * sbet1 * sq(somg12) / (1 + comg12) :
1286  sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12);
1287 
1288  ssig12 = hypotx(salp1, calp1);
1289  csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12;
1290 
1291  if (shortline && ssig12 < g->etol2) {
1292  /* really short lines */
1293  salp2 = cbet1 * somg12;
1294  calp2 = sbet12 - cbet1 * sbet2 *
1295  (comg12 >= 0 ? sq(somg12) / (1 + comg12) : 1 - comg12);
1296  norm2(&salp2, &calp2);
1297  /* Set return value */
1298  sig12 = atan2(ssig12, csig12);
1299  } else if (fabs(g->n) > (real)(0.1) || /* No astroid calc if too eccentric */
1300  csig12 >= 0 ||
1301  ssig12 >= 6 * fabs(g->n) * pi * sq(cbet1)) {
1302  /* Nothing to do, zeroth order spherical approximation is OK */
1303  } else {
1304  /* Scale lam12 and bet2 to x, y coordinate system where antipodal point
1305  * is at origin and singular point is at y = 0, x = -1. */
1306  real y, lamscale, betscale;
1307  /* Volatile declaration needed to fix inverse case
1308  * 56.320923501171 0 -56.320923501171 179.664747671772880215
1309  * which otherwise fails with g++ 4.4.4 x86 -O3 */
1310  volatile real x;
1311  real lam12x = atan2(-slam12, -clam12); /* lam12 - pi */
1312  if (g->f >= 0) { /* In fact f == 0 does not get here */
1313  /* x = dlong, y = dlat */
1314  {
1315  real
1316  k2 = sq(sbet1) * g->ep2,
1317  eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2);
1318  lamscale = g->f * cbet1 * A3f(g, eps) * pi;
1319  }
1320  betscale = lamscale * cbet1;
1321 
1322  x = lam12x / lamscale;
1323  y = sbet12a / betscale;
1324  } else { /* f < 0 */
1325  /* x = dlat, y = dlong */
1326  real
1327  cbet12a = cbet2 * cbet1 - sbet2 * sbet1,
1328  bet12a = atan2(sbet12a, cbet12a);
1329  real m12b, m0;
1330  /* In the case of lon12 = 180, this repeats a calculation made in
1331  * Inverse. */
1332  Lengths(g, g->n, pi + bet12a,
1333  sbet1, -cbet1, dn1, sbet2, cbet2, dn2,
1334  cbet1, cbet2, 0, &m12b, &m0, 0, 0, Ca);
1335  x = -1 + m12b / (cbet1 * cbet2 * m0 * pi);
1336  betscale = x < -(real)(0.01) ? sbet12a / x :
1337  -g->f * sq(cbet1) * pi;
1338  lamscale = betscale / cbet1;
1339  y = lam12x / lamscale;
1340  }
1341 
1342  if (y > -tol1 && x > -1 - xthresh) {
1343  /* strip near cut */
1344  if (g->f >= 0) {
1345  salp1 = minx((real)(1), -(real)(x)); calp1 = - sqrt(1 - sq(salp1));
1346  } else {
1347  calp1 = maxx((real)(x > -tol1 ? 0 : -1), (real)(x));
1348  salp1 = sqrt(1 - sq(calp1));
1349  }
1350  } else {
1351  /* Estimate alp1, by solving the astroid problem.
1352  *
1353  * Could estimate alpha1 = theta + pi/2, directly, i.e.,
1354  * calp1 = y/k; salp1 = -x/(1+k); for f >= 0
1355  * calp1 = x/(1+k); salp1 = -y/k; for f < 0 (need to check)
1356  *
1357  * However, it's better to estimate omg12 from astroid and use
1358  * spherical formula to compute alp1. This reduces the mean number of
1359  * Newton iterations for astroid cases from 2.24 (min 0, max 6) to 2.12
1360  * (min 0 max 5). The changes in the number of iterations are as
1361  * follows:
1362  *
1363  * change percent
1364  * 1 5
1365  * 0 78
1366  * -1 16
1367  * -2 0.6
1368  * -3 0.04
1369  * -4 0.002
1370  *
1371  * The histogram of iterations is (m = number of iterations estimating
1372  * alp1 directly, n = number of iterations estimating via omg12, total
1373  * number of trials = 148605):
1374  *
1375  * iter m n
1376  * 0 148 186
1377  * 1 13046 13845
1378  * 2 93315 102225
1379  * 3 36189 32341
1380  * 4 5396 7
1381  * 5 455 1
1382  * 6 56 0
1383  *
1384  * Because omg12 is near pi, estimate work with omg12a = pi - omg12 */
1385  real k = Astroid(x, y);
1386  real
1387  omg12a = lamscale * ( g->f >= 0 ? -x * k/(1 + k) : -y * (1 + k)/k );
1388  somg12 = sin(omg12a); comg12 = -cos(omg12a);
1389  /* Update spherical estimate of alp1 using omg12 instead of lam12 */
1390  salp1 = cbet2 * somg12;
1391  calp1 = sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12);
1392  }
1393  }
1394  /* Sanity check on starting guess. Backwards check allows NaN through. */
1395  if (!(salp1 <= 0))
1396  norm2(&salp1, &calp1);
1397  else {
1398  salp1 = 1; calp1 = 0;
1399  }
1400 
1401  *psalp1 = salp1;
1402  *pcalp1 = calp1;
1403  if (shortline)
1404  *pdnm = dnm;
1405  if (sig12 >= 0) {
1406  *psalp2 = salp2;
1407  *pcalp2 = calp2;
1408  }
1409  return sig12;
1410 }
1411 
1412 real Lambda12(const struct geod_geodesic* g,
1413  real sbet1, real cbet1, real dn1,
1414  real sbet2, real cbet2, real dn2,
1415  real salp1, real calp1,
1416  real slam120, real clam120,
1417  real* psalp2, real* pcalp2,
1418  real* psig12,
1419  real* pssig1, real* pcsig1,
1420  real* pssig2, real* pcsig2,
1421  real* peps,
1422  real* pdomg12,
1423  boolx diffp, real* pdlam12,
1424  /* Scratch area of the right size */
1425  real Ca[]) {
1426  real salp2 = 0, calp2 = 0, sig12 = 0,
1427  ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0,
1428  domg12 = 0, dlam12 = 0;
1429  real salp0, calp0;
1430  real somg1, comg1, somg2, comg2, somg12, comg12, lam12;
1431  real B312, eta, k2;
1432 
1433  if (sbet1 == 0 && calp1 == 0)
1434  /* Break degeneracy of equatorial line. This case has already been
1435  * handled. */
1436  calp1 = -tiny;
1437 
1438  /* sin(alp1) * cos(bet1) = sin(alp0) */
1439  salp0 = salp1 * cbet1;
1440  calp0 = hypotx(calp1, salp1 * sbet1); /* calp0 > 0 */
1441 
1442  /* tan(bet1) = tan(sig1) * cos(alp1)
1443  * tan(omg1) = sin(alp0) * tan(sig1) = tan(omg1)=tan(alp1)*sin(bet1) */
1444  ssig1 = sbet1; somg1 = salp0 * sbet1;
1445  csig1 = comg1 = calp1 * cbet1;
1446  norm2(&ssig1, &csig1);
1447  /* norm2(&somg1, &comg1); -- don't need to normalize! */
1448 
1449  /* Enforce symmetries in the case abs(bet2) = -bet1. Need to be careful
1450  * about this case, since this can yield singularities in the Newton
1451  * iteration.
1452  * sin(alp2) * cos(bet2) = sin(alp0) */
1453  salp2 = cbet2 != cbet1 ? salp0 / cbet2 : salp1;
1454  /* calp2 = sqrt(1 - sq(salp2))
1455  * = sqrt(sq(calp0) - sq(sbet2)) / cbet2
1456  * and subst for calp0 and rearrange to give (choose positive sqrt
1457  * to give alp2 in [0, pi/2]). */
1458  calp2 = cbet2 != cbet1 || fabs(sbet2) != -sbet1 ?
1459  sqrt(sq(calp1 * cbet1) +
1460  (cbet1 < -sbet1 ?
1461  (cbet2 - cbet1) * (cbet1 + cbet2) :
1462  (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 :
1463  fabs(calp1);
1464  /* tan(bet2) = tan(sig2) * cos(alp2)
1465  * tan(omg2) = sin(alp0) * tan(sig2). */
1466  ssig2 = sbet2; somg2 = salp0 * sbet2;
1467  csig2 = comg2 = calp2 * cbet2;
1468  norm2(&ssig2, &csig2);
1469  /* norm2(&somg2, &comg2); -- don't need to normalize! */
1470 
1471  /* sig12 = sig2 - sig1, limit to [0, pi] */
1472  sig12 = atan2(maxx((real)(0), csig1 * ssig2 - ssig1 * csig2),
1473  csig1 * csig2 + ssig1 * ssig2);
1474 
1475  /* omg12 = omg2 - omg1, limit to [0, pi] */
1476  somg12 = maxx((real)(0), comg1 * somg2 - somg1 * comg2);
1477  comg12 = comg1 * comg2 + somg1 * somg2;
1478  /* eta = omg12 - lam120 */
1479  eta = atan2(somg12 * clam120 - comg12 * slam120,
1480  comg12 * clam120 + somg12 * slam120);
1481  k2 = sq(calp0) * g->ep2;
1482  eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2);
1483  C3f(g, eps, Ca);
1484  B312 = (SinCosSeries(TRUE, ssig2, csig2, Ca, nC3-1) -
1485  SinCosSeries(TRUE, ssig1, csig1, Ca, nC3-1));
1486  domg12 = -g->f * A3f(g, eps) * salp0 * (sig12 + B312);
1487  lam12 = eta + domg12;
1488 
1489  if (diffp) {
1490  if (calp2 == 0)
1491  dlam12 = - 2 * g->f1 * dn1 / sbet1;
1492  else {
1493  Lengths(g, eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,
1494  cbet1, cbet2, 0, &dlam12, 0, 0, 0, Ca);
1495  dlam12 *= g->f1 / (calp2 * cbet2);
1496  }
1497  }
1498 
1499  *psalp2 = salp2;
1500  *pcalp2 = calp2;
1501  *psig12 = sig12;
1502  *pssig1 = ssig1;
1503  *pcsig1 = csig1;
1504  *pssig2 = ssig2;
1505  *pcsig2 = csig2;
1506  *peps = eps;
1507  *pdomg12 = domg12;
1508  if (diffp)
1509  *pdlam12 = dlam12;
1510 
1511  return lam12;
1512 }
1513 
1514 real A3f(const struct geod_geodesic* g, real eps) {
1515  /* Evaluate A3 */
1516  return polyval(nA3 - 1, g->A3x, eps);
1517 }
1518 
1519 void C3f(const struct geod_geodesic* g, real eps, real c[]) {
1520  /* Evaluate C3 coeffs
1521  * Elements c[1] through c[nC3 - 1] are set */
1522  real mult = 1;
1523  int o = 0, l;
1524  for (l = 1; l < nC3; ++l) { /* l is index of C3[l] */
1525  int m = nC3 - l - 1; /* order of polynomial in eps */
1526  mult *= eps;
1527  c[l] = mult * polyval(m, g->C3x + o, eps);
1528  o += m + 1;
1529  }
1530 }
1531 
1532 void C4f(const struct geod_geodesic* g, real eps, real c[]) {
1533  /* Evaluate C4 coeffs
1534  * Elements c[0] through c[nC4 - 1] are set */
1535  real mult = 1;
1536  int o = 0, l;
1537  for (l = 0; l < nC4; ++l) { /* l is index of C4[l] */
1538  int m = nC4 - l - 1; /* order of polynomial in eps */
1539  c[l] = mult * polyval(m, g->C4x + o, eps);
1540  o += m + 1;
1541  mult *= eps;
1542  }
1543 }
1544 
1545 /* The scale factor A1-1 = mean value of (d/dsigma)I1 - 1 */
1546 real A1m1f(real eps) {
1547  static const real coeff[] = {
1548  /* (1-eps)*A1-1, polynomial in eps2 of order 3 */
1549  1, 4, 64, 0, 256,
1550  };
1551  int m = nA1/2;
1552  real t = polyval(m, coeff, sq(eps)) / coeff[m + 1];
1553  return (t + eps) / (1 - eps);
1554 }
1555 
1556 /* The coefficients C1[l] in the Fourier expansion of B1 */
1557 void C1f(real eps, real c[]) {
1558  static const real coeff[] = {
1559  /* C1[1]/eps^1, polynomial in eps2 of order 2 */
1560  -1, 6, -16, 32,
1561  /* C1[2]/eps^2, polynomial in eps2 of order 2 */
1562  -9, 64, -128, 2048,
1563  /* C1[3]/eps^3, polynomial in eps2 of order 1 */
1564  9, -16, 768,
1565  /* C1[4]/eps^4, polynomial in eps2 of order 1 */
1566  3, -5, 512,
1567  /* C1[5]/eps^5, polynomial in eps2 of order 0 */
1568  -7, 1280,
1569  /* C1[6]/eps^6, polynomial in eps2 of order 0 */
1570  -7, 2048,
1571  };
1572  real
1573  eps2 = sq(eps),
1574  d = eps;
1575  int o = 0, l;
1576  for (l = 1; l <= nC1; ++l) { /* l is index of C1p[l] */
1577  int m = (nC1 - l) / 2; /* order of polynomial in eps^2 */
1578  c[l] = d * polyval(m, coeff + o, eps2) / coeff[o + m + 1];
1579  o += m + 2;
1580  d *= eps;
1581  }
1582 }
1583 
1584 /* The coefficients C1p[l] in the Fourier expansion of B1p */
1585 void C1pf(real eps, real c[]) {
1586  static const real coeff[] = {
1587  /* C1p[1]/eps^1, polynomial in eps2 of order 2 */
1588  205, -432, 768, 1536,
1589  /* C1p[2]/eps^2, polynomial in eps2 of order 2 */
1590  4005, -4736, 3840, 12288,
1591  /* C1p[3]/eps^3, polynomial in eps2 of order 1 */
1592  -225, 116, 384,
1593  /* C1p[4]/eps^4, polynomial in eps2 of order 1 */
1594  -7173, 2695, 7680,
1595  /* C1p[5]/eps^5, polynomial in eps2 of order 0 */
1596  3467, 7680,
1597  /* C1p[6]/eps^6, polynomial in eps2 of order 0 */
1598  38081, 61440,
1599  };
1600  real
1601  eps2 = sq(eps),
1602  d = eps;
1603  int o = 0, l;
1604  for (l = 1; l <= nC1p; ++l) { /* l is index of C1p[l] */
1605  int m = (nC1p - l) / 2; /* order of polynomial in eps^2 */
1606  c[l] = d * polyval(m, coeff + o, eps2) / coeff[o + m + 1];
1607  o += m + 2;
1608  d *= eps;
1609  }
1610 }
1611 
1612 /* The scale factor A2-1 = mean value of (d/dsigma)I2 - 1 */
1613 real A2m1f(real eps) {
1614  static const real coeff[] = {
1615  /* (eps+1)*A2-1, polynomial in eps2 of order 3 */
1616  -11, -28, -192, 0, 256,
1617  };
1618  int m = nA2/2;
1619  real t = polyval(m, coeff, sq(eps)) / coeff[m + 1];
1620  return (t - eps) / (1 + eps);
1621 }
1622 
1623 /* The coefficients C2[l] in the Fourier expansion of B2 */
1624 void C2f(real eps, real c[]) {
1625  static const real coeff[] = {
1626  /* C2[1]/eps^1, polynomial in eps2 of order 2 */
1627  1, 2, 16, 32,
1628  /* C2[2]/eps^2, polynomial in eps2 of order 2 */
1629  35, 64, 384, 2048,
1630  /* C2[3]/eps^3, polynomial in eps2 of order 1 */
1631  15, 80, 768,
1632  /* C2[4]/eps^4, polynomial in eps2 of order 1 */
1633  7, 35, 512,
1634  /* C2[5]/eps^5, polynomial in eps2 of order 0 */
1635  63, 1280,
1636  /* C2[6]/eps^6, polynomial in eps2 of order 0 */
1637  77, 2048,
1638  };
1639  real
1640  eps2 = sq(eps),
1641  d = eps;
1642  int o = 0, l;
1643  for (l = 1; l <= nC2; ++l) { /* l is index of C2[l] */
1644  int m = (nC2 - l) / 2; /* order of polynomial in eps^2 */
1645  c[l] = d * polyval(m, coeff + o, eps2) / coeff[o + m + 1];
1646  o += m + 2;
1647  d *= eps;
1648  }
1649 }
1650 
1651 /* The scale factor A3 = mean value of (d/dsigma)I3 */
1652 void A3coeff(struct geod_geodesic* g) {
1653  static const real coeff[] = {
1654  /* A3, coeff of eps^5, polynomial in n of order 0 */
1655  -3, 128,
1656  /* A3, coeff of eps^4, polynomial in n of order 1 */
1657  -2, -3, 64,
1658  /* A3, coeff of eps^3, polynomial in n of order 2 */
1659  -1, -3, -1, 16,
1660  /* A3, coeff of eps^2, polynomial in n of order 2 */
1661  3, -1, -2, 8,
1662  /* A3, coeff of eps^1, polynomial in n of order 1 */
1663  1, -1, 2,
1664  /* A3, coeff of eps^0, polynomial in n of order 0 */
1665  1, 1,
1666  };
1667  int o = 0, k = 0, j;
1668  for (j = nA3 - 1; j >= 0; --j) { /* coeff of eps^j */
1669  int m = nA3 - j - 1 < j ? nA3 - j - 1 : j; /* order of polynomial in n */
1670  g->A3x[k++] = polyval(m, coeff + o, g->n) / coeff[o + m + 1];
1671  o += m + 2;
1672  }
1673 }
1674 
1675 /* The coefficients C3[l] in the Fourier expansion of B3 */
1676 void C3coeff(struct geod_geodesic* g) {
1677  static const real coeff[] = {
1678  /* C3[1], coeff of eps^5, polynomial in n of order 0 */
1679  3, 128,
1680  /* C3[1], coeff of eps^4, polynomial in n of order 1 */
1681  2, 5, 128,
1682  /* C3[1], coeff of eps^3, polynomial in n of order 2 */
1683  -1, 3, 3, 64,
1684  /* C3[1], coeff of eps^2, polynomial in n of order 2 */
1685  -1, 0, 1, 8,
1686  /* C3[1], coeff of eps^1, polynomial in n of order 1 */
1687  -1, 1, 4,
1688  /* C3[2], coeff of eps^5, polynomial in n of order 0 */
1689  5, 256,
1690  /* C3[2], coeff of eps^4, polynomial in n of order 1 */
1691  1, 3, 128,
1692  /* C3[2], coeff of eps^3, polynomial in n of order 2 */
1693  -3, -2, 3, 64,
1694  /* C3[2], coeff of eps^2, polynomial in n of order 2 */
1695  1, -3, 2, 32,
1696  /* C3[3], coeff of eps^5, polynomial in n of order 0 */
1697  7, 512,
1698  /* C3[3], coeff of eps^4, polynomial in n of order 1 */
1699  -10, 9, 384,
1700  /* C3[3], coeff of eps^3, polynomial in n of order 2 */
1701  5, -9, 5, 192,
1702  /* C3[4], coeff of eps^5, polynomial in n of order 0 */
1703  7, 512,
1704  /* C3[4], coeff of eps^4, polynomial in n of order 1 */
1705  -14, 7, 512,
1706  /* C3[5], coeff of eps^5, polynomial in n of order 0 */
1707  21, 2560,
1708  };
1709  int o = 0, k = 0, l, j;
1710  for (l = 1; l < nC3; ++l) { /* l is index of C3[l] */
1711  for (j = nC3 - 1; j >= l; --j) { /* coeff of eps^j */
1712  int m = nC3 - j - 1 < j ? nC3 - j - 1 : j; /* order of polynomial in n */
1713  g->C3x[k++] = polyval(m, coeff + o, g->n) / coeff[o + m + 1];
1714  o += m + 2;
1715  }
1716  }
1717 }
1718 
1719 /* The coefficients C4[l] in the Fourier expansion of I4 */
1720 void C4coeff(struct geod_geodesic* g) {
1721  static const real coeff[] = {
1722  /* C4[0], coeff of eps^5, polynomial in n of order 0 */
1723  97, 15015,
1724  /* C4[0], coeff of eps^4, polynomial in n of order 1 */
1725  1088, 156, 45045,
1726  /* C4[0], coeff of eps^3, polynomial in n of order 2 */
1727  -224, -4784, 1573, 45045,
1728  /* C4[0], coeff of eps^2, polynomial in n of order 3 */
1729  -10656, 14144, -4576, -858, 45045,
1730  /* C4[0], coeff of eps^1, polynomial in n of order 4 */
1731  64, 624, -4576, 6864, -3003, 15015,
1732  /* C4[0], coeff of eps^0, polynomial in n of order 5 */
1733  100, 208, 572, 3432, -12012, 30030, 45045,
1734  /* C4[1], coeff of eps^5, polynomial in n of order 0 */
1735  1, 9009,
1736  /* C4[1], coeff of eps^4, polynomial in n of order 1 */
1737  -2944, 468, 135135,
1738  /* C4[1], coeff of eps^3, polynomial in n of order 2 */
1739  5792, 1040, -1287, 135135,
1740  /* C4[1], coeff of eps^2, polynomial in n of order 3 */
1741  5952, -11648, 9152, -2574, 135135,
1742  /* C4[1], coeff of eps^1, polynomial in n of order 4 */
1743  -64, -624, 4576, -6864, 3003, 135135,
1744  /* C4[2], coeff of eps^5, polynomial in n of order 0 */
1745  8, 10725,
1746  /* C4[2], coeff of eps^4, polynomial in n of order 1 */
1747  1856, -936, 225225,
1748  /* C4[2], coeff of eps^3, polynomial in n of order 2 */
1749  -8448, 4992, -1144, 225225,
1750  /* C4[2], coeff of eps^2, polynomial in n of order 3 */
1751  -1440, 4160, -4576, 1716, 225225,
1752  /* C4[3], coeff of eps^5, polynomial in n of order 0 */
1753  -136, 63063,
1754  /* C4[3], coeff of eps^4, polynomial in n of order 1 */
1755  1024, -208, 105105,
1756  /* C4[3], coeff of eps^3, polynomial in n of order 2 */
1757  3584, -3328, 1144, 315315,
1758  /* C4[4], coeff of eps^5, polynomial in n of order 0 */
1759  -128, 135135,
1760  /* C4[4], coeff of eps^4, polynomial in n of order 1 */
1761  -2560, 832, 405405,
1762  /* C4[5], coeff of eps^5, polynomial in n of order 0 */
1763  128, 99099,
1764  };
1765  int o = 0, k = 0, l, j;
1766  for (l = 0; l < nC4; ++l) { /* l is index of C4[l] */
1767  for (j = nC4 - 1; j >= l; --j) { /* coeff of eps^j */
1768  int m = nC4 - j - 1; /* order of polynomial in n */
1769  g->C4x[k++] = polyval(m, coeff + o, g->n) / coeff[o + m + 1];
1770  o += m + 2;
1771  }
1772  }
1773 }
1774 
1775 int transit(real lon1, real lon2) {
1776  real lon12;
1777  /* Return 1 or -1 if crossing prime meridian in east or west direction.
1778  * Otherwise return zero. */
1779  /* Compute lon12 the same way as Geodesic::Inverse. */
1780  lon1 = AngNormalize(lon1);
1781  lon2 = AngNormalize(lon2);
1782  lon12 = AngDiff(lon1, lon2, 0);
1783  return lon1 <= 0 && lon2 > 0 && lon12 > 0 ? 1 :
1784  (lon2 <= 0 && lon1 > 0 && lon12 < 0 ? -1 : 0);
1785 }
1786 
1787 int transitdirect(real lon1, real lon2) {
1788 #if HAVE_C99_MATH
1789  lon1 = remainder(lon1, (real)(720));
1790  lon2 = remainder(lon2, (real)(720));
1791  return ( (lon2 >= 0 && lon2 < 360 ? 0 : 1) -
1792  (lon1 >= 0 && lon1 < 360 ? 0 : 1) );
1793 #else
1794  lon1 = fmod(lon1, (real)(720));
1795  lon2 = fmod(lon2, (real)(720));
1796  return ( ((lon2 >= 0 && lon2 < 360) || lon2 < -360 ? 0 : 1) -
1797  ((lon1 >= 0 && lon1 < 360) || lon1 < -360 ? 0 : 1) );
1798 #endif
1799 }
1800 
1801 void accini(real s[]) {
1802  /* Initialize an accumulator; this is an array with two elements. */
1803  s[0] = s[1] = 0;
1804 }
1805 
1806 void acccopy(const real s[], real t[]) {
1807  /* Copy an accumulator; t = s. */
1808  t[0] = s[0]; t[1] = s[1];
1809 }
1810 
1811 void accadd(real s[], real y) {
1812  /* Add y to an accumulator. */
1813  real u, z = sumx(y, s[1], &u);
1814  s[0] = sumx(z, s[0], &s[1]);
1815  if (s[0] == 0)
1816  s[0] = u;
1817  else
1818  s[1] = s[1] + u;
1819 }
1820 
1821 real accsum(const real s[], real y) {
1822  /* Return accumulator + y (but don't add to accumulator). */
1823  real t[2];
1824  acccopy(s, t);
1825  accadd(t, y);
1826  return t[0];
1827 }
1828 
1829 void accneg(real s[]) {
1830  /* Negate an accumulator. */
1831  s[0] = -s[0]; s[1] = -s[1];
1832 }
1833 
1834 void geod_polygon_init(struct geod_polygon* p, boolx polylinep) {
1835  p->polyline = (polylinep != 0);
1837 }
1838 
1839 void geod_polygon_clear(struct geod_polygon* p) {
1840  p->lat0 = p->lon0 = p->lat = p->lon = NaN;
1841  accini(p->P);
1842  accini(p->A);
1843  p->num = p->crossings = 0;
1844 }
1845 
1846 void geod_polygon_addpoint(const struct geod_geodesic* g,
1847  struct geod_polygon* p,
1848  real lat, real lon) {
1849  lon = AngNormalize(lon);
1850  if (p->num == 0) {
1851  p->lat0 = p->lat = lat;
1852  p->lon0 = p->lon = lon;
1853  } else {
1854  real s12, S12 = 0; /* Initialize S12 to stop Visual Studio warning */
1855  geod_geninverse(g, p->lat, p->lon, lat, lon,
1856  &s12, 0, 0, 0, 0, 0, p->polyline ? 0 : &S12);
1857  accadd(p->P, s12);
1858  if (!p->polyline) {
1859  accadd(p->A, S12);
1860  p->crossings += transit(p->lon, lon);
1861  }
1862  p->lat = lat; p->lon = lon;
1863  }
1864  ++p->num;
1865 }
1866 
1867 void geod_polygon_addedge(const struct geod_geodesic* g,
1868  struct geod_polygon* p,
1869  real azi, real s) {
1870  if (p->num) { /* Do nothing is num is zero */
1871  real lat, lon, S12 = 0; /* Initialize S12 to stop Visual Studio warning */
1872  geod_gendirect(g, p->lat, p->lon, azi, GEOD_LONG_UNROLL, s,
1873  &lat, &lon, 0,
1874  0, 0, 0, 0, p->polyline ? 0 : &S12);
1875  accadd(p->P, s);
1876  if (!p->polyline) {
1877  accadd(p->A, S12);
1878  p->crossings += transitdirect(p->lon, lon);
1879  }
1880  p->lat = lat; p->lon = lon;
1881  ++p->num;
1882  }
1883 }
1884 
1885 unsigned geod_polygon_compute(const struct geod_geodesic* g,
1886  const struct geod_polygon* p,
1887  boolx reverse, boolx sign,
1888  real* pA, real* pP) {
1889  real s12, S12, t[2], area0;
1890  int crossings;
1891  if (p->num < 2) {
1892  if (pP) *pP = 0;
1893  if (!p->polyline && pA) *pA = 0;
1894  return p->num;
1895  }
1896  if (p->polyline) {
1897  if (pP) *pP = p->P[0];
1898  return p->num;
1899  }
1900  geod_geninverse(g, p->lat, p->lon, p->lat0, p->lon0,
1901  &s12, 0, 0, 0, 0, 0, &S12);
1902  if (pP) *pP = accsum(p->P, s12);
1903  acccopy(p->A, t);
1904  accadd(t, S12);
1905  crossings = p->crossings + transit(p->lon, p->lon0);
1906  area0 = 4 * pi * g->c2;
1907  if (crossings & 1)
1908  accadd(t, (t[0] < 0 ? 1 : -1) * area0/2);
1909  /* area is with the clockwise sense. If !reverse convert to
1910  * counter-clockwise convention. */
1911  if (!reverse)
1912  accneg(t);
1913  /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
1914  if (sign) {
1915  if (t[0] > area0/2)
1916  accadd(t, -area0);
1917  else if (t[0] <= -area0/2)
1918  accadd(t, +area0);
1919  } else {
1920  if (t[0] >= area0)
1921  accadd(t, -area0);
1922  else if (t[0] < 0)
1923  accadd(t, +area0);
1924  }
1925  if (pA) *pA = 0 + t[0];
1926  return p->num;
1927 }
1928 
1929 unsigned geod_polygon_testpoint(const struct geod_geodesic* g,
1930  const struct geod_polygon* p,
1931  real lat, real lon,
1932  boolx reverse, boolx sign,
1933  real* pA, real* pP) {
1934  real perimeter, tempsum, area0;
1935  int crossings, i;
1936  unsigned num = p->num + 1;
1937  if (num == 1) {
1938  if (pP) *pP = 0;
1939  if (!p->polyline && pA) *pA = 0;
1940  return num;
1941  }
1942  perimeter = p->P[0];
1943  tempsum = p->polyline ? 0 : p->A[0];
1944  crossings = p->crossings;
1945  for (i = 0; i < (p->polyline ? 1 : 2); ++i) {
1946  real s12, S12 = 0; /* Initialize S12 to stop Visual Studio warning */
1948  i == 0 ? p->lat : lat, i == 0 ? p->lon : lon,
1949  i != 0 ? p->lat0 : lat, i != 0 ? p->lon0 : lon,
1950  &s12, 0, 0, 0, 0, 0, p->polyline ? 0 : &S12);
1951  perimeter += s12;
1952  if (!p->polyline) {
1953  tempsum += S12;
1954  crossings += transit(i == 0 ? p->lon : lon,
1955  i != 0 ? p->lon0 : lon);
1956  }
1957  }
1958 
1959  if (pP) *pP = perimeter;
1960  if (p->polyline)
1961  return num;
1962 
1963  area0 = 4 * pi * g->c2;
1964  if (crossings & 1)
1965  tempsum += (tempsum < 0 ? 1 : -1) * area0/2;
1966  /* area is with the clockwise sense. If !reverse convert to
1967  * counter-clockwise convention. */
1968  if (!reverse)
1969  tempsum *= -1;
1970  /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
1971  if (sign) {
1972  if (tempsum > area0/2)
1973  tempsum -= area0;
1974  else if (tempsum <= -area0/2)
1975  tempsum += area0;
1976  } else {
1977  if (tempsum >= area0)
1978  tempsum -= area0;
1979  else if (tempsum < 0)
1980  tempsum += area0;
1981  }
1982  if (pA) *pA = 0 + tempsum;
1983  return num;
1984 }
1985 
1986 unsigned geod_polygon_testedge(const struct geod_geodesic* g,
1987  const struct geod_polygon* p,
1988  real azi, real s,
1989  boolx reverse, boolx sign,
1990  real* pA, real* pP) {
1991  real perimeter, tempsum, area0;
1992  int crossings;
1993  unsigned num = p->num + 1;
1994  if (num == 1) { /* we don't have a starting point! */
1995  if (pP) *pP = NaN;
1996  if (!p->polyline && pA) *pA = NaN;
1997  return 0;
1998  }
1999  perimeter = p->P[0] + s;
2000  if (p->polyline) {
2001  if (pP) *pP = perimeter;
2002  return num;
2003  }
2004 
2005  tempsum = p->A[0];
2006  crossings = p->crossings;
2007  {
2008  real lat, lon, s12, S12;
2009  geod_gendirect(g, p->lat, p->lon, azi, GEOD_LONG_UNROLL, s,
2010  &lat, &lon, 0,
2011  0, 0, 0, 0, &S12);
2012  tempsum += S12;
2013  crossings += transitdirect(p->lon, lon);
2014  geod_geninverse(g, lat, lon, p->lat0, p->lon0,
2015  &s12, 0, 0, 0, 0, 0, &S12);
2016  perimeter += s12;
2017  tempsum += S12;
2018  crossings += transit(lon, p->lon0);
2019  }
2020 
2021  area0 = 4 * pi * g->c2;
2022  if (crossings & 1)
2023  tempsum += (tempsum < 0 ? 1 : -1) * area0/2;
2024  /* area is with the clockwise sense. If !reverse convert to
2025  * counter-clockwise convention. */
2026  if (!reverse)
2027  tempsum *= -1;
2028  /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
2029  if (sign) {
2030  if (tempsum > area0/2)
2031  tempsum -= area0;
2032  else if (tempsum <= -area0/2)
2033  tempsum += area0;
2034  } else {
2035  if (tempsum >= area0)
2036  tempsum -= area0;
2037  else if (tempsum < 0)
2038  tempsum += area0;
2039  }
2040  if (pP) *pP = perimeter;
2041  if (pA) *pA = 0 + tempsum;
2042  return num;
2043 }
2044 
2045 void geod_polygonarea(const struct geod_geodesic* g,
2046  real lats[], real lons[], int n,
2047  real* pA, real* pP) {
2048  int i;
2049  struct geod_polygon p;
2051  for (i = 0; i < n; ++i)
2052  geod_polygon_addpoint(g, &p, lats[i], lons[i]);
2053  geod_polygon_compute(g, &p, FALSE, TRUE, pA, pP);
2054 }
2055 
w
RowVector3d w
Definition: Matrix_resize_int.cpp:3
gtsam.examples.DogLegOptimizerExample.int
int
Definition: DogLegOptimizerExample.py:111
NETGeographicLib::captype::CAP_C2
@ CAP_C2
geod_inverseline
void geod_inverseline(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double lat2, double lon2, unsigned caps)
geod_polygon_compute
unsigned geod_polygon_compute(const struct geod_geodesic *g, const struct geod_polygon *p, int reverse, int sign, double *pA, double *pP)
s
RealScalar s
Definition: level1_cplx_impl.h:126
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
atan
const EIGEN_DEVICE_FUNC AtanReturnType atan() const
Definition: ArrayCwiseUnaryOps.h:283
d
static const double d[K][N]
Definition: igam.h:11
geod_direct
void geod_direct(const struct geod_geodesic *g, double lat1, double lon1, double azi1, double s12, double *plat2, double *plon2, double *pazi2)
ceres::sin
Jet< T, N > sin(const Jet< T, N > &f)
Definition: jet.h:439
r2
static const double r2
Definition: testSmartRangeFactor.cpp:32
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
b
Scalar * b
Definition: benchVecAdd.cpp:17
GEOD_GEODESICSCALE
@ GEOD_GEODESICSCALE
Definition: geodesic.h:891
example1::pA
Point2 pA(size_t i)
Definition: testEssentialMatrixFactor.cpp:49
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
GEOD_LONG_UNROLL
@ GEOD_LONG_UNROLL
Definition: geodesic.h:903
sign
const EIGEN_DEVICE_FUNC SignReturnType sign() const
Definition: ArrayCwiseUnaryOps.h:219
T3
static const Pose3 T3(Rot3::Rodrigues(-90, 0, 0), Point3(1, 2, 3))
real
float real
Definition: datatypes.h:10
T
Eigen::Triplet< double > T
Definition: Tutorial_sparse_example.cpp:6
geodesic.h
API for the geodesic routines in C.
geod_polygon_testpoint
unsigned geod_polygon_testpoint(const struct geod_geodesic *g, const struct geod_polygon *p, double lat, double lon, int reverse, int sign, double *pA, double *pP)
log
const EIGEN_DEVICE_FUNC LogReturnType log() const
Definition: ArrayCwiseUnaryOps.h:128
NETGeographicLib::captype::CAP_C1p
@ CAP_C1p
GEOD_DISTANCE
@ GEOD_DISTANCE
Definition: geodesic.h:888
NETGeographicLib::captype::CAP_C1
@ CAP_C1
GEOD_ARCMODE
@ GEOD_ARCMODE
Definition: geodesic.h:902
geod_geodesicline::lon1
double lon1
Definition: geodesic.h:184
GEOD_REDUCEDLENGTH
@ GEOD_REDUCEDLENGTH
Definition: geodesic.h:890
y0
double y0(double x)
Definition: j0.c:220
geod_polygon_addedge
void geod_polygon_addedge(const struct geod_geodesic *g, struct geod_polygon *p, double azi, double s)
ceres::cos
Jet< T, N > cos(const Jet< T, N > &f)
Definition: jet.h:426
boost::multiprecision::fabs
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:119
geod_geodesic
Definition: geodesic.h:168
n
int n
Definition: BiCGSTAB_simple.cpp:1
epsilon
static double epsilon
Definition: testRot3.cpp:37
geod_lineinit
void geod_lineinit(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double azi1, unsigned caps)
geod_init
void geod_init(struct geod_geodesic *g, double a, double f)
NETGeographicLib::captype::OUT_ALL
@ OUT_ALL
geod_setdistance
void geod_setdistance(struct geod_geodesicline *l, double s13)
y1
double y1(double x)
Definition: j1.c:199
NETGeographicLib::captype::CAP_C4
@ CAP_C4
Eigen::bfloat16_impl::fmod
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 fmod(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:567
NETGeographicLib::captype
captype
Definition: NETGeographicLib.h:18
geod_position
void geod_position(const struct geod_geodesicline *l, double s12, double *plat2, double *plon2, double *pazi2)
j
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2
GEOD_DISTANCE_IN
@ GEOD_DISTANCE_IN
Definition: geodesic.h:889
geod_geodesicline
Definition: geodesic.h:182
Eigen::numext::q
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:1984
geod_geninverse
double geod_geninverse(const struct geod_geodesic *g, double lat1, double lon1, double lat2, double lon2, double *ps12, double *pazi1, double *pazi2, double *pm12, double *pM12, double *pM21, double *pS12)
geod_polygon_clear
void geod_polygon_clear(struct geod_polygon *p)
geod_polygon_addpoint
void geod_polygon_addpoint(const struct geod_geodesic *g, struct geod_polygon *p, double lat, double lon)
l
static const Line3 l(Rot3(), 1, 1)
A2
static const double A2[]
Definition: expn.h:7
degree
const double degree
Definition: SimpleRotation.cpp:59
r3
static const double r3
Definition: testSmartRangeFactor.cpp:32
geod_gensetdistance
void geod_gensetdistance(struct geod_geodesicline *l, unsigned flags, double s13_a13)
pybind_wrapper_test_script.z
z
Definition: pybind_wrapper_test_script.py:61
m
Matrix3f m
Definition: AngleAxis_mimic_euler.cpp:1
Eigen::Triplet
A small structure to hold a non zero as a triplet (i,j,value).
Definition: SparseUtil.h:162
GEOD_NONE
@ GEOD_NONE
Definition: geodesic.h:884
g
void g(const string &key, int i)
Definition: testBTree.cpp:41
GEOD_AREA
@ GEOD_AREA
Definition: geodesic.h:892
y
Scalar * y
Definition: level1_cplx_impl.h:124
atan2
AnnoyingScalar atan2(const AnnoyingScalar &y, const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:110
GEOD_NOFLAGS
@ GEOD_NOFLAGS
Definition: geodesic.h:901
E
DiscreteKey E(5, 2)
tree::f
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Definition: testExpression.cpp:218
geod_polygon_testedge
unsigned geod_polygon_testedge(const struct geod_geodesic *g, const struct geod_polygon *p, double azi, double s, int reverse, int sign, double *pA, double *pP)
geod_directline
void geod_directline(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double azi1, double s12, unsigned caps)
geod_genposition
double geod_genposition(const struct geod_geodesicline *l, unsigned flags, double s12_a12, double *plat2, double *plon2, double *pazi2, double *ps12, double *pm12, double *pM12, double *pM21, double *pS12)
Eigen::ArrayBase::pow
const Eigen::CwiseBinaryOp< Eigen::internal::scalar_pow_op< typename Derived::Scalar, typename ExponentDerived::Scalar >, const Derived, const ExponentDerived > pow(const Eigen::ArrayBase< Derived > &x, const Eigen::ArrayBase< ExponentDerived > &exponents)
Definition: GlobalFunctions.h:143
a
ArrayXXi a
Definition: Array_initializer_list_23_cxx11.cpp:1
NETGeographicLib::captype::CAP_C3
@ CAP_C3
NETGeographicLib::captype::CAP_ALL
@ CAP_ALL
geod_gendirectline
void geod_gendirectline(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double azi1, unsigned flags, double s12_a12, unsigned caps)
geod_inverse
void geod_inverse(const struct geod_geodesic *g, double lat1, double lon1, double lat2, double lon2, double *ps12, double *pazi1, double *pazi2)
geod_polygon_init
void geod_polygon_init(struct geod_polygon *p, int polylinep)
geod_polygonarea
void geod_polygonarea(const struct geod_geodesic *g, double lats[], double lons[], int n, double *pA, double *pP)
p
float * p
Definition: Tutorial_Map_using.cpp:9
A1
static const double A1[]
Definition: expn.h:6
NETGeographicLib::captype::CAP_NONE
@ CAP_NONE
v
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
geod_gendirect
double geod_gendirect(const struct geod_geodesic *g, double lat1, double lon1, double azi1, unsigned flags, double s12_a12, double *plat2, double *plon2, double *pazi2, double *ps12, double *pm12, double *pM12, double *pM21, double *pS12)
U
@ U
Definition: testDecisionTree.cpp:296
N
#define N
Definition: igam.h:9
reverse
void reverse(const MatrixType &m)
Definition: array_reverse.cpp:16
lon
static const double lon
Definition: testGeographicLib.cpp:34
geod_geodesicline::salp1
double salp1
Definition: geodesic.h:188
geod_polygon
Definition: geodesic.h:206
M_PI
#define M_PI
Definition: mconf.h:117
GEOD_LONGITUDE
@ GEOD_LONGITUDE
Definition: geodesic.h:886
A4
static const double A4[]
Definition: expn.h:9
align_3::t
Point2 t(10, 10)
gtsam::norm2
double norm2(const Point2 &p, OptionalJacobian< 1, 2 > H)
Distance of the point from the origin, with Jacobian.
Definition: Point2.cpp:27
geod_geodesicline::azi1
double azi1
Definition: geodesic.h:185
geod_geodesicline::caps
unsigned caps
Definition: geodesic.h:198
init
Definition: TutorialInplaceLU.cpp:2
geod_geodesicline::lat1
double lat1
Definition: geodesic.h:183
TRUE
#define TRUE
Definition: ccolamd.c:750
geod_geodesicline::calp1
double calp1
Definition: geodesic.h:189
FALSE
#define FALSE
Definition: ccolamd.c:751
real
Definition: main.h:100
ceres::sqrt
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:418
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
GEOD_AZIMUTH
@ GEOD_AZIMUTH
Definition: geodesic.h:887
S
DiscreteKey S(1, 2)
floor
const EIGEN_DEVICE_FUNC FloorReturnType floor() const
Definition: ArrayCwiseUnaryOps.h:481
GEOD_LATITUDE
@ GEOD_LATITUDE
Definition: geodesic.h:885
lat
static const double lat
Definition: testGeographicLib.cpp:34


gtsam
Author(s):
autogenerated on Mon Jul 1 2024 03:01:20