pygeodesy 24.8.4__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 (50) hide show
  1. {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.8.24.dist-info}/METADATA +16 -15
  2. {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.8.24.dist-info}/RECORD +50 -50
  3. {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.8.24.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +23 -23
  5. pygeodesy/auxilats/auxDST.py +2 -2
  6. pygeodesy/basics.py +3 -3
  7. pygeodesy/cartesianBase.py +5 -5
  8. pygeodesy/constants.py +11 -11
  9. pygeodesy/ellipsoidalBase.py +18 -15
  10. pygeodesy/ellipsoidalExact.py +2 -2
  11. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  12. pygeodesy/ellipsoidalKarney.py +2 -2
  13. pygeodesy/ellipsoidalNvector.py +2 -2
  14. pygeodesy/ellipsoidalVincenty.py +7 -6
  15. pygeodesy/epsg.py +3 -3
  16. pygeodesy/fmath.py +2 -1
  17. pygeodesy/fsums.py +4 -4
  18. pygeodesy/gars.py +9 -8
  19. pygeodesy/geodesicx/gx.py +3 -3
  20. pygeodesy/geodesicx/gxarea.py +3 -3
  21. pygeodesy/geodsolve.py +3 -3
  22. pygeodesy/geohash.py +18 -11
  23. pygeodesy/geoids.py +293 -315
  24. pygeodesy/heights.py +150 -158
  25. pygeodesy/internals.py +21 -1
  26. pygeodesy/interns.py +2 -3
  27. pygeodesy/latlonBase.py +13 -7
  28. pygeodesy/lazily.py +6 -6
  29. pygeodesy/ltp.py +5 -6
  30. pygeodesy/ltpTuples.py +7 -1
  31. pygeodesy/named.py +5 -4
  32. pygeodesy/namedTuples.py +14 -1
  33. pygeodesy/osgr.py +7 -7
  34. pygeodesy/points.py +2 -2
  35. pygeodesy/resections.py +7 -7
  36. pygeodesy/rhumb/solve.py +3 -3
  37. pygeodesy/simplify.py +10 -10
  38. pygeodesy/sphericalBase.py +3 -3
  39. pygeodesy/sphericalTrigonometry.py +2 -2
  40. pygeodesy/streprs.py +3 -3
  41. pygeodesy/triaxials.py +207 -201
  42. pygeodesy/units.py +3 -3
  43. pygeodesy/unitsBase.py +4 -4
  44. pygeodesy/utmupsBase.py +3 -3
  45. pygeodesy/vector2d.py +158 -51
  46. pygeodesy/vector3d.py +13 -52
  47. pygeodesy/vector3dBase.py +81 -63
  48. pygeodesy/webmercator.py +3 -3
  49. pygeodesy/wgrs.py +20 -22
  50. {PyGeodesy-24.8.4.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.25'
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,7 +264,7 @@ 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
269
  _H = self._heightOrthometric if H else None
291
270
  _as, llis = _as_llis2(llis, Error=GeoidError)
@@ -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,12 @@ 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)
418
392
 
419
393
  @property_ROver
420
394
  def _heightOrthometric(self):
@@ -429,9 +403,9 @@ class _GeoidBase(_HeightsBase):
429
403
 
430
404
  @Property_RO
431
405
  def _highest(self):
432
- '''(INTERNAL) Cache for L{highest} method.
406
+ '''(INTERNAL) Cache for C{.highest}.
433
407
  '''
434
- return self._llh3minmax(True)
408
+ return self._LL3T(self._llh3minmax(True), name__=self.highest)
435
409
 
436
410
  def highest(self, LatLon=None, **unused):
437
411
  '''Return the location and largest height of this geoid.
@@ -451,15 +425,6 @@ class _GeoidBase(_HeightsBase):
451
425
  '''
452
426
  return self._yx_hits
453
427
 
454
- @deprecated_method
455
- def _interp2d(self, xs, ys, hs=(), k=0): # overwritten in .__init__ above
456
- '''DEPRECATED on 23.01.06, use keyword argument C{B{kind}=1..5}.'''
457
- # assert k in _interp2d_ks # and len(hs) == len(xs) == len(ys)
458
- try:
459
- return self.scipy_interpolate.interp2d(xs, ys, hs, kind=_interp2d_ks[k])
460
- except AttributeError as x:
461
- raise SciPyError(interp2d=MISSING, kind=k, cause=x)
462
-
463
428
  @Property_RO
464
429
  def kind(self):
465
430
  '''Get the interpolator kind and order (C{int}).
@@ -488,7 +453,7 @@ class _GeoidBase(_HeightsBase):
488
453
  def _llh3LL(self, llh, LatLon):
489
454
  return llh if LatLon is None else self._xnamed(LatLon(*llh))
490
455
 
491
- def _llh3minmax(self, highest=True, *unused):
456
+ def _llh3minmax(self, highest, *unused):
492
457
  hs, np = self._hs_y_x, self.numpy
493
458
  # <https://docs.SciPy.org/doc/numpy/reference/generated/
494
459
  # numpy.argmin.html#numpy.argmin>
@@ -503,7 +468,7 @@ class _GeoidBase(_HeightsBase):
503
468
 
504
469
  @Property_RO
505
470
  def _lowerleft(self):
506
- '''(INTERNAL) Cache for L{lowerleft}.
471
+ '''(INTERNAL) Cache for C{.lowerleft}.
507
472
  '''
508
473
  return self._llh3(self._lat_lo, self._lon_lo)
509
474
 
@@ -521,7 +486,7 @@ class _GeoidBase(_HeightsBase):
521
486
 
522
487
  @Property_RO
523
488
  def _loweright(self):
524
- '''(INTERNAL) Cache for L{loweright}.
489
+ '''(INTERNAL) Cache for C{.loweright}.
525
490
  '''
526
491
  return self._llh3(self._lat_lo, self._lon_hi)
527
492
 
@@ -535,16 +500,15 @@ class _GeoidBase(_HeightsBase):
535
500
  otherwise a B{C{LatLon}} instance with the lat-, longitude and
536
501
  geoid height of the lower-right, SE grid corner.
537
502
  '''
538
-
539
503
  return self._llh3LL(self._loweright, LatLon)
540
504
 
541
505
  lowerright = loweright # synonymous
542
506
 
543
507
  @Property_RO
544
508
  def _lowest(self):
545
- '''(INTERNAL) Cache for L{lowest}.
509
+ '''(INTERNAL) Cache for C{.lowest}.
546
510
  '''
547
- return self._llh3minmax(False)
511
+ return self._LL3T(self._llh3minmax(False), name__=self.lowest)
548
512
 
549
513
  def lowest(self, LatLon=None, **unused):
550
514
  '''Return the location and lowest height of this geoid.
@@ -570,7 +534,7 @@ class _GeoidBase(_HeightsBase):
570
534
  def name(self):
571
535
  '''Get the name of this geoid (C{str}).
572
536
  '''
573
- return _HeightsBase.name.fget(self) or self._geoid # recursion
537
+ return _HeightBase.name.fget(self) or self._geoid # recursion
574
538
 
575
539
  @Property_RO
576
540
  def nBytes(self):
@@ -591,7 +555,7 @@ class _GeoidBase(_HeightsBase):
591
555
  self._datum = _ellipsoidal_datum(datum, name=name)
592
556
  self._kind = int(kind)
593
557
  if name:
594
- _HeightsBase.name.fset(self, name) # rename
558
+ _HeightBase.name.fset(self, name) # rename
595
559
  if smooth:
596
560
  self._smooth = Int_(smooth=smooth, Error=GeoidError, low=0)
597
561
 
@@ -651,8 +615,8 @@ class _GeoidBase(_HeightsBase):
651
615
  swne = crop
652
616
  if len(swne) == 4:
653
617
  s, w, n, e = map(float, swne)
654
- if -90 <= s <= (n - _1_0) <= 89 and \
655
- -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:
656
620
  return s, w, n, e
657
621
  except (IndexError, TypeError, ValueError):
658
622
  pass
@@ -688,7 +652,7 @@ class _GeoidBase(_HeightsBase):
688
652
 
689
653
  @Property_RO
690
654
  def _upperleft(self):
691
- '''(INTERNAL) Cache for method L{upperleft}.
655
+ '''(INTERNAL) Cache for C{.upperleft}.
692
656
  '''
693
657
  return self._llh3(self._lat_hi, self._lon_lo)
694
658
 
@@ -706,7 +670,7 @@ class _GeoidBase(_HeightsBase):
706
670
 
707
671
  @Property_RO
708
672
  def _upperright(self):
709
- '''(INTERNAL) Cache for method L{upperright}.
673
+ '''(INTERNAL) Cache for C{.upperright}.
710
674
  '''
711
675
  return self._llh3(self._lat_hi, self._lon_hi)
712
676
 
@@ -723,12 +687,6 @@ class _GeoidBase(_HeightsBase):
723
687
  return self._llh3LL(self._upperright, LatLon)
724
688
 
725
689
 
726
- class GeoidError(HeightError):
727
- '''Geoid interpolator C{Geoid...} or interpolation issue.
728
- '''
729
- pass
730
-
731
-
732
690
  class GeoidG2012B(_GeoidBase):
733
691
  '''Geoid height interpolator for U{GEOID12B Model
734
692
  <https://www.NGS.NOAA.gov/GEOID/GEOID12B/>} grids U{CONUS
@@ -740,10 +698,11 @@ class GeoidG2012B(_GeoidBase):
740
698
  U{Puerto Rico and U.S. Virgin Islands
741
699
  <https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_PRVI.shtml>} and
742
700
  U{American Samoa<https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_AS.shtml>}
743
- based on C{SciPy} U{RectBivariateSpline<https://docs.SciPy.org/doc/
744
- scipy/reference/generated/scipy.interpolate.RectBivariateSpline.html>}
745
- or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/
746
- 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.
747
706
 
748
707
  Use any of the binary C{le} (little endian) or C{be} (big endian)
749
708
  C{g2012b*.bin} grid files.
@@ -753,38 +712,34 @@ class GeoidG2012B(_GeoidBase):
753
712
  '''New L{GeoidG2012B} interpolator.
754
713
 
755
714
  @arg g2012b_bin: A C{GEOID12B} grid file name (C{.bin}).
756
- @kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2}
757
- or L{a_f2Tuple}), default C{WGS84}.
758
- @kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for
759
- U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/
760
- reference/generated/scipy.interpolate.RectBivariateSpline.html>},
761
- -2 for U{interp2d linear<https://docs.SciPy.org/doc/scipy/
762
- reference/generated/scipy.interpolate.interp2d.html>}, -3
763
- for C{interp2d cubic} or -5 for C{interp2d quintic}.
764
- @kwarg smooth: Smoothing factor for U{RectBivariateSpline
765
- <https://docs.SciPy.org/doc/scipy/reference/generated/
766
- scipy.interpolate.RectBivariateSpline.html>}
767
- only (C{int}).
768
- @kwarg name_crop: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED
769
- keyword argument C{B{crop}}, use C{B{crop}=None} to ignore.
770
-
771
- @raise GeoidError: G2012B grid file B{C{g2012b_bin}} issue or invalid
772
- B{C{crop}}, B{C{kind}} or B{C{smooth}}.
773
-
774
- @raise ImportError: Package C{numpy} or C{scipy} not found or not
775
- 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.
776
732
 
777
733
  @raise LenError: Grid file B{C{g2012b_bin}} axis mismatch.
778
734
 
779
- @raise SciPyError: A C{RectBivariateSpline} or C{inter2d} issue.
735
+ @raise SciPyError: A C{scipy} issue.
780
736
 
781
- @raise SciPyWarning: A C{RectBivariateSpline} or C{inter2d}
782
- warning as exception.
737
+ @raise SciPyWarning: A C{scipy} warning as exception.
783
738
 
784
739
  @raise TypeError: Invalid B{C{datum}}.
785
740
 
786
- @note: C{scipy.interpolate.interp2d} has been C{DEPRECATED}, specify
787
- 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.
788
743
  '''
789
744
  crop, name = _xkwds_pop2(name_crop, crop=None)
790
745
  if crop is not None:
@@ -927,6 +882,7 @@ class GeoidKarney(_GeoidBase):
927
882
  _T( 0, 2),
928
883
  _T( 1, 2))
929
884
 
885
+ # _cropped = None
930
886
  _endian = '>H' # struct.unpack 1 ushort (big endian, unsigned short)
931
887
  _4endian = '>4H' # struct.unpack 4 ushorts
932
888
  _Rendian = NN # struct.unpack a row of ushorts
@@ -944,9 +900,9 @@ class GeoidKarney(_GeoidBase):
944
900
  _u2B = _calcsize(_endian) # pixelsize_ in bytes
945
901
  _4u2B = _calcsize(_4endian) # 4 pixelsize_s in bytes
946
902
  _Ru2B = 0 # row of pixelsize_s in bytes
947
- _yxH = () # cache (y, x) indices
948
- _yxHt = () # cached 4- or 10-tuple for _ev2H resp. _ev3H
949
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
950
906
 
951
907
  def __init__(self, egm_pgm, crop=None, datum=None, # WGS84
952
908
  kind=3, **name_smooth):
@@ -956,34 +912,31 @@ class GeoidKarney(_GeoidBase):
956
912
  C++/doc/geoid.html#geoidinst>} file name (C{egm*.pgm}), see
957
913
  note below.
958
914
  @kwarg crop: Optional box to limit geoid locations, a 4-tuple (C{south,
959
- west, north, east}), 2-tuple (C{(south, west), (north,
960
- east)}) or 2, in C{degrees90} lat- and C{degrees180}
961
- longitudes or a 2-tuple (C{LatLonSW, LatLonNE}) of
962
- C{LatLon} instances.
963
- @kwarg datum: Optional grid datum (C{Datum}, L{Ellipsoid}, L{Ellipsoid2}
964
- or L{a_f2Tuple}), default C{WGS84}.
965
- @kwarg kind: Interpolation order (C{int}), 2 for C{bilinear} or 3
966
- 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}.
967
921
  @kwarg name_smooth: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED
