C library for Geodesics: geodesic.c Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

27 #include <math.h>

28 #include <float.h>

29

30 #if !defined(__cplusplus)

31 #define nullptr 0

32 #endif

33

34 #define GEOGRAPHICLIB_GEODESIC_ORDER 6

35 #define nA1 GEOGRAPHICLIB_GEODESIC_ORDER

36 #define nC1 GEOGRAPHICLIB_GEODESIC_ORDER

37 #define nC1p GEOGRAPHICLIB_GEODESIC_ORDER

38 #define nA2 GEOGRAPHICLIB_GEODESIC_ORDER

39 #define nC2 GEOGRAPHICLIB_GEODESIC_ORDER

40 #define nA3 GEOGRAPHICLIB_GEODESIC_ORDER

41 #define nA3x nA3

42 #define nC3 GEOGRAPHICLIB_GEODESIC_ORDER

43 #define nC3x ((nC3 * (nC3 - 1)) / 2)

44 #define nC4 GEOGRAPHICLIB_GEODESIC_ORDER

45 #define nC4x ((nC4 * (nC4 + 1)) / 2)

46 #define nC (GEOGRAPHICLIB_GEODESIC_ORDER + 1)

47

48 typedef int boolx;

49 enum booly { FALSE = 0, TRUE = 1 };

50

51

52

53 enum dms { qd = 90, hd = 2 * qd, td = 2 * hd };

54

55 static unsigned init = 0;

56 static unsigned digits, maxit1, maxit2;

57 static double epsilon, realmin, pi, degree, NaN,

58 tiny, tol0, tol1, tol2, tolb, xthresh;

59

60 static void Init(void) {

61 if (!init) {

62 digits = DBL_MANT_DIG;

63 epsilon = DBL_EPSILON;

64 realmin = DBL_MIN;

65 #if defined(M_PI)

66 pi = M_PI;

67 #else

68 pi = atan2(0.0, -1.0);

69 #endif

70 maxit1 = 20;

71 maxit2 = maxit1 + digits + 10;

72 tiny = sqrt(realmin);

73 tol0 = epsilon;

74

75

76

77 tol1 = 200 * tol0;

78 tol2 = sqrt(tol0);

79

80 tolb = tol0;

81 xthresh = 1000 * tol2;

82 degree = pi/hd;

83 NaN = nan("0");

84 init = 1;

85 }

86 }

87

88 enum captype {

89 CAP_NONE = 0U,

90 CAP_C1 = 1U<<0,

91 CAP_C1p = 1U<<1,

92 CAP_C2 = 1U<<2,

93 CAP_C3 = 1U<<3,

94 CAP_C4 = 1U<<4,

95 CAP_ALL = 0x1FU,

96 OUT_ALL = 0x7F80U

97 };

98

99 static double sq(double x) { return x * x; }

100

101 static double sumx(double u, double v, double* t) {

102 volatile double s = u + v;

103 volatile double up = s - v;

104 volatile double vpp = s - up;

105 up -= u;

106 vpp -= v;

107 if (t) *t = s != 0 ? 0 - (up + vpp) : s;

108

109

110

111 return s;

112 }

113

114 static double polyvalx(int N, const double p[], double x) {

115 double y = N < 0 ? 0 : *p++;

116 while (--N >= 0) y = y * x + *p++;

117 return y;

118 }

119

120 static void swapx(double* x, double* y)

121 { double t = *x; *x = *y; *y = t; }

122

123 static void norm2(double* sinx, double* cosx) {

124 #if defined(_MSC_VER) && defined(_M_IX86)

125

126

127

128

129

130

131

132

133 double r = sqrt(*sinx * *sinx + *cosx * *cosx);

134 #else

135 double r = hypot(*sinx, *cosx);

136 #endif

137 *sinx /= r;

138 *cosx /= r;

139 }

140

141 static double AngNormalize(double x) {

142 double y = remainder(x, (double)td);

143 return fabs(y) == hd ? copysign((double)hd, x) : y;

144 }

145

146 static double LatFix(double x)

147 { return fabs(x) > qd ? NaN : x; }

148

149 static double AngDiff(double x, double y, double* e) {

150

151

152 double t, d = sumx(remainder(-x, (double)td), remainder( y, (double)td), &t);

153

154

155 d = sumx(remainder(d, (double)td), t, &t);

156

157 if (d == 0 || fabs(d) == hd)

158

159

160 d = copysign(d, t == 0 ? y - x : -t);

161 if (e) *e = t;

162 return d;

163 }

164

165 static double AngRound(double x) {

166

167 const double z = 1.0/16.0;

168 volatile double y = fabs(x);

169 volatile double w = z - y;

170

171 y = w > 0 ? z - w : y;

172 return copysign(y, x);

173 }

174

175 static void sincosdx(double x, double* sinx, double* cosx) {

176

177

178 double r, s, c; int q = 0;

179 r = remquo(x, (double)qd, &q);

180

181 r *= degree;

182

183 s = sin(r); c = cos(r);

184 switch ((unsigned)q & 3U) {

185 case 0U: *sinx = s; *cosx = c; break;

186 case 1U: *sinx = c; *cosx = -s; break;

187 case 2U: *sinx = -s; *cosx = -c; break;

188 default: *sinx = -c; *cosx = s; break;

189 }

190

191 *cosx += 0;

192

193 if (*sinx == 0) *sinx = copysign(*sinx, x);

194 }

195

196 static void sincosde(double x, double t, double* sinx, double* cosx) {

197

198

199 double r, s, c; int q = 0;

200 r = AngRound(remquo(x, (double)qd, &q) + t);

201

202 r *= degree;

203

204 s = sin(r); c = cos(r);

205 switch ((unsigned)q & 3U) {

206 case 0U: *sinx = s; *cosx = c; break;

207 case 1U: *sinx = c; *cosx = -s; break;

208 case 2U: *sinx = -s; *cosx = -c; break;

209 default: *sinx = -c; *cosx = s; break;

210 }

211

212 *cosx += 0;

213

214 if (*sinx == 0) *sinx = copysign(*sinx, x);

215 }

216

217 static double atan2dx(double y, double x) {

218

219

220

221

222 int q = 0; double ang;

223 if (fabs(y) > fabs(x)) { swapx(&x, &y); q = 2; }

224 if (signbit(x)) { x = -x; ++q; }

225

226 ang = atan2(y, x) / degree;

227 switch (q) {

228 case 1: ang = copysign((double)hd, y) - ang; break;

229 case 2: ang = qd - ang; break;

230 case 3: ang = -qd + ang; break;

231 default: break;

232 }

233 return ang;

234 }

235

239 static double SinCosSeries(boolx sinp,

240 double sinx, double cosx,

241 const double c[], int n);

242 static void Lengths(const struct geod_geodesic* g,

243 double eps, double sig12,

244 double ssig1, double csig1, double dn1,

245 double ssig2, double csig2, double dn2,

246 double cbet1, double cbet2,

247 double* ps12b, double* pm12b, double* pm0,

248 double* pM12, double* pM21,

249

250 double Ca[]);

251 static double Astroid(double x, double y);

252 static double InverseStart(const struct geod_geodesic* g,

253 double sbet1, double cbet1, double dn1,

254 double sbet2, double cbet2, double dn2,

255 double lam12, double slam12, double clam12,

256 double* psalp1, double* pcalp1,

257

258 double* psalp2, double* pcalp2,

259

260 double* pdnm,

261

262 double Ca[]);

