pygeodesy 24.11.11__py2.py3-none-any.whl → 25.1.5__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PyGeodesy-24.11.11.dist-info → PyGeodesy-25.1.5.dist-info}/METADATA +34 -35
- PyGeodesy-25.1.5.dist-info/RECORD +118 -0
- {PyGeodesy-24.11.11.dist-info → PyGeodesy-25.1.5.dist-info}/WHEEL +1 -1
- pygeodesy/__init__.py +19 -19
- pygeodesy/__main__.py +1 -1
- pygeodesy/albers.py +5 -5
- pygeodesy/auxilats/_CX_4.py +1 -1
- pygeodesy/auxilats/_CX_6.py +1 -1
- pygeodesy/auxilats/_CX_8.py +1 -1
- pygeodesy/auxilats/_CX_Rs.py +1 -1
- pygeodesy/auxilats/__init__.py +1 -1
- pygeodesy/auxilats/__main__.py +1 -1
- pygeodesy/auxilats/auxAngle.py +5 -5
- pygeodesy/auxilats/auxDLat.py +6 -6
- pygeodesy/auxilats/auxDST.py +2 -2
- pygeodesy/auxilats/auxLat.py +5 -5
- pygeodesy/auxilats/auxily.py +2 -2
- pygeodesy/azimuthal.py +5 -5
- pygeodesy/basics.py +60 -8
- pygeodesy/booleans.py +1 -1
- pygeodesy/cartesianBase.py +22 -61
- pygeodesy/clipy.py +1 -1
- pygeodesy/constants.py +5 -5
- pygeodesy/css.py +1 -1
- pygeodesy/datums.py +1 -1
- pygeodesy/deprecated/__init__.py +2 -2
- pygeodesy/deprecated/bases.py +1 -1
- pygeodesy/deprecated/classes.py +86 -2
- pygeodesy/deprecated/consterns.py +1 -1
- pygeodesy/deprecated/datum.py +5 -5
- pygeodesy/deprecated/functions.py +42 -8
- pygeodesy/deprecated/nvector.py +1 -1
- pygeodesy/deprecated/rhumbBase.py +1 -1
- pygeodesy/deprecated/rhumbaux.py +1 -1
- pygeodesy/deprecated/rhumbsolve.py +1 -1
- pygeodesy/deprecated/rhumbx.py +1 -1
- pygeodesy/dms.py +1 -1
- pygeodesy/ecef.py +53 -56
- pygeodesy/elevations.py +1 -1
- pygeodesy/ellipsoidalBase.py +3 -3
- pygeodesy/ellipsoidalBaseDI.py +1 -1
- pygeodesy/ellipsoidalExact.py +1 -1
- pygeodesy/ellipsoidalGeodSolve.py +1 -1
- pygeodesy/ellipsoidalKarney.py +1 -1
- pygeodesy/ellipsoidalNvector.py +1 -1
- pygeodesy/ellipsoidalVincenty.py +6 -5
- pygeodesy/ellipsoids.py +4 -5
- pygeodesy/elliptic.py +6 -6
- pygeodesy/epsg.py +1 -1
- pygeodesy/errors.py +1 -1
- pygeodesy/etm.py +5 -5
- pygeodesy/fmath.py +18 -17
- pygeodesy/formy.py +409 -555
- pygeodesy/frechet.py +29 -86
- pygeodesy/fstats.py +1 -1
- pygeodesy/fsums.py +32 -33
- pygeodesy/gars.py +1 -1
- pygeodesy/geodesici.py +7 -7
- pygeodesy/geodesicw.py +1 -1
- pygeodesy/geodesicx/_C4_24.py +2 -2
- pygeodesy/geodesicx/_C4_27.py +2 -2
- pygeodesy/geodesicx/_C4_30.py +2 -2
- pygeodesy/geodesicx/__init__.py +2 -2
- pygeodesy/geodesicx/__main__.py +4 -5
- pygeodesy/geodesicx/gx.py +6 -5
- pygeodesy/geodesicx/gxarea.py +2 -2
- pygeodesy/geodesicx/gxbases.py +2 -2
- pygeodesy/geodesicx/gxline.py +16 -12
- pygeodesy/geodsolve.py +1 -1
- pygeodesy/geohash.py +1 -1
- pygeodesy/geoids.py +277 -203
- pygeodesy/hausdorff.py +23 -81
- pygeodesy/heights.py +115 -150
- pygeodesy/internals.py +1 -1
- pygeodesy/interns.py +2 -3
- pygeodesy/iters.py +1 -1
- pygeodesy/karney.py +3 -3
- pygeodesy/ktm.py +16 -15
- pygeodesy/latlonBase.py +323 -409
- pygeodesy/lazily.py +53 -44
- pygeodesy/lcc.py +1 -1
- pygeodesy/ltp.py +46 -50
- pygeodesy/ltpTuples.py +147 -130
- pygeodesy/mgrs.py +1 -1
- pygeodesy/named.py +149 -3
- pygeodesy/namedTuples.py +58 -7
- pygeodesy/nvectorBase.py +122 -105
- pygeodesy/osgr.py +1 -1
- pygeodesy/points.py +1 -1
- pygeodesy/props.py +1 -1
- pygeodesy/resections.py +18 -17
- pygeodesy/rhumb/__init__.py +1 -1
- pygeodesy/rhumb/aux_.py +2 -2
- pygeodesy/rhumb/bases.py +2 -2
- pygeodesy/rhumb/ekx.py +4 -4
- pygeodesy/rhumb/solve.py +1 -1
- pygeodesy/simplify.py +289 -401
- pygeodesy/solveBase.py +1 -1
- pygeodesy/sphericalBase.py +1 -1
- pygeodesy/sphericalNvector.py +5 -5
- pygeodesy/sphericalTrigonometry.py +7 -6
- pygeodesy/streprs.py +10 -5
- pygeodesy/trf.py +1 -1
- pygeodesy/triaxials.py +23 -16
- pygeodesy/units.py +16 -16
- pygeodesy/unitsBase.py +1 -1
- pygeodesy/ups.py +4 -4
- pygeodesy/utily.py +341 -211
- pygeodesy/utm.py +5 -5
- pygeodesy/utmups.py +1 -1
- pygeodesy/utmupsBase.py +1 -1
- pygeodesy/vector2d.py +5 -5
- pygeodesy/vector3d.py +14 -3
- pygeodesy/vector3dBase.py +5 -5
- pygeodesy/webmercator.py +1 -1
- pygeodesy/wgrs.py +1 -1
- PyGeodesy-24.11.11.dist-info/RECORD +0 -118
- {PyGeodesy-24.11.11.dist-info → PyGeodesy-25.1.5.dist-info}/top_level.txt +0 -0
pygeodesy/geoids.py
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
|
|
4
4
|
u'''Geoid models and geoid height interpolations.
|
|
5
5
|
|
|
6
|
-
Classes L{GeoidG2012B}, L{GeoidKarney} and L{GeoidPGM} to
|
|
7
|
-
height of various U{geoid<https://WikiPedia.org/wiki/Geoid>}s
|
|
8
|
-
locations or separate lat-/longitudes using
|
|
9
|
-
and C{geoid} model files.
|
|
6
|
+
Classes L{GeoidEGM96}, L{GeoidG2012B}, L{GeoidKarney} and L{GeoidPGM} to
|
|
7
|
+
interpolate the height of various U{geoid<https://WikiPedia.org/wiki/Geoid>}s
|
|
8
|
+
at C{LatLon} locations or separate lat-/longitudes using various interpolation
|
|
9
|
+
methods and C{geoid} model files.
|
|
10
10
|
|
|
11
11
|
L{GeoidKarney} is a transcoding of I{Charles Karney}'s C++ class U{Geoid
|
|
12
12
|
<https://GeographicLib.SourceForge.io/C++/doc/geoid.html>} to pure Python.
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
|
|
14
|
+
The L{GeoidEGM96}, L{GeoidG2012B} and L{GeoidPGM} interpolators both depend on
|
|
15
|
+
U{scipy<https://SciPy.org>} and U{numpy<https://PyPI.org/project/numpy>} and
|
|
15
16
|
require those packages to be installed.
|
|
16
17
|
|
|
17
18
|
In addition, each geoid interpolator needs C{grid knots} (down)loaded from
|
|
@@ -22,19 +23,19 @@ there are several interpolation choices, like I{linear}, I{cubic}, etc.
|
|
|
22
23
|
Typical usage
|
|
23
24
|
=============
|
|
24
25
|
|
|
25
|
-
1. Choose
|
|
26
|
+
1. Choose an interpolator class L{GeoidEGM96}, L{GeoidG2012B}, L{GeoidKarney}
|
|
26
27
|
or L{GeoidPGM} and download a C{geoid} model file, containing locations with
|
|
27
|
-
known heights also referred to as the C{grid knots}. See the documentation
|
|
28
|
-
|
|
28
|
+
known heights also referred to as the C{grid knots}. See the documentation of
|
|
29
|
+
the interpolator class for references to available C{grid} models.
|
|
29
30
|
|
|
30
|
-
C{>>> from pygeodesy import
|
|
31
|
+
C{>>> from pygeodesy import GeoidEGM96 # or -G2012B, -Karney or -PGM as GeoidXyz}
|
|
31
32
|
|
|
32
33
|
2. Instantiate an interpolator with the C{geoid} model file and use keyword
|
|
33
34
|
arguments to select different interpolation options
|
|
34
35
|
|
|
35
36
|
C{>>> ginterpolator = GeoidXyz(geoid_model_file, **options)}
|
|
36
37
|
|
|
37
|
-
3. Get the interpolated geoid height of
|
|
38
|
+
3. Get the interpolated geoid height of C{LatLon} location(s) with
|
|
38
39
|
|
|
39
40
|
C{>>> ll = LatLon(1, 2, ...)}
|
|
40
41
|
|
|
@@ -48,7 +49,7 @@ or a list, tuple, generator, etc. of C{LatLon}s
|
|
|
48
49
|
|
|
49
50
|
C{>>> hs = ginterpolator(lls)}
|
|
50
51
|
|
|
51
|
-
4. For separate lat- and longitudes invoke the C{
|
|
52
|
+
4. For separate lat- and longitudes invoke the C{height} method as
|
|
52
53
|
|
|
53
54
|
C{>>> h = ginterpolator.height(lat, lon)}
|
|
54
55
|
|
|
@@ -56,10 +57,14 @@ or as 2 lists, 2 tuples, etc.
|
|
|
56
57
|
|
|
57
58
|
C{>>> hs = ginterpolator.height(lats, lons)}
|
|
58
59
|
|
|
60
|
+
or for several positionals use the C{height_} method
|
|
61
|
+
|
|
62
|
+
C{>>> h1, h2, ... = ginterpolator.height_(lat1, lon1, lat2, lon2, ...)}
|
|
63
|
+
|
|
59
64
|
5. An example is in U{issue #64<https://GitHub.com/mrJean1/PyGeodesy/issues/64>},
|
|
60
65
|
courtesy of SBFRF.
|
|
61
66
|
|
|
62
|
-
@note: Classes L{GeoidG2012B} and L{GeoidPGM} require both U{numpy
|
|
67
|
+
@note: Classes L{GeoidEGM96}, L{GeoidG2012B} and L{GeoidPGM} require both U{numpy
|
|
63
68
|
<https://PyPI.org/project/numpy>} and U{scipy<https://PyPI.org/project/scipy>}
|
|
64
69
|
to be installed.
|
|
65
70
|
|
|
@@ -70,6 +75,8 @@ courtesy of SBFRF.
|
|
|
70
75
|
@see: I{Karney}'s U{GeographicLib<https://GeographicLib.SourceForge.io/C++/doc/index.html>},
|
|
71
76
|
U{Geoid height<https://GeographicLib.SourceForge.io/C++/doc/geoid.html>} and U{Installing
|
|
72
77
|
the Geoid datasets<https://GeographicLib.SourceForge.io/C++/doc/geoid.html#geoidinst>},
|
|
78
|
+
World Geodetic System 1984 (WG84) and U{Earth Gravitational Model 96 (EGM96) Data and
|
|
79
|
+
Apps<https://earth-info.NGA.mil/index.php?dir=wgs84&action=wgs84>},
|
|
73
80
|
U{SciPy<https://docs.SciPy.org/doc/scipy/reference/interpolate.html>} interpolation
|
|
74
81
|
U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.
|
|
75
82
|
RectBivariateSpline.html>}, U{bisplrep/-ev<https://docs.scipy.org/doc/scipy/reference/generated/
|
|
@@ -82,22 +89,23 @@ courtesy of SBFRF.
|
|
|
82
89
|
# make sure int/int division yields float quotient, see .basics
|
|
83
90
|
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
84
91
|
|
|
85
|
-
from pygeodesy.basics import len2,
|
|
92
|
+
from pygeodesy.basics import len2, min2, isodd, ub2str as _ub2str
|
|
86
93
|
from pygeodesy.constants import EPS, _float as _F, _1_0, _N_90_0, _180_0, \
|
|
87
94
|
_N_180_0, _360_0
|
|
88
|
-
|
|
95
|
+
from pygeodesy.datums import Datums, _ellipsoidal_datum, _WGS84
|
|
89
96
|
# from pygeodesy.dms import parseDMS2 # _MODS
|
|
90
97
|
from pygeodesy.errors import _incompatible, LenError, RangeError, _SciPyIssue, \
|
|
91
98
|
_xkwds_pop2
|
|
92
99
|
from pygeodesy.fmath import favg, Fdot, fdot, Fhorner, frange
|
|
93
100
|
# from pygoedesy.formy import heightOrthometric # _MODS
|
|
94
101
|
from pygeodesy.heights import _as_llis2, _ascalar, _HeightBase, HeightError, \
|
|
95
|
-
|
|
102
|
+
_Wrap
|
|
96
103
|
# from pygeodesy.internals import _version2 # _MODS
|
|
97
104
|
from pygeodesy.interns import NN, _COLONSPACE_, _COMMASPACE_, _E_, _height_, \
|
|
98
105
|
_in_, _kind_, _lat_, _lon_, _mean_, _N_, _n_a_, \
|
|
99
106
|
_numpy_, _on_, _outside_, _S_, _s_, _scipy_, \
|
|
100
107
|
_SPACE_, _stdev_, _tbd_, _W_, _width_, _4_
|
|
108
|
+
from pygeodesy.interns import _COMMA_ # PYCHOK used!
|
|
101
109
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
|
|
102
110
|
from pygeodesy.named import _name__, _Named, _NamedTuple
|
|
103
111
|
# from pygeodesy.namedTuples import LatLon3Tuple # _MODS
|
|
@@ -118,18 +126,17 @@ except ImportError: # Python 3+
|
|
|
118
126
|
from io import BytesIO as _BytesIO # PYCHOK expected
|
|
119
127
|
|
|
120
128
|
__all__ = _ALL_LAZY.geoids
|
|
121
|
-
__version__ = '24.
|
|
129
|
+
__version__ = '24.12.31'
|
|
122
130
|
|
|
123
|
-
_assert_
|
|
124
|
-
_bHASH_
|
|
125
|
-
_endian_
|
|
126
|
-
_format_
|
|
127
|
-
_header_
|
|
128
|
-
_intCs
|
|
129
|
-
_lli_
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
_supported_ = 'supported'
|
|
131
|
+
_assert_ = 'assert'
|
|
132
|
+
_bHASH_ = b'#'
|
|
133
|
+
_endian_ = 'endian'
|
|
134
|
+
_format_ = '%s %r'
|
|
135
|
+
_header_ = 'header'
|
|
136
|
+
_intCs = {} # cache int value, del below
|
|
137
|
+
_lli_ = 'lli'
|
|
138
|
+
_rb_ = 'rb'
|
|
139
|
+
_supported_ = 'supported'
|
|
133
140
|
|
|
134
141
|
|
|
135
142
|
class GeoidError(HeightError):
|
|
@@ -149,6 +156,7 @@ class _GeoidBase(_HeightBase):
|
|
|
149
156
|
_Error = GeoidError # in ._HeightBase._as_lls, ...
|
|
150
157
|
_geoid = _n_a_
|
|
151
158
|
_hs_y_x = None # numpy 2darray, row-major order
|
|
159
|
+
_iscipy = True # scipy or Karney's interpolation
|
|
152
160
|
_kind = 3 # order for interp2d, RectBivariateSpline
|
|
153
161
|
# _kmin = 2 # min number of knots
|
|
154
162
|
_knots = 0 # nlat * nlon
|
|
@@ -203,7 +211,7 @@ class _GeoidBase(_HeightBase):
|
|
|
203
211
|
s=self._smooth).ev
|
|
204
212
|
self._hs_y_x = hs # numpy 2darray, row-major
|
|
205
213
|
self._nBytes = hs.nbytes # numpy size in bytes
|
|
206
|
-
self._knots = p.knots # grid knots
|
|
214
|
+
self._knots = p.knots # grid knots == len(hs)
|
|
207
215
|
self._lon_of = float(p.flon) # forward offset
|
|
208
216
|
self._lon_og = g = float(p.glon) # reverse offset
|
|
209
217
|
# shrink the bounding box by 1 unit on every side:
|
|
@@ -216,18 +224,18 @@ class _GeoidBase(_HeightBase):
|
|
|
216
224
|
self._lon_hi -= g
|
|
217
225
|
|
|
218
226
|
def __call__(self, *llis, **wrap_H):
|
|
219
|
-
'''Interpolate the geoid height for one or
|
|
227
|
+
'''Interpolate the geoid (or orthometric) height for one or more locations.
|
|
220
228
|
|
|
221
|
-
@arg llis: One or
|
|
229
|
+
@arg llis: One or several locations (each C{LatLon}), all positional.
|
|
222
230
|
@kwarg wrap_H: Keyword arguments C{B{wrap}=False} (C{bool}) and
|
|
223
|
-
C{B{H}=False} (C{bool}).
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
231
|
+
C{B{H}=False} (C{bool}). Use C{B{wrap}=True} to wrap
|
|
232
|
+
or I{normalize} all B{C{llis}} locations. If C{B{H}
|
|
233
|
+
is True}, return the I{orthometric} height instead of
|
|
234
|
+
the I{geoid} height at each location.
|
|
227
235
|
|
|
228
|
-
@return: A single
|
|
229
|
-
|
|
230
|
-
|
|
236
|
+
@return: A single geoid (or orthometric) height (C{float}) or
|
|
237
|
+
a list or tuple of geoid (or orthometric) heights (each
|
|
238
|
+
C{float}).
|
|
231
239
|
|
|
232
240
|
@raise GeoidError: Insufficient number of B{C{llis}}, an invalid
|
|
233
241
|
B{C{lli}} or the C{egm*.pgm} geoid file is closed.
|
|
@@ -245,7 +253,7 @@ class _GeoidBase(_HeightBase):
|
|
|
245
253
|
|
|
246
254
|
@see: Function L{pygeodesy.heightOrthometric}.
|
|
247
255
|
'''
|
|
248
|
-
return self._called(llis,
|
|
256
|
+
return self._called(llis, **wrap_H)
|
|
249
257
|
|
|
250
258
|
def __enter__(self):
|
|
251
259
|
'''Open context.
|
|
@@ -264,12 +272,12 @@ class _GeoidBase(_HeightBase):
|
|
|
264
272
|
def __str__(self):
|
|
265
273
|
return Fmt.PAREN(self.classname, repr(self.name))
|
|
266
274
|
|
|
267
|
-
def _called(self, llis,
|
|
275
|
+
def _called(self, llis, wrap=False, H=False):
|
|
268
276
|
# handle __call__
|
|
269
277
|
_H = self._heightOrthometric if H else None
|
|
270
278
|
_as, llis = _as_llis2(llis, Error=GeoidError)
|
|
271
|
-
|
|
272
|
-
|
|
279
|
+
_w, hs = _Wrap._latlonop(wrap), []
|
|
280
|
+
_h, _a = self._hGeoid, hs.append
|
|
273
281
|
try:
|
|
274
282
|
for i, lli in enumerate(llis):
|
|
275
283
|
N = _h(*_w(lli.lat, lli.lon))
|
|
@@ -278,11 +286,11 @@ class _GeoidBase(_HeightBase):
|
|
|
278
286
|
return _as(hs)
|
|
279
287
|
except (GeoidError, RangeError) as x:
|
|
280
288
|
# XXX avoid str(LatLon()) degree symbols
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
raise type(x)(
|
|
289
|
+
n = _lli_ if _as is _ascalar else Fmt.INDEX(llis=i)
|
|
290
|
+
t = fstr((lli.lat, lli.lon), strepr=repr)
|
|
291
|
+
raise type(x)(n, t, wrap=wrap, H=H, cause=x)
|
|
284
292
|
except Exception as x:
|
|
285
|
-
if
|
|
293
|
+
if self._iscipy and self.scipy:
|
|
286
294
|
raise _SciPyIssue(x, self._ev_name)
|
|
287
295
|
else:
|
|
288
296
|
raise
|
|
@@ -350,12 +358,12 @@ class _GeoidBase(_HeightBase):
|
|
|
350
358
|
raise LenError(self.__class__, grid=m, **{name: n})
|
|
351
359
|
if d < 0:
|
|
352
360
|
d, a = -d, list(reversed(a))
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return
|
|
361
|
+
a = self.numpy.array(a)
|
|
362
|
+
m, i = min2(*map(float, a[1:] - a[:-1]))
|
|
363
|
+
if m < EPS: # non-increasing axis
|
|
364
|
+
i = Fmt.INDEX(name, i + 1)
|
|
365
|
+
raise GeoidError(i, m, txt_not_='increasing')
|
|
366
|
+
return a, d
|
|
359
367
|
|
|
360
368
|
def _g2ll2(self, lat, lon): # PYCHOK no cover
|
|
361
369
|
'''(INTERNAL) I{Must be overloaded}.'''
|
|
@@ -369,26 +377,39 @@ class _GeoidBase(_HeightBase):
|
|
|
369
377
|
def height(self, lats, lons, **wrap):
|
|
370
378
|
'''Interpolate the geoid height for one or several lat-/longitudes.
|
|
371
379
|
|
|
372
|
-
@arg lats: Latitude or latitudes (
|
|
373
|
-
@arg lons: Longitude or longitudes (
|
|
374
|
-
@kwarg wrap:
|
|
375
|
-
|
|
380
|
+
@arg lats: Latitude or latitudes (each C{degrees}).
|
|
381
|
+
@arg lons: Longitude or longitudes (each C{degrees}).
|
|
382
|
+
@kwarg wrap: Use C{B{wrap}=True} to wrap or I{normalize} all
|
|
383
|
+
B{C{lats}} and B{C{lons}}.
|
|
376
384
|
|
|
377
|
-
@return: A single
|
|
378
|
-
|
|
385
|
+
@return: A single geoid height (C{float}) or a list of geoid
|
|
386
|
+
heights (each C{float}).
|
|
379
387
|
|
|
380
|
-
@raise GeoidError: Insufficient or
|
|
381
|
-
|
|
388
|
+
@raise GeoidError: Insufficient or unequal number of B{C{lats}}
|
|
389
|
+
and B{C{lons}}.
|
|
382
390
|
|
|
383
|
-
@raise RangeError: A B{C{lat}} or B{C{lon}} is outside this
|
|
384
|
-
|
|
391
|
+
@raise RangeError: A B{C{lat}} or B{C{lon}} is outside this geoid's
|
|
392
|
+
lat- or longitude range.
|
|
385
393
|
|
|
386
394
|
@raise SciPyError: A C{scipy} issue.
|
|
387
395
|
|
|
388
396
|
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
389
397
|
'''
|
|
390
|
-
|
|
391
|
-
|
|
398
|
+
return _HeightBase.height(self, lats, lons, **wrap)
|
|
399
|
+
|
|
400
|
+
def height_(self, *latlons, **wrap):
|
|
401
|
+
'''Interpolate the geoid height for each M{(latlons[i], latlons[i+1])
|
|
402
|
+
pair for i in range(0, len(latlons), B{2})}.
|
|
403
|
+
|
|
404
|
+
@arg latlons: Alternating lat-/longitude pairs (each C{degrees}),
|
|
405
|
+
all positional.
|
|
406
|
+
|
|
407
|
+
@see: Method L{height} for further details.
|
|
408
|
+
|
|
409
|
+
@return: A tuple of geoid heights (each C{float}).
|
|
410
|
+
'''
|
|
411
|
+
lls = tuple(self._as_lls(latlons[0::2], *latlons[1::2]))
|
|
412
|
+
return self._called(lls, **wrap)
|
|
392
413
|
|
|
393
414
|
@property_ROver
|
|
394
415
|
def _heightOrthometric(self):
|
|
@@ -396,9 +417,9 @@ class _GeoidBase(_HeightBase):
|
|
|
396
417
|
|
|
397
418
|
def _hGeoid(self, lat, lon):
|
|
398
419
|
out = self.outside(lat, lon)
|
|
399
|
-
if out:
|
|
400
|
-
|
|
401
|
-
raise RangeError(lli=
|
|
420
|
+
if out: # XXX avoid str(LatLon()) degree symbols
|
|
421
|
+
t = fstr((lat, lon), strepr=repr)
|
|
422
|
+
raise RangeError(lli=t, txt=_SPACE_(_outside_, _on_, out))
|
|
402
423
|
return float(self._ev(*self._ll2g2(lat, lon)))
|
|
403
424
|
|
|
404
425
|
@Property_RO
|
|
@@ -461,10 +482,10 @@ class _GeoidBase(_HeightBase):
|
|
|
461
482
|
y, x = np.unravel_index(arg(hs, axis=None), hs.shape)
|
|
462
483
|
return self._g2ll2(*self._gyx2g2(y, x)) + (float(hs[y, x]),)
|
|
463
484
|
|
|
464
|
-
def _load(self, g, dtype, n, offset=0):
|
|
485
|
+
def _load(self, g, dtype=float, n=-1, offset=0, **sep): # sep=NN
|
|
465
486
|
# numpy.fromfile, like .frombuffer
|
|
466
487
|
g.seek(offset, _MODS.os.SEEK_SET)
|
|
467
|
-
return self.numpy.fromfile(g, dtype, n)
|
|
488
|
+
return self.numpy.fromfile(g, dtype, count=n, **sep)
|
|
468
489
|
|
|
469
490
|
@Property_RO
|
|
470
491
|
def _lowerleft(self):
|
|
@@ -562,19 +583,17 @@ class _GeoidBase(_HeightBase):
|
|
|
562
583
|
return g
|
|
563
584
|
|
|
564
585
|
def outside(self, lat, lon):
|
|
565
|
-
'''Check whether a location is outside this geoid's
|
|
566
|
-
|
|
586
|
+
'''Check whether a location is outside this geoid's lat-/longitude
|
|
587
|
+
or crop range.
|
|
567
588
|
|
|
568
589
|
@arg lat: The latitude (C{degrees}).
|
|
569
590
|
@arg lon: The longitude (C{degrees}).
|
|
570
591
|
|
|
571
|
-
@return: A 1- or 2-character C{str} if outside
|
|
572
|
-
empty C{str} if inside.
|
|
592
|
+
@return: A 1- or 2-character C{str} if outside, an empty C{str} otherwise.
|
|
573
593
|
'''
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
(_E_ if lon > self._lon_hi else NN))
|
|
594
|
+
lat = _S_ if lat < self._lat_lo else (_N_ if lat > self._lat_hi else NN)
|
|
595
|
+
lon = _W_ if lon < self._lon_lo else (_E_ if lon > self._lon_hi else NN)
|
|
596
|
+
return NN(lat, lon) if lat and lon else (lat or lon)
|
|
578
597
|
|
|
579
598
|
@Property_RO
|
|
580
599
|
def pgm(self):
|
|
@@ -687,6 +706,88 @@ class _GeoidBase(_HeightBase):
|
|
|
687
706
|
return self._llh3LL(self._upperright, LatLon)
|
|
688
707
|
|
|
689
708
|
|
|
709
|
+
class GeoidEGM96(_GeoidBase):
|
|
710
|
+
'''Geoid height interpolator for the EGM96 U{15 Minute Interpolation Grid<https://earth-info.NGA.mil>}
|
|
711
|
+
based on C{SciPy} interpolation U{RectBivariateSpline<https://docs.SciPy.org/doc/scipy/reference/
|
|
712
|
+
generated/scipy.interpolate.RectBivariateSpline.html>}, U{interp2d<https://docs.SciPy.org/doc/scipy/
|
|
713
|
+
reference/generated/scipy.interpolate.interp2d.html>} or U{bisplrep/-ev<https://docs.scipy.org/doc/
|
|
714
|
+
scipy/reference/generated/scipy.interpolate.bisplrep.html>}.
|
|
715
|
+
|
|
716
|
+
Use only the C{WW15MGH.GRD} file, unzipped from the EGM96 U{15 Minute Interpolation Grid
|
|
717
|
+
<https://earth-info.NGA.mil/index.php?dir=wgs84&action=wgs84>} download.
|
|
718
|
+
'''
|
|
719
|
+
def __init__(self, EGM96_grd, datum=_WGS84, kind=3, smooth=0, **name_crop):
|
|
720
|
+
'''New L{GeoidEGM96} interpolator.
|
|
721
|
+
|
|
722
|
+
@arg EGM96_grd: An C{EGM96_grd} grid file name (C{.GRD}).
|
|
723
|
+
@kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}),
|
|
724
|
+
overriding C{WGS84}.
|
|
725
|
+
@kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for U{RectBivariateSpline
|
|
726
|
+
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.
|
|
727
|
+
RectBivariateSpline.html>} or -1, -3 or -5 for U{bisplrep/-ev<https://
|
|
728
|
+
docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.bisplrep.html>}
|
|
729
|
+
or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
|
|
730
|
+
interpolate.interp2d.html>} C{linear}, C{cubic} respectively C{quintic},
|
|
731
|
+
see note for more details.
|
|
732
|
+
@kwarg smooth: Smoothing factor for C{B{kind}=1..5} only (C{int}).
|
|
733
|
+
@kwarg name_crop: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED keyword argument
|
|
734
|
+
C{B{crop}=None}.
|
|
735
|
+
|
|
736
|
+
@raise GeoidError: Invalid B{C{crop}}, B{C{kind}} or B{C{smooth}} or a ECM96 grid file
|
|
737
|
+
B{C{ECM96_grd}} issue.
|
|
738
|
+
|
|
739
|
+
@raise ImportError: Package C{numpy} or C{scipy} not found or not installed.
|
|
740
|
+
|
|
741
|
+
@raise LenError: Grid file B{C{EGM96_grd}} axis mismatch.
|
|
742
|
+
|
|
743
|
+
@raise SciPyError: A C{scipy} issue.
|
|
744
|
+
|
|
745
|
+
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
746
|
+
|
|
747
|
+
@raise TypeError: Invalid B{C{datum}}.
|
|
748
|
+
|
|
749
|
+
@note: Specify C{B{kind}=-1, -3 or -5} to use C{scipy.interpolate.interp2d}
|
|
750
|
+
before or C{scipy.interpolate.bisplrep/-ev} since C{Scipy} version 1.14.
|
|
751
|
+
'''
|
|
752
|
+
crop, name = _xkwds_pop2(name_crop, crop=None)
|
|
753
|
+
if crop is not None:
|
|
754
|
+
raise GeoidError(crop=crop, txt_not_=_supported_)
|
|
755
|
+
|
|
756
|
+
g = self._open(EGM96_grd, datum, kind, _name__(**name), smooth)
|
|
757
|
+
_ = self.numpy # import numpy for .fromfile, .reshape
|
|
758
|
+
|
|
759
|
+
try:
|
|
760
|
+
p, hs = _Gpars(), self._load(g, sep=_SPACE_) # text
|
|
761
|
+
p.slat, n, p.wlon, e, p.dlat, p.dlon = hs[:6] # n-s, 0-E
|
|
762
|
+
p.nlat = int((n - p.slat) / p.dlat) + 1 # include S
|
|
763
|
+
p.nlon = int((e - p.wlon) / p.dlon) + 1 # include W
|
|
764
|
+
p.knots = p.nlat * p.nlon # inverted lats N downto S
|
|
765
|
+
p.glon = _180_0 # Eastern lons 0-360
|
|
766
|
+
hs = hs[6:].reshape(p.nlat, p.nlon)
|
|
767
|
+
_GeoidBase.__init__(self, hs, p)
|
|
768
|
+
|
|
769
|
+
except Exception as x:
|
|
770
|
+
raise _SciPyIssue(x, _in_, repr(EGM96_grd))
|
|
771
|
+
finally:
|
|
772
|
+
g.close()
|
|
773
|
+
|
|
774
|
+
def _g2ll2(self, lat, lon):
|
|
775
|
+
# convert grid (lat, lon) to earth (lat, lon)
|
|
776
|
+
while lon > _180_0: # Eastern
|
|
777
|
+
lon -= _360_0
|
|
778
|
+
return -lat, lon # invert lat
|
|
779
|
+
|
|
780
|
+
def _ll2g2(self, lat, lon):
|
|
781
|
+
# convert earth (lat, lon) to grid (lat, lon)
|
|
782
|
+
while lon < 0: # Eastern
|
|
783
|
+
lon += _360_0
|
|
784
|
+
return -lat, lon # invert lat
|
|
785
|
+
|
|
786
|
+
if _FOR_DOCS:
|
|
787
|
+
__call__ = _GeoidBase.__call__
|
|
788
|
+
height = _GeoidBase.height
|
|
789
|
+
|
|
790
|
+
|
|
690
791
|
class GeoidG2012B(_GeoidBase):
|
|
691
792
|
'''Geoid height interpolator for U{GEOID12B Model
|
|
692
793
|
<https://www.NGS.NOAA.gov/GEOID/GEOID12B/>} grids U{CONUS
|
|
@@ -698,24 +799,24 @@ class GeoidG2012B(_GeoidBase):
|
|
|
698
799
|
U{Puerto Rico and U.S. Virgin Islands
|
|
699
800
|
<https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_PRVI.shtml>} and
|
|
700
801
|
U{American Samoa<https://www.NGS.NOAA.gov/GEOID/GEOID12B/GEOID12B_AS.shtml>}
|
|
701
|
-
based on C{SciPy} U{RectBivariateSpline<https://docs.SciPy.org/doc/
|
|
702
|
-
reference/generated/scipy.interpolate.RectBivariateSpline.html>}, U{interp2d
|
|
703
|
-
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
Use any of the
|
|
708
|
-
C{g2012b*.bin} grid files.
|
|
802
|
+
based on C{SciPy} interpolation U{RectBivariateSpline<https://docs.SciPy.org/doc/
|
|
803
|
+
scipy/reference/generated/scipy.interpolate.RectBivariateSpline.html>}, U{interp2d
|
|
804
|
+
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.interp2d.html>}
|
|
805
|
+
or U{bisplrep/-ev<https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.
|
|
806
|
+
bisplrep.html>}.
|
|
807
|
+
|
|
808
|
+
Use any of the C{le} (little endian) or C{be} (big endian) C{g2012b*.bin} binary grid files.
|
|
709
809
|
'''
|
|
710
|
-
|
|
711
|
-
|
|
810
|
+
_datum = Datums.NAD83
|
|
811
|
+
|
|
812
|
+
def __init__(self, g2012b_bin, datum=Datums.NAD83, kind=3, smooth=0, **name_crop):
|
|
712
813
|
'''New L{GeoidG2012B} interpolator.
|
|
713
814
|
|
|
714
815
|
@arg g2012b_bin: A C{GEOID12B} grid file name (C{.bin}).
|
|
715
816
|
@kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or
|
|
716
|
-
L{a_f2Tuple}),
|
|
817
|
+
L{a_f2Tuple}), overriding C{NAD83}.
|
|
717
818
|
@kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for U{RectBivariateSpline
|
|
718
|
-
<https://docs.SciPy.org/doc/scipy/
|
|
819
|
+
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.
|
|
719
820
|
RectBivariateSpline.html>} or -1, -3 or -5 for U{bisplrep/-ev<https://
|
|
720
821
|
docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.bisplrep.html>}
|
|
721
822
|
or U{interp2d<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
|
|
@@ -804,15 +905,17 @@ class GeoidHeight5Tuple(_NamedTuple): # .geoids.py
|
|
|
804
905
|
def _I(i):
|
|
805
906
|
'''(INTERNAL) Cache a single C{int} constant.
|
|
806
907
|
'''
|
|
908
|
+
i = int(i)
|
|
807
909
|
return _intCs.setdefault(i, i) # PYCHOK undefined due to del _intCs
|
|
808
910
|
|
|
809
911
|
|
|
810
|
-
def _T(
|
|
912
|
+
def _T(cs):
|
|
811
913
|
'''(INTERNAL) Cache a tuple of single C{int} constants.
|
|
812
914
|
'''
|
|
813
|
-
|
|
915
|
+
cs = cs.replace(_COMMA_, _SPACE_).strip()
|
|
916
|
+
return tuple(map(_I, cs.split()))
|
|
814
917
|
|
|
815
|
-
_T0s12 = (_I(0),) * 12 # PYCHOK _T(0, 0, ..., 0)
|
|
918
|
+
_T0s12 = (_I(0),) * 12 # PYCHOK _T('0, 0, ..., 0')
|
|
816
919
|
|
|
817
920
|
|
|
818
921
|
class GeoidKarney(_GeoidBase):
|
|
@@ -831,56 +934,56 @@ class GeoidKarney(_GeoidBase):
|
|
|
831
934
|
'''
|
|
832
935
|
_C0 = _F(372), _F(240), _F(372) # n, _ and s common denominators
|
|
833
936
|
# matrices c3n_, c3, c3s_, transposed from GeographicLib/Geoid.cpp
|
|
834
|
-
_C3 = ((_T(0, 0, 62, 124, 124, 62, 0, 0, 0, 0, 0, 0),
|
|
937
|
+
_C3 = ((_T('0, 0, 62, 124, 124, 62, 0, 0, 0, 0, 0, 0'),
|
|
835
938
|
_T0s12,
|
|
836
|
-
_T(-131, 7, -31, -62, -62, -31, 45, 216, 156, -45, -55, -7),
|
|
939
|
+
_T('-131, 7, -31, -62, -62, -31, 45, 216, 156, -45, -55, -7'),
|
|
837
940
|
_T0s12,
|
|
838
|
-
_T(138, -138, 0, 0, 0, 0, -183, 33, 153, -3, 48, -48), # PYCHOK indent
|
|
839
|
-
_T(144, 42, -62, -124, -124, -62, -9, 87, 99, 9, 42, -42),
|
|
941
|
+
_T('138, -138, 0, 0, 0, 0, -183, 33, 153, -3, 48, -48'), # PYCHOK indent
|
|
942
|
+
_T('144, 42, -62, -124, -124, -62, -9, 87, 99, 9, 42, -42'),
|
|
840
943
|
_T0s12,
|
|
841
|
-
_T(0, 0, 0, 0, 0, 0, 93, -93, -93, 93, 0, 0),
|
|
842
|
-
_T(-102, 102, 0, 0, 0, 0, 18, 12, -12, -18, -84, 84),
|
|
843
|
-
_T(-31, -31, 31, 62, 62, 31, 0, -93, -93, 0, 31, 31)), # PYCHOK indent
|
|
844
|
-
|
|
845
|
-
(_T(9, -9, 9, 186, 54, -9, -9, 54, -54, 9, -9, 9),
|
|
846
|
-
_T(-18, 18, -88, -42, 162, -32, 8, -78, 78, -8, 18, -18),
|
|
847
|
-
_T(-88, 8, -18, -42, -78, 18, 18, 162, 78, -18, -32, -8),
|
|
848
|
-
_T(0, 0, 90, -150, 30, 30, 30, -90, 90, -30, 0, 0),
|
|
849
|
-
_T(96, -96, 96, -96, -24, 24, -96, -24, 144, -24, 24, -24), # PYCHOK indent
|
|
850
|
-
_T(90, 30, 0, -150, -90, 0, 0, 30, 90, 0, 30, -30),
|
|
851
|
-
_T(0, 0, -20, 60, -60, 20, -20, 60, -60, 20, 0, 0),
|
|
852
|
-
_T(0, 0, -60, 60, 60, -60, 60, -60, -60, 60, 0, 0),
|
|
853
|
-
_T(-60, 60, 0, 60, -60, 0, 0, 60, -60, 0, -60, 60),
|
|
854
|
-
_T(-20, -20, 0, 60, 60, 0, 0, -60, -60, 0, 20, 20)),
|
|
855
|
-
|
|
856
|
-
(_T(18, -18, 36, 210, 162, -36, 0, 0, 0, 0, -18, 18), # PYCHOK indent
|
|
857
|
-
_T(-36, 36, -165, 45, 141, -21, 0, 0, 0, 0, 36, -36),
|
|
858
|
-
_T(-122, -2, -27, -111, -75, 27, 62, 124, 124, 62, -64, 2),
|
|
859
|
-
_T(0, 0, 93, -93, -93, 93, 0, 0, 0, 0, 0, 0),
|
|
860
|
-
_T(120, -120, 147, -57, -129, 39, 0, 0, 0, 0, 66, -66), # PYCHOK indent
|
|
861
|
-
_T(135, 51, -9, -192, -180, 9, 31, 62, 62, 31, 51, -51),
|
|
944
|
+
_T('0, 0, 0, 0, 0, 0, 93, -93, -93, 93, 0, 0'),
|
|
945
|
+
_T('-102, 102, 0, 0, 0, 0, 18, 12, -12, -18, -84, 84'),
|
|
946
|
+
_T('-31, -31, 31, 62, 62, 31, 0, -93, -93, 0, 31, 31')), # PYCHOK indent
|
|
947
|
+
|
|
948
|
+
(_T('9, -9, 9, 186, 54, -9, -9, 54, -54, 9, -9, 9'),
|
|
949
|
+
_T('-18, 18, -88, -42, 162, -32, 8, -78, 78, -8, 18, -18'),
|
|
950
|
+
_T('-88, 8, -18, -42, -78, 18, 18, 162, 78, -18, -32, -8'),
|
|
951
|
+
_T('0, 0, 90, -150, 30, 30, 30, -90, 90, -30, 0, 0'),
|
|
952
|
+
_T('96, -96, 96, -96, -24, 24, -96, -24, 144, -24, 24, -24'), # PYCHOK indent
|
|
953
|
+
_T('90, 30, 0, -150, -90, 0, 0, 30, 90, 0, 30, -30'),
|
|
954
|
+
_T('0, 0, -20, 60, -60, 20, -20, 60, -60, 20, 0, 0'),
|
|
955
|
+
_T('0, 0, -60, 60, 60, -60, 60, -60, -60, 60, 0, 0'),
|
|
956
|
+
_T('-60, 60, 0, 60, -60, 0, 0, 60, -60, 0, -60, 60'),
|
|
957
|
+
_T('-20, -20, 0, 60, 60, 0, 0, -60, -60, 0, 20, 20')),
|
|
958
|
+
|
|
959
|
+
(_T('18, -18, 36, 210, 162, -36, 0, 0, 0, 0, -18, 18'), # PYCHOK indent
|
|
960
|
+
_T('-36, 36, -165, 45, 141, -21, 0, 0, 0, 0, 36, -36'),
|
|
961
|
+
_T('-122, -2, -27, -111, -75, 27, 62, 124, 124, 62, -64, 2'),
|
|
962
|
+
_T('0, 0, 93, -93, -93, 93, 0, 0, 0, 0, 0, 0'),
|
|
963
|
+
_T('120, -120, 147, -57, -129, 39, 0, 0, 0, 0, 66, -66'), # PYCHOK indent
|
|
964
|
+
_T('135, 51, -9, -192, -180, 9, 31, 62, 62, 31, 51, -51'),
|
|
862
965
|
_T0s12,
|
|
863
|
-
_T(0, 0, -93, 93, 93, -93, 0, 0, 0, 0, 0, 0),
|
|
864
|
-
_T(-84, 84, 18, 12, -12, -18, 0, 0, 0, 0, -102, 102),
|
|
865
|
-
_T(-31, -31, 0, 93, 93, 0, -31, -62, -62, -31, 31, 31)))
|
|
866
|
-
|
|
867
|
-
_BT = (_T(0, 0), # bilinear 4-tuple [i, j] indices
|
|
868
|
-
_T(1, 0),
|
|
869
|
-
_T(0, 1),
|
|
870
|
-
_T(1, 1))
|
|
871
|
-
|
|
872
|
-
_CM = (_T( 0, -1), # 10x12 cubic matrix [i, j] indices
|
|
873
|
-
_T( 1, -1),
|
|
874
|
-
_T(-1, 0),
|
|
875
|
-
_T( 0, 0),
|
|
876
|
-
_T( 1, 0),
|
|
877
|
-
_T( 2, 0),
|
|
878
|
-
_T(-1, 1),
|
|
879
|
-
_T( 0, 1),
|
|
880
|
-
_T( 1, 1),
|
|
881
|
-
_T( 2, 1),
|
|
882
|
-
_T( 0, 2),
|
|
883
|
-
_T( 1, 2))
|
|
966
|
+
_T('0, 0, -93, 93, 93, -93, 0, 0, 0, 0, 0, 0'),
|
|
967
|
+
_T('-84, 84, 18, 12, -12, -18, 0, 0, 0, 0, -102, 102'),
|
|
968
|
+
_T('-31, -31, 0, 93, 93, 0, -31, -62, -62, -31, 31, 31')))
|
|
969
|
+
|
|
970
|
+
_BT = (_T('0, 0'), # bilinear 4-tuple [i, j] indices
|
|
971
|
+
_T('1, 0'),
|
|
972
|
+
_T('0, 1'),
|
|
973
|
+
_T('1, 1'))
|
|
974
|
+
|
|
975
|
+
_CM = (_T(' 0, -1'), # 10x12 cubic matrix [i, j] indices
|
|
976
|
+
_T(' 1, -1'),
|
|
977
|
+
_T('-1, 0'),
|
|
978
|
+
_T(' 0, 0'),
|
|
979
|
+
_T(' 1, 0'),
|
|
980
|
+
_T(' 2, 0'),
|
|
981
|
+
_T('-1, 1'),
|
|
982
|
+
_T(' 0, 1'),
|
|
983
|
+
_T(' 1, 1'),
|
|
984
|
+
_T(' 2, 1'),
|
|
985
|
+
_T(' 0, 2'),
|
|
986
|
+
_T(' 1, 2'))
|
|
884
987
|
|
|
885
988
|
# _cropped = None
|
|
886
989
|
_endian = '>H' # struct.unpack 1 ushort (big endian, unsigned short)
|
|
@@ -889,12 +992,13 @@ class GeoidKarney(_GeoidBase):
|
|
|
889
992
|
# _highest = (-8.4, 147.367, 85.839) if egm2008-1.pgm else (
|
|
890
993
|
# (-8.167, 147.25, 85.422) if egm96-5.pgm else
|
|
891
994
|
# (-4.5, 148.75, 81.33)) # egm84-15.pgm
|
|
995
|
+
_iscipy = False
|
|
892
996
|
# _lowest = (4.7, 78.767, -106.911) if egm2008-1.pgm else (
|
|
893
997
|
# (4.667, 78.833, -107.043) if egm96-5.pgm else
|
|
894
998
|
# (4.75, 79.25, -107.34)) # egm84-15.pgm
|
|
895
999
|
_mean = _F(-1.317) # from egm2008-1, -1.438 egm96-5, -0.855 egm84-15
|
|
896
1000
|
_nBytes = None # not applicable
|
|
897
|
-
_nterms = len(_C3[0]) # columns length, number of
|
|
1001
|
+
_nterms = len(_C3[0]) # columns length, number of rows
|
|
898
1002
|
_smooth = None # not applicable
|
|
899
1003
|
_stdev = _F(29.244) # from egm2008-1, 29.227 egm96-5, 29.183 egm84-15
|
|
900
1004
|
_u2B = _calcsize(_endian) # pixelsize_ in bytes
|
|
@@ -904,8 +1008,7 @@ class GeoidKarney(_GeoidBase):
|
|
|
904
1008
|
_yx_i = () # cached (y, x) indices
|
|
905
1009
|
_yx_t = () # cached 4- or 10-tuple for _ev2k resp. _ev3k
|
|
906
1010
|
|
|
907
|
-
def __init__(self, egm_pgm, crop=None, datum=
|
|
908
|
-
kind=3, **name_smooth):
|
|
1011
|
+
def __init__(self, egm_pgm, crop=None, datum=_WGS84, kind=3, **name_smooth):
|
|
909
1012
|
'''New L{GeoidKarney} interpolator.
|
|
910
1013
|
|
|
911
1014
|
@arg egm_pgm: An U{EGM geoid dataset<https://GeographicLib.SourceForge.io/
|
|
@@ -916,7 +1019,7 @@ class GeoidKarney(_GeoidBase):
|
|
|
916
1019
|
with 2 C{degrees90} lat- and C{degrees180} longitudes or as
|
|
917
1020
|
2-tuple (C{LatLonSW, LatLonNE}) of C{LatLon} instances.
|
|
918
1021
|
@kwarg datum: Optional grid datum (C{Datum}, L{Ellipsoid}, L{Ellipsoid2} or
|
|
919
|
-
L{a_f2Tuple}),
|
|
1022
|
+
L{a_f2Tuple}), overriding C{WGS84}.
|
|
920
1023
|
@kwarg kind: Interpolation order (C{int}), 2 for C{bilinear} or 3 for C{cubic}.
|
|
921
1024
|
@kwarg name_smooth: Optional geoid C{B{name}=NN} (C{str}) and UNSUPPORTED
|
|
922
1025
|
keyword argument C{B{smooth}}, use C{B{smooth}=None} to ignore.
|
|
@@ -954,34 +1057,6 @@ class GeoidKarney(_GeoidBase):
|
|
|
954
1057
|
self._lat_hi, self._lon_hi = self._swne(crop if crop else p.crop4)
|
|
955
1058
|
self._cropped = bool(crop)
|
|
956
1059
|
|
|
957
|
-
def __call__(self, *llis, **wrap_H):
|
|
958
|
-
'''Interpolate the geoid height for one or several locations.
|
|
959
|
-
|
|
960
|
-
@arg llis: One or more locations (C{LatLon}s), all positional.
|
|
961
|
-
@kwarg wrap_H: Keyword arguments C{B{wrap}=False, B{H}=False}.
|
|
962
|
-
If C{B{wrap} is True}, wrap or I{normalize} all
|
|
963
|
-
B{C{llis}} locations (C{bool}). If C{B{H} is True},
|
|
964
|
-
return the I{orthometric} height instead of the
|
|
965
|
-
I{geoid} height at each location (C{bool}).
|
|
966
|
-
|
|
967
|
-
@return: A single interpolated geoid (or orthometric) height
|
|
968
|
-
(C{float}) or a list or tuple of interpolated geoid
|
|
969
|
-
(or orthometric) heights (C{float}s).
|
|
970
|
-
|
|
971
|
-
@raise GeoidError: Insufficient number of B{C{llis}}, an invalid
|
|
972
|
-
B{C{lli}} or the C{egm*.pgm} geoid file is closed.
|
|
973
|
-
|
|
974
|
-
@raise RangeError: An B{C{lli}} is outside this geoid's lat- or
|
|
975
|
-
longitude range.
|
|
976
|
-
|
|
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.
|
|
980
|
-
|
|
981
|
-
@see: Function L{pygeodesy.heightOrthometric}.
|
|
982
|
-
'''
|
|
983
|
-
return self._called(llis, False, **wrap_H)
|
|
984
|
-
|
|
985
1060
|
def _c0c3v(self, y, x):
|
|
986
1061
|
# get the common denominator, the 10x12 cubic matrix and
|
|
987
1062
|
# the 12 cubic v-coefficients around geoid index (y, x)
|
|
@@ -1036,7 +1111,7 @@ class GeoidKarney(_GeoidBase):
|
|
|
1036
1111
|
else:
|
|
1037
1112
|
y, x = self._yx_i = yx
|
|
1038
1113
|
self._yx_t = self._raws(y, x, GeoidKarney._BT)
|
|
1039
|
-
t =
|
|
1114
|
+
t = self._yx_t
|
|
1040
1115
|
v = _1_0, -fx, fx
|
|
1041
1116
|
H = Fdot(v, t[0], t[0], t[1]).fmul(_1_0 - fy) # c = a * (1 - fy)
|
|
1042
1117
|
H += Fdot(v, t[2], t[2], t[3]).fmul(fy) # c += b * fy
|
|
@@ -1055,7 +1130,7 @@ class GeoidKarney(_GeoidBase):
|
|
|
1055
1130
|
# real h = t[0] + fx * (t[1] + fx * (t[3] + fx * t[6])) +
|
|
1056
1131
|
# fy * (t[2] + fx * (t[4] + fx * t[7]) +
|
|
1057
1132
|
# fy * (t[5] + fx * t[8] + fy * t[9]));
|
|
1058
|
-
t =
|
|
1133
|
+
t = self._yx_t
|
|
1059
1134
|
v = _1_0, fx, fy
|
|
1060
1135
|
H = Fdot(v, t[5], t[8], t[9])
|
|
1061
1136
|
H *= fy
|
|
@@ -1083,27 +1158,6 @@ class GeoidKarney(_GeoidBase):
|
|
|
1083
1158
|
p = self._pgm
|
|
1084
1159
|
return (p.slat + p.dlat * y), (p.wlon + p.dlon * x)
|
|
1085
1160
|
|
|
1086
|
-
def height(self, lats, lons, **wrap):
|
|
1087
|
-
'''Interpolate the geoid height for one or several lat-/longitudes.
|
|
1088
|
-
|
|
1089
|
-
@arg lats: Latitude or latitudes (C{degrees} or C{degrees}s).
|
|
1090
|
-
@arg lons: Longitude or longitudes (C{degrees} or C{degrees}s).
|
|
1091
|
-
@kwarg wrap: If C{True}, wrap or I{normalize} all B{C{lats}}
|
|
1092
|
-
and B{C{lons}} locations (C{bool}).
|
|
1093
|
-
|
|
1094
|
-
@return: A single interpolated geoid height (C{float}) or a
|
|
1095
|
-
list of interpolated geoid heights (C{float}s).
|
|
1096
|
-
|
|
1097
|
-
@raise GeoidError: Insufficient or non-matching number of
|
|
1098
|
-
B{C{lats}} and B{C{lons}} or the C{egm*.pgm}
|
|
1099
|
-
geoid file is closed.
|
|
1100
|
-
|
|
1101
|
-
@raise RangeError: A B{C{lat}} or B{C{lon}} is outside this
|
|
1102
|
-
geoid's lat- or longitude range.
|
|
1103
|
-
'''
|
|
1104
|
-
lls = self._as_lls(lats, lons)
|
|
1105
|
-
return self(lls, **wrap) # __call__(ll) or __call__(lls)
|
|
1106
|
-
|
|
1107
1161
|
@Property_RO
|
|
1108
1162
|
def _highest_ltd(self):
|
|
1109
1163
|
'''(INTERNAL) Cache for C{.highest}.
|
|
@@ -1249,8 +1303,7 @@ class GeoidPGM(_GeoidBase):
|
|
|
1249
1303
|
_cropped = False
|
|
1250
1304
|
_endian = '>u2'
|
|
1251
1305
|
|
|
1252
|
-
def __init__(self, egm_pgm, crop=None, datum=
|
|
1253
|
-
kind=3, smooth=0, **name):
|
|
1306
|
+
def __init__(self, egm_pgm, crop=None, datum=_WGS84, kind=3, smooth=0, **name):
|
|
1254
1307
|
'''New L{GeoidPGM} interpolator.
|
|
1255
1308
|
|
|
1256
1309
|
@arg egm_pgm: An U{EGM geoid dataset<https://GeographicLib.SourceForge.io/
|
|
@@ -1260,7 +1313,7 @@ class GeoidPGM(_GeoidBase):
|
|
|
1260
1313
|
in C{degrees90} lat- and C{degrees180} longitudes or a 2-tuple
|
|
1261
1314
|
(C{LatLonSW, LatLonNE}) of C{LatLon} instances.
|
|
1262
1315
|
@kwarg datum: Optional grid datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or
|
|
1263
|
-
L{a_f2Tuple}),
|
|
1316
|
+
L{a_f2Tuple}), overriding C{WGS84}.
|
|
1264
1317
|
@kwarg kind: C{scipy.interpolate} order (C{int}), use 1..5 for U{RectBivariateSpline
|
|
1265
1318
|
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.interpolate.
|
|
1266
1319
|
RectBivariateSpline.html>} or -1, -3 or -5 for U{bisplrep/-ev<https://
|
|
@@ -1670,7 +1723,7 @@ if __name__ == '__main__': # MCCABE 14
|
|
|
1670
1723
|
from pygeodesy.internals import printf, _secs2str, _versions, _sys
|
|
1671
1724
|
from time import time
|
|
1672
1725
|
|
|
1673
|
-
_crop =
|
|
1726
|
+
_crop = {}
|
|
1674
1727
|
_GeoidEGM = GeoidKarney
|
|
1675
1728
|
_kind = 3
|
|
1676
1729
|
|
|
@@ -1679,7 +1732,10 @@ if __name__ == '__main__': # MCCABE 14
|
|
|
1679
1732
|
geoid = geoids.pop(0)
|
|
1680
1733
|
|
|
1681
1734
|
if '-crop'.startswith(geoid.lower()):
|
|
1682
|
-
_crop = 20, -125, 50, -65 # CONUS
|
|
1735
|
+
_crop = dict(crp=(20, -125, 50, -65)) # CONUS
|
|
1736
|
+
|
|
1737
|
+
elif '-egm96'.startswith(geoid.lower()):
|
|
1738
|
+
_GeoidEGM = GeoidEGM96
|
|
1683
1739
|
|
|
1684
1740
|
elif '-karney'.startswith(geoid.lower()):
|
|
1685
1741
|
_GeoidEGM = GeoidKarney
|
|
@@ -1690,13 +1746,15 @@ if __name__ == '__main__': # MCCABE 14
|
|
|
1690
1746
|
elif '-pgm'.startswith(geoid.lower()):
|
|
1691
1747
|
_GeoidEGM = GeoidPGM
|
|
1692
1748
|
|
|
1693
|
-
elif geoid[-4:].lower() in ('.pgm',):
|
|
1694
|
-
g = _GeoidEGM(geoid,
|
|
1749
|
+
elif geoid[-4:].lower() in ('.pgm', '.grd'):
|
|
1750
|
+
g = _GeoidEGM(geoid, kind=_kind, **_crop)
|
|
1695
1751
|
t = time()
|
|
1696
1752
|
_ = g.highest()
|
|
1697
1753
|
t = _secs2str(time() - t)
|
|
1698
1754
|
printf('%s: %s (%s)', g.toStr(), t, _versions(), nl=1, nt=1)
|
|
1699
|
-
|
|
1755
|
+
t = g.pgm
|
|
1756
|
+
if t:
|
|
1757
|
+
printf(repr(t), nt=1)
|
|
1700
1758
|
# <https://GeographicLib.SourceForge.io/cgi-bin/GeoidEval>:
|
|
1701
1759
|
# The height of the EGM96 geoid at Timbuktu
|
|
1702
1760
|
# echo 16:46:33N 3:00:34W | GeoidEval
|
|
@@ -1722,8 +1780,8 @@ if __name__ == '__main__': # MCCABE 14
|
|
|
1722
1780
|
else:
|
|
1723
1781
|
raise GeoidError(grid=repr(geoid))
|
|
1724
1782
|
|
|
1725
|
-
_I = int
|
|
1726
|
-
del _intCs # trash ints cache
|
|
1783
|
+
_I = int # PYCHOK unused _I
|
|
1784
|
+
del _intCs, _T, _T0s12 # trash ints cache and map
|
|
1727
1785
|
|
|
1728
1786
|
|
|
1729
1787
|
# <https://GeographicLib.SourceForge.io/cgi-bin/GeoidEval>
|
|
@@ -1740,6 +1798,14 @@ del _intCs # trash ints cache
|
|
|
1740
1798
|
# _upperright = 90, 180, 13.0980 # egm84-15.pgm
|
|
1741
1799
|
|
|
1742
1800
|
|
|
1801
|
+
# % python3.12 -m pygeodesy.geoids -egm96 ../testGeoids/WW15MGH.GRD
|
|
1802
|
+
#
|
|
1803
|
+
# GeoidEGM96('WW15MGH.GRD'): lowerleft(-90.0, -180.0, -29.534), upperright(90.0, 180.25, 13.606), center(0.0, 0.125, 17.125), highest(-8.25, -32.75, 85.391), lowest(4.75, -101.25, -106.991): 1.267 ms (pygeodesy 24.12.24 Python 3.12.7 64bit arm64 macOS 14.6.1)
|
|
1804
|
+
#
|
|
1805
|
+
# Timbuktu GeoidEGM96('WW15MGH.GRD').height(16.775833, -3.009444): 28.7073 vs 28.7880
|
|
1806
|
+
# Timbuktu GeoidEGM96('WW15MGH.GRD').height(16.776, -3.009): 28.7072 vs 28.7880
|
|
1807
|
+
|
|
1808
|
+
|
|
1743
1809
|
# % python3.12 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
|
|
1744
1810
|
#
|
|
1745
1811
|
# 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)
|
|
@@ -1764,6 +1830,14 @@ del _intCs # trash ints cache
|
|
|
1764
1830
|
# Timbuktu GeoidKarney('egm96-5.pgm').height(16.776, -3.009): 28.7067 vs 28.7067
|
|
1765
1831
|
|
|
1766
1832
|
|
|
1833
|
+
# % python3.8 -m pygeodesy.geoids -egm96 ../testGeoids/WW15MGH.GRD
|
|
1834
|
+
#
|
|
1835
|
+
# GeoidEGM96('WW15MGH.GRD'): lowerleft(-90.0, -180.0, -29.534), upperright(90.0, 180.25, 13.606), center(0.0, 0.125, 17.125), highest(-8.25, -32.75, 85.391), lowest(4.75, -101.25, -106.991): 1.267 ms (pygeodesy 24.12.24 Python 3.8.10 64bit arm64_x86_64 macOS 10.16)
|
|
1836
|
+
#
|
|
1837
|
+
# Timbuktu GeoidEGM96('WW15MGH.GRD').height(16.775833, -3.009444): 28.7073 vs 28.7880
|
|
1838
|
+
# Timbuktu GeoidEGM96('WW15MGH.GRD').height(16.776, -3.009): 28.7072 vs 28.7880
|
|
1839
|
+
|
|
1840
|
+
|
|
1767
1841
|
# % python3.8 -m pygeodesy.geoids -Karney ../testGeoids/egm*.pgm
|
|
1768
1842
|
#
|
|
1769
1843
|
# 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)
|
|
@@ -1837,7 +1911,7 @@ del _intCs # trash ints cache
|
|
|
1837
1911
|
|
|
1838
1912
|
# **) MIT License
|
|
1839
1913
|
#
|
|
1840
|
-
# Copyright (C) 2016-
|
|
1914
|
+
# Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
|
|
1841
1915
|
#
|
|
1842
1916
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
1843
1917
|
# copy of this software and associated documentation files (the "Software"),
|