968
922
  keyword argument C{B{smooth}}, use C{B{smooth}=None} to ignore.
969
923
 
970
- @raise GeoidError: EGM dataset B{C{egm_pgm}} issue or invalid
971
- 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}}.
972
926
 
973
927
  @raise TypeError: Invalid B{C{datum}}.
974
928
 
975
929
  @see: Class L{GeoidPGM} and function L{egmGeoidHeights}.
976
930
 
977
- @note: Geoid file B{C{egm_pgm}} remains open and must be closed
978
- by calling the C{close} method or by using this instance
979
- 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.
980
933
  '''
981
934
  smooth, name = _xkwds_pop2(name_smooth, smooth=None)
982
935
  if smooth is not None:
983
936
  raise GeoidError(smooth=smooth, txt_not_=_supported_)
984
937
 
985
938
  if kind in (2,):
986
- self._evH = self._ev2H
939
+ self._ev2d = self._ev2k # see ._ev_name
987
940
  elif kind not in (3,):
988
941
  raise GeoidError(kind=kind)
989
942
 
@@ -999,7 +952,7 @@ class GeoidKarney(_GeoidBase):
999
952
  # set earth (lat, lon) limits (s, w, n, e)
1000
953
  self._lat_lo, self._lon_lo, \
1001
954
  self._lat_hi, self._lon_hi = self._swne(crop if crop else p.crop4)
1002
- self._cropped = True if crop else False
955
+ self._cropped = bool(crop)
1003
956
 
1004
957
  def __call__(self, *llis, **wrap_H):
1005
958
  '''Interpolate the geoid height for one or several locations.
