pygeodesy 24.7.24__py2.py3-none-any.whl → 24.8.24__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/METADATA +20 -19
  2. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/RECORD +57 -57
  3. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +26 -27
  5. pygeodesy/auxilats/auxAngle.py +2 -2
  6. pygeodesy/auxilats/auxDST.py +3 -3
  7. pygeodesy/azimuthal.py +4 -4
  8. pygeodesy/basics.py +3 -3
  9. pygeodesy/cartesianBase.py +6 -6
  10. pygeodesy/constants.py +11 -11
  11. pygeodesy/css.py +5 -5
  12. pygeodesy/ellipsoidalBase.py +18 -15
  13. pygeodesy/ellipsoidalExact.py +2 -2
  14. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  15. pygeodesy/ellipsoidalKarney.py +2 -2
  16. pygeodesy/ellipsoidalNvector.py +2 -2
  17. pygeodesy/ellipsoidalVincenty.py +7 -6
  18. pygeodesy/ellipsoids.py +3 -3
  19. pygeodesy/epsg.py +3 -3
  20. pygeodesy/fmath.py +2 -1
  21. pygeodesy/formy.py +2 -2
  22. pygeodesy/fsums.py +4 -4
  23. pygeodesy/gars.py +66 -58
  24. pygeodesy/geodesici.py +4 -10
  25. pygeodesy/geodesicx/gx.py +3 -3
  26. pygeodesy/geodesicx/gxarea.py +3 -3
  27. pygeodesy/geodsolve.py +3 -3
  28. pygeodesy/geohash.py +491 -267
  29. pygeodesy/geoids.py +298 -316
  30. pygeodesy/heights.py +176 -194
  31. pygeodesy/internals.py +39 -6
  32. pygeodesy/interns.py +2 -3
  33. pygeodesy/karney.py +2 -2
  34. pygeodesy/latlonBase.py +14 -8
  35. pygeodesy/lazily.py +22 -21
  36. pygeodesy/ltp.py +6 -7
  37. pygeodesy/ltpTuples.py +12 -6
  38. pygeodesy/named.py +5 -4
  39. pygeodesy/namedTuples.py +14 -1
  40. pygeodesy/osgr.py +7 -7
  41. pygeodesy/points.py +2 -2
  42. pygeodesy/resections.py +7 -7
  43. pygeodesy/rhumb/solve.py +3 -3
  44. pygeodesy/simplify.py +10 -10
  45. pygeodesy/sphericalBase.py +3 -3
  46. pygeodesy/sphericalTrigonometry.py +2 -2
  47. pygeodesy/streprs.py +3 -3
  48. pygeodesy/triaxials.py +210 -204
  49. pygeodesy/units.py +36 -19
  50. pygeodesy/unitsBase.py +4 -4
  51. pygeodesy/utmupsBase.py +3 -3
  52. pygeodesy/vector2d.py +158 -51
  53. pygeodesy/vector3d.py +13 -52
  54. pygeodesy/vector3dBase.py +81 -63
  55. pygeodesy/webmercator.py +3 -3
  56. pygeodesy/wgrs.py +109 -101
  57. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/top_level.txt +0 -0
pygeodesy/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_, _cubic_, _insufficient_, _linear_, \
82
- _NOTEQUAL_, _PLUS_, _scipy_, _SPACE_, _STAR_
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.06.22'
94
+ __version__ = '24.08.24'
95
95
 
96
- _error_ = 'error'
97
- _formy = _MODS.into(formy=__name__)
98
- _llis_ = 'llis'
99
- _smoothing_ = 'smoothing'
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 _insufficientError(m, Error=Error, llis=n)
147
+ raise _InsufficientError(m, Error=Error, llis=n)
148
148
  return _as, llis
149
149
 
150
150
 
151
- def _height_called(inst, lats, lons, Error=HeightError, **wrap): # in .geoids
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 _ordedup(ts, lo=EPS, hi=PI2-EPS):
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
- _0, _90, _180 = _0_0, _90_0, _180_0
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 _m(_0, _r(x + _180)), \
193
- _m(_0, _r(y + _90)), ll.height
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 _HeightBase(_Named): # in .geoids
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 _HeightsBase(_HeightBase): # in .geoids
220
+ class _HeightBase(_HeightNamed): # in .geoids
228
221
  '''(INTERNAL) Interpolator base class.
229
222
  '''
230
- _np_sp = None # (numpy, scipy)
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 _eval(self, llis, **wrap): # XXX single arg, not *args
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._notOverloaded(lats, lons, **wrap)
304
+ lls = self._as_lls(lats, lons)
305
+ return self(lls, **wrap) # __call__(ll) or __call__(lls)
292
306
 