263 static double Lambda12(const struct geod_geodesic* g,

264 double sbet1, double cbet1, double dn1,

265 double sbet2, double cbet2, double dn2,

266 double salp1, double calp1,

267 double slam120, double clam120,

268 double* psalp2, double* pcalp2,

269 double* psig12,

270 double* pssig1, double* pcsig1,

271 double* pssig2, double* pcsig2,

272 double* peps,

273 double* pdomg12,

274 boolx diffp, double* pdlam12,

275

276 double Ca[]);

277 static double A3f(const struct geod_geodesic* g, double eps);

278 static void C3f(const struct geod_geodesic* g, double eps, double c[]);

279 static void C4f(const struct geod_geodesic* g, double eps, double c[]);

280 static double A1m1f(double eps);

281 static void C1f(double eps, double c[]);

282 static void C1pf(double eps, double c[]);

283 static double A2m1f(double eps);

284 static void C2f(double eps, double c[]);

285 static int transit(double lon1, double lon2);

286 static int transitdirect(double lon1, double lon2);

287 static void accini(double s[]);

288 static void acccopy(const double s[], double t[]);

289 static void accadd(double s[], double y);

290 static double accsum(const double s[], double y);

291 static void accneg(double s[]);

292 static void accrem(double s[], double y);

293 static double areareduceA(double area[], double area0,

294 int crossings, boolx reverse, boolx sign);

295 static double areareduceB(double area, double area0,

296 int crossings, boolx reverse, boolx sign);

297

299 if (!init) Init();

300 g->a = a;

301 g->f = f;

302 g->f1 = 1 - g->f;

303 g->e2 = g->f * (2 - g->f);

304 g->ep2 = g->e2 / sq(g->f1);

305 g->n = g->f / ( 2 - g->f);

306 g->b = g->a * g->f1;

307 g->c2 = (sq(g->a) + sq(g->b) *

308 (g->e2 == 0 ? 1 :

309 (g->e2 > 0 ? atanh(sqrt(g->e2)) : atan(sqrt(-g->e2))) /

310 sqrt(fabs(g->e2))))/2;

311

312

313

314

315

316

317

318

319

320 g->etol2 = 0.1 * tol2 /

321 sqrt( fmax(0.001, fabs(g->f)) * fmin(1.0, 1 - g->f/2) / 2 );

322

323 A3coeff(g);

324 C3coeff(g);

325 C4coeff(g);

326 }

327

330 double lat1, double lon1,

331 double azi1, double salp1, double calp1,

332 unsigned caps) {

333 double cbet1, sbet1, eps;

334 l->a = g->a;

335 l->f = g->f;

336 l->b = g->b;

337 l->c2 = g->c2;

338 l->f1 = g->f1;

339

341

343

344 l->lat1 = LatFix(lat1);

345 l->lon1 = lon1;

346 l->azi1 = azi1;

347 l->salp1 = salp1;

348 l->calp1 = calp1;

349

350 sincosdx(AngRound(l->lat1), &sbet1, &cbet1); sbet1 *= l->f1;

351

352 norm2(&sbet1, &cbet1); cbet1 = fmax(tiny, cbet1);

353 l->dn1 = sqrt(1 + g->ep2 * sq(sbet1));

354

355

356 l->salp0 = l->salp1 * cbet1;

357

358

359 l->calp0 = hypot(l->calp1, l->salp1 * sbet1);

360

361

362

363

364

365

366

367

368

369 l->ssig1 = sbet1; l->somg1 = l->salp0 * sbet1;

370 l->csig1 = l->comg1 = sbet1 != 0 || l->calp1 != 0 ? cbet1 * l->calp1 : 1;

371 norm2(&l->ssig1, &l->csig1);

372

373

374 l->k2 = sq(l->calp0) * g->ep2;

375 eps = l->k2 / (2 * (1 + sqrt(1 + l->k2)) + l->k2);

376

377 if (l->caps & CAP_C1) {

378 double s, c;

379 l->A1m1 = A1m1f(eps);

380 C1f(eps, l->C1a);

381 l->B11 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C1a, nC1);

382 s = sin(l->B11); c = cos(l->B11);

383

384 l->stau1 = l->ssig1 * c + l->csig1 * s;

385 l->ctau1 = l->csig1 * c - l->ssig1 * s;

386

387

388 }

389

390 if (l->caps & CAP_C1p)

391 C1pf(eps, l->C1pa);

392

393 if (l->caps & CAP_C2) {

394 l->A2m1 = A2m1f(eps);

395 C2f(eps, l->C2a);

396 l->B21 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C2a, nC2);

397 }

398

399 if (l->caps & CAP_C3) {

400 C3f(g, eps, l->C3a);

401 l->A3c = -l->f * l->salp0 * A3f(g, eps);

402 l->B31 = SinCosSeries(TRUE, l->ssig1, l->csig1, l->C3a, nC3-1);

403 }

404

405 if (l->caps & CAP_C4) {

406 C4f(g, eps, l->C4a);

407

408 l->A4 = sq(l->a) * l->calp0 * l->salp0 * g->e2;

409 l->B41 = SinCosSeries(FALSE, l->ssig1, l->csig1, l->C4a, nC4);

410 }

411

412 l->a13 = l->s13 = NaN;

413 }

414

417 double lat1, double lon1, double azi1, unsigned caps) {

418 double salp1, calp1;

419 azi1 = AngNormalize(azi1);

420

421 sincosdx(AngRound(azi1), &salp1, &calp1);

422 geod_lineinit_int(l, g, lat1, lon1, azi1, salp1, calp1, caps);

423 }

424

427 double lat1, double lon1, double azi1,

428 unsigned flags, double s12_a12,

429 unsigned caps) {

432 }

433

436 double lat1, double lon1, double azi1,

437 double s12, unsigned caps) {

439 }

440

442 unsigned flags, double s12_a12,

443 double* plat2, double* plon2, double* pazi2,

444 double* ps12, double* pm12,

445 double* pM12, double* pM21,

446 double* pS12) {

447 double lat2 = 0, lon2 = 0, azi2 = 0, s12 = 0,

448 m12 = 0, M12 = 0, M21 = 0, S12 = 0;

449

450 double sig12, ssig12, csig12, B12 = 0, AB1 = 0;

451 double omg12, lam12, lon12;

452 double ssig2, csig2, sbet2, cbet2, somg2, comg2, salp2, calp2, dn2;

453 unsigned outmask =

461

462 outmask &= l->caps & OUT_ALL;

464

465 return NaN;

466

468

469 sig12 = s12_a12 * degree;

470 sincosdx(s12_a12, &ssig12, &csig12);

471 } else {

472

473 double

474 tau12 = s12_a12 / (l->b * (1 + l->A1m1)),

475 s = sin(tau12),

476 c = cos(tau12);

477

478 B12 = - SinCosSeries(TRUE,

479 l->stau1 * c + l->ctau1 * s,

480 l->ctau1 * c - l->stau1 * s,

481 l->C1pa, nC1p);

482 sig12 = tau12 - (B12 - l->B11);

483 ssig12 = sin(sig12); csig12 = cos(sig12);

484 if (fabs(l->f) > 0.01) {

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506 double serr;

507 ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12;

508 csig2 = l->csig1 * csig12 - l->ssig1 * ssig12;

509 B12 = SinCosSeries(TRUE, ssig2, csig2, l->C1a, nC1);

510 serr = (1 + l->A1m1) * (sig12 + (B12 - l->B11)) - s12_a12 / l->b;

511 sig12 = sig12 - serr / sqrt(1 + l->k2 * sq(ssig2));

512 ssig12 = sin(sig12); csig12 = cos(sig12);

513

514 }

515 }