@@ -1015,16 +968,15 @@ class GeoidKarney(_GeoidBase):
1015
968
  (C{float}) or a list or tuple of interpolated geoid
1016
969
  (or orthometric) heights (C{float}s).
1017
970
 
1018
- @raise GeoidError: Insufficient number of B{C{llis}}, an
1019
- invalid B{C{lli}} or the C{egm*.pgm}
1020
- 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.
1021
973
 
1022
- @raise RangeError: An B{C{lli}} is outside this geoid's lat-
1023
- or longitude range.
974
+ @raise RangeError: An B{C{lli}} is outside this geoid's lat- or
975
+ longitude range.
1024
976
 
1025
- @note: To obtain I{orthometric} heights, each B{C{llis}}
1026
- location must have an ellipsoid C{height} or C{h}
1027
- 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.
1028
980
 
1029
981
  @see: Function L{pygeodesy.heightOrthometric}.
1030
982
  '''
@@ -1072,38 +1024,38 @@ class GeoidKarney(_GeoidBase):
1072
1024
  y, x = int(floor(fy)), int(floor(fx))
1073
1025
  fy -= y
1074
1026
  fx -= x
1075
- H = self._evH(fy, fx, y, x) # ._ev3H or ._ev2H
1027
+ H = self._ev2d(fy, fx, y, x) # PYCHOK ._ev2k or ._ev3k
1076
1028
  H *= self._pgm.Scale # H.fmul(self._pgm.Scale)
1077
1029
  H += self._pgm.Offset # H.fadd(self._pgm.Offset)
1078
- return H.fsum()
1030
+ return H.fsum() # float(H)
1079
1031
 
1080
- def _ev2H(self, fy, fx, *yx):
1032
+ def _ev2k(self, fy, fx, *yx):
1081
1033
  # compute the bilinear 4-tuple and interpolate raw H
1082
- if self._yxH == yx:
1083
- t = self._yxHt
1034
+ if self._yx_i == yx:
1084
1035
  self._yx_hits += 1
1085
1036
  else:
1086
- y, x = self._yxH = yx
1087
- 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
1088
1040
  v = _1_0, -fx, fx
1089
1041
  H = Fdot(v, t[0], t[0], t[1]).fmul(_1_0 - fy) # c = a * (1 - fy)
1090
1042
  H += Fdot(v, t[2], t[2], t[3]).fmul(fy) # c += b * fy
1091
1043
  return H
1092
1044
 
1093
- def _ev3H(self, fy, fx, *yx):
1045
+ def _ev3k(self, fy, fx, *yx):
1094
1046
  # compute the cubic 10-tuple and interpolate raw H
1095
- if self._yxH == yx:
1096
- t = self._yxHt
1047
+ if self._yx_i == yx:
1097
1048
  self._yx_hits += 1
1098
1049
  else:
1099
- self._yxH = yx
1100
- c0, c3, v = self._c0c3v(*yx)
1101
- t = [fdot(v, *c3[i]) / c0 for i in range(self._nterms)]
1102
- 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
1103
1054
  # GeographicLib/Geoid.cpp Geoid::height(lat, lon) ...
1104
1055
  # real h = t[0] + fx * (t[1] + fx * (t[3] + fx * t[6])) +
1105
1056
  # fy * (t[2] + fx * (t[4] + fx * t[7]) +
1106
1057
  # fy * (t[5] + fx * t[8] + fy * t[9]));
1058
+ t = self._yx_t
1107
1059
  v = _1_0, fx, fy
1108
1060
  H = Fdot(v, t[5], t[8], t[9])
1109
1061
  H *= fy
@@ -1112,7 +1064,7 @@ class GeoidKarney(_GeoidBase):
1112
1064
  H += Fhorner(fx, t[0], t[1], t[3], t[6])
1113
1065
  return H
1114
1066
 
1115
- _evH = _ev3H # overriden for kind == 2
1067
+ _ev2d = _ev3k # overriden for kind=2, see ._ev_name
1116
1068
 
1117
1069
  def _g2ll2(self, lat, lon):
1118
1070
  # convert grid (lat, lon) to earth (lat, lon), uncropped
@@ -1149,13 +1101,14 @@ class GeoidKarney(_GeoidBase):
1149
1101
  @raise RangeError: A B{C{lat}} or B{C{lon}} is outside this
1150
1102
  geoid's lat- or longitude range.
1151
1103
  '''
