// %pacpus:license{ // This file is part of the PACPUS framework distributed under the // CECILL-C License, Version 1.0. // %pacpus:license} /// @file /// @author Firstname Surname /// @date Month, Year /// @version $Id: geodesy.hpp 76 2013-01-10 17:05:10Z kurdejma $ /// @copyright Copyright (c) UTC/CNRS Heudiasyc 2006 - 2013. All rights reserved. /// @brief Brief description. /// /// Detailed description. #ifndef __GEO_UTILITIES__ #define __GEO_UTILITIES__ #include #include #include #include namespace math{ namespace geodesy { #ifndef M_PI const double M_PI = std::atan(1.0)*4.0; #endif /*! * \enum CoordinateSystem * \brief coordinate system enumeration */ enum CoordinateSystem {_LLH_,_ECEF_,_LAMBERT93_,_ENU_,_NED_,_NONE_}; /*! * \def WGS84_a * \brief semi-major axis of WGS84 ellipsoid */ const double WGS84_a = 6378137.0; /*! * \def WGS84_e * \brief eccentricity of WGS84 ellipsoid */ const double WGS84_e = 0.0818191913108695; /*! * \def GRS80_a * \brief semi-major axis of GRS80 ellipsoid */ const double GRS80_a = 6378137.0; /*! * \def GRS80_a * \brief eccentricity of GRS80 ellipsoid */ const double GRS80_e =0.0818191910428152; /**Lambert93 conversion parameters */ const double LAMBERT93_n=0.725607765053267; const double LAMBERT93_c = 11754255.4261; const double LAMBERT93_Xs = 700000.0; const double LAMBERT93_Ys = 12655612.0499; const double LAMBERT93_lon0 = 0.0523598775598299; /**Conversion functions*/ /*! * \fn inline boost::numeric::ublas::vector LLH2ECEF(const boost::numeric::ublas::vector &llh, const T &a, const T &e) * \brief convert an LLH position to a ECEF position * \param llh : ublas vector describing a llh position (latitude, longitude,ellipsoidal height) * \param a : semi-major axis of ellipsoid (by default WGS84 value is used) * \param e : ellipsoid eccentricity (by default WGS84 value is used) * \return ublas vector describing a ecef position (x,y,z) */ template inline boost::numeric::ublas::vector LLH2ECEF(const boost::numeric::ublas::vector &llh, const T &a=WGS84_a, const T &e=WGS84_e){ T N=TranversalRadius(llh[0],a,e); boost::numeric::ublas::vector ecef(3); ecef[0]=(N+llh[2])*std::cos(llh[0])*std::cos(llh[1]); ecef[1]=(N+llh[2])*std::cos(llh[0])*std::sin(llh[1]); ecef[2]=(N*(1-std::pow(e,2))+llh[2])*std::sin(llh[0]); return ecef; } /*! * \fn inline boost::numeric::ublas::vector ECEF2LLH(const boost::numeric::ublas::vector &ecef,const T &a, const T &e) * \brief convert an ECEF position to a LLH position * \param ecef : ublas vector describing a ecef position (x,y,z) * \param a : semi-major axis of ellipsoid (by default WGS84 value is used) * \param e : ellipsoid eccentricity (by default WGS84 value is used) * \return ublas vector describing a llh position (latitude, longitude,ellipsoidal height) */ template inline boost::numeric::ublas::vector ECEF2LLH(const boost::numeric::ublas::vector &ecef,const T &a=WGS84_a, const T &e=WGS84_e){ boost::numeric::ublas::vector lla(3); T P= std::sqrt(pow(ecef[0],2) + pow(ecef[1],2)); T l0 =std::atan(ecef[2]/(P*(1-a*std::pow(e,2)/std::sqrt(std::pow(ecef[0],2) + std::pow(ecef[1],2) + std::pow(ecef[2],2))))); lla[1]= std::atan(ecef[1]/ecef[0]); lla[0]= std::atan((ecef[2]/P)/(1-a*std::pow(e,2)*std::cos(l0)/(P*std::sqrt(1-std::pow(e,2)*std::pow(sin(l0),2))))); while(std::fabs(lla[0]*180/M_PI-l0*180/M_PI)>std::pow(10.0,-12.0)){ l0=lla[0]; lla[0]=std::atan((ecef[2]/P)/(1-a*std::pow(e,2)*std::cos(l0)/(P*sqrt(1-std::pow(e*std::sin(l0),2))))); } lla[2]=(P/std::cos(lla[0]))-(a/std::sqrt(1-pow(e*sin(lla[0]),2))); return lla; } /*! * \fn inline boost::numeric::ublas::vector ECEF2NTF(const boost::numeric::ublas::vector &ecef) * \brief convert an ECEF position to a NTF position * \param ecef : ublas vector describing a ecef position (x,y,z) * \return ublas vector describing a ntf position (x,y,z) */ template inline boost::numeric::ublas::vector ECEF2NTF(const boost::numeric::ublas::vector &ecef){ boost::numeric::ublas::vector ntf(3); ntf[0]=ecef[0]+168; ntf[1]=ecef[1]+60; ntf[2]=ecef[2]-320; return ntf; } /*! * \fn inline boost::numeric::ublas::vector NTF2ECEF(const boost::numeric::ublas::vector &ntf) * \brief convert an ECEF position to a NTF position * \param ntf : ublas vector describing a ntf position (x,y,z) * \return ublas vector describing a ecef position (x,y,z) */ template inline boost::numeric::ublas::vector NTF2ECEF(const boost::numeric::ublas::vector &ntf){ boost::numeric::ublas::vector ecef(3); ecef[0]=ntf[0]-168; ecef[1]=ntf[1]-60; ecef[2]=ntf[2]+320; return ecef; } /*! * \fn inline boost::numeric::ublas::matrix C_ECEF2ENU(const T &lat0,const T &lon0) * \brief compute transformation matrix using to convert an ECEF position to a ENU position * \param lat0 : reference latitude * \param lon0 : reference longitude * \return ublas matrix */ template inline boost::numeric::ublas::matrix C_ECEF2ENU(const T &lat0,const T &lon0){ T slat = std::sin(lat0); T clat = std::cos(lat0); T slon = std::sin(lon0); T clon = std::cos(lon0); boost::numeric::ublas::matrix C(3,3); C(0,0) = -slon; C(0,1) = clon; C(0,2) = 0.0; C(1,0) = -clon * slat; C(1,1) = -slon * slat; C(1,2) = clat; C(2,0) = clon * clat; C(2,1) = slon * clat; C(2,2) = slat; return C; } /*! * \fn inline boost::numeric::ublas::matrix C_ENU2ECEF(const T &lat0, const T &lon0) * \brief compute transformation matrix using to convert an ENU position to a ECEF position * \param lat0 : reference latitude * \param lon0 : reference longitude * \return ublas matrix */ template inline boost::numeric::ublas::matrix C_ENU2ECEF(const T &lat0, const T &lon0){ T clat = std::cos(lat0); T slat = std::sin(lat0); T clon = std::cos(lon0); T slon = std::sin(lon0); boost::numeric::ublas::matrix C(3,3); C(0,0) = -slon; C(0,1) = -clon * slat; C(0,2) = clon * clat; C(1,0) = clon; C(1,1) = -slon * slat; C(1,2) = slon * clat; C(2,0) = 0.0; C(2,1) = clat; C(2,2) = slat; return C; } /*! * \fn inline boost::numeric::ublas::matrix C_ECEF2NED(const T &lat0,const T &lon0) * \brief compute transformation matrix using to convert an ECEF position to a NED position * \param lat0 : reference latitude * \param lon0 : reference longitude * \return ublas matrix */ template inline boost::numeric::ublas::matrix C_ECEF2NED(const T &lat0,const T &lon0){ T clat = std::cos(lat0); T clon = std::cos(lon0); T slat = std::sin(lat0); T slon = std::sin(lon0); boost::numeric::ublas::matrix C(3,3); C(0,0) = -slat * clon; C(0,1) = -slat * slon; C(0,2) = clat; C(1,0) = -slon; C(1,1) = clon; C(1,2) = 0.0; C(2,0) = -clat * clon; C(2,1) = -clat * slon; C(2,2) = -slat; return C; } /*! * \fn inline boost::numeric::ublas::matrix C_NED2ECEF(const T &lat0, const T &lon0) * \brief compute transformation matrix using to convert NED position to a ECEF position * \param lat0 : reference latitude * \param lon0 : reference longitude * \return ublas matrix */ template inline boost::numeric::ublas::matrix C_NED2ECEF(const T &lat0, const T &lon0){ T clat = std::cos(lat0); T clon = std::cos(lon0); T slat = std::sin(lat0); T slon = std::sin(lon0); boost::numeric::ublas::matrix C(3,3); C(0,0) = -slat * clon; C(1,0) = -slat * slon; C(2,0) = clat; C(0,1) = -slon; C(1,1) = clon; C(2,1) = 0.0; C(0,2) = -clat * clon; C(1,2) = -clat * slon; C(2,2) = -slat; return C; } /*! * \fn inline boost::numeric::ublas::vector ECEF2TANGENT (const boost::numeric::ublas::matrix & C, const boost::numeric::ublas::vector & P ,const boost::numeric::ublas::vector Ref ) * \brief convert an ECEF position to a ENU or NED position * \param C : transformation matrix * \param P : ECEF position * \param Ref : reference position in ECEF frame * \return ublas vector */ template inline boost::numeric::ublas::vector ECEF2TANGENT (const boost::numeric::ublas::matrix & C, const boost::numeric::ublas::vector & P ,const boost::numeric::ublas::vector Ref ){ return prod(C,(P-Ref)); } /*! * \fn inline boost::numeric::ublas::vector TANGENT2ECEF (const boost::numeric::ublas::matrix & C, const boost::numeric::ublas::vector & P ,const boost::numeric::ublas::vector Ref ) * \brief convert an ENU or NED position to an ECEF position * \param C : transformation matrix * \param P : ENU or NED position * \param Ref : reference position in ECEF frame * \return ublas vector */ template inline boost::numeric::ublas::vector TANGENT2ECEF (const boost::numeric::ublas::matrix & C, const boost::numeric::ublas::vector & P ,const boost::numeric::ublas::vector Ref ){ return Ref+prod(C,P); } /*! * \fn inline boost::numeric::ublas::vector ENU2NED(const boost::numeric::ublas::vector &enu) * \brief convert an ENU position to an NED position * \param enu : ENU position * \return ublas vector */ template inline boost::numeric::ublas::vector ENU2NED(const boost::numeric::ublas::vector &enu){ boost::numeric::ublas::vector ned(3); ned[0]=enu[1]; ned[1]=enu[0]; ned[2]=-enu[2]; return ned; } /*! * \fn inline boost::numeric::ublas::vector NED2ENU(const boost::numeric::ublas::vector &ned) * \brief convert an NED position to an ENU position * \param ned : NED position * \return ublas vector */ template inline boost::numeric::ublas::vector NED2ENU(const boost::numeric::ublas::vector &ned){ return ENU2NED(ned); } /*! * \fn inline boost::numeric::ublas::vector LLH2LAMBERT(const boost::numeric::ublas::vector &llh, T lon0 ,T e, T n, T c ,T Xs, T Ys) * \brief convert an LLH position to a LAMBERT position * \param llh : LLH position * \param lon0 : reference longitude * \param e : ellipsoid eccentricity * \param n : * \param c : * \param Xs : false easting * \param Ys : false northing * \return ublas vector */ template inline boost::numeric::ublas::vector LLH2LAMBERT(const boost::numeric::ublas::vector &llh, T lon0 ,T e, T n, T c ,T Xs, T Ys){; boost::numeric::ublas::vector lambert(3); T latiso= std::log(std::tan((M_PI / 4) + (llh[0] / 2)) * std::pow((1 - e * std::sin(llh[0])) / (1 + e * std::sin(llh[0])),e / 2)); lambert[0] = Xs + c*std::exp(-n*latiso)*std::sin(n*(llh[1]-lon0)); lambert[1] = Ys - c*std::exp(-n*latiso)*std::cos(n*(llh[1]-lon0)); return lambert; } /*! * \fn inline boost::numeric::ublas::vector LLH2LAMBERT93(const boost::numeric::ublas::vector &llh) * \brief convert an LLH position to a LAMBERT 93 position * \param llh : llh position * \return ublas vector */ template inline boost::numeric::ublas::vector LLH2LAMBERT93(const boost::numeric::ublas::vector &llh){ // boost::numeric::ublas::vector ecef=LLH2ECEF(llh); // boost::numeric::ublas::vector ntf=ECEF2NTF(ecef); // boost::numeric::ublas::vector llhntf=ECEF2LLH(ntf,GRS80_a,GRS80_e); return LLH2LAMBERT(llh,LAMBERT93_lon0 ,GRS80_e, LAMBERT93_n, LAMBERT93_c , LAMBERT93_Xs, LAMBERT93_Ys); } /*! * \fn inline boost::numeric::ublas::vector LAMBERT2LLH(const boost::numeric::ublas::vector &lambert, T lon0, T e , T n, T c, T Xs ,T Ys ) * \brief convert an LLH position to a LAMBERT position * \param lambert : lambert position * \param lon0 : reference longitude * \param e : ellipsoid eccentricity * \param n : * \param c : * \param Xs : false easting * \param Ys : false northing * \return ublas vector */ template inline boost::numeric::ublas::vector LAMBERT2LLH(const boost::numeric::ublas::vector &lambert, T lon0, T e , T n, T c, T Xs ,T Ys ){ boost::numeric::ublas::vector llh(3); T latiso=std::log(c/std::abs(std::sqrt(std::pow(lambert[0]-Xs,2)+std::pow(lambert[1]-Ys,2))))/n; llh[0]=2*std::atan(std::exp(latiso))-M_PI/2; llh[1]=lon0+std::atan(-(lambert[0]-Xs)/(lambert[1]-Ys))/n; T l0=llh[0]+1; while(std::abs(llh[0]-l0)>std::pow(10.0,-12.0)){ l0=llh[0]; llh[0]=2 * std::atan(std::pow((1 + e * std::sin(l0)) / (1 - e * std::sin(l0)), e / 2)*std::exp(latiso)) - M_PI / 2; } return llh; } /*! * \fn inline boost::numeric::ublas::vector LAMBERT932LLH(const boost::numeric::ublas::vector &lambert) * \brief convert an LAMBERT93 position to a LLH position * \param lambert : lmabert 9 position * \return ublas vector */ template inline boost::numeric::ublas::vector LAMBERT932LLH(const boost::numeric::ublas::vector &lambert){ return LAMBERT2LLH(lambert, LAMBERT93_lon0 ,GRS80_e, LAMBERT93_n, LAMBERT93_c , LAMBERT93_Xs, LAMBERT93_Ys); //boost::numeric::ublas::vector llhntf=LAMBERT2LLHCARTO(lambert, LAMBERT93_lon0 ,GRS80_e, LAMBERT93_n, LAMBERT93_c , LAMBERT93_Xs, LAMBERT93_Ys); //boost::numeric::ublas::vector ecefntf=LLH2ECEF(llhntf); //boost::numeric::ublas::vector ecef=NTF2ECEF(ecefntf); //return ECEF2LLH(ecef); } /*! * \fn inline T MeridionalRadius(const T &latitude,const T &a, const T &e) * \brief compute the prime vertical curvature radius * \param latitude : a latitude * \param a : semi-major axis of ellipsoid (by default WGS84 value is used) * \param e : ellipsoid eccentricity (by default WGS84 value is used) * \return ublas vector */ template inline T MeridionalRadius(const T &latitude,const T &a=WGS84_a, const T &e=WGS84_e){ return a/(std::pow(1-std::pow(e*std::sin(latitude),2),1.5)); } /*! * \fn inline T TranversalRadius(const T &latitude,const T &a, const T &e) * \brief compute the prime horizontal curvature radius * \param latitude : a latitude * \param a : semi-major axis of ellipsoid (by default WGS84 value is used) * \param e : ellipsoid eccentricity (by default WGS84 value is used) * \return ublas vector */ template inline T TranversalRadius(const T &latitude,const T &a=WGS84_a, const T &e=WGS84_e){ return a/std::sqrt(1-std::pow(e*std::sin(latitude),2)); } }; }; #endif