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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "GeographicLib/TransverseMercator.hpp"
00043
00044 #define GEOGRAPHICLIB_TRANSVERSEMERCATOR_CPP "$Id: TransverseMercator.cpp 6937 2011-02-01 20:17:13Z karney $"
00045
00046 RCSID_DECL(GEOGRAPHICLIB_TRANSVERSEMERCATOR_CPP)
00047 RCSID_DECL(GEOGRAPHICLIB_TRANSVERSEMERCATOR_HPP)
00048
00049 namespace GeographicLib {
00050
00051 using namespace std;
00052
00053 const Math::real TransverseMercator::tol =
00054 real(0.1)*sqrt(numeric_limits<real>::epsilon());
00055
00056 const Math::real TransverseMercator::overflow =
00057 1 / sq(numeric_limits<real>::epsilon());
00058
00059 TransverseMercator::TransverseMercator(real a, real r, real k0)
00060 : _a(a)
00061 , _r(r)
00062 , _f(_r != 0 ? 1 / _r : 0)
00063 , _k0(k0)
00064 , _e2(_f * (2 - _f))
00065 , _e(sqrt(abs(_e2)))
00066 , _e2m(1 - _e2)
00067
00068
00069 , _c( sqrt(_e2m) * exp(eatanhe(real(1))) )
00070 , _n(_f / (2 - _f))
00071 {
00072 if (!(_a > 0))
00073 throw GeographicErr("Major radius is not positive");
00074 if (!(_f < 1))
00075 throw GeographicErr("Minor radius is not positive");
00076 if (!(_k0 > 0))
00077 throw GeographicErr("Scale is not positive");
00078
00079
00080 real nx = sq(_n);
00081 switch (maxpow) {
00082 case 4:
00083 _b1 = 1/(1+_n)*(nx*(nx+16)+64)/64;
00084 _alp[1] = _n*(_n*(_n*(164*_n+225)-480)+360)/720;
00085 _bet[1] = _n*(_n*((555-4*_n)*_n-960)+720)/1440;
00086 _alp[2] = nx*(_n*(557*_n-864)+390)/1440;
00087 _bet[2] = nx*((96-437*_n)*_n+30)/1440;
00088 nx *= _n;
00089 _alp[3] = (427-1236*_n)*nx/1680;
00090 _bet[3] = (119-148*_n)*nx/3360;
00091 nx *= _n;
00092 _alp[4] = 49561*nx/161280;
00093 _bet[4] = 4397*nx/161280;
00094 break;
00095 case 5:
00096 _b1 = 1/(1+_n)*(nx*(nx+16)+64)/64;
00097 _alp[1] = _n*(_n*(_n*((328-635*_n)*_n+450)-960)+720)/1440;
00098 _bet[1] = _n*(_n*(_n*((-3645*_n-64)*_n+8880)-15360)+11520)/23040;
00099 _alp[2] = nx*(_n*(_n*(4496*_n+3899)-6048)+2730)/10080;
00100 _bet[2] = nx*(_n*(_n*(4416*_n-3059)+672)+210)/10080;
00101 nx *= _n;
00102 _alp[3] = nx*(_n*(15061*_n-19776)+6832)/26880;
00103 _bet[3] = nx*((-627*_n-592)*_n+476)/13440;
00104 nx *= _n;
00105 _alp[4] = (49561-171840*_n)*nx/161280;
00106 _bet[4] = (4397-3520*_n)*nx/161280;
00107 nx *= _n;
00108 _alp[5] = 34729*nx/80640;
00109 _bet[5] = 4583*nx/161280;
00110 break;
00111 case 6:
00112 _b1 = 1/(1+_n)*(nx*(nx*(nx+4)+64)+256)/256;
00113 _alp[1] = _n*(_n*(_n*(_n*(_n*(31564*_n-66675)+34440)+47250)-100800)+
00114 75600)/151200;
00115 _bet[1] = _n*(_n*(_n*(_n*(_n*(384796*_n-382725)-6720)+932400)-1612800)+
00116 1209600)/2419200;
00117 _alp[2] = nx*(_n*(_n*((863232-1983433*_n)*_n+748608)-1161216)+524160)/
00118 1935360;
00119 _bet[2] = nx*(_n*(_n*((1695744-1118711*_n)*_n-1174656)+258048)+80640)/
00120 3870720;
00121 nx *= _n;
00122 _alp[3] = nx*(_n*(_n*(670412*_n+406647)-533952)+184464)/725760;
00123 _bet[3] = nx*(_n*(_n*(22276*_n-16929)-15984)+12852)/362880;
00124 nx *= _n;
00125 _alp[4] = nx*(_n*(6601661*_n-7732800)+2230245)/7257600;
00126 _bet[4] = nx*((-830251*_n-158400)*_n+197865)/7257600;
00127 nx *= _n;
00128 _alp[5] = (3438171-13675556*_n)*nx/7983360;
00129 _bet[5] = (453717-435388*_n)*nx/15966720;
00130 nx *= _n;
00131 _alp[6] = 212378941*nx/319334400;
00132 _bet[6] = 20648693*nx/638668800;
00133 break;
00134 case 7:
00135 _b1 = 1/(1+_n)*(nx*(nx*(nx+4)+64)+256)/256;
00136 _alp[1] = _n*(_n*(_n*(_n*(_n*(_n*(1804025*_n+2020096)-4267200)+2204160)+
00137 3024000)-6451200)+4838400)/9676800;
00138 _bet[1] = _n*(_n*(_n*(_n*(_n*((6156736-5406467*_n)*_n-6123600)-107520)+
00139 14918400)-25804800)+19353600)/38707200;
00140 _alp[2] = nx*(_n*(_n*(_n*(_n*(4626384*_n-9917165)+4316160)+3743040)-
00141 5806080)+2620800)/9676800;
00142 _bet[2] = nx*(_n*(_n*(_n*(_n*(829456*_n-5593555)+8478720)-5873280)+
00143 1290240)+403200)/19353600;
00144 nx *= _n;
00145 _alp[3] = nx*(_n*(_n*((26816480-67102379*_n)*_n+16265880)-21358080)+
00146 7378560)/29030400;
00147 _bet[3] = nx*(_n*(_n*(_n*(9261899*_n+3564160)-2708640)-2557440)+
00148 2056320)/58060800;
00149 nx *= _n;
00150 _alp[4] = nx*(_n*(_n*(155912000*_n+72618271)-85060800)+24532695)/
00151 79833600;
00152 _bet[4] = nx*(_n*(_n*(14928352*_n-9132761)-1742400)+2176515)/79833600;
00153 nx *= _n;
00154 _alp[5] = nx*(_n*(102508609*_n-109404448)+27505368)/63866880;
00155 _bet[5] = nx*((-8005831*_n-1741552)*_n+1814868)/63866880;
00156 nx *= _n;
00157 _alp[6] = (2760926233.0-12282192400.0*_n)*nx/4151347200.0;
00158 _bet[6] = (268433009-261810608*_n)*nx/8302694400.0;
00159 nx *= _n;
00160 _alp[7] = 1522256789.0*nx/1383782400.0;
00161 _bet[7] = 219941297*nx/5535129600.0;
00162 break;
00163 case 8:
00164 _b1 = 1/(1+_n)*(nx*(nx*(nx*(25*nx+64)+256)+4096)+16384)/16384;
00165 _alp[1] = _n*(_n*(_n*(_n*(_n*(_n*((37884525-75900428*_n)*_n+42422016)-
00166 89611200)+46287360)+63504000)-135475200)+
00167 101606400)/203212800;
00168 _bet[1] = _n*(_n*(_n*(_n*(_n*(_n*(_n*(31777436*_n-37845269)+43097152)-
00169 42865200)-752640)+104428800)-180633600)+
00170 135475200)/270950400;
00171 _alp[2] = nx*(_n*(_n*(_n*(_n*(_n*(148003883*_n+83274912)-178508970)+
00172 77690880)+67374720)-104509440)+47174400)/
00173 174182400;
00174 _bet[2] = nx*(_n*(_n*(_n*(_n*(_n*(24749483*_n+14930208)-100683990)+
00175 152616960)-105719040)+23224320)+7257600)/
00176 348364800;
00177 nx *= _n;
00178 _alp[3] = nx*(_n*(_n*(_n*(_n*(318729724*_n-738126169)+294981280)+
00179 178924680)-234938880)+81164160)/319334400;
00180 _bet[3] = nx*(_n*(_n*(_n*((101880889-232468668*_n)*_n+39205760)-
00181 29795040)-28131840)+22619520)/638668800;
00182 nx *= _n;
00183 _alp[4] = nx*(_n*(_n*((14967552000.0-40176129013.0*_n)*_n+6971354016.0)-
00184 8165836800.0)+2355138720.0)/7664025600.0;
00185 _bet[4] = nx*(_n*(_n*(_n*(324154477*_n+1433121792.0)-876745056)-
00186 167270400)+208945440)/7664025600.0;
00187 nx *= _n;
00188 _alp[5] = nx*(_n*(_n*(10421654396.0*_n+3997835751.0)-4266773472.0)+
00189 1072709352.0)/2490808320.0;
00190 _bet[5] = nx*(_n*(_n*(457888660*_n-312227409)-67920528)+70779852)/
00191 2490808320.0;
00192 nx *= _n;
00193 _alp[6] = nx*(_n*(175214326799.0*_n-171950693600.0)+38652967262.0)/
00194 58118860800.0;
00195 _bet[6] = nx*((-19841813847.0*_n-3665348512.0)*_n+3758062126.0)/
00196 116237721600.0;
00197 nx *= _n;
00198 _alp[7] = (13700311101.0-67039739596.0*_n)*nx/12454041600.0;
00199 _bet[7] = (1979471673.0-1989295244.0*_n)*nx/49816166400.0;
00200 nx *= _n;
00201 _alp[8] = 1424729850961.0*nx/743921418240.0;
00202 _bet[8] = 191773887257.0*nx/3719607091200.0;
00203 break;
00204 default:
00205 STATIC_ASSERT(maxpow >= 4 && maxpow <= 8, "Bad value of maxpow");
00206 }
00207
00208
00209 _a1 = _b1 * _a;
00210 }
00211
00212 const TransverseMercator
00213 TransverseMercator::UTM(Constants::WGS84_a<real>(),
00214 Constants::WGS84_r<real>(),
00215 Constants::UTM_k0<real>());
00216
00217 void TransverseMercator::Forward(real lon0, real lat, real lon,
00218 real& x, real& y, real& gamma, real& k)
00219 const throw() {
00220
00221 if (lon - lon0 > 180)
00222 lon -= lon0 + 360;
00223 else if (lon - lon0 <= -180)
00224 lon -= lon0 - 360;
00225 else
00226 lon -= lon0;
00227
00228
00229 int
00230 latsign = lat < 0 ? -1 : 1,
00231 lonsign = lon < 0 ? -1 : 1;
00232 lon *= lonsign;
00233 lat *= latsign;
00234 bool backside = lon > 90;
00235 if (backside) {
00236 if (lat == 0)
00237 latsign = -1;
00238 lon = 180 - lon;
00239 }
00240 real
00241 phi = lat * Math::degree<real>(),
00242 lam = lon * Math::degree<real>();
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 real etap, xip;
00261 if (lat != 90) {
00262 real
00263 c = max(real(0), cos(lam)),
00264 tau = tan(phi),
00265 secphi = Math::hypot(real(1), tau),
00266 sig = sinh( eatanhe(tau / secphi) ),
00267 taup = Math::hypot(real(1), sig) * tau - sig * secphi;
00268 xip = atan2(taup, c);
00269
00270
00271 etap = Math::asinh(sin(lam) / Math::hypot(taup, c));
00272
00273
00274
00275 gamma = atan(tanx(lam) *
00276 taup / Math::hypot(real(1), taup));
00277
00278
00279
00280
00281
00282
00283
00284 k = sqrt(_e2m + _e2 * sq(cos(phi))) * secphi / Math::hypot(taup, c);
00285 } else {
00286 xip = Math::pi<real>()/2;
00287 etap = 0;
00288 gamma = lam;
00289 k = _c;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 real
00345 c0 = cos(2 * xip), ch0 = cosh(2 * etap),
00346 s0 = sin(2 * xip), sh0 = sinh(2 * etap),
00347 ar = 2 * c0 * ch0, ai = -2 * s0 * sh0;
00348 int n = maxpow;
00349 real
00350 xi0 = (n & 1 ? _alp[n] : 0), eta0 = 0,
00351 xi1 = 0, eta1 = 0;
00352 real
00353 yr0 = (n & 1 ? 2 * maxpow * _alp[n--] : 0), yi0 = 0,
00354 yr1 = 0, yi1 = 0;
00355 while (n) {
00356 xi1 = ar * xi0 - ai * eta0 - xi1 + _alp[n];
00357 eta1 = ai * xi0 + ar * eta0 - eta1;
00358 yr1 = ar * yr0 - ai * yi0 - yr1 + 2 * n * _alp[n];
00359 yi1 = ai * yr0 + ar * yi0 - yi1;
00360 --n;
00361 xi0 = ar * xi1 - ai * eta1 - xi0 + _alp[n];
00362 eta0 = ai * xi1 + ar * eta1 - eta0;
00363 yr0 = ar * yr1 - ai * yi1 - yr0 + 2 * n * _alp[n];
00364 yi0 = ai * yr1 + ar * yi1 - yi0;
00365 --n;
00366 }
00367 ar /= 2; ai /= 2;
00368 yr1 = 1 - yr1 + ar * yr0 - ai * yi0;
00369 yi1 = - yi1 + ai * yr0 + ar * yi0;
00370 ar = s0 * ch0; ai = c0 * sh0;
00371 real
00372 xi = xip + ar * xi0 - ai * eta0,
00373 eta = etap + ai * xi0 + ar * eta0;
00374
00375
00376 gamma -= atan2(yi1, yr1);
00377 k *= _b1 * Math::hypot(yr1, yi1);
00378 gamma /= Math::degree<real>();
00379 y = _a1 * _k0 * (backside ? Math::pi<real>() - xi : xi) * latsign;
00380 x = _a1 * _k0 * eta * lonsign;
00381 if (backside)
00382 gamma = 180 - gamma;
00383 gamma *= latsign * lonsign;
00384 k *= _k0;
00385 }
00386
00387 void TransverseMercator::Reverse(real lon0, real x, real y,
00388 real& lat, real& lon, real& gamma, real& k)
00389 const throw() {
00390
00391
00392
00393 real
00394 xi = y / (_a1 * _k0),
00395 eta = x / (_a1 * _k0);
00396
00397 int
00398 xisign = xi < 0 ? -1 : 1,
00399 etasign = eta < 0 ? -1 : 1;
00400 xi *= xisign;
00401 eta *= etasign;
00402 bool backside = xi > Math::pi<real>()/2;
00403 if (backside)
00404 xi = Math::pi<real>() - xi;
00405 real
00406 c0 = cos(2 * xi), ch0 = cosh(2 * eta),
00407 s0 = sin(2 * xi), sh0 = sinh(2 * eta),
00408 ar = 2 * c0 * ch0, ai = -2 * s0 * sh0;
00409 int n = maxpow;
00410 real
00411 xip0 = (n & 1 ? -_bet[n] : 0), etap0 = 0,
00412 xip1 = 0, etap1 = 0;
00413 real
00414 yr0 = (n & 1 ? - 2 * maxpow * _bet[n--] : 0), yi0 = 0,
00415 yr1 = 0, yi1 = 0;
00416 while (n) {
00417 xip1 = ar * xip0 - ai * etap0 - xip1 - _bet[n];
00418 etap1 = ai * xip0 + ar * etap0 - etap1;
00419 yr1 = ar * yr0 - ai * yi0 - yr1 - 2 * n * _bet[n];
00420 yi1 = ai * yr0 + ar * yi0 - yi1;
00421 --n;
00422 xip0 = ar * xip1 - ai * etap1 - xip0 - _bet[n];
00423 etap0 = ai * xip1 + ar * etap1 - etap0;
00424 yr0 = ar * yr1 - ai * yi1 - yr0 - 2 * n * _bet[n];
00425 yi0 = ai * yr1 + ar * yi1 - yi0;
00426 --n;
00427 }
00428 ar /= 2; ai /= 2;
00429 yr1 = 1 - yr1 + ar * yr0 - ai * yi0;
00430 yi1 = - yi1 + ai * yr0 + ar * yi0;
00431 ar = s0 * ch0; ai = c0 * sh0;
00432 real
00433 xip = xi + ar * xip0 - ai * etap0,
00434 etap = eta + ai * xip0 + ar * etap0;
00435
00436 gamma = atan2(yi1, yr1);
00437 k = _b1 / Math::hypot(yr1, yi1);
00438
00439
00440
00441
00442
00443 real lam, phi;
00444 real
00445 s = sinh(etap),
00446 c = max(real(0), cos(xip)),
00447 r = Math::hypot(s, c);
00448 if (r != 0) {
00449 lam = atan2(s, c);
00450
00451 real
00452 taup = sin(xip)/r,
00453 tau = taup,
00454 stol = tol * max(real(1), abs(taup));
00455
00456 for (int i = 0; i < numit; ++i) {
00457 real
00458 tau1 = Math::hypot(real(1), tau),
00459 sig = sinh( eatanhe( tau / tau1 ) ),
00460 taupa = Math::hypot(real(1), sig) * tau - sig * tau1,
00461 dtau = (taup - taupa) * (1 + _e2m * sq(tau)) /
00462 ( _e2m * tau1 * Math::hypot(real(1), taupa) );
00463 tau += dtau;
00464 if (!(abs(dtau) >= stol))
00465 break;
00466 }
00467 phi = atan(tau);
00468 gamma += atan(tanx(xip) * tanh(etap));
00469
00470 k *= sqrt(_e2m + _e2 * sq(cos(phi))) * Math::hypot(real(1), tau) * r;
00471 } else {
00472 phi = Math::pi<real>()/2;
00473 lam = 0;
00474 k *= _c;
00475 }
00476 lat = phi / Math::degree<real>() * xisign;
00477 lon = lam / Math::degree<real>();
00478 if (backside)
00479 lon = 180 - lon;
00480 lon *= etasign;
00481
00482 if (lon + lon0 >= 180)
00483 lon += lon0 - 360;
00484 else if (lon + lon0 < -180)
00485 lon += lon0 + 360;
00486 else
00487 lon += lon0;
00488 gamma /= Math::degree<real>();
00489 if (backside)
00490 gamma = 180 - gamma;
00491 gamma *= xisign * etasign;
00492 k *= _k0;
00493 }
00494
00495 }