pygeodesy 24.7.7__py2.py3-none-any.whl → 24.8.4__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/geoids.py CHANGED
@@ -93,15 +93,14 @@ from pygeodesy.fmath import favg, Fdot, fdot, Fhorner, frange
93
93
  from pygeodesy.heights import _as_llis2, _ascalar, _height_called, HeightError, \
94
94
  _HeightsBase, _ellipsoidal_datum, _Wrap
95
95
  # from pygeodesy.internals import _version2 # _MODS
96
- from pygeodesy.interns import MISSING, NN, _4_, _COLONSPACE_, _COMMASPACE_, \
97
- _cubic_, _E_, _height_, _in_, _kind_, _lat_, \
98
- _linear_, _lon_, _mean_, _N_, _n_a_, _numpy_, \
99
- _on_, _outside_, _S_, _s_, _scipy_, _SPACE_, \
100
- _stdev_, _tbd_, _W_, _width_
96
+ from pygeodesy.interns import MISSING, NN, _4_, _COLONSPACE_, _COMMASPACE_, _cubic_, \
97
+ _E_, _height_, _in_, _kind_, _lat_, _linear_, _lon_, \
98
+ _mean_, _N_, _n_a_, _numpy_, _on_, _outside_, _S_, _s_, \
99
+ _scipy_, _SPACE_, _stdev_, _tbd_, _W_, _width_
101
100
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
102
101
  from pygeodesy.named import _name__, _Named, _NamedTuple
103
102
  # from pygeodesy.namedTuples import LatLon3Tuple # _MODS
104
- from pygeodesy.props import deprecated_method, Property_RO, property_RO
103
+ from pygeodesy.props import deprecated_method, Property_RO, property_RO, property_ROver
105
104
  from pygeodesy.streprs import attrs, Fmt, fstr, pairs
106
105
  from pygeodesy.units import Height, Int_, Lat, Lon
107
106
  # from pygeodesy.utily import _Wrap # from .heights
@@ -118,7 +117,7 @@ except ImportError: # Python 3+
118
117
  from io import BytesIO as _BytesIO # PYCHOK expected
119
118
 
120
119
  __all__ = _ALL_LAZY.geoids
121
- __version__ = '24.06.11'
120
+ __version__ = '24.07.25'
122
121
 
123
122
  _assert_ = 'assert'
124
123
  _bHASH_ = b'#'
@@ -288,7 +287,7 @@ class _GeoidBase(_HeightsBase):
288
287
 
289
288
  def _called(self, llis, scipy, wrap=False, H=False):
290
289
  # handle __call__
291
- _H = _MODS.formy.heightOrthometric if H else None
290
+ _H = self._heightOrthometric if H else None
292
291
  _as, llis = _as_llis2(llis, Error=GeoidError)
293
292
  hs, _w = [], _Wrap._latlonop(wrap)
294
293
  _a, _h = hs.append, self._hGeoid
@@ -417,6 +416,10 @@ class _GeoidBase(_HeightsBase):
417
416
  '''
418
417
  return _height_called(self, lats, lons, Error=GeoidError, **wrap)
419
418
 
419
+ @property_ROver
420
+ def _heightOrthometric(self):
421
+ return _MODS.formy.heightOrthometric # overwrite property_ROver
422
+
420
423
  def _hGeoid(self, lat, lon):
421
424
  out = self.outside(lat, lon)
422
425
  if out:
@@ -473,12 +476,11 @@ class _GeoidBase(_HeightsBase):
473
476
  '''(INTERNAL) I{Must be overloaded}.'''
474
477
  self._notOverloaded(lat, lon)
475
478
 
476
- @property_RO
479
+ @property_ROver
477
480
  def _LL3T(self):
478
481
  '''(INTERNAL) Get L{LatLon3Tuple}, I{once}.
479
482
  '''
480
- _GeoidBase._LL3T = T = _MODS.namedTuples.LatLon3Tuple # overwrite poperty_RO
481
- return T
483
+ return _MODS.namedTuples.LatLon3Tuple # overwrite property_ROver
482
484
 
483
485
  def _llh3(self, lat, lon):
484
486
  return self._LL3T(lat, lon, self._hGeoid(lat, lon), name=self.name)
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
@@ -83,7 +83,7 @@ from pygeodesy.interns import NN, _COMMASPACE_, _cubic_, _insufficient_, _linear
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,7 +91,7 @@ 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.07.25'
95
95
 
96
96
  _error_ = 'error'
97
97
  _formy = _MODS.into(formy=__name__)
@@ -169,14 +169,13 @@ def _insufficientError(need, Error=HeightError, **name_value): # PYCHOK no cove
169
169
  return Error(txt=t, **name_value)
170
170
 
171
171
 
172
- def _ordedup(ts, lo=EPS, hi=PI2-EPS):
172
+ def _orderedup(ts, lo=EPS, hi=PI2-EPS):
173
173
  # clip, order and remove duplicates
174
- # p, ks = 0, []
174
+ # p = 0
175
175
  # for k in sorted(max(lo, min(hi, t)) for t in ts):
176
176
  # if k > p:
177
- # ks.append(k)
177
+ # yield k
178
178
  # p = k
179
- # return ks
180
179
  return sorted(set(max(lo, min(hi, t)) for t in ts)) # list
181
180
 
182
181
 
@@ -227,8 +226,6 @@ class _HeightBase(_Named): # in .geoids
227
226
  class _HeightsBase(_HeightBase): # in .geoids
228
227
  '''(INTERNAL) Interpolator base class.
