pygeodesy 24.7.24__py2.py3-none-any.whl → 24.8.24__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 (57) hide show
  1. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/METADATA +20 -19
  2. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/RECORD +57 -57
  3. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +26 -27
  5. pygeodesy/auxilats/auxAngle.py +2 -2
  6. pygeodesy/auxilats/auxDST.py +3 -3
  7. pygeodesy/azimuthal.py +4 -4
  8. pygeodesy/basics.py +3 -3
  9. pygeodesy/cartesianBase.py +6 -6
  10. pygeodesy/constants.py +11 -11
  11. pygeodesy/css.py +5 -5
  12. pygeodesy/ellipsoidalBase.py +18 -15
  13. pygeodesy/ellipsoidalExact.py +2 -2
  14. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  15. pygeodesy/ellipsoidalKarney.py +2 -2
  16. pygeodesy/ellipsoidalNvector.py +2 -2
  17. pygeodesy/ellipsoidalVincenty.py +7 -6
  18. pygeodesy/ellipsoids.py +3 -3
  19. pygeodesy/epsg.py +3 -3
  20. pygeodesy/fmath.py +2 -1
  21. pygeodesy/formy.py +2 -2
  22. pygeodesy/fsums.py +4 -4
  23. pygeodesy/gars.py +66 -58
  24. pygeodesy/geodesici.py +4 -10
  25. pygeodesy/geodesicx/gx.py +3 -3
  26. pygeodesy/geodesicx/gxarea.py +3 -3
  27. pygeodesy/geodsolve.py +3 -3
  28. pygeodesy/geohash.py +491 -267
  29. pygeodesy/geoids.py +298 -316
  30. pygeodesy/heights.py +176 -194
  31. pygeodesy/internals.py +39 -6
  32. pygeodesy/interns.py +2 -3
  33. pygeodesy/karney.py +2 -2
  34. pygeodesy/latlonBase.py +14 -8
  35. pygeodesy/lazily.py +22 -21
  36. pygeodesy/ltp.py +6 -7
  37. pygeodesy/ltpTuples.py +12 -6
  38. pygeodesy/named.py +5 -4
  39. pygeodesy/namedTuples.py +14 -1
  40. pygeodesy/osgr.py +7 -7
  41. pygeodesy/points.py +2 -2
  42. pygeodesy/resections.py +7 -7
  43. pygeodesy/rhumb/solve.py +3 -3
  44. pygeodesy/simplify.py +10 -10
  45. pygeodesy/sphericalBase.py +3 -3
  46. pygeodesy/sphericalTrigonometry.py +2 -2
  47. pygeodesy/streprs.py +3 -3
  48. pygeodesy/triaxials.py +210 -204
  49. pygeodesy/units.py +36 -19
  50. pygeodesy/unitsBase.py +4 -4
  51. pygeodesy/utmupsBase.py +3 -3
  52. pygeodesy/vector2d.py +158 -51
  53. pygeodesy/vector3d.py +13 -52
  54. pygeodesy/vector3dBase.py +81 -63
  55. pygeodesy/webmercator.py +3 -3
  56. pygeodesy/wgrs.py +109 -101
  57. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/top_level.txt +0 -0
pygeodesy/geoids.py CHANGED
@@ -63,44 +63,45 @@ courtesy of SBFRF.
63
63
  <https://PyPI.org/project/numpy>} and U{scipy<https://PyPI.org/project/scipy>}
64
64
  to be installed.
65
65
 
66
- @note: Errors from C{scipy} are raised as L{SciPyError}s. Warnings issued by
67
- C{scipy} can be thrown as L{SciPyWarning} exceptions, provided Python
68
- C{warnings} are filtered accordingly, see L{SciPyWarning}.
66
+ @note: Errors from C{scipy} are raised as L{SciPyError}s. Warnings issued by C{scipy} can
67
+ be thrown as L{SciPyWarning} exceptions, provided Python C{warnings} are filtered
68
+ accordingly, see L{SciPyWarning}.
69
69
 
70
70
  @see: I{Karney}'s U{GeographicLib<https://GeographicLib.SourceForge.io/C++/doc/index.html>},
