Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "GeographicLib/Geocentric.hpp"
00010 #include "GeographicLib/Constants.hpp"
00011 #include <algorithm>
00012 #include <limits>
00013
00014 namespace {
00015 char RCSID[] = "$Id: Geocentric.cpp 6568 2009-03-01 17:58:41Z ckarney $";
00016 char RCSID_H[] = GEOCENTRIC_HPP;
00017 }
00018
00019 namespace GeographicLib {
00020
00021 using namespace std;
00022
00023 Geocentric::Geocentric(double a, double invf)
00024 throw()
00025 : _a(a)
00026 , _f(invf > 0 ? 1 / invf : 0)
00027 , _e2(_f * (2 - _f))
00028 , _e4(sq(_e2))
00029 , _e2m(1 - _e2)
00030 , _maxrad(2 * _a / numeric_limits<double>::epsilon())
00031 {}
00032
00033 const Geocentric Geocentric::WGS84(Constants::WGS84_a(),
00034 Constants::WGS84_invf());
00035
00036 void Geocentric::Forward(double lat, double lon, double h,
00037 double& x, double& y, double& z) const throw() {
00038 double
00039 phi = lat * Constants::degree(),
00040 lam = lon * Constants::degree(),
00041 sphi = sin(phi),
00042 n = _a/sqrt(1 - _e2 * sq(sphi));
00043 z = ( sq(1 - _f) * n + h) * sphi;
00044 x = (n + h) * cos(phi);
00045 y = x * sin(lam);
00046 x *= cos(lam);
00047 }
00048
00049 void Geocentric::Reverse(double x, double y, double z,
00050 double& lat, double& lon, double& h) const throw() {
00051 double rad = hypot(x, y);
00052 h = hypot(rad, z);
00053 double phi;
00054 if (h > _maxrad)
00055
00056
00057
00058
00059
00060
00061 phi = atan2(z/2, hypot(x/2, y/2));
00062 else if (_e4 == 0) {
00063
00064
00065
00066 phi = atan2(h != 0 ? z : 1.0, rad);
00067 h -= _a;
00068 } else {
00069 double
00070 p = sq(rad / _a),
00071 q = _e2m * sq(z / _a),
00072 r = (p + q - _e4) / 6;
00073 if ( !(_e4 * q == 0 && r <= 0) ) {
00074 double
00075
00076
00077 S = _e4 * p * q / 4,
00078 r2 = sq(r),
00079 r3 = r * r2,
00080 disc = S * (2 * r3 + S);
00081 double u = r;
00082 if (disc >= 0) {
00083 double T3 = r3 + S;
00084
00085
00086
00087 T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc);
00088
00089 double T = cbrt(T3);
00090
00091 u += T + (T != 0 ? r2 / T : 0);
00092 } else {
00093
00094 double ang = atan2(sqrt(-disc), r3 + S);
00095
00096
00097
00098
00099
00100
00101 u += 2 * abs(r) * cos((2 * Constants::pi() + ang) / 3.0);
00102 }
00103 double
00104 v = sqrt(sq(u) + _e4 * q),
00105
00106
00107 uv = u < 0 ? _e4 * q / (v - u) : u + v,
00108
00109 w = max(0.0, _e2 * (uv - q) / (2 * v)),
00110
00111
00112 k = uv / (sqrt(uv + sq(w)) + w),
00113 d = k * rad / (k + _e2);
00114
00115
00116 phi = atan2(z, d);
00117 h = (k + _e2 - 1) * hypot(d, z) / k;
00118 } else {
00119
00120
00121
00122
00123
00124
00125 phi = atan2(sqrt( -6 * r), sqrt(p * _e2m));
00126 if (z < 0) phi = -phi;
00127 h = - _a * _e2m / sqrt(1 - _e2 * sq(sin(phi)));
00128 }
00129 }
00130 lat = phi / Constants::degree();
00131
00132 lon = -atan2(-y, x) / Constants::degree();
00133 }
00134
00135 }
00136