229
228
  '''
230
- _np_sp = None # (numpy, scipy)
231
-
232
229
  def __call__(self, *llis, **wrap): # PYCHOK no cover
233
230
  '''Interpolate the height for one or several locations. I{Must be overloaded}.
234
231
 
@@ -290,46 +287,37 @@ class _HeightsBase(_HeightBase): # in .geoids
290
287
  '''
291
288
  self._notOverloaded(lats, lons, **wrap)
292
289
 
293
- def _np_sp2(self, throwarnings=False):
290
+ def _np_sp2(self, throwarnings=False): # PYCHOK no cover
294
291
  '''(INTERNAL) Import C{numpy} and C{scipy}, once.
295
292
  '''
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
-
312
- @Property_RO
293
+ # raise SciPyWarnings, but not if
294
+ # scipy has already been imported
295
+ if throwarnings: # PYCHOK no cover
296
+ import sys
297
+ if _scipy_ not in sys.modules:
298
+ import warnings
299
+ warnings.filterwarnings(_error_)
300
+ return self.numpy, self.scipy
301
+
302
+ @property_ROver
313
303
  def numpy(self):
314
304
  '''Get the C{numpy} module or C{None}.
315
305
  '''
316
- np, _ = self._np_sp2()
317
- return np
306
+ return _xnumpy(self.__class__, 1, 9) # overwrite property_ROver
318
307
 
319
- @Property_RO
308
+ @property_ROver
320
309
  def scipy(self):
321
310
  '''Get the C{scipy} module or C{None}.
322
311
  '''
323
- _, sp = self._np_sp2()
324
- return sp
312
+ return _xscipy(self.__class__, 1, 2) # overwrite property_ROver
325
313
 
326
- @Property_RO
314
+ @property_ROver
327
315
  def scipy_interpolate(self):
328
316
  '''Get the C{scipy.interpolate} module or C{None}.
329
317
  '''
330
318
  _ = self.scipy
331
319
  import scipy.interpolate as spi # scipy 1.2.2
332
- return spi
320
+ return spi # overwrite property_ROver
333
321
 
334
322
  def _scipy_version(self, **n):
335
323
  '''Get the C{scipy} version as 2- or 3-tuple C{(major, minor, micro)}.
@@ -441,19 +429,20 @@ class HeightLSQBiSpline(_HeightsBase):
441
429
  '''
442
430
  _kmin = 16 # k = 3, always
443
431
 
444
- def __init__(self, knots, weight=None, **name_wrap):
432
+ def __init__(self, knots, weight=None, low=1e-4, **name_wrap):
445
433
  '''New L{HeightLSQBiSpline} interpolator.
446
434
 
447
435
  @arg knots: The points with known height (C{LatLon}s).
448
436
  @kwarg weight: Optional weight or weights for each B{C{knot}}
449
437
  (C{scalar} or C{scalar}s).
438
+ @kwarg low: Optional lower bound for I{ordered knots} (C{radians}).
450
439
  @kwarg name_wrap: Optional C{B{name}=NN} for this height interpolator
451
440
  (C{str}) and keyword argument C{b{wrap}=False} to wrap or
452
441
  I{normalize} all B{C{knots}} and B{C{llis}} locations iff
453
442
  C{True} (C{bool}).
454
443
 
455
- @raise HeightError: Insufficient number of B{C{knots}} or
456
- an invalid B{C{knot}} or B{C{weight}}.
444
+ @raise HeightError: Insufficient number of B{C{knots}} or an invalid
445
+ B{C{knot}}, B{C{weight}} or B{C{eps}}.
457
446
 
458
447
  @raise LenError: Unequal number of B{C{knots}} and B{C{weight}}s.
459
448
 
@@ -487,9 +476,10 @@ class HeightLSQBiSpline(_HeightsBase):
487
476
  w = Fmt.INDEX(weight=w.index(m))
488
477
  raise HeightError(w, m)
489
478
  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))