71
71
  U{Geoid height<https://GeographicLib.SourceForge.io/C++/doc/geoid.html>} and U{Installing
72
72
  the Geoid datasets<https://GeographicLib.SourceForge.io/C++/doc/geoid.html#geoidinst>},
73
73
  U{SciPy<https://docs.SciPy.org/doc/scipy/reference/interpolate.html>} interpolation
74
- U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
75
- interpolate.RectBivariateSpline.html>} and U{interp2d<https://docs.SciPy.org/doc/scipy/
76
- reference/generated/scipy.interpolate.interp2d.html>}, functions L{elevations.elevation2}
77
- and L{elevations.geoidHeight2}, U{I{Ellispoid vs Orthometric Elevations}<https://
78
- www.YouTube.com/watch?v=dX6a6kCk3Po>} and U{I{Pitfalls Related to Ellipsoid Height
79
- and Height Above Mean Sea Level (AMSL)}<https://Wiki.ROS.org/mavros#mavros.2FPlugins.
80
- Avoiding_Pitfalls_Related_to_Ellipsoid_Height_and_Height_Above_Mean_Sea_Level>}.
74
+ U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.
75
+ RectBivariateSpline.html>}, U{bisplrep/-ev<https://docs.scipy.org/doc/scipy/reference/generated/
76
+ scipy.interpolate.bisplrep.html>} and U{interp2d<https://docs.SciPy.org/doc/scipy/reference/
77
+ generated/scipy.interpolate.interp2d.html>}, functions L{elevations.elevation2} and
78
+ L{elevations.geoidHeight2}, U{I{Ellispoid vs Orthometric Elevations}<https://www.YouTube.com/
79
+ watch?v=dX6a6kCk3Po>} and U{6.22.1 Avoiding Pitfalls Related to Ellipsoid Height and Height
80
+ Above Mean Sea Level<https://Wiki.ROS.org/mavros>}.
81
81
  '''
82
82
  # make sure int/int division yields float quotient, see .basics
83
83
  from __future__ import division as _; del _ # PYCHOK semicolon
84
84
 
85
85
  from pygeodesy.basics import len2, map1, isodd, ub2str as _ub2str
86
- from pygeodesy.constants import EPS, _float as _F, _0_0, _1_0, _180_0, _360_0
86
+ from pygeodesy.constants import EPS, _float as _F, _1_0, _N_90_0, _180_0, \
87
+ _N_180_0, _360_0
87
88
  # from pygeodesy.datums import _ellipsoidal_datum # from .heights
88
89
  # from pygeodesy.dms import parseDMS2 # _MODS
89
- from pygeodesy.errors import _incompatible, LenError, RangeError, SciPyError, \
90
- _SciPyIssue, _xkwds_pop2
90
+ from pygeodesy.errors import _incompatible, LenError, RangeError, _SciPyIssue, \
91
+ _xkwds_pop2
91
92
  from pygeodesy.fmath import favg, Fdot, fdot, Fhorner, frange
92
93
  # from pygoedesy.formy import heightOrthometric # _MODS
93
- from pygeodesy.heights import _as_llis2, _ascalar, _height_called, HeightError, \
94
- _HeightsBase, _ellipsoidal_datum, _Wrap
94
+ from pygeodesy.heights import _as_llis2, _ascalar, _HeightBase, HeightError, \
95
+ _ellipsoidal_datum, _Wrap
95
96
  # from pygeodesy.internals import _version2 # _MODS
96
- from pygeodesy.interns import MISSING, NN, _4_, _COLONSPACE_, _COMMASPACE_, _cubic_, \
97
- _E_, _height_, _in_, _kind_, _lat_, _linear_, _lon_, \
98
- _mean_, _N_, _n_a_, _numpy_, _on_, _outside_, _S_, _s_, \
99
- _scipy_, _SPACE_, _stdev_, _tbd_, _W_, _width_
97
+ from pygeodesy.interns import NN, _COLONSPACE_, _COMMASPACE_, _E_, _height_, \
98
+ _in_, _kind_, _lat_, _lon_, _mean_, _N_, _n_a_, \
99
+ _numpy_, _on_, _outside_, _S_, _s_, _scipy_, \
100
+ _SPACE_, _stdev_, _tbd_, _W_, _width_, _4_
100
101
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
101
102
  from pygeodesy.named import _name__, _Named, _NamedTuple
102
103
  # from pygeodesy.namedTuples import LatLon3Tuple # _MODS
103
- from pygeodesy.props import deprecated_method, Property_RO, property_RO, property_ROver
104
+ from pygeodesy.props import Property_RO, property_RO, property_ROver
104
105
  from pygeodesy.streprs import attrs, Fmt, fstr, pairs
105
106
  from pygeodesy.units import Height, Int_, Lat, Lon
106
107
  # from pygeodesy.utily import _Wrap # from .heights
@@ -117,80 +118,65 @@ except ImportError: # Python 3+
117
118
  from io import BytesIO as _BytesIO # PYCHOK expected
118
119
 
119
120
  __all__ = _ALL_LAZY.geoids
120
- __version__ = '24.07.12'
121
-
122
- _assert_ = 'assert'
123
- _bHASH_ = b'#'
124
- _endian_ = 'endian'
125
- _format_ = '%s %r'
126
- _header_ = 'header'
127
- _intCs = {} # cache int value
128
- _interp2d_ks = {-2: _linear_,
129
- -3: _cubic_,
130
- -5: 'quintic'}
131
- _lli_ = 'lli'
132
- _non_increasing_ = 'non-increasing'
133
- _rb_ = 'rb'
134
- _supported_ = 'supported'
135
-
136
-
137
- class _GeoidBase(_HeightsBase):
121
+ __version__ = '24.08.24'
122
+
123
+ _assert_ = 'assert'
124
+ _bHASH_ = b'#'
125
+ _endian_ = 'endian'
126
+ _format_ = '%s %r'
127
+ _header_ = 'header'
128
+ _intCs = {} # cache int value
129
+ _lli_ = 'lli'
130
+ _non_increasing_ = 'non-increasing'
131
+ _rb_ = 'rb'
132
+ _supported_ = 'supported'
133
+
134
+
135
+ class GeoidError(HeightError):
136
+ '''Geoid interpolator C{Geoid...} or interpolation issue.
137
+ '''
138
+ pass
139
+
140
+
141
+ class _GeoidBase(_HeightBase):
138
142
  '''(INTERNAL) Base class for C{Geoid...}s.
139
143
  '''
144
+ _center = None # (lat, lon, height)
140
145
  _cropped = None
141
- # _datum = _WGS84 # from _HeightsBase
146
+ # _datum = _WGS84 # from _HeightBase
142
147
  _egm = None # open C{egm*.pgm} geoid file
143
148
  _endian = _tbd_
149
+ _Error = GeoidError # in ._HeightBase._as_lls, ...
144
150
  _geoid = _n_a_
145
151
  _hs_y_x = None # numpy 2darray, row-major order
146
- _interp2d = None # interp2d interpolation
147
152
  _kind = 3 # order for interp2d, RectBivariateSpline
148
153
  # _kmin = 2 # min number of knots
149
154
  _knots = 0 # nlat * nlon
150
155
  _mean = None # fixed in GeoidKarney
151
- # _name = NN # _Named
152
156
  _nBytes = 0 # numpy size in bytes, float64
153
157
  _pgm = None # PGM attributes, C{_PGM} or C{None}
154
158
  _sizeB = 0 # geoid file size in bytes
155
159
  _smooth = 0 # used only for RectBivariateSpline
156
160
  _stdev = None # fixed in GeoidKarney
157
161
  _u2B = 0 # np.itemsize or undefined
162
+ _yx_hits = None # cache hits, ala Karney
158
163
 
159
- _lat_d = _0_0 # increment, +tive
160
- _lat_lo = _0_0 # lower lat, south
161
- _lat_hi = _0_0 # upper lat, noth
162
- _lon_d = _0_0 # increment, +tive
163
- _lon_lo = _0_0 # left lon, west
164
- _lon_hi = _0_0 # right lon, east
165
- _lon_of = _0_0 # forward lon offset
166
- _lon_og = _0_0 # reverse lon offset
167
-
168
- _center = None # (lat, lon, height)
169
- _yx_hits = None # cache hits, ala Karney
164
+ # _lat_d = _0_0 # increment, +tive
165
+ # _lat_lo = _0_0 # lower lat, south
166
+ # _lat_hi = _0_0 # upper lat, noth
167
+ # _lon_d = _0_0 # increment, +tive
168
+ # _lon_lo = _0_0 # left lon, west
169
+ # _lon_hi = _0_0 # right lon, east
170
+ # _lon_of = _0_0 # forward lon offset
171
+ # _lon_og = _0_0 # reverse lon offset
170
172
 
171
173
  def __init__(self, hs, p):
172
- '''(INTERNAL) Set up the grid axes, the C{SciPy} interpolator
173
- and several internal geoid attributes.
174
+ '''(INTERNAL) Set up the grid axes, the C{SciPy} interpolator and
175
+ several internal geoid attributes.
174
176
 
175
177
  @arg hs: Grid knots with known height (C{numpy 2darray}).
176
- @arg p: The C{slat, wlon, nlat, nlon, dlat, dlon} and
177
- other geoid parameters (C{INTERNAL}).
178
-
179
- @raise GeoidError: Incompatible grid B{C{hs}} shape or
180
- invalid B{C{kind}}.
181
-
182
- @raise LenError: Mismatch grid B{C{hs}} axis.
183
-
184
- @raise SciPyError: A C{scipy.interpolate.inter2d} or
185
- C{-.RectBivariateSpline} issue.
186
-
187
- @raise SciPyWarning: A C{scipy.interpolate.inter2d} or
188
- C{-.RectBivariateSpline} warning as
189
- exception.
190
-
191
- @note: C{scipy.interpolate.interp2d} has been C{DEPRECATED},
192
- specify keyword argument C{B{kind}=1..5} to use
193
- C{scipy.interpolate.RectBivariateSpline}.
178
+ @arg p: The C{slat, wlon, nlat, nlon, dlat, dlon} and other
179
+ geoid parameters (C{INTERNAL}).
194
180
  '''
195
181
  spi = self.scipy_interpolate
196
182
  # for 2d scipy.interpolate.interp2d(xs, ys, hs, ...) and
@@ -209,28 +195,25 @@ class _GeoidBase(_HeightsBase):
209
195
  # with rows (90..-90) reversed and columns (0..360) wrapped
210
196
  # to Easten longitude, 0 <= east < 180 and 180 <= west < 360
211
197
  k = self.kind
212
- if k in _interp2d_ks: # .interp2d DEPRECATED since scipy 1.10
213
- if self._scipy_version() < (1, 10):
214
- self._interp2d = spi.interp2d(xs, ys, hs, kind=_interp2d_ks[k])
215
- else: # call and overwrite the DEPRECATED .interp2d
216
- self._interp2d = self._interp2d(xs, ys, hs, k)
217
- elif 1 <= k <= 5:
198
+ if k in self._k2interp2d: # see _HeightBase
199
+ self._interp2d(xs, ys, hs, kind=k)
200
+ else: # XXX order ys and xs, see HeightLSQBiSpline
201
+ k = self._kxky(k)
218
202
  self._ev = spi.RectBivariateSpline(ys, xs, hs, bbox=bb, ky=k, kx=k,
219
203
  s=self._smooth).ev
220
- else:
221
- raise GeoidError(kind=k)
222
-
223
204
  self._hs_y_x = hs # numpy 2darray, row-major
224
205
  self._nBytes = hs.nbytes # numpy size in bytes
225
206
  self._knots = p.knots # grid knots
226
- self._lon_of = float(p.flon) # forward offset
227
- self._lon_og = float(p.glon) # reverse offset
228
- # shrink the box by 1 unit on every side
229
- # bb += self._lat_d, -self._lat_d, self._lon_d, -self._lon_d
230
- self._lat_lo = float(bb[0])
231
- self._lat_hi = float(bb[1])
232
- self._lon_lo = float(bb[2] - p.glon)
233
- self._lon_hi = float(bb[3] - p.glon)
207
+ self._lon_of = float(p.flon) # forward offset
208
+ self._lon_og = g = float(p.glon) # reverse offset
209
+ # shrink the bounding box by 1 unit on every side:
210
+ # +self._lat_d, -self._lat_d, +self._lon_d, -self._lon_d
211
+ self._lat_lo, \
212
+ self._lat_hi, \
213
+ self._lon_lo, \
214
+ self._lon_hi = map(float, bb)
215
+ self._lon_lo -= g
216
+ self._lon_hi -= g
234
217
 
235
218
  def __call__(self, *llis, **wrap_H):
236
219
  '''Interpolate the geoid height for one or several locations.
@@ -246,23 +229,19 @@ class _GeoidBase(_HeightsBase):
246
229
  (C{float}) or a list or tuple of interpolated geoid
247
230
  (or orthometric) heights (C{float}s).
248
231
 
249
- @raise GeoidError: Insufficient number of B{C{llis}}, an
250
- invalid B{C{lli}} or the C{egm*.pgm}
251
- geoid file is closed.
232
+ @raise GeoidError: Insufficient number of B{C{llis}}, an invalid
233
+ B{C{lli}} or the C{egm*.pgm} geoid file is closed.
252
234
 
253
- @raise RangeError: An B{C{lli}} is outside this geoid's lat-
254
- or longitude range.
235
+ @raise RangeError: An B{C{lli}} is outside this geoid's lat- or
236
+ longitude range.
255
237
 
256
- @raise SciPyError: A C{scipy.interpolate.inter2d} or
257
- C{-.RectBivariateSpline} issue.
238
+ @raise SciPyError: A C{scipy} issue.
258
239
 
259
- @raise SciPyWarning: A C{scipy.interpolate.inter2d} or
260
- C{-.RectBivariateSpline} warning as
261
- exception.
240
+ @raise SciPyWarning: A C{scipy} warning as exception.
262
241
 
263
- @note: To obtain I{orthometric} heights, each B{C{llis}}
264
- location must have an ellipsoid C{height} or C{h}
265
- attribute, otherwise C{height=0} is used.
242
+ @note: To obtain I{orthometric} heights, each B{C{llis}} location
243
+ must have an ellipsoid C{height} or C{h} attribute, otherwise
244
+ C{height=0} is used.
266
245
 
267
246
  @see: Function L{pygeodesy.heightOrthometric}.
268
247
  '''
@@ -285,9 +264,9 @@ class _GeoidBase(_HeightsBase):
285
264
  def __str__(self):
286
265
  return Fmt.PAREN(self.classname, repr(self.name))
287
266
 
288
- def _called(self, llis, scipy, wrap=False, H=False):
267
+ def _called(self, llis, iscipy, wrap=False, H=False):
289
268
  # handle __call__
290
- _H = _MODS.formy.heightOrthometric if H else None
269
+ _H = self._heightOrthometric if H else None
291
270
  _as, llis = _as_llis2(llis, Error=GeoidError)
292
271
  hs, _w = [], _Wrap._latlonop(wrap)
293
272
  _a, _h = hs.append, self._hGeoid
@@ -297,15 +276,14 @@ class _GeoidBase(_HeightsBase):
297
276
  # orthometric or geoid height
298
277
  _a(_H(lli, N) if _H else N)
299
278
  return _as(hs)
300
-
301
279
  except (GeoidError, RangeError) as x:
302
280
  # XXX avoid str(LatLon()) degree symbols
303
281
  t = _lli_ if _as is _ascalar else Fmt.INDEX(llis=i)
304
282
  lli = fstr((lli.lat, lli.lon), strepr=repr)
305
283
  raise type(x)(t, lli, wrap=wrap, H=H, cause=x)
306
284
  except Exception as x:
307
- if scipy and self.scipy:
308
- raise _SciPyIssue(x)
285
+ if iscipy and self.scipy:
286
+ raise _SciPyIssue(x, self._ev_name)
309
287
  else:
310
288
  raise
311
289
 
@@ -361,11 +339,9 @@ class _GeoidBase(_HeightsBase):
361
339
  '''
362
340
  return self._endian
363
341
 
364
- def _ev(self, y, x): # PYCHOK expected
365
- # only used for .interpolate.interp2d, but
366
- # overwritten for .RectBivariateSpline,
367
- # note (y, x) must be flipped!
368
- return self._interp2d(x, y)
342
+ def _ev(self, y, x): # PYCHOK overwritten with .RectBivariateSpline.ev
343
+ # see methods _HeightBase._ev and -._interp2d
344
+ return self._ev2d(x, y) # (y, x) flipped!
369
345
 
370
346
  def _gaxis2(self, lo, d, n, name):
371
347
  # build grid axis, hi = lo + (n - 1) * d
@@ -407,14 +383,16 @@ class _GeoidBase(_HeightsBase):
407
383
  @raise RangeError: A B{C{lat}} or B{C{lon}} is outside this
408
384
  geoid's lat- or longitude range.
409
385
 
410
- @raise SciPyError: A C{scipy.interpolate.inter2d} or
411
- C{-.RectBivariateSpline} issue.
386
+ @raise SciPyError: A C{scipy} issue.
412
387
 
413
- @raise SciPyWarning: A C{scipy.interpolate.inter2d} or
414
- C{-.RectBivariateSpline} warning as
415
- exception.
388
+ @raise SciPyWarning: A C{scipy} warning as exception.
416
389
  '''
417
- return _height_called(self, lats, lons, Error=GeoidError, **wrap)
390
+ lls = self._as_lls(lats, lons)
391
+ return self(lls, **wrap) # __call__(ll) or __call__(lls)
392
+
393
+ @property_ROver
394
+ def _heightOrthometric(self):
395
+ return _MODS.formy.heightOrthometric # overwrite property_ROver
418
396
 
419
397
  def _hGeoid(self, lat, lon):
420
398
  out = self.outside(lat, lon)
@@ -425,9 +403,9 @@ class _GeoidBase(_HeightsBase):
425
403
 
426
404
  @Property_RO
427
405
  def _highest(self):
428
- '''(INTERNAL) Cache for L{highest} method.
406
+ '''(INTERNAL) Cache for C{.highest}.
429
407
  '''
430
- return self._llh3minmax(True)
408
+ return self._LL3T(self._llh3minmax(True), name__=self.highest)
431
409
 
432
410
  def highest(self, LatLon=None, **unused):
433
411
  '''Return the location and largest height of this geoid.
@@ -447,15 +425,6 @@ class _GeoidBase(_HeightsBase):
447
425
  '''
448
426
  return self._yx_hits
449
427
 
450
- @deprecated_method
451
- def _interp2d(self, xs, ys, hs=(), k=0): # overwritten in .__init__ above
452
- '''DEPRECATED on 23.01.06, use keyword argument C{B{kind}=1..5}.'''
453
- # assert k in _interp2d_ks # and len(hs) == len(xs) == len(ys)
454
- try:
455
- return self.scipy_interpolate.interp2d(xs, ys, hs, kind=_interp2d_ks[k])
456
- except AttributeError as x:
457
- raise SciPyError(interp2d=MISSING, kind=k, cause=x)
458
-
459
428
  @Property_RO
460
429
  def kind(self):
461
430
  '''Get the interpolator kind and order (C{int}).
@@ -484,7 +453,7 @@ class _GeoidBase(_HeightsBase):
484
453
  def _llh3LL(self, llh, LatLon):
485
454
  return llh if LatLon is None else self._xnamed(LatLon(*llh))
486
455
 
487
- def _llh3minmax(self, highest=True, *unused):
456
+ def _llh3minmax(self, highest, *unused):
488
457
  hs, np = self._hs_y_x, self.numpy
489
458
  # <https://docs.SciPy.org/doc/numpy/reference/generated/
490
459
  # numpy.argmin.html#numpy.argmin>
@@ -499,7 +468,7 @@ class _GeoidBase(_HeightsBase):
499
468
 
500
469
  @Property_RO
501
470
  def _lowerleft(self):
502
- '''(INTERNAL) Cache for L{lowerleft}.
471
+ '''(INTERNAL) Cache for C{.lowerleft}.
503
472
  '''
504
473
  return self._llh3(self._lat_lo, self._lon_lo)
505
474
 
@@ -517,7 +486,7 @@ class _GeoidBase(_HeightsBase):
517
486
 
518
487
  @Property_RO
519
488
  def _loweright(self):
520
- '''(INTERNAL) Cache for L{loweright}.
489
+ '''(INTERNAL) Cache for C{.loweright}.
521
490
  '''
522
491
  return self._llh3(self._lat_lo, self._lon_hi)
523
492
 
@@ -531,16 +500,15 @@ class _GeoidBase(_HeightsBase):
531
500
  otherwise a B{C{LatLon}} instance with the lat-, longitude and
532
501
  geoid height of the lower-right, SE grid corner.
533
502
  '''
534
-
535
503
  return self._llh3LL(self._loweright, LatLon)
536
504
 
537
505
  lowerright = loweright # synonymous
538
506
 
539
507
  @Property_RO
540
508
  def _lowest(self):
541
- '''(INTERNAL) Cache for L{lowest}.
509
+ '''(INTERNAL) Cache for C{.lowest}.
542
510
  '''
543
- return self._llh3minmax(False)
511
+ return self._LL3T(self._llh3minmax(False), name__=self.lowest)
544
512
 
545
513
  def lowest(self, LatLon=None, **unused):
546
514
  '''Return the location and lowest height of this geoid.
@@ -566,7 +534,7 @@ class _GeoidBase(_HeightsBase):
566
534
  def name(self):
567
535
  '''Get the name of this geoid (C{str}).
568
536
  '''
569
- return _HeightsBase.name.fget(self) or self._geoid # recursion
537
+ return _HeightBase.name.fget(self) or self._geoid # recursion
570
538
 
571
539
  @Property_RO
572
540
  def nBytes(self):
@@ -587,7 +555,7 @@ class _GeoidBase(_HeightsBase):
587
555
  self._datum = _ellipsoidal_datum(datum, name=name)
588
556
  self._kind = int(kind)
589
557
  if name:
590
- _HeightsBase.name.fset(self, name) # rename
558
+ _HeightBase.name.fset(self, name) # rename
591
559
  if smooth:
592
560
  self._smooth = Int_(smooth=smooth, Error=GeoidError, low=0)
593
561
 
@@ -647,8 +615,8 @@ class _GeoidBase(_HeightsBase):
647
615
  swne = crop
648
616
  if len(swne) == 4:
649
617
  s, w, n, e = map(float, swne)
650
- if -90 <= s <= (n - _1_0) <= 89 and \
651
- -180 <= w <= (e - _1_0) <= 179:
618
+ if _N_90_0 <= s <= (n - _1_0) <= 89.0 and \
619
+ _N_180_0 <= w <= (e - _1_0) <= 179.0:
652
620
  return s, w, n, e
653
621
  except (IndexError, TypeError, ValueError):
654
622
  pass
@@ -684,7 +652,7 @@ class _GeoidBase(_HeightsBase):
684
652
 
685
653
  @Property_RO
686
654
  def _upperleft(self):
687
- '''(INTERNAL) Cache for method L{upperleft}.
655
+ '''(INTERNAL) Cache for C{.upperleft}.
688
656
  '''
689
657
  return self._llh3(self._lat_hi, self._lon_lo)
690
658
 
@@ -702,7 +670,7 @@ class _GeoidBase(_HeightsBase):
702
670
 
703
671
  @Property_RO
704
672
  def _upperright(self):
705
- '''(INTERNAL) Cache for method L{upperright}.
673
+ '''(INTERNAL) Cache for C{.upperright}.
706
674
  '''
707
675
  return self._llh3(self._lat_hi, self._lon_hi)
708
676
 
@@ -719,12 +687,6 @@ class _GeoidBase(_HeightsBase):
719
687
  return self._llh3LL(self._upperright, LatLon)
720
688
 
721
689
 
722
- class GeoidError(HeightError):
723
- '''Geoid interpolator C{Geoid...} or interpolation issue.
724
- '''
725
- pass
726
-
727
-
728
690
  class GeoidG2012B(_GeoidBase):
729
691
  '''Geoid height interpolator for U{GEOID12B Model
730
692
  <https://www.NGS.NOAA.gov/GEOID/GEOID12B/>} grids U{CONUS
@@ -736,10 +698,11 @@ class GeoidG2012B(_GeoidBase):
736
698
  U{Puerto Rico and U.S. Virgin Islands
737
699
  <https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_PRVI.shtml>} and
738
700
  U{American Samoa<https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_AS.shtml>}
739
- based on C{SciPy} U{RectBivariateSpline<https://docs.SciPy.org/doc/
740
- scipy/reference/generated/scipy.interpolate.RectBivariateSpline.html>}
741
- or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/
742
- scipy.interpolate.interp2d.html>} interpolation.
701
+ based on C{SciPy} U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/
702
+ reference/generated/scipy.interpolate.RectBivariateSpline.html>}, U{interp2d
703
+ <https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate
704
+ .interp2d.html>} or U{bisplrep/-ev<https://docs.scipy.org/doc/scipy/reference/
705
+ generated/scipy.interpolate.bisplrep.html>} interpolation.
743
706
 
