How can I convert geodetic (latitude, longitude, altitude) coordinates into local tangent plane ENU (East, North, Up) coordinates with Python?
pyproj package does not seem to have the right functionality ...
latitude = Math. PI * latitude / 180; longitude = Math. PI * longitude / 180; // adjust position by radians latitude -= 1.570795765134; // subtract 90 degrees (in radians) // and switch z and y xPos = (app. radius) * Math.
One degree has 60 minutes and one minute has 60 seconds. If you have 91.456 degrees you can see that your measurement is 91 whole degress plus 0.456 of a degree. To state the decimal 0.456 degrees in minutes multiply 0.456*60 to get 27.36 minutes. Now you have 27 whole minutes plus 0.36 of a minute.
Multiply the degrees of separation of longitude and latitude by 111,139 to get the corresponding linear distances in meters.
You could use the pymap3d package:
pip install pymap3d
Let's take the example values shown on this page.
import pymap3d as pm
# The local coordinate origin (Zermatt, Switzerland)
lat0 = 46.017 # deg
lon0 = 7.750 # deg
h0 = 1673 # meters
# The point of interest
lat = 45.976 # deg
lon = 7.658 # deg
h = 4531 # meters
pm.geodetic2enu(lat, lon, h, lat0, lon0, h0)
which produces
(-7134.757195979863, -4556.321513844541, 2852.3904239436915)
which are the east, north and up components, respectively.
The used ellipsoid is WGS84 by default. All available ellipsoid models (which can be fed as an argument to geodetic2enu) can be seen here. Here is how you would calculate the same ENU coordinates using WGS72 reference ellipsoid:
pm.geodetic2enu(lat, lon, h, lat0, lon0, h0, ell=pm.utils.Ellipsoid('wgs72'))
# (-7134.754845247729, -4556.320150825548, 2852.3904257449926)
Use pyproj without pymap3d
import numpy as np
import pyproj
import scipy.spatial.transform
def geodetic2enu(lat, lon, alt, lat_org, lon_org, alt_org):
transformer = pyproj.Transformer.from_crs(
{"proj":'latlong', "ellps":'WGS84', "datum":'WGS84'},
{"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'},
)
x, y, z = transformer.transform( lon,lat, alt,radians=False)
x_org, y_org, z_org = transformer.transform( lon_org,lat_org, alt_org,radians=False)
vec=np.array([[ x-x_org, y-y_org, z-z_org]]).T
rot1 = scipy.spatial.transform.Rotation.from_euler('x', -(90-lat_org), degrees=True).as_matrix()#angle*-1 : left handed *-1
rot3 = scipy.spatial.transform.Rotation.from_euler('z', -(90+lon_org), degrees=True).as_matrix()#angle*-1 : left handed *-1
rotMatrix = rot1.dot(rot3)
enu = rotMatrix.dot(vec).T.ravel()
return enu.T
def enu2geodetic(x,y,z, lat_org, lon_org, alt_org):
transformer1 = pyproj.Transformer.from_crs(
{"proj":'latlong', "ellps":'WGS84', "datum":'WGS84'},
{"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'},
)
transformer2 = pyproj.Transformer.from_crs(
{"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'},
{"proj":'latlong', "ellps":'WGS84', "datum":'WGS84'},
)
x_org, y_org, z_org = transformer1.transform( lon_org,lat_org, alt_org,radians=False)
ecef_org=np.array([[x_org,y_org,z_org]]).T
rot1 = scipy.spatial.transform.Rotation.from_euler('x', -(90-lat_org), degrees=True).as_matrix()#angle*-1 : left handed *-1
rot3 = scipy.spatial.transform.Rotation.from_euler('z', -(90+lon_org), degrees=True).as_matrix()#angle*-1 : left handed *-1
rotMatrix = rot1.dot(rot3)
ecefDelta = rotMatrix.T.dot( np.array([[x,y,z]]).T )
ecef = ecefDelta+ecef_org
lon, lat, alt = transformer2.transform( ecef[0,0],ecef[1,0],ecef[2,0],radians=False)
return [lat,lon,alt]
if __name__ == '__main__':
# The local coordinate origin (Zermatt, Switzerland)
lat_org = 46.017 # deg
lon_org = 7.750 # deg
alt_org = 1673 # meters
# The point of interest
lat = 45.976 # deg
lon = 7.658 # deg
alt = 4531 # meters
res1 = geodetic2enu(lat, lon, alt, lat_org, lon_org, alt_org)
print (res1)
#[-7134.75719598 -4556.32151385 2852.39042395]
x=res1[0]
y=res1[1]
z=res1[2]
res2 = enu2geodetic(x,y,z, lat_org, lon_org, alt_org)
print (res2)
#[45.97600000000164, 7.658000000000001, 4531.0000001890585]
Ref. 1 https://gssc.esa.int/navipedia/index.php/Transformations_between_ECEF_and_ENU_coordinates
Ref 2 https://www.nsstc.uah.edu/users/phillip.bitzer/python_doc/pyltg/_modules/pyltg/utilities/latlon.html
Ref 3 https://gist.github.com/sbarratt/a72bede917b482826192bf34f9ff5d0b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With