479
+ if not EPS < low < (PI_2 - EPS): # 1e-4 like SciPy example
480
+ raise HeightError(low=low)
481
+ ps = np.array(_orderedup(xs, low, PI2 - low))
482
+ ts = np.array(_orderedup(ys, low, PI - low))
493
483
  self._ev = spi.LSQSphereBivariateSpline(ys, xs, hs,
494
484
  ts, ps, eps=EPS, w=w).ev
495
485
  except Exception as x:
pygeodesy/internals.py CHANGED
@@ -213,6 +213,13 @@ class _MODS_Base(object):
213
213
  from pygeodesy import streprs # DON'T _lazy_import2
214
214
  return streprs
215
215
 
216
+ @_Property_RO
217
+ def version(self):
218
+ '''Get pygeodesy version, I{once}.
219
+ '''
220
+ from pygeodesy import version
221
+ return version
222
+
216
223
  _MODS = _MODS_Base() # PYCHOK overwritten by .lazily
217
224
 
218
225
 
@@ -430,7 +437,7 @@ def _print7(nl=0, nt=0, prec=6, prefix=NN, sep=_SPACE_, file=_sys.stdout,
430
437
 
431
438
 
432
439
  def _Pythonarchine(sep=NN): # in .lazily, test/bases.py versions
433
- '''(INTERNAL) Get PyPy and Python versions, bit and machine as C{3- or 4-list} or C{str}.
440
+ '''(INTERNAL) Get PyPy and Python versions, bits and machine as C{3- or 4-list} or C{str}.
434
441
  '''
435
442
  l3 = _MODS.Pythonarchine
436
443
  return sep.join(l3) if sep else l3 # 3- or 4-list
@@ -576,16 +583,22 @@ def _version_ints(vs):
576
583
  return tuple(_ints(vs))
577
584
 
578
585
 
586
+ def _versions(sep=_SPACE_):
587
+ '''(INTERNAL) Get pygeodesy, PyPy and Python versions, bits, machine and OS as C{7- or 8-list} or C{str}.
588
+ '''
589
+ l7 = [_pygeodesy_, _MODS.version] + _Pythonarchine() + _osversion2()
590
+ return sep.join(l7) if sep else l7 # 5- or 6-list
591
+
592
+
579
593
  __all__ = tuple(map(_dunder_nameof, (machine, print_, printf)))
580
- __version__ = '24.07.04'
594
+ __version__ = '24.08.01'
581
595
 
582
596
  if _dunder_ismain(__name__): # PYCHOK no cover
583
597
 
584
- from pygeodesy import _isfrozen, isLazy, version as vs
598
+ from pygeodesy import _isfrozen, isLazy
585
599
 
586
- print_(_pygeodesy_, vs, *(_Pythonarchine() + _osversion2()
587
- + ['_isfrozen', _isfrozen,
588
- 'isLazy', isLazy]))
600
+ print_(*(_versions(sep=NN) + ['_isfrozen', _isfrozen,
601
+ 'isLazy', isLazy]))
589
602
 
590
603
  # **) MIT License
591
604
  #
pygeodesy/karney.py CHANGED
@@ -4,14 +4,12 @@
4
4
  u'''Wrapper around several C{geomath.Math} functions from I{Karney}'s Python package U{geographiclib
5
5
  <https://PyPI.org/project/geographiclib>}, provided that package is installed.
6
6
 
7
- The I{wrapped} class methods return a L{GDict} instance offering access to the C{dict} items
8
- either by C{key} or by C{attribute} name.
9
- All methods of the I{wrapped} L{Geodesic<geodesicw.Geodesic>} and L{GeodesicLine<geodesicw.GeodesicLine>}
7
+ Methods of the I{wrapped} L{Geodesic<geodesicw.Geodesic>} and L{GeodesicLine<geodesicw.GeodesicLine>}
10
8
  classes return a L{GDict} instance offering access to the C{dict} items either by C{key} or by
11
9
  C{attribute} name.
12
10
 
13
- With env variable C{PYGEODESY_GEOGRAPHICLIB} left undefined or set to C{"2"}, modules L{geodesicx},
14
- L{geodesicw} and this module will use U{GeographicLib 2.0<https://GeographicLib.SourceForge.io/C++/doc/>}
11
+ With env variable C{PYGEODESY_GEOGRAPHICLIB} left undefined or set to C{"2"}, modules L{geodesicw},
12
+ L{geodesicx} and this module will use U{GeographicLib 2.0+<https://GeographicLib.SourceForge.io/C++/doc/>}
15
13
  and newer transcoding, otherwise C{1.52} or older.
16
14
 
17
15
  Karney-based functionality
@@ -60,8 +58,11 @@ Karney-based functionality
60
58
  - L{GnomonicExact}, L{GnomonicGeodSolve}, L{GnomonicKarney} -- U{Gnomonic
61
59
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Gnomonic.html>}
62
60
 
61
+ - L{Intersector} -- U{Intersect
62
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Intersect.html>} from I{GeographicLib 2.3+}
63
+
63
64
  - L{JacobiConformal} -- U{JacobiConformal
64
- <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1JacobiConformal.html#details>}
65
+ <https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1experimental_1_1JacobiConformal.html>}
65
66
 
66
67
  - L{KTransverseMercator} - U{TransverseMercator
67
68
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1TransverseMercator.html>}
@@ -94,13 +95,14 @@ are I{transcoded} from C++ classes in I{Karney}'s U{GeographicLib<https://Geogra
94
95
 
95
96
  2. These C{pygeodesy} modules and classes
96
97
 
97
- - L{ellipsoidalGeodSolve}, L{ellipsoidalKarney}, L{geodsolve}, L{karney}, L{rhumb.solve}
98
+ - L{ellipsoidalGeodSolve}, L{ellipsoidalKarney}, L{geodesici}, L{geodsolve}, L{karney}, L{rhumb.solve}
98
99
  - L{EquidistantKarney}, L{FrechetKarney}, L{GeodesicSolve}, L{GeodesicLineSolve}, L{GnomonicGeodSolve},
99
- L{GnomonicKarney}, L{HeightIDWkarney}
100
+ L{GnomonicKarney}, L{HeightIDWkarney}, L{Intersectool}
100
101
 
101
- are or use I{wrappers} around I{Karney}'s Python U{geographiclib<https://PyPI.org/project/geographiclib>}
102
- C{geodesic}, C++ utility U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>} or
103
- C++ utility U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>}.
102
+ are or use I{wrappers} around I{Karney}'s Python U{geographiclib<https://PyPI.org/project/geographiclib>} or
103
+ C++ utility U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/GeodSolve.1.html>},
104
+ U{IntersectTool<https://GeographicLib.SourceForge.io/C++/doc/IntersectTool.1.html>} or
105
+ U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/RhumbSolve.1.html>}.
104
106
 