744
707
  Use any of the binary C{le} (little endian) or C{be} (big endian)
745
708
  C{g2012b*.bin} grid files.
@@ -749,38 +712,34 @@ class GeoidG2012B(_GeoidBase):
749
712
  '''New L{GeoidG2012B} interpolator.
750
713
 
751
714
  @arg g2012b_bin: A C{GEOID12B} grid file name (C{.bin}).
752
- @kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2}
753
- or L{a_f2Tuple}), default C{WGS84}.
754
- @kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for
755
- U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/
756
- reference/generated/scipy.interpolate.RectBivariateSpline.html>},
757
- -2 for U{interp2d linear<https://docs.SciPy.org/doc/scipy/
758
- reference/generated/scipy.interpolate.interp2d.html>}, -3
759
- for C{interp2d cubic} or -5 for C{interp2d quintic}.
760
- @kwarg smooth: Smoothing factor for U{RectBivariateSpline
761
- <https://docs.SciPy.org/doc/scipy/reference/generated/
762
- scipy.interpolate.RectBivariateSpline.html>}
763
- only (C{int}).
764
- @kwarg name_crop: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED
765
- keyword argument C{B{crop}}, use C{B{crop}=None} to ignore.
766
-
767
- @raise GeoidError: G2012B grid file B{C{g2012b_bin}} issue or invalid
768
- B{C{crop}}, B{C{kind}} or B{C{smooth}}.
769
-
770
- @raise ImportError: Package C{numpy} or C{scipy} not found or not
771
- installed.
715
+ @kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or
716
+ L{a_f2Tuple}), default C{WGS84}.
717
+ @kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for U{RectBivariateSpline
718
+ <https://docs.SciPy.org/doc/scipy/ reference/generated/scipy.interpolate.
719
+ RectBivariateSpline.html>} or -1, -3 or -5 for U{bisplrep/-ev<https://
720
+ docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.bisplrep.html>}
721
+ or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
722
+ interpolate.interp2d.html>} C{linear}, C{cubic} respectively C{quintic},
723
+ see note for more details.
724
+ @kwarg smooth: Smoothing factor for C{B{kind}=1..5} only (C{int}).
725
+ @kwarg name_crop: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED keyword argument
726
+ C{B{crop}=None}.
727
+
728
+ @raise GeoidError: Invalid B{C{crop}}, B{C{kind}} or B{C{smooth}} or a G2012B grid file
729
+ B{C{g2012b_bin}} issue.
730
+
731
+ @raise ImportError: Package C{numpy} or C{scipy} not found or not installed.
772
732
 
773
733
  @raise LenError: Grid file B{C{g2012b_bin}} axis mismatch.
774
734
 
775
- @raise SciPyError: A C{RectBivariateSpline} or C{inter2d} issue.
735
+ @raise SciPyError: A C{scipy} issue.
776
736
 
777
- @raise SciPyWarning: A C{RectBivariateSpline} or C{inter2d}
778
- warning as exception.
737
+ @raise SciPyWarning: A C{scipy} warning as exception.
779
738
 
780
739
  @raise TypeError: Invalid B{C{datum}}.
781
740
 
782
- @note: C{scipy.interpolate.interp2d} has been C{DEPRECATED}, specify
783
- C{B{kind}=1..5} for C{scipy.interpolate.RectBivariateSpline}.
741
+ @note: Specify C{B{kind}=-1, -3 or -5} to use C{scipy.interpolate.interp2d}
742
+ before or C{scipy.interpolate.bisplrep/-ev} since C{Scipy} version 1.14.
784
743
  '''
