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 #include "GeographicLib/TransverseMercatorExact.hpp"
00041 #include "GeographicLib/Constants.hpp"
00042 #include <limits>
00043 #include <algorithm>
00044
00045 namespace {
00046 char RCSID[] = "$Id: TransverseMercatorExact.cpp 6568 2009-03-01 17:58:41Z ckarney $";
00047 char RCSID_H[] = TRANSVERSEMERCATOREXACT_HPP;
00048 }
00049
00050 namespace GeographicLib {
00051
00052 using namespace std;
00053
00054 const double TransverseMercatorExact::tol = numeric_limits<double>::epsilon();
00055 const double TransverseMercatorExact::tol1 = 0.1 * sqrt(tol);
00056 const double TransverseMercatorExact::tol2 = 0.1 * tol;
00057 const double TransverseMercatorExact::taytol = pow(tol, 0.6);
00058
00059 const double TransverseMercatorExact::ahypover =
00060 (double)(numeric_limits<double>::digits)
00061 /log((double)(numeric_limits<double>::radix)) + 2;
00062
00063 TransverseMercatorExact::TransverseMercatorExact(double a, double invf,
00064 double k0, bool extendp)
00065 throw()
00066 : _a(a)
00067 , _f(1 / invf)
00068 , _k0(k0)
00069 , _mu(_f * (2 - _f))
00070 , _mv(1 - _mu)
00071 , _e(sqrt(_mu))
00072 , _ep2(_mu / _mv)
00073 , _extendp(extendp)
00074 , _Eu(_mu)
00075 , _Ev(_mv)
00076 {}
00077
00078 const TransverseMercatorExact
00079 TransverseMercatorExact::UTM(Constants::WGS84_a(), Constants::WGS84_invf(),
00080 Constants::UTM_k0());
00081
00082 double TransverseMercatorExact::psi(double phi) const throw() {
00083 double s = sin(phi);
00084
00085
00086
00087 return asinh(s / max(cos(phi), 0.1 * tol)) - _e * atanh(_e * s);
00088 }
00089
00090 double TransverseMercatorExact::psiinv(double psi) const throw() {
00091
00092
00093
00094
00095
00096
00097 double q = psi;
00098 for (int i = 0; i < numit; ++i) {
00099
00100 double
00101 t = tanh(q),
00102 dq = -(q - _e * atanh(_e * t) - psi) * (1 - _mu * sq(t)) / _mv;
00103 q += dq;
00104 if (abs(dq) < tol1)
00105 break;
00106 }
00107 return atan(sinh(q));
00108 }
00109
00110 void TransverseMercatorExact::zeta(double u,
00111 double snu, double cnu, double dnu,
00112 double v,
00113 double snv, double cnv, double dnv,
00114 double& psi, double& lam) const throw() {
00115
00116
00117
00118 double
00119 d1 = sqrt(sq(cnu) + _mv * sq(snu * snv)),
00120 d2 = sqrt(_mu * sq(cnu) + _mv * sq(cnv));
00121 psi =
00122
00123 (d1 ? asinh(snu * dnv / d1) : snu < 0 ? -ahypover : ahypover)
00124 - (d2 ? _e * asinh(_e * snu / d2) : snu < 0 ? -ahypover : ahypover);
00125 lam = (d1 != 0 && d2 != 0) ?
00126 atan2(dnu * snv, cnu * cnv) - _e * atan2(_e * cnu * snv, dnu * cnv) :
00127 0;
00128 }
00129
00130 void TransverseMercatorExact::dwdzeta(double u,
00131 double snu, double cnu, double dnu,
00132 double v,
00133 double snv, double cnv, double dnv,
00134 double& du, double& dv) const throw() {
00135
00136
00137 double d = _mv * sq(sq(cnv) + _mu * sq(snu * snv));
00138 du = cnu * dnu * dnv * (sq(cnv) - _mu * sq(snu * snv)) / d;
00139 dv = -snu * snv * cnv * (sq(dnu * dnv) + _mu * sq(cnu)) / d;
00140 }
00141
00142
00143 bool TransverseMercatorExact::zetainv0(double psi, double lam,
00144 double& u, double& v) const throw() {
00145 bool retval = false;
00146 if (psi < -_e * Constants::pi()/4 &&
00147 lam > (1 - 2 * _e) * Constants::pi()/2 &&
00148 psi < lam - (1 - _e) * Constants::pi()/2) {
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 double
00159 psix = 1 - psi / _e,
00160 lamx = (Constants::pi()/2 - lam) / _e;
00161 u = asinh(sin(lamx) / hypot(cos(lamx), sinh(psix))) * (1 + _mu/2);
00162 v = atan2(cos(lamx), sinh(psix)) * (1 + _mu/2);
00163 u = _Eu.K() - u;
00164 v = _Ev.K() - v;
00165 } else if (psi < _e * Constants::pi()/2 &&
00166 lam > (1 - 2 * _e) * Constants::pi()/2) {
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 double
00179 dlam = lam - (1 - _e) * Constants::pi()/2,
00180 rad = hypot(psi, dlam),
00181
00182
00183
00184
00185
00186 ang = atan2(dlam-psi, psi+dlam) - 0.75 * Constants::pi();
00187
00188 retval = rad < _e * taytol;
00189 rad = pow(3 / (_mv * _e) * rad, 1/3.0);
00190 ang /= 3;
00191 u = rad * cos(ang);
00192 v = rad * sin(ang) + _Ev.K();
00193 } else {
00194
00195
00196
00197 v = asinh(sin(lam) / hypot(cos(lam), sinh(psi)));
00198 u = atan2(sinh(psi), cos(lam));
00199
00200 u *= _Eu.K() / (Constants::pi()/2);
00201 v *= _Eu.K() / (Constants::pi()/2);
00202 }
00203 return retval;
00204 }
00205
00206
00207 void TransverseMercatorExact::zetainv(double psi, double lam,
00208 double& u, double& v) const throw() {
00209 if (zetainv0(psi, lam, u, v))
00210 return;
00211 double stol2 = tol2 / sq(max(psi, 1.0));
00212
00213 for (int i = 0, trip = 0; i < numit; ++i) {
00214 double snu, cnu, dnu, snv, cnv, dnv;
00215 _Eu.sncndn(u, snu, cnu, dnu);
00216 _Ev.sncndn(v, snv, cnv, dnv);
00217 double psi1, lam1, du1, dv1;
00218 zeta(u, snu, cnu, dnu, v, snv, cnv, dnv, psi1, lam1);
00219 dwdzeta(u, snu, cnu, dnu, v, snv, cnv, dnv, du1, dv1);
00220 psi1 -= psi;
00221 lam1 -= lam;
00222 double
00223 delu = psi1 * du1 - lam1 * dv1,
00224 delv = psi1 * dv1 + lam1 * du1;
00225 u -= delu;
00226 v -= delv;
00227 if (trip)
00228 break;
00229 double delw2 = sq(delu) + sq(delv);
00230 if (delw2 < stol2)
00231 ++trip;
00232 }
00233 }
00234
00235 void TransverseMercatorExact::sigma(double u,
00236 double snu, double cnu, double dnu,
00237 double v,
00238 double snv, double cnv, double dnv,
00239 double& xi, double& eta) const throw() {
00240
00241
00242 double d = _mu * sq(cnu) + _mv * sq(cnv);
00243 xi = _Eu.E(snu, cnu, dnu) - _mu * snu * cnu * dnu / d;
00244 eta = v - _Ev.E(snv, cnv, dnv) + _mv * snv * cnv * dnv / d;
00245 }
00246
00247 void TransverseMercatorExact::dwdsigma(double u,
00248 double snu, double cnu, double dnu,
00249 double v,
00250 double snv, double cnv, double dnv,
00251 double& du, double& dv) const throw() {
00252
00253
00254 double d = _mv * sq(sq(cnv) + _mu * sq(snu * snv));
00255 double
00256 dnr = dnu * cnv * dnv,
00257 dni = - _mu * snu * cnu * snv;
00258 du = (sq(dnr) - sq(dni)) / d;
00259 dv = 2 * dnr * dni / d;
00260 }
00261
00262
00263 bool TransverseMercatorExact::sigmainv0(double xi, double eta,
00264 double& u, double& v) const throw() {
00265 bool retval = false;
00266 if (eta > 1.25 * _Ev.KE() ||
00267 (xi < -0.25 * _Eu.E() && xi < eta - _Ev.KE())) {
00268
00269
00270
00271
00272 double
00273 x = xi - _Eu.E(),
00274 y = eta - _Ev.KE(),
00275 r2 = sq(x) + sq(y);
00276 u = _Eu.K() + x/r2;
00277 v = _Ev.K() - y/r2;
00278 } else if ((eta > 0.75 * _Ev.KE() && xi < 0.25 * _Eu.E())
00279 || eta > _Ev.KE()) {
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 double
00293 deta = eta - _Ev.KE(),
00294 rad = hypot(xi, deta),
00295
00296
00297 ang = atan2(deta-xi, xi+deta) - 0.75 * Constants::pi();
00298
00299 retval = rad < 2 * taytol;
00300 rad = pow(3 / _mv * rad, 1/3.0);
00301 ang /= 3;
00302 u = rad * cos(ang);
00303 v = rad * sin(ang) + _Ev.K();
00304 } else {
00305
00306 u = xi * _Eu.K()/_Eu.E();
00307 v = eta * _Eu.K()/_Eu.E();
00308 }
00309 return retval;
00310 }
00311
00312
00313 void TransverseMercatorExact::sigmainv(double xi, double eta,
00314 double& u, double& v) const throw() {
00315 if (sigmainv0(xi, eta, u, v))
00316 return;
00317
00318 for (int i = 0, trip = 0; i < numit; ++i) {
00319 double snu, cnu, dnu, snv, cnv, dnv;
00320 _Eu.sncndn(u, snu, cnu, dnu);
00321 _Ev.sncndn(v, snv, cnv, dnv);
00322 double xi1, eta1, du1, dv1;
00323 sigma(u, snu, cnu, dnu, v, snv, cnv, dnv, xi1, eta1);
00324 dwdsigma(u, snu, cnu, dnu, v, snv, cnv, dnv, du1, dv1);
00325 xi1 -= xi;
00326 eta1 -= eta;
00327 double
00328 delu = xi1 * du1 - eta1 * dv1,
00329 delv = xi1 * dv1 + eta1 * du1;
00330 u -= delu;
00331 v -= delv;
00332 if (trip)
00333 break;
00334 double delw2 = sq(delu) + sq(delv);
00335 if (delw2 < tol2)
00336 ++trip;
00337 }
00338 }
00339
00340 void TransverseMercatorExact::Scale(double phi, double lam,
00341 double snu, double cnu, double dnu,
00342 double snv, double cnv, double dnv,
00343 double& gamma, double& k) const throw() {
00344 double
00345 c = cos(phi),
00346 s = sin(lam),
00347 c2 = sq(c),
00348 s2 = sq(s),
00349 d = 1 - s2 * c2;
00350
00351 if ( !( phi > 0 && d > 0.75 && c2 * sq(c2 * _ep2) * s2 < tol ) ) {
00352
00353
00354 gamma = atan2(_mv * snu * snv * cnv, cnu * dnu * dnv);
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368 k = sqrt(_mv + _mu * sq(c)) / c *
00369 sqrt( (_mv * sq(snv) + sq(cnu * dnv)) /
00370 (_mu * sq(cnu) + _mv * sq(cnv)) );
00371 } else {
00372
00373
00374
00375 double
00376
00377 gam1 = sq(c2) * s2 / d * _ep2,
00378
00379
00380 k1 = gam1 * ((c2 - 2) * s2 + 1) / (2 * d);
00381 gamma = atan2(sin(phi) * s * (1 + gam1), cos(lam));
00382 k = (1 + k1) / sqrt(d);
00383 }
00384 }
00385
00386 void TransverseMercatorExact::Forward(double lon0, double lat, double lon,
00387 double& x, double& y,
00388 double& gamma, double& k)
00389 const throw() {
00390
00391 if (lon - lon0 > 180)
00392 lon -= lon0 - 360;
00393 else if (lon - lon0 <= -180)
00394 lon -= lon0 + 360;
00395 else
00396 lon -= lon0;
00397
00398
00399 int
00400 latsign = !_extendp && lat < 0 ? -1 : 1,
00401 lonsign = !_extendp && lon < 0 ? -1 : 1;
00402 lon *= lonsign;
00403 lat *= latsign;
00404 bool backside = !_extendp && lon > 90;
00405 if (backside) {
00406 if (lat == 0)
00407 latsign = -1;
00408 lon = 180 - lon;
00409 }
00410 double
00411 phi = lat * Constants::degree(),
00412 lam = lon * Constants::degree();
00413
00414
00415 double u, v;
00416 if (lat == 90) {
00417 u = _Eu.K();
00418 v = 0;
00419 } else if (lat == 0 && lon == 90 * (1 - _e)) {
00420 u = 0;
00421 v = _Ev.K();
00422 } else
00423 zetainv(psi(phi), lam, u, v);
00424
00425 double snu, cnu, dnu, snv, cnv, dnv;
00426 _Eu.sncndn(u, snu, cnu, dnu);
00427 _Ev.sncndn(v, snv, cnv, dnv);
00428
00429 double xi, eta;
00430 sigma(u, snu, cnu, dnu, v, snv, cnv, dnv, xi, eta);
00431 if (backside)
00432 xi = 2 * _Eu.E() - xi;
00433 y = xi * _a * _k0 * latsign;
00434 x = eta * _a * _k0 * lonsign;
00435
00436 Scale(phi, lam, snu, cnu, dnu, snv, cnv, dnv, gamma, k);
00437 gamma /= Constants::degree();
00438 if (backside)
00439 gamma = 180 - gamma;
00440 gamma *= latsign * lonsign;
00441 k *= _k0;
00442 }
00443
00444 void TransverseMercatorExact::Reverse(double lon0, double x, double y,
00445 double& lat, double& lon,
00446 double& gamma, double& k)
00447 const throw() {
00448
00449 double
00450 xi = y / (_a * _k0),
00451 eta = x / (_a * _k0);
00452
00453 int
00454 latsign = !_extendp && y < 0 ? -1 : 1,
00455 lonsign = !_extendp && x < 0 ? -1 : 1;
00456 xi *= latsign;
00457 eta *= lonsign;
00458 bool backside = !_extendp && xi > _Eu.E();
00459 if (backside)
00460 xi = 2 * _Eu.E()- xi;
00461
00462
00463 double u, v;
00464 if (xi == 0 && eta == _Ev.KE()) {
00465 u = 0;
00466 v = _Ev.K();
00467 } else
00468 sigmainv(xi, eta, u, v);
00469
00470 double snu, cnu, dnu, snv, cnv, dnv;
00471 _Eu.sncndn(u, snu, cnu, dnu);
00472 _Ev.sncndn(v, snv, cnv, dnv);
00473 double phi, lam;
00474 if (v != 0 || u != _Eu.K()) {
00475 double psi;
00476 zeta(u, snu, cnu, dnu, v, snv, cnv, dnv, psi, lam);
00477 phi = psiinv(psi);
00478 lat = phi / Constants::degree();
00479 lon = lam / Constants::degree();
00480 } else {
00481 phi = Constants::pi()/2;
00482 lat = 90;
00483 lon = lam = 0;
00484 }
00485 Scale(phi, lam, snu, cnu, dnu, snv, cnv, dnv, gamma, k);
00486 gamma /= Constants::degree();
00487 if (backside)
00488 lon = 180 - lon;
00489 lon *= lonsign;
00490
00491 if (lon + lon0 >= 180)
00492 lon += lon0 - 360;
00493 else if (lon + lon0 < -180)
00494 lon += lon0 + 360;
00495 else
00496 lon += lon0;
00497 lat *= latsign;
00498 if (backside)
00499 y = 2 * _Eu.E() - y;
00500 y *= _a * _k0 * latsign;
00501 x *= _a * _k0 * lonsign;
00502 if (backside)
00503 gamma = 180 - gamma;
00504 gamma *= latsign * lonsign;
00505 k *= _k0;
00506 }
00507
00508 }