Skip to content

Commit

Permalink
add no-numpy NED and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
scivision committed May 8, 2019
1 parent c31a098 commit 95e1e17
Show file tree
Hide file tree
Showing 3 changed files with 309 additions and 0 deletions.
1 change: 1 addition & 0 deletions pymap3d/math/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .ecef import Ellipsoid, geodetic2ecef, ecef2geodetic, ecef2enuv, ecef2enu, enu2uvw, uvw2enu, enu2ecef # noqa: F401
from .enu import enu2aer, aer2enu, enu2geodetic, geodetic2enu # noqa: F401
from .aer import aer2ecef, ecef2aer, geodetic2aer, aer2geodetic # noqa: F401
from .ned import aer2ned, ned2aer, ned2geodetic, ned2ecef, ecef2ned, geodetic2ned, ecef2nedv # noqa: F401
270 changes: 270 additions & 0 deletions pymap3d/math/ned.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
""" Transforms involving NED North East Down """
from .enu import geodetic2enu, aer2enu, enu2aer
from .ecef import ecef2geodetic, ecef2enuv, ecef2enu, enu2ecef, Ellipsoid
from typing import Tuple

__all__ = ['aer2ned', 'ned2aer', 'ned2geodetic', 'ned2ecef', 'ecef2ned', 'geodetic2ned', 'ecef2nedv']


def aer2ned(az: float, elev: float, slantRange: float,
deg: bool = True) -> Tuple[float, float, float]:
"""
converts azimuth, elevation, range to target from observer to North, East, Down
Parameters
-----------
az : float
azimuth
elev : float
elevation
slantRange : float
slant range [meters]
deg : bool, optional
degrees input/output (False: radians in/out)
Results
-------
n : float
North NED coordinate (meters)
e : float
East NED coordinate (meters)
d : float
Down NED coordinate (meters)
"""
e, n, u = aer2enu(az, elev, slantRange, deg=deg)

return n, e, -u


def ned2aer(n: float, e: float, d: float,
deg: bool = True) -> Tuple[float, float, float]:
"""
converts North, East, Down to azimuth, elevation, range
Parameters
----------
n : float
North NED coordinate (meters)
e : float
East NED coordinate (meters)
d : float
Down NED coordinate (meters)
deg : bool, optional
degrees input/output (False: radians in/out)
Results
-------
az : float
azimuth
elev : float
elevation
slantRange : float
slant range [meters]
"""
return enu2aer(e, n, -d, deg=deg)


def ned2geodetic(n: float, e: float, d: float,
lat0: float, lon0: float, h0: float,
ell: Ellipsoid = None, deg: bool = True) -> Tuple[float, float, float]:
"""
Converts North, East, Down to target latitude, longitude, altitude
Parameters
----------
n : float
North NED coordinate (meters)
e : float
East NED coordinate (meters)
d : float
Down NED coordinate (meters)
lat0 : float
Observer geodetic latitude
lon0 : float
Observer geodetic longitude
h0 : float
observer altitude above geodetic ellipsoid (meters)
ell : Ellipsoid, optional
reference ellipsoid
deg : bool, optional
degrees input/output (False: radians in/out)
Results
-------
lat : float
target geodetic latitude
lon : float
target geodetic longitude
h : float
target altitude above geodetic ellipsoid (meters)
"""
x, y, z = enu2ecef(e, n, -d, lat0, lon0, h0, ell, deg=deg)

return ecef2geodetic(x, y, z, ell, deg=deg)


def ned2ecef(n: float, e: float, d: float,
lat0: float, lon0: float, h0: float,
ell: Ellipsoid = None, deg: bool = True) -> Tuple[float, float, float]:
"""
North, East, Down to target ECEF coordinates
Parameters
----------
n : float
North NED coordinate (meters)
e : float
East NED coordinate (meters)
d : float
Down NED coordinate (meters)
lat0 : float
Observer geodetic latitude
lon0 : float
Observer geodetic longitude
h0 : float
observer altitude above geodetic ellipsoid (meters)
ell : Ellipsoid, optional
reference ellipsoid
deg : bool, optional
degrees input/output (False: radians in/out)
Results
-------
x : float
ECEF x coordinate (meters)
y : float
ECEF y coordinate (meters)
z : float
ECEF z coordinate (meters)
"""
return enu2ecef(e, n, -d, lat0, lon0, h0, ell, deg=deg)