785
744
  crop, name = _xkwds_pop2(name_crop, crop=None)
786
745
  if crop is not None:
@@ -923,6 +882,7 @@ class GeoidKarney(_GeoidBase):
923
882
  _T( 0, 2),
924
883
  _T( 1, 2))
925
884
 
885
+ # _cropped = None
926
886
  _endian = '>H' # struct.unpack 1 ushort (big endian, unsigned short)
927
887
  _4endian = '>4H' # struct.unpack 4 ushorts
928
888
  _Rendian = NN # struct.unpack a row of ushorts
@@ -940,9 +900,9 @@ class GeoidKarney(_GeoidBase):
940
900
  _u2B = _calcsize(_endian) # pixelsize_ in bytes
941
901
  _4u2B = _calcsize(_4endian) # 4 pixelsize_s in bytes
942
902
  _Ru2B = 0 # row of pixelsize_s in bytes
943
- _yxH = () # cache (y, x) indices
944
- _yxHt = () # cached 4- or 10-tuple for _ev2H resp. _ev3H
945
903
  _yx_hits = 0 # cache hits
904
+ _yx_i = () # cached (y, x) indices
905
+ _yx_t = () # cached 4- or 10-tuple for _ev2k resp. _ev3k
946
906
 
947
907
  def __init__(self, egm_pgm, crop=None, datum=None, # WGS84
948
908
  kind=3, **name_smooth):
@@ -952,34 +912,31 @@ class GeoidKarney(_GeoidBase):
952
912
  C++/doc/geoid.html#geoidinst>} file name (C{egm*.pgm}), see
953
913
  note below.
954
914
  @kwarg crop: Optional box to limit geoid locations, a 4-tuple (C{south,
955
- west, north, east}), 2-tuple (C{(south, west), (north,
956
- east)}) or 2, in C{degrees90} lat- and C{degrees180}
957
- longitudes or a 2-tuple (C{LatLonSW, LatLonNE}) of
958
- C{LatLon} instances.
959
- @kwarg datum: Optional grid datum (C{Datum}, L{Ellipsoid}, L{Ellipsoid2}
960
- or L{a_f2Tuple}), default C{WGS84}.
961
- @kwarg kind: Interpolation order (C{int}), 2 for C{bilinear} or 3
962
- for C{cubic}.
915
+ west, north, east}), 2-tuple (C{(south, west), (north, east)})
916
+ with 2 C{degrees90} lat- and C{degrees180} longitudes or as
917
+ 2-tuple (C{LatLonSW, LatLonNE}) of C{LatLon} instances.
918
+ @kwarg datum: Optional grid datum (C{Datum}, L{Ellipsoid}, L{Ellipsoid2} or
919
+ L{a_f2Tuple}), default C{WGS84}.
920
+ @kwarg kind: Interpolation order (C{int}), 2 for C{bilinear} or 3 for C{cubic}.
963
921
  @kwarg name_smooth: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED
964
922
  keyword argument C{B{smooth}}, use C{B{smooth}=None} to ignore.