516

517

518 ssig2 = l->ssig1 * csig12 + l->csig1 * ssig12;

519 csig2 = l->csig1 * csig12 - l->ssig1 * ssig12;

520 dn2 = sqrt(1 + l->k2 * sq(ssig2));

523 B12 = SinCosSeries(TRUE, ssig2, csig2, l->C1a, nC1);

524 AB1 = (1 + l->A1m1) * (B12 - l->B11);

525 }

526

527 sbet2 = l->calp0 * ssig2;

528

529 cbet2 = hypot(l->salp0, l->calp0 * csig2);

530 if (cbet2 == 0)

531

532 cbet2 = csig2 = tiny;

533

534 salp2 = l->salp0; calp2 = l->calp0 * csig2;

535

538 l->b * ((1 + l->A1m1) * sig12 + AB1) :

539 s12_a12;

540

542 double E = copysign(1, l->salp0);

543

544 somg2 = l->salp0 * ssig2; comg2 = csig2;

545

547 ? E * (sig12

548 - (atan2( ssig2, csig2) - atan2( l->ssig1, l->csig1))

549 + (atan2(E * somg2, comg2) - atan2(E * l->somg1, l->comg1)))

550 : atan2(somg2 * l->comg1 - comg2 * l->somg1,

551 comg2 * l->comg1 + somg2 * l->somg1);

552 lam12 = omg12 + l->A3c *

553 ( sig12 + (SinCosSeries(TRUE, ssig2, csig2, l->C3a, nC3-1)

554 - l->B31));

555 lon12 = lam12 / degree;

557 AngNormalize(AngNormalize(l->lon1) + AngNormalize(lon12));

558 }

559

561 lat2 = atan2dx(sbet2, l->f1 * cbet2);

562

564 azi2 = atan2dx(salp2, calp2);

565

567 double

568 B22 = SinCosSeries(TRUE, ssig2, csig2, l->C2a, nC2),

569 AB2 = (1 + l->A2m1) * (B22 - l->B21),

570 J12 = (l->A1m1 - l->A2m1) * sig12 + (AB1 - AB2);

572

573

574 m12 = l->b * ((dn2 * (l->csig1 * ssig2) - l->dn1 * (l->ssig1 * csig2))

575 - l->csig1 * csig2 * J12);

577 double t = l->k2 * (ssig2 - l->ssig1) * (ssig2 + l->ssig1) /

578 (l->dn1 + dn2);

579 M12 = csig12 + (t * ssig2 - csig2 * J12) * l->ssig1 / l->dn1;

580 M21 = csig12 - (t * l->ssig1 - l->csig1 * J12) * ssig2 / dn2;

581 }

582 }

583

585 double

586 B42 = SinCosSeries(FALSE, ssig2, csig2, l->C4a, nC4);

587 double salp12, calp12;

588 if (l->calp0 == 0 || l->salp0 == 0) {

589

590 salp12 = salp2 * l->calp1 - calp2 * l->salp1;

591 calp12 = calp2 * l->calp1 + salp2 * l->salp1;

592 } else {

593

594

595

596

597

598

599

600

601 salp12 = l->calp0 * l->salp0 *

602 (csig12 <= 0 ? l->csig1 * (1 - csig12) + ssig12 * l->ssig1 :

603 ssig12 * (l->csig1 * ssig12 / (1 + csig12) + l->ssig1));

604 calp12 = sq(l->salp0) + sq(l->calp0) * l->csig1 * csig2;

605 }

606 S12 = l->c2 * atan2(salp12, calp12) + l->A4 * (B42 - l->B41);

607 }

608

609

610

611

612

613

614

615

616

618 *plat2 = lat2;

620 *plon2 = lon2;

622 *pazi2 = azi2;

624 *ps12 = s12;

626 *pm12 = m12;

628 if (pM12) *pM12 = M12;

629 if (pM21) *pM21 = M21;

630 }

631 if ((outmask & GEOD_AREA) && pS12)

632 *pS12 = S12;

633

634 return (flags & GEOD_ARCMODE) ? s12_a12 : sig12 / degree;

635 }

636

638 l->s13 = s13;

640 nullptr, nullptr, nullptr, nullptr, nullptr);

641 }

642

643 static void geod_setarc(struct geod_geodesicline* l, double a13) {

644 l->a13 = a13; l->s13 = NaN;

646 nullptr, nullptr, nullptr, nullptr);

647 }

648

650 unsigned flags, double s13_a13) {

652 geod_setarc(l, s13_a13) :

654 }

655

657 double* plat2, double* plon2, double* pazi2) {

659 nullptr, nullptr, nullptr, nullptr, nullptr);

660 }

661

663 double lat1, double lon1, double azi1,

664 unsigned flags, double s12_a12,

665 double* plat2, double* plon2, double* pazi2,

666 double* ps12, double* pm12, double* pM12, double* pM21,

667 double* pS12) {

669 unsigned outmask =

677

679

680 outmask |

683 plat2, plon2, pazi2, ps12, pm12, pM12, pM21, pS12);

684 }

685

688 double s12,

689 double* plat2, double* plon2, double* pazi2) {

691 nullptr, nullptr, nullptr, nullptr, nullptr);

692 }

693

