99 from math import radians , degrees , cos , atan2 , tan , pi # type: ignore
1010
1111from .ellipsoid import Ellipsoid
12+ from .utils import sign
1213from . import rcurve
1314from . import rsphere
1415from .latitude import (
@@ -146,15 +147,17 @@ def loxodrome_inverse(
146147
147148 # compute azimuth
148149 az12 = atan2 (dlon , disolat )
149- cosaz12 = cos (az12 )
150+ aux = abs ( cos (az12 ) )
150151
151152 # compute distance along loxodromic curve
152- dist = meridian_arc (lat2 , lat1 , deg = False , ell = ell ) / abs (cos (az12 ))
153+ dist = meridian_arc (lat2 , lat1 , deg = False , ell = ell ) / aux
154+
155+ # straight east or west
153156 try :
154- if (abs ( cosaz12 ) < 1e-9 ).any ():
155- dist [abs ( cosaz12 ) < 1e-9 ] = departure (lon2 , lon1 , lat1 , ell , deg = False )
157+ if (aux < 1e-9 ).any ():
158+ dist [aux < 1e-9 ] = departure (lon2 , lon1 , lat1 , ell , deg = False )
156159 except (AttributeError , TypeError ):
157- if abs ( cosaz12 ) < 1e-9 : # straight east or west
160+ if aux < 1e-9 :
158161 dist = departure (lon2 , lon1 , lat1 , ell , deg = False )
159162
160163 if deg :
@@ -167,14 +170,15 @@ def loxodrome_direct(
167170 lat1 : float | ndarray ,
168171 lon1 : float | ndarray ,
169172 rng : float | ndarray ,
170- a12 : float | float ,
173+ a12 : float ,
171174 ell : Ellipsoid = None ,
172175 deg : bool = True ,
173- ) -> tuple [ndarray , ndarray ]:
176+ ) -> tuple [float | ndarray , float | ndarray ]:
174177 """
175178 Given starting lat, lon with arclength and azimuth, compute final lat, lon
176179
177180 like Matlab reckon('rh', ...)
181+ except that "rng" in meters instead of "arclen" degrees of arc
178182
179183 Parameters
180184 ----------
@@ -226,14 +230,23 @@ def loxodrome_direct(
226230 newiso = geodetic2isometric (lat2 , ell , deg = False )
227231 iso = geodetic2isometric (lat1 , ell , deg = False )
228232
233+ # stability near singularities
234+ i = abs (cos (a12 )) < 1e-6
229235 dlon = tan (a12 ) * (newiso - iso )
236+
237+ try :
238+ dlon [i ] = sign (dlon [i ]) * rng [i ] / rcurve .transverse (lat1 [i ], ell = ell , deg = False ) # type: ignore
239+ except (AttributeError , TypeError ):
240+ if i : # straight east or west
241+ dlon = sign (dlon ) * rng / rcurve .transverse (lat1 , ell = ell , deg = False )
242+
230243 lon2 = lon1 + dlon
231244
232245 if deg :
233246 lat2 , lon2 = degrees (lat2 ), degrees (lon2 )
234247
235248 try :
236- return lat2 .squeeze ()[()], lon2 .squeeze ()[()]
249+ return lat2 .squeeze ()[()], lon2 .squeeze ()[()] # type: ignore
237250 except AttributeError :
238251 return lat2 , lon2
239252
0 commit comments