965
923
 
966
- @raise GeoidError: EGM dataset B{C{egm_pgm}} issue or invalid
967
- B{C{crop}}, B{C{kind}} or B{C{smooth}}.
924
+ @raise GeoidError: EGM dataset B{C{egm_pgm}} issue or invalid B{C{crop}},
925
+ B{C{kind}} or B{C{smooth}}.
968
926
 
969
927
  @raise TypeError: Invalid B{C{datum}}.
970
928
 
971
929
  @see: Class L{GeoidPGM} and function L{egmGeoidHeights}.
972
930
 
973
- @note: Geoid file B{C{egm_pgm}} remains open and must be closed
974
- by calling the C{close} method or by using this instance
975
- in a C{with B{GeoidKarney}(...) as ...} context.
931
+ @note: Geoid file B{C{egm_pgm}} remains open and I{must be closed} by calling
932
+ method C{close} or by using C{with B{GeoidKarney}(...) as ...:} context.
976
933
  '''
977
934
  smooth, name = _xkwds_pop2(name_smooth, smooth=None)
978
935
  if smooth is not None:
979
936
  raise GeoidError(smooth=smooth, txt_not_=_supported_)
980
937
 
981
938
  if kind in (2,):
982
- self._evH = self._ev2H
939
+ self._ev2d = self._ev2k # see ._ev_name
983
940
  elif kind not in (3,):
984
941
  raise GeoidError(kind=kind)
985
942
 
@@ -995,7 +952,7 @@ class GeoidKarney(_GeoidBase):
995
952
  # set earth (lat, lon) limits (s, w, n, e)
996
953
  self._lat_lo, self._lon_lo, \
997
954
  self._lat_hi, self._lon_hi = self._swne(crop if crop else p.crop4)
998
- self._cropped = True if crop else False
955
+ self._cropped = bool(crop)
999
956
 
1000
957
  def __call__(self, *llis, **wrap_H):
1001
958
  '''Interpolate the geoid height for one or several locations.
@@ -1011,16 +968,15 @@ class GeoidKarney(_GeoidBase):
1011
968
  (C{float}) or a list or tuple of interpolated geoid
1012
969
  (or orthometric) heights (C{float}s).
1013
970
 
1014
- @raise GeoidError: Insufficient number of B{C{llis}}, an
1015
- invalid B{C{lli}} or the C{egm*.pgm}
1016
- geoid file is closed.
971
+ @raise GeoidError: Insufficient number of B{C{llis}}, an invalid
972
+ B{C{lli}} or the C{egm*.pgm} geoid file is closed.
1017
973
 
1018
- @raise RangeError: An B{C{lli}} is outside this geoid's lat-
1019
- or longitude range.
974
+ @raise RangeError: An B{C{lli}} is outside this geoid's lat- or
975
+ longitude range.
1020
976
 
1021
- @note: To obtain I{orthometric} heights, each B{C{llis}}
1022
- location must have an ellipsoid C{height} or C{h}
1023
- attribute, otherwise C{height=0} is used.
977
+ @note: To obtain I{orthometric} heights, each B{C{llis}} location
978
+ must have an ellipsoid C{height} or C{h} attribute, otherwise
979
+ C{height=0} is used.
1024
980
 
1025
981
  @see: Function L{pygeodesy.heightOrthometric}.
1026
982
  '''
@@ -1068,38 +1024,38 @@ class GeoidKarney(_GeoidBase):
1068
1024
  y, x = int(floor(fy)), int(floor(fx))
1069
1025
  fy -= y
1070
1026
  fx -= x
1071
- H = self._evH(fy, fx, y, x) # ._ev3H or ._ev2H
1027
+ H = self._ev2d(fy, fx, y, x) # PYCHOK ._ev2k or ._ev3k
1072
1028
  H *= self._pgm.Scale # H.fmul(self._pgm.Scale)
1073
1029
  H += self._pgm.Offset # H.fadd(self._pgm.Offset)
1074
- return H.fsum()
1030
+ return H.fsum() # float(H)
1075
1031
 
1076
- def _ev2H(self, fy, fx, *yx):
1032
+ def _ev2k(self, fy, fx, *yx):
1077
1033
  # compute the bilinear 4-tuple and interpolate raw H
1078
- if self._yxH == yx:
1079
- t = self._yxHt
1034
+ if self._yx_i == yx:
1080
1035
  self._yx_hits += 1
1081
1036
  else:
1082
- y, x = self._yxH = yx
1083
- self._yxHt = t = self._raws(y, x, GeoidKarney._BT)
1037
+ y, x = self._yx_i = yx
1038
+ self._yx_t = self._raws(y, x, GeoidKarney._BT)
1039
+ t = self._yx_t
1084
1040
  v = _1_0, -fx, fx
1085
1041
  H = Fdot(v, t[0], t[0], t[1]).fmul(_1_0 - fy) # c = a * (1 - fy)
1086
1042
  H += Fdot(v, t[2], t[2], t[3]).fmul(fy) # c += b * fy
1087
1043
  return H
1088
1044
 
1089
- def _ev3H(self, fy, fx, *yx):
1045
+ def _ev3k(self, fy, fx, *yx):
1090
1046
  # compute the cubic 10-tuple and interpolate raw H
1091
- if self._yxH == yx:
1092
- t = self._yxHt
1047
+ if self._yx_i == yx:
1093
1048
  self._yx_hits += 1
1094
1049
  else:
1095
- self._yxH = yx
1096
- c0, c3, v = self._c0c3v(*yx)
1097
- t = [fdot(v, *c3[i]) / c0 for i in range(self._nterms)]
1098
- self._yxHt = t = tuple(t)
1050
+ c0, c3, v = self._c0c3v(*yx)
1051
+ # assert len(c3) == self._nterms
1052
+ self._yx_t = tuple(fdot(v, *r3) / c0 for r3 in c3)
1053
+ self._yx_i = yx
1099
1054
  # GeographicLib/Geoid.cpp Geoid::height(lat, lon) ...
1100
1055
  # real h = t[0] + fx * (t[1] + fx * (t[3] + fx * t[6])) +
1101
1056
  # fy * (t[2] + fx * (t[4] + fx * t[7]) +
1102
1057
  # fy * (t[5] + fx * t[8] + fy * t[9]));
1058
+ t = self._yx_t
1103
1059
  v = _1_0, fx, fy
1104
1060
  H = Fdot(v, t[5], t[8], t[9])
1105
1061
  H *= fy
@@ -1108,7 +1064,7 @@ class GeoidKarney(_GeoidBase):
1108
1064
  H += Fhorner(fx, t[0], t[1], t[3], t[6])
1109
1065
  return H
1110
1066
 
1111
- _evH = _ev3H # overriden for kind == 2
1067
+ _ev2d = _ev3k # overriden for kind=2, see ._ev_name
1112
1068
 
1113
1069
  def _g2ll2(self, lat, lon):
1114
1070
  # convert grid (lat, lon) to earth (lat, lon), uncropped
@@ -1145,13 +1101,14 @@ class GeoidKarney(_GeoidBase):
1145
1101
  @raise RangeError: A B{C{lat}} or B{C{lon}} is outside this
1146
1102
  geoid's lat- or longitude range.
1147
1103
  '''
1148
- return _height_called(self, lats, lons, Error=GeoidError, **wrap)
1104
+ lls = self._as_lls(lats, lons)
1105
+ return self(lls, **wrap) # __call__(ll) or __call__(lls)
1149
1106
 
1150
1107
  @Property_RO
1151
1108
  def _highest_ltd(self):
1152
- '''(INTERNAL) Cache for L{highest} mesthod.
1109
+ '''(INTERNAL) Cache for C{.highest}.
1153
1110
  '''
1154
- return self._llh3minmax(True, -12, -4)
1111
+ return self._LL3T(self._llh3minmax(True, -12, -4), name__=self.highest)
1155
1112
 
1156
1113
  def highest(self, LatLon=None, full=False): # PYCHOK full
1157
1114
  '''Return the location and largest height of this geoid.
@@ -1181,30 +1138,34 @@ class GeoidKarney(_GeoidBase):
1181
1138
  lon += _360_0
1182
1139
  return lat, lon
1183
1140
 
1184
- def _llh3minmax(self, highest=True, *lat2):
1141
+ def _llh3minmax(self, highest, *lat2):
1185
1142
  # find highest or lowest, takes 10+ secs for egm2008-1.pgm geoid
1186
1143
  # (Python 2.7.16, macOS 10.13.6 High Sierra, iMac 3 GHz Core i3)
1187
- y = x = 0
1188
- h = self._raw(y, x)
1189
1144
  if highest:
1190
- for j, r in self._raw2(*lat2):
1145
+ def _mt(r, h):
1191
1146
  m = max(r)
1192
- if m > h:
1193
- h, y, x = m, j, r.index(m)
1147
+ return m, (m > h)
1148
+
1194
1149
  else: # lowest
1195
- for j, r in self._raw2(*lat2):
1150
+ def _mt(r, h): # PYCHOK redef
1196
1151
  m = min(r)
