pygeodesy 25.12.31__py2.py3-none-any.whl → 26.2.2__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/geoids.py CHANGED
@@ -89,18 +89,17 @@ courtesy of SBFRF.
89
89
  # make sure int/int division yields float quotient, see .basics
90
90
  from __future__ import division as _; del _ # noqa: E702 ;
91
91
 
92
- from pygeodesy.basics import _isin, len2, min2, isodd, _splituple, \
93
- ub2str as _ub2str
92
+ from pygeodesy.basics import _isin, len2, min2, isodd, _splituple
94
93
  from pygeodesy.constants import EPS, _float as _F, _1_0, _N_90_0, _180_0, \
95
94
  _N_180_0, _360_0
96
95
  from pygeodesy.datums import Datums, _ellipsoidal_datum, _WGS84
97
96
  # from pygeodesy.dms import parseDMS2 # _MODS
98
97
  from pygeodesy.errors import _incompatible, LenError, RangeError, _SciPyIssue, \
99
98
  _xkwds_pop2
100
- from pygeodesy.fmath import favg, Fdot, fdot, Fhorner, frange
99
+ from pygeodesy.fmath import favg, frange, Fsum
101
100
  # from pygoedesy.formy import heightOrthometric # _MODS
102
- from pygeodesy.heights import _as_llis2, _ascalar, _HeightBase, HeightError, \
103
- _Wrap
101
+ # from pygeodesy.fsums import Fsum # from .fmath
102
+ from pygeodesy.heights import _as_llis2, _ascalar, _HeightBase, HeightError, _Wrap
104
103
  # from pygeodesy.internals import typename, _version2 # _MODS
105
104
  from pygeodesy.interns import NN, _COLONSPACE_, _COMMASPACE_, _DMAIN_, _E_, \
106
105
  _height_, _in_, _kind_, _lat_, _lon_, _mean_, _N_, \
@@ -115,8 +114,8 @@ from pygeodesy.units import Height, Int_, Lat, Lon
115
114
  # from pygeodesy.utily import _Wrap # from .heights
116
115
 
117
116
  from math import floor as _floor
118
- # from os import SEEK_CUR, SEEK_SET # _MODS
119
- # import os.path # _MODS
117
+ # import os as _os # _MODS
118
+ # import os.path # _os.path
120
119
  from struct import calcsize as _calcsize, unpack as _unpack
121
120
  try:
122
121
  from StringIO import StringIO as _BytesIO # reads bytes
@@ -124,9 +123,10 @@ try:
124
123
 
125
124
  except ImportError: # Python 3+
126
125
  from io import BytesIO as _BytesIO # PYCHOK expected
126
+ from pygeodesy.basics import ub2str as _ub2str
127
127
 
128
128
  __all__ = _ALL_LAZY.geoids
129
- __version__ = '25.09.26'
129
+ __version__ = '26.02.02'
130
130
 
131
131
  _assert_ = 'assert'
132
132
  _bHASH_ = b'#'
@@ -135,9 +135,50 @@ _format_ = '%s %r'
135
135
  _header_ = 'header'
136
136
  _intCs = {} # cache int value, del below
137
137
  _lli_ = 'lli'
138
+ _os = _MODS.os
138
139
  _rb_ = 'rb'
139
140
  _supported_ = 'supported'
140
141
 
142
+ if __debug__:
143
+ from pygeodesy.fmath import Fdot as _Dotf, Fhorner as _Hornerf
144
+
145
+ else: # -OO ... runs GeoidKarney 8+X faster (w/o Fwelford)
146
+ from pygeodesy.fsums import _fsum
147
+ from operator import mul as _mul
148
+
149
+ class _GKsum(Fsum): # for GeoidKarney only
150
+
151
+ def __iadd__(self, other):
152
+ xs = other._ps if isinstance(other, _GKsum) else (other,)
153
+ self._ps_acc(self._ps, xs, up=False)
154
+ return self
155
+
156
+ def __imul__(self, x):
157
+ self._ps[:] = (x * p for p in self._ps)
158
+ return self
159
+
160
+ fmul = __imul__ # like .fsums.Fsum
161
+
162
+ def fsum(self): # PYCHOK signature
163
+ return _fsum(self._ps)
164
+
165
+ class _Dotf(_GKsum): # PYCHOK redef
166
+ '''Fast precision dot product M{sum(a[i] * b[i] for i=0..len(a))}
167
+ but for C{float} C{a} and C{b} only.
168
+ '''
169
+ def __init__(self, a, *b):
170
+ self._ps = self._ps_acc([], map(_mul, a, b), up=False)
171
+
172
+ class _Hornerf(_GKsum): # PYCHOK redef
173
+ '''Fast polynomial evaluation M{sum(cs[i] * x**i for i=0..len(cs))}
174
+ but for C{float} C{x} and C{cs} and C{incx=True} only.
175
+ '''
176
+ def __init__(self, x, *cs): # incx=True
177
+ self._ps = []
178
+ for c in reversed(cs): # multiply-accumulate
179
+ self *= x # ps[:] = (x * p for p in ps)
180
+ self += c # self._ps_acc(ps, (c,), up=False)
181
+
141
182
 
