Coverage Report

Created: 2025-10-10 06:31

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