694 static double geod_geninverse_int(const struct geod_geodesic* g,

696 double lat2, double lon2,

697 double* ps12,

698 double* psalp1, double* pcalp1,

699 double* psalp2, double* pcalp2,

700 double* pm12, double* pM12, double* pM21,

701 double* pS12) {

702 double s12 = 0, m12 = 0, M12 = 0, M21 = 0, S12 = 0;

703 double lon12, lon12s;

704 int latsign, lonsign, swapp;

705 double sbet1, cbet1, sbet2, cbet2, s12x = 0, m12x = 0;

706 double dn1, dn2, lam12, slam12, clam12;

707 double a12 = 0, sig12, calp1 = 0, salp1 = 0, calp2 = 0, salp2 = 0;

708 double Ca[nC];

709 boolx meridian;

710

711 double omg12 = 0, somg12 = 2, comg12 = 0;

712

713 unsigned outmask =

718

719 outmask &= OUT_ALL;

720

721

722

723 lon12 = AngDiff(lon1, lon2, &lon12s);

724

725 lonsign = signbit(lon12) ? -1 : 1;

726 lon12 *= lonsign; lon12s *= lonsign;

727 lam12 = lon12 * degree;

728

729 sincosde(lon12, lon12s, &slam12, &clam12);

730 lon12s = (hd - lon12) - lon12s;

731

732

733 lat1 = AngRound(LatFix(lat1));

734 lat2 = AngRound(LatFix(lat2));

735

736

737 swapp = fabs(lat1) < fabs(lat2) || lat2 != lat2 ? -1 : 1;

738 if (swapp < 0) {

739 lonsign *= -1;

740 swapx(&lat1, &lat2);

741 }

742

743 latsign = signbit(lat1) ? 1 : -1;

744 lat1 *= latsign;

745 lat2 *= latsign;

746

747

748

749

750

751

752

753

754

755

756

757

758 sincosdx(lat1, &sbet1, &cbet1); sbet1 *= g->f1;

759

760 norm2(&sbet1, &cbet1); cbet1 = fmax(tiny, cbet1);

761

762 sincosdx(lat2, &sbet2, &cbet2); sbet2 *= g->f1;

763

764 norm2(&sbet2, &cbet2); cbet2 = fmax(tiny, cbet2);

765

766

767

768

769

770

771

772

773

774 if (cbet1 < -sbet1) {

775 if (cbet2 == cbet1)

776 sbet2 = copysign(sbet1, sbet2);

777 } else {

778 if (fabs(sbet2) == -sbet1)

779 cbet2 = cbet1;

780 }

781

782 dn1 = sqrt(1 + g->ep2 * sq(sbet1));

783 dn2 = sqrt(1 + g->ep2 * sq(sbet2));

784

785 meridian = lat1 == -qd || slam12 == 0;

786

787 if (meridian) {

788

789

790

791

792 double ssig1, csig1, ssig2, csig2;

793 calp1 = clam12; salp1 = slam12;

794 calp2 = 1; salp2 = 0;

795

796

797 ssig1 = sbet1; csig1 = calp1 * cbet1;

798 ssig2 = sbet2; csig2 = calp2 * cbet2;

799

800

801 sig12 = atan2(fmax(0.0, csig1 * ssig2 - ssig1 * csig2) + 0,

802 csig1 * csig2 + ssig1 * ssig2);

803 Lengths(g, g->n, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,

804 cbet1, cbet2, &s12x, &m12x, nullptr,

807 Ca);

808

809

810

811

812

813

814

815 if (sig12 < 1 || m12x >= 0) {

816

817 if (sig12 < 3 * tiny ||

818

819 (sig12 < tol0 && (s12x < 0 || m12x < 0)))

820 sig12 = m12x = s12x = 0;

821 m12x *= g->b;

822 s12x *= g->b;

823 a12 = sig12 / degree;

824 } else

825

826 meridian = FALSE;

827 }

828

829 if (!meridian &&

830 sbet1 == 0 &&

831

832 (g->f <= 0 || lon12s >= g->f * hd)) {

833

834

835 calp1 = calp2 = 0; salp1 = salp2 = 1;

836 s12x = g->a * lam12;

837 sig12 = omg12 = lam12 / g->f1;

838 m12x = g->b * sin(sig12);

840 M12 = M21 = cos(sig12);

841 a12 = lon12 / g->f1;

842

843 } else if (!meridian) {

844

845

846

847

848

849 double dnm = 0;

850 sig12 = InverseStart(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2,

851 lam12, slam12, clam12,

852 &salp1, &calp1, &salp2, &calp2, &dnm,

853 Ca);

854

855 if (sig12 >= 0) {

856

857 s12x = sig12 * g->b * dnm;

858 m12x = sq(dnm) * g->b * sin(sig12 / dnm);

860 M12 = M21 = cos(sig12 / dnm);

861 a12 = sig12 / degree;

862 omg12 = lam12 / (g->f1 * dnm);

863 } else {

864

865

866

867

868

869

870

871

872

873

874

875

876 double ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0, domg12 = 0;

877 unsigned numit = 0;

878

879 double salp1a = tiny, calp1a = 1, salp1b = tiny, calp1b = -1;

880 boolx tripn = FALSE;

881 boolx tripb = FALSE;

882 for (;; ++numit) {

883

884

885 double dv = 0,

886 v = Lambda12(g, sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1,

887 slam12, clam12,

888 &salp2, &calp2, &sig12, &ssig1, &csig1, &ssig2, &csig2,

889 &eps, &domg12, numit < maxit1, &dv, Ca);

890 if (tripb ||

891

892 !(fabs(v) >= (tripn ? 8 : 1) * tol0) ||

893

894 numit == maxit2)

895 break;

896

897 if (v > 0 && (numit > maxit1 || calp1/salp1 > calp1b/salp1b))

899 else if (v < 0 && (numit > maxit1 || calp1/salp1 < calp1a/salp1a))

901 if (numit < maxit1 && dv > 0) {

902 double

903 dalp1 = -v/dv;

904 if (fabs(dalp1) < pi) {

905 double

906 sdalp1 = sin(dalp1), cdalp1 = cos(dalp1),

907 nsalp1 = salp1 * cdalp1 + calp1 * sdalp1;

908 if (nsalp1 > 0) {

912

913

914

915 tripn = fabs(v) <= 16 * tol0;

916 continue;

917 }

918 }

919 }

920

921

922

923

924

925

926

927

928 salp1 = (salp1a + salp1b)/2;

929 calp1 = (calp1a + calp1b)/2;

931 tripn = FALSE;

932 tripb = (fabs(salp1a - salp1) + (calp1a - calp1) < tolb ||

933 fabs(salp1 - salp1b) + (calp1 - calp1b) < tolb);

934 }

935 Lengths(g, eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,

936 cbet1, cbet2, &s12x, &m12x, nullptr,

939 m12x *= g->b;

940 s12x *= g->b;

941 a12 = sig12 / degree;

943

944 double sdomg12 = sin(domg12), cdomg12 = cos(domg12);

945 somg12 = slam12 * cdomg12 - clam12 * sdomg12;

946 comg12 = clam12 * cdomg12 + slam12 * sdomg12;

947 }

948 }

949 }

950

952 s12 = 0 + s12x;

953

955 m12 = 0 + m12x;

956

958 double

959

960 salp0 = salp1 * cbet1,

961 calp0 = hypot(calp1, salp1 * sbet1);

962 double alp12;

963 if (calp0 != 0 && salp0 != 0) {

964 double

965

966 ssig1 = sbet1, csig1 = calp1 * cbet1,

967 ssig2 = sbet2, csig2 = calp2 * cbet2,

968 k2 = sq(calp0) * g->ep2,

969 eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2),

970

971 A4 = sq(g->a) * calp0 * salp0 * g->e2;

972 double B41, B42;

973 norm2(&ssig1, &csig1);

974 norm2(&ssig2, &csig2);

975 C4f(g, eps, Ca);

976 B41 = SinCosSeries(FALSE, ssig1, csig1, Ca, nC4);

977 B42 = SinCosSeries(FALSE, ssig2, csig2, Ca, nC4);

978 S12 = A4 * (B42 - B41);

979 } else

980

981 S12 = 0;

982

983 if (!meridian && somg12 == 2) {

984 somg12 = sin(omg12); comg12 = cos(omg12);

985 }

986

987 if (!meridian &&

988

989 comg12 > -0.7071 &&

990 sbet2 - sbet1 < 1.75) {

991

992

993

994 double

995 domg12 = 1 + comg12, dbet1 = 1 + cbet1, dbet2 = 1 + cbet2;

996 alp12 = 2 * atan2( somg12 * ( sbet1 * dbet2 + sbet2 * dbet1 ),

997 domg12 * ( sbet1 * sbet2 + dbet1 * dbet2 ) );

998 } else {

999

1000 double

1001 salp12 = salp2 * calp1 - calp2 * salp1,

1002 calp12 = calp2 * calp1 + salp2 * salp1;

1003

1004

1005

1006

1007 if (salp12 == 0 && calp12 < 0) {

1008 salp12 = tiny * calp1;

1009 calp12 = -1;

1010 }

1011 alp12 = atan2(salp12, calp12);

1012 }

1013 S12 += g->c2 * alp12;

1014 S12 *= swapp * lonsign * latsign;

1015

1016 S12 += 0;

1017 }

1018

1019

1020 if (swapp < 0) {

1021 swapx(&salp1, &salp2);

1022 swapx(&calp1, &calp2);

1024 swapx(&M12, &M21);

1025 }

1026

1027 salp1 *= swapp * lonsign; calp1 *= swapp * latsign;

1028 salp2 *= swapp * lonsign; calp2 *= swapp * latsign;

