Skip to content

Commit 01126f5

Browse files
committed
geodetic <=> geocentric added
vers
1 parent 2b15287 commit 01126f5

File tree

5 files changed

+158
-6
lines changed

5 files changed

+158
-6
lines changed

pymap3d/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from .ned import ned2ecef, ned2geodetic, geodetic2ned, ecef2nedv, ned2aer, aer2ned, ecef2ned
3838
from .ecef import geodetic2ecef, ecef2geodetic, eci2geodetic, ecef2enuv, enu2ecef, ecef2enu, enu2uvw, uvw2enu
3939
from .sidereal import datetime2sidereal
40+
from .latitude import geodetic2geocentric, geocentric2geodetic
4041
from .lox import isometric, meridian_dist, loxodrome_inverse
4142
from .los import lookAtSpheroid
4243
from .timeconv import str2dt

pymap3d/latitude.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
from .ellipsoid import Ellipsoid
2+
from math import atan, radians, degrees, tan
3+
4+
try:
5+
import numpy
6+
except ImportError:
7+
numpy = None
8+
9+
10+
def geodetic2geocentric(geodetic_lat: float, ell: Ellipsoid = None, deg: bool = True) -> float:
11+
if numpy is not None:
12+
fun = numpy.vectorize(geodetic2geocentric_point)
13+
return fun(geodetic_lat, ell, deg)
14+
else:
15+
return geodetic2geocentric_point(geodetic_lat, ell, deg)
16+
17+
18+
def geodetic2geocentric_point(geodetic_lat: float, ell: Ellipsoid = None, deg: bool = True) -> float:
19+
"""
20+
convert geodetic latitude to geocentric latitude.
21+
22+
this is like Matlab geocentricLatitude()
23+
https://www.mathworks.com/help/map/ref/geocentriclatitude.html
24+
25+
Parameters
26+
----------
27+
geodetic_lat : float
28+
geodetic latitude
29+
ell : Ellipsoid, optional
30+
reference ellipsoid (default WGS84)
31+
deg : bool, optional
32+
degrees input/output (False: radians in/out)
33+
34+
Returns
35+
-------
36+
geocentric_lat : float
37+
geocentric latiude
38+
39+
Notes
40+
-----
41+
Equations from J. P. Snyder, "Map Projections - A Working Manual",
42+
US Geological Survey Professional Paper 1395, US Government Printing
43+
Office, Washington, DC, 1987, pp. 13-18.
44+
"""
45+
46+
if ell is None:
47+
ell = Ellipsoid()
48+
49+
if abs(geodetic_lat) > 90:
50+
raise ValueError("-90 <= latitude <= 90")
51+
52+
if deg is True:
53+
geodetic_lat = radians(geodetic_lat)
54+
55+
geocentric_lat = atan((1 - (ell.eccentricity) ** 2) * tan(geodetic_lat))
56+
57+
if deg is True:
58+
geocentric_lat = degrees(geocentric_lat)
59+
60+
return geocentric_lat
61+
62+
63+
def geocentric2geodetic(geocentric_lat: float, ell: Ellipsoid = None, deg: bool = True) -> float:
64+
if numpy is not None:
65+
fun = numpy.vectorize(geocentric2geodetic_point)
66+
return fun(geocentric_lat, ell, deg)
67+
else:
68+
return geocentric2geodetic_point(geocentric_lat, ell, deg)
69+
70+
71+
def geocentric2geodetic_point(geocentric_lat: float, ell: Ellipsoid = None, deg: bool = True) -> float:
72+
"""
73+
converts from geocentric latitude to geodetic latitude
74+
75+
like Matlab geodeticLatitudeFromGeocentric
76+
https://www.mathworks.com/help/map/ref/geodeticlatitudefromgeocentric.html
77+
78+
Parameters
79+
----------
80+
geocentric_lat : float or numpy.ndarray of float
81+
geocentric latitude
82+
ell : Ellipsoid, optional
83+
reference ellipsoid (default WGS84)
84+
deg : bool, optional
85+
degrees input/output (False: radians in/out)
86+
87+
Returns
88+
-------
89+
geodetic_lat : float or numpy.ndarray of float
90+
geodetic latiude
91+
92+
Notes
93+
-----
94+
Equations from J. P. Snyder, "Map Projections - A Working Manual",
95+
US Geological Survey Professional Paper 1395, US Government Printing
96+
Office, Washington, DC, 1987, pp. 13-18.
97+
"""
98+
99+
if ell is None:
100+
ell = Ellipsoid()
101+
102+
if abs(geocentric_lat) > 90:
103+
raise ValueError("-90 <= latitude <= 90")
104+
105+
if deg is True:
106+
geocentric_lat = radians(geocentric_lat)
107+
108+
geodetic_lat = atan(tan(geocentric_lat) / (1 - (ell.eccentricity) ** 2))
109+
110+
if deg is True:
111+
geodetic_lat = degrees(geodetic_lat)
112+
113+
return geodetic_lat

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = pymap3d
3-
version = 2.0.0
3+
version = 2.0.1
44
author = Michael Hirsch, Ph.D.
55
author_email = [email protected]
66
description = pure Python (no prereqs) coordinate conversions, following convention of several popular Matlab routines.

tests/test_elliposid.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@
66
xyz0 = (660e3, -4700e3, 4247e3)
77

88

9-
@pytest.mark.parametrize("model,f", [("wgs84", 3.352810664747480e-03),
10-
("wgs72", 3.352779454167505e-03),
11-
("grs80", 3.352810681182319e-03),
12-
("clarke1866", 3.390075303928791e-03),
13-
("moon", 0.)])
9+
@pytest.mark.parametrize(
10+
"model,f",
11+
[
12+
("wgs84", 3.352810664747480e-03),
13+
("wgs72", 3.352779454167505e-03),
14+
("grs80", 3.352810681182319e-03),
15+
("clarke1866", 3.390075303928791e-03),
16+
("moon", 0.0),
17+
],
18+
)
1419
def test_reference(model, f):
1520
assert pm.Ellipsoid(model).flattening == approx(f)
1621

tests/test_latitude.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env python
2+
import pytest
3+
from pytest import approx
4+
from math import radians
5+
6+
import pymap3d as pm
7+
8+
9+
@pytest.mark.parametrize("geodetic_lat,geocentric_lat", [(0, 0), (90, 90), (-90, -90), (45, 44.80757678), (-45, -44.80757678)])
10+
def test_geodetic_geocentric(geodetic_lat, geocentric_lat):
11+
12+
assert pm.geodetic2geocentric(geodetic_lat) == approx(geocentric_lat)
13+
assert pm.geodetic2geocentric(radians(geodetic_lat), deg=False) == approx(radians(geocentric_lat))
14+
15+
assert pm.geocentric2geodetic(geocentric_lat) == approx(geodetic_lat)
16+
assert pm.geocentric2geodetic(radians(geocentric_lat), deg=False) == approx(radians(geodetic_lat))
17+
18+
19+
def test_numpy_geodetic_geocentric():
20+
pytest.importorskip("numpy")
21+
assert pm.geodetic2geocentric([45, 0]) == approx([44.80757678, 0])
22+
assert pm.geocentric2geodetic([44.80757678, 0]) == approx([45, 0])
23+
24+
25+
@pytest.mark.parametrize("lat", [91, -91])
26+
def test_badvals(lat):
27+
with pytest.raises(ValueError):
28+
pm.geodetic2geocentric(lat)
29+
pm.geocentric2geodetic(lat)
30+
31+
32+
if __name__ == "__main__":
33+
pytest.main(["-v", __file__])

0 commit comments

Comments
 (0)