Skip to content

Commit 82576e6

Browse files
committed
los/lox, math and numpy.vectorize
1 parent 1e6bf3e commit 82576e6

File tree

3 files changed

+43
-31
lines changed

3 files changed

+43
-31
lines changed

pymap3d/__init__.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,12 @@
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 .lox import isometric, meridian_dist, loxodrome_inverse
41+
from .los import lookAtSpheroid
42+
from .timeconv import str2dt
4043

4144
try:
42-
from .timeconv import str2dt
4345
from .azelradec import radec2azel, azel2radec
4446
from .eci import eci2ecef, ecef2eci
45-
46-
from .los import lookAtSpheroid
47-
from .lox import isometric, meridian_dist, loxodrome_inverse
4847
except ImportError:
4948
from .vallado import radec2azel, azel2radec

pymap3d/los.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
""" Line of sight intersection of space observer to ellipsoid """
22
from typing import Tuple
3-
import numpy as np
4-
from math import pi
3+
from math import pi, nan, sqrt
4+
55
from .aer import aer2enu
66
from .ecef import enu2uvw, geodetic2ecef, ecef2geodetic
77
from .ellipsoid import Ellipsoid
8+
try:
9+
import numpy
10+
except ImportError:
11+
numpy = None
812

913
__all__ = ['lookAtSpheroid']
1014

1115

1216
def lookAtSpheroid(lat0: float, lon0: float, h0: float, az: float, tilt: float,
1317
ell: Ellipsoid = None, deg: bool = True) -> Tuple[float, float, float]:
18+
if numpy is not None:
19+
fun = numpy.vectorize(lookAtSpheroid_point)
20+
return fun(lat0, lon0, h0, az, tilt, ell, deg)
21+
else:
22+
return lookAtSpheroid_point(lat0, lon0, h0, az, tilt, ell, deg)
23+
24+
25+
def lookAtSpheroid_point(lat0: float, lon0: float, h0: float, az: float, tilt: float,
26+
ell: Ellipsoid = None, deg: bool = True) -> Tuple[float, float, float]:
1427
"""
1528
Calculates line-of-sight intersection with Earth (or other ellipsoid) surface from above surface / orbit
1629
@@ -47,14 +60,12 @@ def lookAtSpheroid(lat0: float, lon0: float, h0: float, az: float, tilt: float,
4760
Algorithm based on https://medium.com/@stephenhartzell/satellite-line-of-sight-intersection-with-earth-d786b4a6a9b6 Stephen Hartzell
4861
"""
4962

50-
if (np.asarray(h0) < 0).any():
63+
if h0 < 0:
5164
raise ValueError('Intersection calculation requires altitude [0, Infinity)')
5265

5366
if ell is None:
5467
ell = Ellipsoid()
5568