1029

1030 if (psalp1) *psalp1 = salp1;

1031 if (pcalp1) *pcalp1 = calp1;

1032 if (psalp2) *psalp2 = salp2;

1033 if (pcalp2) *pcalp2 = calp2;

1034

1036 *ps12 = s12;

1038 *pm12 = m12;

1040 if (pM12) *pM12 = M12;

1041 if (pM21) *pM21 = M21;

1042 }

1044 *pS12 = S12;

1045

1046

1047 return a12;

1048 }

1049

1051 double lat1, double lon1, double lat2, double lon2,

1052 double* ps12, double* pazi1, double* pazi2,

1053 double* pm12, double* pM12, double* pM21,

1054 double* pS12) {

1056 a12 = geod_geninverse_int(g, lat1, lon1, lat2, lon2, ps12,

1058 pm12, pM12, pM21, pS12);

1059 if (pazi1) *pazi1 = atan2dx(salp1, calp1);

1060 if (pazi2) *pazi2 = atan2dx(salp2, calp2);

1061 return a12;

1062 }

1063

1066 double lat1, double lon1, double lat2, double lon2,

1067 unsigned caps) {

1069 a12 = geod_geninverse_int(g, lat1, lon1, lat2, lon2, nullptr,

1071 nullptr, nullptr, nullptr, nullptr),

1074

1077 geod_setarc(l, a12);

1078 }

1079

1081 double lat1, double lon1, double lat2, double lon2,

1082 double* ps12, double* pazi1, double* pazi2) {

1084 nullptr, nullptr, nullptr, nullptr);

1085 }

1086

1087 double SinCosSeries(boolx sinp, double sinx, double cosx,

1088 const double c[], int n) {

1089

1090

1091

1092

1093

1094 double ar, y0, y1;

1095 c += (n + sinp);

1096 ar = 2 * (cosx - sinx) * (cosx + sinx);

1097 y0 = (n & 1) ? *--c : 0; y1 = 0;

1098

1099 n /= 2;

1100 while (n--) {

1101

1102 y1 = ar * y0 - y1 + *--c;

1103 y0 = ar * y1 - y0 + *--c;

1104 }

1105 return sinp

1106 ? 2 * sinx * cosx * y0

1107 : cosx * (y0 - y1);

1108 }

1109

1111 double eps, double sig12,

1112 double ssig1, double csig1, double dn1,

1113 double ssig2, double csig2, double dn2,

1114 double cbet1, double cbet2,

1115 double* ps12b, double* pm12b, double* pm0,

1116 double* pM12, double* pM21,

1117

1118 double Ca[]) {

1119 double m0 = 0, J12 = 0, A1 = 0, A2 = 0;

1120 double Cb[nC];

1121

1122

1123

1124 boolx redlp = pm12b || pm0 || pM12 || pM21;

1125 if (ps12b || redlp) {

1126 A1 = A1m1f(eps);

1127 C1f(eps, Ca);

1128 if (redlp) {

1129 A2 = A2m1f(eps);

1130 C2f(eps, Cb);

1131 m0 = A1 - A2;

1132 A2 = 1 + A2;

1133 }

1134 A1 = 1 + A1;

1135 }

1136 if (ps12b) {

1137 double B1 = SinCosSeries(TRUE, ssig2, csig2, Ca, nC1) -

1138 SinCosSeries(TRUE, ssig1, csig1, Ca, nC1);

1139

1140 *ps12b = A1 * (sig12 + B1);

1141 if (redlp) {

1142 double B2 = SinCosSeries(TRUE, ssig2, csig2, Cb, nC2) -

1143 SinCosSeries(TRUE, ssig1, csig1, Cb, nC2);

1144 J12 = m0 * sig12 + (A1 * B1 - A2 * B2);

1145 }

1146 } else if (redlp) {

1147

1148 int l;

1149 for (l = 1; l <= nC2; ++l)

1150 Cb[l] = A1 * Ca[l] - A2 * Cb[l];

1151 J12 = m0 * sig12 + (SinCosSeries(TRUE, ssig2, csig2, Cb, nC2) -

1152 SinCosSeries(TRUE, ssig1, csig1, Cb, nC2));

1153 }

1154 if (pm0) *pm0 = m0;

1155 if (pm12b)

1156

1157

1158

1159 *pm12b = dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) -

1160 csig1 * csig2 * J12;

1161 if (pM12 || pM21) {

1162 double csig12 = csig1 * csig2 + ssig1 * ssig2;

1163 double t = g->ep2 * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2);

1164 if (pM12)

1165 *pM12 = csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1;

1166 if (pM21)

1167 *pM21 = csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2;

1168 }

1169 }

1170

1171 double Astroid(double x, double y) {

1172

1173

1174 double k;

1175 double

1176 p = sq(x),

1177 q = sq(y),

1178 r = (p + q - 1) / 6;

1179 if ( !(q == 0 && r <= 0) ) {

1180 double

1181

1182

1183 S = p * q / 4,

1184 r2 = sq(r),

1185 r3 = r * r2,

1186

1187

1188 disc = S * (S + 2 * r3);

1189 double u = r;

1190 double v, uv, w;

1191 if (disc >= 0) {

1192 double T3 = S + r3, T;

1193

1194

1195

1196 T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc);

1197

1198 T = cbrt(T3);

1199

1200 u += T + (T != 0 ? r2 / T : 0);

1201 } else {

1202

1203 double ang = atan2(sqrt(-disc), -(S + r3));

1204

1205

1206 u += 2 * r * cos(ang / 3);

1207 }

1208 v = sqrt(sq(u) + q);

1209

1210 uv = u < 0 ? q / (v - u) : u + v;

1211 w = (uv - q) / (2 * v);

1212

1213

1214 k = uv / (sqrt(uv + sq(w)) + w);

1215 } else {

1216

1217

1218 k = 0;

1219 }

1220 return k;

1221 }

1222

1223 double InverseStart(const struct geod_geodesic* g,

1224 double sbet1, double cbet1, double dn1,

1225 double sbet2, double cbet2, double dn2,

1226 double lam12, double slam12, double clam12,

1227 double* psalp1, double* pcalp1,

1228

1229 double* psalp2, double* pcalp2,

1230

1231 double* pdnm,

1232

1233 double Ca[]) {

1234 double salp1 = 0, calp1 = 0, salp2 = 0, calp2 = 0, dnm = 0;

1235

1236

1237

1238

1239 double

1240 sig12 = -1,

1241

1242 sbet12 = sbet2 * cbet1 - cbet2 * sbet1,

1243 cbet12 = cbet2 * cbet1 + sbet2 * sbet1;

1244 double sbet12a;

1245 boolx shortline = cbet12 >= 0 && sbet12 < 0.5 && cbet2 * lam12 < 0.5;

1246 double somg12, comg12, ssig12, csig12;

1247 sbet12a = sbet2 * cbet1 + cbet2 * sbet1;

1248 if (shortline) {

1249 double sbetm2 = sq(sbet1 + sbet2), omg12;

1250

1251

1252 sbetm2 /= sbetm2 + sq(cbet1 + cbet2);

1253 dnm = sqrt(1 + g->ep2 * sbetm2);

1254 omg12 = lam12 / (g->f1 * dnm);

1255 somg12 = sin(omg12); comg12 = cos(omg12);

1256 } else {

1257 somg12 = slam12; comg12 = clam12;

1258 }

1259

1260 salp1 = cbet2 * somg12;

1261 calp1 = comg12 >= 0 ?

1262 sbet12 + cbet2 * sbet1 * sq(somg12) / (1 + comg12) :

1263 sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12);

