pygeodesy 25.5.5__py2.py3-none-any.whl → 25.5.28__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 (88) hide show
  1. pygeodesy/__init__.py +186 -186
  2. pygeodesy/__main__.py +4 -3
  3. pygeodesy/albers.py +4 -4
  4. pygeodesy/auxilats/_CX_Rs.py +3 -3
  5. pygeodesy/auxilats/auxAngle.py +2 -2
  6. pygeodesy/auxilats/auxDLat.py +2 -2
  7. pygeodesy/auxilats/auxDST.py +2 -2
  8. pygeodesy/auxilats/auxLat.py +2 -2
  9. pygeodesy/auxilats/auxily.py +2 -2
  10. pygeodesy/azimuthal.py +2 -2
  11. pygeodesy/booleans.py +11 -11
  12. pygeodesy/cartesianBase.py +2 -2
  13. pygeodesy/clipy.py +2 -2
  14. pygeodesy/constants.py +7 -7
  15. pygeodesy/css.py +1 -1
  16. pygeodesy/datums.py +2 -2
  17. pygeodesy/deprecated/__init__.py +8 -8
  18. pygeodesy/deprecated/bases.py +2 -2
  19. pygeodesy/deprecated/rhumbBase.py +2 -2
  20. pygeodesy/deprecated/rhumbaux.py +2 -2
  21. pygeodesy/deprecated/rhumbsolve.py +2 -2
  22. pygeodesy/deprecated/rhumbx.py +2 -2
  23. pygeodesy/ecef.py +3 -4
  24. pygeodesy/ellipsoidalBase.py +2 -2
  25. pygeodesy/ellipsoidalBaseDI.py +7 -6
  26. pygeodesy/ellipsoidalExact.py +24 -29
  27. pygeodesy/ellipsoidalGeodSolve.py +19 -19
  28. pygeodesy/ellipsoidalKarney.py +22 -27
  29. pygeodesy/ellipsoidalNvector.py +4 -4
  30. pygeodesy/ellipsoidalVincenty.py +17 -15
  31. pygeodesy/ellipsoids.py +4 -4
  32. pygeodesy/elliptic.py +16 -11
  33. pygeodesy/errors.py +1 -1
  34. pygeodesy/etm.py +2 -2
  35. pygeodesy/fmath.py +9 -9
  36. pygeodesy/formy.py +2 -2
  37. pygeodesy/frechet.py +6 -6
  38. pygeodesy/fstats.py +2 -2
  39. pygeodesy/fsums.py +37 -28
  40. pygeodesy/gars.py +2 -3
  41. pygeodesy/geodesici.py +4 -4
  42. pygeodesy/geodesicw.py +27 -8
  43. pygeodesy/geodesicx/__init__.py +3 -3
  44. pygeodesy/geodesicx/gx.py +52 -48
  45. pygeodesy/geodesicx/gxarea.py +54 -65
  46. pygeodesy/geodesicx/gxbases.py +12 -2
  47. pygeodesy/geodesicx/gxline.py +10 -7
  48. pygeodesy/geoids.py +6 -6
  49. pygeodesy/hausdorff.py +5 -5
  50. pygeodesy/heights.py +5 -5
  51. pygeodesy/internals.py +2 -2
  52. pygeodesy/interns.py +5 -5
  53. pygeodesy/iters.py +1 -1
  54. pygeodesy/karney.py +28 -12
  55. pygeodesy/ktm.py +2 -2
  56. pygeodesy/latlonBase.py +3 -4
  57. pygeodesy/lazily.py +1 -1
  58. pygeodesy/lcc.py +3 -3
  59. pygeodesy/ltp.py +5 -5
  60. pygeodesy/mgrs.py +3 -3
  61. pygeodesy/namedTuples.py +3 -3
  62. pygeodesy/nvectorBase.py +2 -2
  63. pygeodesy/osgr.py +2 -2
  64. pygeodesy/points.py +2 -3
  65. pygeodesy/props.py +18 -18
  66. pygeodesy/resections.py +30 -24
  67. pygeodesy/rhumb/aux_.py +2 -2
  68. pygeodesy/rhumb/bases.py +3 -3
  69. pygeodesy/rhumb/ekx.py +3 -4
  70. pygeodesy/rhumb/solve.py +2 -2
  71. pygeodesy/simplify.py +2 -2
  72. pygeodesy/solveBase.py +2 -2
  73. pygeodesy/sphericalBase.py +8 -8
  74. pygeodesy/sphericalNvector.py +19 -16
  75. pygeodesy/sphericalTrigonometry.py +24 -24
  76. pygeodesy/trf.py +4 -4
  77. pygeodesy/triaxials.py +2 -2
  78. pygeodesy/units.py +7 -8
  79. pygeodesy/utily.py +2 -2
  80. pygeodesy/utmupsBase.py +2 -2
  81. pygeodesy/vector2d.py +14 -8
  82. pygeodesy/vector3d.py +3 -3
  83. pygeodesy/webmercator.py +2 -2
  84. {pygeodesy-25.5.5.dist-info → pygeodesy-25.5.28.dist-info}/METADATA +16 -16
  85. pygeodesy-25.5.28.dist-info/RECORD +119 -0
  86. pygeodesy-25.5.5.dist-info/RECORD +0 -119
  87. {pygeodesy-25.5.5.dist-info → pygeodesy-25.5.28.dist-info}/WHEEL +0 -0
  88. {pygeodesy-25.5.5.dist-info → pygeodesy-25.5.28.dist-info}/top_level.txt +0 -0
