pygeodesy 24.7.24__py2.py3-none-any.whl → 24.8.24__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/METADATA +20 -19
- {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/RECORD +57 -57
- {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/WHEEL +1 -1
- pygeodesy/__init__.py +26 -27
- pygeodesy/auxilats/auxAngle.py +2 -2
- pygeodesy/auxilats/auxDST.py +3 -3
- pygeodesy/azimuthal.py +4 -4
- pygeodesy/basics.py +3 -3
- pygeodesy/cartesianBase.py +6 -6
- pygeodesy/constants.py +11 -11
- pygeodesy/css.py +5 -5
- pygeodesy/ellipsoidalBase.py +18 -15
- pygeodesy/ellipsoidalExact.py +2 -2
- pygeodesy/ellipsoidalGeodSolve.py +2 -2
- pygeodesy/ellipsoidalKarney.py +2 -2
- pygeodesy/ellipsoidalNvector.py +2 -2
- pygeodesy/ellipsoidalVincenty.py +7 -6
- pygeodesy/ellipsoids.py +3 -3
- pygeodesy/epsg.py +3 -3
- pygeodesy/fmath.py +2 -1
- pygeodesy/formy.py +2 -2
- pygeodesy/fsums.py +4 -4
- pygeodesy/gars.py +66 -58
- pygeodesy/geodesici.py +4 -10
- pygeodesy/geodesicx/gx.py +3 -3
- pygeodesy/geodesicx/gxarea.py +3 -3
- pygeodesy/geodsolve.py +3 -3
- pygeodesy/geohash.py +491 -267
- pygeodesy/geoids.py +298 -316
- pygeodesy/heights.py +176 -194
- pygeodesy/internals.py +39 -6
- pygeodesy/interns.py +2 -3
- pygeodesy/karney.py +2 -2
- pygeodesy/latlonBase.py +14 -8
- pygeodesy/lazily.py +22 -21
- pygeodesy/ltp.py +6 -7
- pygeodesy/ltpTuples.py +12 -6
- pygeodesy/named.py +5 -4
- pygeodesy/namedTuples.py +14 -1
- pygeodesy/osgr.py +7 -7
- pygeodesy/points.py +2 -2
- pygeodesy/resections.py +7 -7
- pygeodesy/rhumb/solve.py +3 -3
- pygeodesy/simplify.py +10 -10
- pygeodesy/sphericalBase.py +3 -3
- pygeodesy/sphericalTrigonometry.py +2 -2
- pygeodesy/streprs.py +3 -3
- pygeodesy/triaxials.py +210 -204
- pygeodesy/units.py +36 -19
- pygeodesy/unitsBase.py +4 -4
- pygeodesy/utmupsBase.py +3 -3
- pygeodesy/vector2d.py +158 -51
- pygeodesy/vector3d.py +13 -52
- pygeodesy/vector3dBase.py +81 -63
- pygeodesy/webmercator.py +3 -3
- pygeodesy/wgrs.py +109 -101
- {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/top_level.txt +0 -0
pygeodesy/heights.py
CHANGED
|
@@ -69,7 +69,7 @@ C{>>> hs = hinterpolator.height(lats, lons)}
|
|
|
69
69
|
from __future__ import division as _; del _ # PYCHOK semicolon
|
|
70
70
|
|
|
71
71
|
from pygeodesy.basics import isscalar, len2, map1, map2, _xnumpy, _xscipy
|
|
72
|
-
from pygeodesy.constants import EPS, PI, PI2, _0_0, _90_0, _180_0
|
|
72
|
+
from pygeodesy.constants import EPS, PI, PI_2, PI2, _0_0, _90_0, _180_0
|
|
73
73
|
from pygeodesy.datums import _ellipsoidal_datum, _WGS84
|
|
74
74
|
from pygeodesy.errors import _AssertionError, LenError, PointsError, \
|
|
75
75
|
_SciPyIssue, _xattr, _xkwds, _xkwds_get, _xkwds_item2
|
|
@@ -78,12 +78,12 @@ from pygeodesy.errors import _AssertionError, LenError, PointsError, \
|
|
|
78
78
|
# cosineLaw, equirectangular4, euclidean, flatLocal, \
|
|
79
79
|
# flatPolar, haversine, thomas, vincentys # _MODS.into
|
|
80
80
|
# from pygeodesy.internals import _version2 # _MODS
|
|
81
|
-
from pygeodesy.interns import NN, _COMMASPACE_,
|
|
82
|
-
|
|
81
|
+
from pygeodesy.interns import NN, _COMMASPACE_, _insufficient_, _NOTEQUAL_, \
|
|
82
|
+
_PLUS_, _scipy_, _SPACE_, _STAR_
|
|
83
83
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
|
|
84
84
|
from pygeodesy.named import _name2__, _Named
|
|
85
85
|
from pygeodesy.points import _distanceTo, LatLon_, Fmt, radians, _Wrap
|
|
86
|
-
from pygeodesy.props import Property_RO, property_RO
|
|
86
|
+
from pygeodesy.props import Property_RO, property_RO, property_ROver
|
|
87
87
|
# from pygeodesy.streprs import Fmt # from .points
|
|
88
88
|
from pygeodesy.units import _isDegrees, Float_, Int_
|
|
89
89
|
# from pygeodesy.utily import _Wrap # from .points
|
|
@@ -91,12 +91,12 @@ from pygeodesy.units import _isDegrees, Float_, Int_
|
|
|
91
91
|
# from math import radians # from .points
|
|
92
92
|
|
|
93
93
|
__all__ = _ALL_LAZY.heights
|
|
94
|
-
__version__ = '24.
|
|
94
|
+
__version__ = '24.08.24'
|
|
95
95
|
|
|
96
|
-
_error_
|
|
97
|
-
_formy
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
_error_ = 'error'
|
|
97
|
+
_formy = _MODS.into(formy=__name__)
|
|
98
|
+
_linear_ = 'linear'
|
|
99
|
+
_llis_ = 'llis'
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
class HeightError(PointsError):
|
|
@@ -144,67 +144,60 @@ def _as_llis2(llis, m=1, Error=HeightError): # in .geoids
|
|
|
144
144
|
_as = _atuple # return tuple of interpolated heights
|
|
145
145
|
|
|
146
146
|
if n < m:
|
|
147
|
-
raise
|
|
147
|
+
raise _InsufficientError(m, Error=Error, llis=n)
|
|
148
148
|
return _as, llis
|
|
149
149
|
|
|
150
150
|
|
|
151
|
-
def
|
|
152
|
-
LLis, d = inst._LLis, inst.datum
|
|
153
|
-
if _isDegrees(lats) and _isDegrees(lons):
|
|
154
|
-
llis = LLis(lats, lons, datum=d)
|
|
155
|
-
else:
|
|
156
|
-
n, lats = len2(lats)
|
|
157
|
-
m, lons = len2(lons)
|
|
158
|
-
if n != m:
|
|
159
|
-
# format a LenError, but raise an Error
|
|
160
|
-
e = LenError(inst.__class__, lats=n, lons=m, txt=None)
|
|
161
|
-
raise e if Error is LenError else Error(str(e))
|
|
162
|
-
llis = [LLis(*t, datum=d) for t in zip(lats, lons)]
|
|
163
|
-
return inst(llis, **wrap) # __call__(lli) or __call__(llis)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def _insufficientError(need, Error=HeightError, **name_value): # PYCHOK no cover
|
|
151
|
+
def _InsufficientError(need, Error=HeightError, **name_value): # PYCHOK no cover
|
|
167
152
|
# create an insufficient Error instance
|
|
168
153
|
t = _COMMASPACE_(_insufficient_, str(need) + _PLUS_)
|
|
169
154
|
return Error(txt=t, **name_value)
|
|
170
155
|
|
|
171
156
|
|
|
172
|
-
def
|
|
157
|
+
def _orderedup(ts, lo=EPS, hi=PI2-EPS):
|
|
173
158
|
# clip, order and remove duplicates
|
|
174
|
-
# p, ks = 0, []
|
|
175
|
-
# for k in sorted(max(lo, min(hi, t)) for t in ts):
|
|
176
|
-
# if k > p:
|
|
177
|
-
# ks.append(k)
|
|
178
|
-
# p = k
|
|
179
|
-
# return ks
|
|
180
159
|
return sorted(set(max(lo, min(hi, t)) for t in ts)) # list
|
|
181
160
|
|
|
182
161
|
|
|
183
|
-
def _xyhs(wrap=False, **name_lls):
|
|
162
|
+
def _xyhs(wrap=False, _lat=_90_0, _lon=_180_0, **name_lls):
|
|
184
163
|
# map (lat, lon, h) to (x, y, h) in radians, offset
|
|
185
164
|
# x as 0 <= lon <= PI2 and y as 0 <= lat <= PI
|
|
186
165
|
name, lls = _xkwds_item2(name_lls)
|
|
187
|
-
|
|
188
|
-
_m, _r, _w = max, radians, _Wrap._latlonop(wrap)
|
|
166
|
+
_r, _w = radians, _Wrap._latlonop(wrap)
|
|
189
167
|
try:
|
|
190
168
|
for i, ll in enumerate(lls):
|
|
191
169
|
y, x = _w(ll.lat, ll.lon)
|
|
192
|
-
yield
|
|
193
|
-
|
|
170
|
+
yield max(_0_0, _r(x + _lon)), \
|
|
171
|
+
max(_0_0, _r(y + _lat)), ll.height
|
|
194
172
|
except Exception as e:
|
|
195
173
|
i = Fmt.INDEX(name, i)
|
|
196
174
|
raise HeightError(i, ll, cause=e)
|
|
197
175
|
|
|
198
176
|
|
|
199
|
-
class
|
|
177
|
+
class _HeightNamed(_Named): # in .geoids
|
|
200
178
|
'''(INTERNAL) Interpolator base class.
|
|
201
179
|
'''
|
|
202
180
|
_datum = _WGS84 # default
|
|
181
|
+
_Error = HeightError
|
|
203
182
|
_kmin = 2 # min number of knots
|
|
183
|
+
|
|
204
184
|
_LLis = LatLon_ # ._height class
|
|
205
185
|
_np_sp = None # (numpy, scipy)
|
|
206
186
|
_wrap = None # wrap knots and llis
|
|
207
187
|
|
|
188
|
+
def _as_lls(self, lats, lons): # in .geoids
|
|
189
|
+
LLis, d = self._LLis, self.datum
|
|
190
|
+
if _isDegrees(lats) and _isDegrees(lons):
|
|
191
|
+
llis = LLis(lats, lons, datum=d)
|
|
192
|
+
else:
|
|
193
|
+
n, lats = len2(lats)
|
|
194
|
+
m, lons = len2(lons)
|
|
195
|
+
if n != m: # format a LenError, but raise self._Error
|
|
196
|
+
e = LenError(self.__class__, lats=n, lons=m, txt=None)
|
|
197
|
+
raise self._Error(str(e))
|
|
198
|
+
llis = [LLis(*t, datum=d) for t in zip(lats, lons)]
|
|
199
|
+
return llis
|
|
200
|
+
|
|
208
201
|
@property_RO
|
|
209
202
|
def datum(self):
|
|
210
203
|
'''Get the C{datum} setting or the default (L{Datum}).
|
|
@@ -224,10 +217,13 @@ class _HeightBase(_Named): # in .geoids
|
|
|
224
217
|
return self._wrap
|
|
225
218
|
|
|
226
219
|
|
|
227
|
-
class
|
|
220
|
+
class _HeightBase(_HeightNamed): # in .geoids
|
|
228
221
|
'''(INTERNAL) Interpolator base class.
|
|
229
222
|
'''
|
|
230
|
-
|
|
223
|
+
_k2interp2d = {-1: _linear_, # in .geoids._GeoidBase.__init__
|
|
224
|
+
-2: _linear_, # for backward compatibility
|
|
225
|
+
-3: 'cubic',
|
|
226
|
+
-5: 'quintic'}
|
|
231
227
|
|
|
232
228
|
def __call__(self, *llis, **wrap): # PYCHOK no cover
|
|
233
229
|
'''Interpolate the height for one or several locations. I{Must be overloaded}.
|
|
@@ -262,12 +258,29 @@ class _HeightsBase(_HeightBase): # in .geoids
|
|
|
262
258
|
'''(INTERNAL) I{Must be overloaded}.'''
|
|
263
259
|
self._notOverloaded(*args)
|
|
264
260
|
|
|
265
|
-
def
|
|
261
|
+
def _evalls(self, llis, **wrap): # XXX single arg, not *args
|
|
266
262
|
_as, xis, yis, _ = self._as_xyllis4(llis, **wrap)
|
|
267
263
|
try: # SciPy .ev signature: y first, then x!
|
|
268
264
|
return _as(self._ev(yis, xis))
|
|
269
265
|
except Exception as x:
|
|
270
|
-
raise _SciPyIssue(x)
|
|
266
|
+
raise _SciPyIssue(x, self._ev_name)
|
|
267
|
+
|
|
268
|
+
def _ev2d(self, x, y): # PYCHOK no cover
|
|
269
|
+
'''(INTERNAL) I{Must be overloaded}.'''
|
|
270
|
+
self._notOverloaded(x, y)
|
|
271
|
+
|
|
272
|
+
@property_RO
|
|
273
|
+
def _ev_name(self):
|
|
274
|
+
'''(INTERNAL) Get the name of the C{.ev} method.
|
|
275
|
+
'''
|
|
276
|
+
_ev = str(self._ev)
|
|
277
|
+
if _scipy_ not in _ev:
|
|
278
|
+
_ev = str(self._ev2d)
|
|
279
|
+
# '<scipy.interpolate._interpolate.interp2d object at ...>
|
|
280
|
+
# '<function _HeightBase._interp2d.<locals>._bisplev at ...>
|
|
281
|
+
# '<bound method BivariateSpline.ev of ... object at ...>
|
|
282
|
+
_ev = _ev[1:].split(None, 4)
|
|
283
|
+
return Fmt.PAREN(_ev['sfb'.index(_ev[0][0])])
|
|
271
284
|
|
|
272
285
|
def height(self, lats, lons, **wrap): # PYCHOK no cover
|
|
273
286
|
'''Interpolate the height for one or several lat-/longitudes. I{Must be overloaded}.
|
|
@@ -288,48 +301,67 @@ class _HeightsBase(_HeightBase): # in .geoids
|
|
|
288
301
|
|
|
289
302
|
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
290
303
|
'''
|
|
291
|
-
self.
|
|
304
|
+
lls = self._as_lls(lats, lons)
|
|
305
|
+
return self(lls, **wrap) # __call__(ll) or __call__(lls)
|
|
292
306
|
|
|
293
|
-
def
|
|
294
|
-
'''
|
|
307
|
+
def _interp2d(self, xs, ys, hs, kind=-3):
|
|
308
|
+
'''Create a C{scipy.interpolate.interp2d} or C{-.bisplrep/-ev}
|
|
309
|
+
interpolator before, respectively since C{SciPy} version 1.14.
|
|
295
310
|
'''
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if _scipy_ not in sys.modules:
|
|
303
|
-
import warnings
|
|
304
|
-
warnings.filterwarnings(_error_)
|
|
305
|
-
|
|
306
|
-
sp = _xscipy(self.__class__, 1, 2)
|
|
307
|
-
np = _xnumpy(self.__class__, 1, 9)
|
|
308
|
-
|
|
309
|
-
_HeightsBase._np_sp = t = np, sp
|
|
310
|
-
return t
|
|
311
|
+
try:
|
|
312
|
+
spi = self.scipy_interpolate
|
|
313
|
+
if self._scipy_version() < (1, 14) and kind in self._k2interp2d:
|
|
314
|
+
# SciPy.interpolate.interp2d kind 'linear', 'cubic' or 'quintic'
|
|
315
|
+
# DEPRECATED since scipy 1.10, removed altogether in 1.14
|
|
316
|
+
self._ev2d = spi.interp2d(xs, ys, hs, kind=self._k2interp2d[kind])
|
|
311
317
|
|
|
312
|
-
|
|
318
|
+
else: # <https://scipy.GitHub.io/devdocs/tutorial/interpolate/interp_transition_guide.html>
|
|
319
|
+
k = self._kxky(abs(kind))
|
|
320
|
+
# spi.RectBivariateSpline needs strictly ordered xs and ys
|
|
321
|
+
r = spi.bisplrep(xs, ys, hs.T, kx=k, ky=k)
|
|
322
|
+
|
|
323
|
+
def _bisplev(x, y):
|
|
324
|
+
return spi.bisplev(x, y, r) # .T
|
|
325
|
+
|
|
326
|
+
self._ev2d = _bisplev
|
|
327
|
+
|
|
328
|
+
except Exception as x:
|
|
329
|
+
raise _SciPyIssue(x, self._ev_name)
|
|
330
|
+
|
|
331
|
+
def _kxky(self, kind):
|
|
332
|
+
return Int_(kind=kind, low=1, high=5, Error=self._Error)
|
|
333
|
+
|
|
334
|
+
def _np_sp2(self, throwarnings=False): # PYCHOK no cover
|
|
335
|
+
'''(INTERNAL) Import C{numpy} and C{scipy}, once.
|
|
336
|
+
'''
|
|
337
|
+
# raise SciPyWarnings, but not if
|
|
338
|
+
# scipy has already been imported
|
|
339
|
+
if throwarnings: # PYCHOK no cover
|
|
340
|
+
import sys
|
|
341
|
+
if _scipy_ not in sys.modules:
|
|
342
|
+
import warnings
|
|
343
|
+
warnings.filterwarnings(_error_)
|
|
344
|
+
return self.numpy, self.scipy
|
|
345
|
+
|
|
346
|
+
@property_ROver
|
|
313
347
|
def numpy(self):
|
|
314
348
|
'''Get the C{numpy} module or C{None}.
|
|
315
349
|
'''
|
|
316
|
-
|
|
317
|
-
return np
|
|
350
|
+
return _xnumpy(self.__class__, 1, 9) # overwrite property_ROver
|
|
318
351
|
|
|
319
|
-
@
|
|
352
|
+
@property_ROver
|
|
320
353
|
def scipy(self):
|
|
321
354
|
'''Get the C{scipy} module or C{None}.
|
|
322
355
|
'''
|
|
323
|
-
|
|
324
|
-
return sp
|
|
356
|
+
return _xscipy(self.__class__, 1, 2) # overwrite property_ROver
|
|
325
357
|
|
|
326
|
-
@
|
|
358
|
+
@property_ROver
|
|
327
359
|
def scipy_interpolate(self):
|
|
328
360
|
'''Get the C{scipy.interpolate} module or C{None}.
|
|
329
361
|
'''
|
|
330
362
|
_ = self.scipy
|
|
331
363
|
import scipy.interpolate as spi # scipy 1.2.2
|
|
332
|
-
return spi
|
|
364
|
+
return spi # overwrite property_ROver
|
|
333
365
|
|
|
334
366
|
def _scipy_version(self, **n):
|
|
335
367
|
'''Get the C{scipy} version as 2- or 3-tuple C{(major, minor, micro)}.
|
|
@@ -341,85 +373,60 @@ class _HeightsBase(_HeightBase): # in .geoids
|
|
|
341
373
|
xs, ys, hs = zip(*_xyhs(knots=knots, wrap=wrap)) # PYCHOK yield
|
|
342
374
|
n = len(hs)
|
|
343
375
|
if n < self.kmin:
|
|
344
|
-
raise
|
|
376
|
+
raise _InsufficientError(self.kmin, knots=n)
|
|
345
377
|
if name:
|
|
346
378
|
self.name = name
|
|
347
379
|
return map1(self.numpy.array, xs, ys, hs)
|
|
348
380
|
|
|
349
381
|
|
|
350
|
-
class HeightCubic(
|
|
382
|
+
class HeightCubic(_HeightBase):
|
|
351
383
|
'''Height interpolator based on C{SciPy} U{interp2d<https://docs.SciPy.org/
|
|
352
384
|
doc/scipy/reference/generated/scipy.interpolate.interp2d.html>}
|
|
353
|
-
C{kind='cubic'}.
|
|
385
|
+
C{kind='cubic'} or U{bisplrep/-ev<https://docs.SciPy.org/doc/scipy/
|
|
386
|
+
reference/generated/scipy.interpolate.interp2d.html>} C{kx=ky=3}.
|
|
354
387
|
'''
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
_kmin = 16
|
|
388
|
+
_kind = -3
|
|
389
|
+
_kmin = 16
|
|
358
390
|
|
|
359
391
|
def __init__(self, knots, **name_wrap):
|
|
360
392
|
'''New L{HeightCubic} interpolator.
|
|
361
393
|
|
|
362
394
|
@arg knots: The points with known height (C{LatLon}s).
|
|
363
|
-
@kwarg name_wrap: Optional C{B{name}=NN} for this height interpolator
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
C{True} (C{bool}).
|
|
395
|
+
@kwarg name_wrap: Optional C{B{name}=NN} for this height interpolator (C{str})
|
|
396
|
+
and keyword argument C{b{wrap}=False} to wrap or I{normalize} all
|
|
397
|
+
B{C{knots}} and B{C{llis}} locations iff C{True} (C{bool}).
|
|
367
398
|
|
|
368
|
-
@raise HeightError: Insufficient number of B{C{knots}} or
|
|
369
|
-
invalid B{C{knot}}.
|
|
399
|
+
@raise HeightError: Insufficient number of B{C{knots}} or invalid B{C{knot}}.
|
|
370
400
|
|
|
371
|
-
@raise ImportError: Package C{numpy} or C{scipy} not found
|
|
372
|
-
or not installed.
|
|
401
|
+
@raise ImportError: Package C{numpy} or C{scipy} not found or not installed.
|
|
373
402
|
|
|
374
|
-
@raise SciPyError: A C{scipy
|
|
403
|
+
@raise SciPyError: A C{scipy} issue.
|
|
375
404
|
|
|
376
|
-
@raise SciPyWarning: A C{scipy
|
|
377
|
-
as exception.
|
|
405
|
+
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
378
406
|
'''
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
xs, ys, hs = self._xyhs3(knots, **name_wrap)
|
|
382
|
-
try: # SciPy.interpolate.interp2d kind 'linear' or 'cubic'
|
|
383
|
-
self._interp2d = spi.interp2d(xs, ys, hs, kind=self._kind)
|
|
384
|
-
except Exception as x:
|
|
385
|
-
raise _SciPyIssue(x)
|
|
407
|
+
xs_yx_hs = self._xyhs3(knots, **name_wrap)
|
|
408
|
+
self._interp2d(*xs_yx_hs, kind=self._kind)
|
|
386
409
|
|
|
387
410
|
def __call__(self, *llis, **wrap):
|
|
388
411
|
'''Interpolate the height for one or several locations.
|
|
389
412
|
|
|
390
|
-
@
|
|
391
|
-
|
|
392
|
-
@raise SciPyWarning: A C{scipy.interpolate.interp2d} warning
|
|
393
|
-
as exception.
|
|
394
|
-
|
|
395
|
-
@see: L{Here<_HeightsBase.__call__>} for further details.
|
|
413
|
+
@see: L{Here<_HeightBase.__call__>} for further details.
|
|
396
414
|
'''
|
|
397
|
-
return
|
|
415
|
+
return self._evalls(llis, **wrap)
|
|
398
416
|
|
|
399
|
-
def _ev(self, yis, xis): # PYCHOK
|
|
400
|
-
# to make SciPy .interp2d
|
|
417
|
+
def _ev(self, yis, xis): # PYCHOK overwritten with .RectBivariateSpline.ev
|
|
418
|
+
# to make SciPy .interp2d single (x, y) signature
|
|
401
419
|
# match SciPy .ev signature(ys, xs), flipped multiples
|
|
402
|
-
return map(self.
|
|
403
|
-
|
|
404
|
-
def height(self, lats, lons, **wrap):
|
|
405
|
-
'''Interpolate the height for one or several lat-/longitudes.
|
|
406
|
-
|
|
407
|
-
@raise SciPyError: A C{scipy.interpolate.interp2d} issue.
|
|
408
|
-
|
|
409
|
-
@raise SciPyWarning: A C{scipy.interpolate.interp2d} warning
|
|
410
|
-
as exception.
|
|
411
|
-
|
|
412
|
-
@see: L{Here<_HeightsBase.height>} for further details.
|
|
413
|
-
'''
|
|
414
|
-
return _height_called(self, lats, lons, **wrap)
|
|
420
|
+
return map(self._ev2d, xis, yis)
|
|
415
421
|
|
|
416
422
|
|
|
417
423
|
class HeightLinear(HeightCubic):
|
|
418
424
|
'''Height interpolator based on C{SciPy} U{interp2d<https://docs.SciPy.org/
|
|
419
425
|
doc/scipy/reference/generated/scipy.interpolate.interp2d.html>}
|
|
420
|
-
C{kind='linear'}.
|
|
426
|
+
C{kind='linear'} or U{bisplrep/-ev<https://docs.SciPy.org/doc/scipy/
|
|
427
|
+
reference/generated/scipy.interpolate.interp2d.html>} C{kx=ky=1}.
|
|
421
428
|
'''
|
|
422
|
-
_kind =
|
|
429
|
+
_kind = -1
|
|
423
430
|
_kmin = 2
|
|
424
431
|
|
|
425
432
|
def __init__(self, knots, **name_wrap):
|
|
@@ -434,36 +441,36 @@ class HeightLinear(HeightCubic):
|
|
|
434
441
|
height = HeightCubic.height
|
|
435
442
|
|
|
436
443
|
|
|
437
|
-
class HeightLSQBiSpline(
|
|
444
|
+
class HeightLSQBiSpline(_HeightBase):
|
|
438
445
|
'''Height interpolator using C{SciPy} U{LSQSphereBivariateSpline
|
|
439
446
|
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
|
|
440
447
|
interpolate.LSQSphereBivariateSpline.html>}.
|
|
441
448
|
'''
|
|
442
449
|
_kmin = 16 # k = 3, always
|
|
443
450
|
|
|
444
|
-
def __init__(self, knots, weight=None, **name_wrap):
|
|
451
|
+
def __init__(self, knots, weight=None, low=1e-4, **name_wrap):
|
|
445
452
|
'''New L{HeightLSQBiSpline} interpolator.
|
|
446
453
|
|
|
447
454
|
@arg knots: The points with known height (C{LatLon}s).
|
|
448
455
|
@kwarg weight: Optional weight or weights for each B{C{knot}}
|
|
449
456
|
(C{scalar} or C{scalar}s).
|
|
457
|
+
@kwarg low: Optional lower bound for I{ordered knots} (C{radians}).
|
|
450
458
|
@kwarg name_wrap: Optional C{B{name}=NN} for this height interpolator
|
|
451
459
|
(C{str}) and keyword argument C{b{wrap}=False} to wrap or
|
|
452
460
|
I{normalize} all B{C{knots}} and B{C{llis}} locations iff
|
|
453
461
|
C{True} (C{bool}).
|
|
454
462
|
|
|
455
|
-
@raise HeightError: Insufficient number of B{C{knots}} or
|
|
456
|
-
|
|
463
|
+
@raise HeightError: Insufficient number of B{C{knots}} or an invalid
|
|
464
|
+
B{C{knot}}, B{C{weight}} or B{C{eps}}.
|
|
457
465
|
|
|
458
466
|
@raise LenError: Unequal number of B{C{knots}} and B{C{weight}}s.
|
|
459
467
|
|
|
460
|
-
@raise ImportError: Package C{numpy} or C{scipy} not found or
|
|
461
|
-
|
|
468
|
+
@raise ImportError: Package C{numpy} or C{scipy} not found or not
|
|
469
|
+
installed.
|
|
462
470
|
|
|
463
|
-
@raise SciPyError: A C{scipy}
|
|
471
|
+
@raise SciPyError: A C{scipy} issue.
|
|
464
472
|
|
|
465
|
-
@raise SciPyWarning: A C{scipy}
|
|
466
|
-
warning as exception.
|
|
473
|
+
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
467
474
|
'''
|
|
468
475
|
np = self.numpy
|
|
469
476
|
spi = self.scipy_interpolate
|
|
@@ -476,7 +483,7 @@ class HeightLSQBiSpline(_HeightsBase):
|
|
|
476
483
|
w = float(w)
|
|
477
484
|
if w <= 0:
|
|
478
485
|
raise HeightError(weight=w)
|
|
479
|
-
w =
|
|
486
|
+
w = (w,) * n
|
|
480
487
|
elif w is not None:
|
|
481
488
|
m, w = len2(w)
|
|
482
489
|
if m != n:
|
|
@@ -487,40 +494,24 @@ class HeightLSQBiSpline(_HeightsBase):
|
|
|
487
494
|
w = Fmt.INDEX(weight=w.index(m))
|
|
488
495
|
raise HeightError(w, m)
|
|
489
496
|
try:
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
497
|
+
if not EPS < low < (PI_2 - EPS): # 1e-4 like SciPy example
|
|
498
|
+
raise HeightError(low=low)
|
|
499
|
+
ps = np.array(_orderedup(xs, low, PI2 - low))
|
|
500
|
+
ts = np.array(_orderedup(ys, low, PI - low))
|
|
493
501
|
self._ev = spi.LSQSphereBivariateSpline(ys, xs, hs,
|
|
494
502
|
ts, ps, eps=EPS, w=w).ev
|
|
495
503
|
except Exception as x:
|
|
496
|
-
raise _SciPyIssue(x)
|
|
504
|
+
raise _SciPyIssue(x, self._ev_name)
|
|
497
505
|
|
|
498
506
|
def __call__(self, *llis, **wrap):
|
|
499
507
|
'''Interpolate the height for one or several locations.
|
|
500
508
|
|
|
501
|
-
@
|
|
502
|
-
|
|
503
|
-
@raise SciPyWarning: A C{scipy} C{LSQSphereBivariateSpline}
|
|
504
|
-
warning as exception.
|
|
505
|
-
|
|
506
|
-
@see: L{Here<_HeightsBase.__call__>} for further details.
|
|
507
|
-
'''
|
|
508
|
-
return _HeightsBase._eval(self, llis, **wrap)
|
|
509
|
-
|
|
510
|
-
def height(self, lats, lons, **wrap):
|
|
511
|
-
'''Interpolate the height for one or several lat-/longitudes.
|
|
512
|
-
|
|
513
|
-
@raise SciPyError: A C{scipy} C{LSQSphereBivariateSpline} issue.
|
|
514
|
-
|
|
515
|
-
@raise SciPyWarning: A C{scipy} C{LSQSphereBivariateSpline}
|
|
516
|
-
warning as exception.
|
|
517
|
-
|
|
518
|
-
@see: L{Here<_HeightsBase.height>} for further details.
|
|
509
|
+
@see: L{Here<_HeightBase.__call__>} for further details.
|
|
519
510
|
'''
|
|
520
|
-
return
|
|
511
|
+
return self._evalls(llis, **wrap)
|
|
521
512
|
|
|
522
513
|
|
|
523
|
-
class HeightSmoothBiSpline(
|
|
514
|
+
class HeightSmoothBiSpline(_HeightBase):
|
|
524
515
|
'''Height interpolator using C{SciPy} U{SmoothSphereBivariateSpline
|
|
525
516
|
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
|
|
526
517
|
interpolate.SmoothSphereBivariateSpline.html>}.
|
|
@@ -537,54 +528,36 @@ class HeightSmoothBiSpline(_HeightsBase):
|
|
|
537
528
|
I{normalize} all B{C{knots}} and B{C{llis}} locations iff
|
|
538
529
|
C{True} (C{bool}).
|
|
539
530
|
|
|
540
|
-
@raise HeightError: Insufficient number of B{C{knots}} or
|
|
541
|
-
|
|
531
|
+
@raise HeightError: Insufficient number of B{C{knots}} or an invalid
|
|
532
|
+
B{C{knot}} or B{C{s}}.
|
|
542
533
|
|
|
543
534
|
@raise ImportError: Package C{numpy} or C{scipy} not found or not
|
|
544
535
|
installed.
|
|
545
536
|
|
|
546
|
-
@raise SciPyError: A C{scipy}
|
|
537
|
+
@raise SciPyError: A C{scipy} issue.
|
|
547
538
|
|
|
548
|
-
@raise SciPyWarning: A C{scipy}
|
|
549
|
-
warning as exception.
|
|
539
|
+
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
550
540
|
'''
|
|
551
541
|
spi = self.scipy_interpolate
|
|
552
542
|
|
|
553
|
-
s = Float_(s,
|
|
543
|
+
s = Float_(smoothing=s, Error=HeightError, low=4)
|
|
554
544
|
|
|
555
545
|
xs, ys, hs = self._xyhs3(knots, **name_wrap)
|
|
556
546
|
try:
|
|
557
547
|
self._ev = spi.SmoothSphereBivariateSpline(ys, xs, hs,
|
|
558
548
|
eps=EPS, s=s).ev
|
|
559
549
|
except Exception as x:
|
|
560
|
-
raise _SciPyIssue(x)
|
|
550
|
+
raise _SciPyIssue(x, self._ev_name)
|
|
561
551
|
|
|
562
552
|
def __call__(self, *llis, **wrap):
|
|
563
553
|
'''Interpolate the height for one or several locations.
|
|
564
554
|
|
|
565
|
-
@
|
|
566
|
-
|
|
567
|
-
@raise SciPyWarning: A C{scipy} C{SmoothSphereBivariateSpline}
|
|
568
|
-
warning as exception.
|
|
569
|
-
|
|
570
|
-
@see: L{Here<_HeightsBase.__call__>} for further details.
|
|
571
|
-
'''
|
|
572
|
-
return _HeightsBase._eval(self, llis, **wrap)
|
|
573
|
-
|
|
574
|
-
def height(self, lats, lons, **wrap):
|
|
575
|
-
'''Interpolate the height for one or several lat-/longitudes.
|
|
576
|
-
|
|
577
|
-
@raise SciPyError: A C{scipy} C{SmoothSphereBivariateSpline} issue.
|
|
578
|
-
|
|
579
|
-
@raise SciPyWarning: A C{scipy} C{SmoothSphereBivariateSpline}
|
|
580
|
-
warning as exception.
|
|
581
|
-
|
|
582
|
-
@see: L{Here<_HeightsBase.height>} for further details.
|
|
555
|
+
@see: L{Here<_HeightBase.__call__>} for further details.
|
|
583
556
|
'''
|
|
584
|
-
return
|
|
557
|
+
return self._evalls(llis, **wrap)
|
|
585
558
|
|
|
586
559
|
|
|
587
|
-
class _HeightIDW(
|
|
560
|
+
class _HeightIDW(_HeightNamed):
|
|
588
561
|
'''(INTERNAL) Base class for U{Inverse Distance Weighting
|
|
589
562
|
<https://WikiPedia.org/wiki/Inverse_distance_weighting>} (IDW) height
|
|
590
563
|
interpolators.
|
|
@@ -618,7 +591,7 @@ class _HeightIDW(_HeightBase):
|
|
|
618
591
|
|
|
619
592
|
n, self._knots = len2(knots)
|
|
620
593
|
if n < self.kmin:
|
|
621
|
-
raise
|
|
594
|
+
raise _InsufficientError(self.kmin, knots=n)
|
|
622
595
|
self.beta = beta
|
|
623
596
|
self._kwds = kwds or {}
|
|
624
597
|
|
|
@@ -694,6 +667,16 @@ class _HeightIDW(_HeightBase):
|
|
|
694
667
|
i = Fmt.INDEX(knots=i)
|
|
695
668
|
raise HeightError(i, k, cause=e)
|
|
696
669
|
|
|
670
|
+
def _distancesTo(self, _To):
|
|
671
|
+
'''(INTERNAL) Yield distances C{_To}.
|
|
672
|
+
'''
|
|
673
|
+
try:
|
|
674
|
+
for i, k in enumerate(self._knots):
|
|
675
|
+
yield _To(k)
|
|
676
|
+
except Exception as e:
|
|
677
|
+
i = Fmt.INDEX(knots=i)
|
|
678
|
+
raise HeightError(i, k, cause=e)
|
|
679
|
+
|
|
697
680
|
def height(self, lats, lons, **wrap):
|
|
698
681
|
'''Interpolate the height for one or several lat-/longitudes.
|
|
699
682
|
|
|
@@ -708,7 +691,8 @@ class _HeightIDW(_HeightBase):
|
|
|
708
691
|
@raise HeightError: Insufficient or non-matching number of B{C{lats}}
|
|
709
692
|
and B{C{lons}} or a L{pygeodesy.fidw} issue.
|
|
710
693
|
'''
|
|
711
|
-
|
|
694
|
+
lls = self._as_lls(lats, lons)
|
|
695
|
+
return self(lls, **wrap) # __call__(ll) or __call__(lls)
|
|
712
696
|
|
|
713
697
|
@Property_RO
|
|
714
698
|
def _heights(self):
|
|
@@ -861,7 +845,7 @@ class HeightIDWdistanceTo(_HeightIDW):
|
|
|
861
845
|
_HeightIDW.__init__(self, knots, beta=beta, **name__distanceTo_kwds)
|
|
862
846
|
ks0 = _distanceTo(HeightError, knots=self._knots)[0]
|
|
863
847
|
# use knots[0] class and datum to create compatible points
|
|
864
|
-
# in
|
|
848
|
+
# in ._as_lls instead of class LatLon_ and datum None
|
|
865
849
|
self._datum = ks0.datum
|
|
866
850
|
self._LLis = ks0.classof # type(ks0)
|
|
867
851
|
|
|
@@ -869,12 +853,11 @@ class HeightIDWdistanceTo(_HeightIDW):
|
|
|
869
853
|
'''(INTERNAL) Yield distances to C{(x, y)}.
|
|
870
854
|
'''
|
|
871
855
|
kwds, ll = self._kwds, self._LLis(y, x)
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
raise HeightError(i, k, cause=e)
|
|
856
|
+
|
|
857
|
+
def _To(k):
|
|
858
|
+
return k.distanceTo(ll, **kwds)
|
|
859
|
+
|
|
860
|
+
return self._distancesTo(_To)
|
|
878
861
|
|
|
879
862
|
if _FOR_DOCS:
|
|
880
863
|
__call__ = _HeightIDW.__call__
|
|
@@ -902,12 +885,11 @@ class HeightIDWequirectangular(_HeightIDW):
|
|
|
902
885
|
'''(INTERNAL) Yield distances to C{(x, y)}.
|
|
903
886
|
'''
|
|
904
887
|
_f, kwds = _formy.equirectangular4, self._kwds
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
raise HeightError(i, k, cause=e)
|
|
888
|
+
|
|
889
|
+
def _To(k):
|
|
890
|
+
return _f(y, x, k.lat, k.lon, **kwds).distance2
|
|
891
|
+
|
|
892
|
+
return self._distancesTo(_To)
|
|
911
893
|
|
|
912
894
|
if _FOR_DOCS:
|
|
913
895
|
__call__ = _HeightIDW.__call__
|
|
@@ -1124,7 +1106,7 @@ class HeightIDWvincentys(_HeightIDW):
|
|
|
1124
1106
|
height = _HeightIDW.height
|
|
1125
1107
|
|
|
1126
1108
|
|
|
1127
|
-
__all__ += _ALL_DOCS(_HeightBase, _HeightIDW,
|
|
1109
|
+
__all__ += _ALL_DOCS(_HeightBase, _HeightIDW, _HeightNamed)
|
|
1128
1110
|
|
|
1129
1111
|
# **) MIT License
|
|
1130
1112
|
#
|