pygeodesy 25.4.8__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.
Files changed (97) hide show
  1. pygeodesy/__init__.py +36 -31
  2. pygeodesy/__main__.py +3 -3
  3. pygeodesy/albers.py +29 -36
  4. pygeodesy/auxilats/_CX_4.py +2 -2
  5. pygeodesy/auxilats/_CX_6.py +2 -2
  6. pygeodesy/auxilats/_CX_8.py +2 -2
  7. pygeodesy/auxilats/_CX_Rs.py +9 -9
  8. pygeodesy/auxilats/__init__.py +3 -3
  9. pygeodesy/auxilats/__main__.py +8 -6
  10. pygeodesy/auxilats/auxAngle.py +2 -2
  11. pygeodesy/auxilats/auxLat.py +5 -5
  12. pygeodesy/auxilats/auxily.py +5 -3
  13. pygeodesy/azimuthal.py +7 -6
  14. pygeodesy/basics.py +32 -18
  15. pygeodesy/booleans.py +18 -16
  16. pygeodesy/cartesianBase.py +26 -24
  17. pygeodesy/clipy.py +11 -10
  18. pygeodesy/constants.py +11 -10
  19. pygeodesy/css.py +14 -11
  20. pygeodesy/datums.py +8 -8
  21. pygeodesy/deprecated/bases.py +2 -2
  22. pygeodesy/deprecated/classes.py +2 -2
  23. pygeodesy/deprecated/consterns.py +4 -4
  24. pygeodesy/dms.py +8 -8
  25. pygeodesy/ecef.py +22 -29
  26. pygeodesy/ecefLocals.py +186 -0
  27. pygeodesy/elevations.py +9 -8
  28. pygeodesy/ellipsoidalBase.py +19 -8
  29. pygeodesy/ellipsoidalBaseDI.py +17 -15
  30. pygeodesy/ellipsoidalNvector.py +6 -3
  31. pygeodesy/ellipsoidalVincenty.py +4 -1
  32. pygeodesy/ellipsoids.py +186 -164
  33. pygeodesy/elliptic.py +9 -9
  34. pygeodesy/errors.py +44 -43
  35. pygeodesy/etm.py +7 -7
  36. pygeodesy/fmath.py +30 -14
  37. pygeodesy/formy.py +11 -12
  38. pygeodesy/frechet.py +216 -109
  39. pygeodesy/fstats.py +5 -4
  40. pygeodesy/fsums.py +79 -78
  41. pygeodesy/gars.py +4 -3
  42. pygeodesy/geodesici.py +15 -14
  43. pygeodesy/geodesicw.py +34 -32
  44. pygeodesy/geodesicx/__init__.py +1 -1
  45. pygeodesy/geodesicx/__main__.py +11 -9
  46. pygeodesy/geodesicx/gx.py +30 -33
  47. pygeodesy/geodesicx/gxarea.py +2 -2
  48. pygeodesy/geodesicx/gxline.py +5 -5
  49. pygeodesy/geodsolve.py +18 -17
  50. pygeodesy/geohash.py +5 -5
  51. pygeodesy/geoids.py +34 -31
  52. pygeodesy/hausdorff.py +17 -13
  53. pygeodesy/heights.py +2 -4
  54. pygeodesy/internals.py +28 -44
  55. pygeodesy/interns.py +10 -7
  56. pygeodesy/iters.py +8 -8
  57. pygeodesy/karney.py +68 -62
  58. pygeodesy/ktm.py +5 -5
  59. pygeodesy/latlonBase.py +20 -21
  60. pygeodesy/lazily.py +104 -78
  61. pygeodesy/lcc.py +11 -9
  62. pygeodesy/ltp.py +56 -58
  63. pygeodesy/ltpTuples.py +35 -36
  64. pygeodesy/mgrs.py +7 -6
  65. pygeodesy/named.py +48 -177
  66. pygeodesy/nvectorBase.py +7 -7
  67. pygeodesy/osgr.py +9 -8
  68. pygeodesy/points.py +12 -10
  69. pygeodesy/props.py +25 -25
  70. pygeodesy/resections.py +83 -80
  71. pygeodesy/rhumb/__init__.py +1 -1
  72. pygeodesy/rhumb/aux_.py +7 -7
  73. pygeodesy/rhumb/bases.py +22 -20
  74. pygeodesy/rhumb/ekx.py +6 -6
  75. pygeodesy/rhumb/solve.py +15 -15
  76. pygeodesy/solveBase.py +3 -3
  77. pygeodesy/sphericalBase.py +6 -6
  78. pygeodesy/sphericalNvector.py +6 -5
  79. pygeodesy/sphericalTrigonometry.py +8 -7
  80. pygeodesy/streprs.py +14 -14
  81. pygeodesy/trf.py +14 -12
  82. pygeodesy/triaxials.py +29 -26
  83. pygeodesy/units.py +5 -4
  84. pygeodesy/unitsBase.py +5 -4
  85. pygeodesy/ups.py +3 -3
  86. pygeodesy/utily.py +4 -4
  87. pygeodesy/utmups.py +4 -4
  88. pygeodesy/utmupsBase.py +110 -18
  89. pygeodesy/vector2d.py +20 -13
  90. pygeodesy/vector3d.py +7 -6
  91. pygeodesy/webmercator.py +6 -5
  92. pygeodesy/wgrs.py +6 -5
  93. {pygeodesy-25.4.8.dist-info → pygeodesy-25.5.5.dist-info}/METADATA +30 -25
  94. pygeodesy-25.5.5.dist-info/RECORD +119 -0
  95. pygeodesy-25.4.8.dist-info/RECORD +0 -118
  96. {pygeodesy-25.4.8.dist-info → pygeodesy-25.5.5.dist-info}/WHEEL +0 -0
  97. {pygeodesy-25.4.8.dist-info → pygeodesy-25.5.5.dist-info}/top_level.txt +0 -0