105
107
  3. All C{pygeodesy} functions and methods to compute I{ellipsoidal} intersections, nearest points and trilaterations
106
108
 
@@ -139,12 +141,11 @@ in C{pygeodesy} are based on I{Karney}'s post U{Area of a spherical polygon
139
141
  # make sure int/int division yields float quotient, see .basics
140
142
  from __future__ import division as _; del _ # PYCHOK semicolon
141
143
 
142
- from pygeodesy.basics import _copysign, int1s, isint, itemsorted, neg, unsigned0, \
143
- _xgeographiclib, _zip, _version_info
144
+ from pygeodesy.basics import _copysign, isint, neg, unsigned0, _xgeographiclib, \
145
+ _zip, _version_info
144
146
  from pygeodesy.constants import NAN, _isfinite as _math_isfinite, _0_0, \
145
147
  _1_16th, _1_0, _2_0, _180_0, _N_180_0, _360_0
146
- from pygeodesy.errors import GeodesicError, _ValueError, _xkwds, _xkwds_get1, \
147
- _xkwds_kwds, _xkwds_not
148
+ from pygeodesy.errors import GeodesicError, _ValueError, _xkwds, _xkwds_get1
148
149
  from pygeodesy.fmath import cbrt, fremainder, norm2
149
150
  # from pygeodesy.internals import _version_info # from .basics
150
151
  from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
@@ -153,15 +154,15 @@ from pygeodesy.interns import NN, _2_, _a12_, _area_, _azi1_, _azi2_, _azi12_, \
153
154
  _UNDER_, _X_, _BAR_ # PYCHOK used!
154
155
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, _getenv
155
156
  from pygeodesy.named import ADict, _NamedBase, _NamedTuple, notImplemented, _Pass
156
- from pygeodesy.props import deprecated_method, Property_RO
157
- from pygeodesy.units import Bearing as _Azi, Degrees as _Deg, Lat, Lon, \
157
+ from pygeodesy.props import deprecated_method, Property_RO, property_ROnce
158
+ from pygeodesy.units import Azimuth as _Azi, Degrees as _Deg, Lat, Lon, \
158
159
  Meter as _M, Meter2 as _M2, Number_
159
160
  from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
160
161
 
161
162
  # from math import fabs # from .utily
162
163
 
163
164
  __all__ = _ALL_LAZY.karney
164
- __version__ = '24.07.09'
165
+ __version__ = '24.07.25'
165
166
 
166
167
  _K_2_0 = _getenv('PYGEODESY_GEOGRAPHICLIB', _2_) == _2_