1197
- if m < h:
1198
- h, y, x = m, j, r.index(m)
1152
+ return m, (m < h)
1153
+
1154
+ y = x = 0
1155
+ h = self._raw(y, x)
1156
+ for j, r in self._raw2(*lat2):
1157
+ m, t = _mt(r, h)
1158
+ if t:
1159
+ h, y, x = m, j, r.index(m)
1199
1160
  h *= self._pgm.Scale
1200
1161
  h += self._pgm.Offset
1201
1162
  return self._g2ll2(*self._gyx2g2(y, x)) + (h,)
1202
1163
 
1203
1164
  @Property_RO
1204
1165
  def _lowest_ltd(self):
1205
- '''(INTERNAL) Cache for L{lowest}.
1166
+ '''(INTERNAL) Cache for C{.lowest}.
1206
1167
  '''
1207
- return self._llh3minmax(False, 0, 8)
1168
+ return self._LL3T(self._llh3minmax(False, 0, 8), name__=self.lowest)
1208
1169
 
1209
1170
  def lowest(self, LatLon=None, full=False): # PYCHOK full
1210
1171
  '''Return the location and lowest height of this geoid.
@@ -1269,25 +1230,21 @@ class GeoidKarney(_GeoidBase):
1269
1230
 
1270
1231
  class GeoidPGM(_GeoidBase):
1271
1232
  '''Geoid height interpolator for I{Karney}'s U{GeographicLib Earth
1272
- Gravitational Model (EGM)<https://GeographicLib.SourceForge.io/C++/doc/
1273
- geoid.html>} geoid U{egm*.pgm<https://GeographicLib.SourceForge.io/
1274
- C++/doc/geoid.html#geoidinst>} datasets but based on C{SciPy}
1275
- U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/reference/
1276
- generated/scipy.interpolate.RectBivariateSpline.html>} or
1277
- U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/
1278
- scipy.interpolate.interp2d.html>} interpolation.
1279
-
1280
- Use any of the U{egm84-, egm96- or egm2008-*.pgm
1281
- <https://GeographicLib.SourceForge.io/C++/doc/geoid.html#geoidinst>}
1282
- datasets. However, unless cropped, an entire C{egm*.pgm} dataset
1283
- is loaded into the C{SciPy} U{RectBivariateSpline<https://docs.SciPy.org/
1284
- doc/scipy/reference/generated/scipy.interpolate.RectBivariateSpline.html>}
1285
- or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/
1286
- scipy.interpolate.interp2d.html>} interpolator and converted from
1287
- 2-byte C{int} to 8-byte C{dtype float64}. Therefore, internal memory
1288
- usage is 4x the U{egm*.pgm<https://GeographicLib.SourceForge.io/C++/doc/
1289
- geoid.html#geoidinst>} file size and may exceed the available memory,
1290
- especially with 32-bit Python, see properties C{.nBytes} and C{.sizeB}.
1233
+ Gravitational Model (EGM)<https://GeographicLib.SourceForge.io/C++/doc/geoid.html>}
1234
+ geoid U{egm*.pgm<https://GeographicLib.SourceForge.io/C++/doc/geoid.html#geoidinst>}
1235
+ datasets but based on C{SciPy} U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/
1236
+ reference/generated/scipy.interpolate.RectBivariateSpline.html>}, U{bisplrep/-ev
1237
+ <https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.bisplrep.html>}
1238
+ or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.
1239
+ interp2d.html>} interpolation.
1240
+
1241
+ Use any of the U{egm84-, egm96- or egm2008-*.pgm <https://GeographicLib.SourceForge.io/
1242
+ C++/doc/geoid.html#geoidinst>} datasets. However, unless cropped, an entire C{egm*.pgm}
1243
+ dataset is loaded into the C{SciPy} interpolator and converted from 2-byte C{int} to
1244
+ 8-byte C{dtype float64}. Therefore, internal memory usage is 4x the U{egm*.pgm
1245
+ <https://GeographicLib.SourceForge.io/C++/doc/geoid.html#geoidinst>} file size and may
1246
+ exceed the available memory, especially with 32-bit Python, see properties C{.nBytes}
1247
+ and C{.sizeB}.
1291
1248
  '''
1292
1249
  _cropped = False
1293
1250
  _endian = '>u2'
@@ -1300,48 +1257,44 @@ class GeoidPGM(_GeoidBase):
1300
1257
  C++/doc/geoid.html#geoidinst>} file name (C{egm*.pgm}).
1301
1258
  @kwarg crop: Optional box to crop B{C{egm_pgm}}, a 4-tuple (C{south, west,
1302
1259
  north, east}) or 2-tuple (C{(south, west), (north, east)}),
1303
- in C{degrees90} lat- and C{degrees180} longitudes or a
1304
- 2-tuple (C{LatLonSW, LatLonNE}) of C{LatLon} instances.
1305
- @kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2}
1306
- or L{a_f2Tuple}), default C{WGS84}.
1307
- @kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for
1308
- U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/
1309
- reference/generated/scipy.interpolate.RectBivariateSpline.html>},
1310
- -2 for U{interp2d linear<https://docs.SciPy.org/doc/scipy/
1311
- reference/generated/scipy.interpolate.interp2d.html>}, -3
1312
- for C{interp2d cubic} or -5 for C{interp2d quintic}.
1313
- @kwarg smooth: Smoothing factor for U{RectBivariateSpline
1314
- <https://docs.SciPy.org/doc/scipy/reference/generated/
1315
- scipy.interpolate.RectBivariateSpline.html>}
1316
- only (C{int}).
1260
+ in C{degrees90} lat- and C{degrees180} longitudes or a 2-tuple
1261
+ (C{LatLonSW, LatLonNE}) of C{LatLon} instances.
1262
+ @kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or
1263
+ L{a_f2Tuple}), default C{WGS84}.
1264
+ @kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for U{RectBivariateSpline
1265
+ <https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.
1266
+ RectBivariateSpline.html>} or -1, -3 or -5 for U{bisplrep/-ev<https://
1267
+ docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.bisplrep.html>}
1268
+ or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
1269
+ interpolate.interp2d.html>} C{linear}, C{cubic} respectively C{quintic},
1270
+ see note for more details.
1271
+ @kwarg smooth: Smoothing factor for C{B{kind}=1..5} only (C{int}).
1317
1272
  @kwarg name: Optional geoid C{B{name}=NN} (C{str}).
1318
1273
 
1319
- @raise GeoidError: EGM dataset B{C{egm_pgm}} issue or invalid B{C{crop}},
1320
- B{C{kind}} or B{C{smooth}}.
1274
+ @raise GeoidError: EGM dataset B{C{egm_pgm}} issue or invalid B{C{crop}}, B{C{kind}}
1275
+ or B{C{smooth}}.
1321
1276
 
1322
1277
  @raise ImportError: Package C{numpy} or C{scipy} not found or not installed.
1323
1278
 
1324
1279
  @raise LenError: EGM dataset B{C{egm_pgm}} axis mismatch.
1325
1280
 
1326
- @raise SciPyError: A C{RectBivariateSpline} or C{inter2d} issue.
1281
+ @raise SciPyError: A C{scipy} issue.
1327
1282
 
1328
- @raise SciPyWarning: A C{RectBivariateSpline} or C{inter2d}
1329
- warning as exception.
1283
+ @raise SciPyWarning: A C{scipy} warning as exception.
1330
1284
 
1331
1285
  @raise TypeError: Invalid B{C{datum}} or unexpected argument.
1332
1286
 
