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 +4 -4
- data/ext/geodesic_wgs84/geodesic.c +185 -90
- data/ext/geodesic_wgs84/geodesic.h +301 -178
- data/geodesic_wgs84.gemspec +2 -2
- data/lib/geodesic_wgs84/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 139b783b65ccd28ad8fac5977f7700467760a4a4
|
4
|
+
data.tar.gz: 969289b3a018caba12c6c41c6ed891adefc138d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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-
|
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
|
-
|
150
|
-
|
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
|
153
|
-
{ return
|
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
|
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 ?
|
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,
|
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
|
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
|
319
|
-
|
320
|
-
|
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 =
|
335
|
-
|
336
|
-
|
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
|
-
|
469
|
-
|
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
|
-
|
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
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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 ||
|
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 =
|
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, &
|
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 :
|
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 <
|
905
|
-
|
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
|
-
|
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 (
|
947
|
-
|
948
|
-
|
949
|
-
|
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
|
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
|
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 =
|
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 =
|
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,
|
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,
|
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,
|
1307
|
-
real B312,
|
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
|
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
|
-
|
1353
|
-
|
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
|
-
|
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
|
-
*
|
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;
|