geodesic_wgs84 1.44.1 → 1.46.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c45c045313d94c86f6486192b2ab4e721e9651ca
4
- data.tar.gz: 8b4b139acfe9387ad9ffecfe77ee29d849564ba8
3
+ metadata.gz: 139b783b65ccd28ad8fac5977f7700467760a4a4
4
+ data.tar.gz: 969289b3a018caba12c6c41c6ed891adefc138d4
5
5
  SHA512:
6
- metadata.gz: b623d79f1ac14608b19dfe37d07ec05889e3f6e0d4fa50b5290ca38b0fbd640cb82a204473232e3e14be165c0b63bbba18f5fbb054ddf502911758ef8114fc0b
7
- data.tar.gz: b57d30db4536ad153f163b0ff13286ff55e4e30244f23195bb84ffa357f8fd5b19b8bb10994bb40baa041669c2ef4ec63204af57f9d5c115bc7c6483ab3fcb71
6
+ metadata.gz: 381b3d21873d5d2d39b800deca4dc19cb7e70b187eb261cce8e8238b71184565ac38fd07b8471b0f8d9dc7606393a8b17e4d89fd019b9450cbc9fe39443c4864
7
+ data.tar.gz: 59ee2f60234c64b0098f24df557410e566b4350aced63b258a8113ee56d7392eb072593e98929d060faa42e48c899f3d42ad0558d9c096e77d55d73e1ea27410
@@ -14,11 +14,11 @@
14
14
  * Algorithms for geodesics,
15
15
  * J. Geodesy <b>87</b>, 43--55 (2013);
16
16
  * https://dx.doi.org/10.1007/s00190-012-0578-z
17
- * Addenda: http://geographiclib.sf.net/geod-addenda.html
17
+ * Addenda: http://geographiclib.sourceforge.net/geod-addenda.html
18
18
  *
19
19
  * See the comments in geodesic.h for documentation.
20
20
  *
21
- * Copyright (c) Charles Karney (2012-2015) <charles@karney.com> and licensed
21
+ * Copyright (c) Charles Karney (2012-2016) <charles@karney.com> and licensed
22
22
  * under the MIT/X11 License. For more information, see
23
23
  * http://geographiclib.sourceforge.net/
24
24
  */
@@ -119,6 +119,10 @@ static real atanhx(real x) {
119
119
  return x < 0 ? -y : y;
120
120
  }
121
121
 
122
+ static real copysignx(real x, real y) {
123
+ return fabs(x) * (y < 0 || (y == 0 && 1/y < 0) ? -1 : 1);
124
+ }
125
+
122
126
  static real hypotx(real x, real y)
123
127
  { return sqrt(x * x + y * y); }
124
128
 