167
168
  _perimeter_ = 'perimeter'
@@ -208,39 +209,39 @@ class Area3Tuple(_NamedTuple): # in .geodesicx.gxarea
208
209
  _Units_ = ( Number_, _M, _M2)
209
210
 
210
211
 
211
- class Caps(object): # PYCHOK
212
+ class Caps(object):
212
213
  '''(INTERNAL) Overriden by C{Caps} below.
213
214
  '''
214
- EMPTY = 0 # formerly aka NONE
215
- _CAP_1 = 1 << 0 # for goedesici/-w
216
- _CAP_1p = 1 << 1 # for goedesici/-w
217
- _CAP_2 = 1 << 2
218
- _CAP_3 = 1 << 3 # for goedesici/-w
219
- # _CAP_4 = 1 << 4
220
- # _CAP_ALL = 0x1F
221
- # _CAP_MASK = _CAP_ALL
222
- LATITUDE = 1 << 7 # compute latitude C{lat2}
223
- LONGITUDE = 1 << 8 # compute longitude C{lon2} _CAP_3
224
- AZIMUTH = 1 << 9 # azimuths C{azi1} and C{azi2}
225
- DISTANCE = 1 << 10 # compute distance C{s12} _CAP_1
226
- DISTANCE_IN = 1 << 11 # allow distance C{s12} in Direct _CAP_1 | _CAP_1p
227
- REDUCEDLENGTH = 1 << 12 # compute reduced length C{m12} _CAP_1 | _CAP_2
228
- GEODESICSCALE = 1 << 13 # compute geodesic scales C{M12} and C{M21} _CAP_1 | _CAP_2
229
- AREA = 1 << 14 # compute area C{S12} _CAP_4
230
-
231
- STANDARD = AZIMUTH | DISTANCE | DISTANCE_IN | LATITUDE | LONGITUDE
232
- ALL = 0x7F80 # without LONG_UNROLL, LINE_OFF, REVERSE2 and _DEBUG_*
233
-
234
- _DIRECT3 = AZIMUTH | LATITUDE | LONGITUDE | _CAP_3 # for goedesicw only
235
- _INVERSE3 = AZIMUTH | DISTANCE | _CAP_1 # for goedesicw only
236
- _STD = STANDARD | _CAP_3 | _CAP_1 # for goedesicw only
237
- _STD_LINE = _STD | _CAP_2 | _CAP_1p # for goedesici/-w
238
-
239
- LINE_CAPS = _STD_LINE | REDUCEDLENGTH | GEODESICSCALE # .geodesici only
240
-
241
- LINE_OFF = 1 << 15 # Line without updates from parent geodesic or rhumb
242
- LONG_UNROLL = 1 << 16 # unroll C{lon2} in .Direct and .Position
243
- REVERSE2 = 1 << 17 # reverse C{azi2}
215
+ EMPTY = 0 # formerly aka NONE
216
+ _CAP_1 = 1 << 0 # for goedesici/-w
217
+ _CAP_1p = 1 << 1 # for goedesici/-w
218
+ _CAP_2 = 1 << 2
219
+ _CAP_3 = 1 << 3 # for goedesici/-w
220
+ _CAP_4 = 1 << 4 # for goedesicw
221
+ _CAP_ALL = 0x1F
222
+ # _CAP_MASK = _CAP_ALL
223
+ LATITUDE = 1 << 7 # compute latitude C{lat2}
224
+ LONGITUDE = 1 << 8 | _CAP_3 # compute longitude C{lon2}
225
+ AZIMUTH = 1 << 9 # azimuths C{azi1} and C{azi2}
226
+ DISTANCE = 1 << 10 | _CAP_1 # compute distance C{s12}
227
+ DISTANCE_IN = 1 << 11 | _CAP_1 | _CAP_1p # allow distance C{s12} in Direct
228
+ REDUCEDLENGTH = 1 << 12 | _CAP_1 | _CAP_2 # compute reduced length C{m12}
229
+ GEODESICSCALE = 1 << 13 | _CAP_1 | _CAP_2 # compute geodesic scales C{M12} and C{M21}
230
+ AREA = 1 << 14 | _CAP_4 # compute area C{S12}
231
+
232
+ STANDARD = AZIMUTH | DISTANCE | LATITUDE | LONGITUDE
233
+
234
+ _DIRECT3 = AZIMUTH | LATITUDE | LONGITUDE # for goedesicw only
235
+ _INVERSE3 = AZIMUTH | DISTANCE # for goedesicw only
236
+ _STD = STANDARD # for goedesicw only
237
+ _STD_LINE = _STD | DISTANCE_IN # for goedesici/-w
238
+
239
+ LINE_CAPS = _STD_LINE | REDUCEDLENGTH | GEODESICSCALE # .geodesici only
240
+ LONG_UNROLL = 1 << 15 # unroll C{lon2} in .Direct and .Position
241
+ # = 1 << 16 # unused
242
+ LINE_OFF = 1 << 17 # Line without updates from parent geodesic or rhumb
243
+ REVERSE2 = 1 << 18 # reverse C{azi2}
244
+ ALL = 0x7F80 | _CAP_ALL # without LONG_UNROLL, LINE_OFF, REVERSE2 and _DEBUG_*
244
245
 