1152
- 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)
1153
1106
 
1154
1107
  @Property_RO
1155
1108
  def _highest_ltd(self):
1156
- '''(INTERNAL) Cache for L{highest} mesthod.
1109
+ '''(INTERNAL) Cache for C{.highest}.
1157
1110
  '''
1158
- return self._llh3minmax(True, -12, -4)
1111
+ return self._LL3T(self._llh3minmax(True, -12, -4), name__=self.highest)
1159
1112
 
1160
1113
  def highest(self, LatLon=None, full=False): # PYCHOK full
1161
1114
  '''Return the location and largest height of this geoid.
@@ -1185,30 +1138,34 @@ class GeoidKarney(_GeoidBase):
1185
1138
  lon += _360_0
1186
1139
  return lat, lon
1187
1140
 
1188
- def _llh3minmax(self, highest=True, *lat2):
1141
+ def _llh3minmax(self, highest, *lat2):
1189
1142
  # find highest or lowest, takes 10+ secs for egm2008-1.pgm geoid
1190
1143
  # (Python 2.7.16, macOS 10.13.6 High Sierra, iMac 3 GHz Core i3)
1191
- y = x = 0
1192
- h = self._raw(y, x)
1193
1144
  if highest:
1194
- for j, r in self._raw2(*lat2):
1145
+ def _mt(r, h):
1195
1146
  m = max(r)