1333
- @note: C{scipy.interpolate.interp2d} has been C{DEPRECATED}, specify
1334
- C{B{kind}=1..5} for C{scipy.interpolate.RectBivariateSpline}.
1335
-
1336
- @note: The U{GeographicLib egm*.pgm<https://GeographicLib.SourceForge.io/
1337
- C++/doc/geoid.html#geoidinst>} file sizes are based on a 2-byte
1338
- C{int} height converted to 8-byte C{dtype float64} for C{scipy}
1339
- interpolators. Therefore, internal memory usage is 4 times the
1340
- C{egm*.pgm} file size and may exceed the available memory,
1341
- especially with 32-bit Python. To reduce memory usage, set
1342
- keyword argument B{C{crop}} to the region of interest. For example
1343
- C{B{crop}=(20, -125, 50, -65)} covers the U{conterminous US<https://
1344
- www.NGS.NOAA.gov/GEOID/GEOID12B/maps/GEOID12B_CONUS_grids.png>}
1287
+ @note: Specify C{B{kind}=-1, -3 or -5} to use C{scipy.interpolate.interp2d}
1288
+ before or C{scipy.interpolate.bisplrep/-ev} since C{Scipy} version 1.14.
1289
+
1290
+ @note: The U{GeographicLib egm*.pgm<https://GeographicLib.SourceForge.io/C++/doc/
1291
+ geoid.html#geoidinst>} file sizes are based on a 2-byte C{int} height
1292
+ converted to 8-byte C{dtype float64} for C{scipy} interpolators. Therefore,
1293
+ internal memory usage is 4 times the C{egm*.pgm} file size and may exceed
1294
+ the available memory, especially with 32-bit Python. To reduce memory
1295
+ usage, set keyword argument B{C{crop}} to the region of interest. For
1296
+ example C{B{crop}=(20, -125, 50, -65)} covers the U{conterminous US
1297
+ <https://www.NGS.NOAA.gov/GEOID/GEOID12B/maps/GEOID12B_CONUS_grids.png>}
1345
1298
  (CONUS), less than 3% of the entire C{egm2008-1.pgm} dataset.
1346
1299
 
1347
1300
  @see: Class L{GeoidKarney} and function L{egmGeoidHeights}.
@@ -1711,9 +1664,10 @@ def egmGeoidHeights(GeoidHeights_dat):
1711
1664
 
1712
1665
  __all__ += _ALL_DOCS(_GeoidBase)
1713
1666
 
1714
- if __name__ == '__main__':
1667
+ if __name__ == '__main__': # MCCABE 14
1715
1668
 
1716
- from pygeodesy.internals import printf, _sys
1669
+ from pygeodesy.internals import printf, _secs2str, _sys, _versions
1670
+ from time import time
1717
1671
 
1718
1672
  _crop = ()
1719
1673
  _GeoidEGM = GeoidKarney
@@ -1737,7 +1691,10 @@ if __name__ == '__main__':
1737
1691
 
1738
1692
  elif geoid[-4:].lower() in ('.pgm',):
1739
1693
  g = _GeoidEGM(geoid, crop=_crop, kind=_kind)
1740
- printf(g.toStr(), nt=1, nl=1)
1694
+ t = time()
1695
+ _ = g.highest()
1696
+ t = _secs2str(time() - t)
1697
+ printf('%s: %s (%s)', g.toStr(), t, _versions(), nl=1, nt=1)
1741
1698
  printf(repr(g.pgm), nt=1)
1742
1699
  # <https://GeographicLib.SourceForge.io/cgi-bin/GeoidEval>:
1743
1700
  # The height of the EGM96 geoid at Timbuktu
@@ -1767,27 +1724,6 @@ if __name__ == '__main__':
1767
1724
  _I = int # PYCHOK unused _I
1768
1725
  del _intCs # trash ints cache
1769
1726
 
1770
- # **) MIT License
1771
- #
1772
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1773
- #
1774
- # Permission is hereby granted, free of charge, to any person obtaining a
1775
- # copy of this software and associated documentation files (the "Software"),
1776
- # to deal in the Software without restriction, including without limitation
1777
- # the rights to use, copy, modify, merge, publish, distribute, sublicense,
1778
- # and/or sell copies of the Software, and to permit persons to whom the
1779
- # Software is furnished to do so, subject to the following conditions:
1780
- #
1781
- # The above copyright notice and this permission notice shall be included
1782
- # in all copies or substantial portions of the Software.
1783
- #
1784
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1785
- # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1786
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1787
- # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1788
- # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1789
- # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1790
- # OTHER DEALINGS IN THE SOFTWARE.
1791
1727
 
1792
1728
  # <https://GeographicLib.SourceForge.io/cgi-bin/GeoidEval>
1793
1729
  # _lowerleft = -90, -179, -30.1500 # egm2008-1.pgm
@@ -1803,23 +1739,23 @@ del _intCs # trash ints cache
1803
1739
  # _upperright = 90, 180, 13.0980 # egm84-15.pgm
1804
1740
 
1805
1741
 
1806
- # % python3 -m pygeodesy.geoids [-Karney] ../testGeoids/egm*.pgm
1742
+ # % python3.12 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1807
1743
  #
1808
- # GeoidKarney('egm2008-1.pgm'): lowerleft(-90.0, -180.0, -30.15), upperright(90.0, 180.0, 14.898), center(0.0, 0.0, 17.226), highest(-8.4, 147.367, 85.839), lowest(4.7, 78.767, -106.911)
1744
+ # GeoidKarney('egm2008-1.pgm'): lowerleft(-90.0, -180.0, -30.15), upperright(90.0, 180.0, 14.898), center(0.0, 0.0, 17.226), highest(-8.4, 147.367, 85.839), lowest(4.7, 78.767, -106.911): 204.334 ms (pygeodesy 24.8.24 Python 3.12.5 64bit arm64 macOS 14.6.1)
1809
1745
  #
1810
1746
  # _PGM('../testGeoids/egm2008-1.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-31 06:54:00', Description='WGS84 EGM2008, 1-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.025, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.001, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008', Vertical_Datum='WGS84'
1811
1747
  #
1812
1748
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1813
1749
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1814
1750
  #
1815
- # GeoidKarney('egm84-15.pgm'): lowerleft(-90.0, -180.0, -29.712), upperright(90.0, 180.0, 13.098), center(0.0, 0.0, 18.33), highest(-4.5, 148.75, 81.33), lowest(4.75, 79.25, -107.34)
1751
+ # GeoidKarney('egm84-15.pgm'): lowerleft(-90.0, -180.0, -29.712), upperright(90.0, 180.0, 13.098), center(0.0, 0.0, 18.33), highest(-4.5, 148.75, 81.33), lowest(4.75, 79.25, -107.34): 1.007 ms (pygeodesy 24.8.24 Python 3.12.5 64bit arm64 macOS 14.6.1)
1816
1752
  #
1817
1753
  # _PGM('../testGeoids/egm84-15.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:02', Description='WGS84 EGM84, 15-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.413, MaxCubicError=0.02, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.018, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/wgs84_180/wgs84_180.html', Vertical_Datum='WGS84'
1818
1754
  #
1819
1755
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.775833, -3.009444): 31.2983 vs 31.2979
1820
1756
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.776, -3.009): 31.2979 vs 31.2979
1821
1757
  #
1822
- # GeoidKarney('egm96-5.pgm'): lowerleft(-90.0, -180.0, -29.535), upperright(90.0, 180.0, 13.605), center(0.0, 0.0, 17.163), highest(-8.167, 147.25, 85.422), lowest(4.667, 78.833, -107.043)
1758
+ # GeoidKarney('egm96-5.pgm'): lowerleft(-90.0, -180.0, -29.535), upperright(90.0, 180.0, 13.605), center(0.0, 0.0, 17.163), highest(-8.167, 147.25, 85.422), lowest(4.667, 78.833, -107.043): 8.509 ms (pygeodesy 24.8.24 Python 3.12.5 64bit arm64 macOS 14.6.1)
1823
1759
  #
1824
1760
  # _PGM('../testGeoids/egm96-5.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:03', Description='WGS84 EGM96, 5-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.14, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.005, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html', Vertical_Datum='WGS84'
1825
1761
  #
@@ -1827,23 +1763,23 @@ del _intCs # trash ints cache
1827
1763
  # Timbuktu GeoidKarney('egm96-5.pgm').height(16.776, -3.009): 28.7067 vs 28.7067
1828
1764
 
1829
1765
 
1830
- # % python3 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1766
+ # % python3.8 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1831
1767
  #
1832
- # GeoidKarney('egm2008-1.pgm'): lowerleft(-90.0, -180.0, -30.15), upperright(90.0, 180.0, 14.898), center(0.0, 0.0, 17.226), highest(-8.4, 147.367, 85.839), lowest(4.7, 78.767, -106.911)
1768
+ # GeoidKarney('egm2008-1.pgm'): lowerleft(-90.0, -180.0, -30.15), upperright(90.0, 180.0, 14.898), center(0.0, 0.0, 17.226), highest(-8.4, 147.367, 85.839), lowest(4.7, 78.767, -106.911): 353.050 ms (pygeodesy 24.8.24 Python 3.8.10 64bit arm64_x86_64 macOS 10.16)
1833
1769
  #
1834
1770
  # _PGM('../testGeoids/egm2008-1.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-31 06:54:00', Description='WGS84 EGM2008, 1-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.025, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.001, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008', Vertical_Datum='WGS84'
1835
1771
  #
1836
1772
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1837
1773
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1838
1774
  #
1839
- # GeoidKarney('egm84-15.pgm'): lowerleft(-90.0, -180.0, -29.712), upperright(90.0, 180.0, 13.098), center(0.0, 0.0, 18.33), highest(-4.5, 148.75, 81.33), lowest(4.75, 79.25, -107.34)
1775
+ # GeoidKarney('egm84-15.pgm'): lowerleft(-90.0, -180.0, -29.712), upperright(90.0, 180.0, 13.098), center(0.0, 0.0, 18.33), highest(-4.5, 148.75, 81.33), lowest(4.75, 79.25, -107.34): 1.727 ms (pygeodesy 24.8.24 Python 3.8.10 64bit arm64_x86_64 macOS 10.16)
1840
1776
  #
1841
1777
  # _PGM('../testGeoids/egm84-15.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:02', Description='WGS84 EGM84, 15-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.413, MaxCubicError=0.02, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.018, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/wgs84_180/wgs84_180.html', Vertical_Datum='WGS84'
1842
1778
  #
1843
1779
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.775833, -3.009444): 31.2983 vs 31.2979
1844
1780
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.776, -3.009): 31.2979 vs 31.2979
1845
1781
  #
