00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "GeographicLib/Geodesic.hpp"
00029 #include "GeographicLib/Constants.hpp"
00030 #include <algorithm>
00031 #include <limits>
00032
00033 namespace {
00034 char RCSID[] = "$Id: Geodesic.cpp 6568 2009-03-01 17:58:41Z ckarney $";
00035 char RCSID_H[] = GEODESIC_HPP;
00036 }
00037
00038 namespace GeographicLib {
00039
00040 using namespace std;
00041
00042
00043
00044
00045 const double Geodesic::eps2 = sqrt(numeric_limits<double>::min());
00046 const double Geodesic::tol = 100 * numeric_limits<double>::epsilon();
00047
00048 Geodesic::Geodesic(double a, double invf) throw()
00049 : _a(a)
00050 , _f(invf > 0 ? 1 / invf : 0)
00051 , _f1(1 - _f)
00052 , _e2(_f * (2 - _f))
00053 , _ep2(_e2 / sq(_f1))
00054 , _b(_a * _f1)
00055 {}
00056
00057 const Geodesic Geodesic::WGS84(Constants::WGS84_a(),
00058 Constants::WGS84_invf());
00059
00060 double Geodesic::SinSeries(double sinx, double cosx,
00061 const double c[], int n) throw() {
00062
00063
00064 double
00065 ar = 2 * (sq(cosx) - sq(sinx)),
00066 y0 = c[n - 1], y1 = 0;
00067 for (int j = n; --j;) {
00068 double y2 = y1;
00069 y1 = y0; y0 = ar * y1 - y2 + c[j - 1];
00070 }
00071 return 2 * sinx * cosx * y0;
00072 }
00073
00074
00075 double Geodesic::tauScale(double u2) throw() {
00076 return (u2 * (u2 * (u2 * (u2 * (u2 * (u2 * ((3624192 - 2760615 * u2) * u2
00077 - 4967424) + 7225344) - 11468800) + 20971520) - 50331648) +
00078 268435456) + 1073741824.0) / 1073741824.0;
00079 }
00080
00081
00082
00083 void Geodesic::tauCoeff(double u2, double c[]) throw() {
00084 double t = u2;
00085 c[0] = t * (u2 * (u2 * (u2 * (u2 * (u2 * (u2 * (428731 * u2 - 557402) +
00086 748544) - 1046528) + 1540096) - 2424832) + 4194304) - 8388608) / 67108864;
00087 t *= u2;
00088 c[1] = t * (u2 * (u2 * (u2 * (u2 * ((480096 - 397645 * u2) * u2 -
00089 586016) + 720896) - 884736) + 1048576) - 1048576) / 268435456;
00090 t *= u2;
00091 c[2] = t * (u2 * (u2 * (u2 * (u2 * (92295 * u2 - 100482) + 106880) -
00092 108288) + 98304) - 65536) / 201326592;
00093 t *= u2;
00094 c[3] = t * (u2 * (u2 * ((128512 - 136971 * u2) * u2 - 111104) + 81920) -
00095 40960) / 1073741824.0;
00096 t *= u2;
00097 c[4] = t * (u2 * (u2 * (9555 * u2 - 7210) + 4480) - 1792) / 335544320;
00098 t *= u2;
00099 c[5] = t * ((672 - 1251 * u2) * u2 - 224) / 268435456;
00100 t *= u2;
00101 c[6] = t * (231 * u2 - 66) / 469762048;
00102 t *= u2;
00103 c[7] = -429 * t / 17179869184.0;
00104 }
00105
00106
00107
00108 void Geodesic::sigCoeff(double u2, double d[]) throw() {
00109 double t = u2;
00110 d[0] = t * (u2 * (u2 * (u2 * (u2 * (u2 * ((15107266 - 11062823 * u2) *
00111 u2 - 21467904) + 31944192) - 50135040) + 83755008) - 150994944) +
00112 301989888) / 2415919104.0;
00113 t *= u2;
00114 d[1] = t * (u2 * (u2 * (u2 * (u2 * (u2 * (112064929 * u2 - 151134240) +
00115 206026080) - 281149440) + 376504320) - 471859200) + 471859200) / 24159191040.0;
00116 t *= u2;
00117 d[2] = t * (u2 * (u2 * (u2 * ((2266302 - 1841049 * u2) * u2 - 2690560) +
00118 2976768) - 2850816) + 1900544) / 402653184;
00119 t *= u2;
00120 d[3] = t * (u2 * (u2 * (u2 * (174543337 * u2 - 182201856) + 171121152) -
00121 132464640) + 66232320) / 48318382080.0;
00122 t *= u2;
00123 d[4] = t * (u2 * ((5126290 - 6292895 * u2) * u2 - 3328320) + 1331328) / 3019898880.0;
00124 t *= u2;
00125 d[5] = t * (u2 * (45781749 * u2 - 25590432) + 8530144) / 56371445760.0;
00126 t *= u2;
00127 d[6] = (918970 - 3216395 * u2) * t / 16911433728.0;
00128 t *= u2;
00129 d[7] = 109167851 * t / 5411658792960.0;
00130 }
00131
00132 double Geodesic::dlamScale(double f, double mu) throw() {
00133 double g = (f * (f * (f * (f * (f * (f * (f * mu * (mu * (mu * (mu * (mu * (mu *
00134 (184041 * mu - 960498) + 2063880) - 2332400) + 1459200) - 479232) +
00135 65536) + mu * (mu * (mu * (mu * ((544320 - 121968 * mu) * mu -
00136 963200) + 844800) - 368640) + 65536)) + mu * (mu * (mu * (mu *
00137 (84672 * mu - 313600) + 435200) - 270336) + 65536)) + mu * (mu *
00138 ((184320 - 62720 * mu) * mu - 184320) + 65536)) + mu * (mu * (51200
00139 * mu - 110592) + 65536)) + (65536 - 49152 * mu) * mu) + 65536 * mu)
00140 - 262144) / 262144;
00141 return f * g;
00142 }
00143
00144 double Geodesic::dlamScalemu(double f, double mu) throw() {
00145 double h = (f * (f * (f * (f * (f * (f * (mu * (mu * (mu * (mu * (mu *
00146 (1288287 * mu - 5762988) + 10319400) - 9329600) + 4377600) -
00147 958464) + 65536) + mu * (mu * (mu * ((2721600 - 731808 * mu) * mu -
00148 3852800) + 2534400) - 737280) + 65536) + mu * (mu * (mu * (423360 *
00149 mu - 1254400) + 1305600) - 540672) + 65536) + mu * ((552960 -
00150 250880 * mu) * mu - 368640) + 65536) + mu * (153600 * mu - 221184)
00151 + 65536) - 98304 * mu + 65536) + 65536) / 262144;
00152 return h * sq(f);
00153 }
00154
00155 void Geodesic::dlamCoeff(double f, double mu, double e[]) throw() {
00156 double s = f * mu, t = s;
00157 e[0] = (f * (f * (f * (f * (f * (f * (f * (mu * (mu * (mu * (mu * (mu *
00158 ((30816920 - 5080225 * mu) * mu - 79065664) + 110840000) -
00159 91205632) + 43638784) - 11010048) + 1048576) + mu * (mu * (mu * (mu
00160 * (mu * (3213004 * mu - 17049088) + 37224832) - 42637312) +
00161 26828800) - 8650752) + 1048576) + mu * (mu * (mu * ((9543424 -
00162 2100608 * mu) * mu - 17160192) + 15196160) - 6553600) + 1048576) +
00163 mu * (mu * (mu * (1435648 * mu - 5419008) + 7626752) - 4718592) +
00164 1048576) + mu * ((3129344 - 1044480 * mu) * mu - 3145728) +
00165 1048576) + mu * (835584 * mu - 1835008) + 1048576) - 786432 * mu +
00166 1048576) + 1048576) * t / 8388608;
00167 t *= s;
00168 e[1] = (f * (f * (f * (f * (f * (f * (mu * (mu * (mu * (mu * (mu *
00169 (2092939 * mu - 12074982) + 29005488) - 37129344) + 26700800) -
00170 10207232) + 1605632) + mu * (mu * (mu * ((6316264 - 1270932 * mu) *
00171 mu - 12598272) + 12618240) - 6348800) + 1277952) + mu * (mu * (mu *
00172 (787136 * mu - 3268608) + 5143040) - 3645440) + 983040) + mu *
00173 ((1648640 - 498688 * mu) * mu - 1859584) + 720896) + mu * (323584 *
00174 mu - 778240) + 491520) - 212992 * mu + 294912) + 131072) * t / 8388608;
00175 t *= s;
00176 e[2] = (f * (f * (f * (f * (f * (mu * (mu * (mu * ((13101384 - 2474307 *
00177 mu) * mu - 28018000) + 30323072) - 16658432) + 3727360) + mu * (mu
00178 * (mu * (1386756 * mu - 6137024) + 10352064) - 7923712) + 2334720)
00179 + mu * ((2705152 - 770048 * mu) * mu - 3254272) + 1351680) + mu *
00180 (416256 * mu - 1052672) + 696320) - 208896 * mu + 294912) + 81920) * t / 25165824;
00181 t *= s;
00182 e[3] = (f * (f * (f * (f * (mu * (mu * (mu * (273437 * mu - 1265846) +
00183 2238200) - 1799088) + 557760) + mu * ((492328 - 134532 * mu) * mu -
00184 616928) + 266560) + mu * (62080 * mu - 162048) + 110080) - 25088 *
00185 mu + 35840) + 7168) * t / 8388608;
00186 t *= s;
00187 e[4] = (f * (f * (f * (mu * ((1333160 - 353765 * mu) * mu - 1718160) +
00188 761600) + mu * (142140 * mu - 379200) + 262080) - 48000 * mu +
00189 69120) + 10752) * t / 41943040;
00190 t *= s;
00191 e[5] = (f * (f * (mu * (39633 * mu - 107426) + 75152) - 11484 * mu +
00192 16632) + 2112) * t / 25165824;
00193 t *= s;
00194 e[6] = (f * (16016 - 11011 * mu) + 1716) * t / 58720256;
00195 t *= s;
00196 e[7] = 715 * t / 67108864;
00197 }
00198
00199 void Geodesic::dlamCoeffmu(double f, double mu, double h[]) throw() {
00200 double s = f * mu, t = f;
00201 h[0] = (f * (f * (f * (f * (f * (f * (f * (mu * (mu * (mu * (mu * (mu *
00202 ((53929610 - 10160450 * mu) * mu - 118598496) + 138550000) -
00203 91205632) + 32729088) - 5505024) + 262144) + mu * (mu * (mu * (mu *
00204 (mu * (5622757 * mu - 25573632) + 46531040) - 42637312) + 20121600)
00205 - 4325376) + 262144) + mu * (mu * (mu * ((11929280 - 3150912 * mu)
00206 * mu - 17160192) + 11397120) - 3276800) + 262144) + mu * (mu * (mu
00207 * (1794560 * mu - 5419008) + 5720064) - 2359296) + 262144) + mu *
00208 ((2347008 - 1044480 * mu) * mu - 1572864) + 262144) + mu * (626688
00209 * mu - 917504) + 262144) - 393216 * mu + 262144) + 262144) * t / 2097152;
00210 t *= s;
00211 h[1] = (f * (f * (f * (f * (f * (f * (mu * (mu * (mu * (mu * (mu *
00212 (8371756 * mu - 42262437) + 87016464) - 92823360) + 53401600) -
00213 15310848) + 1605632) + mu * (mu * (mu * ((18948792 - 4448262 * mu)
00214 * mu - 31495680) + 25236480) - 9523200) + 1277952) + mu * (mu * (mu
00215 * (2361408 * mu - 8171520) + 10286080) - 5468160) + 983040) + mu *
00216 ((3297280 - 1246720 * mu) * mu - 2789376) + 720896) + mu * (647168
00217 * mu - 1167360) + 491520) - 319488 * mu + 294912) + 131072) * t / 4194304;
00218 t *= s;
00219 h[2] = (f * (f * (f * (f * (f * (mu * (mu * (mu * ((22927422 - 4948614 *
00220 mu) * mu - 42027000) + 37903840) - 16658432) + 2795520) + mu * (mu
00221 * (mu * (2426823 * mu - 9205536) + 12940080) - 7923712) + 1751040)
00222 + mu * ((3381440 - 1155072 * mu) * mu - 3254272) + 1013760) + mu *
00223 (520320 * mu - 1052672) + 522240) - 208896 * mu + 221184) + 61440) * t / 6291456;
00224 t *= s;
00225 h[3] = (f * (f * (f * (f * (mu * (mu * (mu * (1093748 * mu - 4430461) +
00226 6714600) - 4497720) + 1115520) + mu * ((1476984 - 470862 * mu) * mu
00227 - 1542320) + 533120) + mu * (186240 * mu - 405120) + 220160) -
00228 62720 * mu + 71680) + 14336) * t / 4194304;
00229 t *= s;
00230 h[4] = (f * (f * (f * (mu * ((466606 - 141506 * mu) * mu - 515448) +
00231 190400) + mu * (49749 * mu - 113760) + 65520) - 14400 * mu + 17280)
00232 + 2688) * t / 2097152;
00233 t *= s;
00234 h[5] = (f * (f * (mu * (158532 * mu - 375991) + 225456) - 40194 * mu +
00235 49896) + 6336) * t / 12582912;
00236 t *= s;
00237 h[6] = (f * (4004 - 3146 * mu) + 429) * t / 2097152;
00238 t *= s;
00239 h[7] = 715 * t / 8388608;
00240 }
00241
00242 GeodesicLine Geodesic::Line(double lat1, double lon1, double azi1)
00243 const throw() {
00244 return GeodesicLine(*this, lat1, lon1, azi1);
00245 }
00246
00247 void Geodesic::Direct(double lat1, double lon1, double azi1, double s12,
00248 double& lat2, double& lon2, double& azi2)
00249 const throw() {
00250 GeodesicLine l(*this, lat1, lon1, azi1);
00251 l.Position(s12, lat2, lon2, azi2);
00252 }
00253
00254 void Geodesic::Inverse(double lat1, double lon1, double lat2, double lon2,
00255 double& s12, double& azi1, double& azi2)
00256 const throw() {
00257 lon1 = AngNormalize(lon1);
00258 double lon12 = AngNormalize(AngNormalize(lon2) - lon1);
00259
00260
00261 lon12 = AngRound(lon12);
00262
00263 int lonsign = lon12 >= 0 ? 1 : -1;
00264 lon12 *= lonsign;
00265
00266 lat1 = AngRound(lat1);
00267 lat2 = AngRound(lat2);
00268
00269 int swapp = abs(lat1) >= abs(lat2) ? 1 : -1;
00270 if (swapp < 0) {
00271 lonsign *= -1;
00272 swap(lat1, lat2);
00273 }
00274
00275 int latsign = lat1 < 0 ? 1 : -1;
00276 lat1 *= latsign;
00277 lat2 *= latsign;
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 double phi, sbet1, cbet1, sbet2, cbet2, n1;
00291
00292 phi = lat1 * Constants::degree();
00293
00294 sbet1 = _f1 * sin(phi);
00295 cbet1 = lat1 == -90 ? eps2 : cos(phi);
00296
00297 n1 = hypot(sbet1, cbet1);
00298 sbet1 /= n1; cbet1 /= n1;
00299
00300 phi = lat2 * Constants::degree();
00301
00302 sbet2 = _f1 * sin(phi);
00303 cbet2 = abs(lat2) == 90 ? eps2 : cos(phi);
00304 SinCosNorm(sbet2, cbet2);
00305
00306 double
00307
00308 sbet12 = sbet2 * cbet1 - cbet2 * sbet1,
00309
00310 sbet12a = sbet2 * cbet1 + cbet2 * sbet1,
00311 cbet12a = cbet2 * cbet1 - sbet2 * sbet1,
00312 chi12 = lon12 * Constants::degree(),
00313 cchi12 = cos(chi12),
00314 schi12 = lon12 == 180 ? 0 :sin(chi12);
00315
00316 double calp1, salp1, calp2, salp2, c[maxpow];
00317
00318
00319 if (schi12 == 0 || lat1 == -90) {
00320
00321 calp1 = cchi12; salp1 = schi12;
00322
00323 calp2 = 1; salp2 = 0;
00324
00325 double
00326
00327 ssig1 = sbet1, csig1 = calp1 * cbet1,
00328 ssig2 = sbet2, csig2 = calp2 * cbet2;
00329 SinCosNorm(ssig1, csig1);
00330 SinCosNorm(ssig2, csig2);
00331
00332
00333 double sig12 = atan2(max(csig1 * ssig2 - ssig1 * csig2, 0.0),
00334 csig1 * csig2 + ssig1 * ssig2);
00335
00336 tauCoeff(_ep2, c);
00337 s12 = _b * tauScale(_ep2) *
00338 (sig12 + (SinSeries(ssig2, csig2, c, maxpow) -
00339 SinSeries(ssig1, csig1, c, maxpow)));
00340 } else if (sbet1 == 0 &&
00341
00342 chi12 <= Constants::pi() - _f * Constants::pi()) {
00343
00344 calp1 = calp2 = 0; salp1 = salp2 = 1;
00345 s12 = _a * chi12;
00346 } else {
00347
00348
00349
00350
00351 double sig12, ssig1, csig1, ssig2, csig2, u2;
00352
00353
00354 double
00355 chicrita = -cbet1 * dlamScale(_f, sq(sbet1)) * Constants::pi(),
00356 chicrit = Constants::pi() - chicrita;
00357 if (chi12 == chicrit && cbet1 == cbet2 && sbet2 == -sbet1) {
00358 salp1 = 1; calp1 = 0;
00359
00360
00361
00362
00363
00364
00365
00366 } else if (chi12 > chicrit && cbet12a > 0 && sbet12a > - chicrita) {
00367 salp1 = min(1.0, (Constants::pi() - chi12) / chicrita);
00368 calp1 = - sqrt(1 - sq(salp1));
00369 } else if (chi12 > Constants::pi() - 2 * chicrita &&
00370 cbet12a > 0 && sbet12a > - 2 * chicrita) {
00371 salp1 = 1;
00372 calp1 = sbet2 <= 0 ? -eps2 : eps2;
00373 } else {
00374 salp1 = cbet2 * schi12;
00375
00376
00377 calp1 = cchi12 >= 0 ?
00378 sbet12 * _f1/n1 + cbet2 * sbet1 * sq(schi12) / (1 + cchi12) :
00379 sbet12a - cbet2 * sbet1 * sq(schi12) / (1 - cchi12);
00380
00381 SinCosNorm(salp1, calp1);
00382 }
00383
00384
00385 for (unsigned i = 0, trip = 0; i < 100; ++i) {
00386 double dv;
00387 double v = Chi12(sbet1, cbet1, sbet2, cbet2,
00388 salp1, calp1, salp2, calp2,
00389 sig12, ssig1, csig1, ssig2, csig2,
00390 u2, trip < 1, dv, c) - chi12;
00391 if (v == 0 || !(trip < 1))
00392 break;
00393 double
00394 dalp1 = -v/dv,
00395 sdalp1 = sin(dalp1), cdalp1 = cos(dalp1),
00396 nsalp1 = salp1 * cdalp1 + calp1 * sdalp1;
00397 calp1 = calp1 * cdalp1 - salp1 * sdalp1;
00398 salp1 = max(0.0, nsalp1);
00399 SinCosNorm(salp1, calp1);
00400 if (abs(v) < tol) ++trip;
00401 }
00402
00403 tauCoeff(u2, c);
00404 s12 = _b * tauScale(u2) *
00405 (sig12 + (SinSeries(ssig2, csig2, c, maxpow) -
00406 SinSeries(ssig1, csig1, c, maxpow)));
00407 }
00408
00409
00410
00411
00412 if (swapp < 0) {
00413 swap(salp1, salp2);
00414 swap(calp1, calp2);
00415 }
00416
00417
00418 azi1 = 0-atan2(- swapp * lonsign * salp1,
00419 + swapp * latsign * calp1) / Constants::degree();
00420 azi2 = 0-atan2(- azi2sense * swapp * lonsign * salp2,
00421 + azi2sense * swapp * latsign * calp2) / Constants::degree();
00422 return;
00423 }
00424
00425 double Geodesic::Chi12(double sbet1, double cbet1,
00426 double sbet2, double cbet2,
00427 double salp1, double calp1,
00428 double& salp2, double& calp2,
00429 double& sig12,
00430 double& ssig1, double& csig1,
00431 double& ssig2, double& csig2,
00432 double& u2,
00433 bool diffp, double& dchi12, double c[])
00434 const throw() {
00435
00436 if (sbet1 == 0 && calp1 == 0)
00437
00438
00439 calp1 = -eps2;
00440
00441 double
00442
00443 salp0 = salp1 * cbet1,
00444 calp0 = hypot(calp1, salp1 * sbet1);
00445
00446 double slam1, clam1, slam2, clam2, lam12, chi12, mu;
00447
00448
00449 ssig1 = sbet1; slam1 = salp0 * sbet1;
00450 csig1 = clam1 = calp1 * cbet1;
00451 SinCosNorm(ssig1, csig1);
00452 SinCosNorm(slam1, clam1);
00453
00454
00455
00456
00457
00458 salp2 = cbet2 != cbet1 ? salp0 / cbet2 : salp1;
00459
00460
00461
00462
00463 calp2 = cbet2 != cbet1 || abs(sbet2) != -sbet1 ?
00464 sqrt(sq(calp1 * cbet1) + (cbet1 < -sbet1 ?
00465 (cbet2 - cbet1) * (cbet1 + cbet2) :
00466 (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 :
00467 abs(calp1);
00468
00469
00470 ssig2 = sbet2; slam2 = salp0 * sbet2;
00471 csig2 = clam2 = calp2 * cbet2;
00472 SinCosNorm(ssig2, csig2);
00473 SinCosNorm(slam2, clam2);
00474
00475
00476 sig12 = atan2(max(csig1 * ssig2 - ssig1 * csig2, 0.0),
00477 csig1 * csig2 + ssig1 * ssig2);
00478
00479
00480 lam12 = atan2(max(clam1 * slam2 - slam1 * clam2, 0.0),
00481 clam1 * clam2 + slam1 * slam2);
00482
00483 double eta12, lamscale;
00484 mu = sq(calp0);
00485 dlamCoeff(_f, mu, c);
00486 eta12 = SinSeries(ssig2, csig2, c, maxpow) -
00487 SinSeries(ssig1, csig1, c, maxpow);
00488 lamscale = dlamScale(_f, mu),
00489 chi12 = lam12 + salp0 * lamscale * (sig12 + eta12);
00490
00491 if (diffp) {
00492 double dalp0, dsig1, dlam1, dalp2, dsig2, dlam2;
00493
00494 dalp0 = cbet1 * calp1 / calp0;
00495 dalp2 = calp2 != 0 ? calp1 * cbet1/ (calp2 * cbet2) :
00496 calp1 >= 0 ? 1 : -1;
00497
00498
00499 dsig1 = ssig1 * salp0 / calp0;
00500 dsig2 = ssig2 * salp0 / calp0 * dalp2;
00501
00502
00503
00504
00505 dlam1 = (sbet1 * sq(clam1) + slam1 * salp0 / (calp0 * cbet1));
00506 dlam2 = (sbet2 * sq(clam2) + slam2 * salp0 / (calp0 * cbet2)) * dalp2;
00507
00508 double deta12, dmu, dlamscale, dchisig;
00509 dlamCoeffmu(_f, mu, c);
00510 dmu = - 2 * calp0 * salp0 * dalp0;
00511 deta12 = dmu * (SinSeries(ssig2, csig2, c, maxpow) -
00512 SinSeries(ssig1, csig1, c, maxpow));
00513 dlamscale = dlamScalemu(_f, mu) * dmu;
00514
00515
00516
00517 dchisig = - _e2 * salp0 *
00518 (dsig2 / (sqrt(1 - _e2 * (1 - mu * sq(ssig2))) + 1) -
00519 dsig1 / (sqrt(1 - _e2 * (1 - mu * sq(ssig1))) + 1)) ;
00520
00521 dchi12 =
00522 (dlam2 - dlam1) + dchisig +
00523
00524 (dalp0 * calp0 * lamscale + salp0 * dlamscale) * (sig12 + eta12) +
00525 salp0 * lamscale * deta12;
00526 }
00527
00528 u2 = mu * _ep2;
00529 return chi12;
00530 }
00531
00532 GeodesicLine::GeodesicLine(const Geodesic& g,
00533 double lat1, double lon1, double azi1) throw() {
00534 azi1 = Geodesic::AngNormalize(azi1);
00535
00536 if (lat1 == 90) {
00537 lon1 -= azi1 - (azi1 >= 0 ? 180 : -180);
00538 azi1 = -180;
00539 } else if (lat1 == -90) {
00540 lon1 += azi1;
00541 azi1 = 0;
00542 }
00543
00544 azi1 = Geodesic::AngRound(azi1);
00545 lon1 = Geodesic::AngNormalize(lon1);
00546 _bsign = azi1 >= 0 ? 1 : -1;
00547 azi1 *= _bsign;
00548 _lat1 = lat1;
00549 _lon1 = lon1;
00550 _azi1 = azi1;
00551 _f1 = g._f1;
00552
00553 double
00554 alp1 = azi1 * Constants::degree(),
00555
00556
00557 salp1 = azi1 == 180 ? 0 : sin(alp1),
00558 calp1 = azi1 == 90 ? 0 : cos(alp1);
00559 double cbet1, sbet1, phi;
00560 phi = lat1 * Constants::degree();
00561
00562 sbet1 = _f1 * sin(phi);
00563 cbet1 = abs(lat1) == 90 ? Geodesic::eps2 : cos(phi);
00564 Geodesic::SinCosNorm(sbet1, cbet1);
00565
00566
00567 _salp0 = salp1 * cbet1;
00568
00569
00570 _calp0 = Geodesic::hypot(calp1, salp1 * sbet1);
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 _ssig1 = sbet1; _slam1 = _salp0 * sbet1;
00581 _csig1 = _clam1 = sbet1 != 0 || calp1 != 0 ? cbet1 * calp1 : 1;
00582
00583 Geodesic::SinCosNorm(_ssig1, _csig1);
00584 Geodesic::SinCosNorm(_slam1, _clam1);
00585 double
00586 mu = Geodesic::sq(_calp0),
00587 u2 = mu * g._ep2;
00588
00589 _sScale = g._b * Geodesic::tauScale(u2);
00590 Geodesic::tauCoeff(u2, _sigCoeff);
00591 _dtau1 = Geodesic::SinSeries(_ssig1, _csig1, _sigCoeff, maxpow);
00592 {
00593 double s = sin(_dtau1), c = cos(_dtau1);
00594
00595 _stau1 = _ssig1 * c + _csig1 * s;
00596 _ctau1 = _csig1 * c - _ssig1 * s;
00597 }
00598 Geodesic::sigCoeff(u2, _sigCoeff);
00599
00600
00601
00602 _dlamScale = _salp0 * Geodesic::dlamScale(g._f, mu);
00603 Geodesic::dlamCoeff(g._f, mu, _dlamCoeff);
00604 _dchi1 = Geodesic::SinSeries(_ssig1, _csig1, _dlamCoeff, maxpow);
00605 }
00606
00607 void GeodesicLine::Position(double s12,
00608 double& lat2, double& lon2, double& azi2)
00609 const throw() {
00610 if (_sScale == 0)
00611
00612 return;
00613 double tau12, sig12, lam12, chi12, lon12, s, c;
00614 double ssig2, csig2, sbet2, cbet2, slam2, clam2, salp2, calp2;
00615 tau12 = s12 / _sScale;
00616 s = sin(tau12); c = cos(tau12);
00617 sig12 = tau12 + (_dtau1 +
00618
00619 Geodesic::SinSeries(_stau1 * c + _ctau1 * s,
00620 _ctau1 * c - _stau1 * s,
00621 _sigCoeff, maxpow));
00622 s = sin(sig12); c = cos(sig12);
00623
00624 ssig2 = _ssig1 * c + _csig1 * s;
00625 csig2 = _csig1 * c - _ssig1 * s;
00626
00627 sbet2 = _calp0 * ssig2;
00628
00629 cbet2 = Geodesic::hypot(_salp0, _calp0 * csig2);
00630
00631 slam2 = _salp0 * ssig2; clam2 = csig2;
00632
00633 salp2 = _salp0; calp2 = _calp0 * csig2;
00634
00635 lam12 = atan2(slam2 * _clam1 - clam2 * _slam1,
00636 clam2 * _clam1 + slam2 * _slam1);
00637 chi12 = lam12 + _dlamScale *
00638 ( sig12 +
00639 (Geodesic::SinSeries(ssig2, csig2, _dlamCoeff, maxpow) - _dchi1));
00640 lon12 = _bsign * chi12 / Constants::degree();
00641
00642
00643 lon12 = lon12 - 360 * floor(lon12/360 + 0.5);
00644 lat2 = atan2(sbet2, _f1 * cbet2) / Constants::degree();
00645 lon2 = Geodesic::AngNormalize(_lon1 + lon12);
00646
00647 azi2 = 0-atan2(- Geodesic::azi2sense * _bsign * salp2,
00648 + Geodesic::azi2sense * calp2) / Constants::degree();
00649 }
00650
00651 }
00652