245
246
  LATITUDE_LONGITUDE = LATITUDE | LONGITUDE
246
247
  LATITUDE_LONGITUDE_AREA = LATITUDE | LONGITUDE | AREA
@@ -248,35 +249,38 @@ class Caps(object): # PYCHOK
248
249
  AZIMUTH_DISTANCE = AZIMUTH | DISTANCE
249
250
  AZIMUTH_DISTANCE_AREA = AZIMUTH | DISTANCE | AREA
250
251
 
251
- _ANGLE_ONLY = 1 << 18 # angular distance C{a12} only
252
- _S_CALPs_ = 1 << 19 # (INTERNAL) GeodesicExact._GenInverse
252
+ _SALP_CALPs_ = 1 << 19 # (INTERNAL) GeodesicExact._GenInverse
253
253
 
254
254
  _DEBUG_AREA = 1 << 20 # (INTERNAL) include Line details
255
255
  _DEBUG_DIRECT = 1 << 21 # (INTERNAL) include Direct details
256
256
  _DEBUG_INVERSE = 1 << 22 # (INTERNAL) include Inverse details
257
257
  _DEBUG_LINE = 1 << 23 # (INTERNAL) include Line details
258
258
  _DEBUG_ALL = _DEBUG_AREA | _DEBUG_DIRECT | _DEBUG_INVERSE | \
259
- _DEBUG_LINE | _ANGLE_ONLY | _S_CALPs_
259
+ _DEBUG_LINE | _SALP_CALPs_
260
260
 
261
- _OUT_ALL = ALL
261
+ _OUT_ALL = ALL # see geographiclib.geodesiccapabilities.py
262
262
  _OUT_MASK = ALL | LONG_UNROLL | REVERSE2 | _DEBUG_ALL
263
263
 
264
264
  _AZIMUTH_LATITUDE_LONGITUDE = AZIMUTH | LATITUDE | LONGITUDE
265
+ _AZIMUTH_LATITUDE_LONG_UNROLL = AZIMUTH | LATITUDE | LONG_UNROLL
265
266
  _DEBUG_DIRECT_LINE = _DEBUG_DIRECT | _DEBUG_LINE
266
267
  # _DISTANCE_IN_OUT = DISTANCE_IN & _OUT_MASK # == DISTANCE_IN in .gx, .gxline
267
- _LINE = AZIMUTH | LATITUDE | LONG_UNROLL
268
268
  _REDUCEDLENGTH_GEODESICSCALE = REDUCEDLENGTH | GEODESICSCALE
269
269
  # _REDUCEDLENGTH_GEODESICSCALE_DISTANCE = REDUCEDLENGTH | GEODESICSCALE | DISTANCE
270
270
 
271
- def toStr(self, Csk, sep=_BAR_):
272
- '''Return a C{Caps} or C{outmask} as C{str} or tuple of C{str}s.
271
+ def items(self):
272
+ '''Yield all I{public} C{Caps} as 2-tuple C{(NAME, mask)}.
273
+ '''
274
+ for n, C in Caps.__class__.__dict__.items():
275
+ if isint(C) and not n.startswith(_UNDER_) \
276
+ and n.replace(_UNDER_, NN).isupper():
277
+ yield n, C
278
+
279
+ def toStr(self, Cask, sep=_BAR_):
280
+ '''Return C{Caps} or an C{outmask} as C{str} or tuple of C{str}s.
273
281
  '''
274
- s = []
275
- for c, C in itemsorted(self.__class__.__dict__):
276
- if isint(C) and (Csk & C) and int1s(C) == 1 \
277
- and (C in (Caps.REVERSE2, Caps._S_CALPs_)
278
- or c.replace(_UNDER_, NN).isupper()):
279
- s.append(c)
282
+ s = (n for n, C in sorted(Caps.items())
283
+ if C and (Cask & C) == C) # and int1s(C) <= 3
280
284
  return sep.join(s) if sep else tuple(s)
281
285
 
282
286
  Caps = Caps() # PYCHOK singleton
@@ -287,7 +291,7 @@ C{AREA} - compute area C{S12},
287
291
 
288
292
  C{AZIMUTH} - include azimuths C{azi1} and C{azi2},
289
293
 
290
- C{DISTANCE} - compute distance C{s12},
294
+ C{DISTANCE} - compute distance C{s12} and angular distance C{a12},
291
295
 
292
296
  C{DISTANCE_IN} - allow distance C{s12} in C{.Direct},
293
297
 
@@ -311,7 +315,8 @@ and C{ALL} - all of the above.
311
315
 
312
316
  C{STANDARD} = C{AZIMUTH | DISTANCE | DISTANCE_IN | LATITUDE | LONGITUDE}'''