1196
- if m > h:
1197
- h, y, x = m, j, r.index(m)
1147
+ return m, (m > h)
1148
+
1198
1149
  else: # lowest
1199
- for j, r in self._raw2(*lat2):
1150
+ def _mt(r, h): # PYCHOK redef
1200
1151
  m = min(r)
1201
- if m < h:
1202
- 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)
1203
1160
  h *= self._pgm.Scale
1204
1161
  h += self._pgm.Offset
1205
1162
  return self._g2ll2(*self._gyx2g2(y, x)) + (h,)
1206
1163
 
1207
1164
  @Property_RO
1208
1165
  def _lowest_ltd(self):
1209
- '''(INTERNAL) Cache for L{lowest}.
1166
+ '''(INTERNAL) Cache for C{.lowest}.
1210
1167
  '''
1211
- return self._llh3minmax(False, 0, 8)
1168
+ return self._LL3T(self._llh3minmax(False, 0, 8), name__=self.lowest)
1212
1169
 
1213
1170
  def lowest(self, LatLon=None, full=False): # PYCHOK full
1214
1171
  '''Return the location and lowest height of this geoid.
@@ -1273,25 +1230,21 @@ class GeoidKarney(_GeoidBase):
1273
1230
 
1274
1231
  class GeoidPGM(_GeoidBase):
