00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 # include <simgear_config.h>
00020 #endif
00021
00022 #include <cmath>
00023
00024 #include "SGMath.hxx"
00025
00026
00027
00028 #define _EQURAD 6378137.0
00029 #define _FLATTENING 298.257223563
00030
00031
00032 #if 0
00033 #define _SQUASH (1 - 1/_FLATTENING)
00034 #define _STRETCH (1/_SQUASH)
00035 #define _POLRAD (EQURAD * _SQUASH)
00036 #else
00037
00038
00039
00040
00041 #define _SQUASH 0.9966471893352525192801545
00042 #define _STRETCH 1.0033640898209764189003079
00043 #define _POLRAD 6356752.3142451794975639668
00044 #endif
00045
00046
00047 const double SGGeodesy::EQURAD = _EQURAD;
00048 const double SGGeodesy::iFLATTENING = _FLATTENING;
00049 const double SGGeodesy::SQUASH = _SQUASH;
00050 const double SGGeodesy::STRETCH = _STRETCH;
00051 const double SGGeodesy::POLRAD = _POLRAD;
00052
00053
00054
00055
00056 #define E2 fabs(1 - _SQUASH*_SQUASH)
00057 static double a = _EQURAD;
00058 static double ra2 = 1/(_EQURAD*_EQURAD);
00059 static double e = sqrt(E2);
00060 static double e2 = E2;
00061 static double e4 = E2*E2;
00062
00063 #undef _EQURAD
00064 #undef _FLATTENING
00065 #undef _SQUASH
00066 #undef _STRETCH
00067 #undef _POLRAD
00068 #undef E2
00069
00070 void
00071 SGGeodesy::SGCartToGeod(const SGVec3<double>& cart, SGGeod& geod)
00072 {
00073
00074
00075
00076
00077 double X = cart(0);
00078 double Y = cart(1);
00079 double Z = cart(2);
00080 double XXpYY = X*X+Y*Y;
00081 double sqrtXXpYY = sqrt(XXpYY);
00082 double p = XXpYY*ra2;
00083 double q = Z*Z*(1-e2)*ra2;
00084 double r = 1/6.0*(p+q-e4);
00085 double s = e4*p*q/(4*r*r*r);
00086 double t = pow(1+s+sqrt(s*(2+s)), 1/3.0);
00087 double u = r*(1+t+1/t);
00088 double v = sqrt(u*u+e4*q);
00089 double w = e2*(u+v-q)/(2*v);
00090 double k = sqrt(u+v+w*w)-w;
00091 double D = k*sqrtXXpYY/(k+e2);
00092 geod.setLongitudeRad(2*atan2(Y, X+sqrtXXpYY));
00093 double sqrtDDpZZ = sqrt(D*D+Z*Z);
00094 geod.setLatitudeRad(2*atan2(Z, D+sqrtDDpZZ));
00095 geod.setElevationM((k+e2-1)*sqrtDDpZZ/k);
00096 }
00097
00098 void
00099 SGGeodesy::SGGeodToCart(const SGGeod& geod, SGVec3<double>& cart)
00100 {
00101
00102
00103
00104
00105 double lambda = geod.getLongitudeRad();
00106 double phi = geod.getLatitudeRad();
00107 double h = geod.getElevationM();
00108 double sphi = sin(phi);
00109 double n = a/sqrt(1-e2*sphi*sphi);
00110 double cphi = cos(phi);
00111 double slambda = sin(lambda);
00112 double clambda = cos(lambda);
00113 cart(0) = (h+n)*cphi*clambda;
00114 cart(1) = (h+n)*cphi*slambda;
00115 cart(2) = (h+n-e2*n)*sphi;
00116 }
00117
00118 double
00119 SGGeodesy::SGGeodToSeaLevelRadius(const SGGeod& geod)
00120 {
00121
00122
00123 double phi = geod.getLatitudeRad();
00124 double sphi = sin(phi);
00125 double sphi2 = sphi*sphi;
00126 return a*sqrt((1 + (e4 - 2*e2)*sphi2)/(1 - e2*sphi2));
00127 }
00128
00129 void
00130 SGGeodesy::SGCartToGeoc(const SGVec3<double>& cart, SGGeoc& geoc)
00131 {
00132 double minVal = SGLimits<double>::min();
00133 if (fabs(cart(0)) < minVal && fabs(cart(1)) < minVal)
00134 geoc.setLongitudeRad(0);
00135 else
00136 geoc.setLongitudeRad(atan2(cart(1), cart(0)));
00137
00138 double nxy = sqrt(cart(0)*cart(0) + cart(1)*cart(1));
00139 if (fabs(nxy) < minVal && fabs(cart(2)) < minVal)
00140 geoc.setLatitudeRad(0);
00141 else
00142 geoc.setLatitudeRad(atan2(cart(2), nxy));
00143
00144 geoc.setRadiusM(norm(cart));
00145 }
00146
00147 void
00148 SGGeodesy::SGGeocToCart(const SGGeoc& geoc, SGVec3<double>& cart)
00149 {
00150 double lat = geoc.getLatitudeRad();
00151 double lon = geoc.getLongitudeRad();
00152 double slat = sin(lat);
00153 double clat = cos(lat);
00154 double slon = sin(lon);
00155 double clon = cos(lon);
00156 cart = geoc.getRadiusM()*SGVec3<double>(clat*clon, clat*slon, slat);
00157 }