@@ -133,7 +137,7 @@ static real sumx(real u, real v, real* t) {
133
137
  volatile real vpp = s - up;
134
138
  up -= u;
135
139
  vpp -= v;
136
- *t = -(up + vpp);
140
+ if (t) *t = -(up + vpp);
137
141
  /* error-free sum:
138
142
  * u + v = s + t
139
143
  * = round(u + v) + t */
@@ -146,11 +150,12 @@ static real polyval(int N, const real p[], real x) {
146
150
  return y;
147
151
  }
148
152
 
149
- static real minx(real x, real y)
150
- { return x < y ? x : y; }
153
+ /* mimic C++ std::min and std::max */
154
+ static real minx(real a, real b)
155
+ { return (b < a) ? b : a; }
151
156
 
152
- static real maxx(real x, real y)
153
- { return x > y ? x : y; }
157
+ static real maxx(real a, real b)
158
+ { return (a < b) ? b : a; }
154
159
 
155
160
  static void swapx(real* x, real* y)
156
161
  { real t = *x; *x = *y; *y = t; }
@@ -169,7 +174,7 @@ static real AngNormalize(real x) {
169
174
  static real LatFix(real x)
170
175
  { return fabs(x) > 90 ? NaN : x; }
171
176
 
172
- static real AngDiff(real x, real y) {
177
+ static real AngDiff(real x, real y, real* e) {
173
178
  real t, d = - AngNormalize(sumx(AngNormalize(x), AngNormalize(-y), &t));
174
179
  /* Here y - x = d - t (mod 360), exactly, where d is in (-180,180] and
175
180
  * abs(t) <= eps (eps = 2^-45 for doubles). The only case where the
@@ -177,15 +182,16 @@ static real AngDiff(real x, real y) {
177
182
  * and t < 0. The case, d = -180 + eps, t = eps, can't happen, since
178
183
  * sum would have returned the exact result in such a case (i.e., given t
179
184
  * = 0). */
180
- return (d == 180 && t < 0 ? -180 : d) - t;
185
+ return sumx(d == 180 && t < 0 ? -180 : d, -t, e);
181
186
  }
182
187
 
183
188
  static real AngRound(real x) {
184
189
  const real z = 1/(real)(16);
190
+ if (x == 0) return 0;
185
191
  volatile real y = fabs(x);
186
192
  /* The compiler mustn't "simplify" z - (z - y) to y */
187
193
  y = y < z ? z - (z - y) : y;
188
- return x < 0 ? 0 - y : y;
194
+ return x < 0 ? -y : y;
189
195
  }
190
196
 
191
197
  static void sincosdx(real x, real* sinx, real* cosx) {
@@ -249,7 +255,7 @@ static real Astroid(real x, real y);
249
255
  static real InverseStart(const struct geod_geodesic* g,
250
256
  real sbet1, real cbet1, real dn1,
251
257
  real sbet2, real cbet2, real dn2,
252
- real lam12,
258
+ real lam12, real slam12, real clam12,
253
259
  real* psalp1, real* pcalp1,
254
260
  /* Only updated if return val >= 0 */
255
261
  real* psalp2, real* pcalp2,
@@ -261,11 +267,13 @@ static real Lambda12(const struct geod_geodesic* g,
261
267
  real sbet1, real cbet1, real dn1,
262
268
  real sbet2, real cbet2, real dn2,
263
269
  real salp1, real calp1,
270
+ real slam120, real clam120,
264
271
  real* psalp2, real* pcalp2,
265
272
  real* psig12,
266
273
  real* pssig1, real* pcsig1,
267
274
  real* pssig2, real* pcsig2,
268
- real* peps, real* pdomg12,
275
+ real* peps,
276
+ real* psomg12, real* pcomg12,
269
277
  boolx diffp, real* pdlam12,
270
278
  /* Scratch area of the right size */
271
279
  real Ca[]);
@@ -288,7 +296,7 @@ static void accneg(real s[]);
288
296
  void geod_init(struct geod_geodesic* g, real a, real f) {
289
297
  if (!init) Init();
290
298
  g->a = a;
291
- g->f = f <= 1 ? f : 1/f;
299
+ g->f = f;
292
300
  g->f1 = 1 - g->f;
293
301
  g->e2 = g->f * (2 - g->f);
294
302
  g->ep2 = g->e2 / sq(g->f1); /* e2 / (1 - e2) */
@@ -315,9 +323,11 @@ void geod_init(struct geod_geodesic* g, real a, real f) {
315
323
  C4coeff(g);
316
324
  }
317
325
 
318
- void geod_lineinit(struct geod_geodesicline* l,
319
- const struct geod_geodesic* g,
320
- real lat1, real lon1, real azi1, unsigned caps) {
326
+ static void geod_lineinit_int(struct geod_geodesicline* l,
327
+ const struct geod_geodesic* g,
328
+ real lat1, real lon1,
329
+ real azi1, real salp1, real calp1,
330
+ unsigned caps) {
321
331
  real cbet1, sbet1, eps;
322
332
  l->a = g->a;
323
333
  l->f = g->f;
@@ -331,9 +341,9 @@ void geod_lineinit(struct geod_geodesicline* l,
331
341
 
332
342
  l->lat1 = LatFix(lat1);
333
343
  l->lon1 = lon1;
334
- l->azi1 = AngNormalize(azi1);
335
- /* Guard against underflow in salp0 */
336
- sincosdx(AngRound(l->azi1), &l->salp1, &l->calp1);
344
+ l->azi1 = azi1;
345
+ l->salp1 = salp1;
346
+ l->calp1 = calp1;
337
347
 
338
348
  sincosdx(AngRound(l->lat1), &sbet1, &cbet1); sbet1 *= l->f1;
339
349
  /* Ensure cbet1 = +epsilon at poles */
@@ -396,6 +406,34 @@ void geod_lineinit(struct geod_geodesicline* l,
396
406
  l->A4 = sq(l->a) * l->calp0 * l->salp0 * g->e2;
397
407
  l->B41 = SinCosSeries(FALSE, l->ssig1, l->csig1, l->C4a, nC4);
398
408
  }
409
+
410
+ l->a13 = l->s13 = NaN;
411
+ }
412
+
413
+ void geod_lineinit(struct geod_geodesicline* l,
414
+ const struct geod_geodesic* g,
415
+ real lat1, real lon1, real azi1, unsigned caps) {
416
+ azi1 = AngNormalize(azi1);
417
+ real salp1, calp1;
418
+ /* Guard against underflow in salp0 */
419
+ sincosdx(AngRound(azi1), &salp1, &calp1);
420
+ geod_lineinit_int(l, g, lat1, lon1, azi1, salp1, calp1, caps);
421
+ }
422
+
423
+ void geod_gendirectline(struct geod_geodesicline* l,
424
+ const struct geod_geodesic* g,
425
+ real lat1, real lon1, real azi1,
426
+ unsigned flags, real a12_s12,
427
+ unsigned caps) {
428
+ geod_lineinit(l, g, lat1, lon1, azi1, caps);
429
+ geod_gensetdistance(l, flags, a12_s12);
430
+ }
431
+
432
+ void geod_directline(struct geod_geodesicline* l,
433
+ const struct geod_geodesic* g,
434
+ real lat1, real lon1, real azi1,
435
+ real s12, unsigned caps) {
436
+ geod_gendirectline(l, g, lat1, lon1, azi1, GEOD_NOFLAGS, s12, caps);
399
437
  }
400
438
 
401
439
  real geod_genposition(const struct geod_geodesicline* l,
@@ -421,7 +459,7 @@ real geod_genposition(const struct geod_geodesicline* l,
421
459
 
422
460
  outmask &= l->caps & OUT_ALL;
423
461
  if (!( TRUE /*Init()*/ &&
424
- (flags & GEOD_ARCMODE || (l->caps & GEOD_DISTANCE_IN & OUT_ALL)) ))
462
+ (flags & GEOD_ARCMODE || (l->caps & (GEOD_DISTANCE_IN & OUT_ALL))) ))
425
463
  /* Uninitialized or impossible distance calculation requested */
426
464
  return NaN;
427
465
 
@@ -464,10 +502,9 @@ real geod_genposition(const struct geod_geodesicline* l,
464
502
  * 1/20 5376 146e3 10e3
465
503
  * 1/10 829e3 22e6 1.5e6
466
504
  * 1/5 157e6 3.8e9 280e6 */
467
- real
468
- ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12,
469
- csig2 = l->csig1 * csig12 - l->ssig1 * ssig12,
470
- serr;
505
+ real serr;
506
+ ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12;
507
+ csig2 = l->csig1 * csig12 - l->ssig1 * ssig12;
471
508
  B12 = SinCosSeries(TRUE, ssig2, csig2, l->C1a, nC1);
472
509
  serr = (1 + l->A1m1) * (sig12 + (B12 - l->B11)) - s12_a12 / l->b;
473
510
  sig12 = sig12 - serr / sqrt(1 + l->k2 * sq(ssig2));
@@ -499,7 +536,7 @@ real geod_genposition(const struct geod_geodesicline* l,
499
536
  s12 = flags & GEOD_ARCMODE ? l->b * ((1 + l->A1m1) * sig12 + AB1) : s12_a12;
500
537
 
501
538
  if (outmask & GEOD_LONGITUDE) {
502
- int E = l->salp0 < 0 ? -1 : 1; /* east or west going? */
539
+ real E = copysignx(1, l->salp0); /* east or west going? */
503
540
  /* tan(omg2) = sin(alp0) * tan(sig2) */
504
541
  somg2 = l->salp0 * ssig2; comg2 = csig2; /* No need to normalize */
505
542
  /* omg12 = omg2 - omg1 */
@@ -548,14 +585,6 @@ real geod_genposition(const struct geod_geodesicline* l,
548
585
  /* alp12 = alp2 - alp1, used in atan2 so no need to normalize */
549
586
  salp12 = salp2 * l->calp1 - calp2 * l->salp1;
550
587
  calp12 = calp2 * l->calp1 + salp2 * l->salp1;
551
- /* The right thing appears to happen if alp1 = +/-180 and alp2 = 0, viz
552
- * salp12 = -0 and alp12 = -180. However this depends on the sign being
553
- * attached to 0 correctly. The following ensures the correct
554
- * behavior. */
555
- if (salp12 == 0 && calp12 < 0) {
556
- salp12 = tiny * l->calp1;
557
- calp12 = -1;
558
- }
559
588
  } else {
560
589
  /* tan(alp) = tan(alp0) * sec(sig)
561
590
  * tan(alp2-alp1) = (tan(alp2) -tan(alp1)) / (tan(alp2)*tan(alp1)+1)
@@ -593,6 +622,21 @@ real geod_genposition(const struct geod_geodesicline* l,
593
622
  return flags & GEOD_ARCMODE ? s12_a12 : sig12 / degree;
594
623
  }
595
624
 
625
+ void geod_setdistance(struct geod_geodesicline* l, real s13) {
626
+ l->s13 = s13;
627
+ l->a13 = geod_genposition(l, GEOD_NOFLAGS, l->s13, 0, 0, 0, 0, 0, 0, 0, 0);
628
+ }
629
+
630
+ static void geod_setarc(struct geod_geodesicline* l, real a13) {
631
+ l->a13 = a13; l->s13 = NaN;
632
+ geod_genposition(l, GEOD_ARCMODE, l->a13, 0, 0, 0, &l->s13, 0, 0, 0, 0);
633
+ }
634
+
635
+ void geod_gensetdistance(struct geod_geodesicline* l,
636
+ unsigned flags, real s13_a13) {
637
+ flags & GEOD_ARCMODE ? geod_setarc(l, s13_a13) : geod_setdistance(l, s13_a13);
638
+ }
639
+
596
640
  void geod_position(const struct geod_geodesicline* l, real s12,
597
641
  real* plat2, real* plon2, real* pazi2) {
598
642
  geod_genposition(l, FALSE, s12, plat2, plon2, pazi2, 0, 0, 0, 0, 0);
@@ -630,23 +674,26 @@ void geod_direct(const struct geod_geodesic* g,
630
674
  0, 0, 0, 0, 0);
631
675
  }
632
676
 
633
- real geod_geninverse(const struct geod_geodesic* g,
634
- real lat1, real lon1, real lat2, real lon2,
635
- real* ps12, real* pazi1, real* pazi2,
636
- real* pm12, real* pM12, real* pM21, real* pS12) {
637
- real s12 = 0, azi1 = 0, azi2 = 0, m12 = 0, M12 = 0, M21 = 0, S12 = 0;
638
- real lon12;
677
+ static real geod_geninverse_int(const struct geod_geodesic* g,
678
+ real lat1, real lon1, real lat2, real lon2,
679
+ real* ps12,
680
+ real* psalp1, real* pcalp1,
681
+ real* psalp2, real* pcalp2,
682
+ real* pm12, real* pM12, real* pM21,
683
+ real* pS12) {
684
+ real s12 = 0, m12 = 0, M12 = 0, M21 = 0, S12 = 0;
685
+ real lon12, lon12s;
639
686
  int latsign, lonsign, swapp;
640
687
  real sbet1, cbet1, sbet2, cbet2, s12x = 0, m12x = 0;
641
688
  real dn1, dn2, lam12, slam12, clam12;
642
689
  real a12 = 0, sig12, calp1 = 0, salp1 = 0, calp2 = 0, salp2 = 0;
643
690
  real Ca[nC];
644
691
  boolx meridian;
645
- real omg12 = 0;
692
+ /* somg12 > 1 marks that it needs to be calculated */
693
+ real omg12 = 0, somg12 = 2, comg12 = 0;
646
694
 
647
695
  unsigned outmask =
648
696
  (ps12 ? GEOD_DISTANCE : 0U) |
649
- (pazi1 || pazi2 ? GEOD_AZIMUTH : 0U) |
650
697
  (pm12 ? GEOD_REDUCEDLENGTH : 0U) |
651
698
  (pM12 || pM21 ? GEOD_GEODESICSCALE : 0U) |
652
699
  (pS12 ? GEOD_AREA : 0U);
@@ -655,16 +702,25 @@ real geod_geninverse(const struct geod_geodesic* g,
655
702
  /* Compute longitude difference (AngDiff does this carefully). Result is
656
703
  * in [-180, 180] but -180 is only for west-going geodesics. 180 is for
657
704
  * east-going and meridional geodesics. */
658
- /* If very close to being on the same half-meridian, then make it so. */
659
- lon12 = AngRound(AngDiff(lon1, lon2));
705
+ lon12 = AngDiff(lon1, lon2, &lon12s);
660
706
  /* Make longitude difference positive. */
661
707
  lonsign = lon12 >= 0 ? 1 : -1;
662
- lon12 *= lonsign;
708
+ /* If very close to being on the same half-meridian, then make it so. */
709
+ lon12 = lonsign * AngRound(lon12);
710
+ lon12s = AngRound((180 - lon12) - lonsign * lon12s);
711
+ lam12 = lon12 * degree;
712
+ if (lon12 > 90) {
713
+ sincosdx(lon12s, &slam12, &clam12);
714
+ clam12 = -clam12;
715
+ } else
716
+ sincosdx(lon12, &slam12, &clam12);
717
+
663
718
  /* If really close to the equator, treat as on equator. */
664
719
  lat1 = AngRound(LatFix(lat1));
665
720
  lat2 = AngRound(LatFix(lat2));
666
- /* Swap points so that point with higher (abs) latitude is point 1 */
667
- swapp = fabs(lat1) >= fabs(lat2) ? 1 : -1;
721
+ /* Swap points so that point with higher (abs) latitude is point 1
722
+ * If one latitude is a nan, then it becomes lat1. */
723
+ swapp = fabs(lat1) < fabs(lat2) ? -1 : 1;
668
724
  if (swapp < 0) {
669
725
  lonsign *= -1;
670
726
  swapx(&lat1, &lat2);
@@ -712,9 +768,6 @@ real geod_geninverse(const struct geod_geodesic* g,
712
768
  dn1 = sqrt(1 + g->ep2 * sq(sbet1));
713
769
  dn2 = sqrt(1 + g->ep2 * sq(sbet2));
714
770
 
715
- lam12 = lon12 * degree;
716
- sincosdx(lon12, &slam12, &clam12);
717
-
718
771
  meridian = lat1 == -90 || slam12 == 0;
719
772
 
720
773
  if (meridian) {
@@ -731,7 +784,7 @@ real geod_geninverse(const struct geod_geodesic* g,
731
784
  ssig2 = sbet2; csig2 = calp2 * cbet2;
732
785
 
733
786
  /* sig12 = sig2 - sig1 */
734
- sig12 = atan2(maxx(csig1 * ssig2 - ssig1 * csig2, (real)(0)),
787
+ sig12 = atan2(maxx((real)(0), csig1 * ssig2 - ssig1 * csig2),
735
788
  csig1 * csig2 + ssig1 * ssig2);
736
789
  Lengths(g, g->n, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,
737
790
  cbet1, cbet2, &s12x, &m12x, 0,
@@ -760,7 +813,7 @@ real geod_geninverse(const struct geod_geodesic* g,
760
813
  if (!meridian &&
761
814
  sbet1 == 0 && /* and sbet2 == 0 */
762
815
  /* Mimic the way Lambda12 works with calp1 = 0 */
763
- (g->f <= 0 || lam12 <= pi - g->f * pi)) {
816
+ (g->f <= 0 || lon12s >= g->f * 180)) {
764
817
 
765
818
  /* Geodesic runs along equator */
766
819
  calp1 = calp2 = 0; salp1 = salp2 = 1;
@@ -779,7 +832,7 @@ real geod_geninverse(const struct geod_geodesic* g,
779
832
  /* Figure a starting point for Newton's method */
780
833
  real dnm = 0;
781
834
  sig12 = InverseStart(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2,
782
- lam12,
835
+ lam12, slam12, clam12,
783
836
  &salp1, &calp1, &salp2, &calp2, &dnm,
784
837
  Ca);
785
838
 
@@ -813,13 +866,13 @@ real geod_geninverse(const struct geod_geodesic* g,
813
866
  /* the WGS84 test set: mean = 1.47, sd = 1.25, max = 16
814
867
  * WGS84 and random input: mean = 2.85, sd = 0.60 */
815
868
  real dv = 0,
816
- v = (Lambda12(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1,
869
+ v = Lambda12(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1,
870
+ slam12, clam12,
817
871
  &salp2, &calp2, &sig12, &ssig1, &csig1, &ssig2, &csig2,
818
- &eps, &omg12, numit < maxit1, &dv, Ca)
819
- - lam12);
872
+ &eps, &somg12, &comg12, numit < maxit1, &dv, Ca);
820
873
  /* 2 * tol0 is approximately 1 ulp for a number in [0, pi]. */
821
874
  /* Reversed test to allow escape with NaNs */
822
- if (tripb || !(fabs(v) >= (tripn ? 8 : 2) * tol0)) break;
875
+ if (tripb || !(fabs(v) >= (tripn ? 8 : 1) * tol0)) break;
823
876
  /* Update bracketing values */
824
877
  if (v > 0 && (numit > maxit1 || calp1/salp1 > calp1b/salp1b))
825
878
  { salp1b = salp1; calp1b = calp1; }
@@ -864,7 +917,6 @@ real geod_geninverse(const struct geod_geodesic* g,
864
917
  m12x *= g->b;
865
918
  s12x *= g->b;
866
919
  a12 = sig12 / degree;
867
- omg12 = lam12 - omg12;
868
920
  }
869
921
  }
870
922
 
@@ -900,15 +952,22 @@ real geod_geninverse(const struct geod_geodesic* g,
900
952
  /* Avoid problems with indeterminate sig1, sig2 on equator */
901
953
  S12 = 0;
902
954
 
955
+ if (!meridian) {
956
+ if (somg12 > 1) {
957
+ somg12 = sin(omg12); comg12 = cos(omg12);
958
+ } else
959
+ norm2(&somg12, &comg12);
960
+ }
961
+
903
962
  if (!meridian &&
904
- omg12 < (real)(0.75) * pi && /* Long difference too big */
905
- sbet2 - sbet1 < (real)(1.75)) { /* Lat difference too big */
963
+ /* omg12 < 3/4 * pi */
964
+ comg12 > -(real)(0.7071) && /* Long difference not too big */
965
+ sbet2 - sbet1 < (real)(1.75)) { /* Lat difference not too big */
906
966
  /* Use tan(Gamma/2) = tan(omg12/2)
907
967
  * * (tan(bet1/2)+tan(bet2/2))/(1+tan(bet1/2)*tan(bet2/2))
908
968
  * with tan(x/2) = sin(x)/(1+cos(x)) */
909
969
  real
910
- somg12 = sin(omg12), domg12 = 1 + cos(omg12),
911
- dbet1 = 1 + cbet1, dbet2 = 1 + cbet2;
970
+ domg12 = 1 + comg12, dbet1 = 1 + cbet1, dbet2 = 1 + cbet2;
912
971
  alp12 = 2 * atan2( somg12 * ( sbet1 * dbet2 + sbet2 * dbet1 ),
913
972
  domg12 * ( sbet1 * sbet2 + dbet1 * dbet2 ) );
914
973
  } else {
@@ -943,18 +1002,13 @@ real geod_geninverse(const struct geod_geodesic* g,
943
1002
  salp1 *= swapp * lonsign; calp1 *= swapp * latsign;
944
1003
  salp2 *= swapp * lonsign; calp2 *= swapp * latsign;
945
1004
 
946
- if (outmask & GEOD_AZIMUTH) {
947
- /* minus signs give range [-180, 180). 0- converts -0 to +0. */
948
- azi1 = atan2dx(salp1, calp1);
949
- azi2 = atan2dx(salp2, calp2);
950
- }
1005
+ if (psalp1) *psalp1 = salp1;
1006
+ if (pcalp1) *pcalp1 = calp1;
1007
+ if (psalp2) *psalp2 = salp2;
1008
+ if (pcalp2) *pcalp2 = calp2;
951
1009
 
952
1010
  if (outmask & GEOD_DISTANCE)
953
1011
  *ps12 = s12;
954
- if (outmask & GEOD_AZIMUTH) {
955
- if (pazi1) *pazi1 = azi1;
956
- if (pazi2) *pazi2 = azi2;
957
- }
958
1012
  if (outmask & GEOD_REDUCEDLENGTH)
959
1013
  *pm12 = m12;
960
1014
  if (outmask & GEOD_GEODESICSCALE) {
@@ -968,6 +1022,35 @@ real geod_geninverse(const struct geod_geodesic* g,
968
1022
  return a12;
969
1023
  }
970
1024
 
1025
+ real geod_geninverse(const struct geod_geodesic* g,
1026
+ real lat1, real lon1, real lat2, real lon2,
1027
+ real* ps12, real* pazi1, real* pazi2,
1028
+ real* pm12, real* pM12, real* pM21, real* pS12) {
1029
+ real salp1, calp1, salp2, calp2,
1030
+ a12 = geod_geninverse_int(g, lat1, lon1, lat2, lon2, ps12,
1031
+ &salp1, &calp1, &salp2, &calp2,
1032
+ pm12, pM12, pM21, pS12);
1033
+ if (pazi1) *pazi1 = atan2dx(salp1, calp1);
1034
+ if (pazi2) *pazi2 = atan2dx(salp2, calp2);
1035
+ return a12;
1036
+ }
1037
+
1038
+ void geod_inverseline(struct geod_geodesicline* l,
1039
+ const struct geod_geodesic* g,
1040
+ real lat1, real lon1, real lat2, real lon2,
1041
+ unsigned caps) {
1042
+ real salp1, calp1,
1043
+ a12 = geod_geninverse_int(g, lat1, lon1, lat2, lon2, 0,
1044
+ &salp1, &calp1, 0, 0,
1045
+ 0, 0, 0, 0),
1046
+ azi1 = atan2dx(salp1, calp1);
1047
+ caps = caps ? caps : GEOD_DISTANCE_IN | GEOD_LONGITUDE;
1048
+ /* Ensure that a12 can be converted to a distance */
1049
+ if (caps & (OUT_ALL & GEOD_DISTANCE_IN)) caps |= GEOD_DISTANCE;
1050
+ geod_lineinit_int(l, g, lat1, lon1, azi1, salp1, calp1, caps);
1051
+ geod_setarc(l, a12);
1052
+ }
1053
+
971
1054
  void geod_inverse(const struct geod_geodesic* g,
972
1055
  real lat1, real lon1, real lat2, real lon2,
973
1056
  real* ps12, real* pazi1, real* pazi2) {
@@ -1112,7 +1195,7 @@ real Astroid(real x, real y) {
1112
1195
  real InverseStart(const struct geod_geodesic* g,
1113
1196
  real sbet1, real cbet1, real dn1,
1114
1197
  real sbet2, real cbet2, real dn2,
1115
- real lam12,
1198
+ real lam12, real slam12, real clam12,
1116
1199
  real* psalp1, real* pcalp1,
1117
1200
  /* Only updated if return val >= 0 */
1118
1201
  real* psalp2, real* pcalp2,
@@ -1133,7 +1216,7 @@ real InverseStart(const struct geod_geodesic* g,
1133
1216
  real sbet12a;
1134
1217
  boolx shortline = cbet12 >= 0 && sbet12 < (real)(0.5) &&
1135
1218
  cbet2 * lam12 < (real)(0.5);
1136
- real omg12 = lam12, somg12, comg12, ssig12, csig12;
1219
+ real somg12, comg12, ssig12, csig12;
1137
1220
  #if defined(__GNUC__) && __GNUC__ == 4 && \
1138
1221
  (__GNUC_MINOR__ < 6 || defined(__MINGW32__))
1139
1222
  /* Volatile declaration needed to fix inverse cases
@@ -1151,14 +1234,16 @@ real InverseStart(const struct geod_geodesic* g,
1151
1234
  sbet12a = sbet2 * cbet1 + cbet2 * sbet1;
1152
1235
  #endif
1153
1236
  if (shortline) {
1154
- real sbetm2 = sq(sbet1 + sbet2);
1237
+ real sbetm2 = sq(sbet1 + sbet2), omg12;
1155
1238
  /* sin((bet1+bet2)/2)^2
1156
1239
  * = (sbet1 + sbet2)^2 / ((sbet1 + sbet2)^2 + (cbet1 + cbet2)^2) */
1157
1240
  sbetm2 /= sbetm2 + sq(cbet1 + cbet2);
1158
1241
  dnm = sqrt(1 + g->ep2 * sbetm2);
1159
- omg12 /= g->f1 * dnm;
1242
+ omg12 = lam12 / (g->f1 * dnm);
1243
+ somg12 = sin(omg12); comg12 = cos(omg12);
1244
+ } else {
1245
+ somg12 = slam12; comg12 = clam12;
1160
1246
  }
1161
- somg12 = sin(omg12); comg12 = cos(omg12);
1162
1247
 
1163
1248
  salp1 = cbet2 * somg12;
1164
1249
  calp1 = comg12 >= 0 ?
@@ -1188,6 +1273,7 @@ real InverseStart(const struct geod_geodesic* g,
1188
1273
  * 56.320923501171 0 -56.320923501171 179.664747671772880215
1189
1274
  * which otherwise fails with g++ 4.4.4 x86 -O3 */
1190
1275
  volatile real x;
1276
+ real lam12x = atan2(-slam12, -clam12); /* lam12 - pi */
1191
1277
  if (g->f >= 0) { /* In fact f == 0 does not get here */
1192
1278
  /* x = dlong, y = dlat */
1193
1279
  {
@@ -1198,7 +1284,7 @@ real InverseStart(const struct geod_geodesic* g,
1198
1284
  }
1199
1285
  betscale = lamscale * cbet1;
1200
1286
 
1201
- x = (lam12 - pi) / lamscale;
1287
+ x = lam12x / lamscale;
1202
1288
  y = sbet12a / betscale;
1203
1289
  } else { /* f < 0 */
1204
1290
  /* x = dlat, y = dlong */
@@ -1215,7 +1301,7 @@ real InverseStart(const struct geod_geodesic* g,
1215
1301
  betscale = x < -(real)(0.01) ? sbet12a / x :
1216
1302
  -g->f * sq(cbet1) * pi;
1217
1303
  lamscale = betscale / cbet1;
1218
- y = (lam12 - pi) / lamscale;
1304
+ y = lam12x / lamscale;
1219
1305
  }
1220
1306
 
1221
1307
  if (y > -tol1 && x > -1 - xthresh) {
@@ -1292,19 +1378,22 @@ real Lambda12(const struct geod_geodesic* g,
1292
1378
  real sbet1, real cbet1, real dn1,
1293
1379
  real sbet2, real cbet2, real dn2,
1294
1380
  real salp1, real calp1,
1381
+ real slam120, real clam120,
1295
1382
  real* psalp2, real* pcalp2,
1296
1383
  real* psig12,
1297
1384
  real* pssig1, real* pcsig1,
1298
1385
  real* pssig2, real* pcsig2,
1299
- real* peps, real* pdomg12,
1386
+ real* peps,
1387
+ real* psomg12, real* pcomg12,
1300
1388
  boolx diffp, real* pdlam12,
1301
1389
  /* Scratch area of the right size */
1302
1390
  real Ca[]) {
1303
1391
  real salp2 = 0, calp2 = 0, sig12 = 0,
1304
- ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0, domg12 = 0, dlam12 = 0;
1392
+ ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0,
1393
+ somg12 = 0, comg12 = 0, dlam12 = 0;
1305
1394
  real salp0, calp0;
1306
- real somg1, comg1, somg2, comg2, omg12, lam12;
1307
- real B312, h0, k2;
1395
+ real somg1, comg1, somg2, comg2, lam12;
1396
+ real B312, eta, k2;
1308
1397
 
1309
1398
  if (sbet1 == 0 && calp1 == 0)
1310
1399
  /* Break degeneracy of equatorial line. This case has already been
@@ -1345,20 +1434,21 @@ real Lambda12(const struct geod_geodesic* g,
1345
1434
  /* norm2(&somg2, &comg2); -- don't need to normalize! */
1346
1435
 
1347
1436
  /* sig12 = sig2 - sig1, limit to [0, pi] */
1348
- sig12 = atan2(maxx(csig1 * ssig2 - ssig1 * csig2, (real)(0)),
1437
+ sig12 = atan2(maxx((real)(0), csig1 * ssig2 - ssig1 * csig2),
1349
1438
  csig1 * csig2 + ssig1 * ssig2);
1350
1439
 
1351
1440
  /* omg12 = omg2 - omg1, limit to [0, pi] */
1352
- omg12 = atan2(maxx(comg1 * somg2 - somg1 * comg2, (real)(0)),
1353
- comg1 * comg2 + somg1 * somg2);
1441
+ somg12 = maxx((real)(0), comg1 * somg2 - somg1 * comg2);
1442
+ comg12 = comg1 * comg2 + somg1 * somg2;
1443
+ /* eta = omg12 - lam120 */
1444
+ eta = atan2(somg12 * clam120 - comg12 * slam120,
1445
+ comg12 * clam120 + somg12 * slam120);
1354
1446
  k2 = sq(calp0) * g->ep2;
1355
1447
  eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2);
1356
1448
  C3f(g, eps, Ca);
1357
1449
  B312 = (SinCosSeries(TRUE, ssig2, csig2, Ca, nC3-1) -
1358
1450
  SinCosSeries(TRUE, ssig1, csig1, Ca, nC3-1));
1359
- h0 = -g->f * A3f(g, eps);
1360
- domg12 = salp0 * h0 * (sig12 + B312);
1361
- lam12 = omg12 + domg12;
1451
+ lam12 = eta - g->f * A3f(g, eps) * salp0 * (sig12 + B312);
1362
1452
 
1363
1453
  if (diffp) {
1364
1454
  if (calp2 == 0)
@@ -1378,7 +1468,8 @@ real Lambda12(const struct geod_geodesic* g,
1378
1468
  *pssig2 = ssig2;
1379
1469
  *pcsig2 = csig2;
1380
1470
  *peps = eps;
1381
- *pdomg12 = domg12;
1471
+ *psomg12 = somg12;
1472
+ *pcomg12 = comg12;
1382
1473
  if (diffp)
1383
1474
  *pdlam12 = dlam12;
1384
1475
 
@@ -1653,7 +1744,7 @@ int transit(real lon1, real lon2) {
1653
1744
  /* Compute lon12 the same way as Geodesic::Inverse. */
1654
1745
  lon1 = AngNormalize(lon1);
1655
1746
  lon2 = AngNormalize(lon2);
1656
- lon12 = AngDiff(lon1, lon2);
1747
+ lon12 = AngDiff(lon1, lon2, 0);
1657
1748
  return lon1 < 0 && lon2 >= 0 && lon12 > 0 ? 1 :
1658
1749
  (lon2 < 0 && lon1 >= 0 && lon12 < 0 ? -1 : 0);
1659
1750
  }
@@ -1699,8 +1790,12 @@ void accneg(real s[]) {
1699
1790
  }
1700
1791
 
1701
1792
  void geod_polygon_init(struct geod_polygon* p, boolx polylinep) {
1702
- p->lat0 = p->lon0 = p->lat = p->lon = NaN;
1703
1793
  p->polyline = (polylinep != 0);
1794
+ geod_polygon_clear(p);
1795
+ }
1796
+
1797
+ void geod_polygon_clear(struct geod_polygon* p) {
1798
+ p->lat0 = p->lon0 = p->lat = p->lon = NaN;
1704
1799
  accini(p->P);
1705
1800
  accini(p->A);
1706
1801
  p->num = p->crossings = 0;