ENU与ecef与WGS84相互转换(c++和python)

Posted 乌托邦2号

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ENU与ecef与WGS84相互转换(c++和python)相关的知识,希望对你有一定的参考价值。

(1)enu转wgs84

c++版本:

void enu_to_wgs84(double x_east, double y_north, double z_up, double lati, double longti,double height, double*result)

	double pi = std::acos(-1.0);
	double a = 6378137.0;    //earth radius in meters
	double b = 6356752.3142; //earth semiminor in meters 
	double f = (a - b) / a;
	double e_sq = f * (2-f);

	double lamb = lati * pi / 180.0;
	double phi = longti * pi / 180.0;
	double sl = std::sin(lamb);
	double N = a / std::sqrt(1 - e_sq * sl * sl);
	double sin_lambda = std::sin(lamb);
	double cos_lambda = std::cos(lamb);
	double sin_phi = std::sin(phi);
	double cos_phi = std::cos(phi);
	double x0 = (height + N) * cos_lambda * cos_phi;
	double y0 = (height + N) * cos_lambda * sin_phi;
	double z0 = (height + (1 - e_sq) * N) * sin_lambda;
	double t = cos_lambda * z_up - sin_lambda * y_north;
	double zd = sin_lambda * z_up + cos_lambda * y_north;
	double xd = cos_phi * t - sin_phi * x_east;
	double yd = sin_phi * t + cos_phi * x_east;
	
	//Convert from ECEF cartesian coordinates to 
	//latitude, longitude and height.  WGS-8
	double x = xd + x0;
	double y = yd + y0;
	double z = zd + z0;
	double x2 = std::pow(x, 2);
	double y2 = std::pow(y, 2);
	double z2 = std::pow(z, 2);
	double e = std::sqrt (1-std::pow((b/a) , 2));
	double b2 = b*b;
	double e2 = e*e;
	double ep = e*(a/b); 
	double r = std::sqrt(x2+y2); 
	double r2 = r*r;
	double E2 = a*a - b*b;
	double F = 54*b2*z2;
	double G = r2 + (1-e2)*z2 - e2*E2;
	double c = (e2*e2*F*r2)/(G*G*G); 
	double s = std::pow(( 1 + c + std::sqrt(c*c + 2*c) ) ,(1/3)); 
	double P = F / (3 * std::pow((s+1/s+1), 2) * G*G); 
	double Q = std::sqrt(1+2*e2*e2*P);
	double ro = -(P*e2*r)/(1+Q) + std::sqrt((a*a/2)*(1+1/Q) - (P*(1-e2)*z2)/(Q*(1+Q)) - P*r2/2);
	double tmp = std::pow((r - e2*ro), 2); 
	double U = std::sqrt( tmp + z2 ); 
	double V = std::sqrt( tmp + (1-e2)*z2 ); 
	double zo = (b2*z)/(a*V); 
	double high = U*( 1 - b2/(a*V) );
	double lat = std::atan( (z + ep*ep*zo)/r );
	double temp = std::atan(y/x);
	double lon = temp - pi;
	if (x >= 0) 
		lon = temp;
	
	else if (x < 0 && y >= 0) 
		lon = pi + temp;
	
	*result = lat/(pi/180);
	*(result + 1) = lon/(pi/180);
	*(result + 2) = high;

调用

char result[3] = 0;

enu_to_wgs84(x-190.000000, y-170.000000, z-20.000000, 30.37,114.88, result);

python版本:

# -*- coding: utf-8 -*-
# @Author: wuzida
# @Date:   2018-12-28 15:20:54
# @Last Modified by:   wuzida
# @Last Modified time: 2018-12-29 16:49:16
import math

a = 6378137
b = 6356752.3142
f = (a - b) / a
e_sq = f * (2-f)
pi = 3.14159265359