@@ -15,9 +15,9 @@ and licensed under the MIT/X11 License. For more information, see the
15
15
  U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
16
16
  '''
17
17
  # make sure int/int division yields float quotient
18
- from __future__ import division as _; del _ # PYCHOK semicolon
18
+ from __future__ import division as _; del _ # noqa: E702 ;
19
19
 
20
- from pygeodesy.basics import isodd, unsigned0
20
+ from pygeodesy.basics import _copysign, isodd, unsigned0
21
21
  from pygeodesy.constants import NAN, _0_0, _0_5, _720_0
22
22
  from pygeodesy.internals import printf, typename
23
23
  # from pygeodesy.interns import _COMMASPACE_ # from .lazily
@@ -31,19 +31,16 @@ from pygeodesy.props import Property, Property_RO, property_RO
31
31
  from math import fmod as _fmod
32
32
 
33
33
  __all__ = ()
34
- __version__ = '24.10.14'
34
+ __version__ = '25.05.28'
35
35
 
36
36
 
37
37
  class GeodesicAreaExact(_NamedBase):
38
- '''Area and perimeter of a geodesic polygon, an enhanced
39
- version of I{Karney}'s Python class U{PolygonArea
40
- <https://GeographicLib.SourceForge.io/html/python/
41
- code.html#module-geographiclib.polygonarea>} using
42
- the more accurate surface area.
43
-
44
- @note: The name of this class C{*Exact} is a misnomer, see
45
- I{Karney}'s comments at C++ attribute U{GeodesicExact._c2
46
- <https://GeographicLib.SourceForge.io/C++/doc/
38
+ '''Area and perimeter of a geodesic polygon, an enhanced version of I{Karney}'s
39
+ Python class U{PolygonArea<https://GeographicLib.SourceForge.io/html/python/
40
+ code.html#module-geographiclib.polygonarea>} using the more accurate surface area.
41
+
42
+ @note: The name of this class C{*Exact} is a misnomer, see I{Karney}'s comments at
43
+ C++ attribute U{GeodesicExact._c2<https://GeographicLib.SourceForge.io/C++/doc/
47
44
  GeodesicExact_8cpp_source.html>}.
48
45
  '''
49
46
  _Area = None
@@ -140,36 +137,35 @@ class GeodesicAreaExact(_NamedBase):
140
137
 
141
138
  @Property_RO
142
139
  def area0x(self):
143
- '''Get the ellipsoid's surface area (C{meter} I{squared}),
144
- more accurate for very I{oblate} ellipsoids.
140
+ '''Get the ellipsoid's surface area (C{meter} I{squared}), more accurate
141
+ for very I{oblate} ellipsoids.
145
142
  '''
146
143
  return self.ellipsoid.areax # not .area!
147
144
 
148
145
  area0 = area0x # for C{geographiclib} compatibility
149
146
 
150
- def Compute(self, reverse=False, sign=True):
147
+ def Compute(self, reverse=False, sign=True, polar=False):
151
148
  '''Compute the accumulated perimeter and area.
152
149
 
