pygeodesy 25.5.25__py2.py3-none-any.whl → 25.7.25__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/__init__.py +8 -8
- pygeodesy/__main__.py +2 -1
- pygeodesy/booleans.py +10 -10
- pygeodesy/constants.py +6 -6
- pygeodesy/css.py +1 -1
- pygeodesy/ellipsoidalBase.py +52 -58
- pygeodesy/ellipsoidalExact.py +22 -27
- pygeodesy/ellipsoidalGeodSolve.py +19 -19
- pygeodesy/ellipsoidalKarney.py +22 -27
- pygeodesy/ellipsoidalVincenty.py +12 -11
- pygeodesy/elliptic.py +258 -232
- pygeodesy/fmath.py +6 -4
- pygeodesy/frechet.py +2 -2
- pygeodesy/fsums.py +40 -18
- pygeodesy/geodesici.py +3 -3
- pygeodesy/geodesicw.py +27 -8
- pygeodesy/geodesicx/__init__.py +1 -1
- pygeodesy/geodesicx/__main__.py +2 -2
- pygeodesy/geodesicx/gx.py +53 -48
- pygeodesy/geodesicx/gxarea.py +56 -68
- pygeodesy/geodesicx/gxbases.py +14 -3
- pygeodesy/geodesicx/gxline.py +9 -6
- pygeodesy/geoids.py +1 -1
- pygeodesy/hausdorff.py +2 -2
- pygeodesy/heights.py +4 -4
- pygeodesy/internals.py +2 -2
- pygeodesy/interns.py +5 -5
- pygeodesy/karney.py +27 -11
- pygeodesy/lcc.py +2 -2
- pygeodesy/props.py +3 -3
- pygeodesy/sphericalBase.py +3 -3
- pygeodesy/sphericalNvector.py +18 -15
- pygeodesy/sphericalTrigonometry.py +19 -20
- pygeodesy/vector2d.py +2 -2
- {pygeodesy-25.5.25.dist-info → pygeodesy-25.7.25.dist-info}/METADATA +8 -8
- {pygeodesy-25.5.25.dist-info → pygeodesy-25.7.25.dist-info}/RECORD +38 -38
- {pygeodesy-25.5.25.dist-info → pygeodesy-25.7.25.dist-info}/WHEEL +0 -0
- {pygeodesy-25.5.25.dist-info → pygeodesy-25.7.25.dist-info}/top_level.txt +0 -0
pygeodesy/geodesicx/gxarea.py
CHANGED
|
@@ -17,7 +17,7 @@ U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
|
|
|
17
17
|
# make sure int/int division yields float quotient
|
|
18
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__ = '25.
|
|
34
|
+
__version__ = '25.06.04'
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class GeodesicAreaExact(_NamedBase):
|
|
38
|
-
'''Area and perimeter of a geodesic polygon, an enhanced
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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,46 +137,45 @@ 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
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
the
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
the
|
|
166
|
-
with C{polyline=False}. For perimeter
|
|
167
|
-
C{polyline=True}, area is C{NAN}.
|
|
168
|
-
|
|
169
|
-
@note: Arbitrarily complex polygons are allowed. In the case
|
|
170
|
-
|
|
171
|
-
|
|
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
|
'''
|
|
176
172
|
r, n = None, self.num
|
|
177
173
|
if n < 2:
|
|
178
174
|
p = _0_0
|
|
179
|
-
a =
|
|
175
|
+
a = NAN if n > 0 and 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,
|
|
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,
|
|
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,53 @@ class GeodesicAreaExact(_NamedBase):
|
|
|
313
311
|
|
|
314
312
|
Clear = Reset
|
|
315
313
|
|
|
316
|
-
def TestEdge(self, azi, s,
|
|
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
|
|
322
|
-
|
|
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.
|
|
328
|
-
|
|
329
|
-
@return: L{Area3Tuple}C{(number, perimeter, area)}.
|
|
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}.
|
|
330
321
|
|
|
331
|
-
@
|
|
322
|
+
@return: L{Area3Tuple}C{(number, perimeter, area)}, with C{perimeter} and
|
|
323
|
+
C{area} both C{NAN} for insuffcient C{number} of points.
|
|
332
324
|
'''
|
|
333
|
-
n = self.num + 1
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
a, r = NAN, None
|
|
337
|
-
elif n < 2:
|
|
338
|
-
raise GeodesicError(num=self.num)
|
|
325
|
+
r, n = None, self.num + 1
|
|
326
|
+
if n < 2: # raise GeodesicError(num=self.num)
|
|
327
|
+
a = p = NAN # like .test_Planimeter19
|
|
339
328
|
else:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
329
|
+
p = self._Peri.Sum(s)
|
|
330
|
+
if self.polyline:
|
|
331
|
+
a = NAN
|
|
332
|
+
else:
|
|
333
|
+
d = self._Direct(azi, s)
|
|
334
|
+
r = self._Inverse(d.lat2, d.lon2, self.lat0, self.lon0)
|
|
335
|
+
a = self._reduced(d.S12 + r.S12, d.xing + r.xing, n, **reverse_sign_polar)
|
|
336
|
+
p += r.s12
|
|
344
337
|
if self.verbose: # PYCHOK no cover
|
|
345
338
|
self._print(n, p, a, r, azi=azi, s=s)
|
|
346
339
|
return Area3Tuple(n, p, a)
|
|
347
340
|
|
|
348
|
-
def TestPoint(self, lat, lon,
|
|
341
|
+
def TestPoint(self, lat, lon, **reverse_sign_polar):
|
|
349
342
|
'''Compute the properties for a tentative, additional vertex
|
|
350
343
|
|
|
351
344
|
@arg lat: Latitude of the point (C{degrees}).
|
|
352
345
|
@arg lon: Longitude of the point (C{degrees}).
|
|
353
|
-
@kwarg
|
|
354
|
-
|
|
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.
|
|
346
|
+
@kwarg reverse_sign_polar: Optional C{B{reverse}=False}, C{B{sign}=True} and
|
|
347
|
+
C{B{polar}=False} keyword arguments, see method L{Compute}.
|
|
360
348
|
|
|
361
349
|
@return: L{Area3Tuple}C{(number, perimeter, area)}.
|
|
362
350
|
'''
|
|
363
351
|
r, n = None, self.num + 1
|
|
364
352
|
if n < 2:
|
|
365
353
|
p = _0_0
|
|
366
|
-
a =
|
|
354
|
+
a = NAN if self.polyline else p
|
|
367
355
|
else:
|
|
368
356
|
i = self._Inverse(self.lat1, self.lon1, lat, lon)
|
|
369
357
|
p = self._Peri.Sum(i.s12)
|
|
370
358
|
if self._Area:
|
|
371
359
|
r = self._Inverse(lat, lon, self.lat0, self.lon0)
|
|
372
|
-
a = self._reduced(i.S12 + r.S12,
|
|
360
|
+
a = self._reduced(i.S12 + r.S12, i.xing + r.xing, n, **reverse_sign_polar)
|
|
373
361
|
p += r.s12
|
|
374
362
|
else:
|
|
375
363
|
a = NAN
|
pygeodesy/geodesicx/gxbases.py
CHANGED
|
@@ -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__ = '
|
|
23
|
+
__version__ = '25.06.01'
|
|
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,12 +147,23 @@ 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
|
'''
|
|
153
163
|
n, nC4 = _xkwds_item2(name_nC4)
|
|
154
164
|
if nC4 not in _nC4s or not isinstance(nC4, int):
|
|
155
|
-
|
|
165
|
+
t = map(str, _nC4s)
|
|
166
|
+
raise GeodesicError(n, nC4, txt_not_=_or(*t))
|
|
156
167
|
return _nC4s[nC4]
|
|
157
168
|
|
|
158
169
|
|
pygeodesy/geodesicx/gxline.py
CHANGED
|
@@ -37,13 +37,14 @@ from __future__ import division as _; del _ # noqa: E702 ;
|
|
|
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,
|
|
41
|
-
_180_0, _2__PI,
|
|
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.05.
|
|
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
|
@@ -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
|
|
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)
|
pygeodesy/hausdorff.py
CHANGED
|
@@ -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.05.
|
|
88
|
+
__version__ = '25.05.26'
|
|
89
89
|
|
|
90
90
|
_formy = _MODS.into(formy=__name__)
|
|
91
91
|
|
|
@@ -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
|
|
127
|
+
name, kwds = _name2__(**name__kwds) # name__=type(self)
|
|
128
128
|
if name:
|
|
129
129
|
self.name = name
|
|
130
130
|
|
pygeodesy/heights.py
CHANGED
|
@@ -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.05.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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(
|
|
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(
|
|
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/karney.py
CHANGED
|
@@ -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.05.
|
|
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
|
-
|
|
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
|
-
|
|
456
|
-
|
|
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(
|
|
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)
|
|
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/lcc.py
CHANGED
|
@@ -50,7 +50,7 @@ from pygeodesy.utily import atan1, degrees90, degrees180, sincos2, tanPI_2_2
|
|
|
50
50
|
from math import atan, fabs, log, radians, sin, sqrt
|
|
51
51
|
|
|
52
52
|
__all__ = _ALL_LAZY.lcc
|
|
53
|
-
__version__ = '25.05.
|
|
53
|
+
__version__ = '25.05.26'
|
|
54
54
|
|
|
55
55
|
_E0_ = 'E0'
|
|
56
56
|
_N0_ = 'N0'
|
|
@@ -457,7 +457,7 @@ class Lcc(_NamedBase):
|
|
|
457
457
|
# h=self.height, conic=self.conic,
|
|
458
458
|
# name=self._name__(name))
|
|
459
459
|
# args, kwds = _args_kwds(**kwds)
|
|
460
|
-
# return self
|
|
460
|
+
# return type(self)(*args, **kwds) # .classof
|
|
461
461
|
|
|
462
462
|
@Property_RO
|
|
463
463
|
def easting(self):
|
pygeodesy/props.py
CHANGED
|
@@ -26,7 +26,7 @@ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, \
|
|
|
26
26
|
from functools import wraps as _wraps
|
|
27
27
|
|
|
28
28
|
__all__ = _ALL_LAZY.props
|
|
29
|
-
__version__ = '25.05.
|
|
29
|
+
__version__ = '25.05.26'
|
|
30
30
|
|
|
31
31
|
_class_ = 'class'
|
|
32
32
|
_DNL_ = _NL_ * 2 # PYCHOK used!
|
|
@@ -347,7 +347,7 @@ class property_RO(_PropertyBase):
|
|
|
347
347
|
if Clas: # overrides inst.__class__
|
|
348
348
|
d = Clas[0].__dict__.get(uname, MISSING)
|
|
349
349
|
else:
|
|
350
|
-
d = getattr(inst
|
|
350
|
+
d = getattr(type(inst), uname, MISSING)
|
|
351
351
|
# if d is MISSING: # XXX superfluous
|
|
352
352
|
# for c in type(inst).__mro__[:-1]:
|
|
353
353
|
# if uname in c.__dict__:
|
|
@@ -403,7 +403,7 @@ class property_ROver(_property_RO___):
|
|
|
403
403
|
'''
|
|
404
404
|
v = self.method(inst)
|
|
405
405
|
n = self.name
|
|
406
|
-
C = inst
|
|
406
|
+
C = type(inst)
|
|
407
407
|
for c in C.__mro__: # [:-1]
|
|
408
408
|
if getattr(c, n, None) is self:
|
|
409
409
|
setattr(c, n, v) # overwrite property_ROver
|
pygeodesy/sphericalBase.py
CHANGED
|
@@ -40,7 +40,7 @@ from pygeodesy.utily import acos1, asin1, atan2b, atan2d, degrees90, \
|
|
|
40
40
|
from math import cos, fabs, log, sin, sqrt
|
|
41
41
|
|
|
42
42
|
__all__ = _ALL_LAZY.sphericalBase
|
|
43
|
-
__version__ = '25.05.
|
|
43
|
+
__version__ = '25.05.26'
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class CartesianSphericalBase(CartesianBase):
|
|
@@ -592,7 +592,7 @@ def _intersecant2(c, r, p, b, radius=R_M, exact=False, height=None, wrap=False):
|
|
|
592
592
|
p = _unrollon(c, p, wrap=wrap)
|
|
593
593
|
nonexact = exact is None
|
|
594
594
|
|
|
595
|
-
if not isinstanceof(r, c
|
|
595
|
+
if not isinstanceof(r, type(c), type(p)):
|
|
596
596
|
r = Radius_(circle=r)
|
|
597
597
|
elif nonexact:
|
|
598
598
|
r = c.distanceTo(r, radius=radius, wrap=wrap)
|
|
@@ -601,7 +601,7 @@ def _intersecant2(c, r, p, b, radius=R_M, exact=False, height=None, wrap=False):
|
|
|
601
601
|
else:
|
|
602
602
|
raise _ValueError(exact=exact)
|
|
603
603
|
|
|
604
|
-
if not isinstanceof(b, c
|
|
604
|
+
if not isinstanceof(b, type(c), type(p)):
|
|
605
605
|
b = Bearing(b)
|
|
606
606
|
elif nonexact:
|
|
607
607
|
b = p.initialBearingTo(b, wrap=wrap)
|