def ecef2ned(x: float, y: float, z: float,
lat0: float, lon0: float, h0: float,
ell: Ellipsoid = None, deg: bool = True) -> Tuple[float, float, float]:
"""
Convert ECEF x,y,z to North, East, Down
Parameters
----------
x : float
ECEF x coordinate (meters)
y : float
ECEF y coordinate (meters)
z : float
ECEF z coordinate (meters)
lat0 : float
Observer geodetic latitude
lon0 : float
Observer geodetic longitude
h0 : float
observer altitude above geodetic ellipsoid (meters)
ell : Ellipsoid, optional
reference ellipsoid
deg : bool, optional
degrees input/output (False: radians in/out)
Results
-------
n : float
North NED coordinate (meters)
e : float
East NED coordinate (meters)
d : float
Down NED coordinate (meters)
"""
e, n, u = ecef2enu(x, y, z, lat0, lon0, h0, ell, deg=deg)

return n, e, -u


def geodetic2ned(lat: float, lon: float, h: float,
lat0: float, lon0: float, h0: float,
ell: Ellipsoid = None, deg: bool = True) -> Tuple[float, float, float]:
"""
convert latitude, longitude, altitude of target to North, East, Down from observer
Parameters
----------
lat : float
target geodetic latitude
lon : float
target geodetic longitude
h : float
target altitude above geodetic ellipsoid (meters)
lat0 : float
Observer geodetic latitude
lon0 : float
Observer geodetic longitude
h0 : float
observer altitude above geodetic ellipsoid (meters)
ell : Ellipsoid, optional
reference ellipsoid
deg : bool, optional
degrees input/output (False: radians in/out)
Results
-------
n : float
North NED coordinate (meters)
e : float
East NED coordinate (meters)
d : float
Down NED coordinate (meters)
"""
e, n, u = geodetic2enu(lat, lon, h, lat0, lon0, h0, ell, deg=deg)

return n, e, -u


def ecef2nedv(x: float, y: float, z: float,
lat0: float, lon0: float,
deg: bool = True) -> Tuple[float, float, float]:
"""
for VECTOR between two points
Parameters
----------
x : float
ECEF x coordinate (meters)
y : float
ECEF y coordinate (meters)
z : float
ECEF z coordinate (meters)
lat0 : float
Observer geodetic latitude
lon0 : float
Observer geodetic longitude
deg : bool, optional
degrees input/output (False: radians in/out)
Results
-------
(Vector)
n : float
North NED coordinate (meters)
e : float
East NED coordinate (meters)
d : float
Down NED coordinate (meters)
"""
e, n, u = ecef2enuv(x, y, z, lat0, lon0, deg=deg)

return n, e, -u
38 changes: 38 additions & 0 deletions tests/test_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
aer0 = (33, 70, 1000)
raer0 = (radians(aer0[0]), radians(aer0[1]), aer0[2])
enu0 = (186.277521, 286.842228, 939.692621)
ned0 = (enu0[1], enu0[0], -enu0[2])
vx, vy, vz = (5, 3, 2)
ve, vn, vu = (5.368859646588048, 3.008520763668120, -0.352347711524077)


def test_aer_enu():
Expand All @@ -32,5 +35,40 @@ def test_aer_enu():
assert pm.ecef2enu(*xyz, *rlla0, deg=False) == approx(enu)


def test_ned():
xyz = pm.aer2ecef(*aer0, *lla0)
enu = pm.aer2enu(*aer0)
ned = (enu[1], enu[0], -enu[2])
lla = pm.aer2geodetic(*aer0, *lla0)

assert pm.aer2ned(*aer0) == approx(ned0)

with pytest.raises(ValueError):
pm.aer2ned(aer0[0], aer0[1], -1)

assert pm.enu2aer(*enu) == approx(aer0)
assert pm.enu2aer(*enu, deg=False) == approx(raer0)

assert pm.ned2aer(*ned) == approx(aer0)

assert pm.ecef2ned(*xyz, *lla0) == approx(ned)

assert pm.ned2ecef(*ned, *lla0) == approx(xyz)
# %%
assert pm.ecef2enuv(vx, vy, vz, *lla0[:2]) == approx((ve, vn, vu))

assert pm.ecef2nedv(vx, vy, vz, *lla0[:2]) == approx((vn, ve, -vu))

# %%
enu3 = pm.geodetic2enu(*lla, *lla0)
ned3 = (enu3[1], enu3[0], -enu3[2])

assert pm.geodetic2ned(*lla, *lla0) == approx(ned3)

assert pm.enu2geodetic(*enu3, *lla0) == approx(lla)

assert pm.ned2geodetic(*ned3, *lla0) == approx(lla)


if __name__ == '__main__':
pytest.main([__file__])

0 comments on commit 95e1e17

Please sign in to comment.