56-
tilt = np.asarray(tilt)
57-
5869
a = ell.semimajor_axis
5970
b = ell.semimajor_axis
6071
c = ell.semiminor_axis
@@ -73,11 +84,13 @@ def lookAtSpheroid(lat0: float, lon0: float, h0: float, az: float, tilt: float,
7384
magnitude = a**2 * b**2 * w**2 + a**2 * c**2 * v**2 + b**2 * c**2 * u**2
7485

7586
# %% Return nan if radical < 0 or d < 0 because LOS vector does not point towards Earth
76-
with np.errstate(invalid='ignore'):
77-
d = np.where(radical > 0,
78-
(value - a * b * c * np.sqrt(radical)) / magnitude,
79-
np.nan)
80-
d[d < 0] = np.nan
87+
if radical > 0:
88+
d = (value - a * b * c * sqrt(radical)) / magnitude
89+
else:
90+
d = nan
91+
92+
if d < 0:
93+
d = nan
8194
# %% cartesian to ellipsodal
8295
lat, lon, _ = ecef2geodetic(x + d * u, y + d * v, z + d * w, deg=deg)
8396

pymap3d/lox.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
""" isometric latitude, meridian distance """
2-
import numpy as np
2+
from math import radians, degrees, sin, cos, atan2, tan, log, sqrt, pi
33
from .ellipsoid import Ellipsoid
44

55

@@ -40,20 +40,20 @@ def isometric(lat: float, ell: Ellipsoid = None, deg: bool = True):
4040
f = ell.flattening # flattening of ellipsoid
4141

4242
if deg is True:
43-
lat = np.deg2rad(lat)
43+
lat = radians(lat)
4444

4545
e2 = f * (2 - f) # eccentricity-squared
46-
e = np.sqrt(e2) # eccentricity of ellipsoid
46+
e = sqrt(e2) # eccentricity of ellipsoid
4747

48-
x = e * np.sin(lat)
48+
x = e * sin(lat)
4949
y = (1 - x) / (1 + x)
50-
z = np.pi / 4 + lat / 2
50+
z = pi / 4 + lat / 2
5151

5252
# calculate the isometric latitude
53-
isolat = np.log(np.tan(z) * (y**(e / 2)))
53+
isolat = log(tan(z) * (y**(e / 2)))
5454

5555
if deg is True:
56-
isolat = np.degrees(isolat)
56+
isolat = degrees(isolat)
5757

5858
return isolat
5959

@@ -90,7 +90,7 @@ def meridian_dist(lat: float, ell: Ellipsoid = None, deg: bool = True):
9090
"""
9191

9292
if deg is True:
93-
lat = np.radians(lat)
93+
lat = radians(lat)
9494

9595
# set ellipsoid parameters
9696
if ell is None:
@@ -116,11 +116,11 @@ def meridian_dist(lat: float, ell: Ellipsoid = None, deg: bool = True):
116116
F = (693 / 131072) * e10
117117

118118
term1 = A * lat
119-
term2 = (B / 2) * np.sin(2 * lat)
120-
term3 = (C / 4) * np.sin(4 * lat)
121-
term4 = (D / 6) * np.sin(6 * lat)
122-
term5 = (E / 8) * np.sin(8 * lat)
123-
term6 = (F / 10) * np.sin(10 * lat)
119+
term2 = (B / 2) * sin(2 * lat)
120+
term3 = (C / 4) * sin(4 * lat)
121+
term4 = (D / 6) * sin(6 * lat)
122+
term5 = (E / 8) * sin(8 * lat)
123+
term6 = (F / 10) * sin(10 * lat)
124124

125125
mdist = a * (1 - e2) * (term1 - term2 + term3 - term4 + term5 - term6)
126126

@@ -177,7 +177,7 @@ def loxodrome_inverse(lat1: float, lon1: float, lat2: float, lon2: float,
177177
ell = Ellipsoid()
178178

179179
if deg is True:
180-
lat1, lon1, lat2, lon2 = np.radians([lat1, lon1, lat2, lon2])
180+
lat1, lon1, lat2, lon2 = radians(lat1), radians(lon1), radians(lat2), radians(lon2)
181181

182182
# compute isometric latitude of P1 and P2
183183
isolat1 = isometric(lat1, deg=False, ell=ell)
@@ -188,15 +188,15 @@ def loxodrome_inverse(lat1: float, lon1: float, lat2: float, lon2: float,
188188
dlon = lon2 - lon1
189189

190190
# compute azimuth
191-
az12 = np.arctan2(dlon, disolat)
191+
az12 = atan2(dlon, disolat)
192192

193193
# compute distance along loxodromic curve
194194
m1 = meridian_dist(lat1, deg=False, ell=ell)
195195
m2 = meridian_dist(lat2, deg=False, ell=ell)
196196
dm = m2 - m1
197-
lox_s = dm / np.cos(az12)
197+
lox_s = dm / cos(az12)
198198

199199
if deg is True:
200-
az12 = np.degrees(az12) % 360.
200+
az12 = degrees(az12) % 360.
201201

202202
return lox_s, az12

0 commit comments

Comments
 (0)