1846
- # GeoidKarney('egm96-5.pgm'): lowerleft(-90.0, -180.0, -29.535), upperright(90.0, 180.0, 13.605), center(0.0, 0.0, 17.163), highest(-8.167, 147.25, 85.422), lowest(4.667, 78.833, -107.043)
1782
+ # GeoidKarney('egm96-5.pgm'): lowerleft(-90.0, -180.0, -29.535), upperright(90.0, 180.0, 13.605), center(0.0, 0.0, 17.163), highest(-8.167, 147.25, 85.422), lowest(4.667, 78.833, -107.043): 14.807 ms (pygeodesy 24.8.24 Python 3.8.10 64bit arm64_x86_64 macOS 10.16)
1847
1783
  #
1848
1784
  # _PGM('../testGeoids/egm96-5.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:03', Description='WGS84 EGM96, 5-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.14, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.005, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html', Vertical_Datum='WGS84'
1849
1785
  #
@@ -1851,25 +1787,71 @@ del _intCs # trash ints cache
1851
1787
  # Timbuktu GeoidKarney('egm96-5.pgm').height(16.776, -3.009): 28.7067 vs 28.7067
1852
1788
 
1853
1789
 
1854
- # % python2 -m pygeodesy.geoids -PGM ../testGeoids/egm*.pgm
1790
+ # % python2 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1855
1791
  #
1856
- # GeoidPGM('egm2008-1.pgm'): lowerleft(-90.0, -180.0, -30.15), upperright(90.0, 180.0, 14.898), center(0.0, 0.0, 17.226), highest(-8.4, -32.633, 85.839), lowest(4.683, -101.25, -106.911)
1792
+ # GeoidKarney('egm2008-1.pgm'): lowerleft(-90.0, -180.0, -30.15), upperright(90.0, 180.0, 14.898), center(0.0, 0.0, 17.226), highest(-8.4, 147.367, 85.839), lowest(4.7, 78.767, -106.911): 283.362 ms (pygeodesy 24.8.24 Python 2.7.18 64bit arm64_x86_64 macOS 10.16)
1793
+ #
1794
+ # _PGM('../testGeoids/egm2008-1.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-31 06:54:00', Description='WGS84 EGM2008, 1-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.025, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.001, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008', Vertical_Datum='WGS84'
1795
+ #
1796
+ # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1797
+ # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1798
+ #
1799
+ # GeoidKarney('egm84-15.pgm'): lowerleft(-90.0, -180.0, -29.712), upperright(90.0, 180.0, 13.098), center(0.0, 0.0, 18.33), highest(-4.5, 148.75, 81.33), lowest(4.75, 79.25, -107.34): 1.378 ms (pygeodesy 24.8.24 Python 2.7.18 64bit arm64_x86_64 macOS 10.16)
1800
+ #
1801
+ # _PGM('../testGeoids/egm84-15.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:02', Description='WGS84 EGM84, 15-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.413, MaxCubicError=0.02, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.018, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/wgs84_180/wgs84_180.html', Vertical_Datum='WGS84'
1802
+ #
1803
+ # Timbuktu GeoidKarney('egm84-15.pgm').height(16.775833, -3.009444): 31.2983 vs 31.2979
1804
+ # Timbuktu GeoidKarney('egm84-15.pgm').height(16.776, -3.009): 31.2979 vs 31.2979
1805
+ #
1806
+ # GeoidKarney('egm96-5.pgm'): lowerleft(-90.0, -180.0, -29.535), upperright(90.0, 180.0, 13.605), center(0.0, 0.0, 17.163), highest(-8.167, 147.25, 85.422), lowest(4.667, 78.833, -107.043): 11.612 ms (pygeodesy 24.8.24 Python 2.7.18 64bit arm64_x86_64 macOS 10.16)
1807
+ #
1808
+ # _PGM('../testGeoids/egm96-5.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:03', Description='WGS84 EGM96, 5-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.14, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.005, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html', Vertical_Datum='WGS84'
1809
+ #
1810
+ # Timbuktu GeoidKarney('egm96-5.pgm').height(16.775833, -3.009444): 28.7068 vs 28.7067
1811
+ # Timbuktu GeoidKarney('egm96-5.pgm').height(16.776, -3.009): 28.7067 vs 28.7067
1812
+
1813
+
1814
+ # % python3.12 -m pygeodesy.geoids -PGM ../testGeoids/egm*.pgm
1815
+ #
1816
+ # GeoidPGM('egm2008-1.pgm'): lowerleft(-90.0, -180.0, -30.15), upperright(90.0, 180.0, 14.898), center(0.0, 0.0, 17.226), highest(-8.4, -32.633, 85.839), lowest(4.683, -101.25, -106.911): 543.148 ms (pygeodesy 24.8.24 Python 3.12.5 64bit arm64 macOS 14.6.1)
1857
1817
  #
1858
1818
  # _PGM('../testGeoids/egm2008-1.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-31 06:54:00', Description='WGS84 EGM2008, 1-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.025, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.001, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008', Vertical_Datum='WGS84'
1859
1819
  #
1860
1820
  # Timbuktu GeoidPGM('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1861
1821
  # Timbuktu GeoidPGM('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1862
1822
  #
1863
- # GeoidPGM('egm84-15.pgm'): lowerleft(-90.0, -180.0, -29.712), upperright(90.0, 180.0, 13.098), center(0.0, 0.0, 18.33), highest(-4.5, -31.25, 81.33), lowest(4.75, -100.75, -107.34)
1823
+ # GeoidPGM('egm84-15.pgm'): lowerleft(-90.0, -180.0, -29.712), upperright(90.0, 180.0, 13.098), center(0.0, 0.0, 18.33), highest(-4.5, -31.25, 81.33), lowest(4.75, -100.75, -107.34): 1.762 ms (pygeodesy 24.8.24 Python 3.12.5 64bit arm64 macOS 14.6.1)
1864
1824
  #
1865
1825
  # _PGM('../testGeoids/egm84-15.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:02', Description='WGS84 EGM84, 15-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.413, MaxCubicError=0.02, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.018, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/wgs84_180/wgs84_180.html', Vertical_Datum='WGS84'
1866
1826
  #
1867
1827
  # Timbuktu GeoidPGM('egm84-15.pgm').height(16.775833, -3.009444): 31.2979 vs 31.2979
1868
1828
  # Timbuktu GeoidPGM('egm84-15.pgm').height(16.776, -3.009): 31.2975 vs 31.2979
1869
1829
  #
1870
- # GeoidPGM('egm96-5.pgm'): lowerleft(-90.0, -180.0, -29.535), upperright(90.0, 180.0, 13.605), center(0.0, -0.0, 17.179), highest(-8.167, -32.75, 85.422), lowest(4.667, -101.167, -107.043)
1830
+ # GeoidPGM('egm96-5.pgm'): lowerleft(-90.0, -180.0, -29.535), upperright(90.0, 180.0, 13.605), center(0.0, -0.0, 17.179), highest(-8.167, -32.75, 85.422), lowest(4.667, -101.167, -107.043): 12.594 ms (pygeodesy 24.8.24 Python 3.12.5 64bit arm64 macOS 14.6.1)
1871
1831
  #
1872
1832
  # _PGM('../testGeoids/egm96-5.pgm'): AREA_OR_POINT='Point', DateTime='2009-08-29 18:45:03', Description='WGS84 EGM96, 5-minute grid', Geoid='file in PGM format for the GeographicLib::Geoid class', MaxBilinearError=0.14, MaxCubicError=0.003, Offset=-108.0, Origin=LatLon2Tuple(lat=90.0, lon=0.0), Pixel=65535, RMSBilinearError=0.005, RMSCubicError=0.001, Scale=0.003, URL='http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm96/egm96.html', Vertical_Datum='WGS84'
1873
1833
  #
1874
1834
  # Timbuktu GeoidPGM('egm96-5.pgm').height(16.775833, -3.009444): 28.7065 vs 28.7067
1875
1835
  # Timbuktu GeoidPGM('egm96-5.pgm').height(16.776, -3.009): 28.7064 vs 28.7067
1836
+
1837
+ # **) MIT License
1838
+ #
1839
+ # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1840
+ #
1841
+ # Permission is hereby granted, free of charge, to any person obtaining a
1842
+ # copy of this software and associated documentation files (the "Software"),
1843
+ # to deal in the Software without restriction, including without limitation
1844
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
1845
+ # and/or sell copies of the Software, and to permit persons to whom the
1846
+ # Software is furnished to do so, subject to the following conditions:
1847
+ #
1848
+ # The above copyright notice and this permission notice shall be included
1849
+ # in all copies or substantial portions of the Software.
1850
+ #
1851
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1852
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1853
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1854
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1855
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1856
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1857
+ # OTHER DEALINGS IN THE SOFTWARE.