153
- @kwarg reverse: If C{True}, clockwise traversal counts as a
154
- positive area instead of counter-clockwise
155
- (C{bool}).
156
- @kwarg sign: If C{True}, return a signed result for the area if
157
- the polygon is traversed in the "wrong" direction
158
- instead of returning the area for the rest of the
159
- earth.
160
-
161
- @return: L{Area3Tuple}C{(number, perimeter, area)} with the
162
- number of points, the perimeter in C{meter} and the
163
- area in C{meter**2}. The perimeter includes the
164
- length of a final edge, connecting the current to
165
- the initial point, if this polygon was initialized
166
- with C{polyline=False}. For perimeter only, i.e.
167
- C{polyline=True}, area is C{NAN}.
168
-
169
- @note: Arbitrarily complex polygons are allowed. In the case
170
- of self-intersecting polygons, the area is accumulated
171
- "algebraically". E.g., the areas of the 2 loops in a
172
- I{figure-8} polygon will partially cancel.
150
+ @kwarg reverse: If C{True}, clockwise traversal counts as a positive area instead
151
+ of counter-clockwise (C{bool}).
152
+ @kwarg sign: If C{True}, return a signed result for the area if the polygon is
153
+ traversed in the "wrong" direction instead of returning the area for
154
+ the rest of the earth.
155
+ @kwarg polar: Use C{B{polar}=True} if the polygon encloses a pole (C{bool}), see
156
+ function L{ispolar<pygeodesy.points.ispolar>} and U{area of a polygon
157
+ enclosing a pole<https://GeographicLib.SourceForge.io/C++/doc/
158
+ classGeographicLib_1_1GeodesicExact.html#a3d7a9155e838a09a48dc14d0c3fac525>}.
159
+
160
+ @return: L{Area3Tuple}C{(number, perimeter, area)} with the number of points, the
161
+ perimeter in C{meter} and the (signed) area in C{meter**2}. The perimeter
162
+ includes the length of a final edge, connecting the current to the initial
163
+ point, if this polygon was initialized with C{polyline=False}. For perimeter
164
+ only, i.e. C{polyline=True}, area is C{NAN}.
165
+
166
+ @note: Arbitrarily complex polygons are allowed. In the case of self-intersecting
167
+ polygons, the area is accumulated "algebraically". E.g., the areas of both
168
+ loops in a I{figure-8} polygon will partially cancel.
173
169
 
174
170
  @note: More points and edges can be added after this call.
175
171
  '''
@@ -179,7 +175,7 @@ class GeodesicAreaExact(_NamedBase):
179
175
  a = NAN if self.polyline else p
180
176
  elif self._Area:
181
177
  r = self._Inverse(self.lat1, self.lon1, self.lat0, self.lon0)
182
- a = self._reduced(r.S12, reverse, sign, r.xing)
178
+ a = self._reduced(r.S12, r.xing, n, reverse=reverse, sign=sign, polar=polar)
183
179
  p = self._Peri.Sum(r.s12)
184
180
  else:
185
181
  p = self._Peri.Sum()
@@ -279,7 +275,7 @@ class GeodesicAreaExact(_NamedBase):
279
275
  t = _COMMASPACE_.join(pairs(d, prec=10))
280
276
  printf('%s %s: %s (%s)', self.named2, n, t, callername(up=2))
281
277
 
282
- def _reduced(self, S12, reverse, sign, xing):
278
+ def _reduced(self, S12, xing, n, reverse=False, sign=True, polar=False):
283
279
  '''(INTERNAL) Accumulate and reduce area to allowed range.
284
280
  '''
285
281
  a0 = self.area0x
@@ -296,6 +292,8 @@ class GeodesicAreaExact(_NamedBase):
296
292
  a = A.Add(-a0)
297
293
  elif a <= -a0_:
298
294
  a = A.Add( a0)
295
+ if polar: # see .geodesicw._gwrapped.Geodesic.Area
296
+ a = A.Add(_copysign(a0 * _0_5 * n, a)) # - if reverse or sign?
299
297
  return unsigned0(a)
300
298
 
301
299
  def Reset(self):
@@ -313,63 +311,54 @@ class GeodesicAreaExact(_NamedBase):
313
311
 
314
312
  Clear = Reset
315
313
 
316
- def TestEdge(self, azi, s, reverse=False, sign=True):
314
+ def TestEdge(self, azi, s, **reverse_sign_polar):
317
315
  '''Compute the properties for a tentative, additional edge
318
316
 
319
317
  @arg azi: Azimuth at the current the point (compass C{degrees}).
320
318
  @arg s: Length of the edge (C{meter}).
321
- @kwarg reverse: If C{True}, clockwise traversal counts as a
322
- positive area instead of counter-clockwise
323
- (C{bool}).
324
- @kwarg sign: If C{True}, return a signed result for the area if
325
- the polygon is traversed in the "wrong" direction
326
- instead of returning the area for the rest of the
327
- earth.
319
+ @kwarg reverse_sign_polar: Optional C{B{reverse}=False}, C{B{sign}=True} and
320
+ C{B{polar}=False} keyword arguments, see method L{Compute}.
328
321
 
329
322
  @return: L{Area3Tuple}C{(number, perimeter, area)}.
330
323
 
331
324
  @raise GeodesicError: No points.
332
325
  '''
333
- n = self.num + 1
334
- p = self._Peri.Sum(s)
335
- if self.polyline:
336
- a, r = NAN, None
337
- elif n < 2:
338
- raise GeodesicError(num=self.num)
326
+ r, n = None, self.num + 1
327
+ if n < 2: # raise GeodesicError(num=self.num)
328
+ a = p = NAN # like .test_Planimeter19
339
329
  else:
340
- d = self._Direct(azi, s)
341
- r = self._Inverse(d.lat2, d.lon2, self.lat0, self.lon0)
342
- a = self._reduced(d.S12 + r.S12, reverse, sign, d.xing + r.xing)
343
- p += r.s12
330
+ p = self._Peri.Sum(s)
331
+ if self.polyline:
332
+ a = NAN
333
+ else:
334
+ d = self._Direct(azi, s)
335
+ r = self._Inverse(d.lat2, d.lon2, self.lat0, self.lon0)
336
+ a = self._reduced(d.S12 + r.S12, d.xing + r.xing, n, **reverse_sign_polar)
337
+ p += r.s12
344
338
  if self.verbose: # PYCHOK no cover
345
339
  self._print(n, p, a, r, azi=azi, s=s)
346
340
  return Area3Tuple(n, p, a)
347
341
 
348
- def TestPoint(self, lat, lon, reverse=False, sign=True):
342
+ def TestPoint(self, lat, lon, **reverse_sign_polar):
349
343
  '''Compute the properties for a tentative, additional vertex
350
344
 
351
345
  @arg lat: Latitude of the point (C{degrees}).
352
346
  @arg lon: Longitude of the point (C{degrees}).
353
- @kwarg reverse: If C{True}, clockwise traversal counts as a
354
- positive area instead of counter-clockwise
355
- (C{bool}).
356
- @kwarg sign: If C{True}, return a signed result for the area if
357
- the polygon is traversed in the "wrong" direction
358
- instead of returning the area for the rest of the
359
- earth.
347
+ @kwarg reverse_sign_polar: Optional C{B{reverse}=False}, C{B{sign}=True} and
348
+ C{B{polar}=False} keyword arguments, see method L{Compute}.
360
349
 
361
350
  @return: L{Area3Tuple}C{(number, perimeter, area)}.
362
351
  '''
363
352
  r, n = None, self.num + 1
364
353
  if n < 2:
365
354
  p = _0_0
366
- a = NAN if self.polyline else p
355
+ a = NAN if self.polyline else p
367
356
  else:
368
357
  i = self._Inverse(self.lat1, self.lon1, lat, lon)
369
358
  p = self._Peri.Sum(i.s12)
370
359
  if self._Area:
371
360
  r = self._Inverse(lat, lon, self.lat0, self.lon0)
372
- a = self._reduced(i.S12 + r.S12, reverse, sign, i.xing + r.xing)
361
+ a = self._reduced(i.S12 + r.S12, i.xing + r.xing, n, **reverse_sign_polar)
373
362
  p += r.s12
374
363
  else:
375
364
  a = NAN
@@ -9,7 +9,7 @@ U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
9
9
  '''
10
10
 
11
11
  from pygeodesy.basics import isodd, _MODS
12
- from pygeodesy.constants import _EPSmin as _TINY, _0_0
12
+ from pygeodesy.constants import _EPSmin as _TINY, _0_0, isfinite
13
13
  from pygeodesy.errors import _or, _xkwds_item2
14
14
  from pygeodesy.fmath import hypot as _hypot
15
15
  # from pygeodesy.interns import _numpy_ # _MODS
@@ -20,7 +20,7 @@ from pygeodesy.karney import _CapsBase, GeodesicError, _2cos2x, \
20
20
  from math import fabs, ldexp as _ldexp
21
21
 
22
22
  __all__ = ()
23
- __version__ = '24.09.07'
23
+ __version__ = '25.05.28'
24
24
 
25
25
  # valid C{nC4}s and C{C4order}s, see _xnC4 below
26
26
  _nC4s = {24: 2900, 27: 4032, 30: 5425}
@@ -147,6 +147,16 @@ def _sinf1cos2d(lat, f1):
147
147
  return sbet, (cbet if fabs(cbet) > _TINY else _TINY)
148
148
 
149
149
 
150
+ def _toNAN(outmask, *args):
151
+ '''(INTERNAL) Is any C{arg} not finite?
152
+ '''
153
+ if (outmask & _CapsBase.NONFINITONAN): # Caps.NONFINITONAN
154
+ for arg in args:
155
+ if not isfinite(arg):
156
+ return True
157
+ return False
158
+
159
+
150
160
  def _xnC4(**name_nC4):
151
161
  '''(INTERNAL) Validate C{C4order}.
152
162
  '''
@@ -13,7 +13,7 @@ and licensed under the MIT/X11 License. For more information, see the
13
13
  U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
14
14
  '''
15
15
  # make sure int/int division yields float quotient
16
- from __future__ import division as _; del _ # PYCHOK semicolon
16
+ from __future__ import division as _; del _ # noqa: E702 ;
17
17
 
18
18
  # A copy of comments from Karney's C{GeodesicLineExact.cpp}:
19
19
  #
@@ -37,13 +37,14 @@ from __future__ import division as _; del _ # PYCHOK semicolon
37
37
  # - s and c prefixes mean sin and cos
38
38
 
39
39
  # from pygeodesy.basics import _xinstanceof # _MODS
40
- from pygeodesy.constants import NAN, _EPSqrt as _TOL, _0_0, _1_0, \
41
- _180_0, _2__PI, _copysign_1_0, isfinite
40
+ from pygeodesy.constants import NAN, _EPSqrt as _TOL, \
41
+ _0_0, _1_0, _180_0, _2__PI, \
42
+ _copysign_1_0, isfinite
42
43
  from pygeodesy.errors import _xError, _xkwds_pop2
43
44
  from pygeodesy.fsums import fsumf_, fsum1f_
44
45
  from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
45
46
  _sincos12, _sin1cos2, \
46
- _sinf1cos2d, _TINY
47
+ _sinf1cos2d, _TINY, _toNAN
47
48
  # from pygeodesy.geodesicw import _Intersecant2 # _MODS
48
49
  from pygeodesy.lazily import _ALL_DOCS, _ALL_MODS as _MODS
49
50
  from pygeodesy.karney import _around, _atan2d, Caps, GDict, _fix90, \
@@ -55,7 +56,7 @@ from pygeodesy.utily import atan2, atan2d as _atan2d_reverse, sincos2
55
56
  from math import cos, degrees, fabs, floor, radians, sin
56
57
 
57
58
  __all__ = ()
58
- __version__ = '25.04.12'
59
+ __version__ = '25.05.28'
59
60
 
60
61
  _glXs = [] # instances of C{[_]GeodesicLineExact} to be updated
61
62
 
@@ -91,6 +92,7 @@ class _GeodesicLineExact(_GeodesicBase):
91
92
  # _salp1 = _calp1 = NAN
92
93
  # _somg1 = _comg1 = NAN
93
94
  # _ssig1 = _csig1 = NAN
95
+ # _toNAN = False
94
96
 
95
97
  def __init__(self, gX, lat1, lon1, azi1, caps, **name_):
96
98
  '''(INTERNAL) New C{[_]GeodesicLineExact} instance.
@@ -104,6 +106,7 @@ class _GeodesicLineExact(_GeodesicBase):
104
106
  salp1, calp1 = _sincos2d(_around(azi1))
105
107
  if name_:
106
108
  self.name = name_
109
+ self._toNAN = _toNAN(caps, lat1, lon1, azi1, salp1, calp1)
107
110
 
108
111
  self._gX = gX # GeodesicExact only
109
112
  self._lat1 = lat1 = _fix90(lat1)
@@ -297,9 +300,9 @@ class _GeodesicLineExact(_GeodesicBase):
297
300
  gX = self.geodesic # ._gX
298
301
  r = GDict(a12=NAN, s12=NAN) # both a12 and s12, always
299
302
 
300
- if not isfinite(s12_a12):
303
+ if self._toNAN or not isfinite(s12_a12): # _toNAN(outmask, s12_a12)?
301
304
  # E2 = sig12 = ssig12 = csig12 = NAN
302
- return r._toNAN(outmask)
305
+ return r._toNAN(outmask | Cs.NONFINITONAN) # for backward compatibility
303
306
  elif arcmode: # s12_a12 is (spherical) arc length
304
307
  r.set_(a12=s12_a12)
305
308
  sig12 = radians(s12_a12)
pygeodesy/geoids.py CHANGED
@@ -87,7 +87,7 @@ courtesy of SBFRF.
87
87
  Above Mean Sea Level<https://Wiki.ROS.org/mavros>}.
88
88
  '''
89
89
  # make sure int/int division yields float quotient, see .basics
90
- from __future__ import division as _; del _ # PYCHOK semicolon
90
+ from __future__ import division as _; del _ # noqa: E702 ;
91
91
 
92
92
  from pygeodesy.basics import _isin, len2, min2, isodd, _splituple, \
93
93
  ub2str as _ub2str
@@ -126,7 +126,7 @@ except ImportError: # Python 3+
126
126
  from io import BytesIO as _BytesIO # PYCHOK expected
127
127
 
128
128
  __all__ = _ALL_LAZY.geoids
129
- __version__ = '25.04.14'
129
+ __version__ = '25.05.21'
130
130
 
131
131
  _assert_ = 'assert'
132
132
  _bHASH_ = b'#'
@@ -148,7 +148,7 @@ class GeoidError(HeightError):
148
148
  class _GeoidBase(_HeightBase):
149
149
  '''(INTERNAL) Base class for C{Geoid...}s.
150
150
  '''
151
- _center = None # (lat, lon, height)
151
+ # _center = None # (lat, lon, height)
152
152
  _cropped = None
153
153
  # _datum = _WGS84 # from _HeightBase
154
154
  _egm = None # open C{egm*.pgm} geoid file
@@ -297,7 +297,7 @@ class _GeoidBase(_HeightBase):
297
297
 
298
298
  @Property_RO
299
299
  def _center(self):
300
- ''' Cache for method L{center}.
300
+ '''(INTERNAL) Cache for method L{center}.
301
301
  '''
302
302
  return self._llh3(favg(self._lat_lo, self._lat_hi),
303
303
  favg(self._lon_lo, self._lon_hi))
@@ -355,7 +355,7 @@ class _GeoidBase(_HeightBase):
355
355
  # build grid axis, hi = lo + (n - 1) * d
356
356
  m, a = len2(frange(lo, n, d))
357
357
  if m != n:
358
- raise LenError(self.__class__, grid=m, **{name: n})
358
+ raise LenError(type(self), grid=m, **{name: n})
359
359
  if d < 0:
360
360
  d, a = -d, list(reversed(a))
361
361
  a = self.numpy.array(a)
@@ -907,7 +907,7 @@ def _I(i):
907
907
  '''(INTERNAL) Cache a single C{int} constant.
908
908
  '''
909
909
  i = int(i)
910
- return _intCs.setdefault(i, i) # PYCHOK undefined due to del _intCs
910
+ return _intCs.setdefault(i, i) # noqa: F821 del
911
911
 
912
912
 
913
913
  def _T(cs):
pygeodesy/hausdorff.py CHANGED
@@ -75,8 +75,8 @@ from pygeodesy.interns import NN, _i_, _j_, _units_
75
75
  # from pygeodesy.iters import points2 as _points2 # from .points
76
76
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
77
77
  from pygeodesy.named import _name2__, _Named, _NamedTuple, _Pass
78
- # from pygeodesy.namedTuples import PhiLam2Tuple # from .points
79
- from pygeodesy.points import _distanceTo, PhiLam2Tuple, points2 as _points2, radians
78
+ from pygeodesy.namedTuples import PhiLam2Tuple
79
+ from pygeodesy.points import _distanceTo, points2 as _points2, radians
80
80
  from pygeodesy.props import Property, Property_RO, property_doc_, property_RO
81
81
  from pygeodesy.units import Float, Number_
82
82
  from pygeodesy import unitsBase as _unitsBase # _Str_..., _xUnit, _xUnits
@@ -85,7 +85,7 @@ from pygeodesy import unitsBase as _unitsBase # _Str_..., _xUnit, _xUnits
85
85
  from random import Random
86
86
 
87
87
  __all__ = _ALL_LAZY.hausdorff
88
- __version__ = '25.04.21'
88
+ __version__ = '25.05.26'
89
89
 
90
90
  _formy = _MODS.into(formy=__name__)
91
91
 
@@ -101,7 +101,7 @@ class Hausdorff(_Named):
101
101
  be overloaded.
102
102
  '''
103
103
  _datum = _WGS84
104
- _func = None # formy function/property
104
+ # _func = None # formy function/property
105
105
  _kwds = {} # func_ options
106
106
  _model = ()
107
107
  _seed = None
@@ -124,7 +124,7 @@ class Hausdorff(_Named):
124
124
  @raise HausdorffError: Insufficient number of B{C{point1s}} or an invalid
125
125
  B{C{point1}}, B{C{seed}} or B{C{units}}.
126
126
  '''
127
- name, kwds = _name2__(**name__kwds) # name__=self.__class__
127
+ name, kwds = _name2__(**name__kwds) # name__=type(self)
128
128
  if name:
129
129
  self.name = name
130
130
 
pygeodesy/heights.py CHANGED
@@ -69,7 +69,7 @@ C{>>> h1, h2, ... = hinterpolator.height_(lat1, lon1, lat2, lon2, ...)}
69
69
  Interpolation.
70
70
  '''
71
71
  # make sure int/int division yields float quotient, see .basics
72
- from __future__ import division as _; del _ # PYCHOK semicolon
72
+ from __future__ import division as _; del _ # noqa: E702 ;
73
73
 
74
74
  from pygeodesy.basics import isscalar, len2, map1, min2, _xnumpy, _xscipy
75
75
  from pygeodesy.constants import EPS, PI, PI_2, PI2, _0_0, _90_0, _180_0
@@ -92,7 +92,7 @@ from pygeodesy.units import _isDegrees, Float_, Int_
92
92
  # from math import radians # from .points
93
93
 
94
94
  __all__ = _ALL_LAZY.heights
95
- __version__ = '25.04.21'
95
+ __version__ = '25.05.26'
96
96
 
97
97
  _error_ = 'error'
98
98
  _formy = _MODS.into(formy=__name__)
@@ -212,7 +212,7 @@ class _HeightNamed(_Named): # in .geoids
212
212
  n, lats = len2(lats)
213
213
  m, lons = len2(lons)
214
214
  if n != m: # format a LenError, but raise self._Error
215
- e = LenError(self.__class__, lats=n, lons=m, txt=None)
215
+ e = LenError(type(self), lats=n, lons=m, txt=None)
216
216
  raise self._Error(str(e))
217
217
  llis = [LLiC(*t, datum=d) for t in zip(lats, lons)]
218
218
  return llis
@@ -363,13 +363,13 @@ class _HeightBase(_HeightNamed): # in .geoids
363
363
  def numpy(self):
364
364
  '''Get the C{numpy} module or C{None}.
365
365
  '''
366
- return _xnumpy(self.__class__, 1, 9) # overwrite property_ROver
366
+ return _xnumpy(type(self), 1, 9) # overwrite property_ROver
367
367
 
368
368
  @property_ROver
369
369
  def scipy(self):
370
370
  '''Get the C{scipy} module or C{None}.
371
371
  '''
372
- return _xscipy(self.__class__, 1, 2) # overwrite property_ROver
372
+ return _xscipy(type(self), 1, 2) # overwrite property_ROver
373
373
 
374
374
  @property_ROver
375
375
  def scipy_interpolate(self):
pygeodesy/internals.py CHANGED
@@ -132,7 +132,7 @@ class _MODS_Base(object):
132
132
  def name(self):
133
133
  '''Get this name (C{str}).
134
134
  '''
135
- return typename(self.__class__)
135
+ return typename(type(self))
136
136
 
137
137
  @_Property_RO
138
138
  def nix2(self): # PYCHOK no cover
@@ -686,7 +686,7 @@ def _versions(sep=_SPACE_):
686
686
 
687
687
 
688
688
  __all__ = tuple(map(typename, (machine, print_, printf, typename)))
689
- __version__ = '25.04.14'
689
+ __version__ = '25.05.26'
690
690
 
691
691
  if __name__ == _DMAIN_:
692
692
 
pygeodesy/interns.py CHANGED
@@ -443,15 +443,15 @@ _LR_PAIRS = {_LANGLE_: _RANGLE_,
443
443
 
444
444
  __all__ = (_NN_, # NOT MISSING!
445
445
  Str_.__name__) # classes
446
- __version__ = '25.04.12'
446
+ __version__ = '25.05.26'
447
447
 
448
448
  if __name__ == _DMAIN_:
449
449
 
450
- def _main():
450
+ def _main(globalocals):
451
451
  from pygeodesy import itemsorted, printf
452
452
 
453
453
  t = b = 0
454
- for n, v in itemsorted(locals(), asorted=False, reverse=True):
454
+ for n, v in itemsorted(globalocals, asorted=False, reverse=True):
455
455
  if n.endswith(_UNDER_) and n.startswith(_UNDER_) and \
456
456
  not n.startswith(_DUNDER_):
457
457
  t += 1
@@ -459,10 +459,10 @@ if __name__ == _DMAIN_:
459
459
  m = n[1:-1]
460
460
  if m != v and m.replace(_UNDER_, _SPACE_) != v:
461
461
  printf('%4d: %s = %r', t, n, v)
462
- n = len(locals())
462
+ n = len(globalocals)
463
463
  printf('%4d (%d) names, %s chars total, %.2f chars avg', t, n, b, float(b) / t, nl=1)
464
464
 
465
- _main()
465
+ _main(globals()) # or locals()
466
466
 
467
467
  # **) MIT License
468
468
  #
pygeodesy/iters.py CHANGED
@@ -26,7 +26,7 @@ from pygeodesy.units import Int, Radius
26
26
  from pygeodesy.utily import degrees2m, _Wrap, _1_0
27
27
 
28
28
  __all__ = _ALL_LAZY.iters
29
- __version__ = '25.04.14'
29
+ __version__ = '25.05.19'
30
30
 
31
31
  _items_ = 'items'
32
32
  _iterNumpy2len = 1 # adjustable for testing purposes
pygeodesy/karney.py CHANGED
@@ -141,7 +141,7 @@ in C{pygeodesy} are based on I{Karney}'s post U{Area of a spherical polygon
141
141
  <https://MathOverflow.net/questions/97711/the-area-of-spherical-polygons>}, 3rd Answer.
142
142
  '''
143
143
  # make sure int/int division yields float quotient, see .basics
144
- from __future__ import division as _; del _ # PYCHOK semicolon
144
+ from __future__ import division as _; del _ # noqa: E702 ;
145
145
 
146
146
  from pygeodesy.basics import _copysign, _isin, isint, neg, unsigned0, \
147
147
  _xgeographiclib, _zip
@@ -166,7 +166,7 @@ from pygeodesy.utily import atan2d, sincos2d, tand, _unrollon, fabs
166
166
  # from math import fabs # from .utily
167
167
 
168
168
  __all__ = _ALL_LAZY.karney
169
- __version__ = '25.04.14'
169
+ __version__ = '25.05.28'
170
170
 
171
171
  _2_4_ = '2.4'
172
172
  _K_2_0 = _getenv(_PYGEODESY_ENV(typename(_xgeographiclib)[2:]), _2_)
@@ -240,6 +240,8 @@ class Caps(object):
240
240
 
241
241
  C{LONG_UNROLL} - unroll C{lon2} in method C{.Direct},
242
242
 
243
+ C{NONFINITONAN} - set all C{GDict} items to C{NAN} iff any argument is C{non-finite}.
244
+
243
245
  C{REDUCEDLENGTH} - compute the reduced length C{m12},
244
246
 
245
247
  C{REVERSE2} - reverse azimuth C{azi2} by 180 degrees,
@@ -274,7 +276,7 @@ class Caps(object):
274
276
 
275
277
  LINE_CAPS = STANDARD_LINE | REDUCEDLENGTH | GEODESICSCALE # .geodesici only
276
278
  LONG_UNROLL = 1 << 15 # unroll C{lon2} in .Direct and .Position
277
- # = 1 << 16 # unused
279
+ NONFINITONAN = 1 << 16 # see method GDict._toNAN
278
280
  LINE_OFF = 1 << 17 # Line without updates from parent geodesic or rhumb
279
281
  REVERSE2 = 1 << 18 # reverse C{azi2}
280
282
  ALL = 0x7F80 | _CAP_ALL # without LONG_UNROLL, LINE_OFF, REVERSE2 and _DEBUG_*
@@ -327,9 +329,12 @@ if _FOR_DOCS: # PYCHOK force ...
327
329
  else:
328
330
  Caps = Caps() # PYCHOK singleton
329
331
 
330
- _key2Caps = dict(a12 =Caps.DISTANCE, # in GDict._unCaps
332
+ _key2Caps = dict(a12 =Caps.DISTANCE, # in GDict._toNAN, -._unCaps
333
+ azi1=Caps.AZIMUTH,
331
334
  azi2=Caps.AZIMUTH,
335
+ lat1=Caps.LATITUDE,
332
336
  lat2=Caps.LATITUDE,
337
+ lon1=Caps.LONGITUDE,
333
338
  lon2=Caps.LONGITUDE,
334
339
  m12 =Caps.REDUCEDLENGTH,
335
340
  M12 =Caps.GEODESICSCALE,
@@ -353,6 +358,7 @@ class _CapsBase(_NamedBase): # in .auxilats, .geodesicx.gxbases
353
358
  LINE_OFF = Caps.LINE_OFF
354
359
  LONGITUDE = Caps.LONGITUDE
355
360
  LONG_UNROLL = Caps.LONG_UNROLL
361
+ NONFINITONAN = Caps.NONFINITONAN
356
362
  REDUCEDLENGTH = Caps.REDUCEDLENGTH
357
363
  STANDARD = Caps.STANDARD
358
364
  STANDARD_LINE = Caps.STANDARD_LINE # for geodesici
@@ -449,11 +455,14 @@ class GDict(ADict): # XXX _NamedDict
449
455
  '''
450
456
  return self._toTuple(Inverse10Tuple, dflt)
451
457
 
452
- def _toNAN(self, outmask): # .GeodesicLineExact._GenPosition
458
+ def _toNAN(self, outmask): # .GeodesicExact._GDistInverse, .GeodesicLineExact._GenPosition
453
459
  '''(INTERNAL) Convert this C{GDict} to all C{NAN}s.
454
460
  '''
455
- d = dict((n, NAN) for n in GeodSolve12Tuple._Names_)
456
- return self.set_(**d)._unCaps(outmask)
461
+ if (outmask & Caps.NONFINITONAN):
462
+ d = dict((k, NAN) for k, C in _key2Caps.items()
463
+ if (outmask & C) == C)
464
+ self.set_(**d)
465
+ return self
457
466
 
458
467
  @deprecated_method
459
468
  def toRhumb7Tuple(self, dflt=NAN): # PYCHOK no cover
@@ -543,7 +552,7 @@ class Inverse10Tuple(_GTuple):
543
552
  **updates) # PYCHOK indent
544
553
 
545
554
 
546
- class _kWrapped(object): # in .geodesicw
555
+ class _kWrapped(_CapsBase): # in .geodesicw
547
556
  '''(INTERNAL) Wrapper for some of I{Karney}'s U{geographiclib
548
557
  <https://PyPI.org/project/geographiclib>} classes.
549
558
  '''
@@ -554,13 +563,15 @@ class _kWrapped(object): # in .geodesicw
554
563
  <https://PyPI.org/project/geographiclib>} package is installed,
555
564
  otherwise raise a C{LazyImportError}.
556
565
  '''
557
- g = _xgeographiclib(type(self).__module__, 1, 49)
566
+ g = _xgeographiclib(type(self), 1, 49)
558
567
  from geographiclib.geodesic import Geodesic
559
568
  g.Geodesic = Geodesic
560
569
  from geographiclib.geodesicline import GeodesicLine
561
570
  g.GeodesicLine = GeodesicLine
562
571
  from geographiclib.geomath import Math
563
572
  g.Math = Math
573
+ # from geographiclib.polygonarea import PolygonArea
574
+ # g.PolygonArea = PolygonArea # see below
564
575
  return g
565
576
 
566
577
  @property_ROnce
@@ -586,6 +597,11 @@ class _kWrapped(object): # in .geodesicw
586
597
  return (_2_4_ if _K_2_4 else
587
598
  (_2_ if _K_2_0 else _1_)) if self.Math else NN
588
599
 
600
+ @property_ROnce
601
+ def _PolygonArea(self): # lazy import
602
+ from geographiclib.polygonarea import PolygonArea
603
+ return PolygonArea
604
+
589
605
  _wrapped = _kWrapped() # PYCHOK singleton, .datum, .test/base.py
590
606
 
591
607
 
@@ -830,7 +846,7 @@ def _norm180(deg): # mimick geomath.Math.AngNormalize
830
846
  return d
831
847
 
832
848
 
833
- def _polygon(geodesic, points, closed, line, wrap):
849
+ def _polygon(geodesic, points, closed, line, wrap, polar):
834
850
  '''(INTERNAL) Compute the area or perimeter of a polygon,
835
851
  using a L{GeodesicExact}, L{GeodesicSolve} or (if the
836
852
  C{geographiclib} package is installed) a C{Geodesic}
@@ -848,7 +864,7 @@ def _polygon(geodesic, points, closed, line, wrap):
848
864
  if not closed: # closed only
849
865
  raise _ValueError(closed=closed, points=_composite_)
850
866
 
851
- return points._sum1(_a_p, closed, line, wrap)
867
+ return points._sum1(_a_p, closed, line, wrap, polar)
852
868
 
853
869
  gP = geodesic.Polygon(line)
854
870
  _A = gP.AddPoint
@@ -867,7 +883,7 @@ def _polygon(geodesic, points, closed, line, wrap):
867
883
  _A(p0.lat, p0.lon)
868
884
 
869
885
  # gP.Compute returns (number_of_points, perimeter, signed area)
870
- return gP.Compute(False, True)[1 if line else 2]
886
+ return gP.Compute(reverse=False, sign=True, polar=polar)[1 if line else 2]
871
887
 
872
888
 
873
889
  try:
pygeodesy/ktm.py CHANGED
@@ -40,7 +40,7 @@ and licensed under the MIT/X11 License. For more information, see the
40
40
  U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
41
41
  '''
42
42
  # make sure int/int division yields float quotient
43
- from __future__ import division as _; del _ # PYCHOK semicolon
43
+ from __future__ import division as _; del _ # noqa: E702 ;
44
44
 
45
45
  from pygeodesy.basics import copysign0, _isin, isodd, neg, neg_, \
46
46
  _reverange, _xinstanceof
@@ -66,7 +66,7 @@ from cmath import polar
66
66
  from math import asinh, cos, cosh, degrees, fabs, sin, sinh, sqrt, tanh
67
67
 
68
68
  __all__ = _ALL_LAZY.ktm
69
- __version__ = '25.04.14'
69
+ __version__ = '25.05.12'
70
70
 
71
71
 
72
72
  class KTMError(_ValueError):