293
- def _np_sp2(self, throwarnings=False):
294
- '''(INTERNAL) Import C{numpy} and C{scipy}, once.
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
- t = _HeightsBase._np_sp
297
- if not t:
298
- # raise SciPyWarnings, but not if
299
- # scipy has already been imported
300
- if throwarnings: # PYCHOK no cover
301
- import sys
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
- @Property_RO
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
- np, _ = self._np_sp2()
317
- return np
350
+ return _xnumpy(self.__class__, 1, 9) # overwrite property_ROver
318
351
 
319
- @Property_RO
352
+ @property_ROver
320
353
  def scipy(self):
321
354
  '''Get the C{scipy} module or C{None}.
322
355
  '''
323
- _, sp = self._np_sp2()
324
- return sp
356
+ return _xscipy(self.__class__, 1, 2) # overwrite property_ROver
325
357
 
326
- @Property_RO
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 _insufficientError(self.kmin, knots=n)
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(_HeightsBase):
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
- _interp2d = None
356
- _kind = _cubic_
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
- (C{str}) and keyword argument C{b{wrap}=False} to wrap or
365
- I{normalize} all B{C{knots}} and B{C{llis}} locations iff
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.interpolate.interp2d} issue.
403
+ @raise SciPyError: A C{scipy} issue.
375
404
 
376
- @raise SciPyWarning: A C{scipy.interpolate.interp2d} warning
377
- as exception.
405
+ @raise SciPyWarning: A C{scipy} warning as exception.
378
406
  '''
379
- spi = self.scipy_interpolate
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
- @raise SciPyError: A C{scipy.interpolate.interp2d} issue.
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 _HeightsBase._eval(self, llis, **wrap)
415
+ return self._evalls(llis, **wrap)
398
416
 
399
- def _ev(self, yis, xis): # PYCHOK expected
400
- # to make SciPy .interp2d signature(x, y), single (x, y)
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._interp2d, xis, yis)
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 = _linear_
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(_HeightsBase):
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
- an invalid B{C{knot}} or B{C{weight}}.
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
- not installed.
468
+ @raise ImportError: Package C{numpy} or C{scipy} not found or not
469
+ installed.
462
470
 
463
- @raise SciPyError: A C{scipy} C{LSQSphereBivariateSpline} issue.
471
+ @raise SciPyError: A C{scipy} issue.
464
472
 
465
- @raise SciPyWarning: A C{scipy} C{LSQSphereBivariateSpline}
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 = [w] * n
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
- T = 1.0e-4 # like SciPy example
491
- ps = np.array(_ordedup(xs, T, PI2 - T))
492
- ts = np.array(_ordedup(ys, T, PI - T))
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
- @raise SciPyError: A C{scipy} C{LSQSphereBivariateSpline} issue.
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 _height_called(self, lats, lons, **wrap)
511
+ return self._evalls(llis, **wrap)
521
512
 
522
513
 
523
- class HeightSmoothBiSpline(_HeightsBase):
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
- an invalid B{C{knot}} or B{C{s}}.
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} C{SmoothSphereBivariateSpline} issue.
537
+ @raise SciPyError: A C{scipy} issue.
547
538
 
548
- @raise SciPyWarning: A C{scipy} C{SmoothSphereBivariateSpline}
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, name=_smoothing_, Error=HeightError, low=4)
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
- @raise SciPyError: A C{scipy} C{SmoothSphereBivariateSpline} issue.
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 _height_called(self, lats, lons, **wrap)
557
+ return self._evalls(llis, **wrap)
585
558
 
586
559
 
587
- class _HeightIDW(_HeightBase):
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 _insufficientError(self.kmin, knots=n)
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
- return _height_called(self, lats, lons, **wrap)
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 _height_called instead of class LatLon_ and datum None
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
- try:
873
- for i, k in enumerate(self._knots):
874
- yield k.distanceTo(ll, **kwds)
875
- except Exception as e:
876
- i = Fmt.INDEX(knots=i)
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
- try:
906
- for i, k in enumerate(self._knots):
907
- yield _f(y, x, k.lat, k.lon, **kwds).distance2
908
- except Exception as e:
909
- i = Fmt.INDEX(knots=i)
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, _HeightsBase)
1109
+ __all__ += _ALL_DOCS(_HeightBase, _HeightIDW, _HeightNamed)
1128
1110
 
1129
1111
  # **) MIT License
1130
1112
  #