GeographicLib
1.21
|
00001 /** 00002 * \file AlbersEqualArea.cpp 00003 * \brief Implementation for GeographicLib::AlbersEqualArea class 00004 * 00005 * Copyright (c) Charles Karney (2010, 2011) <charles@karney.com> and licensed 00006 * under the MIT/X11 License. For more information, see 00007 * http://geographiclib.sourceforge.net/ 00008 **********************************************************************/ 00009 00010 #include <GeographicLib/AlbersEqualArea.hpp> 00011 00012 #define GEOGRAPHICLIB_ALBERSEQUALAREA_CPP \ 00013 "$Id: a7aa5e2e232feec5c866f0d645f110fd0bb38dd2 $" 00014 00015 RCSID_DECL(GEOGRAPHICLIB_ALBERSEQUALAREA_CPP) 00016 RCSID_DECL(GEOGRAPHICLIB_ALBERSEQUALAREA_HPP) 00017 00018 namespace GeographicLib { 00019 00020 using namespace std; 00021 00022 const Math::real AlbersEqualArea::eps_ = numeric_limits<real>::epsilon(); 00023 const Math::real AlbersEqualArea::epsx_ = Math::sq(eps_); 00024 const Math::real AlbersEqualArea::epsx2_ = Math::sq(epsx_); 00025 const Math::real AlbersEqualArea::tol_ = sqrt(eps_); 00026 const Math::real AlbersEqualArea::tol0_ = tol_ * sqrt(sqrt(eps_)); 00027 const Math::real AlbersEqualArea::ahypover_ = 00028 real(numeric_limits<real>::digits) * log(real(numeric_limits<real>::radix)) 00029 + 2; 00030 00031 AlbersEqualArea::AlbersEqualArea(real a, real f, real stdlat, real k0) 00032 : _a(a) 00033 , _f(f <= 1 ? f : 1/f) 00034 , _fm(1 - _f) 00035 , _e2(_f * (2 - _f)) 00036 , _e(sqrt(abs(_e2))) 00037 , _e2m(1 - _e2) 00038 , _qZ(1 + _e2m * atanhee(real(1))) 00039 , _qx(_qZ / ( 2 * _e2m )) 00040 { 00041 if (!(Math::isfinite(_a) && _a > 0)) 00042 throw GeographicErr("Major radius is not positive"); 00043 if (!(Math::isfinite(_f) && _f < 1)) 00044 throw GeographicErr("Minor radius is not positive"); 00045 if (!(Math::isfinite(k0) && k0 > 0)) 00046 throw GeographicErr("Scale is not positive"); 00047 if (!(abs(stdlat) <= 90)) 00048 throw GeographicErr("Standard latitude not in [-90, 90]"); 00049 real 00050 phi = stdlat * Math::degree<real>(), 00051 sphi = sin(phi), 00052 cphi = abs(stdlat) != 90 ? cos(phi) : 0; 00053 Init(sphi, cphi, sphi, cphi, k0); 00054 } 00055 00056 AlbersEqualArea::AlbersEqualArea(real a, real f, real stdlat1, real stdlat2, 00057 real k1) 00058 : _a(a) 00059 , _f(f <= 1 ? f : 1/f) 00060 , _fm(1 - _f) 00061 , _e2(_f * (2 - _f)) 00062 , _e(sqrt(abs(_e2))) 00063 , _e2m(1 - _e2) 00064 , _qZ(1 + _e2m * atanhee(real(1))) 00065 , _qx(_qZ / ( 2 * _e2m )) 00066 { 00067 if (!(Math::isfinite(_a) && _a > 0)) 00068 throw GeographicErr("Major radius is not positive"); 00069 if (!(Math::isfinite(_f) && _f < 1)) 00070 throw GeographicErr("Minor radius is not positive"); 00071 if (!(Math::isfinite(k1) && k1 > 0)) 00072 throw GeographicErr("Scale is not positive"); 00073 if (!(abs(stdlat1) <= 90)) 00074 throw GeographicErr("Standard latitude 1 not in [-90, 90]"); 00075 if (!(abs(stdlat2) <= 90)) 00076 throw GeographicErr("Standard latitude 2 not in [-90, 90]"); 00077 real 00078 phi1 = stdlat1 * Math::degree<real>(), 00079 phi2 = stdlat2 * Math::degree<real>(); 00080 Init(sin(phi1), abs(stdlat1) != 90 ? cos(phi1) : 0, 00081 sin(phi2), abs(stdlat2) != 90 ? cos(phi2) : 0, k1); 00082 } 00083 00084 AlbersEqualArea::AlbersEqualArea(real a, real f, 00085 real sinlat1, real coslat1, 00086 real sinlat2, real coslat2, 00087 real k1) 00088 : _a(a) 00089 , _f(f <= 1 ? f : 1/f) 00090 , _fm(1 - _f) 00091 , _e2(_f * (2 - _f)) 00092 , _e(sqrt(abs(_e2))) 00093 , _e2m(1 - _e2) 00094 , _qZ(1 + _e2m * atanhee(real(1))) 00095 , _qx(_qZ / ( 2 * _e2m )) 00096 { 00097 if (!(Math::isfinite(_a) && _a > 0)) 00098 throw GeographicErr("Major radius is not positive"); 00099 if (!(Math::isfinite(_f) && _f < 1)) 00100 throw GeographicErr("Minor radius is not positive"); 00101 if (!(Math::isfinite(k1) && k1 > 0)) 00102 throw GeographicErr("Scale is not positive"); 00103 if (!(coslat1 >= 0)) 00104 throw GeographicErr("Standard latitude 1 not in [-90, 90]"); 00105 if (!(coslat2 >= 0)) 00106 throw GeographicErr("Standard latitude 2 not in [-90, 90]"); 00107 if (!(abs(sinlat1) <= 1 && coslat1 <= 1) || (coslat1 == 0 && sinlat1 == 0)) 00108 throw GeographicErr("Bad sine/cosine of standard latitude 1"); 00109 if (!(abs(sinlat2) <= 1 && coslat2 <= 1) || (coslat2 == 0 && sinlat2 == 0)) 00110 throw GeographicErr("Bad sine/cosine of standard latitude 2"); 00111 if (coslat1 == 0 && coslat2 == 0 && sinlat1 * sinlat2 <= 0) 00112 throw GeographicErr 00113 ("Standard latitudes cannot be opposite poles"); 00114 Init(sinlat1, coslat1, sinlat2, coslat2, k1); 00115 } 00116 00117 void AlbersEqualArea::Init(real sphi1, real cphi1, 00118 real sphi2, real cphi2, real k1) throw() { 00119 { 00120 real r; 00121 r = Math::hypot(sphi1, cphi1); 00122 sphi1 /= r; cphi1 /= r; 00123 r = Math::hypot(sphi2, cphi2); 00124 sphi2 /= r; cphi2 /= r; 00125 } 00126 bool polar = (cphi1 == 0); 00127 cphi1 = max(epsx_, cphi1); // Avoid singularities at poles 00128 cphi2 = max(epsx_, cphi2); 00129 // Determine hemisphere of tangent latitude 00130 _sign = sphi1 + sphi2 >= 0 ? 1 : -1; 00131 // Internally work with tangent latitude positive 00132 sphi1 *= _sign; sphi2 *= _sign; 00133 if (sphi1 > sphi2) { 00134 swap(sphi1, sphi2); swap(cphi1, cphi2); // Make phi1 < phi2 00135 } 00136 real 00137 tphi1 = sphi1/cphi1, tphi2 = sphi2/cphi2; 00138 00139 // q = (1-e^2)*(sphi/(1-e^2*sphi^2) - atanhee(sphi)) 00140 // qZ = q(pi/2) = (1 + (1-e^2)*atanhee(1)) 00141 // atanhee(x) = atanh(e*x)/e 00142 // q = sxi * qZ 00143 // dq/dphi = 2*(1-e^2)*cphi/(1-e^2*sphi^2)^2 00144 // 00145 // n = (m1^2-m2^2)/(q2-q1) -> sin(phi0) for phi1, phi2 -> phi0 00146 // C = m1^2 + n*q1 = (m1^2*q2-m2^2*q1)/(q2-q1) 00147 // let 00148 // rho(pi/2)/rho(-pi/2) = (1-s)/(1+s) 00149 // s = n*qZ/C 00150 // = qZ * (m1^2-m2^2)/(m1^2*q2-m2^2*q1) 00151 // = qZ * (scbet2^2 - scbet1^2)/(scbet2^2*q2 - scbet1^2*q1) 00152 // = (scbet2^2 - scbet1^2)/(scbet2^2*sxi2 - scbet1^2*sxi1) 00153 // = (tbet2^2 - tbet1^2)/(scbet2^2*sxi2 - scbet1^2*sxi1) 00154 // 1-s = -((1-sxi2)*scbet2^2 - (1-sxi1)*scbet1^2)/ 00155 // (scbet2^2*sxi2 - scbet1^2*sxi1) 00156 // 00157 // Define phi0 to give same value of s, i.e., 00158 // s = sphi0 * qZ / (m0^2 + sphi0*q0) 00159 // = sphi0 * scbet0^2 / (1/qZ + sphi0 * scbet0^2 * sxi0) 00160 00161 real tphi0, C; 00162 if (polar || tphi1 == tphi2) { 00163 tphi0 = tphi2; 00164 C = 1; // ignored 00165 } else { 00166 real 00167 tbet1 = _fm * tphi1, scbet12 = 1 + Math::sq(tbet1), 00168 tbet2 = _fm * tphi2, scbet22 = 1 + Math::sq(tbet2), 00169 txi1 = txif(tphi1), cxi1 = 1/hyp(txi1), sxi1 = txi1 * cxi1, 00170 txi2 = txif(tphi2), cxi2 = 1/hyp(txi2), sxi2 = txi2 * cxi2, 00171 dtbet2 = _fm * (tbet1 + tbet2), 00172 es1 = 1 - _e2 * Math::sq(sphi1), es2 = 1 - _e2 * Math::sq(sphi2), 00173 /* 00174 dsxi = ( (_e2 * sq(sphi2 + sphi1) + es2 + es1) / (2 * es2 * es1) + 00175 Datanhee(sphi2, sphi1) ) * Dsn(tphi2, tphi1, sphi2, sphi1) / 00176 ( 2 * _qx ), 00177 */ 00178 dsxi = ( (1 + _e2 * sphi1 * sphi2) / (es2 * es1) + 00179 Datanhee(sphi2, sphi1) ) * Dsn(tphi2, tphi1, sphi2, sphi1) / 00180 ( 2 * _qx ), 00181 den = (sxi2 + sxi1) * dtbet2 + (scbet22 + scbet12) * dsxi, 00182 // s = (sq(tbet2) - sq(tbet1)) / (scbet22*sxi2 - scbet12*sxi1) 00183 s = 2 * dtbet2 / den, 00184 // 1-s = -(sq(scbet2)*(1-sxi2) - sq(scbet1)*(1-sxi1)) / 00185 // (scbet22*sxi2 - scbet12*sxi1) 00186 // Write 00187 // sq(scbet)*(1-sxi) = sq(scbet)*(1-sphi) * (1-sxi)/(1-sphi) 00188 sm1 = -Dsn(tphi2, tphi1, sphi2, sphi1) * 00189 ( -( ((sphi2 <= 0 ? (1 - sxi2) / (1 - sphi2) : 00190 Math::sq(cxi2/cphi2) * (1 + sphi2) / (1 + sxi2)) + 00191 (sphi1 <= 0 ? (1 - sxi1) / (1 - sphi1) : 00192 Math::sq(cxi1/cphi1) * (1 + sphi1) / (1 + sxi1))) ) * 00193 (1 + _e2 * (sphi1 + sphi2 + sphi1 * sphi2)) / 00194 (1 + (sphi1 + sphi2 + sphi1 * sphi2)) + 00195 (scbet22 * (sphi2 <= 0 ? 1 - sphi2 : Math::sq(cphi2) / ( 1 + sphi2)) + 00196 scbet12 * (sphi1 <= 0 ? 1 - sphi1 : Math::sq(cphi1) / ( 1 + sphi1))) 00197 * (_e2 * (1 + sphi1 + sphi2 + _e2 * sphi1 * sphi2)/(es1 * es2) 00198 +_e2m * DDatanhee(sphi1, sphi2) ) / _qZ ) / den; 00199 // C = (scbet22*sxi2 - scbet12*sxi1) / (scbet22 * scbet12 * (sx2 - sx1)) 00200 C = den / (2 * scbet12 * scbet22 * dsxi); 00201 tphi0 = (tphi2 + tphi1)/2; 00202 real stol = tol0_ * max(real(1), abs(tphi0)); 00203 for (int i = 0; i < 2*numit0_; ++i) { 00204 // Solve (scbet0^2 * sphi0) / (1/qZ + scbet0^2 * sphi0 * sxi0) = s 00205 // for tphi0 by Newton's method on 00206 // v(tphi0) = (scbet0^2 * sphi0) - s * (1/qZ + scbet0^2 * sphi0 * sxi0) 00207 // = 0 00208 // Alt: 00209 // (scbet0^2 * sphi0) / (1/qZ - scbet0^2 * sphi0 * (1-sxi0)) = s / (1-s) 00210 // w(tphi0) = (1-s) * (scbet0^2 * sphi0) 00211 // - s * (1/qZ - scbet0^2 * sphi0 * (1-sxi0)) 00212 // = (1-s) * (scbet0^2 * sphi0) 00213 // - S/qZ * (1 - scbet0^2 * sphi0 * (qZ-q0)) 00214 // Now 00215 // qZ-q0 = (1+e2*sphi0)*(1-sphi0)/(1-e2*sphi0^2) + 00216 // (1-e2)*atanhee((1-sphi0)/(1-e2*sphi0)) 00217 // In limit sphi0 -> 1, qZ-q0 -> 2*(1-sphi0)/(1-e2), so wrte 00218 // qZ-q0 = 2*(1-sphi0)/(1-e2) + A + B 00219 // A = (1-sphi0)*( (1+e2*sphi0)/(1-e2*sphi0^2) - (1+e2)/(1-e2) ) 00220 // = -e2 *(1-sphi0)^2 * (2+(1+e2)*sphi0) / ((1-e2)*(1-e2*sphi0^2)) 00221 // B = (1-e2)*atanhee((1-sphi0)/(1-e2*sphi0)) - (1-sphi0) 00222 // = (1-sphi0)*(1-e2)/(1-e2*sphi0)* 00223 // ((atanhee(x)/x-1) - e2*(1-sphi0)/(1-e2)) 00224 // x = (1-sphi0)/(1-e2*sphi0), atanhee(x)/x = atanh(e*x)/(e*x) 00225 // 00226 // 1 - scbet0^2 * sphi0 * (qZ-q0) 00227 // = 1 - scbet0^2 * sphi0 * (2*(1-sphi0)/(1-e2) + A + B) 00228 // = D - scbet0^2 * sphi0 * (A + B) 00229 // D = 1 - scbet0^2 * sphi0 * 2*(1-sphi0)/(1-e2) 00230 // = (1-sphi0)*(1-e2*(1+2*sphi0*(1+sphi0)))/((1-e2)*(1+sphi0)) 00231 // dD/dsphi0 = -2*(1-e2*sphi0^2*(2*sphi0+3))/((1-e2)*(1+sphi0)^2) 00232 // d(A+B)/dsphi0 = 2*(1-sphi0^2)*e2*(2-e2*(1+sphi0^2))/ 00233 // ((1-e2)*(1-e2*sphi0^2)^2) 00234 00235 real 00236 scphi02 = 1 + Math::sq(tphi0), scphi0 = sqrt(scphi02), 00237 // sphi0m = 1-sin(phi0) = 1/( sec(phi0) * (tan(phi0) + sec(phi0)) ) 00238 sphi0 = tphi0 / scphi0, sphi0m = 1/(scphi0 * (tphi0 + scphi0)), 00239 // scbet0^2 * sphi0 00240 g = (1 + Math::sq( _fm * tphi0 )) * sphi0, 00241 // dg/dsphi0 = dg/dtphi0 * scphi0^3 00242 dg = _e2m * scphi02 * (1 + 2 * Math::sq(tphi0)) + _e2, 00243 D = sphi0m * (1 - _e2*(1 + 2*sphi0*(1+sphi0))) / (_e2m * (1+sphi0)), 00244 // dD/dsphi0 00245 dD = -2 * (1 - _e2*Math::sq(sphi0) * (2*sphi0+3)) / 00246 (_e2m * Math::sq(1+sphi0)), 00247 A = -_e2 * Math::sq(sphi0m) * (2+(1+_e2)*sphi0) / 00248 (_e2m*(1-_e2*Math::sq(sphi0))), 00249 B = (sphi0m * _e2m / (1 - _e2*sphi0) * 00250 (atanhxm1(_e2 * 00251 Math::sq(sphi0m / (1-_e2*sphi0))) - _e2*sphi0m/_e2m)), 00252 // d(A+B)/dsphi0 00253 dAB = (2 * _e2 * (2 - _e2 * (1 + Math::sq(sphi0))) / 00254 (_e2m * Math::sq(1 - _e2*Math::sq(sphi0)) * scphi02)), 00255 u = sm1 * g - s/_qZ * ( D - g * (A + B) ), 00256 // du/dsphi0 00257 du = sm1 * dg - s/_qZ * (dD - dg * (A + B) - g * dAB), 00258 dtu = -u/du * (scphi0 * scphi02); 00259 tphi0 += dtu; 00260 if (!(abs(dtu) >= stol)) 00261 break; 00262 } 00263 } 00264 _txi0 = txif(tphi0); _scxi0 = hyp(_txi0); _sxi0 = _txi0 / _scxi0; 00265 _n0 = tphi0/hyp(tphi0); 00266 _m02 = 1 / (1 + Math::sq(_fm * tphi0)); 00267 _nrho0 = polar ? 0 : _a * sqrt(_m02); 00268 _k0 = sqrt(tphi1 == tphi2 ? 1 : C / (_m02 + _n0 * _qZ * _sxi0)) * k1; 00269 _k2 = Math::sq(_k0); 00270 _lat0 = _sign * atan(tphi0)/Math::degree<real>(); 00271 } 00272 00273 const AlbersEqualArea 00274 AlbersEqualArea::CylindricalEqualArea(Constants::WGS84_a<real>(), 00275 Constants::WGS84_f<real>(), 00276 real(0), real(1), real(0), real(1), 00277 real(1)); 00278 00279 const AlbersEqualArea 00280 AlbersEqualArea::AzimuthalEqualAreaNorth(Constants::WGS84_a<real>(), 00281 Constants::WGS84_f<real>(), 00282 real(1), real(0), real(1), real(0), 00283 real(1)); 00284 00285 const AlbersEqualArea 00286 AlbersEqualArea::AzimuthalEqualAreaSouth(Constants::WGS84_a<real>(), 00287 Constants::WGS84_f<real>(), 00288 real(-1), real(0), real(-1), real(0), 00289 real(1)); 00290 00291 Math::real AlbersEqualArea::txif(real tphi) const throw() { 00292 // sxi = ( sphi/(1-e2*sphi^2) + atanhee(sphi) ) / 00293 // ( 1/(1-e2) + atanhee(1) ) 00294 // 00295 // txi = ( sphi/(1-e2*sphi^2) + atanhee(sphi) ) / 00296 // sqrt( ( (1+e2*sphi)*(1-sphi)/( (1-e2*sphi^2) * (1-e2) ) + 00297 // atanhee((1-sphi)/(1-e2*sphi)) ) * 00298 // ( (1-e2*sphi)*(1+sphi)/( (1-e2*sphi^2) * (1-e2) ) + 00299 // atanhee((1+sphi)/(1+e2*sphi)) ) ) 00300 // 00301 // subst 1-sphi = cphi^2/(1+sphi) 00302 int s = tphi < 0 ? -1 : 1; // Enforce odd parity 00303 tphi *= s; 00304 real 00305 cphi2 = 1 / (1 + Math::sq(tphi)), 00306 sphi = tphi * sqrt(cphi2), 00307 es1 = _e2 * sphi, 00308 es2m1 = 1 - es1 * sphi, 00309 sp1 = 1 + sphi, 00310 es1m1 = (1 - es1) * sp1, 00311 es2m1a = _e2m * es2m1, 00312 es1p1 = sp1 / (1 + es1); 00313 return s * ( sphi / es2m1 + atanhee(sphi) ) / 00314 sqrt( ( cphi2 / (es1p1 * es2m1a) + atanhee(cphi2 / es1m1) ) * 00315 ( es1m1 / es2m1a + atanhee(es1p1) ) ); 00316 } 00317 00318 Math::real AlbersEqualArea::tphif(real txi) const throw() { 00319 real 00320 tphi = txi, 00321 stol = tol_ * max(real(1), abs(txi)); 00322 // CHECK: min iterations = 1, max iterations = 2; mean = 1.99 00323 for (int i = 0; i < numit_; ++i) { 00324 // dtxi/dtphi = (scxi/scphi)^3 * 2*(1-e^2)/(qZ*(1-e^2*sphi^2)^2) 00325 real 00326 txia = txif(tphi), 00327 tphi2 = Math::sq(tphi), 00328 scphi2 = 1 + tphi2, 00329 scterm = scphi2/(1 + Math::sq(txia)), 00330 dtphi = (txi - txia) * scterm * sqrt(scterm) * 00331 _qx * Math::sq(1 - _e2 * tphi2 / scphi2); 00332 tphi += dtphi; 00333 if (!(abs(dtphi) >= stol)) 00334 break; 00335 } 00336 return tphi; 00337 } 00338 00339 // return atanh(sqrt(x))/sqrt(x) - 1 = y/3 + y^2/5 + y^3/7 + ... 00340 // typical x < e^2 = 2*f 00341 Math::real AlbersEqualArea::atanhxm1(real x) throw() { 00342 real s = 0; 00343 if (abs(x) < real(0.5)) { 00344 real os = -1, y = 1, k = 1; 00345 while (os != s) { 00346 os = s; 00347 y *= x; // y = x^n 00348 k += 2; // k = 2*n + 1 00349 s += y/k; // sum( x^n/(2*n + 1) ) 00350 } 00351 } else { 00352 real xs = sqrt(abs(x)); 00353 s = (x > 0 ? Math::atanh(xs) : atan(xs)) / xs - 1; 00354 } 00355 return s; 00356 } 00357 00358 // return (Datanhee(1,y) - Datanhee(1,x))/(y-x) 00359 Math::real AlbersEqualArea::DDatanhee(real x, real y) const throw() { 00360 real s = 0; 00361 if (_e2 * (abs(x) + abs(y)) < real(0.5)) { 00362 real os = -1, z = 1, k = 1, t = 0, c = 0, en = 1; 00363 while (os != s) { 00364 os = s; 00365 t = y * t + z; c += t; z *= x; 00366 t = y * t + z; c += t; z *= x; 00367 k += 2; en *= _e2; 00368 // Here en[l] = e2^l, k[l] = 2*l + 1, 00369 // c[l] = sum( x^i * y^j; i >= 0, j >= 0, i+j < 2*l) 00370 s += en * c / k; 00371 } 00372 // Taylor expansion is 00373 // s = sum( c[l] * e2^l / (2*l + 1), l, 1, N) 00374 } else 00375 s = (Datanhee(1, y) - Datanhee(x, y))/(1 - x); 00376 return s; 00377 } 00378 00379 void AlbersEqualArea::Forward(real lon0, real lat, real lon, 00380 real& x, real& y, real& gamma, real& k) 00381 const throw() { 00382 if (lon - lon0 >= 180) 00383 lon -= lon0 + 360; 00384 else if (lon - lon0 < -180) 00385 lon -= lon0 - 360; 00386 else 00387 lon -= lon0; 00388 lat *= _sign; 00389 real 00390 lam = lon * Math::degree<real>(), 00391 phi = lat * Math::degree<real>(), 00392 sphi = sin(phi), cphi = abs(lat) != 90 ? cos(phi) : epsx_, 00393 tphi = sphi/cphi, txi = txif(tphi), sxi = txi/hyp(txi), 00394 dq = _qZ * Dsn(txi, _txi0, sxi, _sxi0) * (txi - _txi0), 00395 drho = - _a * dq / (sqrt(_m02 - _n0 * dq) + _nrho0 / _a), 00396 theta = _k2 * _n0 * lam, stheta = sin(theta), ctheta = cos(theta), 00397 t = _nrho0 + _n0 * drho; 00398 x = t * (_n0 != 0 ? stheta / _n0 : _k2 * lam) / _k0; 00399 y = (_nrho0 * 00400 (_n0 != 0 ? 00401 (ctheta < 0 ? 1 - ctheta : Math::sq(stheta)/(1 + ctheta)) / _n0 : 00402 0) 00403 - drho * ctheta) / _k0; 00404 k = _k0 * (t != 0 ? t * hyp(_fm * tphi) / _a : 1); 00405 y *= _sign; 00406 gamma = _sign * theta / Math::degree<real>(); 00407 } 00408 00409 void AlbersEqualArea::Reverse(real lon0, real x, real y, 00410 real& lat, real& lon, 00411 real& gamma, real& k) 00412 const throw() { 00413 y *= _sign; 00414 real 00415 nx = _k0 * _n0 * x, ny = _k0 * _n0 * y, y1 = _nrho0 - ny, 00416 den = Math::hypot(nx, y1) + _nrho0, // 0 implies origin with polar aspect 00417 drho = den != 0 ? (_k0*x*nx - 2*_k0*y*_nrho0 + _k0*y*ny) / den : 0, 00418 // dsxia = scxi0 * dsxi 00419 dsxia = - _scxi0 * (2 * _nrho0 + _n0 * drho) * drho / 00420 (Math::sq(_a) * _qZ), 00421 txi = (_txi0 + dsxia) / sqrt(max(1 - dsxia * (2*_txi0 + dsxia), epsx2_)), 00422 tphi = tphif(txi), 00423 phi = _sign * atan(tphi), 00424 theta = atan2(nx, y1), 00425 lam = _n0 != 0 ? theta / (_k2 * _n0) : x / (y1 * _k0); 00426 gamma = _sign * theta / Math::degree<real>(); 00427 lat = phi / Math::degree<real>(); 00428 lon = lam / Math::degree<real>(); 00429 // Avoid losing a bit of accuracy in lon (assuming lon0 is an integer) 00430 if (lon + lon0 >= 180) 00431 lon += lon0 - 360; 00432 else if (lon + lon0 < -180) 00433 lon += lon0 + 360; 00434 else 00435 lon += lon0; 00436 k = _k0 * (den != 0 ? (_nrho0 + _n0 * drho) * hyp(_fm * tphi) / _a : 1); 00437 } 00438 00439 void AlbersEqualArea::SetScale(real lat, real k) { 00440 if (!(Math::isfinite(k) && k > 0)) 00441 throw GeographicErr("Scale is not positive"); 00442 if (!(abs(lat) < 90)) 00443 throw GeographicErr("Latitude for SetScale not in (-90, 90)"); 00444 real x, y, gamma, kold; 00445 Forward(0, lat, 0, x, y, gamma, kold); 00446 k /= kold; 00447 _k0 *= k; 00448 _k2 = Math::sq(_k0); 00449 } 00450 00451 } // namespace GeographicLib