1264

1266 csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12;

1267

1268 if (shortline && ssig12 < g->etol2) {

1269

1270 salp2 = cbet1 * somg12;

1271 calp2 = sbet12 - cbet1 * sbet2 *

1272 (comg12 >= 0 ? sq(somg12) / (1 + comg12) : 1 - comg12);

1273 norm2(&salp2, &calp2);

1274

1275 sig12 = atan2(ssig12, csig12);

1276 } else if (fabs(g->n) > 0.1 ||

1277 csig12 >= 0 ||

1278 ssig12 >= 6 * fabs(g->n) * pi * sq(cbet1)) {

1279

1280 } else {

1281

1282

1283 double x, y, lamscale, betscale;

1284 double lam12x = atan2(-slam12, -clam12);

1285 if (g->f >= 0) {

1286

1287 {

1288 double

1289 k2 = sq(sbet1) * g->ep2,

1290 eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2);

1291 lamscale = g->f * cbet1 * A3f(g, eps) * pi;

1292 }

1293 betscale = lamscale * cbet1;

1294

1295 x = lam12x / lamscale;

1296 y = sbet12a / betscale;

1297 } else {

1298

1299 double

1300 cbet12a = cbet2 * cbet1 - sbet2 * sbet1,

1301 bet12a = atan2(sbet12a, cbet12a);

1302 double m12b, m0;

1303

1304

1305 Lengths(g, g->n, pi + bet12a,

1306 sbet1, -cbet1, dn1, sbet2, cbet2, dn2,

1307 cbet1, cbet2, nullptr, &m12b, &m0, nullptr, nullptr, Ca);

1308 x = -1 + m12b / (cbet1 * cbet2 * m0 * pi);

1309 betscale = x < -0.01 ? sbet12a / x :

1310 -g->f * sq(cbet1) * pi;

1311 lamscale = betscale / cbet1;

1312 y = lam12x / lamscale;

1313 }

1314

1315 if (y > -tol1 && x > -1 - xthresh) {

1316

1317 if (g->f >= 0) {

1319 } else {

1320 calp1 = fmax(x > -tol1 ? 0.0 : -1.0, x);

1322 }

1323 } else {

1324

1325

1326

1327

1328

1329

1330

1331

1332

1333

1334

1335

1336

1337

1338

1339

1340

1341

1342

1343

1344

1345

1346

1347

1348

1349

1350

1351

1352

1353

1354

1355

1356

1357

1358 double k = Astroid(x, y);

1359 double

1360 omg12a = lamscale * ( g->f >= 0 ? -x * k/(1 + k) : -y * (1 + k)/k );

1361 somg12 = sin(omg12a); comg12 = -cos(omg12a);

1362

1363 salp1 = cbet2 * somg12;

1364 calp1 = sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12);

1365 }

1366 }

1367

1368 if (!(salp1 <= 0))

1370 else {

1372 }

1373

1374 *psalp1 = salp1;

1375 *pcalp1 = calp1;

1376 if (shortline)

1377 *pdnm = dnm;

1378 if (sig12 >= 0) {

1379 *psalp2 = salp2;

1380 *pcalp2 = calp2;

1381 }

1382 return sig12;

1383 }

1384

1386 double sbet1, double cbet1, double dn1,

1387 double sbet2, double cbet2, double dn2,

1389 double slam120, double clam120,

1390 double* psalp2, double* pcalp2,

1391 double* psig12,

1392 double* pssig1, double* pcsig1,

1393 double* pssig2, double* pcsig2,

1394 double* peps,

1395 double* pdomg12,

1396 boolx diffp, double* pdlam12,

1397

