00001 #ifndef __NED_CLASS__
00002 #define __NED_CLASS__
00003
00004 #include "math.h"
00005 #include <Eigen/Dense>
00006
00007 namespace geodesy_ned {
00008 static const double a = 6378137;
00009 static const double b = 6356752.3142;
00010 static const double esq = 6.69437999014 * 0.001;
00011 static const double e1sq = 6.73949674228 * 0.001;
00012 static const double f = 1 / 298.257223563;
00013
00014 class Ned {
00015 public:
00016
00017 Ned( const double lat,
00018 const double lon,
00019 const double height )
00020 {
00021
00022 _init_lat = deg2Rad( lat );
00023 _init_lon = deg2Rad( lon );
00024 _init_h = height;
00025
00026
00027 geodetic2Ecef( lat, lon, height,
00028 _init_ecef_x,
00029 _init_ecef_y,
00030 _init_ecef_z );
00031
00032
00033 double phiP = atan2( _init_ecef_z, sqrt( pow( _init_ecef_x, 2 ) +
00034 pow( _init_ecef_y, 2 ) ) );
00035
00036 _ecef_to_ned_matrix = __nRe__( phiP, _init_lon );
00037 _ned_to_ecef_matrix = __nRe__( _init_lat, _init_lon ).transpose();
00038 }
00039
00040
00041 void
00042 geodetic2Ecef( const double lat,
00043 const double lon,
00044 const double height,
00045 double& x,
00046 double& y,
00047 double& z )
00048 {
00049
00050
00051 double lat_rad = deg2Rad( lat );
00052 double lon_rad = deg2Rad( lon );
00053 double xi = sqrt(1 - esq * sin( lat_rad ) * sin( lat_rad ) );
00054 x = ( a / xi + height ) * cos( lat_rad ) * cos( lon_rad );
00055 y = ( a / xi + height ) * cos( lat_rad ) * sin( lon_rad );
00056 z = ( a / xi * ( 1 - esq ) + height ) * sin( lat_rad );
00057 }
00058
00059 void
00060 ecef2Geodetic( const double x,
00061 const double y,
00062 const double z,
00063 double& lat,
00064 double& lon,
00065 double& height )
00066 {
00067
00068
00069
00070
00071
00072 double r = sqrt( x * x + y * y );
00073 double Esq = a * a - b * b;
00074 double F = 54 * b * b * z * z;
00075 double G = r * r + (1 - esq) * z * z - esq * Esq;
00076 double C = (esq * esq * F * r * r) / pow( G, 3 );
00077 double S = __cbrt__( 1 + C + sqrt( C * C + 2 * C ) );
00078 double P = F / (3 * pow( (S + 1 / S + 1), 2 ) * G * G);
00079 double Q = sqrt( 1 + 2 * esq * esq * P );
00080 double r_0 = -(P * esq * r) / (1 + Q) + sqrt( 0.5 * a * a * (1 + 1.0 / Q) - P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r);
00081 double U = sqrt( pow( (r - esq * r_0), 2 ) + z * z );
00082 double V = sqrt( pow( (r - esq * r_0), 2 ) + (1 - esq) * z * z );
00083 double Z_0 = b * b * z / (a * V);
00084 height = U * (1 - b * b / (a * V));
00085 lat = rad2Deg( atan( (z + e1sq * Z_0) / r ) );
00086 lon = rad2Deg( atan2( y, x ) );
00087 }
00088
00089
00090 void
00091 ecef2Ned( const double x,
00092 const double y,
00093 const double z,
00094 double& north,
00095 double& east,
00096 double& depth )
00097 {
00098
00099
00100
00101
00102 Eigen::Vector3d vect, ret;
00103 vect(0) = x - _init_ecef_x;
00104 vect(1) = y - _init_ecef_y;
00105 vect(2) = z - _init_ecef_z;
00106 ret = _ecef_to_ned_matrix * vect;
00107 north = ret(0);
00108 east = ret(1);
00109 depth = -ret(2);
00110 }
00111
00112
00113 void
00114 ned2Ecef( const double north,
00115 const double east,
00116 const double depth,
00117 double& x,
00118 double& y,
00119 double& z )
00120 {
00121
00122 Eigen::Vector3d ned, ret;
00123 ned(0) = north;
00124 ned(1) = east;
00125 ned(2) = -depth;
00126 ret = _ned_to_ecef_matrix * ned;
00127 x = ret(0) + _init_ecef_x;
00128 y = ret(1) + _init_ecef_y;
00129 z = ret(2) + _init_ecef_z;
00130 }
00131
00132
00133 void
00134 geodetic2Ned( const double lat,
00135 const double lon,
00136 const double height,
00137 double& north,
00138 double& east,
00139 double& depth )
00140 {
00141
00142 double x, y, z;
00143 geodetic2Ecef( lat, lon, height,
00144 x, y, z );
00145 ecef2Ned( x, y, z,
00146 north, east, depth );
00147 }
00148
00149
00150 void
00151 ned2Geodetic( const double north,
00152 const double east,
00153 const double depth,
00154 double& lat,
00155 double& lon,
00156 double& height )
00157 {
00158
00159 double x, y, z;
00160 ned2Ecef( north, east, depth,
00161 x, y, z );
00162 ecef2Geodetic( x, y, z,
00163 lat, lon, height );
00164 }
00165
00166
00167 private:
00168 double _init_lat;
00169 double _init_lon;
00170 double _init_h;
00171 double _init_ecef_x;
00172 double _init_ecef_y;
00173 double _init_ecef_z;
00174 Eigen::Matrix3d _ecef_to_ned_matrix;
00175 Eigen::Matrix3d _ned_to_ecef_matrix;
00176
00177
00178 double
00179 __cbrt__( const double x )
00180 {
00181 if( x >= 0.0 ) {
00182 return pow( x, 1.0/3.0 );
00183 }
00184 else {
00185 return -pow( fabs(x), 1.0/3.0 );
00186 }
00187 }
00188
00189
00190 Eigen::Matrix3d
00191 __nRe__( const double lat_rad,
00192 const double lon_rad )
00193 {
00194 double sLat = sin( lat_rad );
00195 double sLon = sin( lon_rad );
00196 double cLat = cos( lat_rad );
00197 double cLon = cos( lon_rad );
00198
00199 Eigen::Matrix3d ret;
00200 ret(0, 0) = -sLat*cLon; ret(0, 1) = -sLat*sLon; ret(0, 2) = cLat;
00201 ret(1, 0) = -sLon; ret(1, 1) = cLon; ret(1, 2) = 0.0;
00202 ret(2, 0) = cLat*cLon; ret(2, 1) = cLat*sLon; ret(2, 2) = sLat;
00203
00204 return ret;
00205 }
00206
00207 double
00208 rad2Deg( const double radians )
00209 {
00210 return ( radians / M_PI ) * 180.0;
00211 }
00212
00213
00214 double
00215 deg2Rad( const double degrees )
00216 {
00217 return ( degrees / 180.0 ) * M_PI;
00218 }
00219
00220 };
00221 };
00222 #endif // __NED_CLASS__