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.
- {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.8.24.dist-info}/METADATA +16 -15
- {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.8.24.dist-info}/RECORD +50 -50
- {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.8.24.dist-info}/WHEEL +1 -1
- pygeodesy/__init__.py +23 -23
- pygeodesy/auxilats/auxDST.py +2 -2
- pygeodesy/basics.py +3 -3
- pygeodesy/cartesianBase.py +5 -5
- pygeodesy/constants.py +11 -11
- 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/epsg.py +3 -3
- pygeodesy/fmath.py +2 -1
- pygeodesy/fsums.py +4 -4
- pygeodesy/gars.py +9 -8
- pygeodesy/geodesicx/gx.py +3 -3
- pygeodesy/geodesicx/gxarea.py +3 -3
- pygeodesy/geodsolve.py +3 -3
- pygeodesy/geohash.py +18 -11
- pygeodesy/geoids.py +293 -315
- pygeodesy/heights.py +150 -158
- pygeodesy/internals.py +21 -1
- pygeodesy/interns.py +2 -3
- pygeodesy/latlonBase.py +13 -7
- pygeodesy/lazily.py +6 -6
- pygeodesy/ltp.py +5 -6
- pygeodesy/ltpTuples.py +7 -1
- 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 +207 -201
- pygeodesy/units.py +3 -3
- 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 +20 -22
- {PyGeodesy-24.8.4.dist-info → PyGeodesy-24.8.24.dist-info}/top_level.txt +0 -0
pygeodesy/heights.py
CHANGED
|
@@ -78,8 +78,8 @@ 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
|
|
@@ -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,26 +144,11 @@ 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)
|
|
@@ -171,39 +156,48 @@ def _insufficientError(need, Error=HeightError, **name_value): # PYCHOK no cove
|
|
|
171
156
|
|
|
172
157
|
def _orderedup(ts, lo=EPS, hi=PI2-EPS):
|
|
173
158
|
# clip, order and remove duplicates
|
|
174
|
-
# p = 0
|
|
175
|
-
# for k in sorted(max(lo, min(hi, t)) for t in ts):
|
|
176
|
-
# if k > p:
|
|
177
|
-
# yield k
|
|
178
|
-
# p = k
|
|
179
159
|
return sorted(set(max(lo, min(hi, t)) for t in ts)) # list
|
|
180
160
|
|
|
181
161
|
|
|
182
|
-
def _xyhs(wrap=False, **name_lls):
|
|
162
|
+
def _xyhs(wrap=False, _lat=_90_0, _lon=_180_0, **name_lls):
|
|
183
163
|
# map (lat, lon, h) to (x, y, h) in radians, offset
|
|
184
164
|
# x as 0 <= lon <= PI2 and y as 0 <= lat <= PI
|
|
185
165
|
name, lls = _xkwds_item2(name_lls)
|
|
186
|
-
|
|
187
|
-
_m, _r, _w = max, radians, _Wrap._latlonop(wrap)
|
|
166
|
+
_r, _w = radians, _Wrap._latlonop(wrap)
|
|
188
167
|
try:
|
|
189
168
|
for i, ll in enumerate(lls):
|
|
190
169
|
y, x = _w(ll.lat, ll.lon)
|
|
191
|
-
yield
|
|
192
|
-
|
|
170
|
+
yield max(_0_0, _r(x + _lon)), \
|
|
171
|
+
max(_0_0, _r(y + _lat)), ll.height
|
|
193
172
|
except Exception as e:
|
|
194
173
|
i = Fmt.INDEX(name, i)
|
|
195
174
|
raise HeightError(i, ll, cause=e)
|
|
196
175
|
|
|
197
176
|
|
|
198
|
-
class
|
|
177
|
+
class _HeightNamed(_Named): # in .geoids
|
|
199
178
|
'''(INTERNAL) Interpolator base class.
|
|
200
179
|
'''
|
|
201
180
|
_datum = _WGS84 # default
|
|
181
|
+
_Error = HeightError
|
|
202
182
|
_kmin = 2 # min number of knots
|
|
183
|
+
|
|
203
184
|
_LLis = LatLon_ # ._height class
|
|
204
185
|
_np_sp = None # (numpy, scipy)
|
|
205
186
|
_wrap = None # wrap knots and llis
|
|
206
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
|
+
|
|
207
201
|
@property_RO
|
|
208
202
|
def datum(self):
|
|
209
203
|
'''Get the C{datum} setting or the default (L{Datum}).
|
|
@@ -223,9 +217,14 @@ class _HeightBase(_Named): # in .geoids
|
|
|
223
217
|
return self._wrap
|
|
224
218
|
|
|
225
219
|
|
|
226
|
-
class
|
|
220
|
+
class _HeightBase(_HeightNamed): # in .geoids
|
|
227
221
|
'''(INTERNAL) Interpolator base class.
|
|
228
222
|
'''
|
|
223
|
+
_k2interp2d = {-1: _linear_, # in .geoids._GeoidBase.__init__
|
|
224
|
+
-2: _linear_, # for backward compatibility
|
|
225
|
+
-3: 'cubic',
|
|
226
|
+
-5: 'quintic'}
|
|
227
|
+
|
|
229
228
|
def __call__(self, *llis, **wrap): # PYCHOK no cover
|
|
230
229
|
'''Interpolate the height for one or several locations. I{Must be overloaded}.
|
|
231
230
|
|
|
@@ -259,12 +258,29 @@ class _HeightsBase(_HeightBase): # in .geoids
|
|
|
259
258
|
'''(INTERNAL) I{Must be overloaded}.'''
|
|
260
259
|
self._notOverloaded(*args)
|
|
261
260
|
|
|
262
|
-
def
|
|
261
|
+
def _evalls(self, llis, **wrap): # XXX single arg, not *args
|
|
263
262
|
_as, xis, yis, _ = self._as_xyllis4(llis, **wrap)
|
|
264
263
|
try: # SciPy .ev signature: y first, then x!
|
|
265
264
|
return _as(self._ev(yis, xis))
|
|
266
265
|
except Exception as x:
|
|
267
|
-
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])])
|
|
268
284
|
|
|
269
285
|
def height(self, lats, lons, **wrap): # PYCHOK no cover
|
|
270
286
|
'''Interpolate the height for one or several lat-/longitudes. I{Must be overloaded}.
|
|
@@ -285,7 +301,35 @@ class _HeightsBase(_HeightBase): # in .geoids
|
|
|
285
301
|
|
|
286
302
|
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
287
303
|
'''
|
|
288
|
-
self.
|
|
304
|
+
lls = self._as_lls(lats, lons)
|
|
305
|
+
return self(lls, **wrap) # __call__(ll) or __call__(lls)
|
|
306
|
+
|
|
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.
|
|
310
|
+
'''
|
|
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])
|
|
317
|
+
|
|
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)
|
|
289
333
|
|
|
290
334
|
def _np_sp2(self, throwarnings=False): # PYCHOK no cover
|
|
291
335
|
'''(INTERNAL) Import C{numpy} and C{scipy}, once.
|
|
@@ -329,85 +373,60 @@ class _HeightsBase(_HeightBase): # in .geoids
|
|
|
329
373
|
xs, ys, hs = zip(*_xyhs(knots=knots, wrap=wrap)) # PYCHOK yield
|
|
330
374
|
n = len(hs)
|
|
331
375
|
if n < self.kmin:
|
|
332
|
-
raise
|
|
376
|
+
raise _InsufficientError(self.kmin, knots=n)
|
|
333
377
|
if name:
|
|
334
378
|
self.name = name
|
|
335
379
|
return map1(self.numpy.array, xs, ys, hs)
|
|
336
380
|
|
|
337
381
|
|
|
338
|
-
class HeightCubic(
|
|
382
|
+
class HeightCubic(_HeightBase):
|
|
339
383
|
'''Height interpolator based on C{SciPy} U{interp2d<https://docs.SciPy.org/
|
|
340
384
|
doc/scipy/reference/generated/scipy.interpolate.interp2d.html>}
|
|
341
|
-
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}.
|
|
342
387
|
'''
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
_kmin = 16
|
|
388
|
+
_kind = -3
|
|
389
|
+
_kmin = 16
|
|
346
390
|
|
|
347
391
|
def __init__(self, knots, **name_wrap):
|
|
348
392
|
'''New L{HeightCubic} interpolator.
|
|
349
393
|
|
|
350
394
|
@arg knots: The points with known height (C{LatLon}s).
|
|
351
|
-
@kwarg name_wrap: Optional C{B{name}=NN} for this height interpolator
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
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}).
|
|
355
398
|
|
|
356
|
-
@raise HeightError: Insufficient number of B{C{knots}} or
|
|
357
|
-
invalid B{C{knot}}.
|
|
399
|
+
@raise HeightError: Insufficient number of B{C{knots}} or invalid B{C{knot}}.
|
|
358
400
|
|
|
359
|
-
@raise ImportError: Package C{numpy} or C{scipy} not found
|
|
360
|
-
or not installed.
|
|
401
|
+
@raise ImportError: Package C{numpy} or C{scipy} not found or not installed.
|
|
361
402
|
|
|
362
|
-
@raise SciPyError: A C{scipy
|
|
403
|
+
@raise SciPyError: A C{scipy} issue.
|
|
363
404
|
|
|
364
|
-
@raise SciPyWarning: A C{scipy
|
|
365
|
-
as exception.
|
|
405
|
+
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
366
406
|
'''
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
xs, ys, hs = self._xyhs3(knots, **name_wrap)
|
|
370
|
-
try: # SciPy.interpolate.interp2d kind 'linear' or 'cubic'
|
|
371
|
-
self._interp2d = spi.interp2d(xs, ys, hs, kind=self._kind)
|
|
372
|
-
except Exception as x:
|
|
373
|
-
raise _SciPyIssue(x)
|
|
407
|
+
xs_yx_hs = self._xyhs3(knots, **name_wrap)
|
|
408
|
+
self._interp2d(*xs_yx_hs, kind=self._kind)
|
|
374
409
|
|
|
375
410
|
def __call__(self, *llis, **wrap):
|
|
376
411
|
'''Interpolate the height for one or several locations.
|
|
377
412
|
|
|
378
|
-
@
|
|
379
|
-
|
|
380
|
-
@raise SciPyWarning: A C{scipy.interpolate.interp2d} warning
|
|
381
|
-
as exception.
|
|
382
|
-
|
|
383
|
-
@see: L{Here<_HeightsBase.__call__>} for further details.
|
|
413
|
+
@see: L{Here<_HeightBase.__call__>} for further details.
|
|
384
414
|
'''
|
|
385
|
-
return
|
|
415
|
+
return self._evalls(llis, **wrap)
|
|
386
416
|
|
|
387
|
-
def _ev(self, yis, xis): # PYCHOK
|
|
388
|
-
# to make SciPy .interp2d
|
|
417
|
+
def _ev(self, yis, xis): # PYCHOK overwritten with .RectBivariateSpline.ev
|
|
418
|
+
# to make SciPy .interp2d single (x, y) signature
|
|
389
419
|
# match SciPy .ev signature(ys, xs), flipped multiples
|
|
390
|
-
return map(self.
|
|
391
|
-
|
|
392
|
-
def height(self, lats, lons, **wrap):
|
|
393
|
-
'''Interpolate the height for one or several lat-/longitudes.
|
|
394
|
-
|
|
395
|
-
@raise SciPyError: A C{scipy.interpolate.interp2d} issue.
|
|
396
|
-
|
|
397
|
-
@raise SciPyWarning: A C{scipy.interpolate.interp2d} warning
|
|
398
|
-
as exception.
|
|
399
|
-
|
|
400
|
-
@see: L{Here<_HeightsBase.height>} for further details.
|
|
401
|
-
'''
|
|
402
|
-
return _height_called(self, lats, lons, **wrap)
|
|
420
|
+
return map(self._ev2d, xis, yis)
|
|
403
421
|
|
|
404
422
|
|
|
405
423
|
class HeightLinear(HeightCubic):
|
|
406
424
|
'''Height interpolator based on C{SciPy} U{interp2d<https://docs.SciPy.org/
|
|
407
425
|
doc/scipy/reference/generated/scipy.interpolate.interp2d.html>}
|
|
408
|
-
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}.
|
|
409
428
|
'''
|
|
410
|
-
_kind =
|
|
429
|
+
_kind = -1
|
|
411
430
|
_kmin = 2
|
|
412
431
|
|
|
413
432
|
def __init__(self, knots, **name_wrap):
|
|
@@ -422,7 +441,7 @@ class HeightLinear(HeightCubic):
|
|
|
422
441
|
height = HeightCubic.height
|
|
423
442
|
|
|
424
443
|
|
|
425
|
-
class HeightLSQBiSpline(
|
|
444
|
+
class HeightLSQBiSpline(_HeightBase):
|
|
426
445
|
'''Height interpolator using C{SciPy} U{LSQSphereBivariateSpline
|
|
427
446
|
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
|
|
428
447
|
interpolate.LSQSphereBivariateSpline.html>}.
|
|
@@ -446,13 +465,12 @@ class HeightLSQBiSpline(_HeightsBase):
|
|
|
446
465
|
|
|
447
466
|
@raise LenError: Unequal number of B{C{knots}} and B{C{weight}}s.
|
|
448
467
|
|
|
449
|
-
@raise ImportError: Package C{numpy} or C{scipy} not found or
|
|
450
|
-
|
|
468
|
+
@raise ImportError: Package C{numpy} or C{scipy} not found or not
|
|
469
|
+
installed.
|
|
451
470
|
|
|
452
|
-
@raise SciPyError: A C{scipy}
|
|
471
|
+
@raise SciPyError: A C{scipy} issue.
|
|
453
472
|
|
|
454
|
-
@raise SciPyWarning: A C{scipy}
|
|
455
|
-
warning as exception.
|
|
473
|
+
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
456
474
|
'''
|
|
457
475
|
np = self.numpy
|
|
458
476
|
spi = self.scipy_interpolate
|
|
@@ -465,7 +483,7 @@ class HeightLSQBiSpline(_HeightsBase):
|
|
|
465
483
|
w = float(w)
|
|
466
484
|
if w <= 0:
|
|
467
485
|
raise HeightError(weight=w)
|
|
468
|
-
w =
|
|
486
|
+
w = (w,) * n
|
|
469
487
|
elif w is not None:
|
|
470
488
|
m, w = len2(w)
|
|
471
489
|
if m != n:
|
|
@@ -483,34 +501,17 @@ class HeightLSQBiSpline(_HeightsBase):
|
|
|
483
501
|
self._ev = spi.LSQSphereBivariateSpline(ys, xs, hs,
|
|
484
502
|
ts, ps, eps=EPS, w=w).ev
|
|
485
503
|
except Exception as x:
|
|
486
|
-
raise _SciPyIssue(x)
|
|
504
|
+
raise _SciPyIssue(x, self._ev_name)
|
|
487
505
|
|
|
488
506
|
def __call__(self, *llis, **wrap):
|
|
489
507
|
'''Interpolate the height for one or several locations.
|
|
490
508
|
|
|
491
|
-
@
|
|
492
|
-
|
|
493
|
-
@raise SciPyWarning: A C{scipy} C{LSQSphereBivariateSpline}
|
|
494
|
-
warning as exception.
|
|
495
|
-
|
|
496
|
-
@see: L{Here<_HeightsBase.__call__>} for further details.
|
|
509
|
+
@see: L{Here<_HeightBase.__call__>} for further details.
|
|
497
510
|
'''
|
|
498
|
-
return
|
|
499
|
-
|
|
500
|
-
def height(self, lats, lons, **wrap):
|
|
501
|
-
'''Interpolate the height for one or several lat-/longitudes.
|
|
502
|
-
|
|
503
|
-
@raise SciPyError: A C{scipy} C{LSQSphereBivariateSpline} issue.
|
|
511
|
+
return self._evalls(llis, **wrap)
|
|
504
512
|
|
|
505
|
-
@raise SciPyWarning: A C{scipy} C{LSQSphereBivariateSpline}
|
|
506
|
-
warning as exception.
|
|
507
513
|
|
|
508
|
-
|
|
509
|
-
'''
|
|
510
|
-
return _height_called(self, lats, lons, **wrap)
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
class HeightSmoothBiSpline(_HeightsBase):
|
|
514
|
+
class HeightSmoothBiSpline(_HeightBase):
|
|
514
515
|
'''Height interpolator using C{SciPy} U{SmoothSphereBivariateSpline
|
|
515
516
|
<https://docs.SciPy.org/doc/scipy/reference/generated/scipy.
|
|
516
517
|
interpolate.SmoothSphereBivariateSpline.html>}.
|
|
@@ -527,54 +528,36 @@ class HeightSmoothBiSpline(_HeightsBase):
|
|
|
527
528
|
I{normalize} all B{C{knots}} and B{C{llis}} locations iff
|
|
528
529
|
C{True} (C{bool}).
|
|
529
530
|
|
|
530
|
-
@raise HeightError: Insufficient number of B{C{knots}} or
|
|
531
|
-
|
|
531
|
+
@raise HeightError: Insufficient number of B{C{knots}} or an invalid
|
|
532
|
+
B{C{knot}} or B{C{s}}.
|
|
532
533
|
|
|
533
534
|
@raise ImportError: Package C{numpy} or C{scipy} not found or not
|
|
534
535
|
installed.
|
|
535
536
|
|
|
536
|
-
@raise SciPyError: A C{scipy}
|
|
537
|
+
@raise SciPyError: A C{scipy} issue.
|
|
537
538
|
|
|
538
|
-
@raise SciPyWarning: A C{scipy}
|
|
539
|
-
warning as exception.
|
|
539
|
+
@raise SciPyWarning: A C{scipy} warning as exception.
|
|
540
540
|
'''
|
|
541
541
|
spi = self.scipy_interpolate
|
|
542
542
|
|
|
543
|
-
s = Float_(s,
|
|
543
|
+
s = Float_(smoothing=s, Error=HeightError, low=4)
|
|
544
544
|
|
|
545
545
|
xs, ys, hs = self._xyhs3(knots, **name_wrap)
|
|
546
546
|
try:
|
|
547
547
|
self._ev = spi.SmoothSphereBivariateSpline(ys, xs, hs,
|
|
548
548
|
eps=EPS, s=s).ev
|
|
549
549
|
except Exception as x:
|
|
550
|
-
raise _SciPyIssue(x)
|
|
550
|
+
raise _SciPyIssue(x, self._ev_name)
|
|
551
551
|
|
|
552
552
|
def __call__(self, *llis, **wrap):
|
|
553
553
|
'''Interpolate the height for one or several locations.
|
|
554
554
|
|
|
555
|
-
@
|
|
556
|
-
|
|
557
|
-
@raise SciPyWarning: A C{scipy} C{SmoothSphereBivariateSpline}
|
|
558
|
-
warning as exception.
|
|
559
|
-
|
|
560
|
-
@see: L{Here<_HeightsBase.__call__>} for further details.
|
|
561
|
-
'''
|
|
562
|
-
return _HeightsBase._eval(self, llis, **wrap)
|
|
563
|
-
|
|
564
|
-
def height(self, lats, lons, **wrap):
|
|
565
|
-
'''Interpolate the height for one or several lat-/longitudes.
|
|
566
|
-
|
|
567
|
-
@raise SciPyError: A C{scipy} C{SmoothSphereBivariateSpline} issue.
|
|
568
|
-
|
|
569
|
-
@raise SciPyWarning: A C{scipy} C{SmoothSphereBivariateSpline}
|
|
570
|
-
warning as exception.
|
|
571
|
-
|
|
572
|
-
@see: L{Here<_HeightsBase.height>} for further details.
|
|
555
|
+
@see: L{Here<_HeightBase.__call__>} for further details.
|
|
573
556
|
'''
|
|
574
|
-
return
|
|
557
|
+
return self._evalls(llis, **wrap)
|
|
575
558
|
|
|
576
559
|
|
|
577
|
-
class _HeightIDW(
|
|
560
|
+
class _HeightIDW(_HeightNamed):
|
|
578
561
|
'''(INTERNAL) Base class for U{Inverse Distance Weighting
|
|
579
562
|
<https://WikiPedia.org/wiki/Inverse_distance_weighting>} (IDW) height
|
|
580
563
|
interpolators.
|
|
@@ -608,7 +591,7 @@ class _HeightIDW(_HeightBase):
|
|
|
608
591
|
|
|
609
592
|
n, self._knots = len2(knots)
|
|
610
593
|
if n < self.kmin:
|
|
611
|
-
raise
|
|
594
|
+
raise _InsufficientError(self.kmin, knots=n)
|
|
612
595
|
self.beta = beta
|
|
613
596
|
self._kwds = kwds or {}
|
|
614
597
|
|
|
@@ -684,6 +667,16 @@ class _HeightIDW(_HeightBase):
|
|
|
684
667
|
i = Fmt.INDEX(knots=i)
|
|
685
668
|
raise HeightError(i, k, cause=e)
|
|
686
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
|
+
|
|
687
680
|
def height(self, lats, lons, **wrap):
|
|
688
681
|
'''Interpolate the height for one or several lat-/longitudes.
|
|
689
682
|
|
|
@@ -698,7 +691,8 @@ class _HeightIDW(_HeightBase):
|
|
|
698
691
|
@raise HeightError: Insufficient or non-matching number of B{C{lats}}
|
|
699
692
|
and B{C{lons}} or a L{pygeodesy.fidw} issue.
|
|
700
693
|
'''
|
|
701
|
-
|
|
694
|
+
lls = self._as_lls(lats, lons)
|
|
695
|
+
return self(lls, **wrap) # __call__(ll) or __call__(lls)
|
|
702
696
|
|
|
703
697
|
@Property_RO
|
|
704
698
|
def _heights(self):
|
|
@@ -851,7 +845,7 @@ class HeightIDWdistanceTo(_HeightIDW):
|
|
|
851
845
|
_HeightIDW.__init__(self, knots, beta=beta, **name__distanceTo_kwds)
|
|
852
846
|
ks0 = _distanceTo(HeightError, knots=self._knots)[0]
|
|
853
847
|
# use knots[0] class and datum to create compatible points
|
|
854
|
-
# in
|
|
848
|
+
# in ._as_lls instead of class LatLon_ and datum None
|
|
855
849
|
self._datum = ks0.datum
|
|
856
850
|
self._LLis = ks0.classof # type(ks0)
|
|
857
851
|
|
|
@@ -859,12 +853,11 @@ class HeightIDWdistanceTo(_HeightIDW):
|
|
|
859
853
|
'''(INTERNAL) Yield distances to C{(x, y)}.
|
|
860
854
|
'''
|
|
861
855
|
kwds, ll = self._kwds, self._LLis(y, x)
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
raise HeightError(i, k, cause=e)
|
|
856
|
+
|
|
857
|
+
def _To(k):
|
|
858
|
+
return k.distanceTo(ll, **kwds)
|
|
859
|
+
|
|
860
|
+
return self._distancesTo(_To)
|
|
868
861
|
|
|
869
862
|
if _FOR_DOCS:
|
|
870
863
|
__call__ = _HeightIDW.__call__
|
|
@@ -892,12 +885,11 @@ class HeightIDWequirectangular(_HeightIDW):
|
|
|
892
885
|
'''(INTERNAL) Yield distances to C{(x, y)}.
|
|
893
886
|
'''
|
|
894
887
|
_f, kwds = _formy.equirectangular4, self._kwds
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
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)
|
|
901
893
|
|
|
902
894
|
if _FOR_DOCS:
|
|
903
895
|
__call__ = _HeightIDW.__call__
|
|
@@ -1114,7 +1106,7 @@ class HeightIDWvincentys(_HeightIDW):
|
|
|
1114
1106
|
height = _HeightIDW.height
|
|
1115
1107
|
|
|
1116
1108
|
|
|
1117
|
-
__all__ += _ALL_DOCS(_HeightBase, _HeightIDW,
|
|
1109
|
+
__all__ += _ALL_DOCS(_HeightBase, _HeightIDW, _HeightNamed)
|
|
1118
1110
|
|
|
1119
1111
|
# **) MIT License
|
|
1120
1112
|
#
|
pygeodesy/internals.py
CHANGED
|
@@ -18,6 +18,7 @@ _0_0 = 0.0 # PYCHOK in .basics, .constants
|
|
|
18
18
|
_arm64_ = 'arm64'
|
|
19
19
|
_iOS_ = 'iOS'
|
|
20
20
|
_macOS_ = 'macOS'
|
|
21
|
+
_SIsecs = 'fs', 'ps', 'ns', 'us', 'ms', 'sec' # reversed
|
|
21
22
|
_Windows_ = 'Windows'
|
|
22
23
|
|
|
23
24
|
|
|
@@ -443,6 +444,25 @@ def _Pythonarchine(sep=NN): # in .lazily, test/bases.py versions
|
|
|
443
444
|
return sep.join(l3) if sep else l3 # 3- or 4-list
|
|
444
445
|
|
|
445
446
|
|
|
447
|
+
def _secs2str(secs): # in .geoids, ../test/bases.py
|
|
448
|
+
'''Convert a time in C{secs} to C{str}.
|
|
449
|
+
'''
|
|
450
|
+
if secs < _MODS.constants._100_0:
|
|
451
|
+
unit = len(_SIsecs) - 1
|
|
452
|
+
while 0 < secs < 1 and unit > 0:
|
|
453
|
+
secs *= 1e3 # _1000_0
|
|
454
|
+
unit -= 1
|
|
455
|
+
t = '%.3f %s' % (secs, _SIsecs[unit])
|
|
456
|
+
else:
|
|
457
|
+
m, s = divmod(secs, 60)
|
|
458
|
+
if m < 60:
|
|
459
|
+
t = '%d:%06.3f' % (int(m), s)
|
|
460
|
+
else:
|
|
461
|
+
h, m = divmod(int(m), 60)
|
|
462
|
+
t = '%d:%02d:%06.3f' % (h, m, s)
|
|
463
|
+
return t
|
|
464
|
+
|
|
465
|
+
|
|
446
466
|
def _sizeof(obj):
|
|
447
467
|
'''(INTERNAL) Recursively size an C{obj}ect.
|
|
448
468
|
|
|
@@ -591,7 +611,7 @@ def _versions(sep=_SPACE_):
|
|
|
591
611
|
|
|
592
612
|
|
|
593
613
|
__all__ = tuple(map(_dunder_nameof, (machine, print_, printf)))
|
|
594
|
-
__version__ = '24.08.
|
|
614
|
+
__version__ = '24.08.24'
|
|
595
615
|
|
|
596
616
|
if _dunder_ismain(__name__): # PYCHOK no cover
|
|
597
617
|
|
pygeodesy/interns.py
CHANGED
|
@@ -184,7 +184,6 @@ _concentric_ = 'concentric' # PYCHOK OK
|
|
|
184
184
|
_convergence_ = _Prefix('convergence') # PYCHOK OK
|
|
185
185
|
_conversion_ = 'conversion' # PYCHOK OK
|
|
186
186
|
_convex_ = 'convex' # PYCHOK OK
|
|
187
|
-
_cubic_ = 'cubic' # PYCHOK OK
|
|
188
187
|
_d_ = 'd' # PYCHOK OK
|
|
189
188
|
_D_ = 'D' # PYCHOK OK
|
|
190
189
|
_DASH_ = Str_('-') # PYCHOK == _MINUS_
|
|
@@ -250,6 +249,7 @@ _inside_ = 'inside' # PYCHOK OK
|
|
|
250
249
|
_insufficient_ = 'insufficient' # PYCHOK OK
|
|
251
250
|
_intersection_ = 'intersection' # PYCHOK OK
|
|
252
251
|
_Intl1924_ = 'Intl1924' # PYCHOK OK
|
|
252
|
+
_INV_ = 'INV' # PYCHOK INValid
|
|
253
253
|
_invalid_ = 'invalid' # PYCHOK OK
|
|
254
254
|
_invokation_ = 'invokation' # PYCHOK OK
|
|
255
255
|
_j_ = 'j' # PYCHOK OK
|
|
@@ -270,7 +270,6 @@ _LCURLY_ = '{' # PYCHOK LBRACE
|
|
|
270
270
|
_len_ = 'len' # PYCHOK OK
|
|
271
271
|
_limit_ = 'limit' # PYCHOK OK
|
|
272
272
|
_line_ = 'line' # PYCHOK OK
|
|
273
|
-
_linear_ = 'linear' # PYCHOK OK
|
|
274
273
|
_LPAREN_ = '(' # PYCHOK OK
|
|
275
274
|
_lon_ = 'lon' # PYCHOK OK
|
|
276
275
|
_lon0_ = 'lon0' # PYCHOK OK
|
|
@@ -441,7 +440,7 @@ _LR_PAIRS = {_LANGLE_: _RANGLE_,
|
|
|
441
440
|
|
|
442
441
|
__all__ = (_NN_, # NOT MISSING!
|
|
443
442
|
Str_.__name__) # classes
|
|
444
|
-
__version__ = '24.
|
|
443
|
+
__version__ = '24.08.22'
|
|
445
444
|
|
|
446
445
|
if __name__ == '__main__':
|
|
447
446
|
|
pygeodesy/latlonBase.py
CHANGED
|
@@ -54,7 +54,7 @@ from contextlib import contextmanager
|
|
|
54
54
|
from math import asin, cos, degrees, fabs, radians
|
|
55
55
|
|
|
56
56
|
__all__ = _ALL_LAZY.latlonBase
|
|
57
|
-
__version__ = '24.
|
|
57
|
+
__version__ = '24.08.18'
|
|
58
58
|
|
|
59
59
|
_formy = _MODS.into(formy=__name__)
|
|
60
60
|
|
|
@@ -247,7 +247,7 @@ class LatLonBase(_NamedBase):
|
|
|
247
247
|
|
|
248
248
|
@arg point2: Second point (C{LatLon}).
|
|
249
249
|
@arg point3: Third point (C{LatLon}).
|
|
250
|
-
@kwarg circum: If C{True} return the C{circumradius} and C{circumcenter},
|
|
250
|
+
@kwarg circum: If C{True}, return the C{circumradius} and C{circumcenter},
|
|
251
251
|
always, ignoring the I{Meeus}' Type I case (C{bool}).
|
|
252
252
|
@kwarg eps: Tolerance for function L{pygeodesy.trilaterate3d2}.
|
|
253
253
|
@kwarg wrap_name: Optional C{B{name}=NN} (C{str}) and optional keyword
|
|
@@ -699,9 +699,9 @@ class LatLonBase(_NamedBase):
|
|
|
699
699
|
I{overriding} this datum (L{Datum}, L{Ellipsoid},
|
|
700
700
|
L{Ellipsoid2}, L{a_f2Tuple}, L{Triaxial}, L{Triaxial_},
|
|
701
701
|
L{JacobiConformal} or C{meter}, conventionally).
|
|
702
|
-
@kwarg normal: If C{True} the projection is the normal to this
|
|
703
|
-
|
|
704
|
-
|
|
702
|
+
@kwarg normal: If C{True}, the projection is the normal to this ellipsoid's
|
|
703
|
+
surface, otherwise the intersection of the I{radial} line to
|
|
704
|
+
this ellipsoid's center (C{bool}).
|
|
705
705
|
@kwarg LatLon: Optional class to return the projection, height and
|
|
706
706
|
datum (C{LatLon}) or C{None}.
|
|
707
707
|
@kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword arguments,
|
|
@@ -1483,8 +1483,8 @@ class LatLonBase(_NamedBase):
|
|
|
1483
1483
|
'''Get this point I{normalized} to C{abs(lat) <= 90}
|
|
1484
1484
|
and C{abs(lon) <= 180}.
|
|
1485
1485
|
|
|
1486
|
-
@kwarg deep: If C{True} make a deep, otherwise a
|
|
1487
|
-
|
|
1486
|
+
@kwarg deep: If C{True}, make a deep, otherwise a shallow
|
|
1487
|
+
copy (C{bool}).
|
|
1488
1488
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
1489
1489
|
|
|
1490
1490
|
@return: A copy of this point, I{normalized} (C{LatLon}),
|
|
@@ -1650,6 +1650,12 @@ class LatLonBase(_NamedBase):
|
|
|
1650
1650
|
'''
|
|
1651
1651
|
return self._ecef9.xyz
|
|
1652
1652
|
|
|
1653
|
+
@property_RO
|
|
1654
|
+
def xyz3(self):
|
|
1655
|
+
'''Get the I{geocentric} C{(x, y, z)} coordinates as C{3-tuple}.
|
|
1656
|
+
'''
|
|
1657
|
+
return tuple(self.xyz)
|
|
1658
|
+
|
|
1653
1659
|
@Property_RO
|
|
1654
1660
|
def xyzh(self):
|
|
1655
1661
|
'''Get the I{geocentric} C{(x, y, z)} coordinates and height (L{Vector4Tuple}C{(x, y, z, h)})
|