1398 double Ca[]) {

1399 double salp2 = 0, calp2 = 0, sig12 = 0,

1400 ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0,

1401 domg12 = 0, dlam12 = 0;

1402 double salp0, calp0;

1403 double somg1, comg1, somg2, comg2, somg12, comg12, lam12;

1404 double B312, eta, k2;

1405

1406 if (sbet1 == 0 && calp1 == 0)

1407

1408

1410

1411

1412 salp0 = salp1 * cbet1;

1413 calp0 = hypot(calp1, salp1 * sbet1);

1414

1415

1416

1417 ssig1 = sbet1; somg1 = salp0 * sbet1;

1418 csig1 = comg1 = calp1 * cbet1;

1419 norm2(&ssig1, &csig1);

1420

1421

1422

1423

1424

1425

1426 salp2 = cbet2 != cbet1 ? salp0 / cbet2 : salp1;

1427

1428

1429

1430

1431 calp2 = cbet2 != cbet1 || fabs(sbet2) != -sbet1 ?

1432 sqrt(sq(calp1 * cbet1) +

1433 (cbet1 < -sbet1 ?

1434 (cbet2 - cbet1) * (cbet1 + cbet2) :

1435 (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 :

1437

1438

1439 ssig2 = sbet2; somg2 = salp0 * sbet2;

1440 csig2 = comg2 = calp2 * cbet2;

1441 norm2(&ssig2, &csig2);

1442

1443

1444

1445 sig12 = atan2(fmax(0.0, csig1 * ssig2 - ssig1 * csig2) + 0,

1446 csig1 * csig2 + ssig1 * ssig2);

1447

1448

1449 somg12 = fmax(0.0, comg1 * somg2 - somg1 * comg2) + 0;

1450 comg12 = comg1 * comg2 + somg1 * somg2;

1451

1452 eta = atan2(somg12 * clam120 - comg12 * slam120,

1453 comg12 * clam120 + somg12 * slam120);

1454 k2 = sq(calp0) * g->ep2;

1455 eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2);

1456 C3f(g, eps, Ca);

1457 B312 = (SinCosSeries(TRUE, ssig2, csig2, Ca, nC3-1) -

1458 SinCosSeries(TRUE, ssig1, csig1, Ca, nC3-1));

1459 domg12 = -g->f * A3f(g, eps) * salp0 * (sig12 + B312);

1460 lam12 = eta + domg12;

1461

1462 if (diffp) {

1463 if (calp2 == 0)

1464 dlam12 = - 2 * g->f1 * dn1 / sbet1;

1465 else {

1466 Lengths(g, eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2,

1467 cbet1, cbet2, nullptr, &dlam12, nullptr, nullptr, nullptr, Ca);

1468 dlam12 *= g->f1 / (calp2 * cbet2);

1469 }

1470 }

1471

1472 *psalp2 = salp2;

1473 *pcalp2 = calp2;

1474 *psig12 = sig12;

1475 *pssig1 = ssig1;

1476 *pcsig1 = csig1;

1477 *pssig2 = ssig2;

1478 *pcsig2 = csig2;

1479 *peps = eps;

1480 *pdomg12 = domg12;

1481 if (diffp)

1482 *pdlam12 = dlam12;

1483

1484 return lam12;

1485 }

1486

1487 double A3f(const struct geod_geodesic* g, double eps) {

1488

1489 return polyvalx(nA3 - 1, g->A3x, eps);

1490 }

1491

1492 void C3f(const struct geod_geodesic* g, double eps, double c[]) {

1493

1494

1495 double mult = 1;

1496 int o = 0, l;

1497 for (l = 1; l < nC3; ++l) {

1498 int m = nC3 - l - 1;

1499 mult *= eps;

1500 c[l] = mult * polyvalx(m, g->C3x + o, eps);

1501 o += m + 1;

1502 }

1503 }

1504

1505 void C4f(const struct geod_geodesic* g, double eps, double c[]) {

1506

1507

1508 double mult = 1;

1509 int o = 0, l;

1510 for (l = 0; l < nC4; ++l) {

1511 int m = nC4 - l - 1;

1512 c[l] = mult * polyvalx(m, g->C4x + o, eps);

1513 o += m + 1;

1514 mult *= eps;

1515 }

1516 }

1517

1518

1519 double A1m1f(double eps) {

1520 static const double coeff[] = {

1521

1522 1, 4, 64, 0, 256,

1523 };

1524 int m = nA1/2;

1525 double t = polyvalx(m, coeff, sq(eps)) / coeff[m + 1];

1526 return (t + eps) / (1 - eps);

1527 }

1528

1529

1530 void C1f(double eps, double c[]) {

1531 static const double coeff[] = {

1532

1533 -1, 6, -16, 32,

1534

1535 -9, 64, -128, 2048,

1536

1537 9, -16, 768,

1538

1539 3, -5, 512,

1540

1541 -7, 1280,

1542

1543 -7, 2048,

1544 };

1545 double

1546 eps2 = sq(eps),

1547 d = eps;

1548 int o = 0, l;

1549 for (l = 1; l <= nC1; ++l) {

1550 int m = (nC1 - l) / 2;

1551 c[l] = d * polyvalx(m, coeff + o, eps2) / coeff[o + m + 1];

1552 o += m + 2;

1553 d *= eps;

1554 }

1555 }

1556

1557

1558 void C1pf(double eps, double c[]) {

1559 static const double coeff[] = {

1560

1561 205, -432, 768, 1536,

1562

1563 4005, -4736, 3840, 12288,

1564

1565 -225, 116, 384,

1566

1567 -7173, 2695, 7680,

1568

1569 3467, 7680,

1570

1571 38081, 61440,

1572 };

1573 double

1574 eps2 = sq(eps),

1575 d = eps;

1576 int o = 0, l;

1577 for (l = 1; l <= nC1p; ++l) {

1578 int m = (nC1p - l) / 2;

1579 c[l] = d * polyvalx(m, coeff + o, eps2) / coeff[o + m + 1];

1580 o += m + 2;

1581 d *= eps;

1582 }

1583 }

1584

1585

1586 double A2m1f(double eps) {

1587 static const double coeff[] = {

1588

1589 -11, -28, -192, 0, 256,

1590 };

1591 int m = nA2/2;

1592 double t = polyvalx(m, coeff, sq(eps)) / coeff[m + 1];

1593 return (t - eps) / (1 + eps);

1594 }

1595

1596

1597 void C2f(double eps, double c[]) {

1598 static const double coeff[] = {

1599

1600 1, 2, 16, 32,

1601

1602 35, 64, 384, 2048,

1603

1604 15, 80, 768,

1605

1606 7, 35, 512,

1607

1608 63, 1280,

1609

1610 77, 2048,

1611 };

1612 double

1613 eps2 = sq(eps),

1614 d = eps;

1615 int o = 0, l;

1616 for (l = 1; l <= nC2; ++l) {

1617 int m = (nC2 - l) / 2;

1618 c[l] = d * polyvalx(m, coeff + o, eps2) / coeff[o + m + 1];

1619 o += m + 2;

1620 d *= eps;

1621 }

1622 }

1623

1624

1626 static const double coeff[] = {

1627

1628 -3, 128,

1629

1630 -2, -3, 64,

1631

1632 -1, -3, -1, 16,

1633

1634 3, -1, -2, 8,

1635

1636 1, -1, 2,

1637

1638 1, 1,

1639 };

1640 int o = 0, k = 0, j;

1641 for (j = nA3 - 1; j >= 0; --j) {

1642 int m = nA3 - j - 1 < j ? nA3 - j - 1 : j;

1643 g->A3x[k++] = polyvalx(m, coeff + o, g->n) / coeff[o + m + 1];

1644 o += m + 2;

1645 }

1646 }

1647

1648

1650 static const double coeff[] = {

1651

1652 3, 128,

1653

1654 2, 5, 128,

1655

1656 -1, 3, 3, 64,

1657

1658 -1, 0, 1, 8,

1659

1660 -1, 1, 4,

1661

1662 5, 256,

1663

1664 1, 3, 128,

1665

1666 -3, -2, 3, 64,

1667

1668 1, -3, 2, 32,

1669

1670 7, 512,

1671

1672 -10, 9, 384,

1673

1674 5, -9, 5, 192,

1675

1676 7, 512,

1677

1678 -14, 7, 512,

1679

1680 21, 2560,

1681 };

1682 int o = 0, k = 0, l, j;

1683 for (l = 1; l < nC3; ++l) {

1684 for (j = nC3 - 1; j >= l; --j) {

1685 int m = nC3 - j - 1 < j ? nC3 - j - 1 : j;

1686 g->C3x[k++] = polyvalx(m, coeff + o, g->n) / coeff[o + m + 1];

1687 o += m + 2;

1688 }

1689 }

1690 }

1691

1692

1694 static const double coeff[] = {

1695

1696 97, 15015,

1697

1698 1088, 156, 45045,

1699

1700 -224, -4784, 1573, 45045,

1701

1702 -10656, 14144, -4576, -858, 45045,

1703

1704 64, 624, -4576, 6864, -3003, 15015,

1705

1706 100, 208, 572, 3432, -12012, 30030, 45045,

1707

1708 1, 9009,

1709

1710 -2944, 468, 135135,

1711

1712 5792, 1040, -1287, 135135,

1713

1714 5952, -11648, 9152, -2574, 135135,

1715

1716 -64, -624, 4576, -6864, 3003, 135135,

1717

1718 8, 10725,

1719

1720 1856, -936, 225225,

1721

1722 -8448, 4992, -1144, 225225,

1723

1724 -1440, 4160, -4576, 1716, 225225,

1725

1726 -136, 63063,

1727

1728 1024, -208, 105105,

1729

1730 3584, -3328, 1144, 315315,

1731

1732 -128, 135135,

1733

1734 -2560, 832, 405405,

1735

1736 128, 99099,

1737 };

1738 int o = 0, k = 0, l, j;

1739 for (l = 0; l < nC4; ++l) {

1740 for (j = nC4 - 1; j >= l; --j) {

1741 int m = nC4 - j - 1;

1742 g->C4x[k++] = polyvalx(m, coeff + o, g->n) / coeff[o + m + 1];

1743 o += m + 2;

1744 }

1745 }

1746 }

1747

1748 int transit(double lon1, double lon2) {

1749 double lon12;

1750

1751

1752

1753 lon12 = AngDiff(lon1, lon2, nullptr);

1755 lon2 = AngNormalize(lon2);

1756 return

1757 lon12 > 0 && ((lon1 < 0 && lon2 >= 0) ||

1758 (lon1 > 0 && lon2 == 0)) ? 1 :

1759 (lon12 < 0 && lon1 >= 0 && lon2 < 0 ? -1 : 0);

1760 }

1761

1762 int transitdirect(double lon1, double lon2) {

1763

1764

1765 lon1 = remainder(lon1, 2.0 * td); lon2 = remainder(lon2, 2.0 * td);

1766 return ( (lon2 >= 0 && lon2 < td ? 0 : 1) -

1767 (lon1 >= 0 && lon1 < td ? 0 : 1) );

1768 }

1769

1770 void accini(double s[]) {

1771

1772 s[0] = s[1] = 0;

1773 }

1774