1275
1232
  '''Geoid height interpolator for I{Karney}'s U{GeographicLib Earth
1276
- Gravitational Model (EGM)<https://GeographicLib.SourceForge.io/C++/doc/
1277
- geoid.html>} geoid U{egm*.pgm<https://GeographicLib.SourceForge.io/
1278
- C++/doc/geoid.html#geoidinst>} datasets but based on C{SciPy}
1279
- U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/reference/
1280
- generated/scipy.interpolate.RectBivariateSpline.html>} or
1281
- U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/
1282
- scipy.interpolate.interp2d.html>} interpolation.
1283
-
1284
- Use any of the U{egm84-, egm96- or egm2008-*.pgm
1285
- <https://GeographicLib.SourceForge.io/C++/doc/geoid.html#geoidinst>}
1286
- datasets. However, unless cropped, an entire C{egm*.pgm} dataset
1287
- is loaded into the C{SciPy} U{RectBivariateSpline<https://docs.SciPy.org/
1288
- doc/scipy/reference/generated/scipy.interpolate.RectBivariateSpline.html>}
1289
- or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/
1290
- scipy.interpolate.interp2d.html>} interpolator and converted from
1291
- 2-byte C{int} to 8-byte C{dtype float64}. Therefore, internal memory
1292
- usage is 4x the U{egm*.pgm<https://GeographicLib.SourceForge.io/C++/doc/
1293
- geoid.html#geoidinst>} file size and may exceed the available memory,
1294
- 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}.
1295
1248
  '''
1296
1249
  _cropped = False
1297
1250
  _endian = '>u2'
@@ -1304,48 +1257,44 @@ class GeoidPGM(_GeoidBase):
1304
1257
  C++/doc/geoid.html#geoidinst>} file name (C{egm*.pgm}).
1305
1258
  @kwarg crop: Optional box to crop B{C{egm_pgm}}, a 4-tuple (C{south, west,
1306
1259
  north, east}) or 2-tuple (C{(south, west), (north, east)}),
1307
- in C{degrees90} lat- and C{degrees180} longitudes or a
1308
- 2-tuple (C{LatLonSW, LatLonNE}) of C{LatLon} instances.
1309
- @kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2}
1310
- or L{a_f2Tuple}), default C{WGS84}.
1311
- @kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for
1312
- U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/
1313
- reference/generated/scipy.interpolate.RectBivariateSpline.html>},
1314
- -2 for U{interp2d linear<https://docs.SciPy.org/doc/scipy/
1315
- reference/generated/scipy.interpolate.interp2d.html>}, -3
1316
- for C{interp2d cubic} or -5 for C{interp2d quintic}.
1317
- @kwarg smooth: Smoothing factor for U{RectBivariateSpline
1318
- <https://docs.SciPy.org/doc/scipy/reference/generated/
1319
- scipy.interpolate.RectBivariateSpline.html>}
1320
- 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}).
1321
1272
  @kwarg name: Optional geoid C{B{name}=NN} (C{str}).