313
317
 
314
- _KEY2Caps = dict(azi2=Caps.AZIMUTH, # see GDict._unCaps
318
+ _key2Caps = dict(a12 =Caps.DISTANCE, # in GDict._unCaps
319
+ azi2=Caps.AZIMUTH,
315
320
  lat2=Caps.LATITUDE,
316
321
  lon2=Caps.LONGITUDE,
317
322
  m12 =Caps.REDUCEDLENGTH,
@@ -322,7 +327,7 @@ _KEY2Caps = dict(azi2=Caps.AZIMUTH, # see GDict._unCaps
322
327
 
323
328
 
324
329
  class _CapsBase(_NamedBase): # in .auxilats, .geodesicx.gxbases
325
- '''(INTERNAL) Base class for C{[_]Geodesic*Exact}.
330
+ '''(INTERNAL) Base class for C{Geodesic*}, C{Geodesic*Exact}, C{Intersectool} and C{Rhumb*Base}.
326
331
  '''
327
332
  ALL = Caps.ALL
328
333
  AREA = Caps.AREA
@@ -473,8 +478,8 @@ class GDict(ADict): # XXX _NamedDict
473
478
  t = tuple(_g(self, n, dflt) for n in nTuple._Names_)
474
479
  return nTuple(t, iteration=self._iteration)
475
480
 
476
- def _2X(self, gl, _2X=_X_): # .Intesectool, .Intersector
477
- '''(INTERNAL) Rename attr tail from C{-2} to C{-X} or C{-M}.
481
+ def _2X(self, gl, _2X=_X_): # .Intersectool, .Intersector
482
+ '''(INTERNAL) Rename C{-2} attr to C{-X} or C{-M}.
478
483
  '''
479
484
  X = GDict(self)
480
485
  for n in (_lat2_, _lon2_, _azi2_, _s12_, _a12_):
@@ -488,8 +493,8 @@ class GDict(ADict): # XXX _NamedDict
488
493
  def _unCaps(self, outmask): # in .geodsolve
489
494
  '''(INTERNAL) Remove superfluous items.
490
495
  '''
491
- for k, m in _KEY2Caps.items():
492
- if k in self and not (outmask & m):
496
+ for k, C in _key2Caps.items():
497
+ if k in self and (outmask & C) != C:
493
498
  self.pop(k) # delattr(self, k)
494
499
  return self
495
500
 
@@ -531,13 +536,13 @@ class _kWrapped(object): # in .geodesicw
531
536
  <https://PyPI.org/project/geographiclib>} classes.
532
537
  '''
533
538
 
534
- @Property_RO
539
+ @property_ROnce
535
540
  def geographiclib(self):
536
541
  '''Lazily import C{geographiclib}, provided the U{geographiclib
537
542
  <https://PyPI.org/project/geographiclib>} package is installed,
538
543
  otherwise raise a C{LazyImportError}.
539
544
  '''
540
- g = _xgeographiclib(self.__class__, 1, 49)
545
+ g = _xgeographiclib(self.__class__.__module__, 1, 49)
541
546
  from geographiclib.geodesic import Geodesic
542
547
  g.Geodesic = Geodesic
543
548
  from geographiclib.geodesicline import GeodesicLine
@@ -546,7 +551,7 @@ class _kWrapped(object): # in .geodesicw
546
551
  g.Math = Math
547
552
  return g
548
553
 
549
- @Property_RO
554
+ @property_ROnce
550
555
  def Math(self):
551
556
  '''Wrap the C{geomath.Math} class, provided the U{geographiclib
552
557
  <https://PyPI.org/project/geographiclib>} package is installed,
@@ -599,7 +604,7 @@ class Rhumb8Tuple(_GTuple):
599
604
 
600
605
  @kwarg dflt: Default value for missing items (C{any}).
601
606
  @kwarg a12_m12_M12_M21_salp1_calp1_salp2_calp2: Optional keyword
602
- arguments to specify or override L{Inverse10Tuple} items.
607
+ arguments to specify or override L{Inverse10Tuple} items.
603
608
 
604
609
  @return: L{Inverse10Tuple}C{(a12, s12, salp1, calp1, salp2, calp2,
605
610
  m12, M12, M21, S12)}.
@@ -724,14 +729,15 @@ def _isfinite(x): # mimick geomath.Math.isfinite
724
729
  return _math_isfinite(x) # and fabs(x) <= _MAX
725
730
 
726
731
 
727
- def _llz2line(line, **llz2):
728
- '''(INTERNAL) Set C{line.lat2, .lon2, .azi2} from C{llz2}.
732
+ def _llz2gl(gl, **llz2): # see .geodesici._llz2G
733
+ '''(INTERNAL) Set C{gl.lat2, .lon2, .azi2} from C{llz2}.
729
734
  '''
730
735
  if llz2:
731
- llz2 = _xkwds_not(None, **_xkwds_kwds(llz2, lat2=None, lon2=None, azi2=None))
732
- if llz2:
733
- line.__dict__.update(llz2)
734
- return line
736
+ for n in (_lat2_, _lon2_, _azi2_): # _lat1_, _lon1_, _azi1_
737
+ v = llz2.get(n, None)
738
+ if v is not None:
739
+ setattr(gl, n, v)
740
+ return gl
735
741
 
736
742
 
737
743
  def _norm2(x, y): # mimick geomath.Math.norm
pygeodesy/ktm.py CHANGED
@@ -67,7 +67,7 @@ from cmath import polar
67
67
  from math import atan2, asinh, cos, cosh, degrees, fabs, sin, sinh, sqrt, tanh
68
68
 
69
69
  __all__ = _ALL_LAZY.ktm
70
- __version__ = '24.06.11'
70
+ __version__ = '24.07.16'
71
71
 
72
72
 
73
73
  class KTMError(_ValueError):
@@ -433,10 +433,7 @@ def _cma(a, b0, b1, Cn):
433
433
  @see: CPython function U{_Py_c_prod<https://GitHub.com/python/
434
434
  cpython/blob/main/Objects/complexobject.c>}.
435
435
 
436
- @note: Python function C{cmath.fsum} is no longer available,
437
- but stil mentioned in Note 4 of the comments before
438
- CPython function U{math_fsum<https://GitHub.com/python/
439
- cpython/blob/main/Modules/mathmodule.c>}
436
+ @note: Python function C{cmath.fsum} is no longer available.
440
437
  '''
441
438
  r = fsum1f_(a.real * b0.real, -a.imag * b0.imag, -b1.real, Cn)
442
439
  j = fsum1f_(a.real * b0.imag, a.imag * b0.real, -b1.imag)
pygeodesy/latlonBase.py CHANGED
@@ -41,7 +41,7 @@ from pygeodesy.namedTuples import Bounds2Tuple, LatLon2Tuple, PhiLam2Tuple, \
41
41
  Trilaterate5Tuple
42
42
  # from pygeodesy.nvectorBase import _N_vector_ # _MODS
43
43
  from pygeodesy.props import deprecated_method, Property, Property_RO, \
44
- property_RO, _update_all
44
+ property_RO, property_ROnce, _update_all
45
45
  # from pygeodesy.streprs import Fmt, hstr # from .named, _MODS
46
46
  from pygeodesy.units import _isDegrees, _isRadius, Distance_, Lat, Lon, \
47
47
  Height, Radius, Radius_, Scalar, Scalar_
@@ -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.06.11'
57
+ __version__ = '24.07.29'
58
58
 
59
59
  _formy = _MODS.into(formy=__name__)
60
60
 
@@ -475,12 +475,11 @@ class LatLonBase(_NamedBase):
475
475
  r = func_(phi2, self.phi, lam21, datum=D)
476
476
  return r * (D.ellipsoid.a if radius is None else radius)
477
477
 
478
- @property_RO
478
+ @property_ROnce
479
479
  def Ecef(self):
480
480
  '''Get the ECEF I{class} (L{EcefKarney}), I{once}.
481
481
  '''
482
- LatLonBase.Ecef = E = _MODS.ecef.EcefKarney # overwrite property_RO
483
- return E
482
+ return _MODS.ecef.EcefKarney
484
483
 
485
484
  @Property_RO
486
485
  def _Ecef_forward(self):
@@ -1535,7 +1534,7 @@ class LatLonBase(_NamedBase):
1535
1534
 
1536
1535
  @kwarg form: The lat-/longitude C{B{form}at} to use (C{str}), see
1537
1536
  functions L{pygeodesy.latDMS} or L{pygeodesy.lonDMS}.
1538
- @kwarg joined: Separator to join the lat-, longitude and heigth
1537
+ @kwarg joined: Separator to join the lat-, longitude and height
1539
1538
  strings (C{str} or C{None} or C{NN} for non-joined).
1540
1539
  @kwarg m: Optional unit of the height (C{str}), use C{None} to
1541
1540
  exclude height from the returned string.