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