1322
1273
 
1323
- @raise GeoidError: EGM dataset B{C{egm_pgm}} issue or invalid B{C{crop}},
1324
- 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}}.
1325
1276
 
1326
1277
  @raise ImportError: Package C{numpy} or C{scipy} not found or not installed.
1327
1278
 
1328
1279
  @raise LenError: EGM dataset B{C{egm_pgm}} axis mismatch.
1329
1280
 
1330
- @raise SciPyError: A C{RectBivariateSpline} or C{inter2d} issue.
1281
+ @raise SciPyError: A C{scipy} issue.
1331
1282
 
1332
- @raise SciPyWarning: A C{RectBivariateSpline} or C{inter2d}
1333
- warning as exception.
1283
+ @raise SciPyWarning: A C{scipy} warning as exception.
1334
1284
 
1335
1285
  @raise TypeError: Invalid B{C{datum}} or unexpected argument.
1336
1286
 
1337
- @note: C{scipy.interpolate.interp2d} has been C{DEPRECATED}, specify
1338
- C{B{kind}=1..5} for C{scipy.interpolate.RectBivariateSpline}.
1339
-
1340
- @note: The U{GeographicLib egm*.pgm<https://GeographicLib.SourceForge.io/
1341
- C++/doc/geoid.html#geoidinst>} file sizes are based on a 2-byte
1342
- C{int} height converted to 8-byte C{dtype float64} for C{scipy}
1343
- interpolators. Therefore, internal memory usage is 4 times the
1344
- C{egm*.pgm} file size and may exceed the available memory,
1345
- especially with 32-bit Python. To reduce memory usage, set
1346
- keyword argument B{C{crop}} to the region of interest. For example
1347
- C{B{crop}=(20, -125, 50, -65)} covers the U{conterminous US<https://
1348
- 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>}
1349
1298
  (CONUS), less than 3% of the entire C{egm2008-1.pgm} dataset.
1350
1299
 
1351
1300
  @see: Class L{GeoidKarney} and function L{egmGeoidHeights}.
@@ -1715,9 +1664,10 @@ def egmGeoidHeights(GeoidHeights_dat):
1715
1664
 
1716
1665
  __all__ += _ALL_DOCS(_GeoidBase)
1717
1666
 
1718
- if __name__ == '__main__':
1667
+ if __name__ == '__main__': # MCCABE 14
1719
1668
 
1720
- from pygeodesy.internals import printf, _sys
1669
+ from pygeodesy.internals import printf, _secs2str, _sys, _versions
1670
+ from time import time
1721
1671
 
1722
1672
  _crop = ()
1723
1673
  _GeoidEGM = GeoidKarney
@@ -1741,7 +1691,10 @@ if __name__ == '__main__':
1741
1691
 
1742
1692
  elif geoid[-4:].lower() in ('.pgm',):
1743
1693
  g = _GeoidEGM(geoid, crop=_crop, kind=_kind)
1744
- 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)
1745
1698
  printf(repr(g.pgm), nt=1)
1746
1699
  # <https://GeographicLib.SourceForge.io/cgi-bin/GeoidEval>:
1747
1700
  # The height of the EGM96 geoid at Timbuktu
@@ -1771,27 +1724,6 @@ if __name__ == '__main__':
1771
1724
  _I = int # PYCHOK unused _I
1772
1725
  del _intCs # trash ints cache
1773
1726
 
1774
- # **) MIT License
1775
- #
1776
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1777
- #
1778
- # Permission is hereby granted, free of charge, to any person obtaining a
1779
- # copy of this software and associated documentation files (the "Software"),
1780
- # to deal in the Software without restriction, including without limitation
1781
- # the rights to use, copy, modify, merge, publish, distribute, sublicense,
1782
- # and/or sell copies of the Software, and to permit persons to whom the
1783
- # Software is furnished to do so, subject to the following conditions:
1784
- #
1785
- # The above copyright notice and this permission notice shall be included
1786
- # in all copies or substantial portions of the Software.
1787
- #
1788
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1789
- # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1790
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1791
- # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1792
- # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1793
- # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1794
- # OTHER DEALINGS IN THE SOFTWARE.
1795
1727
 
1796
1728
  # <https://GeographicLib.SourceForge.io/cgi-bin/GeoidEval>
