pygeodesy 24.6.9__py2.py3-none-any.whl → 24.7.7__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-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/METADATA +2 -2
- PyGeodesy-24.7.7.dist-info/RECORD +117 -0
- pygeodesy/__init__.py +39 -32
- pygeodesy/__main__.py +6 -1
- pygeodesy/albers.py +2 -2
- pygeodesy/auxilats/__init__.py +1 -1
- pygeodesy/auxilats/auxAngle.py +40 -39
- pygeodesy/auxilats/auxDLat.py +3 -2
- pygeodesy/auxilats/auxLat.py +16 -18
- pygeodesy/auxilats/auxily.py +1 -1
- pygeodesy/azimuthal.py +10 -10
- pygeodesy/basics.py +16 -4
- pygeodesy/booleans.py +4 -4
- pygeodesy/cartesianBase.py +11 -14
- pygeodesy/css.py +14 -18
- pygeodesy/datums.py +6 -6
- pygeodesy/deprecated/__init__.py +1 -1
- pygeodesy/deprecated/classes.py +25 -4
- pygeodesy/deprecated/datum.py +3 -3
- pygeodesy/deprecated/functions.py +6 -8
- pygeodesy/dms.py +23 -27
- pygeodesy/ecef.py +4 -4
- pygeodesy/elevations.py +4 -4
- pygeodesy/ellipsoidalBase.py +23 -28
- pygeodesy/ellipsoidalBaseDI.py +19 -23
- pygeodesy/ellipsoidalExact.py +3 -3
- pygeodesy/ellipsoidalGeodSolve.py +15 -23
- pygeodesy/ellipsoidalKarney.py +37 -60
- pygeodesy/ellipsoidalNvector.py +38 -44
- pygeodesy/ellipsoidalVincenty.py +11 -14
- pygeodesy/ellipsoids.py +107 -101
- pygeodesy/errors.py +109 -48
- pygeodesy/etm.py +32 -44
- pygeodesy/formy.py +55 -58
- pygeodesy/frechet.py +18 -20
- pygeodesy/fsums.py +3 -3
- pygeodesy/gars.py +3 -4
- pygeodesy/geodesici.py +1696 -0
- pygeodesy/geodesicw.py +15 -15
- pygeodesy/geodesicx/__init__.py +4 -4
- pygeodesy/geodesicx/gx.py +34 -55
- pygeodesy/geodesicx/gxbases.py +20 -8
- pygeodesy/geodesicx/gxline.py +93 -88
- pygeodesy/geodsolve.py +108 -59
- pygeodesy/geohash.py +26 -34
- pygeodesy/geoids.py +28 -37
- pygeodesy/hausdorff.py +17 -18
- pygeodesy/heights.py +2 -2
- pygeodesy/internals.py +46 -13
- pygeodesy/interns.py +2 -2
- pygeodesy/karney.py +78 -15
- pygeodesy/ktm.py +13 -16
- pygeodesy/latlonBase.py +17 -19
- pygeodesy/lazily.py +28 -25
- pygeodesy/lcc.py +28 -31
- pygeodesy/ltp.py +7 -8
- pygeodesy/ltpTuples.py +71 -73
- pygeodesy/mgrs.py +8 -9
- pygeodesy/named.py +19 -10
- pygeodesy/nvectorBase.py +9 -10
- pygeodesy/osgr.py +9 -9
- pygeodesy/points.py +6 -6
- pygeodesy/rhumb/__init__.py +1 -1
- pygeodesy/rhumb/aux_.py +5 -5
- pygeodesy/rhumb/bases.py +30 -31
- pygeodesy/rhumb/ekx.py +3 -4
- pygeodesy/rhumb/solve.py +21 -22
- pygeodesy/solveBase.py +177 -123
- pygeodesy/sphericalBase.py +10 -11
- pygeodesy/sphericalNvector.py +13 -13
- pygeodesy/sphericalTrigonometry.py +86 -97
- pygeodesy/streprs.py +4 -34
- pygeodesy/triaxials.py +48 -43
- pygeodesy/units.py +208 -275
- pygeodesy/unitsBase.py +115 -107
- pygeodesy/ups.py +26 -31
- pygeodesy/utily.py +8 -8
- pygeodesy/utm.py +35 -40
- pygeodesy/utmups.py +43 -46
- pygeodesy/utmupsBase.py +8 -9
- pygeodesy/vector3d.py +26 -27
- pygeodesy/vector3dBase.py +6 -7
- pygeodesy/webmercator.py +19 -21
- pygeodesy/wgrs.py +18 -20
- PyGeodesy-24.6.9.dist-info/RECORD +0 -116
- {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.6.9.dist-info → PyGeodesy-24.7.7.dist-info}/top_level.txt +0 -0
pygeodesy/geodesicx/gxline.py
CHANGED
|
@@ -37,30 +37,28 @@ from __future__ import division as _; del _ # PYCHOK semicolon
|
|
|
37
37
|
# - s and c prefixes mean sin and cos
|
|
38
38
|
|
|
39
39
|
# from pygeodesy.basics import _xinstanceof # _MODS
|
|
40
|
-
from pygeodesy.constants import NAN,
|
|
41
|
-
|
|
42
|
-
from pygeodesy.errors import _xError,
|
|
40
|
+
from pygeodesy.constants import NAN, _EPSqrt as _TOL, _0_0, _1_0, \
|
|
41
|
+
_180_0, _2__PI, _copysign_1_0, isfinite
|
|
42
|
+
from pygeodesy.errors import _xError, _xkwds_pop2
|
|
43
43
|
from pygeodesy.fsums import fsumf_, fsum1f_
|
|
44
44
|
from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
|
|
45
|
-
_sincos12, _sin1cos2
|
|
45
|
+
_sincos12, _sin1cos2, \
|
|
46
|
+
_sinf1cos2d, _TINY
|
|
46
47
|
# from pygeodesy.geodesicw import _Intersecant2 # _MODS
|
|
47
|
-
# from pygeodesy.interns import _COMMASPACE_ # from .errors
|
|
48
48
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS
|
|
49
49
|
from pygeodesy.karney import _around, _atan2d, Caps, GDict, _fix90, \
|
|
50
|
-
_K_2_0, _norm2, _norm180,
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
_K_2_0, _llz2line, _norm2, _norm180, \
|
|
51
|
+
_sincos2, _sincos2d
|
|
52
|
+
from pygeodesy.named import Property_RO, _update_all
|
|
53
|
+
# from pygeodesy.props import Property_RO, _update_all # from .named
|
|
53
54
|
from pygeodesy.utily import atan2d as _atan2d_reverse, sincos2
|
|
54
55
|
|
|
55
56
|
from math import atan2, cos, degrees, fabs, floor, radians, sin
|
|
56
57
|
|
|
57
58
|
__all__ = ()
|
|
58
|
-
__version__ = '24.
|
|
59
|
+
__version__ = '24.07.09'
|
|
59
60
|
|
|
60
61
|
_glXs = [] # instances of C{[_]GeodesicLineExact} to be updated
|
|
61
|
-
# underflow guard, we require _TINY * EPS > 0, _TINY + EPS == EPS
|
|
62
|
-
_TINY = _EPSmin
|
|
63
|
-
# assert (_TINY * EPS) > 0 and (_TINY + EPS) == EPS
|
|
64
62
|
|
|
65
63
|
|
|
66
64
|
def _update_glXs(gX): # see GeodesicExact.C4order and -._ef_reset_k2
|
|
@@ -95,23 +93,18 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
95
93
|
# _somg1 = _comg1 = NAN
|
|
96
94
|
# _ssig1 = _csig1 = NAN
|
|
97
95
|
|
|
98
|
-
def __init__(self, gX, lat1, lon1, azi1, caps,
|
|
96
|
+
def __init__(self, gX, lat1, lon1, azi1, caps, **name_):
|
|
99
97
|
'''(INTERNAL) New C{[_]GeodesicLineExact} instance.
|
|
100
98
|
'''
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if salp1_calp1:
|
|
107
|
-
salp1, calp1 = salp1_calp1
|
|
108
|
-
else:
|
|
99
|
+
# _xGeodesicExact(gX=gX)
|
|
100
|
+
if azi1 is None: # see GeodesicExact.InverseLine
|
|
101
|
+
(salp1, calp1), name_ = _xkwds_pop2(name_, _s_calp1=(_0_0, _1_0))
|
|
102
|
+
azi1 = _atan2d(salp1, calp1)
|
|
103
|
+
else: # guard against salp0 underflow, convert -0 to +0
|
|
109
104
|
azi1 = _norm180(azi1)
|
|
110
|
-
# guard against salp0 underflow,
|
|
111
|
-
# also -0 is converted to +0
|
|
112
105
|
salp1, calp1 = _sincos2d(_around(azi1))
|
|
113
|
-
if
|
|
114
|
-
self.name =
|
|
106
|
+
if name_:
|
|
107
|
+
self.name = name_
|
|
115
108
|
|
|
116
109
|
self._gX = gX # GeodesicExact only
|
|
117
110
|
self._lat1 = lat1 = _fix90(lat1)
|
|
@@ -120,9 +113,9 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
120
113
|
self._salp1 = salp1
|
|
121
114
|
self._calp1 = calp1
|
|
122
115
|
# allow lat, azimuth and unrolling of lon
|
|
123
|
-
self._caps = caps |
|
|
116
|
+
self._caps = caps | Caps._LINE
|
|
124
117
|
|
|
125
|
-
sbet1, cbet1 =
|
|
118
|
+
sbet1, cbet1 = _sinf1cos2d(_around(lat1), gX.f1)
|
|
126
119
|
self._dn1 = gX._dn(sbet1, cbet1)
|
|
127
120
|
# Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0), with alp0
|
|
128
121
|
# in [0, pi/2 - |bet1|]. Alt: calp0 = hypot(sbet1, calp1 * cbet1),
|
|
@@ -145,11 +138,11 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
145
138
|
self._ssig1, self._csig1 = _norm2(sbet1, c) # sig1 in (-pi, pi]
|
|
146
139
|
# _norm2(somg1, comg1) # no need to normalize!
|
|
147
140
|
# _norm2(schi1?, cchi1) # no need to normalize!
|
|
148
|
-
if not (caps &
|
|
141
|
+
if not (caps & Caps.LINE_OFF):
|
|
149
142
|
_glXs.append(self)
|
|
150
143
|
# no need to pre-compute other attrs based on _Caps.X. All are
|
|
151
|
-
# Property_RO's, computed once and cached/memoized until reset
|
|
152
|
-
#
|
|
144
|
+
# Property_RO's, computed once and cached/memoized until reset when
|
|
145
|
+
# arc, distance, C4order is changed or Elliptic function is reset.
|
|
153
146
|
|
|
154
147
|
def __del__(self): # XXX use weakref?
|
|
155
148
|
if _glXs: # may be empty or None
|
|
@@ -298,22 +291,18 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
298
291
|
C{lon1}, C{azi1} and arc length C{a12} always included,
|
|
299
292
|
except when C{a12=NAN}.
|
|
300
293
|
'''
|
|
301
|
-
|
|
302
|
-
r = GDict(a12=NAN, s12=NAN) # note both a12 and s12, always
|
|
303
|
-
if not (arcmode or self._caps_DISTANCE_IN): # PYCHOK no cover
|
|
304
|
-
return r # Uninitialized or impossible distance requested
|
|
305
|
-
|
|
306
294
|
Cs = Caps
|
|
307
|
-
if
|
|
308
|
-
outmask
|
|
309
|
-
outmask &= self._caps & Cs._OUT_MASK
|
|
310
|
-
|
|
295
|
+
if outmask:
|
|
296
|
+
outmask &= self._caps & Cs._OUT_MASK
|
|
311
297
|
eF = self._eF
|
|
312
298
|
gX = self.geodesic # ._gX
|
|
299
|
+
r = GDict(a12=NAN, s12=NAN) # both a12 and s12, always
|
|
313
300
|
|
|
314
|
-
if
|
|
315
|
-
#
|
|
316
|
-
|
|
301
|
+
if not isfinite(s12_a12):
|
|
302
|
+
# E2 = sig12 = ssig12 = csig12 = NAN
|
|
303
|
+
return r._toNAN(outmask)
|
|
304
|
+
elif arcmode: # s12_a12 is (spherical) arc length
|
|
305
|
+
r.set_(a12=s12_a12)
|
|
317
306
|
sig12 = radians(s12_a12)
|
|
318
307
|
if _K_2_0:
|
|
319
308
|
ssig12, csig12 = sincos2(sig12) # utily, no NEG0
|
|
@@ -322,31 +311,25 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
322
311
|
a -= floor(a / _180_0) * _180_0 # 0 <= 0 < 180
|
|
323
312
|
ssig12 = _0_0 if a == 0 else sin(sig12)
|
|
324
313
|
csig12 = _0_0 if a == 90 else cos(sig12)
|
|
325
|
-
|
|
314
|
+
E2 = _0_0
|
|
315
|
+
elif self._caps_DISTANCE_IN: # s12_a12 is distance
|
|
326
316
|
t = s12_a12 / self._E0b
|
|
327
317
|
s, c = _sincos2(t) # tau12
|
|
328
318
|
# tau2 = tau1 + tau12
|
|
329
319
|
E2 = -eF.deltaEinv(*_sincos12(-s, c, *self._stau1_ctau1))
|
|
330
320
|
sig12 = fsum1f_(self._E1, -E2, t) # == t - (E2 - E1)
|
|
331
321
|
ssig12, csig12 = _sincos2(sig12)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
322
|
+
r.set_(a12=degrees(sig12))
|
|
323
|
+
else: # uninitialized or impossible distance requested
|
|
324
|
+
return r
|
|
335
325
|
|
|
336
326
|
# sig2 = sig1 + sig12
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
# cbet2 = hypot(salp0, calp0 * csig2). Alt:
|
|
341
|
-
# cbet2 = hypot(csig2, salp0 * ssig2)
|
|
342
|
-
sbet2, cbet2 = _sin1cos2(calp0, salp0, csig2, ssig2)
|
|
343
|
-
if cbet2 == 0: # salp0 = 0, csig2 = 0, break degeneracy
|
|
344
|
-
cbet2 = csig2 = _TINY
|
|
345
|
-
# tan(alp0) = cos(sig2) * tan(alp2)
|
|
346
|
-
salp2 = salp0
|
|
347
|
-
calp2 = calp0 * csig2 # no need to normalize
|
|
327
|
+
ssig1, csig1 = self._ssig1, self._csig1
|
|
328
|
+
ssig2, csig2 = t = _sincos12(-ssig12, csig12, ssig1, csig1)
|
|
329
|
+
dn2 = eF.fDelta(*t)
|
|
348
330
|
|
|
349
|
-
if (outmask &
|
|
331
|
+
if (outmask & Cs.DISTANCE):
|
|
332
|
+
outmask ^= Cs.DISTANCE
|
|
350
333
|
if arcmode: # or f_0_01
|
|
351
334
|
E2 = eF.deltaE(ssig2, csig2, dn2)
|
|
352
335
|
# AB1 = _E0 * (E2 - _E1)
|
|
@@ -358,10 +341,34 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
358
341
|
s12 = s12_a12
|
|
359
342
|
r.set_(s12=s12)
|
|
360
343
|
|
|
344
|
+
if not outmask: # all done, see ._GenSet
|
|
345
|
+
return r
|
|
346
|
+
|
|
347
|
+
if self._debug: # PYCHOK no cover
|
|
348
|
+
outmask |= self._debug & Cs._DEBUG_DIRECT_LINE
|
|
349
|
+
|
|
361
350
|
if (outmask & Cs._DEBUG_DIRECT_LINE): # PYCHOK no cover
|
|
362
351
|
r.set_(sig12=sig12, dn2=dn2, b=gX.b, e2=gX.e2, f1=gX.f1,
|
|
363
352
|
E0b=self._E0b, E1=self._E1, E2=E2, eFk2=eF.k2, eFa2=eF.alpha2)
|
|
364
353
|
|
|
354
|
+
# sin(bet2) = cos(alp0) * sin(sig2) and
|
|
355
|
+
# cbet2 = hypot(salp0, calp0 * csig2). Alt:
|
|
356
|
+
# cbet2 = hypot(csig2, salp0 * ssig2)
|
|
357
|
+
salp0, calp0 = self._salp0, self._calp0
|
|
358
|
+
sbet2, cbet2 = _sin1cos2(calp0, salp0, csig2, ssig2)
|
|
359
|
+
if cbet2 == 0: # salp0 = 0, csig2 = 0, break degeneracy
|
|
360
|
+
cbet2 = csig2 = _TINY
|
|
361
|
+
# tan(alp0) = cos(sig2) * tan(alp2)
|
|
362
|
+
salp2 = salp0
|
|
363
|
+
calp2 = calp0 * csig2 # no need to normalize
|
|
364
|
+
|
|
365
|
+
if (outmask & Cs.AZIMUTH):
|
|
366
|
+
r.set_(azi2=_atan2d_reverse(salp2, calp2,
|
|
367
|
+
reverse=outmask & Cs.REVERSE2))
|
|
368
|
+
|
|
369
|
+
if (outmask & Cs.LATITUDE):
|
|
370
|
+
r.set_(lat2=_atan2d(sbet2, gX.f1 * cbet2))
|
|
371
|
+
|
|
365
372
|
if (outmask & Cs.LONGITUDE):
|
|
366
373
|
schi1 = self._somg1
|
|
367
374
|
cchi1 = self._cchi1
|
|
@@ -375,7 +382,7 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
375
382
|
tchi2 = t * schi2
|
|
376
383
|
chi12 = t * fsum1f_(_a(ssig1, csig1), -_a(ssig2, csig2),
|
|
377
384
|
_a(tchi2, cchi2), -_a(tchi1, cchi1), sig12)
|
|
378
|
-
lon2
|
|
385
|
+
lon2 = self.lon1 + degrees(chi12 - lam12)
|
|
379
386
|
else:
|
|
380
387
|
chi12 = atan2(*_sincos12(schi1, cchi1, schi2, cchi2))
|
|
381
388
|
lon2 = _norm180(self._lon1_norm180 + _norm180(degrees(chi12 - lam12)))
|
|
@@ -384,12 +391,6 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
384
391
|
r.set_(ssig2=ssig2, chi12=chi12, H0e2_f1=self._H0e2_f1,
|
|
385
392
|
csig2=csig2, lam12=lam12, H1=self._H1)
|
|
386
393
|
|
|
387
|
-
if (outmask & Cs.LATITUDE):
|
|
388
|
-
r.set_(lat2=_atan2d(sbet2, gX.f1 * cbet2))
|
|
389
|
-
|
|
390
|
-
if (outmask & Cs.AZIMUTH):
|
|
391
|
-
r.set_(azi2=_atan2d_reverse(salp2, calp2, reverse=outmask & Cs.REVERSE2))
|
|
392
|
-
|
|
393
394
|
if (outmask & Cs._REDUCEDLENGTH_GEODESICSCALE):
|
|
394
395
|
dn1 = self._dn1
|
|
395
396
|
J12 = self._D0k2 * fsumf_(eF.deltaD(ssig2, csig2, dn2), -self._D1, sig12)
|
|
@@ -441,10 +442,9 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
441
442
|
S12 += gX.c2 * atan2(salp12, calp12)
|
|
442
443
|
r.set_(S12=S12)
|
|
443
444
|
|
|
444
|
-
r.set_(
|
|
445
|
+
r.set_(azi1=_norm180(self.azi1),
|
|
445
446
|
lat1=self.lat1, # == _fix90(lat1)
|
|
446
|
-
lon1=self.lon1 if (outmask & Cs.LONG_UNROLL) else self._lon1_norm180
|
|
447
|
-
azi1=_norm180(self.azi1))
|
|
447
|
+
lon1=self.lon1 if (outmask & Cs.LONG_UNROLL) else self._lon1_norm180)
|
|
448
448
|
return r
|
|
449
449
|
|
|
450
450
|
def _GenPosition(self, arcmode, s12_a12, outmask):
|
|
@@ -456,14 +456,24 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
456
456
|
r = self._GDictPosition(arcmode, s12_a12, outmask)
|
|
457
457
|
return r.toDirect9Tuple()
|
|
458
458
|
|
|
459
|
-
def _GenSet(self,
|
|
459
|
+
def _GenSet(self, debug, s12=None, a12=None, **llz2):
|
|
460
460
|
'''(INTERNAL) Aka C++ C{GenSetDistance}.
|
|
461
461
|
'''
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
462
|
+
Cs = Caps
|
|
463
|
+
if debug: # PYCHOK no cover
|
|
464
|
+
self._debug |= debug & Cs._DEBUG_ALL
|
|
465
|
+
# _CapsBase.debug._update(self)
|
|
466
|
+
if s12 is None:
|
|
467
|
+
if a12 is None: # see GeodesicExact.Line
|
|
468
|
+
return self
|
|
469
|
+
s12 = self._GDictPosition(True, a12, outmask=Cs.DISTANCE).s12 if a12 else _0_0
|
|
470
|
+
elif a12 is None:
|
|
471
|
+
a12 = self._GDictPosition(False, s12, 0).a12 if s12 else _0_0
|
|
472
|
+
self._s13 = s12
|
|
473
|
+
self._a13 = a12
|
|
474
|
+
self._caps |= Cs.DISTANCE | Cs.DISTANCE_IN
|
|
475
|
+
# _update_all(self) # new, from GeodesicExact.*Line
|
|
476
|
+
return _llz2line(self, **llz2)
|
|
467
477
|
|
|
468
478
|
@Property_RO
|
|
469
479
|
def geodesic(self):
|
|
@@ -597,8 +607,7 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
597
607
|
the reference point or C{NAN}.
|
|
598
608
|
'''
|
|
599
609
|
if self._a13 != a13:
|
|
600
|
-
self.
|
|
601
|
-
self._s13 = self._GDictPosition(True, a13, Caps.DISTANCE).s12 # if a13 else _0_0
|
|
610
|
+
self._GenSet(0, a12=a13)
|
|
602
611
|
_update_all(self)
|
|
603
612
|
return self._s13
|
|
604
613
|
|
|
@@ -611,10 +620,9 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
611
620
|
and the reference point or C{NAN}.
|
|
612
621
|
'''
|
|
613
622
|
if self._s13 != s13:
|
|
614
|
-
self.
|
|
615
|
-
self._a13 = self._GDictPosition(False, s13, 0).a12 if s13 else _0_0
|
|
623
|
+
self._GenSet(0, s12=s13)
|
|
616
624
|
_update_all(self)
|
|
617
|
-
return self._a13
|
|
625
|
+
return self._a13
|
|
618
626
|
|
|
619
627
|
@Property_RO
|
|
620
628
|
def _stau1_ctau1(self):
|
|
@@ -626,20 +634,17 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
626
634
|
# unnecessary because Einv inverts E
|
|
627
635
|
# return -self._eF.deltaEinv(stau1, ctau1)
|
|
628
636
|
|
|
629
|
-
def toStr(self,
|
|
637
|
+
def toStr(self, **prec_sep_name): # PYCHOK signature
|
|
630
638
|
'''Return this C{GeodesicLineExact} as string.
|
|
631
639
|
|
|
632
|
-
@
|
|
633
|
-
|
|
634
|
-
of 1 and above, but kept for negative B{C{prec}} values.
|
|
635
|
-
@kwarg sep: Separator to join (C{str}).
|
|
640
|
+
@see: L{Ellipsoid.toStr<pygeodesy.ellipsoids.Ellipsoid.toStr>}
|
|
641
|
+
for further details.
|
|
636
642
|
|
|
637
643
|
@return: C{GeodesicLineExact} (C{str}).
|
|
638
644
|
'''
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
return sep.join(_MODS.streprs.pairs(d, prec=prec))
|
|
645
|
+
C = _GeodesicLineExact
|
|
646
|
+
t = C.lat1, C.lon1, C.azi1, C.a13, C.s13, C.caps, C.geodesic
|
|
647
|
+
return self._instr(props=t, **prec_sep_name)
|
|
643
648
|
|
|
644
649
|
|
|
645
650
|
__all__ += _ALL_DOCS(_GeodesicLineExact)
|
pygeodesy/geodsolve.py
CHANGED
|
@@ -10,46 +10,31 @@ of the C{GeodSolve} executable.
|
|
|
10
10
|
'''
|
|
11
11
|
|
|
12
12
|
from pygeodesy.basics import _xinstanceof
|
|
13
|
+
# from pygeodesy.constants import NAN, _0_0 # from .karney
|
|
13
14
|
# from pygeodesy.geodesicx import GeodesicAreaExact # _MODS
|
|
14
|
-
from pygeodesy.interns import NN,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
from pygeodesy.interns import _UNUSED_, _not_ # PYCHOK used!
|
|
18
|
-
from pygeodesy.karney import _Azi, Caps, _Deg, GeodesicError, _GTuple, \
|
|
19
|
-
_Pass, _Lat, _Lon, _M, _M2, _sincos2d
|
|
15
|
+
from pygeodesy.interns import NN, _UNDER_
|
|
16
|
+
from pygeodesy.karney import Caps, GeodesicError, GeodSolve12Tuple, \
|
|
17
|
+
_llz2line, _sincos2d, _0_0, NAN
|
|
20
18
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, \
|
|
21
19
|
_getenv, _PYGEODESY_GEODSOLVE_
|
|
22
20
|
from pygeodesy.named import _name1__
|
|
23
21
|
from pygeodesy.namedTuples import Destination3Tuple, Distance3Tuple
|
|
24
|
-
from pygeodesy.props import Property, Property_RO
|
|
25
|
-
from pygeodesy.solveBase import
|
|
22
|
+
from pygeodesy.props import Property, Property_RO, property_RO
|
|
23
|
+
from pygeodesy.solveBase import _SolveGDictBase, _SolveGDictLineBase
|
|
26
24
|
from pygeodesy.utily import _unrollon, _Wrap, wrap360
|
|
27
25
|
|
|
28
26
|
__all__ = _ALL_LAZY.geodsolve
|
|
29
|
-
__version__ = '24.
|
|
27
|
+
__version__ = '24.07.09'
|
|
30
28
|
|
|
31
29
|
|
|
32
|
-
class
|
|
33
|
-
'''12-Tuple C{(lat1, lon1, azi1, lat2, lon2, azi2, s12, a12, m12, M12, M21, S12)} with
|
|
34
|
-
angles C{lat1}, C{lon1}, C{azi1}, C{lat2}, C{lon2} and C{azi2} and arc C{a12} all in
|
|
35
|
-
C{degrees}, initial C{azi1} and final C{azi2} forward azimuths, distance C{s12} and
|
|
36
|
-
reduced length C{m12} in C{meter}, area C{S12} in C{meter} I{squared} and geodesic
|
|
37
|
-
scale factors C{M12} and C{M21}, both C{scalar}, see U{GeodSolve
|
|
38
|
-
<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>}.
|
|
39
|
-
'''
|
|
40
|
-
# from GeodSolve --help option -f ... lat1 lon1 azi1 lat2 lon2 azi2 s12 a12 m12 M12 M21 S12
|
|
41
|
-
_Names_ = (_lat1_, _lon1_, _azi1_, _lat2_, _lon2_, _azi2_, _s12_, _a12_, _m12_, _M12_, _M21_, _S12_)
|
|
42
|
-
_Units_ = (_Lat, _Lon, _Azi, _Lat, _Lon, _Azi, _M, _Deg, _Pass, _Pass, _Pass, _M2)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class _GeodesicSolveBase(_SolveBase):
|
|
30
|
+
class _GeodesicSolveBase(_SolveGDictBase):
|
|
46
31
|
'''(INTERNAL) Base class for L{GeodesicSolve} and L{GeodesicLineSolve}.
|
|
47
32
|
'''
|
|
48
33
|
_Error = GeodesicError
|
|
49
34
|
_Names_Direct = \
|
|
50
35
|
_Names_Inverse = GeodSolve12Tuple._Names_
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
_Xable_name = 'GeodSolve'
|
|
37
|
+
_Xable_path = _getenv(_PYGEODESY_GEODSOLVE_, _PYGEODESY_GEODSOLVE_)
|
|
53
38
|
|
|
54
39
|
@Property_RO
|
|
55
40
|
def _b_option(self):
|
|
@@ -65,16 +50,12 @@ class _GeodesicSolveBase(_SolveBase):
|
|
|
65
50
|
self._p_option +
|
|
66
51
|
self._u_option)
|
|
67
52
|
|
|
68
|
-
@Property_RO
|
|
69
|
-
def _E_option(self):
|
|
70
|
-
return ('-E',) if self.Exact else ()
|
|
71
|
-
|
|
72
53
|
@Property
|
|
73
54
|
def GeodSolve(self):
|
|
74
55
|
'''Get the U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>}
|
|
75
56
|
executable (C{filename}).
|
|
76
57
|
'''
|
|
77
|
-
return self.
|
|
58
|
+
return self._Xable_path
|
|
78
59
|
|
|
79
60
|
@GeodSolve.setter # PYCHOK setter!
|
|
80
61
|
def GeodSolve(self, path):
|
|
@@ -84,20 +65,20 @@ class _GeodesicSolveBase(_SolveBase):
|
|
|
84
65
|
@raise GeodesicError: Invalid B{C{path}}, B{C{path}} doesn't exist or
|
|
85
66
|
isn't the C{GeodSolve} executable.
|
|
86
67
|
'''
|
|
87
|
-
self.
|
|
68
|
+
self._setXable(path)
|
|
88
69
|
|
|
89
70
|
def toStr(self, **prec_sep): # PYCHOK signature
|
|
90
71
|
'''Return this C{GeodesicSolve} as string.
|
|
91
72
|
|
|
92
|
-
@kwarg prec_sep: Keyword argumens C{B{prec}=6} and C{B{sep}=
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
73
|
+
@kwarg prec_sep: Keyword argumens C{B{prec}=6} and C{B{sep}=", "}
|
|
74
|
+
for the C{float} C{prec}ision, number of decimal digits
|
|
75
|
+
(0..9) and the C{sep}arator string to join. Trailing
|
|
76
|
+
zero decimals are stripped for B{C{prec}} values of 1
|
|
77
|
+
and above, but kept for negative B{C{prec}} values.
|
|
97
78
|
|
|
98
79
|
@return: GeodesicSolve items (C{str}).
|
|
99
80
|
'''
|
|
100
|
-
return
|
|
81
|
+
return _SolveGDictBase._toStr(self, GeodSolve=self.GeodSolve, **prec_sep)
|
|
101
82
|
|
|
102
83
|
@Property_RO
|
|
103
84
|
def _u_option(self):
|
|
@@ -117,11 +98,11 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
117
98
|
'''
|
|
118
99
|
|
|
119
100
|
def Area(self, polyline=False, **name):
|
|
120
|
-
'''Set up a L{GeodesicAreaExact} to compute area and
|
|
121
|
-
|
|
101
|
+
'''Set up a L{GeodesicAreaExact} to compute area and perimeter
|
|
102
|
+
of a polygon.
|
|
122
103
|
|
|
123
|
-
@kwarg polyline: If C{True} perimeter only, otherwise
|
|
124
|
-
|
|
104
|
+
@kwarg polyline: If C{True} perimeter only, otherwise area
|
|
105
|
+
and perimeter (C{bool}).
|
|
125
106
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
126
107
|
|
|
127
108
|
@return: A L{GeodesicAreaExact} instance.
|
|
@@ -137,8 +118,8 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
137
118
|
Polygon = Area # for C{geographiclib} compatibility
|
|
138
119
|
|
|
139
120
|
def Direct3(self, lat1, lon1, azi1, s12): # PYCHOK outmask
|
|
140
|
-
'''Return the destination lat, lon and reverse azimuth
|
|
141
|
-
|
|
121
|
+
'''Return the destination lat, lon and reverse azimuth (final bearing)
|
|
122
|
+
in C{degrees}.
|
|
142
123
|
|
|
143
124
|
@return: L{Destination3Tuple}C{(lat, lon, final)}.
|
|
144
125
|
'''
|
|
@@ -222,11 +203,14 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
222
203
|
<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>} and
|
|
223
204
|
Python U{Geodesic.InverseLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
|
|
224
205
|
'''
|
|
225
|
-
r
|
|
226
|
-
|
|
206
|
+
r = self.Inverse(lat1, lon1, lat2, lon2)
|
|
207
|
+
gl = GeodesicLineSolve(self, lat1, lon1, r.azi1, **_name1__(caps_name, _or_nameof=self))
|
|
208
|
+
gl._a13 = r.a12 # gl.SetArc(r.a12)
|
|
209
|
+
gl._s13 = r.s12 # gl.SetDistance(r.s12)
|
|
210
|
+
return _llz2line(gl, lat2=lat2, lon2=lon2, azi2=r.azi2)
|
|
227
211
|
|
|
228
212
|
|
|
229
|
-
class GeodesicLineSolve(_GeodesicSolveBase,
|
|
213
|
+
class GeodesicLineSolve(_GeodesicSolveBase, _SolveGDictLineBase):
|
|
230
214
|
'''Wrapper to invoke I{Karney}'s U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>}
|
|
231
215
|
as an C{Exact} version of I{Karney}'s Python class U{GeodesicLine<https://GeographicLib.SourceForge.io/C++/doc/
|
|
232
216
|
python/code.html#geographiclib.geodesicline.GeodesicLine>}.
|
|
@@ -237,6 +221,8 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
|
|
|
237
221
|
@note: This C{geodesic} is intended I{for testing purposes only}, it invokes the C{GeodSolve}
|
|
238
222
|
executable for I{every} method call.
|
|
239
223
|
'''
|
|
224
|
+
_a13 = \
|
|
225
|
+
_s13 = NAN # see GeodesicSolve._InverseLine
|
|
240
226
|
|
|
241
227
|
def __init__(self, geodesic, lat1, lon1, azi1, caps=Caps.ALL, **name):
|
|
242
228
|
'''New L{GeodesicLineSolve} instance, allowing points to be found along
|
|
@@ -262,13 +248,28 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
|
|
|
262
248
|
_xinstanceof(GeodesicSolve, geodesic=geodesic)
|
|
263
249
|
if (caps & Caps.LINE_OFF): # copy to avoid updates
|
|
264
250
|
geodesic = geodesic.copy(deep=False, name=_UNDER_(NN, geodesic.name)) # NOT _under!
|
|
265
|
-
|
|
251
|
+
_SolveGDictLineBase.__init__(self, geodesic, lat1, lon1, caps, azi1=azi1, **name)
|
|
266
252
|
try:
|
|
267
253
|
self.GeodSolve = geodesic.GeodSolve # geodesic or copy of geodesic
|
|
268
254
|
except GeodesicError:
|
|
269
255
|
pass
|
|
270
256
|
|
|
271
|
-
|
|
257
|
+
@Property_RO
|
|
258
|
+
def a13(self):
|
|
259
|
+
'''Get the arc length to reference point 3 (C{degrees}).
|
|
260
|
+
|
|
261
|
+
@see: Methods L{Arc} and L{SetArc}.
|
|
262
|
+
'''
|
|
263
|
+
return self._a13
|
|
264
|
+
|
|
265
|
+
def Arc(self):
|
|
266
|
+
'''Return the arc length to reference point 3 (C{degrees} or C{NAN}).
|
|
267
|
+
|
|
268
|
+
@see: Method L{SetArc} and property L{a13}.
|
|
269
|
+
'''
|
|
270
|
+
return self.a13
|
|
271
|
+
|
|
272
|
+
def ArcPosition(self, a12, outmask=Caps.STANDARD): # PYCHOK unused
|
|
272
273
|
'''Find the position on the line given B{C{a12}}.
|
|
273
274
|
|
|
274
275
|
@arg a12: Spherical arc length from the first point to the
|
|
@@ -277,7 +278,7 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
|
|
|
277
278
|
@return: A C{GDict} with 12 items C{lat1, lon1, azi1, lat2, lon2,
|
|
278
279
|
azi2, m12, a12, s12, M12, M21, S12}.
|
|
279
280
|
'''
|
|
280
|
-
return self._GDictInvoke(self._cmdArc,
|
|
281
|
+
return self._GDictInvoke(self._cmdArc, self._Names_Direct, a12)._unCaps(outmask)
|
|
281
282
|
|
|
282
283
|
@Property_RO
|
|
283
284
|
def azi1(self):
|
|
@@ -301,6 +302,17 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
|
|
|
301
302
|
'''
|
|
302
303
|
return self._cmdDistance + ('-a',)
|
|
303
304
|
|
|
305
|
+
def Distance(self):
|
|
306
|
+
'''Return the distance to reference point 3 (C{meter} or C{NAN}).
|
|
307
|
+
'''
|
|
308
|
+
return self.s13
|
|
309
|
+
|
|
310
|
+
@property_RO
|
|
311
|
+
def geodesic(self):
|
|
312
|
+
'''Get the geodesic (L{GeodesicSolve}).
|
|
313
|
+
'''
|
|
314
|
+
return self._solve # see .solveBase._SolveLineBase
|
|
315
|
+
|
|
304
316
|
def Intersecant2(self, lat0, lon0, radius, **kwds): # PYCHOK no cover
|
|
305
317
|
'''B{Not implemented}, throws a C{NotImplementedError} always.'''
|
|
306
318
|
self._notImplemented(lat0, lon0, radius, **kwds)
|
|
@@ -309,7 +321,7 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
|
|
|
309
321
|
'''B{Not implemented}, throws a C{NotImplementedError} always.'''
|
|
310
322
|
self._notImplemented(lat0, lon0, **kwds)
|
|
311
323
|
|
|
312
|
-
def Position(self, s12, outmask=
|
|
324
|
+
def Position(self, s12, outmask=Caps.STANDARD):
|
|
313
325
|
'''Find the position on the line given B{C{s12}}.
|
|
314
326
|
|
|
315
327
|
@arg s12: Distance from the first point to the second (C{meter}).
|
|
@@ -317,21 +329,58 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveLineBase):
|
|
|
317
329
|
@return: A C{GDict} with 12 items C{lat1, lon1, azi1, lat2, lon2,
|
|
318
330
|
azi2, m12, a12, s12, M12, M21, S12}, possibly C{a12=NAN}.
|
|
319
331
|
'''
|
|
320
|
-
return self._GDictInvoke(self._cmdDistance,
|
|
332
|
+
return self._GDictInvoke(self._cmdDistance, self._Names_Direct, s12)._unCaps(outmask)
|
|
333
|
+
|
|
334
|
+
@Property_RO
|
|
335
|
+
def s13(self):
|
|
336
|
+
'''Get the distance to reference point 3 (C{meter} or C{NAN}).
|
|
337
|
+
|
|
338
|
+
@see: Methods L{Distance} and L{SetDistance}.
|
|
339
|
+
'''
|
|
340
|
+
return self._s13
|
|
341
|
+
|
|
342
|
+
def SetArc(self, a13):
|
|
343
|
+
'''Set reference point 3 in terms relative to the first point.
|
|
344
|
+
|
|
345
|
+
@arg a13: Spherical arc length from the first to the reference
|
|
346
|
+
point (C{degrees}).
|
|
347
|
+
|
|
348
|
+
@return: The distance C{s13} (C{meter}) between the first and
|
|
349
|
+
the reference point or C{NAN}.
|
|
350
|
+
'''
|
|
351
|
+
if self._a13 != a13:
|
|
352
|
+
self._a13 = a13
|
|
353
|
+
self._s13 = self.ArcPosition(a13, outmask=Caps.DISTANCE).s12 # if a13 else _0_0
|
|
354
|
+
# _update_all(self)
|
|
355
|
+
return self._s13
|
|
356
|
+
|
|
357
|
+
def SetDistance(self, s13):
|
|
358
|
+
'''Set reference point 3 in terms relative to the first point.
|
|
359
|
+
|
|
360
|
+
@arg s13: Distance from the first to the reference point (C{meter}).
|
|
361
|
+
|
|
362
|
+
@return: The arc length C{a13} (C{degrees}) between the first
|
|
363
|
+
and the reference point or C{NAN}.
|
|
364
|
+
'''
|
|
365
|
+
if self._s13 != s13:
|
|
366
|
+
self._s13 = s13
|
|
367
|
+
self._a13 = self.Position(s13, outmask=Caps.DISTANCE).a12 if s13 else _0_0
|
|
368
|
+
# _update_all(self)
|
|
369
|
+
return self._a13 # NAN for GeodesicLineExact without Cap.DISTANCE_IN
|
|
321
370
|
|
|
322
371
|
def toStr(self, **prec_sep): # PYCHOK signature
|
|
323
372
|
'''Return this C{GeodesicLineSolve} as string.
|
|
324
373
|
|
|
325
|
-
@kwarg prec_sep: Keyword argumens C{B{prec}=6} and C{B{sep}=
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
374
|
+
@kwarg prec_sep: Keyword argumens C{B{prec}=6} and C{B{sep}=", "}
|
|
375
|
+
for the C{float} C{prec}ision, number of decimal digits
|
|
376
|
+
(0..9) and the C{sep}arator string to join. Trailing
|
|
377
|
+
zero decimals are stripped for B{C{prec}} values of 1
|
|
378
|
+
and above, but kept for negative B{C{prec}} values.
|
|
330
379
|
|
|
331
380
|
@return: GeodesicLineSolve items (C{str}).
|
|
332
381
|
'''
|
|
333
|
-
return
|
|
334
|
-
|
|
382
|
+
return _SolveGDictLineBase._toStr(self, azi1=self.azi1, geodesic=self._solve,
|
|
383
|
+
GeodSolve=self.GeodSolve, **prec_sep)
|
|
335
384
|
|
|
336
385
|
|
|
337
386
|
__all__ += _ALL_DOCS(_GeodesicSolveBase)
|
|
@@ -345,7 +394,7 @@ if __name__ == '__main__':
|
|
|
345
394
|
gS.verbose = '--verbose' in argv # or '-v' in argv
|
|
346
395
|
|
|
347
396
|
if gS.GeodSolve in (_PYGEODESY_GEODSOLVE_, None): # not set
|
|
348
|
-
gS.GeodSolve = '/opt/local/bin/GeodSolve' # '/opt/local/Cellar/geographiclib/
|
|
397
|
+
gS.GeodSolve = '/opt/local/bin/GeodSolve' # '/opt/local/Cellar/geographiclib/2.3/bin/GeodSolve' # HomeBrew
|
|
349
398
|
printf('version: %s', gS.version)
|
|
350
399
|
|
|
351
400
|
r = gS.Direct(40.6, -73.8, 51, 5.5e6)
|