pygeodesy/datums.py CHANGED
@@ -67,7 +67,7 @@ datum, q.v. U{"A Guide to Coordinate Systems in Great Britain", Section 6
67
67
  # make sure int/int division yields float quotient, see .basics
68
68
  from __future__ import division as _; del _ # PYCHOK semicolon
69
69
 
70
- from pygeodesy.basics import islistuple, map2, neg, _xinstanceof, _zip
70
+ from pygeodesy.basics import _isin, islistuple, map2, neg, _xinstanceof, _zip
71
71
  from pygeodesy.constants import R_M, _float as _F, _0_0, _1_0, _2_0, _8_0, _3600_0
72
72
  # from pygeodesy.ellipsoidalBase import CartesianEllipsoidalBase as _CEB, \
73
73
  # LatLonEllipsoidalBase as _LLEB # MODS
@@ -77,10 +77,10 @@ from pygeodesy.errors import _IsnotError, _TypeError, _xellipsoidall, _xkwds, _x
77
77
  from pygeodesy.fmath import fdot, fmean, Fmt, _operator
78
78
  from pygeodesy.internals import _passarg, _under
79
79
  from pygeodesy.interns import NN, _a_, _Airy1830_, _AiryModified_, _BAR_, _Bessel1841_, \
80
- _Clarke1866_, _Clarke1880IGN_, _COMMASPACE_, _DOT_, _earth_, \
81
- _ellipsoid_, _ellipsoidal_, _GRS80_, _Intl1924_, _MINUS_, \
82
- _Krassovski1940_, _Krassowsky1940_, _NAD27_, _NAD83_, _s_, \
83
- _PLUS_, _Sphere_, _spherical_, _transform_, _UNDER_, \
80
+ _Clarke1866_, _Clarke1880IGN_, _COMMASPACE_, _DMAIN_,_DOT_, \
81
+ _earth_, _ellipsoid_, _ellipsoidal_, _GRS80_, _Intl1924_, \
82
+ _MINUS_, _Krassovski1940_, _Krassowsky1940_, _NAD27_, _NAD83_, \
83
+ _s_, _PLUS_, _Sphere_, _spherical_, _transform_, _UNDER_, \
84
84
  _WGS72_, _WGS84_
85
85
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
86
86
  from pygeodesy.named import _lazyNamedEnumItem as _lazy, _name__, _name2__, _NamedEnum, \
@@ -94,7 +94,7 @@ from pygeodesy.units import _isRadius, Radius_, radians
94
94
  # import operator as _operator # from .fmath
95
95
 
96
96
  __all__ = _ALL_LAZY.datums
97
- __version__ = '24.10.12'
97
+ __version__ = '25.04.14'
98
98
 
99
99
  _a_ellipsoid_ = _UNDER_(_a_, _ellipsoid_)
100
100
  _BD72_ = 'BD72'
@@ -510,7 +510,7 @@ def _earth_datum(inst, a_earth, f=None, raiser=_a_ellipsoid_, **name): # in .ka
510
510
  E, n, D = _EnD3((a_earth, f), name)
511
511
  if raiser and not E:
512
512
  raise _TypeError(f=f, **{raiser: a_earth})
513
- elif a_earth in (_EWGS84, _WGS84, None) and inst._datum is _WGS84:
513
+ elif _isin(a_earth, None, _EWGS84, _WGS84) and inst._datum is _WGS84:
514
514
  return
515
515
  elif isinstance(a_earth, Datum):
516
516
  E, n, D = None, NN, a_earth
@@ -721,7 +721,7 @@ _WGS84 = Datums.WGS84
721
721
  assert _WGS84.ellipsoid is _EWGS84
722
722
  # assert _WGS84.transform.isunity
723
723
 
724
- if __name__ == '__main__':
724
+ if __name__ == _DMAIN_:
725
725
 
726
726
  from pygeodesy.interns import _COMMA_, _NL_, _NLATvar_
727
727
  from pygeodesy import printf
@@ -9,11 +9,11 @@ from pygeodesy.latlonBase import LatLonBase as _LatLonBase
9
9
  from pygeodesy.lazily import _ALL_DEPRECATED
10
10
 
11
11
  __all__ = _ALL_DEPRECATED.deprecated_bases
12
- __version__ = '23.11.25'
12
+ __version__ = '25.04.09'
13
13
 
14
14
 
15
15
  class LatLonHeightBase(_LatLonBase): # PYCHOK no cover
16
- ''''DEPRECATED on 2021.02.10, use (INTERNAL) class L{pygeodesy.latlonBase.LatLonBase}.'''
16
+ '''DEPRECATED on 2021.02.10, use (INTERNAL) class L{pygeodesy.latlonBase.LatLonBase}.'''
17
17
  pass
18
18
 
19
19
 
@@ -22,7 +22,7 @@ from pygeodesy.trf import TRFXform7Tuple as _TRFXform7Tuple
22
22
  from pygeodesy.units import Bearing, Int, Lamd, Lat, Lon, Meter, Phid
23
23
 
24
24
  __all__ = _ALL_DEPRECATED.deprecated_classes
25
- __version__ = '24.12.31'
25
+ __version__ = '25.04.11'
26
26
 
27
27
 
28
28
  class _Deprecated_NamedTuple(_NamedTuple):
@@ -349,7 +349,7 @@ class UtmUps4Tuple(_Deprecated_NamedTuple): # PYCHOK no cover
349
349
 
350
350
 
351
351
  class XDist(ADict):
352
- '''DEPRECATED on 2024.07.02, use class L{XDict}.'''
352
+ '''DEPRECATED on 2024.07.02, use class L{ADict}.'''
353
353
  def __init__(self, *args, **kwds): # PYCHOK no cover
354
354
  deprecated_class(self.__class__)
355
355
  ADict.__init__(self, *args, **kwds)
@@ -9,21 +9,21 @@ from pygeodesy.lazily import _ALL_DEPRECATED
9
9
  from pygeodesy.units import Float, Int, Str
10
10
 
11
11
  __all__ = _ALL_DEPRECATED.deprecated_consterns
12
- __version__ = '23.11.24'
12
+ __version__ = '25.04.09'
13
13
 
14
14
 
15
15
  class _Deprecated_Float(Float):
16
- '''DEPRECATED on 2023.09.12, don't use.'''
16
+ '''DEPRECATED on 2023.09.12, I{don't use}.'''
17
17
  pass
18
18
 
19
19
 
20
20
  class _Deprecated_Int(Int):
21
- '''DEPRECATED on 2023.09.12, don't use.'''
21
+ '''DEPRECATED on 2023.09.12, I{don't use}.'''
22
22
  pass
23
23
 
24
24
 
25
25
  class _Deprecated_Str(Str):
26
- '''DEPRECATED on 2023.09.12, don't use.'''
26
+ '''DEPRECATED on 2023.09.12, I{don't use}.'''
27
27
  pass
28
28
 
29
29
 
pygeodesy/dms.py CHANGED
@@ -62,11 +62,11 @@ U{Vector-based geodesy<https://www.Movable-Type.co.UK/scripts/latlong-vectors.ht
62
62
  '''
63
63
 
64
64
  from pygeodesy.basics import copysign0, isLatLon, isodd, issequence, isstr, \
65
- neg as _neg # in .ups
65
+ neg as _neg, typename # in .ups
66
66
  from pygeodesy.constants import _umod_360, _0_0, _0_5, _60_0, _360_0, _3600_0
67
67
  from pygeodesy.errors import ParseError, RangeError, _TypeError, _ValueError, \
68
- _parseX, rangerrors, _xError, _xkwds, _getPYGEODESY
69
- # from pygeodesy.internals import _getPYGEODESY # from .errors
68
+ _parseX, rangerrors, _xError, _xkwds, _envPYGEODESY
69
+ # from pygeodesy.internals import _envPYGEODESY, typename # from .errors
70
70
  from pygeodesy.interns import NN, _COMMA_, _d_, _DASH_, _deg_, _degrees_, _DOT_, \
71
71
  _0_, _e_, _E_, _EW_, _f_, _F_, _g_, _MINUS_, _N_, \
72
72
  _NE_, _NS_, _NSEW_, _NW_, _PERCENTDOTSTAR_, _PLUS_, \
@@ -86,7 +86,7 @@ except ImportError: # Python 3+
86
86
  from string import ascii_letters as _LETTERS
87
87
 
88
88
  __all__ = _ALL_LAZY.dms
89
- __version__ = '24.10.18'
89
+ __version__ = '25.04.14'
90
90
 
91
91
  _beyond_ = 'beyond'
92
92
  _deg_min_ = 'deg+min'
@@ -100,7 +100,7 @@ F_D_, F_DM_, F_DMS_, F_DEG_, F_MIN_, F_SEC_, F_D60_, F__E_, F__F_, F__G
100
100
  F_D__, F_DM__, F_DMS__, F_DEG__, F_MIN__, F_SEC__, F_D60__, F__E__, F__F__, F__G__, F_RAD__ = (NN(
101
101
  _PLUS_, _) for _ in _F_s)
102
102
  del _F_s
103
- _F_DMS = _getPYGEODESY('FMT_FORM') or F_DMS
103
+ _F_DMS = _envPYGEODESY('FMT_FORM') or F_DMS
104
104
 
105
105
  _F_case = {F_D: F_D, F_DEG: F_D, _degrees_: F_D, # unsigned _F_s
106
106
  F_DM: F_DM, F_MIN: F_DM, _deg_min_: F_DM,
@@ -348,7 +348,7 @@ def compassPoint(bearing, prec=3):
348
348
  p = _MODS.units.Precision_(prec, low=1, high=4) \
349
349
  if prec != 3 else int(prec)
350
350
  m = 2 << p
351
- w = 32 // m # if m in (4, 8, 16, 32)
351
+ w = 32 // m # if _isin(m, 4, 8, 16, 32)
352
352
  # not round(b), half-even rounding in Python 3+, but
353
353
  # round-away-from-zero as int(b + copysign0(_0_5, b))
354
354
  w *= int(b * m / _360_0 + _0_5) % m
@@ -483,7 +483,7 @@ def _latlonDMS_sep2(where, sep=None, **kwds):
483
483
  i = _MODS.inters
484
484
  k = Fmt.EQUAL(sep=repr(sep))
485
485
  k = _SPACE_(i._keyword_, i._arg_, k, i._of_)
486
- n = where.__name__
486
+ n = typename(where)
487
487
  t = _latlonDMS_sep2.__doc__ % (sep, n)
488
488
  _MODS.props._throwarning(k, n, t)
489
489
  return sep, kwds
@@ -670,7 +670,7 @@ def _DDDMMSS6(t, S):
670
670
  # check [D]DDMMSS form and compass point
671
671
  X = _EW_ if isodd(n) else _NS_
672
672
  if not (P in X or (S in X and (P.isdigit() or P == _DOT_))):
673
- t = parseDDDMMSS.__name__[5 if isodd(n) else 6:]
673
+ t = typename(parseDDDMMSS)[(5 if isodd(n) else 6):]
674
674
  t = _SPACE_('form', t, 'applies', _DASH_.join(X))
675
675
  raise ParseError(t)
676
676
  else:
pygeodesy/ecef.py CHANGED
@@ -57,24 +57,25 @@ for conversion between geodetic and I{local cartesian} coordinates in a I{local
57
57
  plane} as opposed to I{geocentric} (ECEF) ones.
58
58
  '''
59
59
 
60
- from pygeodesy.basics import copysign0, isscalar, issubclassof, neg, map1, \
61
- _xinstanceof, _xsubclassof # _args_kwds_names
60
+ from pygeodesy.basics import copysign0, _isin, isscalar, issubclassof, neg, map1, \
61
+ _xinstanceof, _xsubclassof, typename # _args_kwds_names
62
62
  from pygeodesy.constants import EPS, EPS0, EPS02, EPS1, EPS2, EPS_2, INT0, PI, PI_2, \
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 a_f2Tuple, _ellipsoidal_datum, _WGS84, _EWGS84
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, Fpowers, hypot, hypot1, hypot2_, sqrt0
71
+ from pygeodesy.fmath import cbrt, fdot, hypot, hypot1, hypot2_, sqrt0
71
72
  from pygeodesy.fsums import Fsum, fsumf_, Fmt, unstr
73
+ # from pygeodesy.internals import typename # from .basics
72
74
  from pygeodesy.interns import NN, _a_, _C_, _datum_, _ellipsoid_, _f_, _height_, \
73
75
  _lat_, _lon_, _M_, _name_, _singular_, _SPACE_, \
74
76
  _x_, _xyz_, _y_, _z_
75
77
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
76
- from pygeodesy.named import _name__, _name1__, _NamedBase, _NamedLocal, \
77
- _NamedTuple, _Pass, _xnamed
78
+ from pygeodesy.named import _name__, _name1__, _NamedBase, _NamedTuple, _Pass, _xnamed
78
79
  from pygeodesy.namedTuples import LatLon2Tuple, LatLon3Tuple, \
79
80
  PhiLam2Tuple, Vector3Tuple, Vector4Tuple
80
81
  from pygeodesy.props import deprecated_method, Property_RO, property_RO, \
@@ -89,7 +90,7 @@ from pygeodesy.utily import atan1, atan1d, atan2, atan2d, degrees90, degrees180,
89
90
  from math import cos, degrees, fabs, radians, sqrt
90
91
 
91
92
  __all__ = _ALL_LAZY.ecef
92
- __version__ = '24.12.06'
93
+ __version__ = '25.04.28'
93
94
 
94
95
  _Ecef_ = 'Ecef'
95
96
  _prolate_ = 'prolate'
@@ -109,6 +110,7 @@ class _EcefBase(_NamedBase):
109
110
  '''
110
111
  _datum = _WGS84
111
112
  _E = _EWGS84
113
+ _isYou = False
112
114
  _lon00 = INT0 # arbitrary, "polar" lon for LocalCartesian, Ltp
113
115
 
114
116
  def __init__(self, a_ellipsoid=_EWGS84, f=None, lon00=INT0, **name):
@@ -138,7 +140,7 @@ class _EcefBase(_NamedBase):
138
140
  else:
139
141
  raise ValueError() # _invalid_
140
142
 
141
- if E not in (_EWGS84, _WGS84):
143
+ if not _isin(E, _EWGS84, _WGS84):
142
144
  d = _ellipsoidal_datum(E, **name)
143
145
  E = d.ellipsoid
144
146
  if E.a < EPS or E.f > EPS1:
@@ -271,12 +273,6 @@ class _EcefBase(_NamedBase):
271
273
  return (Ecef9Tuple, # overwrite property_ROver
272
274
  _MODS.vector3d.Vector3d) # _MODS.cartesianBase.CartesianBase
273
275
 
274
- @Property_RO
275
- def _isYou(self):
276
- '''(INTERNAL) Is this an C{EcefYou}?.
277
- '''
278
- return isinstance(self, EcefYou)
279
-
280
276
  @property
281
277
  def lon00(self):
282
278
  '''Get the I{"polar"} longitude (C{degrees}), see method C{reverse}.
@@ -789,6 +785,7 @@ class EcefYou(_EcefBase):
789
785
  11589/115114_9021_geod2ellip_final.pdf>} Studia Geophysica et Geodaetica, 2008, 52,
790
786
  pages 1-18 and U{PyMap3D <https://PyPI.org/project/pymap3d>}.
791
787
  '''
788
+ _isYou = True
792
789
 
793
790
  def __init__(self, a_ellipsoid=_EWGS84, f=None, **lon00_name): # PYCHOK signature
794
791
  _EcefBase.__init__(self, a_ellipsoid, f=f, **lon00_name) # inherited documentation
@@ -824,13 +821,14 @@ class EcefYou(_EcefBase):
824
821
  ellipsoid is I{prolate}.
825
822
  '''
826
823
  x, y, z, name = _xyzn4(xyz, y, z, self._Geocentrics, **lon00_name)
824
+ q = hypot(x, y) # R
827
825
 
828
826
  E = self.ellipsoid
829
827
  e, e2 = self._ee2
830
828
 
831
- q = hypot(x, y) # R
832
- u = Fpowers(2, x, y, z) - e2
833
- u = u.fadd_(hypot(u, e * z * _2_0)).fover(_2_0)
829
+ u = hypot2_(x, y, z) - e2
830
+ u += hypot(u, e * z * _2_0)
831
+ u *= _0_5
834
832
  if u > EPS02:
835
833
  u = sqrt(u)
836
834
  p = hypot(u, e)
@@ -956,7 +954,7 @@ class EcefMatrix(_NamedTuple):
956
954
  # <https://GeographicLib.SourceForge.io/C++/doc/LocalCartesian_8cpp_source.html>
957
955
  # X = (fdot(self.column(r), *other.column(c)) for r in (0,1,2) for c in (0,1,2))
958
956
  X = (fdot(self[r::3], *other[c::3]) for r in range(3) for c in range(3))
959
- return _xnamed(EcefMatrix(*X), EcefMatrix.multiply.__name__)
957
+ return _xnamed(EcefMatrix(*X), typename(EcefMatrix.multiply))
960
958
 
961
959
  def rotate(self, xyz, *xyz0):
962
960
  '''Forward rotation M{M0' ⋅ ([x, y, z] - [x0, y0, z0])'}.
@@ -1018,7 +1016,7 @@ class EcefMatrix(_NamedTuple):
1018
1016
  return xyz_
1019
1017
 
1020
1018
 
1021
- class Ecef9Tuple(_NamedTuple, _NamedLocal):
1019
+ class Ecef9Tuple(_NamedTuple, _EcefLocal):
1022
1020
  '''9-Tuple C{(x, y, z, lat, lon, height, C, M, datum)} with I{geocentric} C{x},
1023
1021
  C{y} and C{z} plus I{geodetic} C{lat}, C{lon} and C{height}, case C{C} (see
1024
1022
  the C{Ecef*.reverse} methods) and optionally, rotation matrix C{M} (L{EcefMatrix})
@@ -1040,7 +1038,7 @@ class Ecef9Tuple(_NamedTuple, _NamedLocal):
1040
1038
  return self.toDatum(datum2)
1041
1039
 
1042
1040
  @property_RO
1043
- def _ecef9(self):
1041
+ def _ecef9(self): # in ._EcefLocal._Ltp_ecef2local
1044
1042
  return self
1045
1043
 
1046
1044
  @Property_RO
@@ -1102,13 +1100,6 @@ class Ecef9Tuple(_NamedTuple, _NamedLocal):
1102
1100
  '''
1103
1101
  return Lon(Vermeille=degrees(self.lamVermeille))
1104
1102
 
1105
- def _ltp_toLocal(self, ltp, Xyz_kwds, **Xyz): # overloads C{_NamedLocal}'s
1106
- '''(INTERNAL) Invoke C{ltp._xLtp(ltp)._ecef2local}.
1107
- '''
1108
- Xyz_ = self._ltp_toLocal2(Xyz_kwds, **Xyz) # in ._NamedLocal
1109
- ltp = self._ltp._xLtp(ltp, self._Ltp) # both in ._NamedLocal
1110
- return ltp._ecef2local(self, *Xyz_)
1111
-
1112
1103
  @Property_RO
1113
1104
  def phi(self):
1114
1105
  '''Get the latitude in C{radians} (C{float}).
@@ -1141,6 +1132,8 @@ class Ecef9Tuple(_NamedTuple, _NamedLocal):
1141
1132
  '''
1142
1133
  return PhiLam2Tuple(radians(self.lat), self.lamVermeille, name=self.name)
1143
1134
 
1135
+ phiVermeille = phi
1136
+
1144
1137
  def toCartesian(self, Cartesian=None, **Cartesian_kwds):
1145
1138
  '''Return the geocentric C{(x, y, z)} coordinates as an ellipsoidal or spherical
1146
1139
  C{Cartesian}.
@@ -1157,7 +1150,7 @@ class Ecef9Tuple(_NamedTuple, _NamedLocal):
1157
1150
 
1158
1151
  @raise TypeError: Invalid B{C{Cartesian}} or B{C{Cartesian_kwds}} item.
1159
1152
  '''
1160
- if Cartesian in (None, Vector4Tuple):
1153
+ if _isin(Cartesian, None, Vector4Tuple):
1161
1154
  r = self.xyzh
1162
1155
  elif Cartesian is Vector3Tuple:
1163
1156
  r = self.xyz
@@ -1177,7 +1170,7 @@ class Ecef9Tuple(_NamedTuple, _NamedLocal):
1177
1170
  @raise TypeError: The B{C{datum2}} is not a L{Datum}.
1178
1171
  '''
1179
1172
  n = _name__(name, _or_nameof=self)
1180
- if self.datum in (None, datum2): # PYCHOK _Names_
1173
+ if _isin(self.datum, None, datum2): # PYCHOK _Names_
1181
1174
  r = self.copy(name=n)
1182
1175
  else:
1183
1176
  c = self._CartesianBase(self, datum=self.datum, name=n) # PYCHOK _Names_
@@ -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/elevations.py CHANGED
@@ -21,11 +21,12 @@ U{USGS10mElev.py<https://Gist.GitHub.com/pyRobShrk>}.
21
21
  C{"/Applications/Python\\ X.Y/Install\\ Certificates.command"}
22
22
  '''
23
23
 
24
- from pygeodesy.basics import clips, ub2str
24
+ from pygeodesy.basics import clips, ub2str, typename
25
25
  from pygeodesy.errors import ParseError, _xkwds_get
26
- from pygeodesy.interns import NN, _AMPERSAND_, _COLONSPACE_, \
27
- _elevation_, _height_, _LCURLY_, \
28
- _n_a_, _no_, _RCURLY_, _SPACE_
26
+ # from pygeodesy.internals import typename # from .basics
27
+ from pygeodesy.interns import NN, _AMPERSAND_, _COLONSPACE_, _DMAIN_, \
28
+ _elevation_, _height_, _LCURLY_, _n_a_, \
29
+ _no_, _RCURLY_, _SPACE_
29
30
  from pygeodesy.lazily import _ALL_LAZY
30
31
  from pygeodesy.named import _NamedTuple
31
32
  from pygeodesy.streprs import fabs, Fmt, fstr, lrstrip
@@ -34,7 +35,7 @@ from pygeodesy.units import Lat, Lon, Meter, Scalar, Str
34
35
  # from math import fabs # from .karney
35
36
 
36
37
  __all__ = _ALL_LAZY.elevations
37
- __version__ = '24.06.11'
38
+ __version__ = '25.04.14'
38
39
 
39
40
  try:
40
41
  from urllib2 import urlopen # quote, urlcleanup
@@ -91,7 +92,7 @@ except ImportError:
91
92
  def _error(fun, lat, lon, e):
92
93
  '''(INTERNAL) Format an error
93
94
  '''
94
- return _COLONSPACE_(Fmt.PAREN(fun.__name__, fstr((lat, lon))), e)
95
+ return _COLONSPACE_(Fmt.PAREN(typename(fun), fstr((lat, lon))), e)
95
96
 
96
97
 
97
98
  def _qURL(url, timeout=2, **params):
@@ -243,14 +244,14 @@ def geoidHeight2(lat, lon, model=0, timeout=2.0):
243
244
  return GeoidHeight2Tuple(None, e)
244
245
 
245
246
 
246
- if __name__ == '__main__':
247
+ if __name__ == _DMAIN_:
247
248
 
248
249
  from pygeodesy import printf
249
250
  # <https://WikiPedia.org/wiki/Mount_Diablo>
250
251
  for f in (elevation2, # (1173.79, '3DEP 1/3 arc-second')
251
252
  geoidHeight2): # (-31.699, u'GEOID12B')
252
253
  t = f(37.8816, -121.9142)
253
- printf(_COLONSPACE_(f.__name__, t))
254
+ printf(_COLONSPACE_(typename(f), t))
254
255
 
255
256
  # **) MIT License
256
257
  #
@@ -12,30 +12,41 @@ and published under the same MIT Licence**, see for example U{latlon-ellipsoidal
12
12
  # make sure int/int division yields float quotient, see .basics
13
13
  from __future__ import division as _; del _ # PYCHOK semicolon
14
14
 
15
- # from pygeodesy.basics import _xinstanceof # from .datums
15
+ # from pygeodesy.azimuthal import EquidistantExact, EquidistantKarney # _MODS
16
+ from pygeodesy.basics import _isin, _xinstanceof
16
17
  from pygeodesy.constants import EPS, EPS0, EPS1, _0_0, _0_5
17
18
  from pygeodesy.cartesianBase import CartesianBase # PYCHOK used!
19
+ # from pygeodesy.css import toCss # _MODS
18
20
  from pygeodesy.datums import Datum, Datums, _earth_ellipsoid, _ellipsoidal_datum, \
19
- Transform, _WGS84, _EWGS84, _xinstanceof # _spherical_datum
21
+ Transform, _WGS84, _EWGS84 # _spherical_datum
22
+ # from pygeodesy.dms import parse3llh # _MODS
23
+ # from pygeodesy.elevations import elevation2, geoidHeight2 # _MODS
24
+ # from pygeodesy.ellipsoidalBaseDI import _intersect3, _intersections2, _nearestOn2 # _MODS
20
25
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
21
26
  from pygeodesy.errors import _IsnotError, RangeError, _TypeError, _xattr, _xellipsoidal, \
22
27
  _xellipsoids, _xError, _xkwds, _xkwds_not
28
+ # from pygeodesy.etm import etm, toEtm8 # _MODS
23
29
  # from pygeodesy.fmath import favg # _MODS
24
30
  from pygeodesy.interns import NN, _COMMA_, _ellipsoidal_
25
31
  from pygeodesy.latlonBase import LatLonBase, _trilaterate5, fabs, _Wrap
26
32
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
27
33
  # from pygeodesy.lcc import toLcc # _MODS
28
34
  # from pygeodesy.namedTuples import Vector3Tuple # _MODS
35
+ # from pygeodesy.osgr import toOsgr # _MODS
36
+ # from pygeodesy.points import isenclosedBy # _MODS
29
37
  from pygeodesy.props import deprecated_method, deprecated_property_RO, \
30
38
  Property_RO, property_doc_, property_RO, _update_all
31
- # from pygeodesy.trf import _eT0Ds4 # _MODS
39
+ # from pygeodesy.trf import RefFrame, _toRefFrame # _MODS
32
40
  from pygeodesy.units import Epoch, _isDegrees, Radius_, _1mm as _TOL_M
41
+ # from pygeodesy import ups, utm, utmups # MODS
42
+ # from pygeodesy.utmupsBase import _lowerleft # MODS
33
43
  # from pygeodesy.utily import _Wrap # from .latlonBase
44
+ # from pygeodesy.vector3d import _intersects2 # _MODS
34
45
 
35
46
  # from math import fabs # from .latlonBase
36
47
 
37
48
  __all__ = _ALL_LAZY.ellipsoidalBase
38
- __version__ = '24.12.04'
49
+ __version__ = '25.04.14'
39
50
 
40
51
 
41
52
  class CartesianEllipsoidalBase(CartesianBase):
@@ -246,7 +257,7 @@ class LatLonEllipsoidalBase(LatLonBase):
246
257
  @raise UnitError: Invalid B{C{lat}}, B{C{lon}} or B{C{height}}.
247
258
  '''
248
259
  LatLonBase.__init__(self, latlonh, lon=lon, height=height, wrap=wrap, **name)
249
- if datum not in (None, self._datum, _EWGS84):
260
+ if not _isin(datum, None, self._datum, _EWGS84):
250
261
  self.datum = _ellipsoidal_datum(datum, name=self.name)
251
262
  if reframe:
252
263
  self.reframe = reframe
@@ -738,7 +749,7 @@ class LatLonEllipsoidalBase(LatLonBase):
738
749
  n = Datums.NAD83.ellipsoid.rocGauss(self.lat)
739
750
  if n > EPS0:
740
751
  # use ratio, datum and NAD83 units may differ
741
- E = self.ellipsoid() if datum in (None, self.datum) else \
752
+ E = self.ellipsoid() if _isin(datum, None, self.datum) else \
742
753
  _earth_ellipsoid(datum)
743
754
  r = E.rocGauss(self.lat)
744
755
  if r > EPS0 and fabs(r - n) > EPS: # EPS1
@@ -1109,9 +1120,9 @@ class LatLonEllipsoidalBase(LatLonBase):
1109
1120
  def _lowerleft(utmups, center):
1110
1121
  '''(INTERNAL) Optionally I{un}-center C{utmups}.
1111
1122
  '''
1112
- if center in (False, 0, _0_0):
1123
+ if _isin(center, False, 0, _0_0):
1113
1124
  u = utmups
1114
- elif center in (True,):
1125
+ elif _isin(center, True):
1115
1126
  u = utmups._lowerleft
1116
1127
  else:
1117
1128
  u = _MODS.utmupsBase._lowerleft(utmups, center)