142
183
  class GeoidError(HeightError):
143
184
  '''Geoid interpolator C{Geoid...} or interpolation issue.
@@ -484,7 +525,7 @@ class _GeoidBase(_HeightBase):
484
525
 
485
526
  def _load(self, g, dtype=float, n=-1, offset=0, **sep): # sep=NN
486
527
  # numpy.fromfile, like .frombuffer
487
- g.seek(offset, _MODS.os.SEEK_SET)
528
+ g.seek(offset, _os.SEEK_SET)
488
529
  return self.numpy.fromfile(g, dtype, count=n, **sep)
489
530
 
490
531
  @Property_RO
@@ -566,8 +607,8 @@ class _GeoidBase(_HeightBase):
566
607
  def _open(self, geoid, datum, kind, name, smooth):
567
608
  # open the geoid file
568
609
  try:
569
- self._geoid = _MODS.os.path.basename(geoid)
570
- self._sizeB = _MODS.os.path.getsize(geoid)
610
+ self._geoid = _os.path.basename(geoid)
611
+ self._sizeB = _os.path.getsize(geoid)
571
612
  g = open(geoid, _rb_)
572
613
  except (IOError, OSError) as x:
573
614
  raise GeoidError(geoid=geoid, cause=x)
@@ -774,15 +815,11 @@ class GeoidEGM96(_GeoidBase):
774
815
 
775
816
  def _g2ll2(self, lat, lon):
776
817
  # convert grid (lat, lon) to earth (lat, lon)
777
- while lon > _180_0: # Eastern
778
- lon -= _360_0
779
- return -lat, lon # invert lat
818
+ return -lat, _lonE2lon(lon) # invert lat
780
819
 
781
820
  def _ll2g2(self, lat, lon):
782
821
  # convert earth (lat, lon) to grid (lat, lon)
783
- while lon < 0: # Eastern
784
- lon += _360_0
785
- return -lat, lon # invert lat
822
+ return -lat, _lon2lonE(lon) # invert lat
786
823
 
787
824
  if _FOR_DOCS:
788
825
  __call__ = _GeoidBase.__call__
@@ -791,29 +828,27 @@ class GeoidEGM96(_GeoidBase):
791
828
 
792
829
  class GeoidG2012B(_GeoidBase):
793
830
  '''Geoid height interpolator for U{GEOID12B Model
794
- <https://www.NGS.NOAA.gov/GEOID/GEOID12B/>} grids U{CONUS
795
- <https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_CONUS.shtml>},
796
- U{Alaska<https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_AK.shtml>},
797
- U{Hawaii<https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_HI.shtml>},
831
+ <https://Geodesy.NOAA.gov/GEOID/GEOID12B/>} grids U{CONUS
832
+ <https://Geodesy.NOAA.gov/GEOID/GEOID12B/GEOID12B_CONUS.shtml>},
833
+ U{Alaska<https://Geodesy.NOAA.gov/GEOID/GEOID12B/GEOID12B_AK.shtml>},
834
+ U{Hawaii<https://Geodesy.NOAA.gov/GEOID/GEOID12B/GEOID12B_HI.shtml>},
798
835
  U{Guam and Northern Mariana Islands
799
- <https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_GMNI.shtml>},
836
+ <https://Geodesy.NOAA.gov/GEOID/GEOID12B/GEOID12B_GMNI.shtml>},
800
837
  U{Puerto Rico and U.S. Virgin Islands
801
- <https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_PRVI.shtml>} and
802
- U{American Samoa<https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_AS.shtml>}
838
+ <https://Geodesy.NOAA.gov/GEOID/GEOID12B/GEOID12B_PRVI.shtml>} and
839
+ U{American Samoa<https://Geodesy.NOAA.gov/GEOID/GEOID12B/GEOID12B_AS.shtml>}
803
840
  based on C{SciPy} interpolation U{RectBivariateSpline<https://docs.SciPy.org/doc/
804
841
  scipy/reference/generated/scipy.interpolate.RectBivariateSpline.html>}, U{interp2d
805
842
  <https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.interp2d.html>}
806
843
  or U{bisplrep/-ev<https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.
807
844
  bisplrep.html>}.
808
-
809
- Use any of the C{le} (little endian) or C{be} (big endian) C{g2012b*.bin} binary grid files.
810
845
  '''
811
846
  _datum = Datums.NAD83
812
847
 
813
848
  def __init__(self, g2012b_bin, datum=Datums.NAD83, kind=3, smooth=0, **name_crop):
814
849
  '''New L{GeoidG2012B} interpolator.
815
850
 
816
- @arg g2012b_bin: A C{GEOID12B} grid file name (C{.bin}).
851
+ @arg g2012b_bin: A C{GEOID12B} grid file name (C{.bin}, see B{note}).
817
852
  @kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or
818
853
  L{a_f2Tuple}), overriding C{NAD83}.
819
854
  @kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for U{RectBivariateSpline
@@ -827,8 +862,8 @@ class GeoidG2012B(_GeoidBase):
827
862
  @kwarg name_crop: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED keyword argument
828
863
  C{B{crop}=None}.
829
864
 
830
- @raise GeoidError: Invalid B{C{crop}}, B{C{kind}} or B{C{smooth}} or a G2012B grid file
831
- B{C{g2012b_bin}} issue.
865
+ @raise GeoidError: Invalid B{C{crop}}, B{C{kind}} or B{C{smooth}} or a B{C{g2012b_bin}}
866
+ grid file issue.
832
867
 
833
868
  @raise ImportError: Package C{numpy} or C{scipy} not found or not installed.
834
869
 
@@ -840,8 +875,11 @@ class GeoidG2012B(_GeoidBase):
840
875
 
841
876
  @raise TypeError: Invalid B{C{datum}}.
842
877
 
843
- @note: Specify C{B{kind}=-1, -3 or -5} to use C{scipy.interpolate.interp2d}
844
- before or C{scipy.interpolate.bisplrep/-ev} since C{Scipy} version 1.14.
878
+ @note: Only use any of the C{le} (little-endian) or C{be} (big-endian) C{g2012b*.bin}
879
+ I{binary} grid files.
880
+
881
+ @note: Specify C{B{kind}=-1, -3 or -5} to use C{scipy.interpolate.interp2d} I{before}
882
+ or C{scipy.interpolate.bisplrep/-ev} I{since} C{Scipy} version 1.14.
845
883
  '''
846
884
  crop, name = _xkwds_pop2(name_crop, crop=None)
847
885
  if crop is not None:
@@ -871,7 +909,7 @@ class GeoidG2012B(_GeoidBase):
871
909
  p.slat, p.wlon, p.dlat, p.dlon = map(float, self._load(g, en_+'f8', 4))
872
910
  # read all f4 heights, ignoring the first 4xf8 and 3xi4
873
911
  hs = self._load(g, self._endian, n, 44).reshape(p.nlat, p.nlon)
874
- p.wlon -= _360_0 # western-most East longitude to earth (..., lon)
912
+ p.wlon -= _360_0 # western-most lon XXX _lonE2lon
875
913
  _GeoidBase.__init__(self, hs, p)
876
914
 
877
915
  except Exception as x:
@@ -975,12 +1013,12 @@ class GeoidKarney(_GeoidBase):
975
1013
  _CM = (_T(' 0, -1'), # 10x12 cubic matrix [i, j] indices
976
1014
  _T(' 1, -1'),
977
1015
  _T('-1, 0'),
978
- _T(' 0, 0'),
979
- _T(' 1, 0'),
1016
+ _T(' 0, 0'), # _BT[0]
1017
+ _T(' 1, 0'), # _BT[1]
980
1018
  _T(' 2, 0'),
981
1019
  _T('-1, 1'),
982
- _T(' 0, 1'),
983
- _T(' 1, 1'),
1020
+ _T(' 0, 1'), # _BT[2]
1021
+ _T(' 1, 1'), # _BT[3]
984
1022
  _T(' 2, 1'),
985
1023
  _T(' 0, 2'),
986
1024
  _T(' 1, 2'))
@@ -1063,7 +1101,7 @@ class GeoidKarney(_GeoidBase):
1063
1101
  p = self._pgm
1064
1102
  if 0 < x < (p.nlon - 2) and 0 < y < (p.nlat - 2):
1065
1103
  # read 4x4 ushorts, drop the 4 corners
1066
- S = _MODS.os.SEEK_SET
1104
+ S = _os.SEEK_SET
1067
1105
  e = self._4endian
1068
1106
  g = self._egm
1069
1107
  n = self._4u2B
@@ -1099,7 +1137,7 @@ class GeoidKarney(_GeoidBase):
1099
1137
  y, x = int(_floor(fy)), int(_floor(fx))
1100
1138
  fy -= y
1101
1139
  fx -= x
1102
- H = self._ev2d(fy, fx, y, x) # PYCHOK ._ev2k or ._ev3k
1140
+ H = self._ev2d(fy, fx, y, x) # PYCHOK ._ev3k or ._ev2k
1103
1141
  H *= self._pgm.Scale # H.fmul(self._pgm.Scale)
1104
1142
  H += self._pgm.Offset # H.fadd(self._pgm.Offset)
1105
1143
  return H.fsum() # float(H)
@@ -1112,10 +1150,10 @@ class GeoidKarney(_GeoidBase):
1112
1150
  y, x = self._yx_i = yx
1113
1151
  self._yx_t = self._raws(y, x, GeoidKarney._BT)
1114
1152
  t = self._yx_t
1115
- v = _1_0, -fx, fx
1116
- H = Fdot(v, t[0], t[0], t[1]).fmul(_1_0 - fy) # c = a * (1 - fy)
1117
- H += Fdot(v, t[2], t[2], t[3]).fmul(fy) # c += b * fy
1118
- return H
1153
+ v = _1_0, (-fx), fx
1154
+ H = _Dotf(v, t[0], t[0], t[1]).fmul(_1_0 - fy) # c = a * (1 - fy)
1155
+ H += _Dotf(v, t[2], t[2], t[3]).fmul(fy) # c += b * fy
1156
+ return H # Fsum
1119
1157
 
1120
1158
  def _ev3k(self, fy, fx, *yx):
1121
1159
  # compute the cubic 10-tuple and interpolate raw H
@@ -1124,7 +1162,7 @@ class GeoidKarney(_GeoidBase):
1124
1162
  else:
1125
1163
  c0, c3, v = self._c0c3v(*yx)
1126
1164
  # assert len(c3) == self._nterms
1127
- self._yx_t = tuple(fdot(v, *r3) / c0 for r3 in c3)
1165
+ self._yx_t = tuple(_Dotf(v, *r3).fover(c0) for r3 in c3)
1128
1166
  self._yx_i = yx
1129
1167
  # GeographicLib/Geoid.cpp Geoid::height(lat, lon) ...
1130
1168
  # real h = t[0] + fx * (t[1] + fx * (t[3] + fx * t[6])) +
@@ -1132,20 +1170,18 @@ class GeoidKarney(_GeoidBase):
1132
1170
  # fy * (t[5] + fx * t[8] + fy * t[9]));
1133
1171
  t = self._yx_t
1134
1172
  v = _1_0, fx, fy
1135
- H = Fdot(v, t[5], t[8], t[9])
1136
- H *= fy
1137
- H += Fhorner(fx, t[2], t[4], t[7])
1138
- H *= fy
1139
- H += Fhorner(fx, t[0], t[1], t[3], t[6])
1140
- return H
1173
+ H = _Dotf(v, t[5], t[8], t[9])
1174
+ H *= fy
1175
+ H += _Hornerf(fx, t[2], t[4], t[7])
1176
+ H *= fy
1177
+ H += _Hornerf(fx, t[0], t[1], t[3], t[6])
1178
+ return H # Fsum
1141
1179
 
1142
1180
  _ev2d = _ev3k # overriden for kind=2, see ._ev_name
1143
1181
 
1144
1182
  def _g2ll2(self, lat, lon):
1145
1183
  # convert grid (lat, lon) to earth (lat, lon), uncropped
1146
- while lon > _180_0:
1147
- lon -= _360_0
1148
- return lat, lon
1184
+ return lat, _lonE2lon(lon)
1149
1185
 
1150
1186
  def _g2yx2(self, lat, lon):
1151
1187
  # convert grid (lat, lon) to grid (y, x) indices
@@ -1188,9 +1224,7 @@ class GeoidKarney(_GeoidBase):
1188
1224
 
1189
1225
  def _ll2g2(self, lat, lon):
1190
1226
  # convert earth (lat, lon) to grid (lat, lon), uncropped
1191
- while lon < 0:
1192
- lon += _360_0
1193
- return lat, lon
1227
+ return lat, _lon2lonE(lon)
1194
1228
 
1195
1229
  def _llh3minmax(self, highest, *lat2):
1196
1230
  # find highest or lowest, takes 10+ secs for egm2008-1.pgm geoid
@@ -1277,7 +1311,7 @@ class GeoidKarney(_GeoidBase):
1277
1311
  p, g = self._pgm, self._egm
1278
1312
  if g:
1279
1313
  b = p.skip + (y * p.nlon + x) * self._u2B
1280
- g.seek(b, _MODS.os.SEEK_SET)
1314
+ g.seek(b, _os.SEEK_SET)
1281
1315
  return b # position
1282
1316
  raise GeoidError('closed file', txt=repr(p.egm)) # IOError
1283
1317
 
@@ -1347,7 +1381,7 @@ class GeoidPGM(_GeoidBase):
1347
1381
  the available memory, especially with 32-bit Python. To reduce memory
1348
1382
  usage, set keyword argument B{C{crop}} to the region of interest. For
1349
1383
  example C{B{crop}=(20, -125, 50, -65)} covers the U{conterminous US
1350
- <https://www.NGS.NOAA.gov/GEOID/GEOID12B/maps/GEOID12B_CONUS_grids.png>}
1384
+ <https://Geodesy.NOAA.gov/GEOID/GEOID12B/maps/GEOID12B_CONUS_grids.png>}
1351
1385
  (CONUS), less than 3% of the entire C{egm2008-1.pgm} dataset.
1352
1386
 
1353
1387
  @see: Class L{GeoidKarney} and function L{egmGeoidHeights}.
@@ -1382,8 +1416,7 @@ class GeoidPGM(_GeoidBase):
1382
1416
  if self._cropped:
1383
1417
  lon -= self._lon_of
1384
1418
  else:
1385
- while lon > _180_0:
1386
- lon -= _360_0
1419
+ lon = _lonE2lon(lon)
1387
1420
  return lat, lon
1388
1421
 
1389
1422
  def _ll2g2(self, lat, lon):
@@ -1391,8 +1424,7 @@ class GeoidPGM(_GeoidBase):
1391
1424
  if self._cropped:
1392
1425
  lon += self._lon_of
1393
1426
  else:
1394
- while lon < 0:
1395
- lon += _360_0
1427
+ lon = _lon2lonE(lon)
1396
1428
  return lat, lon
1397
1429
 
1398
1430
  if _FOR_DOCS:
@@ -1541,8 +1573,8 @@ class _PGM(_Gpars):
1541
1573
  self.slat, self.wlon = self.Origin
1542
1574
  # note, negative .dlat and .rlat since rows
1543
1575
  # are from .slat 90N down in decreasing lat
1544
- self.dlat, self.dlon = _180_0 / (1 - nlat), _360_0 / nlon
1545
- self.rlat, self.rlon = (1 - nlat) / _180_0, nlon / _360_0
1576
+ self.dlat, self.dlon = (_180_0 / (1 - nlat)), (_360_0 / nlon)
1577
+ self.rlat, self.rlon = ((1 - nlat) / _180_0), (nlon / _360_0)
1546
1578
 
1547
1579
  # grid corners in earth (lat, lon), .slat = 90, .dlat < 0
1548
1580
  n = float(self.slat)
@@ -1604,11 +1636,11 @@ class _PGM(_Gpars):
1604
1636
  t, c = 0, self._tmpfile()
1605
1637
  # reading (s - n) rows, forward
1606
1638
  for y in range(n, s): # PYCHOK y unused
1607
- g.seek(z, _MODS.os.SEEK_SET)
1639
+ g.seek(z, _os.SEEK_SET)
1608
1640
  # Python 2 tmpfile.write returns None
1609
1641
  t += c.write(g.read(r)) or r
1610
1642
  if p: # wrap around to start of row
1611
- g.seek(-q, _MODS.os.SEEK_CUR)
1643
+ g.seek(-q, _os.SEEK_CUR)
1612
1644
  # assert(g.tell() == (z - w * self.u2B))
1613
1645
  # Python 2 tmpfile.write returns None
1614
1646
  t += c.write(g.read(p)) or p
@@ -1635,7 +1667,7 @@ class _PGM(_Gpars):
1635
1667
  self.knots = k
1636
1668
  self.skip = 0 # no header lines in c
1637
1669
 
1638
- c.seek(0, _MODS.os.SEEK_SET)
1670
+ c.seek(0, _os.SEEK_SET)
1639
1671
  # c = open(c.name, _rb_) # reopen for numpy 1.8.0-
1640
1672
  return c
1641
1673
 
@@ -1659,11 +1691,11 @@ class _PGM(_Gpars):
1659
1691
  try:
1660
1692
  from tempfile import NamedTemporaryFile as tmpfile
1661
1693
  except ImportError: # Python 2.7.16-
1662
- from _MODS.os import tmpfile
1663
- t = _MODS.os.path.basename(self.pgm)
1664
- t = _MODS.os.path.splitext(t)[0]
1694
+ from _os import tmpfile # PYCHOK from
1695
+ t = _os.path.basename(self.pgm)
1696
+ t = _os.path.splitext(t)[0]
1665
1697
  f = tmpfile(mode='w+b', prefix=t or 'egm')
1666
- f.seek(0, _MODS.os.SEEK_SET) # force overwrite
1698
+ f.seek(0, _os.SEEK_SET) # force overwrite
1667
1699
  return f
1668
1700
 
1669
1701
  @Property_RO
@@ -1703,7 +1735,7 @@ def egmGeoidHeights(GeoidHeights_dat):
1703
1735
  dat = _BytesIO(dat)
1704
1736
 
1705
1737
  try:
1706
- dat.seek(0, _MODS.os.SEEK_SET) # reset
1738
+ dat.seek(0, _os.SEEK_SET) # reset
1707
1739
  except AttributeError as x:
1708
1740
  raise GeoidError(GeoidHeights_dat=type(dat), cause=x)
1709
1741
 
@@ -1711,11 +1743,26 @@ def egmGeoidHeights(GeoidHeights_dat):
1711
1743
  t = t.strip()
1712
1744
  if t and not t.startswith(_bHASH_):
1713
1745
  lat, lon, egm84, egm96, egm2008 = map(float, t.split())
1714
- while lon > _180_0: # EasternLon to earth lon
1715
- lon -= _360_0
1746
+ lon = _lonE2lon(lon) # Eastern to earth lon
1716
1747
  yield GeoidHeight5Tuple(lat, lon, egm84, egm96, egm2008)
1717
1748
 
1718
1749
 
1750
+ def _lonE2lon(lon):
1751
+ '''(INTERNAL) East to earth longitude.
1752
+ '''
1753
+ while lon > _180_0:
1754
+ lon -= _360_0
1755
+ return lon
1756
+
1757
+
1758
+ def _lon2lonE(lon):
1759
+ '''(INTERNAL) Earth to East longitude.
1760
+ '''
1761
+ while lon < 0:
1762
+ lon += _360_0
1763
+ return lon
1764
+
1765
+
1719
1766
  __all__ += _ALL_DOCS(_GeoidBase)
1720
1767
 
1721
1768
  if __name__ == _DMAIN_: # MCCABE 14
pygeodesy/heights.py CHANGED
@@ -59,7 +59,7 @@ C{>>> h1, h2, ... = hinterpolator.height_(lat1, lon1, lat2, lon2, ...)}
59
59
  L{HeightSmoothBiSpline} require package U{scipy<https://SciPy.org>}.
60
60
  Classes L{HeightIDWkarney} and L{HeightIDWdistanceTo} -if used with
61
61
  L{ellipsoidalKarney.LatLon} points- require I{Karney}'s U{geographiclib
62
- <https://PyPI.org/project/geographiclib>} to be installed.
62
+ <https://PyPI.org/project/geographiclib>} package to be installed.
63
63
 
64
64
  @note: Errors from C{scipy} are raised as L{SciPyError}s. Warnings issued
65
65
  by C{scipy} can be thrown as L{SciPyWarning} exceptions, provided
@@ -92,7 +92,7 @@ from pygeodesy.units import _isDegrees, Float_, Int_
92
92
  # from math import radians # from .points
93
93
 
94
94
  __all__ = _ALL_LAZY.heights
95
- __version__ = '25.09.29'
95
+ __version__ = '26.02.02'
96
96
 
97
97
  _error_ = 'error'
98
98
  _formy = _MODS.into(formy=__name__)
@@ -160,7 +160,7 @@ def _orderedup(ts, lo=EPS, hi=PI2-EPS):
160
160
  return sorted(set(max(lo, min(hi, t)) for t in ts)) # list
161
161
 
162
162
 
163
- def _xyhs(wrap=False, _lat=_90_0, _lon=_180_0, **name_lls):
163
+ def _xyhs(wrap=False, _lat=_90_0, _lon=_180_0, height=True, **name_lls):
164
164
  # map (lat, lon, h) to (x, y, h) in radians, offset
165
165
  # x as 0 <= lon <= PI2 and y as 0 <= lat <= PI
166
166
  name, lls = _xkwds_item2(name_lls)
@@ -168,8 +168,9 @@ def _xyhs(wrap=False, _lat=_90_0, _lon=_180_0, **name_lls):
168
168
  try:
169
169
  for i, ll in enumerate(lls):
170
170
  y, x = _w(ll.lat, ll.lon)
171
- yield max(_0_0, _r(x + _lon)), \
172
- max(_0_0, _r(y + _lat)), ll.height
171
+ h = ll.height if height else 0
172
+ yield (max(_0_0, _r(x + _lon)),
173
+ max(_0_0, _r(y + _lat)), h)
173
174
  except Exception as x:
174
175
  i = Fmt.INDEX(name, i)
175
176
  raise HeightError(i, ll, cause=x)
@@ -266,9 +267,9 @@ class _HeightBase(_HeightNamed): # in .geoids
266
267
  # convert lli C{LatLon}s to tuples or C{NumPy} arrays of
267
268
  # C{SciPy} sphericals and determine the return type
268
269
  atype = self.numpy.array
269
- wrap = _xkwds(wrap, wrap=self._wrap)
270
+ kwds = _xkwds(wrap, wrap=self._wrap, height=False)
270
271
  _as, llis = _as_llis2(llis)
271
- xis, yis, _ = zip(*_xyhs(llis=llis, **wrap)) # PYCHOK yield
272
+ xis, yis, _ = zip(*_xyhs(llis=llis, **kwds)) # PYCHOK yield
272
273
  return _as, atype(xis), atype(yis), llis
273
274
 
274
275
  def _ev(self, *args): # PYCHOK no cover
pygeodesy/internals.py CHANGED
@@ -6,8 +6,8 @@ u'''Mostly INTERNAL functions, except L{machine}, L{print_} and L{printf}.
6
6
  # from pygeodesy.basics import isiterablen, ubstr # _MODS
7
7
  # from pygeodesy.errors import _AttributeError, _error_init, _ImmutableError, _UnexpectedError, _xError2 # _MODS
8
8
  from pygeodesy.interns import _BAR_, _COLON_, _DASH_, _DMAIN_, _DOT_, _ELLIPSIS_, _NL_, NN, \
9
- _pygeodesy_, _PyPy__, _python_, _QUOTE1_, _QUOTE2_, _s_, _sys, \
10
- _SPACE_, _UNDER_
9
+ _NLATvar_, _pygeodesy_, _PyPy__, _python_, _QUOTE1_, _QUOTE2_, \
10
+ _s_, _sys, _SPACE_, _UNDER_
11
11
  from pygeodesy.interns import _COMMA_, _Python_ # PYCHOK used!
12
12
  # from pygeodesy.streprs import anstr, pairs, unstr # _MODS
13
13
 
@@ -459,6 +459,13 @@ def _popen2(cmd, stdin=None): # in .mgrs, .solveBase, .testMgrs
459
459
  return _MODS.basics.ub2str(r).strip(), p.returncode
460
460
 
461
461
 
462
+ def _pregistry(registry):
463
+ '''(INTERNAL) Print all items of a C{registry}.
464
+ '''
465
+ t = [NN] + registry.toRepr(all=True, asorted=True).split(_NL_)
466
+ printf(_NLATvar_.join(i.strip(_COMMA_) for i in t))
467
+
468
+
462
469
  def print_(*args, **nl_nt_prec_prefix__end_file_flush_sep__kwds): # PYCHOK no cover
463
470
  '''Python 3+ C{print}-like formatting and printing.
464
471
 
@@ -709,7 +716,7 @@ def _versions(sep=_SPACE_):
709
716
 
710
717
 
711
718
  __all__ = tuple(map(typename, (machine, print_, printf, typename)))
712
- __version__ = '25.10.26'
719
+ __version__ = '26.01.13'
713
720
 
714
721
  if __name__ == _DMAIN_:
715
722
 
pygeodesy/lazily.py CHANGED
@@ -30,8 +30,8 @@ and line number.
30
30
  from pygeodesy import internals as _internals, interns as _interns, \
31
31
  _isfrozen # DON'T _lazy_import2
32
32
  # from pygeodesy.errors import _error_init, _ImmutableError, _xkwds_item2 # _ALL_MODS
33
- from pygeodesy.internals import _caller3, _envPYGEODESY, _headof, printf, _tailof, \
34
- typename, _versions # _getenv, _PYGEODESY_ENV, \
33
+ from pygeodesy.internals import _caller3, _envPYGEODESY, _headof, printf, _Property_RO, \
34
+ _tailof, typename, _versions # _getenv, _PYGEODESY_ENV, \
35
35
  # _MODS_Base, _MODS.sys_version_info2
36
36
  from pygeodesy.interns import _attribute_, _by_, _COLONSPACE_, _COMMASPACE_, _DALL_, \
37
37
  _DMAIN_, _doesn_t_exist_, _DOT_, _EQUALSPACED_, _from_, \
@@ -234,7 +234,8 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
234
234
  'a_f2b', 'a_f_2b', 'b_f2a', 'b_f_2a',
235
235
  'e2f', 'e22f',
236
236
  'f2e2', 'f2e22', 'f2e32', 'f_2f', 'f2f_', 'f2f2', 'f2n', 'n2e2', 'n2f', 'n2f_'),
237
- elliptic=_a('Elliptic', 'EllipticError', 'Elliptic3Tuple'),
237
+ elliptic=_a('Elliperim', 'Elliptic', 'EllipticError', 'Elliptic3Tuple',
238
+ 'elliperim', 'elliperim_'),
238
239
  epsg=_a('Epsg', 'EPSGError'),
239
240
  errors=_a('AuxError', 'ClipError', 'CrossError', 'GeodesicError', 'IntersectionError',
240
241
  'NumPyError', 'LenError', 'LimitError', 'MGRSError',
@@ -250,10 +251,10 @@ _ALL_LAZY = _NamedEnum_RO(_name='_ALL_LAZY',
250
251
  'fpolynomial', 'fpowers', 'fprod', 'frandoms', 'frange', 'freduce', 'fremainder',
251
252
  'hypot', 'hypot_', 'hypot1', 'hypot2', 'hypot2_',
252
253
  'norm2', 'norm_', 'sqrt0', 'sqrt3', 'sqrt_a', 'zcrt', 'zqrt'),
253
- formy=_a('Elliperim', 'Radical2Tuple',
254
+ formy=_a('Radical2Tuple',
254
255
  'angle2chord', 'antipode', 'antipode_', 'bearing', 'bearing_',
255
256
  'chord2angle', 'compassAngle', 'cosineLaw', 'cosineLaw_',
256
- 'elliperim', 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_',
257
+ 'equirectangular', 'equirectangular4', 'euclidean', 'euclidean_',
257
258
  'excessAbc_', 'excessCagnoli_', 'excessGirard_', 'excessLHuilier_',
258
259
  'excessKarney', 'excessKarney_', 'excessQuad', 'excessQuad_',
259
260
  'flatLocal', 'flatLocal_', 'flatPolar', 'flatPolar_',
@@ -517,10 +518,16 @@ class _ALL_MODS(_internals._MODS_Base):
517
518
  if _headof(n) == _pygeodesy_:
518
519
  yield n, m
519
520
 
521
+ @_Property_RO
522
+ def _triaxials_triaxial5(self):
523
+ '''(INTERNAL) Get module C{triaxial.triaxials}.
524
+ '''
525
+ return self.triaxials.triaxial5
526
+
520
527
  _internals._MODS = _ALL_MODS = _ALL_MODS() # PYCHOK singleton
521
528
 
522
529
  __all__ = _ALL_LAZY.lazily
523
- __version__ = '25.12.23'
530
+ __version__ = '26.01.06'
524
531
 
525
532
 
526
533
  def _ALL_OTHER(*objs):
pygeodesy/lcc.py CHANGED
@@ -651,13 +651,9 @@ def toLcc(latlon, conic=Conics.WRF_Lb, height=None, Lcc=Lcc,
651
651
 
652
652
 
653
653
  if __name__ == _DMAIN_:
654
-
655
- from pygeodesy.interns import _NL_, _NLATvar_
656
- from pygeodesy.lazily import printf
657
-
658
- # __doc__ of this file, force all into registery
659
- t = _NL_ + Conics.toRepr(all=True, asorted=True)
660
- printf(_NLATvar_.join(t.split(_NL_)))
654
+ # __doc__ of this file, force all into registry
655
+ from pygeodesy.internals import _pregistry
656
+ _pregistry(Conics)
661
657
 
662
658
  # **) MIT License
663
659
  #
pygeodesy/named.py CHANGED
@@ -35,7 +35,7 @@ from pygeodesy.streprs import attrs, Fmt, lrstrip, pairs, reprs, unstr
35
35
  # from pygeodesy.units import _toUnit # _MODS
36
36
 
37
37
  __all__ = _ALL_LAZY.named
38
- __version__ = '25.11.13'
38
+ __version__ = '26.01.14'
39
39
 
40
40
  _COMMANL_ = _COMMA_ + _NL_
41
41
  _COMMASPACEDOT_ = _COMMASPACE_ + _DOT_
@@ -658,18 +658,24 @@ class _NamedEnum(_NamedDict):
658
658
  '''(INTERNAL) Check attribute name against given, registered name.
659
659
  '''
660
660
  pypy = _isPyPy()
661
- _isa = isinstance
662
661
  for n, v in kwds.items():
663
- if _isa(v, _LazyNamedEnumItem): # property
662
+ if isinstance(v, _LazyNamedEnumItem): # property
664
663
  assert (n == v.name) if pypy else (n is v.name)
665
664
  # assert not hasattr(self.__class__, n)
666
665
  setattr(self.__class__, n, v)
667
- elif _isa(v, self._item_Classes): # PYCHOK no cover
666
+ elif isinstance(v, self._item_Classes): # PYCHOK no cover
668
667
  assert self[n] is v and getattr(self, n) \
669
668
  and self.find(v) == n
670
669
  else:
671
670
  raise _TypeError(v, name=n)
672
671
 
672
+ def _asserts(self): # in .triaxials.triaxial3
673
+ '''(INTERNAL) Yield all asserted items.
674
+ '''
675
+ for n, p in tuple(type(self).__dict__.items()):
676
+ if isinstance(p, _LazyNamedEnumItem):
677
+ yield n, p
678
+
673
679
  def find(self, item, dflt=None, all=False):
674
680
  '''Find a registered item.
675
681
 
@@ -707,10 +713,8 @@ class _NamedEnum(_NamedDict):
707
713
  case-insensitive} order (C{bool}).
708
714
  '''
709
715
  if all: # instantiate any remaining L{_LazyNamedEnumItem}
710
- _isa = isinstance
711
- for n, p in tuple(type(self).__dict__.items()):
712
- if _isa(p, _LazyNamedEnumItem):
713
- _ = getattr(self, n)
716
+ for n, _ in self._asserts():
717
+ _ = getattr(self, n)
714
718
  return itemsorted(self) if asorted else ADict.items(self)
715
719
 
716
720
  def keys(self, **all_asorted):
@@ -857,7 +861,7 @@ def _lazyNamedEnumItem(name, *args, **kwds):
857
861
 
858
862
 
859
863
  class _NamedEnumItem(_NamedBase):
860
- '''(INTERNAL) Base class for items in a C{_NamedEnum} registery.
864
+ '''(INTERNAL) Base class for items in a C{_NamedEnum} registry.
861
865
  '''
862
866
  _enum = None
863
867
 
pygeodesy/trf.py CHANGED
@@ -1754,7 +1754,7 @@ if __name__ == _DMAIN_:
1754
1754
  t = '%d,%3d,%3d' % t
1755
1755
  printf('# %s = %s = %s %s', f, e, t, x)
1756
1756
 
1757
- # __doc__ of this file, force all into registery
1757
+ # __doc__ of this file, force all into registry
1758
1758
  def _RFs():
1759
1759
  yield NN
1760
1760
  for t in RefFrames.toRepr(all=True).split(_NL_):