def geodetic_to_ecef(lat, lon, h):
    # (lat, lon) in degrees
    # h in meters
    lamb = math.radians(lat)
    phi = math.radians(lon)
    s = math.sin(lamb)
    N = a / math.sqrt(1 - e_sq * s * s)

    sin_lambda = math.sin(lamb)
    cos_lambda = math.cos(lamb)
    sin_phi = math.sin(phi)
    cos_phi = math.cos(phi)

    x = (h + N) * cos_lambda * cos_phi
    y = (h + N) * cos_lambda * sin_phi
    z = (h + (1 - e_sq) * N) * sin_lambda

    return x, y, z

def ecef_to_enu(x, y, z, lat0, lon0, h0):
    lamb = math.radians(lat0)
    phi = math.radians(lon0)
    s = math.sin(lamb)
    N = a / math.sqrt(1 - e_sq * s * s)

    sin_lambda = math.sin(lamb)
    cos_lambda = math.cos(lamb)
    sin_phi = math.sin(phi)
    cos_phi = math.cos(phi)

    x0 = (h0 + N) * cos_lambda * cos_phi
    y0 = (h0 + N) * cos_lambda * sin_phi
    z0 = (h0 + (1 - e_sq) * N) * sin_lambda

    xd = x - x0
    yd = y - y0
    zd = z - z0

    t = -cos_phi * xd -  sin_phi * yd

    xEast = -sin_phi * xd + cos_phi * yd
    yNorth = t * sin_lambda  + cos_lambda * zd
    zUp = cos_lambda * cos_phi * xd + cos_lambda * sin_phi * yd + sin_lambda * zd

    return xEast, yNorth, zUp

def enu_to_ecef(xEast, yNorth, zUp, lat0, lon0, h0):
    lamb = math.radians(lat0)
    phi = math.radians(lon0)
    s = math.sin(lamb)
    N = a / math.sqrt(1 - e_sq * s * s)

    sin_lambda = math.sin(lamb)
    cos_lambda = math.cos(lamb)
    sin_phi = math.sin(phi)
    cos_phi = math.cos(phi)

    x0 = (h0 + N) * cos_lambda * cos_phi
    y0 = (h0 + N) * cos_lambda * sin_phi
    z0 = (h0 + (1 - e_sq) * N) * sin_lambda

    t = cos_lambda * zUp - sin_lambda * yNorth

    zd = sin_lambda * zUp + cos_lambda * yNorth
    xd = cos_phi * t - sin_phi * xEast 
    yd = sin_phi * t + cos_phi * xEast

    x = xd + x0 
    y = yd + y0 
    z = zd + z0 

    return x, y, z

def ecef_to_geodetic(x, y, z):
   # Convert from ECEF cartesian coordinates to 
   # latitude, longitude and height.  WGS-84
    x2 = x ** 2 
    y2 = y ** 2 
    z2 = z ** 2 

    a = 6378137.0000    # earth radius in meters
    b = 6356752.3142    # earth semiminor in meters 
    e = math.sqrt (1-(b/a)**2) 
    b2 = b*b 
    e2 = e ** 2 
    ep = e*(a/b) 
    r = math.sqrt(x2+y2) 
    r2 = r*r 
    E2 = a ** 2 - b ** 2 
    F = 54*b2*z2 
    G = r2 + (1-e2)*z2 - e2*E2 
    c = (e2*e2*F*r2)/(G*G*G) 
    s = ( 1 + c + math.sqrt(c*c + 2*c) )**(1/3) 
    P = F / (3 * (s+1/s+1)**2 * G*G) 
    Q = math.sqrt(1+2*e2*e2*P) 
    ro = -(P*e2*r)/(1+Q) + math.sqrt((a*a/2)*(1+1/Q) - (P*(1-e2)*z2)/(Q*(1+Q)) - P*r2/2) 
    tmp = (r - e2*ro) ** 2 
    U = math.sqrt( tmp + z2 ) 
    V = math.sqrt( tmp + (1-e2)*z2 ) 
    zo = (b2*z)/(a*V) 

    height = U*( 1 - b2/(a*V) ) 
    
    lat = math.atan( (z + ep*ep*zo)/r ) 

    temp = math.atan(y/x) 
    if x >=0 :    
        long = temp 
    elif (x < 0) & (y >= 0):
        long = pi + temp 
    else :
        long = temp - pi 

    lat0 = lat/(pi/180) 
    lon0 = long/(pi/180) 
    h0 = height 

    return lat0, lon0, h0


