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/fmath.py
CHANGED
|
@@ -7,8 +7,8 @@ C{fused-multiply-add}, polynomials, roots, etc.
|
|
|
7
7
|
# make sure int/int division yields float quotient, see .basics
|
|
8
8
|
from __future__ import division as _; del _ # noqa: E702 ;
|
|
9
9
|
|
|
10
|
-
from pygeodesy.basics import _copysign, copysign0, isbool, isint,
|
|
11
|
-
len2, map1, _xiterable, typename
|
|
10
|
+
from pygeodesy.basics import _copysign, copysign0, isbool, isint, isodd, \
|
|
11
|
+
isscalar, len2, map1, _xiterable, typename
|
|
12
12
|
from pygeodesy.constants import EPS0, EPS02, EPS1, NAN, PI, PI_2, PI_4, \
|
|
13
13
|
_0_0, _0_125, _1_6th, _0_25, _1_3rd, _0_5, _1_0, \
|
|
14
14
|
_1_5, _copysign_0_0, isfinite, remainder
|
|
@@ -25,7 +25,7 @@ from math import fabs, sqrt # pow
|
|
|
25
25
|
import operator as _operator # in .datums, .trf, .utm
|
|
26
26
|
|
|
27
27
|
__all__ = _ALL_LAZY.fmath
|
|
28
|
-
__version__ = '25.
|
|
28
|
+
__version__ = '25.06.03'
|
|
29
29
|
|
|
30
30
|
# sqrt(2) - 1 <https://WikiPedia.org/wiki/Square_root_of_2>
|
|
31
31
|
_0_4142 = 0.41421356237309504880 # ~ 3_730_904_090_310_553 / 9_007_199_254_740_992
|
|
@@ -66,7 +66,7 @@ class Fdot(Fsum):
|
|
|
66
66
|
self._facc_dot(n, a, b, **kwds)
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
class Fdot_(Fdot):
|
|
69
|
+
class Fdot_(Fdot): # in .elliptic
|
|
70
70
|
'''Precision dot product.
|
|
71
71
|
'''
|
|
72
72
|
def __init__(self, *xys, **start_name_f2product_nonfinites_RESIDUAL):
|
|
@@ -78,6 +78,8 @@ class Fdot_(Fdot):
|
|
|
78
78
|
|
|
79
79
|
@see: Class L{Fdot<Fdot.__init__>} for further details.
|
|
80
80
|
'''
|
|
81
|
+
if isodd(len(xys)):
|
|
82
|
+
raise LenError(Fdot_, xys=len(xys))
|
|
81
83
|
Fdot.__init__(self, xys[0::2], *xys[1::2], **start_name_f2product_nonfinites_RESIDUAL)
|
|
82
84
|
|
|
83
85
|
|
pygeodesy/frechet.py
CHANGED
|
@@ -101,7 +101,7 @@ from collections import defaultdict as _defaultdict
|
|
|
101
101
|
# from math import radians # from .points
|
|
102
102
|
|
|
103
103
|
__all__ = _ALL_LAZY.frechet
|
|
104
|
-
__version__ = '25.05.
|
|
104
|
+
__version__ = '25.05.26'
|
|
105
105
|
|
|
106
106
|
_formy = _MODS.into(formy=__name__)
|
|
107
107
|
|
|
@@ -153,7 +153,7 @@ class Frechet(_Named):
|
|
|
153
153
|
@raise FrechetError: Insufficient number of B{C{point1s}} or an invalid
|
|
154
154
|
B{C{point1}}, B{C{fraction}} or B{C{units}}.
|
|
155
155
|
'''
|
|
156
|
-
name, kwds = _name2__(**name__kwds) # name__=self
|
|
156
|
+
name, kwds = _name2__(**name__kwds) # name__=type(self)
|
|
157
157
|
if name:
|
|
158
158
|
self.name = name
|
|
159
159
|
|
pygeodesy/fsums.py
CHANGED
|
@@ -39,15 +39,13 @@ results may differ from Python's C{math.fsum} results.
|
|
|
39
39
|
# make sure int/int division yields float quotient, see .basics
|
|
40
40
|
from __future__ import division as _; del _ # noqa: E702 ;
|
|
41
41
|
|
|
42
|
-
from pygeodesy.basics import _gcd, isbool, iscomplex, isint, isscalar, \
|
|
42
|
+
from pygeodesy.basics import _gcd, isbool, iscomplex, isint, isodd, isscalar, \
|
|
43
43
|
_signOf, itemsorted, signOf, _xiterable
|
|
44
|
-
from pygeodesy.constants import INF, INT0, MANT_DIG, NEG0, NINF, _0_0, \
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
_xkwds_get, _xkwds_get1, _xkwds_not, \
|
|
50
|
-
_xkwds_pop, _xsError
|
|
44
|
+
from pygeodesy.constants import INF, INT0, MANT_DIG, NEG0, NINF, _0_0, _1_0, \
|
|
45
|
+
_N_1_0, _isfinite, _pos_self, Float, Int
|
|
46
|
+
from pygeodesy.errors import _AssertionError, _OverflowError, LenError, _TypeError, \
|
|
47
|
+
_ValueError, _xError, _xError2, _xkwds, _xkwds_get, \
|
|
48
|
+
_xkwds_get1, _xkwds_not, _xkwds_pop, _xsError
|
|
51
49
|
from pygeodesy.internals import _enquote, _envPYGEODESY, _passarg, typename # _sizeof
|
|
52
50
|
from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DMAIN_, _DOT_, _from_, \
|
|
53
51
|
_not_finite_, _SPACE_, _std_, _UNDER_
|
|
@@ -64,7 +62,7 @@ from math import fabs, isinf, isnan, \
|
|
|
64
62
|
ceil as _ceil, floor as _floor # PYCHOK used! .ltp
|
|
65
63
|
|
|
66
64
|
__all__ = _ALL_LAZY.fsums
|
|
67
|
-
__version__ = '25.
|
|
65
|
+
__version__ = '25.06.03'
|
|
68
66
|
|
|
69
67
|
from pygeodesy.interns import (
|
|
70
68
|
_PLUS_ as _add_op_, # in .auxilats.auxAngle
|
|
@@ -121,7 +119,9 @@ try: # MCCABE 26
|
|
|
121
119
|
f = x * y
|
|
122
120
|
yield f
|
|
123
121
|
if _isfinite(f):
|
|
124
|
-
|
|
122
|
+
f = _fma(x, y, -f)
|
|
123
|
+
if f:
|
|
124
|
+
yield f
|
|
125
125
|
for z in zs:
|
|
126
126
|
yield z
|
|
127
127
|
|
|
@@ -162,7 +162,7 @@ except ImportError: # PYCHOK DSPACE! Python 3.12-
|
|
|
162
162
|
def _fmaX(r, *a_b_c): # PYCHOK no cover
|
|
163
163
|
# handle non-finite fma result as Python 3.13+ C-function U{math_fma_impl
|
|
164
164
|
# <https://GitHub.com/python/cpython/blob/main/Modules/mathmodule.c#L2305>}:
|
|
165
|
-
# raise a ValueError for a NAN result from non-NAN C{a_b_c}s otherwise an
|
|
165
|
+
# raise a ValueError for a NAN result from non-NAN C{a_b_c}s, otherwise an
|
|
166
166
|
# OverflowError for a non-finite, non-NAN result from all finite C{a_b_c}s.
|
|
167
167
|
if isnan(r):
|
|
168
168
|
def _x(x):
|
|
@@ -560,7 +560,6 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
560
560
|
self._fset(other, op=_fset_op_, **up)
|
|
561
561
|
return self
|
|
562
562
|
|
|
563
|
-
|
|
564
563
|
def __ceil__(self): # PYCHOK not special in Python 2-
|
|
565
564
|
'''Return this instance' C{math.ceil} as C{int} or C{float}.
|
|
566
565
|
|
|
@@ -1137,7 +1136,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1137
1136
|
return E(u, txt=t, cause=X)
|
|
1138
1137
|
|
|
1139
1138
|
def _facc(self, xs, up=True, **_X_x_origin):
|
|
1140
|
-
'''(INTERNAL) Accumulate more C{scalar}s
|
|
1139
|
+
'''(INTERNAL) Accumulate more C{scalar}s, L{Fsum}s pr L{Fsum2Tuple}s.
|
|
1141
1140
|
'''
|
|
1142
1141
|
if xs:
|
|
1143
1142
|
kwds = self._isfine
|
|
@@ -1472,6 +1471,29 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1472
1471
|
f = self._nonfiniteX(X, op, f, **nonfinites)
|
|
1473
1472
|
return self._fset(f)
|
|
1474
1473
|
|
|
1474
|
+
def fma_(self, *xys, **nonfinites):
|
|
1475
|
+
'''Fused-multiply-accumulate C{for i in range(0, len(xys), B{2}):
|
|
1476
|
+
self = }L{fma<pygeodesy.fmath.fma>}C{(xys[i], xys[i+1], self)}.
|
|
1477
|
+
|
|
1478
|
+
@arg xys: Pairwise multiplicand, multiplier (each C{scalar},
|
|
1479
|
+
an L{Fsum} or L{Fsum2Tuple}), all positional.
|
|
1480
|
+
@kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to
|
|
1481
|
+
override L{nonfinites<Fsum.nonfinites>} and
|
|
1482
|
+
L{nonfiniterrors} default (C{bool}).
|
|
1483
|
+
|
|
1484
|
+
@note: Equivalent to L{fdot_<pygeodesy.fmath.fdot_>}C{(*xys,
|
|
1485
|
+
start=self)}.
|
|
1486
|
+
'''
|
|
1487
|
+
if xys:
|
|
1488
|
+
n = len(xys)
|
|
1489
|
+
if n < 2 or isodd(n):
|
|
1490
|
+
raise LenError(self.fma_, xys=n)
|
|
1491
|
+
f, _fmath_fma = self, _MODS.fmath.fma
|
|
1492
|
+
for x, y in zip(xys[0::2], xys[1::2]):
|
|
1493
|
+
f = _fmath_fma(x, y, f, **nonfinites)
|
|
1494
|
+
self._fset(f)
|
|
1495
|
+
return self
|
|
1496
|
+
|
|
1475
1497
|
fmul = __imul__
|
|
1476
1498
|
|
|
1477
1499
|
def _fmul(self, other, op):
|
|
@@ -1581,8 +1603,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1581
1603
|
L{Fsum}, overriding the L{f2product} default.
|
|
1582
1604
|
|
|
1583
1605
|
@arg two: If omitted, leave the override unchanged, if C{True},
|
|
1584
|
-
turn I{TwoProduct} on, if C{False} off, if C{None}
|
|
1585
|
-
remove
|
|
1606
|
+
turn I{TwoProduct} on, if C{False} off, or if C{None}
|
|
1607
|
+
remove the override (C{bool} or C{None}).
|
|
1586
1608
|
|
|
1587
1609
|
@return: The previous setting (C{bool} or C{None} if not set).
|
|
1588
1610
|
|
|
@@ -2682,11 +2704,11 @@ try:
|
|
|
2682
2704
|
del _fsum # nope, remove _fsum ...
|
|
2683
2705
|
raise ImportError() # ... use _fsum below
|
|
2684
2706
|
|
|
2685
|
-
_sum = _fsum
|
|
2707
|
+
_sum = _fsum
|
|
2686
2708
|
except ImportError:
|
|
2687
|
-
_sum = sum
|
|
2709
|
+
_sum = sum
|
|
2688
2710
|
|
|
2689
|
-
def _fsum(xs):
|
|
2711
|
+
def _fsum(xs): # in .elliptic
|
|
2690
2712
|
'''(INTERNAL) Precision summation, Python 2.5-.
|
|
2691
2713
|
'''
|
|
2692
2714
|
F = Fsum(name=_fsum.name, f2product=False, nonfinites=True)
|
pygeodesy/geodesici.py
CHANGED
|
@@ -29,8 +29,8 @@ from pygeodesy.basics import _copy, _enumereverse, map1, \
|
|
|
29
29
|
_xinstanceof, _xor, typename
|
|
30
30
|
from pygeodesy.constants import EPS, INF, INT0, PI, PI2, PI_4, \
|
|
31
31
|
_0_0, _0_5, _1_0, _1_5, _2_0, _3_0, \
|
|
32
|
-
_45_0, _64_0, _90_0, isfinite
|
|
33
|
-
|
|
32
|
+
_45_0, _64_0, _90_0, isfinite
|
|
33
|
+
from pygeodesy.constants import _EPSjam # PYCHOK used!
|
|
34
34
|
from pygeodesy.ellipsoids import _EWGS84, Fmt, unstr
|
|
35
35
|
from pygeodesy.errors import GeodesicError, IntersectionError, _an, \
|
|
36
36
|
_xgeodesics, _xkwds_get, _xkwds_kwds, \
|
|
@@ -57,7 +57,7 @@ from pygeodesy.utily import atan2, sincos2, fabs, radians
|
|
|
57
57
|
# from math import ceil as _ceil, fabs, radians # .fsums, .utily
|
|
58
58
|
|
|
59
59
|
__all__ = _ALL_LAZY.geodesici
|
|
60
|
-
__version__ = '25.
|
|
60
|
+
__version__ = '25.06.02'
|
|
61
61
|
|
|
62
62
|
_0t = 0, # int
|
|
63
63
|
_1_1t = -1, +1
|
pygeodesy/geodesicw.py
CHANGED
|
@@ -39,7 +39,7 @@ from contextlib import contextmanager
|
|
|
39
39
|
# from math import fabs # from .utily
|
|
40
40
|
|
|
41
41
|
__all__ = _ALL_LAZY.geodesicw
|
|
42
|
-
__version__ = '25.
|
|
42
|
+
__version__ = '25.05.28'
|
|
43
43
|
|
|
44
44
|
_plumb_ = 'plumb'
|
|
45
45
|
_TRIPS = 65
|
|
@@ -96,6 +96,28 @@ class _gWrapped(_kWrapped):
|
|
|
96
96
|
if name:
|
|
97
97
|
self._name, _ = _name2__(name, _or_nameof=E)
|
|
98
98
|
|
|
99
|
+
def Area(self, polyline=False, **name): # like GeodesicExact.Area
|
|
100
|
+
'''Return a C{PolygonArea} instance with method C{Compute} extended.
|
|
101
|
+
'''
|
|
102
|
+
_AreaBase = _wrapped._PolygonArea # in .karney._kwrapped
|
|
103
|
+
|
|
104
|
+
class _PolygonArea(_AreaBase):
|
|
105
|
+
# def __init__(self, *earth_polyline):
|
|
106
|
+
# _PolygonArea.__init__(self, *earth_polyline)
|
|
107
|
+
|
|
108
|
+
def Compute(self, reverse=False, sign=True, polar=False):
|
|
109
|
+
'''Use C{B{polar}=True} to adjust the area, see function
|
|
110
|
+
L{areaOf<pygeodesy.geodesicx.gxarea.areaOf>}.
|
|
111
|
+
'''
|
|
112
|
+
n, p, a = _AreaBase.Compute(self, reverse=reverse, sign=sign)
|
|
113
|
+
if polar: # see .geodesicx.gxarea.GeodesicAreaExact._reduced
|
|
114
|
+
a += _copysign(self.area0 * _0_5 * n, a)
|
|
115
|
+
return n, p, a
|
|
116
|
+
|
|
117
|
+
A = _PolygonArea(self, polyline)
|
|
118
|
+
A.name = _name2__(name, _or_nameof=self)
|
|
119
|
+
return A
|
|
120
|
+
|
|
99
121
|
def ArcDirect(self, lat1, lon1, azi1, a12, outmask=Caps.STANDARD): # PYCHOK no cover
|
|
100
122
|
'''Return the C{_Geodesic.ArcDirect} result as L{GDict}.
|
|
101
123
|
'''
|
|
@@ -108,8 +130,6 @@ class _gWrapped(_kWrapped):
|
|
|
108
130
|
'''
|
|
109
131
|
return self._GenDirectLine(lat1, lon1, azi1, True, a12, caps, **name)
|
|
110
132
|
|
|
111
|
-
Area = _Geodesic.Polygon # like GeodesicExact.Area
|
|
112
|
-
|
|
113
133
|
@property_RO
|
|
114
134
|
def datum(self):
|
|
115
135
|
'''Get this geodesic's datum (C{Datum}).
|
|
@@ -257,9 +277,8 @@ class _gWrapped(_kWrapped):
|
|
|
257
277
|
'''
|
|
258
278
|
return self._name
|
|
259
279
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
WGS84 = None # _EWGS84.geodesicw recusion
|
|
280
|
+
Polygon = Area
|
|
281
|
+
WGS84 = None # _EWGS84.geodesicw recusion
|
|
263
282
|
|
|
264
283
|
# Geodesic.ArcDirect.__doc__ = _Geodesic.ArcDirect.__doc__
|
|
265
284
|
# Geodesic.Direct.__doc__ = _Geodesic.Direct.__doc__
|
|
@@ -461,7 +480,7 @@ class Geodesic(_gWrapped): # overwritten by 1st instance
|
|
|
461
480
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
462
481
|
'''
|
|
463
482
|
g = _wrapped.Geodesic(a_ellipsoid, f=f, **name)
|
|
464
|
-
_MODS.geodesicw.Geodesic = g
|
|
483
|
+
_MODS.geodesicw.Geodesic = type(g) # overwrite class
|
|
465
484
|
return g
|
|
466
485
|
|
|
467
486
|
|
|
@@ -485,7 +504,7 @@ class GeodesicLine(_gWrapped): # overwritten by 1st instance
|
|
|
485
504
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
486
505
|
'''
|
|
487
506
|
gl = _wrapped.GeodesicLine(geodesic, lat1, lon1, azi1, caps=caps, **name)
|
|
488
|
-
_MODS.geodesicw.GeodesicLine = gl
|
|
507
|
+
_MODS.geodesicw.GeodesicLine = type(gl) # overwrite class
|
|
489
508
|
return gl
|
|
490
509
|
|
|
491
510
|
|
pygeodesy/geodesicx/__init__.py
CHANGED
pygeodesy/geodesicx/__main__.py
CHANGED
|
@@ -5,7 +5,7 @@ u'''Print L{geodesicx} version, etc. using C{python -m pygeodesy.geodesicx}.
|
|
|
5
5
|
'''
|
|
6
6
|
|
|
7
7
|
__all__ = ()
|
|
8
|
-
__version__ = '25.
|
|
8
|
+
__version__ = '25.06.01'
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _main(**C4order): # PYCHOK no cover
|
|
@@ -47,7 +47,7 @@ from sys import argv # .internals._isPyChOK
|
|
|
47
47
|
_main(C4order=int(argv[1])) if len(argv) == 2 and argv[1].isdigit() else _main()
|
|
48
48
|
|
|
49
49
|
# % python3.13 -m pygeodesy.geodesicx
|
|
50
|
-
# pygeodesy.geodesicx 25.
|
|
50
|
+
# pygeodesy.geodesicx 25.06.01: C4order=30, C4n=5425, C4u=5107, C4u_n=94.1%, C4x=465, C4t=tuple, C4z=166008, geographiclib 2.0 (pygeodesy 25.5.28 Python 3.13.3 64bit arm64 macOS 15.5)
|
|
51
51
|
|
|
52
52
|
# % python3.13 -m pygeodesy.geodesicx 30
|
|
53
53
|
# pygeodesy.geodesicx 24.09.06: C4order=30, C4n=5425, C4u=5107, C4u_n=94.1%, C4x=465, C4t=tuple, C4z=166008 (pygeodesy 24.9.6 Python 3.13.0rc1 64bit arm64 macOS 14.6.1)
|
pygeodesy/geodesicx/gx.py
CHANGED
|
@@ -44,11 +44,11 @@ from pygeodesy.constants import EPS, EPS0, EPS02, MANT_DIG, NAN, PI, _EPSqrt, \
|
|
|
44
44
|
from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
|
|
45
45
|
# from pygeodesy.ellipsoids import _EWGS84 # from .datums
|
|
46
46
|
from pygeodesy.errors import GeodesicError, _xkwds_pop2
|
|
47
|
-
from pygeodesy.fmath import hypot
|
|
47
|
+
from pygeodesy.fmath import fdot_, hypot, hypot2, Fmt
|
|
48
48
|
from pygeodesy.fsums import fsumf_, fsum1f_
|
|
49
49
|
from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
|
|
50
50
|
_sincos12, _sin1cos2, _sinf1cos2d, \
|
|
51
|
-
_TINY, _xnC4
|
|
51
|
+
_TINY, _toNAN, _xnC4
|
|
52
52
|
from pygeodesy.geodesicx.gxline import _GeodesicLineExact, _update_glXs
|
|
53
53
|
# from pygeodesy.internals import typename # from .basics
|
|
54
54
|
from pygeodesy.interns import NN, _DOT_, _UNDER_
|
|
@@ -65,7 +65,7 @@ from pygeodesy.utily import atan2, atan2d as _atan2d_reverse, _unrollon, \
|
|
|
65
65
|
from math import copysign, cos, degrees, fabs, radians, sqrt
|
|
66
66
|
|
|
67
67
|
__all__ = ()
|
|
68
|
-
__version__ = '25.
|
|
68
|
+
__version__ = '25.06.01'
|
|
69
69
|
|
|
70
70
|
_MAXIT1 = 20
|
|
71
71
|
_MAXIT2 = 10 + _MAXIT1 + MANT_DIG # MANT_DIG == C++ digits
|
|
@@ -96,15 +96,12 @@ def _eTOL2(f):
|
|
|
96
96
|
# (bet1 + bet2) / 2, the relative error in the azimuth
|
|
97
97
|
# consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2.
|
|
98
98
|
# (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000.
|
|
99
|
-
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
|
|
105
|
-
# Here 0.1 is a safety factor (error decreased by 100) and
|
|
106
|
-
# max(0.001, abs(f)) stops etol2 getting too large in the
|
|
107
|
-
# nearly spherical case.
|
|
99
|
+
# For a given f and sig12, the max error occurs for lines
|
|
100
|
+
# near the pole. If the old rule for computing dnm = (dn1 +
|
|
101
|
+
# dn2)/2 is used, then the error increases by a factor of 2.)
|
|
102
|
+
# Setting this equal to epsilon gives sig12 = eTOL2. Here,
|
|
103
|
+
# safety factor 0.1 (error decreased by 100) and max(0.001, abs(f))
|
|
104
|
+
# stops eTOL2 getting too large in the nearly spherical case.
|
|
108
105
|
t = min(_1_0, _1_0 - f * _0_5) * max(_0_001, fabs(f)) * _0_5
|
|
109
106
|
return _TOL3 / (sqrt(t) if t > EPS02 else EPS0)
|
|
110
107
|
|
|
@@ -216,11 +213,10 @@ class GeodesicExact(_GeodesicBase):
|
|
|
216
213
|
return GeodesicLineExact(self, lat1, lon1, azi1, caps=caps, **name)._GenSet(self._debug, a12=a12)
|
|
217
214
|
|
|
218
215
|
def Area(self, polyline=False, **name):
|
|
219
|
-
'''Set up a L{GeodesicAreaExact} to compute area and
|
|
220
|
-
perimeter of a polygon.
|
|
216
|
+
'''Set up a L{GeodesicAreaExact} to compute area and perimeter of a polygon.
|
|
221
217
|
|
|
222
|
-
@kwarg polyline: If C{True}, compute the perimeter only, otherwise
|
|
223
|
-
|
|
218
|
+
@kwarg polyline: If C{True}, compute the perimeter only, otherwise the
|
|
219
|
+
perimeter and area (C{bool}).
|
|
224
220
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
225
221
|
|
|
226
222
|
@return: A L{GeodesicAreaExact} instance.
|
|
@@ -429,17 +425,21 @@ class GeodesicExact(_GeodesicBase):
|
|
|
429
425
|
def _eF_reset_cHe2_f1(self, x, y):
|
|
430
426
|
'''(INTERNAL) Reset elliptic function and return M{cH * e2 / f1 * ...}.
|
|
431
427
|
'''
|
|
432
|
-
|
|
433
|
-
|
|
428
|
+
if isnan(x):
|
|
429
|
+
y = NAN
|
|
430
|
+
else:
|
|
431
|
+
self._eF_reset_k2(x)
|
|
432
|
+
y *= self._eF.cH * self._e2_f1
|
|
433
|
+
return y
|
|
434
434
|
|
|
435
435
|
def _eF_reset_k2(self, x):
|
|
436
436
|
'''(INTERNAL) Reset elliptic function and return C{k2}.
|
|
437
437
|
'''
|
|
438
438
|
ep2 = self.ep2
|
|
439
|
-
|
|
440
|
-
self._eF.reset(k2=-
|
|
439
|
+
x *= x * ep2 # see .gxline._GeodesicLineExact._eF
|
|
440
|
+
self._eF.reset(k2=-x, alpha2=-ep2) # kp2, alphap2 defaults
|
|
441
441
|
_update_glXs(self) # zap cached/memoized _GeodesicLineExact attrs
|
|
442
|
-
return
|
|
442
|
+
return x
|
|
443
443
|
|
|
444
444
|
@Property_RO
|
|
445
445
|
def ellipsoid(self):
|
|
@@ -499,6 +499,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
499
499
|
if self._debug: # PYCHOK no cover
|
|
500
500
|
outmask |= Cs._DEBUG_INVERSE & self._debug
|
|
501
501
|
outmask &= Cs._OUT_MASK # incl. _SALP_CALPs_ and _DEBUG_
|
|
502
|
+
toNAN = _toNAN(outmask, lat1, lon1, lat2, lon2)
|
|
502
503
|
# compute longitude difference carefully (with _diff182):
|
|
503
504
|
# result is in [-180, +180] but -180 is only for west-going
|
|
504
505
|
# geodesics, +180 is for east-going and meridional geodesics
|
|
@@ -700,7 +701,9 @@ class GeodesicExact(_GeodesicBase):
|
|
|
700
701
|
eFk2=eF.k2, eFa2=eF.alpha2)
|
|
701
702
|
p.update(r) # r overrides p
|
|
702
703
|
r = p.toGDict()
|
|
703
|
-
|
|
704
|
+
|
|
705
|
+
r = self._iter2tion(r, **p)
|
|
706
|
+
return r._toNAN(outmask) if toNAN else r
|
|
704
707
|
|
|
705
708
|
def _GenDirect(self, lat1, lon1, azi1, arcmode, s12_a12, outmask=Caps.STANDARD):
|
|
706
709
|
'''(INTERNAL) The general I{Inverse} geodesic calculation.
|
|
@@ -805,8 +808,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
805
808
|
<https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>} and
|
|
806
809
|
Python U{Geodesic.InverseLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
|
|
807
810
|
'''
|
|
808
|
-
|
|
809
|
-
r = self._GDictInverse(lat1, lon1, lat2, lon2, caps | Cs._SALP_CALPs_)
|
|
811
|
+
r = self._GDictInverse(lat1, lon1, lat2, lon2, caps | Caps._SALP_CALPs_)
|
|
810
812
|
return GeodesicLineExact(self, lat1, lon1, None, caps=caps, _s_calp1=(r.salp1, r.calp1),
|
|
811
813
|
**name)._GenSet(self._debug, **r)
|
|
812
814
|
|
|
@@ -839,12 +841,12 @@ class GeodesicExact(_GeodesicBase):
|
|
|
839
841
|
# (tan(bet1/2) + tan(bet2/2)) /
|
|
840
842
|
# (tan(bet1/2) * tan(bet2/2) + 1))
|
|
841
843
|
# with tan(x/2) = sin(x) / (1 + cos(x))
|
|
842
|
-
dbet1 =
|
|
843
|
-
dbet2 =
|
|
844
|
-
domg12 =
|
|
845
|
-
salp12 = (p.sbet1
|
|
846
|
-
calp12 = (p.sbet1
|
|
847
|
-
alp12 =
|
|
844
|
+
dbet1 = p.cbet1 + _1_0
|
|
845
|
+
dbet2 = p.cbet2 + _1_0
|
|
846
|
+
domg12 = comg12 + _1_0
|
|
847
|
+
salp12 = fdot_(p.sbet1, dbet2, dbet1, p.sbet2) * somg12
|
|
848
|
+
calp12 = fdot_(p.sbet1, p.sbet2, dbet1, dbet2) * domg12
|
|
849
|
+
alp12 = atan2(salp12, calp12) * _2_0
|
|
848
850
|
else:
|
|
849
851
|
# alp12 = alp2 - alp1, used in atan2, no need to normalize
|
|
850
852
|
salp12, calp12 = _sincos12(salp1, calp1, salp2, calp2)
|
|
@@ -870,7 +872,7 @@ class GeodesicExact(_GeodesicBase):
|
|
|
870
872
|
and C{p.set_sigs} updated for Newton, C{sig12=None}.
|
|
871
873
|
'''
|
|
872
874
|
sig12 = None # use Newton
|
|
873
|
-
salp1 = calp1 = salp2 = calp2 =
|
|
875
|
+
salp1 = calp1 = salp2 = calp2 = NAN
|
|
874
876
|
|
|
875
877
|
# bet12 = bet2 - bet1 in [0, PI)
|
|
876
878
|
sbet12, cbet12 = _sincos12(p.sbet1, p.cbet1, p.sbet2, p.cbet2)
|
|
@@ -878,12 +880,15 @@ class GeodesicExact(_GeodesicBase):
|
|
|
878
880
|
if shortline:
|
|
879
881
|
# sin((bet1 + bet2)/2)^2 = (sbet1 + sbet2)^2 / (
|
|
880
882
|
# (cbet1 + cbet2)^2 + (sbet1 + sbet2)^2)
|
|
881
|
-
t =
|
|
882
|
-
|
|
883
|
-
|
|
883
|
+
t = p.sbet1 + p.sbet2
|
|
884
|
+
if t:
|
|
885
|
+
t *= t / hypot2(t, p.cbet1 + p.cbet2)
|
|
886
|
+
dnm = sqrt(self.ep2 * t + _1_0)
|
|
887
|
+
else:
|
|
888
|
+
dnm = _1_0
|
|
884
889
|
somg12, comg12 = _sincos2(lam12 / (self.f1 * dnm))
|
|
885
890
|
else:
|
|
886
|
-
somg12, comg12 = p.slam12, p.clam12
|
|
891
|
+
somg12, comg12, dnm = p.slam12, p.clam12, NAN
|
|
887
892
|
|
|
888
893
|
# bet12a = bet2 + bet1 in (-PI, 0], note -sbet1
|
|
889
894
|
sbet12a, cbet12a = _sincos12(-p.sbet1, p.cbet1, p.sbet2, p.cbet2)
|
|
@@ -894,8 +899,8 @@ class GeodesicExact(_GeodesicBase):
|
|
|
894
899
|
salp1 = p.cbet2 * somg12
|
|
895
900
|
calp1 = (sbet12a - t) if comg12 < 0 else (sbet12 + t)
|
|
896
901
|
|
|
897
|
-
ssig12 =
|
|
898
|
-
csig12 =
|
|
902
|
+
ssig12 = hypot(salp1, calp1)
|
|
903
|
+
csig12 = fdot_(p.sbet1, p.sbet2, p.cbet1, p.cbet2 * comg12)
|
|
899
904
|
|
|
900
905
|
if shortline and ssig12 < self._eTOL2: # really short lines
|
|
901
906
|
t = c if comg12 < 0 else s
|
|
@@ -970,8 +975,8 @@ class GeodesicExact(_GeodesicBase):
|
|
|
970
975
|
#
|
|
971
976
|
# omg12 is near PI, estimate work with omg12a = PI - omg12
|
|
972
977
|
k = _Astroid(x, y)
|
|
973
|
-
|
|
974
|
-
|
|
978
|
+
k1 = _1_0 + k
|
|
979
|
+
sca *= (y * k1 / k) if f < 0 else (x * k / k1)
|
|
975
980
|
s, c = _sincos2(-sca) # omg12a
|
|
976
981
|
# update spherical estimate of alp1 using omg12 instead of lam12
|
|
977
982
|
salp1 = p.cbet2 * s
|
|
@@ -1082,16 +1087,15 @@ class GeodesicExact(_GeodesicBase):
|
|
|
1082
1087
|
# Missing a factor of self.b. Add parens around
|
|
1083
1088
|
# (csig1 * ssig2) and (ssig1 * csig2) to ensure
|
|
1084
1089
|
# accurate cancellation for coincident points.
|
|
1085
|
-
m12b =
|
|
1086
|
-
|
|
1087
|
-
|
|
1090
|
+
m12b = fdot_(p.dn2, (p.csig1 * p.ssig2),
|
|
1091
|
+
-p.dn1, (p.ssig1 * p.csig2),
|
|
1092
|
+
J12, (p.csig1 * p.csig2))
|
|
1088
1093
|
if (outmask & Cs.GEODESICSCALE):
|
|
1089
|
-
M12 = M21 = p.ssig1
|
|
1090
|
-
p.csig1 * p.csig2
|
|
1094
|
+
M12 = M21 = fdot_(p.ssig1, p.ssig2, p.csig1, p.csig2)
|
|
1091
1095
|
t = (p.cbet1 - p.cbet2) * self.ep2 * \
|
|
1092
1096
|
(p.cbet1 + p.cbet2) / (p.dn1 + p.dn2)
|
|
1093
|
-
M12 += (p.ssig2
|
|
1094
|
-
M21 -= (p.ssig1
|
|
1097
|
+
M12 += fdot_(p.ssig2, t, p.csig2, J12) * p.ssig1 / p.dn1
|
|
1098
|
+
M21 -= fdot_(p.ssig1, t, p.csig1, J12) * p.ssig2 / p.dn2
|
|
1095
1099
|
|
|
1096
1100
|
return s12b, m12b, m0, M12, M21
|
|
1097
1101
|
|
|
@@ -1223,7 +1227,8 @@ class GeodesicExact(_GeodesicBase):
|
|
|
1223
1227
|
tripb = fsum1f_(calp1a, -calp1, _abs(salp1a - salp1)) < TOLb or \
|
|
1224
1228
|
fsum1f_(calp1b, -calp1, _abs(salp1b - salp1)) < TOLb
|
|
1225
1229
|
else:
|
|
1226
|
-
|
|
1230
|
+
v = Fmt.no_convergence(v, TOLv)
|
|
1231
|
+
raise GeodesicError(v, txt=repr(self)) # self.toRepr()
|
|
1227
1232
|
|
|
1228
1233
|
p.set_(iter=i, trip=tripb) # like .geodsolve._GDictInvoke: iter NOT iteration!
|
|
1229
1234
|
return sig12, salp1, calp1, salp2, calp2, domg12
|
|
@@ -1310,7 +1315,7 @@ def _Astroid(x, y):
|
|
|
1310
1315
|
u = _cbrt(S * _2_0) # == T3 + _copysign(abs(S), T3)
|
|
1311
1316
|
else:
|
|
1312
1317
|
u = _0_0
|
|
1313
|
-
v =
|
|
1318
|
+
v = hypot(u, y) # sqrt(u**2 + q)
|
|
1314
1319
|
# avoid loss of accuracy when u < 0
|
|
1315
1320
|
u = (q / (v - u)) if u < 0 else (v + u)
|
|
1316
1321
|
w = (u - q) / (v + v) # positive?
|