pygeodesy 25.4.25__py2.py3-none-any.whl → 25.5.5__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 +8 -6
- pygeodesy/basics.py +1 -1
- pygeodesy/booleans.py +7 -7
- pygeodesy/cartesianBase.py +6 -5
- pygeodesy/ecef.py +13 -23
- pygeodesy/ecefLocals.py +186 -0
- pygeodesy/ellipsoids.py +20 -27
- pygeodesy/fmath.py +21 -6
- pygeodesy/fsums.py +2 -2
- pygeodesy/latlonBase.py +8 -5
- pygeodesy/lazily.py +46 -22
- pygeodesy/ltp.py +50 -53
- pygeodesy/ltpTuples.py +34 -35
- pygeodesy/named.py +2 -147
- pygeodesy/resections.py +73 -71
- pygeodesy/utmupsBase.py +54 -32
- pygeodesy/vector2d.py +4 -4
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/METADATA +6 -5
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/RECORD +21 -20
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/WHEEL +0 -0
- {pygeodesy-25.4.25.dist-info → pygeodesy-25.5.5.dist-info}/top_level.txt +0 -0
pygeodesy/__init__.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
|
-
u'''A pure Python implementation of geodesy tools for various ellipsoidal and spherical earth
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
coordinates.
|
|
4
|
+
u'''A pure Python implementation of geodesy tools for various ellipsoidal and spherical earth models
|
|
5
|
+
using precision exact, elliptic, trigonometric, vector-based, iterative and approximate methods for
|
|
6
|
+
geodetic (lat-/longitude), geocentric (U{ECEF<https://WikiPedia.org/wiki/ECEF>} cartesian), local (U{LTP
|
|
7
|
+
<https://WikiPedia.org/wiki/Local_tangent_plane_coordinates>}) and certain U{triaxial ellipsoidal
|
|
8
|
+
<https://GeographicLib.SourceForge.io/1.44/triaxial.html>} coordinates.
|
|
9
9
|
|
|
10
10
|
Transcoded in part from U{JavaScript originals<https://GitHub.com/ChrisVeness/geodesy>} by I{Chris Veness (C)
|
|
11
11
|
2005-2024} and from several U{C++ classes<https://GeographicLib.SourceForge.io/C++/doc/annotated.html>} by I{Charles
|
|
@@ -406,6 +406,7 @@ if _init__all__ and not _lazy_import2: # import and set __all__
|
|
|
406
406
|
import pygeodesy.deprecated as deprecated # PYCHOK exported
|
|
407
407
|
import pygeodesy.dms as dms # PYCHOK exported
|
|
408
408
|
import pygeodesy.ecef as ecef # PYCHOK exported
|
|
409
|
+
import pygeodesy.ecefLocals as ecefLocals # PYCHOK exported
|
|
409
410
|
import pygeodesy.elevations as elevations # PYCHOK exported
|
|
410
411
|
import pygeodesy.ellipsoidalBase as ellipsoidalBase # PYCHOK INTERNAL
|
|
411
412
|
import pygeodesy.ellipsoidalBaseDI as ellipsoidalBaseDI # PYCHOK INTERNAL
|
|
@@ -491,6 +492,7 @@ if _init__all__ and not _lazy_import2: # import and set __all__
|
|
|
491
492
|
from pygeodesy.deprecated import * # PYCHOK __all__ DEPRECATED
|
|
492
493
|
from pygeodesy.dms import * # PYCHOK __all__
|
|
493
494
|
from pygeodesy.ecef import * # PYCHOK __all__
|
|
495
|
+
# from pygeodesy.ecefLocals import * # PYCHOK __all__
|
|
494
496
|
from pygeodesy.elevations import * # PYCHOK __all__
|
|
495
497
|
# from pygeodesy.ellipsoidalBase import * # PYCHOK __(_)__ INTERNAL
|
|
496
498
|
# from pygeodesy.ellipsoidalBaseDI import * # PYCHOK __(_)__ INTERNAL
|
|
@@ -602,7 +604,7 @@ else:
|
|
|
602
604
|
|
|
603
605
|
from pygeodesy.internals import _version2, _DOT_ # PYCHOK import
|
|
604
606
|
# from pygeodesy.interns import _DOT_ # from .internals
|
|
605
|
-
__version__ = '25.
|
|
607
|
+
__version__ = '25.05.05'
|
|
606
608
|
# see setup.py for similar logic
|
|
607
609
|
version = _DOT_(*_version2(__version__, n=3))
|
|
608
610
|
|
pygeodesy/basics.py
CHANGED
pygeodesy/booleans.py
CHANGED
|
@@ -22,7 +22,7 @@ from pygeodesy.basics import _isin, isodd, issubclassof, map2, \
|
|
|
22
22
|
from pygeodesy.constants import EPS, EPS2, INT0, _0_0, _0_5, _1_0
|
|
23
23
|
from pygeodesy.errors import ClipError, _IsnotError, _TypeError, \
|
|
24
24
|
_ValueError, _xattr, _xkwds_get, _xkwds_pop2
|
|
25
|
-
from pygeodesy.fmath import favg, fdot_, hypot, hypot2
|
|
25
|
+
from pygeodesy.fmath import favg, Fdot_, fdot_, hypot, hypot2
|
|
26
26
|
# from pygeodesy.fsums import fsum1 # _MODS
|
|
27
27
|
# from pygeodesy.internals import typename # from .basics
|
|
28
28
|
from pygeodesy.interns import NN, _BANG_, _clipid_, _COMMASPACE_, \
|
|
@@ -45,7 +45,7 @@ from pygeodesy.utily import fabs, _unrollon, _Wrap
|
|
|
45
45
|
# from math import fabs # from .utily
|
|
46
46
|
|
|
47
47
|
__all__ = _ALL_LAZY.booleans
|
|
48
|
-
__version__ = '25.04.
|
|
48
|
+
__version__ = '25.04.30'
|
|
49
49
|
|
|
50
50
|
_0EPS = EPS # near-zero, positive
|
|
51
51
|
_EPS0 = -EPS # near-zero, negative
|
|
@@ -1612,8 +1612,8 @@ class _EdgeGH(object):
|
|
|
1612
1612
|
|
|
1613
1613
|
def _alpha2(self, x, y, dx, dy):
|
|
1614
1614
|
# Return C{(alpha)}, see .points.nearestOn5
|
|
1615
|
-
a =
|
|
1616
|
-
d =
|
|
1615
|
+
a = Fdot_(y, dy, x, dx).fover(self._hypot2)
|
|
1616
|
+
d = Fdot_(y, dx, -x, dy).fover(self._hypot0)
|
|
1617
1617
|
return a, fabs(d)
|
|
1618
1618
|
|
|
1619
1619
|
def _Error(self, n, *args, **kwds): # PYCHOK no cover
|
|
@@ -1655,10 +1655,10 @@ class _EdgeGH(object):
|
|
|
1655
1655
|
if fabs(d) > _0EPS: # non-parallel edges
|
|
1656
1656
|
dx = x - c1_x
|
|
1657
1657
|
dy = y - c1_y
|
|
1658
|
-
ca =
|
|
1658
|
+
ca = Fdot_(sx, dy, -sy, dx).fover(d)
|
|
1659
1659
|
if _0EPS < ca < _EPS1 or (self._xtend and
|
|
1660
1660
|
_EPS0 < ca < _1EPS):
|
|
1661
|
-
sa =
|
|
1661
|
+
sa = Fdot_(cx, dy, -cy, dx).fover(d)
|
|
1662
1662
|
if _0EPS < sa < _EPS1 or (self._xtend and
|
|
1663
1663
|
_EPS0 < sa < _1EPS):
|
|
1664
1664
|
yield (y + sa * sy), (x + sa * sx), sa, ca
|
|
@@ -1669,7 +1669,7 @@ class _EdgeGH(object):
|
|
|
1669
1669
|
|
|
1670
1670
|
elif self._raiser and not (ca < _EPS0 or ca > _1EPS): # PYCHOK no cover
|
|
1671
1671
|
# intersection at c1 or c2 or at c1 or c2 and s1 or s2
|
|
1672
|
-
sa =
|
|
1672
|
+
sa = Fdot_(cx, dy, -cy, dx).fover(d)
|
|
1673
1673
|
e = 2 if sa < _EPS0 or sa > _1EPS else 3
|
|
1674
1674
|
raise self._Error(e, c1, c2, ca=ca)
|
|
1675
1675
|
|
pygeodesy/cartesianBase.py
CHANGED
|
@@ -16,6 +16,7 @@ from pygeodesy.constants import EPS, EPS0, INT0, PI2, _isfinite, isnear0, \
|
|
|
16
16
|
from pygeodesy.datums import Datum, _earth_ellipsoid, _spherical_datum, \
|
|
17
17
|
Transform, _WGS84
|
|
18
18
|
# from pygeodesy.ecef import EcefKarney # _MODS
|
|
19
|
+
from pygeodesy.ecefLocals import _EcefLocal
|
|
19
20
|
from pygeodesy.errors import _IsnotError, _TypeError, _ValueError, _xattr, \
|
|
20
21
|
_xdatum, _xkwds, _xkwds_get, _xkwds_pop2
|
|
21
22
|
from pygeodesy.fmath import cbrt, hypot, hypot_, hypot2, fabs, sqrt # hypot
|
|
@@ -25,7 +26,7 @@ from pygeodesy.fsums import fsumf_, Fmt
|
|
|
25
26
|
from pygeodesy.interns import _COMMASPACE_, _datum_, _no_, _phi_
|
|
26
27
|
from pygeodesy.interns import _ellipsoidal_, _spherical_ # PYCHOK used!
|
|
27
28
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
28
|
-
from pygeodesy.named import _name2__,
|
|
29
|
+
from pygeodesy.named import _name2__, _Pass
|
|
29
30
|
from pygeodesy.namedTuples import LatLon4Tuple, _NamedTupleTo , Vector3Tuple, \
|
|
30
31
|
Vector4Tuple, Bearing2Tuple # PYCHOK .sphericalBase
|
|
31
32
|
# from pygeodesy.nvectorBase import _N_vector # _MODS
|
|
@@ -43,14 +44,14 @@ from pygeodesy.vector3d import Vector3d, _xyzhdlln4
|
|
|
43
44
|
# from math import degrees, fabs, radians, sqrt # from .fmath, .utily
|
|
44
45
|
|
|
45
46
|
__all__ = _ALL_LAZY.cartesianBase
|
|
46
|
-
__version__ = '25.04.
|
|
47
|
+
__version__ = '25.04.28'
|
|
47
48
|
|
|
48
49
|
_r_ = 'r'
|
|
49
50
|
_resections = _MODS.into(resections=__name__)
|
|
50
51
|
_theta_ = 'theta'
|
|
51
52
|
|
|
52
53
|
|
|
53
|
-
class CartesianBase(Vector3d,
|
|
54
|
+
class CartesianBase(Vector3d, _EcefLocal):
|
|
54
55
|
'''(INTERNAL) Base class for ellipsoidal and spherical C{Cartesian}.
|
|
55
56
|
'''
|
|
56
57
|
_datum = None # L{Datum}, to be overriden
|
|
@@ -200,7 +201,7 @@ class CartesianBase(Vector3d, _NamedLocal):
|
|
|
200
201
|
'''
|
|
201
202
|
n, kwds = _name2__(name_Cartesian_kwds, _or_nameof=self)
|
|
202
203
|
if Cartesian is None:
|
|
203
|
-
r = self.
|
|
204
|
+
r = self._ltp._local2ecef(delta, nine=True) # _EcefLocal._ltp
|
|
204
205
|
else:
|
|
205
206
|
d = self.datum
|
|
206
207
|
if not d:
|
|
@@ -208,7 +209,7 @@ class CartesianBase(Vector3d, _NamedLocal):
|
|
|
208
209
|
t = _xkwds_get(kwds, datum=d)
|
|
209
210
|
if _xattr(t, ellipsoid=None) != d.ellipsoid:
|
|
210
211
|
raise _TypeError(datum=t, txt=str(d))
|
|
211
|
-
c = self.
|
|
212
|
+
c = self._ltp._local2ecef(delta, nine=False) # _EcefLocal._ltp
|
|
212
213
|
r = Cartesian(*c, **kwds)
|
|
213
214
|
return r.renamed(n) if n else r
|
|
214
215
|
|
pygeodesy/ecef.py
CHANGED
|
@@ -63,19 +63,19 @@ from pygeodesy.constants import EPS, EPS0, EPS02, EPS1, EPS2, EPS_2, INT0, PI, P
|
|
|
63
63
|
_0_0, _0_0001, _0_01, _0_5, _1_0, _1_0_1T, _N_1_0, \
|
|
64
64
|
_2_0, _N_2_0, _3_0, _4_0, _6_0, _60_0, _90_0, _N_90_0, \
|
|
65
65
|
_100_0, _copysign_1_0, isnon0 # PYCHOK used!
|
|
66
|
-
from pygeodesy.datums import
|
|
66
|
+
from pygeodesy.datums import _ellipsoidal_datum, _WGS84, a_f2Tuple, _EWGS84
|
|
67
|
+
from pygeodesy.ecefLocals import _EcefLocal
|
|
67
68
|
# from pygeodesy.ellipsoids import a_f2Tuple, _EWGS84 # from .datums
|
|
68
69
|
from pygeodesy.errors import _IndexError, LenError, _ValueError, _TypesError, \
|
|
69
70
|
_xattr, _xdatum, _xkwds, _xkwds_get
|
|
70
|
-
from pygeodesy.fmath import cbrt, fdot,
|
|
71
|
+
from pygeodesy.fmath import cbrt, fdot, hypot, hypot1, hypot2_, sqrt0
|
|
71
72
|
from pygeodesy.fsums import Fsum, fsumf_, Fmt, unstr
|
|
72
73
|
# from pygeodesy.internals import typename # from .basics
|
|
73
74
|
from pygeodesy.interns import NN, _a_, _C_, _datum_, _ellipsoid_, _f_, _height_, \
|
|
74
75
|
_lat_, _lon_, _M_, _name_, _singular_, _SPACE_, \
|
|
75
76
|
_x_, _xyz_, _y_, _z_
|
|
76
77
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
77
|
-
from pygeodesy.named import _name__, _name1__, _NamedBase,
|
|
78
|
-
_NamedTuple, _Pass, _xnamed
|
|
78
|
+
from pygeodesy.named import _name__, _name1__, _NamedBase, _NamedTuple, _Pass, _xnamed
|
|
79
79
|
from pygeodesy.namedTuples import LatLon2Tuple, LatLon3Tuple, \
|
|
80
80
|
PhiLam2Tuple, Vector3Tuple, Vector4Tuple
|
|
81
81
|
from pygeodesy.props import deprecated_method, Property_RO, property_RO, \
|
|
@@ -90,7 +90,7 @@ from pygeodesy.utily import atan1, atan1d, atan2, atan2d, degrees90, degrees180,
|
|
|
90
90
|
from math import cos, degrees, fabs, radians, sqrt
|
|
91
91
|
|
|
92
92
|
__all__ = _ALL_LAZY.ecef
|
|
93
|
-
__version__ = '25.04.
|
|
93
|
+
__version__ = '25.04.28'
|
|
94
94
|
|
|
95
95
|
_Ecef_ = 'Ecef'
|
|
96
96
|
_prolate_ = 'prolate'
|
|
@@ -110,6 +110,7 @@ class _EcefBase(_NamedBase):
|
|
|
110
110
|
'''
|
|
111
111
|
_datum = _WGS84
|
|
112
112
|
_E = _EWGS84
|
|
113
|
+
_isYou = False
|
|
113
114
|
_lon00 = INT0 # arbitrary, "polar" lon for LocalCartesian, Ltp
|
|
114
115
|
|
|
115
116
|
def __init__(self, a_ellipsoid=_EWGS84, f=None, lon00=INT0, **name):
|
|
@@ -272,12 +273,6 @@ class _EcefBase(_NamedBase):
|
|
|
272
273
|
return (Ecef9Tuple, # overwrite property_ROver
|
|
273
274
|
_MODS.vector3d.Vector3d) # _MODS.cartesianBase.CartesianBase
|
|
274
275
|
|
|
275
|
-
@Property_RO
|
|
276
|
-
def _isYou(self):
|
|
277
|
-
'''(INTERNAL) Is this an C{EcefYou}?.
|
|
278
|
-
'''
|
|
279
|
-
return isinstance(self, EcefYou)
|
|
280
|
-
|
|
281
276
|
@property
|
|
282
277
|
def lon00(self):
|
|
283
278
|
'''Get the I{"polar"} longitude (C{degrees}), see method C{reverse}.
|
|
@@ -790,6 +785,7 @@ class EcefYou(_EcefBase):
|
|
|
790
785
|
11589/115114_9021_geod2ellip_final.pdf>} Studia Geophysica et Geodaetica, 2008, 52,
|
|
791
786
|
pages 1-18 and U{PyMap3D <https://PyPI.org/project/pymap3d>}.
|
|
792
787
|
'''
|
|
788
|
+
_isYou = True
|
|
793
789
|
|
|
794
790
|
def __init__(self, a_ellipsoid=_EWGS84, f=None, **lon00_name): # PYCHOK signature
|
|
795
791
|
_EcefBase.__init__(self, a_ellipsoid, f=f, **lon00_name) # inherited documentation
|
|
@@ -825,13 +821,14 @@ class EcefYou(_EcefBase):
|
|
|
825
821
|
ellipsoid is I{prolate}.
|
|
826
822
|
'''
|
|
827
823
|
x, y, z, name = _xyzn4(xyz, y, z, self._Geocentrics, **lon00_name)
|
|
824
|
+
q = hypot(x, y) # R
|
|
828
825
|
|
|
829
826
|
E = self.ellipsoid
|
|
830
827
|
e, e2 = self._ee2
|
|
831
828
|
|
|
832
|
-
|
|
833
|
-
u
|
|
834
|
-
u
|
|
829
|
+
u = hypot2_(x, y, z) - e2
|
|
830
|
+
u += hypot(u, e * z * _2_0)
|
|
831
|
+
u *= _0_5
|
|
835
832
|
if u > EPS02:
|
|
836
833
|
u = sqrt(u)
|
|
837
834
|
p = hypot(u, e)
|
|
@@ -1019,7 +1016,7 @@ class EcefMatrix(_NamedTuple):
|
|
|
1019
1016
|
return xyz_
|
|
1020
1017
|
|
|
1021
1018
|
|
|
1022
|
-
class Ecef9Tuple(_NamedTuple,
|
|
1019
|
+
class Ecef9Tuple(_NamedTuple, _EcefLocal):
|
|
1023
1020
|
'''9-Tuple C{(x, y, z, lat, lon, height, C, M, datum)} with I{geocentric} C{x},
|
|
1024
1021
|
C{y} and C{z} plus I{geodetic} C{lat}, C{lon} and C{height}, case C{C} (see
|
|
1025
1022
|
the C{Ecef*.reverse} methods) and optionally, rotation matrix C{M} (L{EcefMatrix})
|
|
@@ -1041,7 +1038,7 @@ class Ecef9Tuple(_NamedTuple, _NamedLocal):
|
|
|
1041
1038
|
return self.toDatum(datum2)
|
|
1042
1039
|
|
|
1043
1040
|
@property_RO
|
|
1044
|
-
def _ecef9(self):
|
|
1041
|
+
def _ecef9(self): # in ._EcefLocal._Ltp_ecef2local
|
|
1045
1042
|
return self
|
|
1046
1043
|
|
|
1047
1044
|
@Property_RO
|
|
@@ -1103,13 +1100,6 @@ class Ecef9Tuple(_NamedTuple, _NamedLocal):
|
|
|
1103
1100
|
'''
|
|
1104
1101
|
return Lon(Vermeille=degrees(self.lamVermeille))
|
|
1105
1102
|
|
|
1106
|
-
def _ltp_toLocal(self, ltp, Xyz_kwds, **Xyz): # overloads C{_NamedLocal}'s
|
|
1107
|
-
'''(INTERNAL) Invoke C{ltp._xLtp(ltp)._ecef2local}.
|
|
1108
|
-
'''
|
|
1109
|
-
Xyz_ = self._ltp_toLocal2(Xyz_kwds, **Xyz) # in ._NamedLocal
|
|
1110
|
-
ltp = self._ltp._xLtp(ltp, self._Ltp) # both in ._NamedLocal
|
|
1111
|
-
return ltp._ecef2local(self, *Xyz_)
|
|
1112
|
-
|
|
1113
1103
|
@Property_RO
|
|
1114
1104
|
def phi(self):
|
|
1115
1105
|
'''Get the latitude in C{radians} (C{float}).
|
pygeodesy/ecefLocals.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
u'''(INTERNAL) ECEF to local coodinate conversions, separated from
|
|
5
|
+
module C{ecef} to defer importing the latter into C{CartesianBase}
|
|
6
|
+
and C{LatLonBase}.
|
|
7
|
+
'''
|
|
8
|
+
|
|
9
|
+
from pygeodesy.basics import _isin, _xsubclassof
|
|
10
|
+
# from pygeodesy.ecef import EcefKarney # _MODS
|
|
11
|
+
from pygeodesy.errors import _xkwds_item2, _xkwds_pop2
|
|
12
|
+
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
13
|
+
# from pygeodesy import ltp as _ltp # _MODS.into
|
|
14
|
+
# from pygeodesy import ltpTuples as _ltpTuples # _MODS.into
|
|
15
|
+
from pygeodesy.named import _Named, notOverloaded
|
|
16
|
+
from pygeodesy.props import Property_RO, property_RO, property_ROver
|
|
17
|
+
|
|
18
|
+
__all__ = _ALL_LAZY.ecefLocals
|
|
19
|
+
__version__ = '25.04.28'
|
|
20
|
+
|
|
21
|
+
_ltp = _MODS.into(ltp=__name__)
|
|
22
|
+
_ltpTuples = _MODS.into(ltpTuples=__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _EcefLocal(_Named):
|
|
26
|
+
'''(INTERNAL) Base class for C{CartesianBase}, C{Ecef9Tuple} and
|
|
27
|
+
C{LatLonBase}, providing ECEF to local coordinate conversions.
|
|
28
|
+
'''
|
|
29
|
+
|
|
30
|
+
@property_ROver
|
|
31
|
+
def Ecef(self):
|
|
32
|
+
'''Get the ECEF I{class} (L{EcefKarney}), I{once}.
|
|
33
|
+
'''
|
|
34
|
+
return _MODS.ecef.EcefKarney
|
|
35
|
+
|
|
36
|
+
@property_RO
|
|
37
|
+
def _ecef9(self):
|
|
38
|
+
'''I{Must be overloaded}.'''
|
|
39
|
+
notOverloaded(self)
|
|
40
|
+
|
|
41
|
+
@property_RO
|
|
42
|
+
def _ecef9datum(self):
|
|
43
|
+
try:
|
|
44
|
+
d = self.datum # PYCHOK C{CartesianBase}, ...
|
|
45
|
+
except AttributeError:
|
|
46
|
+
d = None
|
|
47
|
+
return d or self._ecef9.datum
|
|
48
|
+
|
|
49
|
+
@Property_RO
|
|
50
|
+
def _ltp(self):
|
|
51
|
+
'''(INTERNAL) Cache this instance' LTP (L{Ltp}).
|
|
52
|
+
'''
|
|
53
|
+
return _ltp.Ltp(self._ecef9, ecef=self.Ecef(self._ecef9datum), name=self.name)
|
|
54
|
+
|
|
55
|
+
def _ltp_ecef2local(self, ltp, Xyz_kwds, _None=None, **Xyz): # in C{Ecef9Tuple}
|
|
56
|
+
'''(INTERNAL) Invoke C{_ltp._xLtp(ltp, self._ltp)._ecef2local}.
|
|
57
|
+
'''
|
|
58
|
+
C, _ = Xyz_ = _xkwds_pop2(Xyz_kwds, **Xyz)
|
|
59
|
+
if C is not _None: # validate C, see .toLocal
|
|
60
|
+
n, X = _xkwds_item2(Xyz)
|
|
61
|
+
if X is not C:
|
|
62
|
+
_xsubclassof(X, **{n: C})
|
|
63
|
+
ltp = _ltp._xLtp(ltp, self._ltp)
|
|
64
|
+
return ltp._ecef2local(self._ecef9, *Xyz_)
|
|
65
|
+
|
|
66
|
+
def toAer(self, ltp=None, **Aer_and_kwds):
|
|
67
|
+
'''Convert this instance to I{local} I{Azimuth, Elevation, slant Range} (AER) components.
|
|
68
|
+
|
|
69
|
+
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
70
|
+
instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
|
|
71
|
+
@kwarg Aer_and_kwds: Optional AER class C{B{Aer}=}L{Aer<pygeodesy.ltpTuples.Aer>}
|
|
72
|
+
to use and optionally, additional B{C{Aer}} keyword arguments.
|
|
73
|
+
|
|
74
|
+
@return: An B{C{Aer}} instance.
|
|
75
|
+
|
|
76
|
+
@raise TypeError: Invalid B{C{ltp}}.
|
|
77
|
+
|
|
78
|
+
@see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
|
|
79
|
+
'''
|
|
80
|
+
return self._ltp_ecef2local(ltp, Aer_and_kwds, Aer=_ltpTuples.Aer)
|
|
81
|
+
|
|
82
|
+
def toEnu(self, ltp=None, **Enu_and_kwds):
|
|
83
|
+
'''Convert this instance to I{local} I{East, North, Up} (ENU) components.
|
|
84
|
+
|
|
85
|
+
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
86
|
+
instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
|
|
87
|
+
@kwarg Enu_and_kwds: Optional ENU class C{B{Enu}=}L{Enu<pygeodesy.ltpTuples.Enu>}
|
|
88
|
+
to use and optionally, additional B{C{Enu}} keyword arguments.
|
|
89
|
+
|
|
90
|
+
@return: An B{C{Enu}} instance.
|
|
91
|
+
|
|
92
|
+
@raise TypeError: Invalid B{C{ltp}}.
|
|
93
|
+
|
|
94
|
+
@see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
|
|
95
|
+
'''
|
|
96
|
+
return self._ltp_ecef2local(ltp, Enu_and_kwds, Enu=_ltpTuples.Enu)
|
|
97
|
+
|
|
98
|
+
def toLocal(self, Xyz=None, ltp=None, **Xyz_kwds):
|
|
99
|
+
'''Convert this instance to I{local} components in a I{local tangent plane} (LTP)
|
|
100
|
+
|
|
101
|
+
@kwarg Xyz: Optional I{local} components class (L{XyzLocal}, L{Aer}, L{Enu},
|
|
102
|
+
L{Ned}) or C{None}.
|
|
103
|
+
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
104
|
+
cartesian's L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
|
|
105
|
+
@kwarg Xyz_kwds: Optionally, additional B{C{Xyz}} keyword arguments, ignored
|
|
106
|
+
if C{B{Xyz} is None}.
|
|
107
|
+
|
|
108
|
+
@return: An B{C{Xyz}} instance or a L{Local9Tuple}C{(x, y, z, lat, lon,
|
|
109
|
+
height, ltp, ecef, M)} if C{B{Xyz} is None} (with C{M=None}).
|
|
110
|
+
|
|
111
|
+
@raise TypeError: Invalid B{C{ltp}}.
|
|
112
|
+
'''
|
|
113
|
+
return self._ltp_ecef2local(ltp, Xyz_kwds, Xyz=Xyz, _None=Xyz)
|
|
114
|
+
|
|
115
|
+
def toLtp(self, Ecef=None, **name):
|
|
116
|
+
'''Return the I{local tangent plane} (LTP) for this instance.
|
|
117
|
+
|
|
118
|
+
@kwarg Ecef: Optional ECEF I{class} (L{EcefKarney}, ... L{EcefYou}), overriding
|
|
119
|
+
this instance' L{Ecef<pygeodesy.ecefLocals._EcefLocal.Ecef>}.
|
|
120
|
+
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
121
|
+
|
|
122
|
+
@return: An B{C{Ltp}} instance.
|
|
123
|
+
'''
|
|
124
|
+
if _isin(Ecef, None, self.Ecef) and not name:
|
|
125
|
+
ltp = self._ltp
|
|
126
|
+
else: # like self._ltp
|
|
127
|
+
ecef = (Ecef if Ecef else self.Ecef)(self._ecef9datum)
|
|
128
|
+
ltp = _ltp.Ltp(self._ecef9, ecef=ecef, name=self._name__(name))
|
|
129
|
+
return ltp
|
|
130
|
+
|
|
131
|
+
def toNed(self, ltp=None, **Ned_and_kwds):
|
|
132
|
+
'''Convert this instance to I{local} I{North, East, Down} (NED) components.
|
|
133
|
+
|
|
134
|
+
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
135
|
+
instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
|
|
136
|
+
@kwarg Ned_and_kwds: Optional NED class C{B{Ned}=}L{Ned<pygeodesy.ltpTuples.Ned>}
|
|
137
|
+
to use and optionally, additional B{C{Ned}} keyword arguments.
|
|
138
|
+
|
|
139
|
+
@return: An B{C{Ned}} instance.
|
|
140
|
+
|
|
141
|
+
@raise TypeError: Invalid B{C{ltp}}.
|
|
142
|
+
|
|
143
|
+
@see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
|
|
144
|
+
'''
|
|
145
|
+
return self._ltp_ecef2local(ltp, Ned_and_kwds, Ned=_ltpTuples.Ned)
|
|
146
|
+
|
|
147
|
+
def toXyz(self, ltp=None, **Xyz_and_kwds):
|
|
148
|
+
'''Convert this instance to I{local} I{X, Y, Z} (XYZ) components.
|
|
149
|
+
|
|
150
|
+
@kwarg ltp: The I{local tangent plane} (LTP) to use (L{Ltp}), overriding this
|
|
151
|
+
instance' L{LTP<pygeodesy.ecefLocals._EcefLocal.toLtp>}.
|
|
152
|
+
@kwarg Xyz_and_kwds: Optional XYZ class C{B{Xyz}=}L{Xyz<pygeodesy.ltpTuples.XyzLocal>}
|
|
153
|
+
to use and optionally, additional B{C{Xyz}} keyword arguments.
|
|
154
|
+
|
|
155
|
+
@return: An B{C{Xyz}} instance.
|
|
156
|
+
|
|
157
|
+
@raise TypeError: Invalid B{C{ltp}}.
|
|
158
|
+
|
|
159
|
+
@see: Method L{toLocal<pygeodesy.ecefLocals._EcefLocal.toLocal>}.
|
|
160
|
+
'''
|
|
161
|
+
return self._ltp_ecef2local(ltp, Xyz_and_kwds, Xyz=_ltpTuples.XyzLocal)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
__all__ += _ALL_DOCS(_EcefLocal)
|
|
165
|
+
|
|
166
|
+
# **) MIT License
|
|
167
|
+
#
|
|
168
|
+
# Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
|
|
169
|
+
#
|
|
170
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
171
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
172
|
+
# to deal in the Software without restriction, including without limitation
|
|
173
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
174
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
175
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
176
|
+
#
|
|
177
|
+
# The above copyright notice and this permission notice shall be included
|
|
178
|
+
# in all copies or substantial portions of the Software.
|
|
179
|
+
#
|
|
180
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
181
|
+
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
182
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
183
|
+
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
184
|
+
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
185
|
+
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
186
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
pygeodesy/ellipsoids.py
CHANGED
|
@@ -95,7 +95,7 @@ from pygeodesy.utily import atan1, atan1d, atan2b, degrees90, m2radians, radians
|
|
|
95
95
|
from math import asinh, atan, atanh, cos, degrees, exp, fabs, radians, sin, sinh, sqrt, tan # as _tan
|
|
96
96
|
|
|
97
97
|
__all__ = _ALL_LAZY.ellipsoids
|
|
98
|
-
__version__ = '25.04.
|
|
98
|
+
__version__ = '25.04.28'
|
|
99
99
|
|
|
100
100
|
_f_0_0 = Float(f =_0_0) # zero flattening
|
|
101
101
|
_f__0_0 = Float(f_=_0_0) # zero inverse flattening
|
|
@@ -140,12 +140,14 @@ class a_f2Tuple(_NamedTuple):
|
|
|
140
140
|
@arg f: Flattening (C{scalar} < 1, negative for I{prolate}).
|
|
141
141
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
142
142
|
|
|
143
|
-
@return: An L{a_f2Tuple}C{(a, f)}
|
|
143
|
+
@return: An L{a_f2Tuple}C{(a, f)}.
|
|
144
144
|
|
|
145
145
|
@raise UnitError: Invalid B{C{a}} or B{C{f}}.
|
|
146
146
|
|
|
147
|
-
@note: C{abs(B{f}) < EPS} is
|
|
148
|
-
|
|
147
|
+
@note: C{abs(B{f}) < }L{EPS<pygeodesy.constants.EPS>} is
|
|
148
|
+
forced to C{B{f}=0}, I{spherical}.
|
|
149
|
+
|
|
150
|
+
@note: Negative C{B{f}} produces a I{prolate} ellipsoid.
|
|
149
151
|
'''
|
|
150
152
|
a = Radius_(a=a) # low=EPS, high=None
|
|
151
153
|
f = Float_( f=f, low=None, high=EPS1)
|
|
@@ -359,11 +361,16 @@ class Ellipsoid(_NamedEnumItem):
|
|
|
359
361
|
'''
|
|
360
362
|
return a_f2Tuple(self.a, self.f, name=self.name)
|
|
361
363
|
|
|
364
|
+
a_f2 = a_f # synonym
|
|
365
|
+
|
|
362
366
|
@Property_RO
|
|
363
367
|
def A(self):
|
|
364
368
|
'''Get the UTM I{meridional (or rectifying)} radius (C{meter}).
|
|
365
369
|
|
|
366
|
-
@
|
|
370
|
+
@note: C{A * PI / 2} ≈= L{L<Ellipsoid.L>}, the I{quarter meridian}.
|
|
371
|
+
|
|
372
|
+
@see: I{Meridian arc unit} U{Q<https://StudyLib.net/doc/7443565/>},
|
|
373
|
+
the mean, meridional length I{per radian}.
|
|
367
374
|
'''
|
|
368
375
|
A, n = self.a, self.n
|
|
369
376
|
if n:
|
|
@@ -375,6 +382,11 @@ class Ellipsoid(_NamedEnumItem):
|
|
|
375
382
|
# A *= fhorner(n**2, 1048576, 262144, 16384, 4096, 1600, 784, 441) / 1048576) / (1 + n)
|
|
376
383
|
A = Radius(A=Fhorner(n**2, 1048576, 262144, 16384, 4096, 1600, 784, 441).fover(d))
|
|
377
384
|
return A
|
|
385
|
+
# # Moritz, H. <https://Geodesy.Geology.Ohio-State.EDU/course/refpapers/00740128.pdf>
|
|
386
|
+
# # q = 4 / self.rocPolar
|
|
387
|
+
# # Q = (1 - 3 / 4 * e'2 + 45 / 64 * e'4 - 175 / 256 * e'6 + 11025 / 16384 * e'8) * rocPolar
|
|
388
|
+
# # = (4 + e'2 * (-3 + e'2 * (45 / 16 + e'2 * (-175 / 64 + e'2 * 11025 / 4096)))) / q
|
|
389
|
+
# return Radius(Q=Fhorner(self.e22, 4, -3, 45 / 16, -175 / 64, 11025 / 4096).fover(q))
|
|
378
390
|
|
|
379
391
|
@Property_RO
|
|
380
392
|
def _albersCyl(self):
|
|
@@ -1339,23 +1351,7 @@ class Ellipsoid(_NamedEnumItem):
|
|
|
1339
1351
|
|
|
1340
1352
|
polaradius = b # Rpolar
|
|
1341
1353
|
|
|
1342
|
-
#
|
|
1343
|
-
# def Q(self):
|
|
1344
|
-
# '''Get the I{meridian arc unit} C{Q}, the mean, meridional length I{per radian} C({float}).
|
|
1345
|
-
#
|
|
1346
|
-
# @note: C{Q * PI / 2} ≈ C{L}, the I{quarter meridian}.
|
|
1347
|
-
#
|
|
1348
|
-
# @see: Property C{A} and U{Engsager, K., Poder, K.<https://StudyLib.net/doc/7443565/
|
|
1349
|
-
# a-highly-accurate-world-wide-algorithm-for-the-transverse...>}.
|
|
1350
|
-
# '''
|
|
1351
|
-
# n = self.n
|
|
1352
|
-
# d = (n + _1_0) / self.a
|
|
1353
|
-
# return Float(Q=Fhorner(n**2, _1_0, _0_25, _1_16th, _0_25).fover(d) if d else self.b)
|
|
1354
|
-
|
|
1355
|
-
# # Moritz, H. <https://Geodesy.Geology.Ohio-State.EDU/course/refpapers/00740128.pdf>
|
|
1356
|
-
# # Q = (1 - 3/4 * e'2 + 45/64 * e'4 - 175/256 * e'6 + 11025/16384 * e'8) * rocPolar
|
|
1357
|
-
# # = (4 + e'2 * (-3 + e'2 * (45/16 + e'2 * (-175/64 + e'2 * 11025/4096)))) * rocPolar / 4
|
|
1358
|
-
# return Fhorner(self.e22, 4, -3, 45 / 16, -175 / 64, 11025 / 4096).fover(4 / self.rocPolar)
|
|
1354
|
+
# Q = A # I{meridian arc unit} C{Q}, the mean, meridional length I{per radian}
|
|
1359
1355
|
|
|
1360
1356
|
@deprecated_Property_RO
|
|
1361
1357
|
def quarteradius(self): # PYCHOK no cover
|
|
@@ -1382,16 +1378,13 @@ class Ellipsoid(_NamedEnumItem):
|
|
|
1382
1378
|
<https://WikiPedia.org/wiki/Earth_radius>}.
|
|
1383
1379
|
'''
|
|
1384
1380
|
return Radius(R2=sqrt(self.c2) if self.f else self.a)
|
|
1385
|
-
|
|
1386
|
-
Rauthalic = R2
|
|
1387
|
-
|
|
1388
|
-
# @Property_RO
|
|
1389
|
-
# def R2(self):
|
|
1390
1381
|
# # Moritz, H. <https://Geodesy.Geology.Ohio-State.EDU/course/refpapers/00740128.pdf>
|
|
1391
1382
|
# # R2 = (1 - 2/3 * e'2 + 26/45 * e'4 - 100/189 * e'6 + 7034/14175 * e'8) * rocPolar
|
|
1392
1383
|
# # = (3 + e'2 * (-2 + e'2 * (26/15 + e'2 * (-100/63 + e'2 * 7034/4725)))) * rocPolar / 3
|
|
1393
1384
|
# return Fhorner(self.e22, 3, -2, 26 / 15, -100 / 63, 7034 / 4725).fover(3 / self.rocPolar)
|
|
1394
1385
|
|
|
1386
|
+
Rauthalic = R2
|
|
1387
|
+
|
|
1395
1388
|
@Property_RO
|
|
1396
1389
|
def R2x(self):
|
|
1397
1390
|
'''Get the I{authalic} earth radius (C{meter}), M{sqrt(c2x)}.
|
pygeodesy/fmath.py
CHANGED
|
@@ -25,7 +25,7 @@ from math import fabs, sqrt # pow
|
|
|
25
25
|
import operator as _operator # in .datums, .trf, .utm
|
|
26
26
|
|
|
27
27
|
__all__ = _ALL_LAZY.fmath
|
|
28
|
-
__version__ = '25.04.
|
|
28
|
+
__version__ = '25.04.30'
|
|
29
29
|
|
|
30
30
|
# sqrt(2) - 1 <https://WikiPedia.org/wiki/Square_root_of_2>
|
|
31
31
|
_0_4142 = 0.41421356237309504880 # ~ 3_730_904_090_310_553 / 9_007_199_254_740_992
|
|
@@ -66,13 +66,27 @@ class Fdot(Fsum):
|
|
|
66
66
|
self._facc_dot(n, a, b, **kwds)
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
class Fdot_(Fdot):
|
|
70
|
+
'''Precision dot product.
|
|
71
|
+
'''
|
|
72
|
+
def __init__(self, *xys, **start_name_f2product_nonfinites_RESIDUAL):
|
|
73
|
+
'''New L{Fdot_} precision dot product M{sum(xys[i] * xys[i+1] for i in
|
|
74
|
+
range(0, len(xys), B{2}))}.
|
|
75
|
+
|
|
76
|
+
@arg xys: Pairwise values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
|
|
77
|
+
all positional.
|
|
78
|
+
|
|
79
|
+
@see: Class L{Fdot<Fdot.__init__>} for further details.
|
|
80
|
+
'''
|
|
81
|
+
Fdot.__init__(self, xys[0::2], *xys[1::2], **start_name_f2product_nonfinites_RESIDUAL)
|
|
82
|
+
|
|
83
|
+
|
|
69
84
|
class Fhorner(Fsum):
|
|
70
85
|
'''Precision polynomial evaluation using the Horner form.
|
|
71
86
|
'''
|
|
72
87
|
def __init__(self, x, *cs, **incx_name_f2product_nonfinites_RESIDUAL):
|
|
73
|
-
'''New L{Fhorner} form evaluation of polynomial M{sum(cs[i] * x**i for
|
|
74
|
-
|
|
75
|
-
= len(cs) - 1}.
|
|
88
|
+
'''New L{Fhorner} form evaluation of polynomial M{sum(cs[i] * x**i for i=0..n)}
|
|
89
|
+
with in- or decreasing exponent M{sum(... i=n..0)}, where C{n = len(cs) - 1}.
|
|
76
90
|
|
|
77
91
|
@arg x: Polynomial argument (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
|
|
78
92
|
@arg cs: Polynomial coeffients (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
|
|
@@ -454,7 +468,8 @@ def fdot_(*xys, **start_f2product_nonfinites):
|
|
|
454
468
|
|
|
455
469
|
@return: Dot product (C{float}).
|
|
456
470
|
'''
|
|
457
|
-
|
|
471
|
+
D = Fdot_(*xys, **_xkwds(start_f2product_nonfinites, nonfinites=True))
|
|
472
|
+
return float(D)
|
|
458
473
|
|
|
459
474
|
|
|
460
475
|
def fdot3(xs, ys, zs, **start_f2product_nonfinites):
|
|
@@ -555,7 +570,7 @@ def fidw(xs, ds, beta=2):
|
|
|
555
570
|
|
|
556
571
|
|
|
557
572
|
try:
|
|
558
|
-
from math import fma as _fma
|
|
573
|
+
from math import fma as _fma # in .resections
|
|
559
574
|
except ImportError: # PYCHOK DSPACE!
|
|
560
575
|
|
|
561
576
|
def _fma(x, y, z): # no need for accuracy
|
pygeodesy/fsums.py
CHANGED
|
@@ -64,7 +64,7 @@ from math import fabs, isinf, isnan, \
|
|
|
64
64
|
ceil as _ceil, floor as _floor # PYCHOK used! .ltp
|
|
65
65
|
|
|
66
66
|
__all__ = _ALL_LAZY.fsums
|
|
67
|
-
__version__ = '25.04.
|
|
67
|
+
__version__ = '25.04.26'
|
|
68
68
|
|
|
69
69
|
from pygeodesy.interns import (
|
|
70
70
|
_PLUS_ as _add_op_, # in .auxilats.auxAngle
|
|
@@ -1485,7 +1485,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1485
1485
|
@deprecated_method
|
|
1486
1486
|
def f2mul(self, *others, **raiser):
|
|
1487
1487
|
'''DEPRECATED on 2024.09.13, use method L{f2mul_<Fsum.f2mul_>}.'''
|
|
1488
|
-
return self._fset(self.
|
|
1488
|
+
return self._fset(self._f2mul(self.f2mul, others, **raiser))
|
|
1489
1489
|
|
|
1490
1490
|
def f2mul_(self, *others, **f2product_nonfinites): # in .fmath.f2mul
|
|
1491
1491
|
'''Return C{B{self} * B{other} * B{other} ...} for all B{C{others}} using cascaded,
|