geodesy_ned.hpp
Go to the documentation of this file.
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             // Save NED origin
00022             _init_lat = deg2Rad( lat );
00023             _init_lon = deg2Rad( lon );
00024             _init_h = height;
00025 
00026             // Compute ECEF of NED origin
00027             geodetic2Ecef( lat, lon, height,
00028                         _init_ecef_x,
00029                         _init_ecef_y,
00030                         _init_ecef_z );
00031 
00032             // Compute ECEF to NED and NED to ECEF matrices
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             // Convert geodetic coordinates to ECEF.
00050             // http://code.google.com/p/pysatel/source/browse/trunk/coord.py?r=22
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             // Convert ECEF coordinates to geodetic.
00068             // J. Zhu, "Conversion of Earth-centered Earth-fixed coordinates
00069             // to geodetic coordinates," IEEE Transactions on Aerospace and
00070             // Electronic Systems, vol. 30, pp. 957-961, 1994.
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             // Converts ECEF coordinate pos into local-tangent-plane ENU
00099             // coordinates relative to another ECEF coordinate ref. Returns a tuple
00100             // (East, North, Up).
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             // NED (north/east/down) to ECEF coordinate system conversion.
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             // Geodetic position to a local NED system """
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             // Local NED position to geodetic
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 }; // namespace geodesy_ned
00222 #endif // __NED_CLASS__


asctec_hl_gps
Author(s): Markus Achtelik
autogenerated on Thu Jun 6 2019 20:57:13