def geodetic_to_enu(lat, lon, h, lat_ref, lon_ref, h_ref):

    x, y, z = geodetic_to_ecef(lat, lon, h)
    
    return ecef_to_enu(x, y, z, lat_ref, lon_ref, h_ref)

def enu_to_geodetic(xEast, yNorth, zUp, lat_ref, lon_ref, h_ref):

    x,y,z = enu_to_ecef(xEast, yNorth, zUp, lat_ref, lon_ref, h_ref)

    return ecef_to_geodetic(x,y,z)

(2)WGS84坐标系转为地心坐标系

void double[] wgs84ToEcef(double lat, double lon, double h) 

		double a = 6378137;
		double b = 6356752.3142;
		double f = (a - b) / a;
		double e_sq = f * (2 - f);
		double lamb = Math.toRadians(lat);
		double phi = Math.toRadians(lon);
		double s = Math.sin(lamb);
		double N = a / Math.sqrt(1 - e_sq * s * s);

		double sin_lambda = Math.sin(lamb);
		double cos_lambda = Math.cos(lamb);
		double sin_phi = Math.sin(phi);
		double cos_phi = Math.cos(phi);

		double x = (h + N) * cos_lambda * cos_phi;
		double y = (h + N) * cos_lambda * sin_phi;
		double z = (h + (1 - e_sq) * N) * sin_lambda;
		return new double[]x,y,z;

(3)站点经纬度转Enu

void double[] ecefToEnu(double x, double y, double z, double lat, double lng, double height) 

		double a = 6378137;
		double b = 6356752.3142;
		double f = (a - b) / a;
		double e_sq = f * (2 - f);
		double lamb = Math.toRadians(lat);
		double phi = Math.toRadians(lng);
		double s = Math.sin(lamb);
		double N = a / Math.sqrt(1 - e_sq * s * s);
		double sin_lambda = Math.sin(lamb);
		double cos_lambda = Math.cos(lamb);
		double sin_phi = Math.sin(phi);
		double cos_phi = Math.cos(phi);

		double x0 = (height + N) * cos_lambda * cos_phi;
		double y0 = (height + N) * cos_lambda * sin_phi;
		double z0 = (height + (1 - e_sq) * N) * sin_lambda;

		double xd = x - x0;
		double yd = y - y0;
		double zd = z - z0;

		double t = -cos_phi * xd - sin_phi * yd;

		double xEast = -sin_phi * xd + cos_phi * yd;
		double yNorth = t * sin_lambda + cos_lambda * zd;
		double zUp = cos_lambda * cos_phi * xd + cos_lambda * sin_phi * yd + sin_lambda * zd;
		return new double[]  xEast, yNorth, zUp ;
	


 double[] arr1 = wgs84ToEcef(30.7335905, 103.968191, 493.080);//此处经纬度是需要比对的偏移经纬度       //对应<SRS>ENU:30.37479991,114.8956375</SRS>和 <SRSOrigin>-196.000000,-177.000000,-22.000000</SRSOrigin>
 ecefToEnu(arr1[0],arr1[1], arr1[2],30.7335905, 103.968191,  493.080);//此处经纬度是站点经纬度                 //六个参数,偏移每个坐标

以上是关于ENU与ecef与WGS84相互转换(c++和python)的主要内容,如果未能解决你的问题,请参考以下文章

CGCS2000坐标系与WGS84的相互投影转换

北京54全国80及WGS84坐标系的相互转换

iOS 百度坐标、GPS坐标、 高德坐标相互转换

北京54全国80及WGS84坐标系的相互转换

wgs84转换为百度坐标要如何操作呢?

如何将WGS84坐标转换成经纬度坐标