1775 void acccopy(const double s[], double t[]) {

1776

1777 t[0] = s[0]; t[1] = s[1];

1778 }

1779

1780 void accadd(double s[], double y) {

1781

1782 double u, z = sumx(y, s[1], &u);

1783 s[0] = sumx(z, s[0], &s[1]);

1784 if (s[0] == 0)

1785 s[0] = u;

1786 else

1787 s[1] = s[1] + u;

1788 }

1789

1790 double accsum(const double s[], double y) {

1791

1792 double t[2];

1793 acccopy(s, t);

1794 accadd(t, y);

1795 return t[0];

1796 }

1797

1798 void accneg(double s[]) {

1799

1800 s[0] = -s[0]; s[1] = -s[1];

1801 }

1802

1803 void accrem(double s[], double y) {

1804

1805 s[0] = remainder(s[0], y);

1806 accadd(s, 0.0);

1807 }

1808

1810 p->polyline = (polylinep != 0);

1812 }

1813

1815 p->lat0 = p->lon0 = p->lat = p->lon = NaN;

1816 accini(p->P);

1817 accini(p->A);

1818 p->num = p->crossings = 0;

1819 }

1820

1823 double lat, double lon) {

1824 if (p->num == 0) {

1825 p->lat0 = p->lat = lat;

1826 p->lon0 = p->lon = lon;

1827 } else {

1828 double s12, S12 = 0;

1830 &s12, nullptr, nullptr, nullptr, nullptr, nullptr,

1831 p->polyline ? nullptr : &S12);

1832 accadd(p->P, s12);

1833 if (!p->polyline) {

1834 accadd(p->A, S12);

1835 p->crossings += transit(p->lon, lon);

1836 }

1837 p->lat = lat; p->lon = lon;

1838 }

1839 ++p->num;

1840 }

1841

1844 double azi, double s) {

1845 if (p->num) {

1846

1847

1848 double lat = 0, lon = 0, S12 = 0;

1850 &lat, &lon, nullptr,

1851 nullptr, nullptr, nullptr, nullptr,

1852 p->polyline ? nullptr : &S12);

1853 accadd(p->P, s);

1854 if (!p->polyline) {

1855 accadd(p->A, S12);

1856 p->crossings += transitdirect(p->lon, lon);

1857 }

1858 p->lat = lat; p->lon = lon;

1859 ++p->num;

1860 }

1861 }

1862

1865 boolx reverse, boolx sign,

1866 double* pA, double* pP) {

1867 double s12, S12, t[2];

1868 if (p->num < 2) {

1869 if (pP) *pP = 0;

1870 if (!p->polyline && pA) *pA = 0;

1871 return p->num;

1872 }

1873 if (p->polyline) {

1874 if (pP) *pP = p->P[0];

1875 return p->num;

1876 }

1878 &s12, nullptr, nullptr, nullptr, nullptr, nullptr, &S12);

1879 if (pP) *pP = accsum(p->P, s12);

1880 acccopy(p->A, t);

1881 accadd(t, S12);

1882 if (pA) *pA = areareduceA(t, 4 * pi * g->c2,

1883 p->crossings + transit(p->lon, p->lon0),

1884 reverse, sign);

1885 return p->num;

1886 }

1887

1890 double lat, double lon,

1891 boolx reverse, boolx sign,

1892 double* pA, double* pP) {

1893 double perimeter, tempsum;

1894 int crossings, i;

1895 unsigned num = p->num + 1;

1896 if (num == 1) {

1897 if (pP) *pP = 0;

1898 if (!p->polyline && pA) *pA = 0;

1899 return num;

1900 }

1901 perimeter = p->P[0];

1902 tempsum = p->polyline ? 0 : p->A[0];

1903 crossings = p->crossings;

1904 for (i = 0; i < (p->polyline ? 1 : 2); ++i) {

1905 double s12, S12 = 0;

1907 i == 0 ? p->lat : lat, i == 0 ? p->lon : lon,

1908 i != 0 ? p->lat0 : lat, i != 0 ? p->lon0 : lon,

1909 &s12, nullptr, nullptr, nullptr, nullptr, nullptr,

1910 p->polyline ? nullptr : &S12);

1911 perimeter += s12;

1912 if (!p->polyline) {

1913 tempsum += S12;

1914 crossings += transit(i == 0 ? p->lon : lon,

1915 i != 0 ? p->lon0 : lon);

1916 }

1917 }

1918

1919 if (pP) *pP = perimeter;

1920 if (p->polyline)

1921 return num;

1922

1923 if (pA) *pA = areareduceB(tempsum, 4 * pi * g->c2, crossings, reverse, sign);

1924 return num;

1925 }

1926

1929 double azi, double s,

1930 boolx reverse, boolx sign,

1931 double* pA, double* pP) {

1932 double perimeter, tempsum;

1933 int crossings;

1934 unsigned num = p->num + 1;

1935 if (num == 1) {

1936 if (pP) *pP = NaN;

1937 if (!p->polyline && pA) *pA = NaN;

1938 return 0;

1939 }

1940 perimeter = p->P[0] + s;

1941 if (p->polyline) {

1942 if (pP) *pP = perimeter;

1943 return num;

1944 }

1945

1946 tempsum = p->A[0];

1947 crossings = p->crossings;

1948 {

1949

1950

1951 double lat = 0, lon = 0, s12, S12 = 0;

1953 &lat, &lon, nullptr,

1954 nullptr, nullptr, nullptr, nullptr, &S12);

1955 tempsum += S12;

1956 crossings += transitdirect(p->lon, lon);

1958 &s12, nullptr, nullptr, nullptr, nullptr, nullptr, &S12);

1959 perimeter += s12;

1960 tempsum += S12;

1961 crossings += transit(lon, p->lon0);

1962 }

1963

1964 if (pP) *pP = perimeter;

1965 if (pA) *pA = areareduceB(tempsum, 4 * pi * g->c2, crossings, reverse, sign);

1966 return num;

1967 }

1968

1970 double lats[], double lons[], int n,

1971 double* pA, double* pP) {

1972 int i;

1975 for (i = 0; i < n; ++i)

1978 }

1979

1980 double areareduceA(double area[], double area0,

1981 int crossings, boolx reverse, boolx sign) {

1982 accrem(area, area0);

1983 if (crossings & 1)

1984 accadd(area, (area[0] < 0 ? 1 : -1) * area0/2);

1985

1986

1987 if (!reverse)

1988 accneg(area);

1989

1990 if (sign) {

1991 if (area[0] > area0/2)

1992 accadd(area, -area0);

1993 else if (area[0] <= -area0/2)

1994 accadd(area, +area0);

1995 } else {

1996 if (area[0] >= area0)

1997 accadd(area, -area0);

1998 else if (area[0] < 0)

1999 accadd(area, +area0);

2000 }

2001 return 0 + area[0];

2002 }

2003

2004 double areareduceB(double area, double area0,

2005 int crossings, boolx reverse, boolx sign) {

2006 area = remainder(area, area0);

2007 if (crossings & 1)

2008 area += (area < 0 ? 1 : -1) * area0/2;

2009

2010

2011 if (!reverse)

2012 area *= -1;

2013

2014 if (sign) {

2015 if (area > area0/2)

2016 area -= area0;

2017 else if (area <= -area0/2)

2018 area += area0;

2019 } else {

2020 if (area >= area0)

2021 area -= area0;

2022 else if (area < 0)

2023 area += area0;

2024 }

2025 return 0 + area;

2026 }

2027

2028

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)