30#if defined(__cplusplus)
31#define NULLPTR nullptr
38#define GEOGRAPHICLIB_GEODESIC_ORDER 6
39#define nA1 GEOGRAPHICLIB_GEODESIC_ORDER
40#define nC1 GEOGRAPHICLIB_GEODESIC_ORDER
41#define nC1p GEOGRAPHICLIB_GEODESIC_ORDER
42#define nA2 GEOGRAPHICLIB_GEODESIC_ORDER
43#define nC2 GEOGRAPHICLIB_GEODESIC_ORDER
44#define nA3 GEOGRAPHICLIB_GEODESIC_ORDER
46#define nC3 GEOGRAPHICLIB_GEODESIC_ORDER
47#define nC3x ((nC3 * (nC3 - 1)) / 2)
48#define nC4 GEOGRAPHICLIB_GEODESIC_ORDER
49#define nC4x ((nC4 * (nC4 + 1)) / 2)
50#define nC (GEOGRAPHICLIB_GEODESIC_ORDER + 1)
53enum booly { FALSE = 0, TRUE = 1 };
57enum dms { qd = 90, hd = 2 * qd, td = 2 * hd };
59static unsigned init = 0;
60static unsigned digits, maxit1, maxit2;
61static double epsilon, realmin, pi, degree, NaN,
62 tiny, tol0, tol1, tol2, tolb, xthresh;
64static void Init(
void) {
66 digits = DBL_MANT_DIG;
67 epsilon = DBL_EPSILON;
72 pi = atan2(0.0, -1.0);
75 maxit2 = maxit1 + digits + 10;
85 xthresh = 1000 * tol2;
103static double sq(
double x) {
return x * x; }
105static double sumx(
double u,
double v,
double* t) {
106 volatile double s = u + v;
107 volatile double up = s - v;
108 volatile double vpp = s - up;
111 if (t) *t = s != 0 ? 0 - (up + vpp) : s;
118static double polyvalx(
int N,
const double p[],
double x) {
119 double y = N < 0 ? 0 : *p++;
120 while (--N >= 0) y = y * x + *p++;
124static void swapx(
double* x,
double* y)
125{
double t = *x; *x = *y; *y = t; }
127static void norm2(
double* sinx,
double* cosx) {
128#if defined(_MSC_VER) && defined(_M_IX86)
137 double r = sqrt(*sinx * *sinx + *cosx * *cosx);
139 double r = hypot(*sinx, *cosx);
145static double AngNormalize(
double x) {
146 double y = remainder(x, (
double)td);
147 return fabs(y) == hd ? copysign((
double)hd, x) : y;
150static double LatFix(
double x)
151{
return fabs(x) > qd ? NaN : x; }
153static double AngDiff(
double x,
double y,
double* e) {
156 double t, d = sumx(remainder(-x, (
double)td), remainder( y, (
double)td), &t);
159 d = sumx(remainder(d, (
double)td), t, &t);
161 if (d == 0 || fabs(d) == hd)
164 d = copysign(d, t == 0 ? y - x : -t);
169static double AngRound(
double x) {
171 const double z = 1.0/16.0;
172 volatile double y = fabs(x);
173 volatile double w = z - y;
175 y = w > 0 ? z - w : y;
176 return copysign(y, x);
179static void sincosdx(
double x,
double* sinx,
double* cosx) {
182 double r, s, c;
int q = 0;
183 r = remquo(x, (
double)qd, &q);
187 s = sin(r); c = cos(r);
188 switch ((
unsigned)q & 3U) {
189 case 0U: *sinx = s; *cosx = c;
break;
190 case 1U: *sinx = c; *cosx = -s;
break;
191 case 2U: *sinx = -s; *cosx = -c;
break;
192 default: *sinx = -c; *cosx = s;
break;
197 if (*sinx == 0) *sinx = copysign(*sinx, x);
200static void sincosde(
double x,
double t,
double* sinx,
double* cosx) {
203 double r, s, c;
int q = 0;
204 r = AngRound(remquo(x, (
double)qd, &q) + t);
208 s = sin(r); c = cos(r);
209 switch ((
unsigned)q & 3U) {
210 case 0U: *sinx = s; *cosx = c;
break;
211 case 1U: *sinx = c; *cosx = -s;
break;
212 case 2U: *sinx = -s; *cosx = -c;
break;
213 default: *sinx = -c; *cosx = s;
break;
218 if (*sinx == 0) *sinx = copysign(*sinx, x);
221static double atan2dx(
double y,
double x) {
226 int q = 0;
double ang;
227 if (fabs(y) > fabs(x)) { swapx(&x, &y); q = 2; }
228 if (signbit(x)) { x = -x; ++q; }
230 ang = atan2(y, x) / degree;
232 case 1: ang = copysign((
double)hd, y) - ang;
break;
233 case 2: ang = qd - ang;
break;
234 case 3: ang = -qd + ang;
break;
243static double SinCosSeries(boolx sinp,
244 double sinx,
double cosx,
245 const double c[],
int n);
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,
255static double Astroid(
double x,
double y);
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,
262 double* psalp2,
double* pcalp2,
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,
274 double* pssig1,
double* pcsig1,
275 double* pssig2,
double* pcsig2,
278 boolx diffp,
double* pdlam12,
282static void C3f(
const struct geod_geodesic* g,
double eps,
double c[]);
283static void C4f(
const struct geod_geodesic* g,
double eps,
double c[]);
284static double A1m1f(
double eps);
285static void C1f(
double eps,
double c[]);
286static void C1pf(
double eps,
double c[]);
287static double A2m1f(
double eps);
288static void C2f(
double eps,
double c[]);
289static int transit(
double lon1,
double lon2);
290static int transitdirect(
double lon1,
double lon2);
291static void accini(
double s[]);
292static void acccopy(
const double s[],
double t[]);
293static void accadd(
double s[],
double y);
294static double accsum(
const double s[],
double y);
295static void accneg(
double s[]);
296static void accrem(
double s[],
double y);
297static double areareduceA(
double area[],
double area0,
298 int crossings, boolx reverse, boolx sign);
299static double areareduceB(
double area,
double area0,
300 int crossings, boolx reverse, boolx sign);
307 g->e2 = g->
f * (2 - g->
f);
308 g->ep2 = g->e2 / sq(g->f1);
309 g->n = g->
f / ( 2 - g->
f);
311 g->c2 = (sq(g->
a) + sq(g->b) *
313 (g->e2 > 0 ? atanh(sqrt(g->e2)) : atan(sqrt(-g->e2))) /
314 sqrt(fabs(g->e2))))/2;
324 g->etol2 = 0.1 * tol2 /
325 sqrt( fmax(0.001, fabs(g->
f)) * fmin(1.0, 1 - g->
f/2) / 2 );
334 double lat1,
double lon1,
335 double azi1,
double salp1,
double calp1,
337 double cbet1, sbet1, eps;
348 l->
lat1 = LatFix(lat1);
354 sincosdx(AngRound(l->
lat1), &sbet1, &cbet1); sbet1 *= l->f1;
356 norm2(&sbet1, &cbet1); cbet1 = fmax(tiny, cbet1);
357 l->dn1 = sqrt(1 + g->ep2 * sq(sbet1));
360 l->salp0 = l->
salp1 * cbet1;
373 l->ssig1 = sbet1; l->somg1 = l->salp0 * sbet1;
374 l->csig1 = l->comg1 = sbet1 != 0 || l->
calp1 != 0 ? cbet1 * l->
calp1 : 1;
375 norm2(&l->ssig1, &l->csig1);
378 l->k2 = sq(l->calp0) * g->ep2;
379 eps = l->k2 / (2 * (1 + sqrt(1 + l->k2)) + l->k2);
381 if (l->
caps & CAP_C1) {
383 l->A1m1 = A1m1f(eps);
385 l->B11 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C1a, nC1);
386 s = sin(l->B11); c = cos(l->B11);
388 l->stau1 = l->ssig1 * c + l->csig1 * s;
389 l->ctau1 = l->csig1 * c - l->ssig1 * s;
394 if (l->
caps & CAP_C1p)
397 if (l->
caps & CAP_C2) {
398 l->A2m1 = A2m1f(eps);
400 l->B21 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C2a, nC2);
403 if (l->
caps & CAP_C3) {
405 l->A3c = -l->
f * l->salp0 * A3f(g, eps);
406 l->B31 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C3a, nC3-1);
409 if (l->
caps & CAP_C4) {
412 l->A4 = sq(l->
a) * l->calp0 * l->salp0 * g->e2;
413 l->B41 = SinCosSeries(FALSE, l->ssig1, l->csig1, l->C4a, nC4);
421 double lat1,
double lon1,
double azi1,
unsigned caps) {
423 azi1 = AngNormalize(azi1);
425 sincosdx(AngRound(azi1), &salp1, &calp1);
426 geod_lineinit_int(l, g, lat1, lon1, azi1, salp1, calp1, caps);
431 double lat1,
double lon1,
double azi1,
432 unsigned flags,
double s12_a12,
440 double lat1,
double lon1,
double azi1,
441 double s12,
unsigned caps) {
446 unsigned flags,
double s12_a12,
447 double* plat2,
double* plon2,
double* pazi2,
448 double* ps12,
double* pm12,
449 double* pM12,
double* pM21,
451 double lat2 = 0, lon2 = 0, azi2 = 0, s12 = 0,
452 m12 = 0, M12 = 0, M21 = 0, S12 = 0;
454 double sig12, ssig12, csig12, B12 = 0, AB1 = 0;
455 double omg12, lam12, lon12;
456 double ssig2, csig2, sbet2, cbet2, somg2, comg2, salp2, calp2, dn2;
466 outmask &= l->
caps & OUT_ALL;
475 sig12 = s12_a12 * degree;
476 sincosdx(s12_a12, &ssig12, &csig12);
480 tau12 = s12_a12 / (l->b * (1 + l->A1m1)),
484 B12 = - SinCosSeries(TRUE,
485 l->stau1 * c + l->ctau1 * s,
486 l->ctau1 * c - l->stau1 * s,
488 sig12 = tau12 - (B12 - l->B11);
489 ssig12 = sin(sig12); csig12 = cos(sig12);
490 if (fabs(l->
f) > 0.01) {
513 ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12;
514 csig2 = l->csig1 * csig12 - l->ssig1 * ssig12;
515 B12 = SinCosSeries(TRUE, ssig2, csig2, l->C1a, nC1);
516 serr = (1 + l->A1m1) * (sig12 + (B12 - l->B11)) - s12_a12 / l->b;
517 sig12 = sig12 - serr / sqrt(1 + l->k2 * sq(ssig2));
518 ssig12 = sin(sig12); csig12 = cos(sig12);
524 ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12;
525 csig2 = l->csig1 * csig12 - l->ssig1 * ssig12;
526 dn2 = sqrt(1 + l->k2 * sq(ssig2));
529 B12 = SinCosSeries(TRUE, ssig2, csig2, l->C1a, nC1);
530 AB1 = (1 + l->A1m1) * (B12 - l->B11);
533 sbet2 = l->calp0 * ssig2;
535 cbet2 = hypot(l->salp0, l->calp0 * csig2);
538 cbet2 = csig2 = tiny;
540 salp2 = l->salp0; calp2 = l->calp0 * csig2;
544 l->b * ((1 + l->A1m1) * sig12 + AB1) :
548 double E = copysign(1, l->salp0);
550 somg2 = l->salp0 * ssig2; comg2 = csig2;
554 - (atan2( ssig2, csig2) - atan2( l->ssig1, l->csig1))
555 + (atan2(E * somg2, comg2) - atan2(E * l->somg1, l->comg1)))
556 : atan2(somg2 * l->comg1 - comg2 * l->somg1,
557 comg2 * l->comg1 + somg2 * l->somg1);
558 lam12 = omg12 + l->A3c *
559 ( sig12 + (SinCosSeries(TRUE, ssig2, csig2, l->C3a, nC3-1)
561 lon12 = lam12 / degree;
563 AngNormalize(AngNormalize(l->lon1) + AngNormalize(lon12));
567 lat2 = atan2dx(sbet2, l->f1 * cbet2);
570 azi2 = atan2dx(salp2, calp2);
574 B22 = SinCosSeries(TRUE, ssig2, csig2, l->C2a, nC2),
575 AB2 = (1 + l->A2m1) * (B22 - l->B21),
576 J12 = (l->A1m1 - l->A2m1) * sig12 + (AB1 - AB2);
580 m12 = l->b * ((dn2 * (l->csig1 * ssig2) - l->dn1 * (l->ssig1 * csig2))
581 - l->csig1 * csig2 * J12);
583 double t = l->k2 * (ssig2 - l->ssig1) * (ssig2 + l->ssig1) /
585 M12 = csig12 + (t * ssig2 - csig2 * J12) * l->ssig1 / l->dn1;
586 M21 = csig12 - (t * l->ssig1 - l->csig1 * J12) * ssig2 / dn2;
592 B42 = SinCosSeries(FALSE, ssig2, csig2, l->C4a, nC4);
593 double salp12, calp12;
594 if (l->calp0 == 0 || l->salp0 == 0) {
607 salp12 = l->calp0 * l->salp0 *
608 (csig12 <= 0 ? l->csig1 * (1 - csig12) + ssig12 * l->ssig1 :
609 ssig12 * (l->csig1 * ssig12 / (1 + csig12) + l->ssig1));
610 calp12 = sq(l->salp0) + sq(l->calp0) * l->csig1 * csig2;
612 S12 = l->c2 * atan2(salp12, calp12) + l->A4 * (B42 - l->B41);
634 if (pM12) *pM12 = M12;
635 if (pM21) *pM21 = M21;
640 return (flags &
GEOD_ARCMODE) ? s12_a12 : sig12 / degree;
646 NULLPTR, NULLPTR, NULLPTR, NULLPTR, NULLPTR);
650 l->
a13 = a13; l->
s13 = NaN;
652 NULLPTR, NULLPTR, NULLPTR, NULLPTR);
656 unsigned flags,
double s13_a13) {
658 geod_setarc(l, s13_a13) :
663 double* plat2,
double* plon2,
double* pazi2) {
665 NULLPTR, NULLPTR, NULLPTR, NULLPTR, NULLPTR);
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,
689 plat2, plon2, pazi2, ps12, pm12, pM12, pM21, pS12);
695 double* plat2,
double* plon2,
double* pazi2) {
697 NULLPTR, NULLPTR, NULLPTR, NULLPTR, NULLPTR);
700static double geod_geninverse_int(
const struct geod_geodesic* g,
702 double lat2,
double lon2,
704 double* psalp1,
double* pcalp1,
705 double* psalp2,
double* pcalp2,
706 double* pm12,
double* pM12,
double* pM21,
708 double s12 = 0, m12 = 0, M12 = 0, M21 = 0, S12 = 0;
709 double lon12, lon12s;
710 int latsign, lonsign, swapp;
711 double sbet1, cbet1, sbet2, cbet2, s12x = 0, m12x = 0;
712 double dn1, dn2, lam12, slam12, clam12;
713 double a12 = 0, sig12,
calp1 = 0,
salp1 = 0, calp2 = 0, salp2 = 0;
717 double omg12 = 0, somg12 = 2, comg12 = 0;
729 lon12 = AngDiff(
lon1, lon2, &lon12s);
731 lonsign = signbit(lon12) ? -1 : 1;
732 lon12 *= lonsign; lon12s *= lonsign;
733 lam12 = lon12 * degree;
735 sincosde(lon12, lon12s, &slam12, &clam12);
736 lon12s = (hd - lon12) - lon12s;
740 lat2 = AngRound(LatFix(lat2));
743 swapp = fabs(
lat1) < fabs(lat2) || lat2 != lat2 ? -1 : 1;
749 latsign = signbit(
lat1) ? 1 : -1;
764 sincosdx(
lat1, &sbet1, &cbet1); sbet1 *= g->f1;
766 norm2(&sbet1, &cbet1); cbet1 = fmax(tiny, cbet1);
768 sincosdx(lat2, &sbet2, &cbet2); sbet2 *= g->f1;
770 norm2(&sbet2, &cbet2); cbet2 = fmax(tiny, cbet2);
780 if (cbet1 < -sbet1) {
782 sbet2 = copysign(sbet1, sbet2);
784 if (fabs(sbet2) == -sbet1)
788 dn1 = sqrt(1 + g->ep2 * sq(sbet1));
789 dn2 = sqrt(1 + g->ep2 * sq(sbet2));
791 meridian =
lat1 == -qd || slam12 == 0;
798 double ssig1, csig1, ssig2, csig2;
800 calp2 = 1; salp2 = 0;
803 ssig1 = sbet1; csig1 =
calp1 * cbet1;
804 ssig2 = sbet2; csig2 = calp2 * cbet2;
807 sig12 = atan2(fmax(0.0, csig1 * ssig2 - ssig1 * csig2) + 0,
808 csig1 * csig2 + ssig1 * ssig2);
809 Lengths(g, g->n, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,
810 cbet1, cbet2, &s12x, &m12x, NULLPTR,
819 if (sig12 < tol2 || m12x >= 0) {
821 if (sig12 < 3 * tiny ||
823 (sig12 < tol0 && (s12x < 0 || m12x < 0)))
824 sig12 = m12x = s12x = 0;
827 a12 = sig12 / degree;
836 (g->
f <= 0 || lon12s >= g->
f * hd)) {
841 sig12 = omg12 = lam12 / g->f1;
842 m12x = g->b * sin(sig12);
844 M12 = M21 = cos(sig12);
847 }
else if (!meridian) {
854 sig12 = InverseStart(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2,
855 lam12, slam12, clam12,
861 s12x = sig12 * g->b * dnm;
862 m12x = sq(dnm) * g->b * sin(sig12 / dnm);
864 M12 = M21 = cos(sig12 / dnm);
865 a12 = sig12 / degree;
866 omg12 = lam12 / (g->f1 * dnm);
880 double ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0, domg12 = 0;
883 double salp1a = tiny, calp1a = 1, salp1b = tiny, calp1b = -1;
890 v = Lambda12(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2,
salp1,
calp1,
892 &salp2, &calp2, &sig12, &ssig1, &csig1, &ssig2, &csig2,
893 &eps, &domg12, numit < maxit1, &dv, Ca);
896 !(fabs(v) >= (tripn ? 8 : 1) * tol0) ||
901 if (v > 0 && (numit > maxit1 ||
calp1/
salp1 > calp1b/salp1b))
903 else if (v < 0 && (numit > maxit1 ||
calp1/
salp1 < calp1a/salp1a))
905 if (numit < maxit1 && dv > 0) {
908 if (fabs(dalp1) < pi) {
910 sdalp1 = sin(dalp1), cdalp1 = cos(dalp1),
919 tripn = fabs(v) <= 16 * tol0;
932 salp1 = (salp1a + salp1b)/2;
933 calp1 = (calp1a + calp1b)/2;
936 tripb = (fabs(salp1a -
salp1) + (calp1a -
calp1) < tolb ||
937 fabs(
salp1 - salp1b) + (
calp1 - calp1b) < tolb);
939 Lengths(g, eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,
940 cbet1, cbet2, &s12x, &m12x, NULLPTR,
945 a12 = sig12 / degree;
948 double sdomg12 = sin(domg12), cdomg12 = cos(domg12);
949 somg12 = slam12 * cdomg12 - clam12 * sdomg12;
950 comg12 = clam12 * cdomg12 + slam12 * sdomg12;
964 salp0 =
salp1 * cbet1,
967 if (calp0 != 0 && salp0 != 0) {
970 ssig1 = sbet1, csig1 =
calp1 * cbet1,
971 ssig2 = sbet2, csig2 = calp2 * cbet2,
972 k2 = sq(calp0) * g->ep2,
973 eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2),
975 A4 = sq(g->
a) * calp0 * salp0 * g->e2;
977 norm2(&ssig1, &csig1);
978 norm2(&ssig2, &csig2);
980 B41 = SinCosSeries(FALSE, ssig1, csig1, Ca, nC4);
981 B42 = SinCosSeries(FALSE, ssig2, csig2, Ca, nC4);
982 S12 = A4 * (B42 - B41);
987 if (!meridian && somg12 == 2) {
988 somg12 = sin(omg12); comg12 = cos(omg12);
994 sbet2 - sbet1 < 1.75) {
999 domg12 = 1 + comg12, dbet1 = 1 + cbet1, dbet2 = 1 + cbet2;
1000 alp12 = 2 * atan2( somg12 * ( sbet1 * dbet2 + sbet2 * dbet1 ),
1001 domg12 * ( sbet1 * sbet2 + dbet1 * dbet2 ) );
1011 if (salp12 == 0 && calp12 < 0) {
1012 salp12 = tiny *
calp1;
1015 alp12 = atan2(salp12, calp12);
1017 S12 += g->c2 * alp12;
1018 S12 *= swapp * lonsign * latsign;
1025 swapx(&
salp1, &salp2);
1026 swapx(&
calp1, &calp2);
1031 salp1 *= swapp * lonsign;
calp1 *= swapp * latsign;
1032 salp2 *= swapp * lonsign; calp2 *= swapp * latsign;
1034 if (psalp1) *psalp1 =
salp1;
1035 if (pcalp1) *pcalp1 =
calp1;
1036 if (psalp2) *psalp2 = salp2;
1037 if (pcalp2) *pcalp2 = calp2;
1044 if (pM12) *pM12 = M12;
1045 if (pM21) *pM21 = M21;
1055 double lat1,
double lon1,
double lat2,
double lon2,
1056 double* ps12,
double* pazi1,
double* pazi2,
1057 double* pm12,
double* pM12,
double* pM21,
1060 a12 = geod_geninverse_int(g,
lat1,
lon1, lat2, lon2, ps12,
1062 pm12, pM12, pM21, pS12);
1064 if (pazi2) *pazi2 = atan2dx(salp2, calp2);
1070 double lat1,
double lon1,
double lat2,
double lon2,
1073 a12 = geod_geninverse_int(g,
lat1,
lon1, lat2, lon2, NULLPTR,
1075 NULLPTR, NULLPTR, NULLPTR, NULLPTR),
1082 geod_setarc(l, a12);
1086 double lat1,
double lon1,
double lat2,
double lon2,
1087 double* ps12,
double* pazi1,
double* pazi2) {
1089 NULLPTR, NULLPTR, NULLPTR, NULLPTR);
1092double SinCosSeries(boolx sinp,
double sinx,
double cosx,
1093 const double c[],
int n) {
1101 ar = 2 * (cosx - sinx) * (cosx + sinx);
1102 y0 = (n & 1) ? *--c : 0; y1 = 0;
1107 y1 = ar * y0 - y1 + *--c;
1108 y0 = ar * y1 - y0 + *--c;
1111 ? 2 * sinx * cosx * y0
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,
1124 double m0 = 0, J12 = 0, A1 = 0, A2 = 0;
1129 boolx redlp = pm12b || pm0 || pM12 || pM21;
1130 if (ps12b || redlp) {
1142 double B1 = SinCosSeries(TRUE, ssig2, csig2, Ca, nC1) -
1143 SinCosSeries(TRUE, ssig1, csig1, Ca, nC1);
1145 *ps12b = A1 * (sig12 + B1);
1147 double B2 = SinCosSeries(TRUE, ssig2, csig2, Cb, nC2) -
1148 SinCosSeries(TRUE, ssig1, csig1, Cb, nC2);
1149 J12 = m0 * sig12 + (A1 * B1 - A2 * B2);
1154 for (l = 1; l <= nC2; ++l)
1155 Cb[l] = A1 * Ca[l] - A2 * Cb[l];
1156 J12 = m0 * sig12 + (SinCosSeries(TRUE, ssig2, csig2, Cb, nC2) -
1157 SinCosSeries(TRUE, ssig1, csig1, Cb, nC2));
1164 *pm12b = dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) -
1165 csig1 * csig2 * J12;
1167 double csig12 = csig1 * csig2 + ssig1 * ssig2;
1168 double t = g->ep2 * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2);
1170 *pM12 = csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1;
1172 *pM21 = csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2;
1176double Astroid(
double x,
double y) {
1183 r = (p + q - 1) / 6;
1184 if ( !(q == 0 && r <= 0) ) {
1193 disc = S * (S + 2 * r3);
1197 double T3 = S + r3, T;
1201 T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc);
1205 u += T + (T != 0 ? r2 / T : 0);
1208 double ang = atan2(sqrt(-disc), -(S + r3));
1211 u += 2 * r * cos(ang / 3);
1213 v = sqrt(sq(u) + q);
1215 uv = u < 0 ? q / (v - u) : u + v;
1216 w = (uv - q) / (2 * v);
1219 k = uv / (sqrt(uv + sq(w)) + w);
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,
1234 double* psalp2,
double* pcalp2,
1239 double salp1 = 0,
calp1 = 0, salp2 = 0, calp2 = 0, dnm = 0;
1247 sbet12 = sbet2 * cbet1 - cbet2 * sbet1,
1248 cbet12 = cbet2 * cbet1 + sbet2 * sbet1;
1250 boolx shortline = cbet12 >= 0 && sbet12 < 0.5 && cbet2 * lam12 < 0.5;
1251 double somg12, comg12, ssig12, csig12;
1252 sbet12a = sbet2 * cbet1 + cbet2 * sbet1;
1254 double sbetm2 = sq(sbet1 + sbet2), omg12;
1257 sbetm2 /= sbetm2 + sq(cbet1 + cbet2);
1258 dnm = sqrt(1 + g->ep2 * sbetm2);
1259 omg12 = lam12 / (g->f1 * dnm);
1260 somg12 = sin(omg12); comg12 = cos(omg12);
1262 somg12 = slam12; comg12 = clam12;
1265 salp1 = cbet2 * somg12;
1266 calp1 = comg12 >= 0 ?
1267 sbet12 + cbet2 * sbet1 * sq(somg12) / (1 + comg12) :
1268 sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12);
1271 csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12;
1273 if (shortline && ssig12 < g->etol2) {
1275 salp2 = cbet1 * somg12;
1276 calp2 = sbet12 - cbet1 * sbet2 *
1277 (comg12 >= 0 ? sq(somg12) / (1 + comg12) : 1 - comg12);
1278 norm2(&salp2, &calp2);
1280 sig12 = atan2(ssig12, csig12);
1281 }
else if (fabs(g->n) > 0.1 ||
1283 ssig12 >= 6 * fabs(g->n) * pi * sq(cbet1)) {
1288 double x, y, lamscale, betscale;
1289 double lam12x = atan2(-slam12, -clam12);
1294 k2 = sq(sbet1) * g->ep2,
1295 eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2);
1296 lamscale = g->
f * cbet1 * A3f(g, eps) * pi;
1298 betscale = lamscale * cbet1;
1300 x = lam12x / lamscale;
1301 y = sbet12a / betscale;
1305 cbet12a = cbet2 * cbet1 - sbet2 * sbet1,
1306 bet12a = atan2(sbet12a, cbet12a);
1310 Lengths(g, g->n, pi + bet12a,
1311 sbet1, -cbet1, dn1, sbet2, cbet2, dn2,
1312 cbet1, cbet2, NULLPTR, &m12b, &m0, NULLPTR, NULLPTR, Ca);
1313 x = -1 + m12b / (cbet1 * cbet2 * m0 * pi);
1314 betscale = x < -0.01 ? sbet12a / x :
1315 -g->
f * sq(cbet1) * pi;
1316 lamscale = betscale / cbet1;
1317 y = lam12x / lamscale;
1320 if (y > -tol1 && x > -1 - xthresh) {
1325 calp1 = fmax(x > -tol1 ? 0.0 : -1.0, x);
1363 double k = Astroid(x, y);
1365 omg12a = lamscale * ( g->
f >= 0 ? -x * k/(1 + k) : -y * (1 + k)/k );
1366 somg12 = sin(omg12a); comg12 = -cos(omg12a);
1368 salp1 = cbet2 * somg12;
1369 calp1 = sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12);
1391 double sbet1,
double cbet1,
double dn1,
1392 double sbet2,
double cbet2,
double dn2,
1394 double slam120,
double clam120,
1395 double* psalp2,
double* pcalp2,
1397 double* pssig1,
double* pcsig1,
1398 double* pssig2,
double* pcsig2,
1401 boolx diffp,
double* pdlam12,
1404 double salp2 = 0, calp2 = 0, sig12 = 0,
1405 ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0,
1406 domg12 = 0, dlam12 = 0;
1407 double salp0, calp0;
1408 double somg1, comg1, somg2, comg2, somg12, comg12, lam12;
1409 double B312, eta, k2;
1411 if (sbet1 == 0 &&
calp1 == 0)
1417 salp0 =
salp1 * cbet1;
1422 ssig1 = sbet1; somg1 = salp0 * sbet1;
1423 csig1 = comg1 =
calp1 * cbet1;
1424 norm2(&ssig1, &csig1);
1431 salp2 = cbet2 != cbet1 ? salp0 / cbet2 :
salp1;
1436 calp2 = cbet2 != cbet1 || fabs(sbet2) != -sbet1 ?
1437 sqrt(sq(
calp1 * cbet1) +
1439 (cbet2 - cbet1) * (cbet1 + cbet2) :
1440 (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 :
1444 ssig2 = sbet2; somg2 = salp0 * sbet2;
1445 csig2 = comg2 = calp2 * cbet2;
1446 norm2(&ssig2, &csig2);
1450 sig12 = atan2(fmax(0.0, csig1 * ssig2 - ssig1 * csig2) + 0,
1451 csig1 * csig2 + ssig1 * ssig2);
1454 somg12 = fmax(0.0, comg1 * somg2 - somg1 * comg2) + 0;
1455 comg12 = comg1 * comg2 + somg1 * somg2;
1457 eta = atan2(somg12 * clam120 - comg12 * slam120,
1458 comg12 * clam120 + somg12 * slam120);
1459 k2 = sq(calp0) * g->ep2;
1460 eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2);
1462 B312 = (SinCosSeries(TRUE, ssig2, csig2, Ca, nC3-1) -
1463 SinCosSeries(TRUE, ssig1, csig1, Ca, nC3-1));
1464 domg12 = -g->
f * A3f(g, eps) * salp0 * (sig12 + B312);
1465 lam12 = eta + domg12;
1469 dlam12 = - 2 * g->f1 * dn1 / sbet1;
1471 Lengths(g, eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,
1472 cbet1, cbet2, NULLPTR, &dlam12, NULLPTR, NULLPTR, NULLPTR, Ca);
1473 dlam12 *= g->f1 / (calp2 * cbet2);
1494 return polyvalx(nA3 - 1, g->A3x, eps);
1497void C3f(
const struct geod_geodesic* g,
double eps,
double c[]) {
1502 for (l = 1; l < nC3; ++l) {
1503 int m = nC3 - l - 1;
1505 c[l] = mult * polyvalx(m, g->C3x + o, eps);
1510void C4f(
const struct geod_geodesic* g,
double eps,
double c[]) {
1515 for (l = 0; l < nC4; ++l) {
1516 int m = nC4 - l - 1;
1517 c[l] = mult * polyvalx(m, g->C4x + o, eps);
1524double A1m1f(
double eps) {
1525 static const double coeff[] = {
1530 double t = polyvalx(m, coeff, sq(eps)) / coeff[m + 1];
1531 return (t + eps) / (1 - eps);
1535void C1f(
double eps,
double c[]) {
1536 static const double coeff[] = {
1554 for (l = 1; l <= nC1; ++l) {
1555 int m = (nC1 - l) / 2;
1556 c[l] = d * polyvalx(m, coeff + o, eps2) / coeff[o + m + 1];
1563void C1pf(
double eps,
double c[]) {
1564 static const double coeff[] = {
1566 205, -432, 768, 1536,
1568 4005, -4736, 3840, 12288,
1582 for (l = 1; l <= nC1p; ++l) {
1583 int m = (nC1p - l) / 2;
1584 c[l] = d * polyvalx(m, coeff + o, eps2) / coeff[o + m + 1];
1591double A2m1f(
double eps) {
1592 static const double coeff[] = {
1594 -11, -28, -192, 0, 256,
1597 double t = polyvalx(m, coeff, sq(eps)) / coeff[m + 1];
1598 return (t - eps) / (1 + eps);
1602void C2f(
double eps,
double c[]) {
1603 static const double coeff[] = {
1621 for (l = 1; l <= nC2; ++l) {
1622 int m = (nC2 - l) / 2;
1623 c[l] = d * polyvalx(m, coeff + o, eps2) / coeff[o + m + 1];
1631 static const double coeff[] = {
1645 int o = 0, k = 0, j;
1646 for (j = nA3 - 1; j >= 0; --j) {
1647 int m = nA3 - j - 1 < j ? nA3 - j - 1 : j;
1648 g->A3x[k++] = polyvalx(m, coeff + o, g->n) / coeff[o + m + 1];
1655 static const double coeff[] = {
1687 int o = 0, k = 0, l, j;
1688 for (l = 1; l < nC3; ++l) {
1689 for (j = nC3 - 1; j >= l; --j) {
1690 int m = nC3 - j - 1 < j ? nC3 - j - 1 : j;
1691 g->C3x[k++] = polyvalx(m, coeff + o, g->n) / coeff[o + m + 1];
1699 static const double coeff[] = {
1705 -224, -4784, 1573, 45045,
1707 -10656, 14144, -4576, -858, 45045,
1709 64, 624, -4576, 6864, -3003, 15015,
1711 100, 208, 572, 3432, -12012, 30030, 45045,
1717 5792, 1040, -1287, 135135,
1719 5952, -11648, 9152, -2574, 135135,
1721 -64, -624, 4576, -6864, 3003, 135135,
1727 -8448, 4992, -1144, 225225,
1729 -1440, 4160, -4576, 1716, 225225,
1735 3584, -3328, 1144, 315315,
1743 int o = 0, k = 0, l, j;
1744 for (l = 0; l < nC4; ++l) {
1745 for (j = nC4 - 1; j >= l; --j) {
1746 int m = nC4 - j - 1;
1747 g->C4x[k++] = polyvalx(m, coeff + o, g->n) / coeff[o + m + 1];
1753int transit(
double lon1,
double lon2) {
1758 lon12 = AngDiff(
lon1, lon2, NULLPTR);
1760 lon2 = AngNormalize(lon2);
1763 (
lon1 > 0 && lon2 == 0)) ? 1 :
1764 (lon12 < 0 &&
lon1 >= 0 && lon2 < 0 ? -1 : 0);
1767int transitdirect(
double lon1,
double lon2) {
1770 lon1 = remainder(
lon1, 2.0 * td); lon2 = remainder(lon2, 2.0 * td);
1771 return ( (lon2 >= 0 && lon2 < td ? 0 : 1) -
1772 (
lon1 >= 0 &&
lon1 < td ? 0 : 1) );
1775void accini(
double s[]) {
1780void acccopy(
const double s[],
double t[]) {
1782 t[0] = s[0]; t[1] = s[1];
1785void accadd(
double s[],
double y) {
1787 double u, z = sumx(y, s[1], &u);
1788 s[0] = sumx(z, s[0], &s[1]);
1795double accsum(
const double s[],
double y) {
1803void accneg(
double s[]) {
1805 s[0] = -s[0]; s[1] = -s[1];
1808void accrem(
double s[],
double y) {
1810 s[0] = remainder(s[0], y);
1815 p->polyline = (polylinep != 0);
1820 p->lat0 = p->lon0 = p->
lat = p->
lon = NaN;
1823 p->
num = p->crossings = 0;
1828 double lat,
double lon) {
1830 p->lat0 = p->
lat = lat;
1831 p->lon0 = p->
lon = lon;
1833 double s12, S12 = 0;
1835 &s12, NULLPTR, NULLPTR, NULLPTR, NULLPTR, NULLPTR,
1836 p->polyline ? NULLPTR : &S12);
1840 p->crossings += transit(p->
lon, lon);
1842 p->
lat = lat; p->
lon = lon;
1849 double azi,
double s) {
1853 double lat = 0, lon = 0, S12 = 0;
1855 &lat, &lon, NULLPTR,
1856 NULLPTR, NULLPTR, NULLPTR, NULLPTR,
1857 p->polyline ? NULLPTR : &S12);
1861 p->crossings += transitdirect(p->
lon, lon);
1863 p->
lat = lat; p->
lon = lon;
1870 boolx reverse, boolx sign,
1871 double* pA,
double* pP) {
1872 double s12, S12, t[2];
1875 if (!p->polyline && pA) *pA = 0;
1879 if (pP) *pP = p->P[0];
1883 &s12, NULLPTR, NULLPTR, NULLPTR, NULLPTR, NULLPTR, &S12);
1884 if (pP) *pP = accsum(p->P, s12);
1887 if (pA) *pA = areareduceA(t, 4 * pi * g->c2,
1888 p->crossings + transit(p->
lon, p->lon0),
1895 double lat,
double lon,
1896 boolx reverse, boolx sign,
1897 double* pA,
double* pP) {
1898 double perimeter, tempsum;
1900 unsigned num = p->
num + 1;
1903 if (!p->polyline && pA) *pA = 0;
1906 perimeter = p->P[0];
1907 tempsum = p->polyline ? 0 : p->A[0];
1908 crossings = p->crossings;
1909 for (i = 0; i < (p->polyline ? 1 : 2); ++i) {
1910 double s12, S12 = 0;
1912 i == 0 ? p->
lat : lat, i == 0 ? p->
lon : lon,
1913 i != 0 ? p->lat0 : lat, i != 0 ? p->lon0 : lon,
1914 &s12, NULLPTR, NULLPTR, NULLPTR, NULLPTR, NULLPTR,
1915 p->polyline ? NULLPTR : &S12);
1919 crossings += transit(i == 0 ? p->
lon : lon,
1920 i != 0 ? p->lon0 : lon);
1924 if (pP) *pP = perimeter;
1928 if (pA) *pA = areareduceB(tempsum, 4 * pi * g->c2, crossings, reverse, sign);
1934 double azi,
double s,
1935 boolx reverse, boolx sign,
1936 double* pA,
double* pP) {
1937 double perimeter, tempsum;
1939 unsigned num = p->
num + 1;
1942 if (!p->polyline && pA) *pA = NaN;
1945 perimeter = p->P[0] + s;
1947 if (pP) *pP = perimeter;
1952 crossings = p->crossings;
1956 double lat = 0, lon = 0, s12, S12 = 0;
1958 &lat, &lon, NULLPTR,
1959 NULLPTR, NULLPTR, NULLPTR, NULLPTR, &S12);
1961 crossings += transitdirect(p->
lon, lon);
1963 &s12, NULLPTR, NULLPTR, NULLPTR, NULLPTR, NULLPTR, &S12);
1966 crossings += transit(lon, p->lon0);
1969 if (pP) *pP = perimeter;
1970 if (pA) *pA = areareduceB(tempsum, 4 * pi * g->c2, crossings, reverse, sign);
1975 double lats[],
double lons[],
int n,
1976 double* pA,
double* pP) {
1980 for (i = 0; i < n; ++i)
1985double areareduceA(
double area[],
double area0,
1986 int crossings, boolx reverse, boolx sign) {
1987 accrem(area, area0);
1989 accadd(area, (area[0] < 0 ? 1 : -1) * area0/2);
1996 if (area[0] > area0/2)
1997 accadd(area, -area0);
1998 else if (area[0] <= -area0/2)
1999 accadd(area, +area0);
2001 if (area[0] >= area0)
2002 accadd(area, -area0);
2003 else if (area[0] < 0)
2004 accadd(area, +area0);
2009double areareduceB(
double area,
double area0,
2010 int crossings, boolx reverse, boolx sign) {
2011 area = remainder(area, area0);
2013 area += (area < 0 ? 1 : -1) * area0/2;
2022 else if (area <= -area0/2)
API for the geodesic routines in C.
double GEOD_DLL geod_gendirect(const struct geod_geodesic *g, double lat1, double lon1, double azi1, unsigned flags, double s12_a12, double *plat2, double *plon2, double *pazi2, double *ps12, double *pm12, double *pM12, double *pM21, double *pS12)
void GEOD_DLL geod_polygon_addedge(const struct geod_geodesic *g, struct geod_polygon *p, double azi, double s)
void GEOD_DLL geod_polygon_addpoint(const struct geod_geodesic *g, struct geod_polygon *p, double lat, double lon)
void GEOD_DLL geod_setdistance(struct geod_geodesicline *l, double s13)
void GEOD_DLL geod_gensetdistance(struct geod_geodesicline *l, unsigned flags, double s13_a13)
unsigned GEOD_DLL geod_polygon_testpoint(const struct geod_geodesic *g, const struct geod_polygon *p, double lat, double lon, int reverse, int sign, double *pA, double *pP)
void GEOD_DLL geod_polygon_clear(struct geod_polygon *p)
void GEOD_DLL geod_init(struct geod_geodesic *g, double a, double f)
void GEOD_DLL geod_directline(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double azi1, double s12, unsigned caps)
void GEOD_DLL geod_inverse(const struct geod_geodesic *g, double lat1, double lon1, double lat2, double lon2, double *ps12, double *pazi1, double *pazi2)
unsigned GEOD_DLL geod_polygon_testedge(const struct geod_geodesic *g, const struct geod_polygon *p, double azi, double s, int reverse, int sign, double *pA, double *pP)
void GEOD_DLL geod_lineinit(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double azi1, unsigned caps)
unsigned GEOD_DLL geod_polygon_compute(const struct geod_geodesic *g, const struct geod_polygon *p, int reverse, int sign, double *pA, double *pP)
void GEOD_DLL geod_position(const struct geod_geodesicline *l, double s12, double *plat2, double *plon2, double *pazi2)
double GEOD_DLL geod_geninverse(const struct geod_geodesic *g, double lat1, double lon1, double lat2, double lon2, double *ps12, double *pazi1, double *pazi2, double *pm12, double *pM12, double *pM21, double *pS12)
double GEOD_DLL geod_genposition(const struct geod_geodesicline *l, unsigned flags, double s12_a12, double *plat2, double *plon2, double *pazi2, double *ps12, double *pm12, double *pM12, double *pM21, double *pS12)
void GEOD_DLL geod_direct(const struct geod_geodesic *g, double lat1, double lon1, double azi1, double s12, double *plat2, double *plon2, double *pazi2)
void GEOD_DLL geod_polygonarea(const struct geod_geodesic *g, double lats[], double lons[], int n, double *pA, double *pP)
void GEOD_DLL geod_inverseline(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double lat2, double lon2, unsigned caps)
void GEOD_DLL geod_gendirectline(struct geod_geodesicline *l, const struct geod_geodesic *g, double lat1, double lon1, double azi1, unsigned flags, double s12_a12, unsigned caps)
void GEOD_DLL geod_polygon_init(struct geod_polygon *p, int polylinep)