1797
1729
  # _lowerleft = -90, -179, -30.1500 # egm2008-1.pgm
@@ -1807,23 +1739,47 @@ del _intCs # trash ints cache
1807
1739
  # _upperright = 90, 180, 13.0980 # egm84-15.pgm
1808
1740
 
1809
1741
 
1810
- # % python3 -m pygeodesy.geoids [-Karney] ../testGeoids/egm*.pgm
1742
+ # % python3.12 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1743
+ #
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)
1745
+ #
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'
1747
+ #
1748
+ # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1749
+ # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1750
+ #
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)
1752
+ #
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'
1754
+ #
1755
+ # Timbuktu GeoidKarney('egm84-15.pgm').height(16.775833, -3.009444): 31.2983 vs 31.2979
1756
+ # Timbuktu GeoidKarney('egm84-15.pgm').height(16.776, -3.009): 31.2979 vs 31.2979
1757
+ #
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)
1759
+ #
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'
1761
+ #
1762
+ # Timbuktu GeoidKarney('egm96-5.pgm').height(16.775833, -3.009444): 28.7068 vs 28.7067
1763
+ # Timbuktu GeoidKarney('egm96-5.pgm').height(16.776, -3.009): 28.7067 vs 28.7067
1764
+
1765
+
1766
+ # % python3.8 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1811
1767
  #
1812
- # 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)
1813
1769
  #
1814
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'
1815
1771
  #
1816
1772
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1817
1773
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1818
1774
  #
1819
- # 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)
1820
1776
  #
1821
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'
1822
1778
  #
1823
1779
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.775833, -3.009444): 31.2983 vs 31.2979
1824
1780
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.776, -3.009): 31.2979 vs 31.2979
1825
1781
  #
1826
- # 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)
1827
1783
  #
1828
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'
1829
1785
  #
@@ -1831,23 +1787,23 @@ del _intCs # trash ints cache
1831
1787
  # Timbuktu GeoidKarney('egm96-5.pgm').height(16.776, -3.009): 28.7067 vs 28.7067
1832
1788
 
1833
1789
 
1834
- # % python3 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1790
+ # % python2 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
1835
1791
  #
1836
- # 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)
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)
1837
1793
  #
1838
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'
1839
1795
  #
1840
1796
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1841
1797
  # Timbuktu GeoidKarney('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1842
1798
  #
1843
- # 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)
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)
1844
1800
  #
1845
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'
1846
1802
  #
1847
1803
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.775833, -3.009444): 31.2983 vs 31.2979
1848
1804
  # Timbuktu GeoidKarney('egm84-15.pgm').height(16.776, -3.009): 31.2979 vs 31.2979
1849
1805
  #
1850
- # 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)
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)
1851
1807
  #
1852
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'
1853
1809
  #
@@ -1855,25 +1811,47 @@ del _intCs # trash ints cache
1855
1811
  # Timbuktu GeoidKarney('egm96-5.pgm').height(16.776, -3.009): 28.7067 vs 28.7067
1856
1812
 
1857
1813
 
1858
- # % python2 -m pygeodesy.geoids -PGM ../testGeoids/egm*.pgm
1814
+ # % python3.12 -m pygeodesy.geoids -PGM ../testGeoids/egm*.pgm
1859
1815
  #
1860
- # 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)
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)
1861
1817
  #
1862
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'
1863
1819
  #
1864
1820
  # Timbuktu GeoidPGM('egm2008-1.pgm').height(16.775833, -3.009444): 28.7881 vs 28.7880
1865
1821
  # Timbuktu GeoidPGM('egm2008-1.pgm').height(16.776, -3.009): 28.7880 vs 28.7880
1866
1822
  #
1867
- # 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)
1868
1824
  #
1869
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'
1870
1826
  #
1871
1827
  # Timbuktu GeoidPGM('egm84-15.pgm').height(16.775833, -3.009444): 31.2979 vs 31.2979
1872
1828
  # Timbuktu GeoidPGM('egm84-15.pgm').height(16.776, -3.009): 31.2975 vs 31.2979
1873
1829
  #
1874
- # 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)
1875
1831
  #
1876
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'
1877
1833
  #
1878
1834
  # Timbuktu GeoidPGM('egm96-5.pgm').height(16.775833, -3.009444): 28.7065 vs 28.7067
1879
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.