pygeodesy 25.7.25__py2.py3-none-any.whl → 25.9.9__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygeodesy/__init__.py +10 -9
- pygeodesy/auxilats/__init__.py +1 -1
- pygeodesy/auxilats/auxAngle.py +4 -3
- pygeodesy/auxilats/auxily.py +1 -1
- pygeodesy/basics.py +4 -4
- pygeodesy/booleans.py +25 -25
- pygeodesy/cartesianBase.py +21 -20
- pygeodesy/constants.py +37 -7
- pygeodesy/deprecated/functions.py +1 -0
- pygeodesy/dms.py +2 -2
- pygeodesy/ecef.py +324 -260
- pygeodesy/ellipsoidalExact.py +4 -4
- pygeodesy/ellipsoidalGeodSolve.py +3 -3
- pygeodesy/ellipsoids.py +79 -52
- pygeodesy/elliptic.py +8 -11
- pygeodesy/errors.py +18 -5
- pygeodesy/etm.py +8 -8
- pygeodesy/fmath.py +1 -1
- pygeodesy/geodesicx/__init__.py +1 -1
- pygeodesy/geodesicx/__main__.py +1 -0
- pygeodesy/geodesicx/gx.py +30 -37
- pygeodesy/geodesicx/gxbases.py +1 -5
- pygeodesy/geodesicx/gxline.py +43 -34
- pygeodesy/geodsolve.py +10 -17
- pygeodesy/internals.py +39 -15
- pygeodesy/karney.py +19 -18
- pygeodesy/ktm.py +3 -3
- pygeodesy/latlonBase.py +4 -4
- pygeodesy/lazily.py +14 -13
- pygeodesy/lcc.py +5 -5
- pygeodesy/named.py +10 -13
- pygeodesy/nvectorBase.py +4 -4
- pygeodesy/rhumb/__init__.py +1 -1
- pygeodesy/rhumb/aux_.py +1 -1
- pygeodesy/rhumb/bases.py +7 -8
- pygeodesy/rhumb/ekx.py +9 -9
- pygeodesy/solveBase.py +14 -3
- pygeodesy/sphericalTrigonometry.py +8 -8
- pygeodesy/utily.py +200 -159
- pygeodesy/vector3dBase.py +10 -8
- {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/METADATA +12 -11
- {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/RECORD +44 -44
- {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/WHEEL +0 -0
- {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/top_level.txt +0 -0
pygeodesy/geodesicx/gx.py
CHANGED
|
@@ -65,7 +65,7 @@ from pygeodesy.utily import atan2, atan2d as _atan2d_reverse, _unrollon, \
|
|
|
65
65
|
from math import copysign, cos, degrees, fabs, radians, sqrt
|
|
66
66
|
|
|
67
67
|
__all__ = ()
|
|
68
|
-
__version__ = '25.
|
|
68
|
+
__version__ = '25.09.02'
|
|
69
69
|
|
|
70
70
|
_MAXIT1 = 20
|
|
71
71
|
_MAXIT2 = 10 + _MAXIT1 + MANT_DIG # MANT_DIG == C++ digits
|
|
@@ -134,7 +134,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
134
134
|
_datum = _WGS84
|
|
135
135
|
_nC4 = 30 # default C4order
|
|
136
136
|
|
|
137
|
-
def __init__(self, a_ellipsoid=_EWGS84, f=None, C4order=None, **name_C4Order): # for backward compatibility
|
|
137
|
+
def __init__(self, a_ellipsoid=_EWGS84, f=None, caps=None, C4order=None, **name_C4Order): # for backward compatibility
|
|
138
138
|
'''New L{GeodesicExact} instance.
|
|
139
139
|
|
|
140
140
|
@arg a_ellipsoid: An ellipsoid (L{Ellipsoid}) or datum (L{Datum}) or
|
|
@@ -142,6 +142,8 @@ class GeodesicExact(_GeodesicBase):
|
|
|
142
142
|
conventionally in C{meter}), see B{C{f}}.
|
|
143
143
|
@arg f: The flattening of the ellipsoid (C{scalar}) if B{C{a_ellipsoid}}
|
|
144
144
|
is specified as C{scalar}.
|
|
145
|
+
@kwarg caps: Optional default capabilities for L{GeodesicLineExact} instances,
|
|
146
|
+
use C{B{caps}=Caps.NONFINITONAN} to handle nonfinites silently.
|
|
145
147
|
@kwarg C4order: Optional series expansion order (C{int}), see property
|
|
146
148
|
L{C4order}, default C{30}.
|
|
147
149
|
@kwarg name_C4Order: Optional C{B{name}=NN} (C{str}) and the DEPRECATED
|
|
@@ -154,9 +156,11 @@ class GeodesicExact(_GeodesicBase):
|
|
|
154
156
|
if name:
|
|
155
157
|
self.name = name
|
|
156
158
|
else:
|
|
157
|
-
name =
|
|
159
|
+
name = name_C4Order # no name
|
|
158
160
|
|
|
159
161
|
_earth_datum(self, a_ellipsoid, f=f, **name)
|
|
162
|
+
if caps:
|
|
163
|
+
self._caps |= caps & Caps._OUT_MASK
|
|
160
164
|
if C4order: # XXX private copy, always?
|
|
161
165
|
self.C4order = C4order
|
|
162
166
|
|
|
@@ -193,10 +197,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
193
197
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
194
198
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
195
199
|
@arg a12: Arc length between the points (C{degrees}), can be negative.
|
|
196
|
-
@kwarg caps:
|
|
197
|
-
specifying the capabilities the L{GeodesicLineExact} instance
|
|
198
|
-
should possess, i.e., which quantities can be returned by methods
|
|
199
|
-
L{GeodesicLineExact.Position} and L{GeodesicLineExact.ArcPosition}.
|
|
200
|
+
@kwarg caps: Desired capabilities for the L{GeodesicLineExact} instance.
|
|
200
201
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
201
202
|
|
|
202
203
|
@return: A L{GeodesicLineExact} instance.
|
|
@@ -370,10 +371,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
370
371
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
371
372
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
372
373
|
@arg s12: Distance between the points (C{meter}), can be negative.
|
|
373
|
-
@kwarg caps:
|
|
374
|
-
specifying the capabilities the L{GeodesicLineExact} instance
|
|
375
|
-
should possess, i.e., which quantities can be returned by methods
|
|
376
|
-
L{GeodesicLineExact.Position}.
|
|
374
|
+
@kwarg caps: Desired capabilities for the L{GeodesicLineExact} instance.
|
|
377
375
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
378
376
|
|
|
379
377
|
@return: A L{GeodesicLineExact} instance.
|
|
@@ -487,7 +485,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
487
485
|
@return: A L{GDict} ...
|
|
488
486
|
'''
|
|
489
487
|
C = outmask if arcmode else (outmask | Caps.DISTANCE_IN)
|
|
490
|
-
glX = self.Line(lat1, lon1, azi1, C | Caps.LINE_OFF)
|
|
488
|
+
glX = self.Line(lat1, lon1, azi1, caps=C | Caps.LINE_OFF)
|
|
491
489
|
return glX._GDictPosition(arcmode, s12_a12, outmask)
|
|
492
490
|
|
|
493
491
|
def _GDictInverse(self, lat1, lon1, lat2, lon2, outmask=Caps.STANDARD): # MCCABE 33, 41 vars
|
|
@@ -495,22 +493,23 @@ class GeodesicExact(_GeodesicBase):
|
|
|
495
493
|
|
|
496
494
|
@return: A L{GDict} ...
|
|
497
495
|
'''
|
|
498
|
-
Cs = Caps
|
|
496
|
+
r, Cs = GDict(), Caps
|
|
499
497
|
if self._debug: # PYCHOK no cover
|
|
500
498
|
outmask |= Cs._DEBUG_INVERSE & self._debug
|
|
499
|
+
outmask |= self.caps
|
|
501
500
|
outmask &= Cs._OUT_MASK # incl. _SALP_CALPs_ and _DEBUG_
|
|
502
|
-
|
|
501
|
+
if _toNAN(outmask, lat1, lon1, lat2, lon2):
|
|
502
|
+
return r._toNAN(outmask, lat1=lat1, lon1=lon1, lat2=lat2, lon2=lon2)
|
|
503
|
+
|
|
503
504
|
# compute longitude difference carefully (with _diff182):
|
|
504
505
|
# result is in [-180, +180] but -180 is only for west-going
|
|
505
506
|
# geodesics, +180 is for east-going and meridional geodesics
|
|
506
507
|
lon12, lon12s = _diff182(lon1, lon2)
|
|
507
508
|
# see C{result} from geographiclib.geodesic.Inverse
|
|
508
509
|
if (outmask & Cs.LONG_UNROLL): # == (lon1 + lon12) + lon12s
|
|
509
|
-
r
|
|
510
|
+
r.set_(lon1=lon1, lon2=fsumf_(lon1, lon12, lon12s))
|
|
510
511
|
elif (outmask & Cs.LONGITUDE):
|
|
511
|
-
r
|
|
512
|
-
else:
|
|
513
|
-
r = GDict()
|
|
512
|
+
r.set_(lon1=_norm180(lon1), lon2=_norm180(lon2))
|
|
514
513
|
if _K_2_0: # GeographicLib 2.0
|
|
515
514
|
# make longitude difference positive
|
|
516
515
|
lon12, lon_ = _unsigned2(lon12)
|
|
@@ -543,7 +542,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
543
542
|
r.set_(lat1=lat1, lat2=lat2)
|
|
544
543
|
# Swap points so that point with higher (abs) latitude is
|
|
545
544
|
# point 1. If one latitude is a NAN, then it becomes lat1.
|
|
546
|
-
swap_ =
|
|
545
|
+
swap_ = isnan(lat2) or fabs(lat1) < fabs(lat2)
|
|
547
546
|
if swap_:
|
|
548
547
|
lat1, lat2 = lat2, lat1
|
|
549
548
|
lon_ = not lon_
|
|
@@ -580,7 +579,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
580
579
|
p = _PDict(sbet1=sbet1, cbet1=cbet1, dn1=self._dn(sbet1, cbet1),
|
|
581
580
|
sbet2=sbet2, cbet2=cbet2, dn2=self._dn(sbet2, cbet2))
|
|
582
581
|
|
|
583
|
-
_meridian = _b = True # i.e.
|
|
582
|
+
_meridian = _b = True # i.e. meridian = b = False
|
|
584
583
|
if lat1 == -90 or slam12 == 0:
|
|
585
584
|
# Endpoints are on a single full meridian,
|
|
586
585
|
# so the geodesic might lie on a meridian.
|
|
@@ -597,17 +596,18 @@ class GeodesicExact(_GeodesicBase):
|
|
|
597
596
|
# echo 20.001 0 20.001 0 | GeodSolve -i
|
|
598
597
|
# In fact, we will have sig12 > PI/2 for meridional
|
|
599
598
|
# geodesic which is not a shortest path.
|
|
600
|
-
if
|
|
599
|
+
if sig12 < _TOL2 or m12x >= 0: # GeographicLib 2.5.1
|
|
601
600
|
# Need at least 2 to handle 90 0 90 180
|
|
602
601
|
# Prevent negative s12 or m12 from geographiclib 1.52
|
|
603
602
|
if sig12 < _TINY3 or (sig12 < _TOL0 and (s12x < 0 or m12x < 0)):
|
|
604
603
|
sig12 = m12x = s12x = _0_0
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
604
|
+
# else:
|
|
605
|
+
# m12x *= self.b
|
|
606
|
+
# s12x *= self.b
|
|
607
|
+
_meridian = _b = False # i.e. meridian = b = True
|
|
608
608
|
C = 1
|
|
609
|
-
|
|
610
|
-
|
|
609
|
+
# else: # m12 < 0, prolate and too close to anti-podal
|
|
610
|
+
# _meridian = True # i.e. meridian = False
|
|
611
611
|
a12 = _0_0 # if _b else degrees(sig12)
|
|
612
612
|
|
|
613
613
|
if _meridian:
|
|
@@ -651,7 +651,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
651
651
|
if (outmask & Cs.AREA):
|
|
652
652
|
somg12, comg12 = _sincos2(lam12 / (self.f1 * dnm))
|
|
653
653
|
|
|
654
|
-
else: # _meridian is False
|
|
654
|
+
else: # _meridian is False, i.e. meridian is True
|
|
655
655
|
somg12 = comg12 = NAN
|
|
656
656
|
|
|
657
657
|
r.set_(a12=a12 if _b else degrees(sig12)) # in [0, 180]
|
|
@@ -702,8 +702,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
702
702
|
p.update(r) # r overrides p
|
|
703
703
|
r = p.toGDict()
|
|
704
704
|
|
|
705
|
-
|
|
706
|
-
return r._toNAN(outmask) if toNAN else r
|
|
705
|
+
return self._iter2tion(r, **p)
|
|
707
706
|
|
|
708
707
|
def _GenDirect(self, lat1, lon1, azi1, arcmode, s12_a12, outmask=Caps.STANDARD):
|
|
709
708
|
'''(INTERNAL) The general I{Inverse} geodesic calculation.
|
|
@@ -791,10 +790,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
791
790
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
792
791
|
@arg lat2: Latitude of the second point (C{degrees}).
|
|
793
792
|
@arg lon2: Longitude of the second point (C{degrees}).
|
|
794
|
-
@kwarg caps:
|
|
795
|
-
specifying the capabilities the L{GeodesicLineExact} instance
|
|
796
|
-
should possess, i.e., which quantities can be returned by methods
|
|
797
|
-
L{GeodesicLineExact.Position} and L{GeodesicLineExact.ArcPosition}.
|
|
793
|
+
@kwarg caps: Desired capabilities for the L{GeodesicLineExact} instance.
|
|
798
794
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
799
795
|
|
|
800
796
|
@return: A L{GeodesicLineExact} instance.
|
|
@@ -1106,10 +1102,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
1106
1102
|
@arg lat1: Latitude of the first point (C{degrees}).
|
|
1107
1103
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
1108
1104
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
1109
|
-
@kwarg caps:
|
|
1110
|
-
specifying the capabilities the L{GeodesicLineExact} instance
|
|
1111
|
-
should possess, i.e., which quantities can be returned by methods
|
|
1112
|
-
L{GeodesicLineExact.Position} and L{GeodesicLineExact.ArcPosition}.
|
|
1105
|
+
@kwarg caps: Desired capabilities for the L{GeodesicLineExact} instance.
|
|
1113
1106
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
1114
1107
|
|
|
1115
1108
|
@return: A L{GeodesicLineExact} instance.
|
pygeodesy/geodesicx/gxbases.py
CHANGED
|
@@ -150,11 +150,7 @@ def _sinf1cos2d(lat, f1):
|
|
|
150
150
|
def _toNAN(outmask, *args):
|
|
151
151
|
'''(INTERNAL) Is any C{arg} not finite?
|
|
152
152
|
'''
|
|
153
|
-
|
|
154
|
-
for arg in args:
|
|
155
|
-
if not isfinite(arg):
|
|
156
|
-
return True
|
|
157
|
-
return False
|
|
153
|
+
return bool(outmask & _CapsBase.NONFINITONAN) and not all(map(isfinite, args))
|
|
158
154
|
|
|
159
155
|
|
|
160
156
|
def _xnC4(**name_nC4):
|
pygeodesy/geodesicx/gxline.py
CHANGED
|
@@ -38,9 +38,11 @@ from __future__ import division as _; del _ # noqa: E702 ;
|
|
|
38
38
|
|
|
39
39
|
# from pygeodesy.basics import _xinstanceof # _MODS
|
|
40
40
|
from pygeodesy.constants import NAN, _EPSqrt as _TOL, \
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
_copysign_1_0, isfinite, \
|
|
42
|
+
_0_0, _1_0, _180_0, _360_0, \
|
|
43
|
+
_2__PI # PYCHOK used!
|
|
43
44
|
from pygeodesy.errors import _xError, _xkwds_pop2
|
|
45
|
+
# from pygeodesy.fmath import fremainder # from .karney
|
|
44
46
|
from pygeodesy.fsums import fsumf_, fsum1f_
|
|
45
47
|
from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
|
|
46
48
|
_sincos12, _sin1cos2, \
|
|
@@ -49,14 +51,14 @@ from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
|
|
|
49
51
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS
|
|
50
52
|
from pygeodesy.karney import _around, _atan2d, Caps, GDict, _fix90, \
|
|
51
53
|
_K_2_0, _llz2gl, _norm2, _norm180, \
|
|
52
|
-
_sincos2, _sincos2d
|
|
54
|
+
_sincos2, _sincos2d, fremainder
|
|
53
55
|
from pygeodesy.props import Property_RO, property_ROver, _update_all
|
|
54
56
|
from pygeodesy.utily import atan2, atan2d as _atan2d_reverse, sincos2
|
|
55
57
|
|
|
56
|
-
from math import
|
|
58
|
+
from math import degrees, fabs, radians
|
|
57
59
|
|
|
58
60
|
__all__ = ()
|
|
59
|
-
__version__ = '25.
|
|
61
|
+
__version__ = '25.09.09'
|
|
60
62
|
|
|
61
63
|
_glXs = [] # instances of C{[_]GeodesicLineExact} to be updated
|
|
62
64
|
|
|
@@ -83,6 +85,7 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
83
85
|
'''
|
|
84
86
|
_a13 = _s13 = NAN
|
|
85
87
|
# _azi1 = _0_0
|
|
88
|
+
_caps = Caps._AZIMUTH_LATITUDE_LONG_UNROLL
|
|
86
89
|
# _cchi1 = NAN
|
|
87
90
|
# _dn1 = NAN
|
|
88
91
|
_gX = None # Exact only
|
|
@@ -106,7 +109,6 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
106
109
|
salp1, calp1 = _sincos2d(_around(azi1))
|
|
107
110
|
if name_:
|
|
108
111
|
self.name = name_
|
|
109
|
-
self._toNAN = _toNAN(caps, lat1, lon1, azi1, salp1, calp1)
|
|
110
112
|
|
|
111
113
|
self._gX = gX # GeodesicExact only
|
|
112
114
|
self._lat1 = lat1 = _fix90(lat1)
|
|
@@ -115,7 +117,9 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
115
117
|
self._salp1 = salp1
|
|
116
118
|
self._calp1 = calp1
|
|
117
119
|
# allow lat, azimuth and unrolling of lon
|
|
118
|
-
self._caps
|
|
120
|
+
self._caps |= caps | gX.caps # | Caps._AZIMUTH_LATITUDE_LONG_UNROLL
|
|
121
|
+
|
|
122
|
+
self._toNAN = _toNAN(self._caps, lat1, lon1, azi1, salp1, calp1)
|
|
119
123
|
|
|
120
124
|
sbet1, cbet1 = _sinf1cos2d(_around(lat1), gX.f1)
|
|
121
125
|
self._dn1 = gX._dn(sbet1, cbet1)
|
|
@@ -282,8 +286,11 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
282
286
|
def _eF(self):
|
|
283
287
|
'''(INTERNAL) Cached/memoized C{Elliptic} function.
|
|
284
288
|
'''
|
|
285
|
-
|
|
286
|
-
|
|
289
|
+
e = _MODS.elliptic
|
|
290
|
+
try: # see .gx.GeodesicExact._ef_reset_k2
|
|
291
|
+
return e.Elliptic(k2=-self._k2, alpha2=-self.geodesic.ep2)
|
|
292
|
+
except e.EllipticError: # nonfinite
|
|
293
|
+
return None
|
|
287
294
|
|
|
288
295
|
def _GDictPosition(self, arcmode, s12_a12, outmask=Caps.STANDARD): # MCCABE 17
|
|
289
296
|
'''(INTERNAL) Generate a new position along the geodesic.
|
|
@@ -293,26 +300,27 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
293
300
|
C{lon1}, C{azi1} and arc length C{a12} always included,
|
|
294
301
|
except when C{a12=NAN}.
|
|
295
302
|
'''
|
|
296
|
-
Cs = Caps
|
|
303
|
+
r, Cs = GDict(), Caps
|
|
297
304
|
if outmask:
|
|
298
305
|
outmask &= self._caps & Cs._OUT_MASK
|
|
299
306
|
eF = self._eF
|
|
307
|
+
if eF is None or self._toNAN or not isfinite(s12_a12): # _toNAN(outmask, s12_a12)?
|
|
308
|
+
# E2 = sig12 = ssig12 = csig12 = NAN
|
|
309
|
+
d = dict(a12=s12_a12) if arcmode else dict(s12=s12_a12)
|
|
310
|
+
return r._toNAN(outmask | Cs.NONFINITONAN, # for backward compatibility
|
|
311
|
+
lat1=self.lat1, lon1=self.lon1, azi1=self.azi1, **d)
|
|
300
312
|
gX = self.geodesic # ._gX
|
|
301
|
-
r = GDict(a12=NAN, s12=NAN) # both a12 and s12, always
|
|
302
313
|
|
|
303
|
-
if
|
|
304
|
-
|
|
305
|
-
return r._toNAN(outmask | Cs.NONFINITONAN) # for backward compatibility
|
|
306
|
-
elif arcmode: # s12_a12 is (spherical) arc length
|
|
307
|
-
r.set_(a12=s12_a12)
|
|
314
|
+
if arcmode: # s12_a12 is (spherical) arc length
|
|
315
|
+
r.set_(a12=s12_a12, s12=NAN)
|
|
308
316
|
sig12 = radians(s12_a12)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
317
|
+
ssig12, csig12 = sincos2(sig12) # utily, no NEG0
|
|
318
|
+
if not _K_2_0: # PYCHOK no cover
|
|
319
|
+
d = fremainder(fabs(s12_a12), _180_0)
|
|
320
|
+
if d == 90:
|
|
321
|
+
csig12 = _0_0
|
|
322
|
+
elif d == 0:
|
|
323
|
+
ssig12 = _0_0
|
|
316
324
|
E2 = _0_0
|
|
317
325
|
elif self._caps_DISTANCE_IN: # s12_a12 is distance
|
|
318
326
|
t = s12_a12 / self._E0b
|
|
@@ -321,9 +329,9 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
321
329
|
E2 = -eF.deltaEinv(*_sincos12(-s, c, *self._stau1_ctau1))
|
|
322
330
|
sig12 = fsum1f_(self._E1, -E2, t) # == t - (E2 - E1)
|
|
323
331
|
ssig12, csig12 = _sincos2(sig12)
|
|
324
|
-
r.set_(a12=degrees(sig12))
|
|
332
|
+
r.set_(a12=degrees(sig12), s12=s12_a12)
|
|
325
333
|
else: # uninitialized or impossible distance requested
|
|
326
|
-
return r
|
|
334
|
+
return r.set_(a12=NAN, s12=NAN)
|
|
327
335
|
|
|
328
336
|
# sig2 = sig1 + sig12
|
|
329
337
|
ssig1, csig1 = self._ssig1, self._csig1
|
|
@@ -331,7 +339,6 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
331
339
|
dn2 = eF.fDelta(*t)
|
|
332
340
|
|
|
333
341
|
if (outmask & Cs.DISTANCE):
|
|
334
|
-
outmask ^= Cs.DISTANCE
|
|
335
342
|
if arcmode: # or f_0_01
|
|
336
343
|
E2 = eF.deltaE(ssig2, csig2, dn2)
|
|
337
344
|
# AB1 = _E0 * (E2 - _E1)
|
|
@@ -343,7 +350,7 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
343
350
|
s12 = s12_a12
|
|
344
351
|
r.set_(s12=s12)
|
|
345
352
|
|
|
346
|
-
if not outmask: # all done, see ._GenSet
|
|
353
|
+
if not (outmask ^ Cs.DISTANCE): # all done, see ._GenSet
|
|
347
354
|
return r
|
|
348
355
|
|
|
349
356
|
if self._debug: # PYCHOK no cover
|
|
@@ -374,17 +381,19 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
374
381
|
if (outmask & Cs.LONGITUDE):
|
|
375
382
|
schi1 = self._somg1
|
|
376
383
|
cchi1 = self._cchi1
|
|
377
|
-
schi2 = ssig2 * salp0
|
|
378
|
-
cchi2 = gX.f1 * dn2 * csig2
|
|
384
|
+
schi2 = ssig2 * salp0 # schi2 = somg2 without normalization
|
|
385
|
+
cchi2 = gX.f1 * dn2 * csig2
|
|
379
386
|
lam12 = salp0 * self._H0e2_f1 * fsum1f_(eF.deltaH(ssig2, csig2, dn2),
|
|
380
387
|
-self._H1, sig12)
|
|
381
388
|
if (outmask & Cs.LONG_UNROLL):
|
|
382
|
-
|
|
383
|
-
tchi1 =
|
|
384
|
-
tchi2 =
|
|
385
|
-
chi12 =
|
|
389
|
+
e = _copysign_1_0(salp0) # east-going?
|
|
390
|
+
tchi1 = e * schi1
|
|
391
|
+
tchi2 = e * schi2
|
|
392
|
+
chi12 = e * fsum1f_(atan2(ssig1, csig1), -atan2(ssig2, csig2),
|
|
386
393
|
atan2(tchi2, cchi2), -atan2(tchi1, cchi1), sig12)
|
|
387
394
|
lon2 = self.lon1 + degrees(chi12 - lam12)
|
|
395
|
+
if fabs(lon2) > _360_0: # XXX kludge
|
|
396
|
+
lon2 = _norm180(lon2)
|
|
388
397
|
else:
|
|
389
398
|
chi12 = atan2(*_sincos12(schi1, cchi1, schi2, cchi2))
|
|
390
399
|
lon2 = _norm180(self._lon1_norm180 + _norm180(degrees(chi12 - lam12)))
|
|
@@ -398,7 +407,7 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
398
407
|
J12 = self._D0k2 * fsumf_(eF.deltaD(ssig2, csig2, dn2), -self._D1, sig12)
|
|
399
408
|
if (outmask & Cs._DEBUG_DIRECT_LINE): # PYCHOK no cover
|
|
400
409
|
r.set_(ssig1=ssig1, dn1=dn1, D0k2=self._D0k2,
|
|
401
|
-
csig1=csig1,
|
|
410
|
+
csig1=csig1, dn2=dn2, D1=self._D1, J12=J12)
|
|
402
411
|
if (outmask & Cs.REDUCEDLENGTH):
|
|
403
412
|
# Add parens around (csig1 * ssig2) and (ssig1 * csig2) to
|
|
404
413
|
# ensure accurate cancellation in the case of coincident points.
|
pygeodesy/geodsolve.py
CHANGED
|
@@ -16,14 +16,13 @@ from pygeodesy.interns import _DMAIN_, NN, _UNDER_
|
|
|
16
16
|
from pygeodesy.karney import Caps, GeodesicError, GeodSolve12Tuple, \
|
|
17
17
|
_sincos2d, _Xables, _0_0, NAN
|
|
18
18
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
19
|
-
from pygeodesy.named import _name1__
|
|
20
19
|
from pygeodesy.namedTuples import Destination3Tuple, Distance3Tuple
|
|
21
20
|
from pygeodesy.props import Property, Property_RO, property_RO
|
|
22
21
|
from pygeodesy.solveBase import _SolveGDictBase, _SolveGDictLineBase
|
|
23
22
|
from pygeodesy.utily import _unrollon, _Wrap, wrap360
|
|
24
23
|
|
|
25
24
|
__all__ = _ALL_LAZY.geodsolve
|
|
26
|
-
__version__ = '25.
|
|
25
|
+
__version__ = '25.09.03'
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
class _GeodesicSolveBase(_SolveGDictBase):
|
|
@@ -131,18 +130,15 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
131
130
|
'''
|
|
132
131
|
return self.DirectLine(ll1.lat, ll1.lon, azi12, **caps_name)
|
|
133
132
|
|
|
134
|
-
def DirectLine(self, lat1, lon1, azi1, **
|
|
133
|
+
def DirectLine(self, lat1, lon1, azi1, caps=Caps.ALL, **name):
|
|
135
134
|
'''Set up a L{GeodesicLineSolve} to compute several points
|
|
136
135
|
on a single geodesic.
|
|
137
136
|
|
|
138
137
|
@arg lat1: Latitude of the first point (C{degrees}).
|
|
139
138
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
140
139
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
141
|
-
@kwarg
|
|
142
|
-
|
|
143
|
-
of L{Caps<pygeodesy.karney.Caps>} values specifying
|
|
144
|
-
the capabilities the L{GeodesicLineSolve} instance
|
|
145
|
-
should possess.
|
|
140
|
+
@kwarg caps: Desired capabilities for the L{GeodesicLineSolve} instance.
|
|
141
|
+
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
146
142
|
|
|
147
143
|
@return: A L{GeodesicLineSolve} instance.
|
|
148
144
|
|
|
@@ -154,9 +150,9 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
154
150
|
<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>}
|
|
155
151
|
and Python U{Geodesic.Line<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
|
|
156
152
|
'''
|
|
157
|
-
return GeodesicLineSolve(self, lat1, lon1, azi1,
|
|
153
|
+
return GeodesicLineSolve(self, lat1, lon1, azi1, caps=caps, **name)
|
|
158
154
|
|
|
159
|
-
Line = DirectLine
|
|
155
|
+
Line = ArcDirectLine = DirectLine
|
|
160
156
|
|
|
161
157
|
def _Inverse(self, ll1, ll2, wrap, **outmask): # PYCHOK no cover
|
|
162
158
|
'''(INTERNAL) Short-cut version, see .ellipsoidalBaseDI.intersecant2.
|
|
@@ -182,7 +178,7 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
182
178
|
ll2 = _unrollon(ll1, _Wrap.point(ll2))
|
|
183
179
|
return self.InverseLine(ll1.lat, ll1.lon, ll2.lat, ll2.lon, **caps_name)
|
|
184
180
|
|
|
185
|
-
def InverseLine(self, lat1, lon1, lat2, lon2, **
|
|
181
|
+
def InverseLine(self, lat1, lon1, lat2, lon2, caps=Caps.ALL, **name): # PYCHOK no cover
|
|
186
182
|
'''Set up a L{GeodesicLineSolve} to compute several points
|
|
187
183
|
on a single geodesic.
|
|
188
184
|
|
|
@@ -190,11 +186,8 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
190
186
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
191
187
|
@arg lat2: Latitude of the second point (C{degrees}).
|
|
192
188
|
@arg lon2: Longitude of the second point (C{degrees}).
|
|
193
|
-
@kwarg
|
|
194
|
-
|
|
195
|
-
of L{Caps<pygeodesy.karney.Caps>} values specifying
|
|
196
|
-
the capabilities the L{GeodesicLineSolve} instance
|
|
197
|
-
should possess.
|
|
189
|
+
@kwarg caps: Desired capabilities for the L{GeodesicLineSolve} instance.
|
|
190
|
+
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
198
191
|
|
|
199
192
|
@return: A L{GeodesicLineSolve} instance.
|
|
200
193
|
|
|
@@ -205,7 +198,7 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
205
198
|
Python U{Geodesic.InverseLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
|
|
206
199
|
'''
|
|
207
200
|
r = self.Inverse(lat1, lon1, lat2, lon2)
|
|
208
|
-
gl = GeodesicLineSolve(self, lat1, lon1, r.azi1,
|
|
201
|
+
gl = GeodesicLineSolve(self, lat1, lon1, r.azi1, caps=caps, **name)
|
|
209
202
|
gl._a13 = r.a12 # gl.SetArc(r.a12)
|
|
210
203
|
gl._s13 = r.s12 # gl.SetDistance(r.s12)
|
|
211
204
|
return gl
|
pygeodesy/internals.py
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
u'''Mostly INTERNAL functions, except L{machine}, L{print_} and L{printf}.
|
|
5
5
|
'''
|
|
6
6
|
# from pygeodesy.basics import isiterablen, ubstr # _MODS
|
|
7
|
-
# from pygeodesy.errors import _AttributeError, _error_init, _UnexpectedError, _xError2 # _MODS
|
|
8
|
-
from pygeodesy.interns import _BAR_, _COLON_, _DASH_, _DMAIN_, _DOT_, _ELLIPSIS_,
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
# from pygeodesy.errors import _AttributeError, _error_init, _ImmutableError, _UnexpectedError, _xError2 # _MODS
|
|
8
|
+
from pygeodesy.interns import _BAR_, _COLON_, _DASH_, _DMAIN_, _DOT_, _ELLIPSIS_, _NL_, NN, \
|
|
9
|
+
_pygeodesy_, _PyPy__, _python_, _QUOTE1_, _QUOTE2_, _s_, _sys, \
|
|
10
|
+
_SPACE_, _UNDER_
|
|
11
11
|
from pygeodesy.interns import _COMMA_, _Python_ # PYCHOK used!
|
|
12
12
|
# from pygeodesy.streprs import anstr, pairs, unstr # _MODS
|
|
13
13
|
|
|
@@ -56,6 +56,27 @@ def _Property_RO(method):
|
|
|
56
56
|
return property(_get, _set, _del)
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
class _Enum(object): # in .elliptic, .utily
|
|
60
|
+
'''(INTERNAL) Enum-like, immutable items.
|
|
61
|
+
'''
|
|
62
|
+
# _ImmutableError = None
|
|
63
|
+
|
|
64
|
+
def __init__(self, **enums):
|
|
65
|
+
self.__dict__.update(enums)
|
|
66
|
+
# for item in enums.items():
|
|
67
|
+
# setattr(self, *item) # object.__setattr__
|
|
68
|
+
|
|
69
|
+
def __str__(self):
|
|
70
|
+
_unstr = _MODS.streprs.unstr
|
|
71
|
+
return _unstr(_Enum, **self.__dict__)
|
|
72
|
+
|
|
73
|
+
# def __delattr__(self, attr): # PYCHOK no cover
|
|
74
|
+
# raise _ImmutableError(self, attr) # _del_
|
|
75
|
+
|
|
76
|
+
# def __setattr__(self, attr, value): # PYCHOK no cover
|
|
77
|
+
# raise _ImmutableError(self, attr, value)
|
|
78
|
+
|
|
79
|
+
|
|
59
80
|
class _MODS_Base(object):
|
|
60
81
|
'''(INTERNAL) Base-class for C{lazily._ALL_MODS}.
|
|
61
82
|
'''
|
|
@@ -63,10 +84,7 @@ class _MODS_Base(object):
|
|
|
63
84
|
self.__dict__.pop(attr, None)
|
|
64
85
|
|
|
65
86
|
def __setattr__(self, attr, value): # PYCHOK no cover
|
|
66
|
-
|
|
67
|
-
n = _DOT_(self.name, attr)
|
|
68
|
-
t = _EQUALSPACED_(n, repr(value))
|
|
69
|
-
raise e._AttributeError(_immutable_, txt=t)
|
|
87
|
+
raise _ImmutableError(self, attr, value)
|
|
70
88
|
|
|
71
89
|
@_Property_RO
|
|
72
90
|
def basics(self):
|
|
@@ -76,7 +94,7 @@ class _MODS_Base(object):
|
|
|
76
94
|
return b
|
|
77
95
|
|
|
78
96
|
@_Property_RO
|
|
79
|
-
def bits_machine2(self):
|
|
97
|
+
def bits_machine2(self): # in test/bases.py
|
|
80
98
|
'''Get platform 2-list C{[bits, machine]}, I{once}.
|
|
81
99
|
'''
|
|
82
100
|
import platform as p
|
|
@@ -302,6 +320,12 @@ def _headof(name):
|
|
|
302
320
|
return name if i < 0 else name[:i]
|
|
303
321
|
|
|
304
322
|
|
|
323
|
+
def _ImmutableError(*inst_attr_value):
|
|
324
|
+
'''(INTERNAL) Format an C{_ImmutableError}.
|
|
325
|
+
'''
|
|
326
|
+
return _MODS.errors._ImmutableError(*inst_attr_value)
|
|
327
|
+
|
|
328
|
+
|
|
305
329
|
# def _is(a, b): # PYCHOK no cover
|
|
306
330
|
# '''(INTERNAL) C{a is b}? in C{PyPy}
|
|
307
331
|
# '''
|
|
@@ -473,10 +497,10 @@ def printf(fmt, *args, **nl_nt_prec_prefix__end_file_flush_sep__kwds):
|
|
|
473
497
|
else:
|
|
474
498
|
t = fmt
|
|
475
499
|
except Exception as x:
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
t =
|
|
479
|
-
raise
|
|
500
|
+
_Error, s = _MODS.errors._xError2(x)
|
|
501
|
+
_unstr = _MODS.strepr.unstr
|
|
502
|
+
t = _unstr(printf, fmt, *args, **nl_nt_prec_prefix__end_file_flush_sep__kwds)
|
|
503
|
+
raise _Error(s, txt=t, cause=x)
|
|
480
504
|
try:
|
|
481
505
|
n = f.write(NN(b, t, e))
|
|
482
506
|
except UnicodeEncodeError: # XXX only Windows
|
|
@@ -686,7 +710,7 @@ def _versions(sep=_SPACE_):
|
|
|
686
710
|
|
|
687
711
|
|
|
688
712
|
__all__ = tuple(map(typename, (machine, print_, printf, typename)))
|
|
689
|
-
__version__ = '25.05
|
|
713
|
+
__version__ = '25.09.05'
|
|
690
714
|
|
|
691
715
|
if __name__ == _DMAIN_:
|
|
692
716
|
|
|
@@ -699,7 +723,7 @@ if __name__ == _DMAIN_:
|
|
|
699
723
|
_main()
|
|
700
724
|
|
|
701
725
|
# % python3 -m pygeodesy.internals
|
|
702
|
-
# pygeodesy 25.
|
|
726
|
+
# pygeodesy 25.8.18 Python 3.13.5 64bit arm64 macOS 15.6 _isfrozen False isLazy 1
|
|
703
727
|
|
|
704
728
|
# **) MIT License
|
|
705
729
|
#
|
pygeodesy/karney.py
CHANGED
|
@@ -157,8 +157,7 @@ from pygeodesy.interns import NN, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
|
|
|
157
157
|
_SPACE_, _UNDER_, _X_, _1_, _2_, _BAR_ # PYCHOK used!
|
|
158
158
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
|
|
159
159
|
from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
|
|
160
|
-
from pygeodesy.props import deprecated_method,
|
|
161
|
-
property_ROnce
|
|
160
|
+
from pygeodesy.props import deprecated_method, property_RO, property_ROnce
|
|
162
161
|
from pygeodesy.units import Azimuth as _Azi, Degrees as _Deg, Lat, Lon, \
|
|
163
162
|
Meter as _M, Meter2 as _M2, Number_
|
|
164
163
|
from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
|
|
@@ -166,7 +165,7 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
|
|
|
166
165
|
# from math import fabs # from .utily
|
|
167
166
|
|
|
168
167
|
__all__ = _ALL_LAZY.karney
|
|
169
|
-
__version__ = '25.
|
|
168
|
+
__version__ = '25.08.31'
|
|
170
169
|
|
|
171
170
|
_2_4_ = '2.4'
|
|
172
171
|
_K_2_0 = _getenv(_PYGEODESY_ENV(typename(_xgeographiclib)[2:]), _2_)
|
|
@@ -270,16 +269,16 @@ class Caps(object):
|
|
|
270
269
|
REDUCEDLENGTH = 1 << 12 | _CAP_1 | _CAP_2 # compute reduced length C{m12}
|
|
271
270
|
GEODESICSCALE = 1 << 13 | _CAP_1 | _CAP_2 # compute geodesic scales C{M12} and C{M21}
|
|
272
271
|
AREA = 1 << 14 | _CAP_4 # compute area C{S12}
|
|
272
|
+
ALL = 0x7F80 | _CAP_ALL # without LONG_UNROLL, LINE_OFF, NONFINITONAN, REVERSE2 and _DEBUG_*
|
|
273
273
|
|
|
274
274
|
STANDARD = AZIMUTH | DISTANCE | LATITUDE | LONGITUDE
|
|
275
275
|
STANDARD_LINE = STANDARD | DISTANCE_IN # for goedesici/-w
|
|
276
276
|
|
|
277
277
|
LINE_CAPS = STANDARD_LINE | REDUCEDLENGTH | GEODESICSCALE # .geodesici only
|
|
278
278
|
LONG_UNROLL = 1 << 15 # unroll C{lon2} in .Direct and .Position
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
LINE_OFF = 1 << 16 # Line without updates from parent geodesic or rhumb
|
|
280
|
+
NONFINITONAN = 1 << 17 # see method GDict._toNAN
|
|
281
281
|
REVERSE2 = 1 << 18 # reverse C{azi2}
|
|
282
|
-
ALL = 0x7F80 | _CAP_ALL # without LONG_UNROLL, LINE_OFF, REVERSE2 and _DEBUG_*
|
|
283
282
|
|
|
284
283
|
AZIMUTH_DISTANCE = AZIMUTH | DISTANCE
|
|
285
284
|
AZIMUTH_DISTANCE_AREA = AZIMUTH | DISTANCE | AREA
|
|
@@ -300,7 +299,7 @@ class Caps(object):
|
|
|
300
299
|
_INVERSE3 = AZIMUTH | DISTANCE # for goedesicw only
|
|
301
300
|
|
|
302
301
|
_OUT_ALL = ALL # see geographiclib.geodesiccapabilities.py
|
|
303
|
-
_OUT_MASK = ALL | LONG_UNROLL | REVERSE2 | _DEBUG_ALL
|
|
302
|
+
_OUT_MASK = ALL | LONG_UNROLL | NONFINITONAN | REVERSE2 | _DEBUG_ALL
|
|
304
303
|
|
|
305
304
|
_AZIMUTH_LATITUDE_LONGITUDE = AZIMUTH | LATITUDE | LONGITUDE
|
|
306
305
|
_AZIMUTH_LATITUDE_LONG_UNROLL = AZIMUTH | LATITUDE | LONG_UNROLL
|
|
@@ -366,7 +365,7 @@ class _CapsBase(_NamedBase): # in .auxilats, .geodesicx.gxbases
|
|
|
366
365
|
_caps = 0 # None
|
|
367
366
|
_debug = 0 # or Caps._DEBUG_...
|
|
368
367
|
|
|
369
|
-
@
|
|
368
|
+
@property_RO
|
|
370
369
|
def caps(self):
|
|
371
370
|
'''Get the capabilities (bit-or'ed C{Caps}).
|
|
372
371
|
'''
|
|
@@ -455,13 +454,16 @@ class GDict(ADict): # XXX _NamedDict
|
|
|
455
454
|
'''
|
|
456
455
|
return self._toTuple(Inverse10Tuple, dflt)
|
|
457
456
|
|
|
458
|
-
def _toNAN(self, outmask): # .GeodesicExact._GDistInverse, .GeodesicLineExact._GenPosition
|
|
457
|
+
def _toNAN(self, outmask, **specs): # .GeodesicExact._GDistInverse, .GeodesicLineExact._GenPosition
|
|
459
458
|
'''(INTERNAL) Convert this C{GDict} to all C{NAN}s.
|
|
460
459
|
'''
|
|
461
460
|
if (outmask & Caps.NONFINITONAN):
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
461
|
+
def _t2(k):
|
|
462
|
+
return k, specs.get(k, NAN)
|
|
463
|
+
|
|
464
|
+
d = dict(_t2(k) for k, C in _key2Caps.items()
|
|
465
|
+
if (outmask & C) == C)
|
|
466
|
+
self.set_(**d) # self.update(d)
|
|
465
467
|
return self
|
|
466
468
|
|
|
467
469
|
@deprecated_method
|
|
@@ -721,12 +723,11 @@ def _around(x): # in .utily.sincos2d
|
|
|
721
723
|
try:
|
|
722
724
|
return _wrapped.Math.AngRound(x)
|
|
723
725
|
except AttributeError:
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
x = _0_0 # -0 to 0
|
|
726
|
+
b, a = _1_16th, fabs(x)
|
|
727
|
+
if a < b:
|
|
728
|
+
a -= b
|
|
729
|
+
a += b
|
|
730
|
+
x = _copysign(a, x)
|
|
730
731
|
return x
|
|
731
732
|
|
|
732
733
|
|