pygeodesy 25.12.31__py2.py3-none-any.whl → 26.2.2__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 +9 -9
- pygeodesy/albers.py +5 -5
- pygeodesy/auxilats/auxDLat.py +2 -3
- pygeodesy/auxilats/auxLat.py +7 -8
- pygeodesy/cartesianBase.py +2 -2
- pygeodesy/constants.py +6 -1
- pygeodesy/datums.py +5 -8
- pygeodesy/ellipsoids.py +9 -8
- pygeodesy/elliptic.py +543 -149
- pygeodesy/fmath.py +2 -2
- pygeodesy/formy.py +10 -249
- pygeodesy/fsums.py +43 -27
- pygeodesy/geod3solve.py +18 -3
- pygeodesy/geoids.py +120 -73
- pygeodesy/heights.py +8 -7
- pygeodesy/internals.py +10 -3
- pygeodesy/lazily.py +13 -6
- pygeodesy/lcc.py +3 -7
- pygeodesy/named.py +13 -9
- pygeodesy/trf.py +1 -1
- pygeodesy/triaxials/bases.py +64 -42
- pygeodesy/triaxials/triaxial3.py +40 -43
- pygeodesy/triaxials/triaxial5.py +17 -49
- pygeodesy/utily.py +7 -7
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/METADATA +10 -10
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/RECORD +28 -28
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/WHEEL +0 -0
- {pygeodesy-25.12.31.dist-info → pygeodesy-26.2.2.dist-info}/top_level.txt +0 -0
pygeodesy/fmath.py
CHANGED
|
@@ -22,10 +22,10 @@ from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
|
|
|
22
22
|
from pygeodesy.units import Int_, _isHeight, _isRadius
|
|
23
23
|
|
|
24
24
|
from math import fabs, sqrt # pow
|
|
25
|
-
import operator as _operator # in .datums, .trf, .utm
|
|
25
|
+
import operator as _operator # in .datums, .elliptic, .trf, .utm
|
|
26
26
|
|
|
27
27
|
__all__ = _ALL_LAZY.fmath
|
|
28
|
-
__version__ = '
|
|
28
|
+
__version__ = '26.01.06'
|
|
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
|
pygeodesy/formy.py
CHANGED
|
@@ -8,28 +8,25 @@ from __future__ import division as _; del _ # noqa: E702 ;
|
|
|
8
8
|
|
|
9
9
|
from pygeodesy.basics import _copysign, _isin # _args_kwds_count2
|
|
10
10
|
# from pygeodesy.cartesianBase import CartesianBase # _MODS
|
|
11
|
-
from pygeodesy.constants import EPS, EPS0, EPS1,
|
|
11
|
+
from pygeodesy.constants import EPS, EPS0, EPS1, PI, PI2, PI3, PI_2, R_M, \
|
|
12
12
|
_0_0s, float0_, isnon0, remainder, _umod_PI2, \
|
|
13
13
|
_0_0, _0_125, _0_25, _0_5, _1_0, _2_0, _4_0, \
|
|
14
14
|
_90_0, _180_0, _360_0
|
|
15
|
-
from pygeodesy.constants import _3_0, _10_0, MANT_DIG as _DIG53 # PYCHOK used!
|
|
16
15
|
from pygeodesy.datums import Datum, Ellipsoid, _ellipsoidal_datum, \
|
|
17
16
|
_mean_radius, _spherical_datum, _WGS84, _EWGS84
|
|
18
17
|
# from pygeodesy.ellipsoids import Ellipsoid, _EWGS84 # from .datums
|
|
19
|
-
# from pygeodesy.elliptic import Elliptic # _MODS
|
|
20
18
|
from pygeodesy.errors import IntersectionError, LimitError, limiterrors, \
|
|
21
19
|
_TypeError, _ValueError, _xattr, _xError, \
|
|
22
20
|
_xcallable, _xkwds, _xkwds_pop2
|
|
23
|
-
from pygeodesy.fmath import euclid, fdot_,
|
|
24
|
-
from pygeodesy.fsums import
|
|
21
|
+
from pygeodesy.fmath import euclid, fdot_, fprod, hypot, hypot2, sqrt0
|
|
22
|
+
from pygeodesy.fsums import fsumf_, Fmt, unstr
|
|
25
23
|
# from pygeodesy.internals import typename # from .named
|
|
26
|
-
from pygeodesy.interns import _delta_, _distant_,
|
|
27
|
-
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
|
|
28
|
-
from pygeodesy.named import
|
|
29
|
-
|
|
24
|
+
from pygeodesy.interns import _delta_, _distant_, _inside_, _SPACE_, _too_
|
|
25
|
+
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
|
|
26
|
+
from pygeodesy.named import _name__, _name2__, _NamedTuple, _xnamed, \
|
|
27
|
+
typename
|
|
30
28
|
from pygeodesy.namedTuples import Bearing2Tuple, Distance4Tuple, LatLon2Tuple, \
|
|
31
29
|
Intersection3Tuple, PhiLam2Tuple
|
|
32
|
-
from pygeodesy.props import property_ROnce
|
|
33
30
|
# from pygeodesy.streprs import Fmt, unstr # from .fsums
|
|
34
31
|
# from pygeodesy.triaxials.triaxial5 import _hartzell3 # _MODS
|
|
35
32
|
from pygeodesy.units import _isDegrees, _isHeight, _isRadius, Bearing, Degrees_, \
|
|
@@ -46,241 +43,13 @@ from contextlib import contextmanager
|
|
|
46
43
|
from math import atan, cos, degrees, fabs, radians, sin, sqrt # pow
|
|
47
44
|
|
|
48
45
|
__all__ = _ALL_LAZY.formy
|
|
49
|
-
__version__ = '
|
|
46
|
+
__version__ = '26.01.06'
|
|
50
47
|
|
|
51
48
|
_RADIANS2 = radians(_1_0)**2 # degree to radians-squared
|
|
52
49
|
_ratio_ = 'ratio'
|
|
53
50
|
_xline_ = 'xline'
|
|
54
51
|
|
|
55
52
|
|
|
56
|
-
class Elliperim(object):
|
|
57
|
-
'''Singleton with various methods to compute the perimeter of an ellipse.
|
|
58
|
-
'''
|
|
59
|
-
_TOL53 = sqrt(EPS_2) # sqrt(pow(_0_5, _DIG53))
|
|
60
|
-
_TOL53_53 = _TOL53 / _DIG53 # "flat" b/a tolerance, 1.9e-10
|
|
61
|
-
# assert _DIG53 == 53
|
|
62
|
-
|
|
63
|
-
def AGM(self, a, b, maxit=_DIG53):
|
|
64
|
-
'''Return the perimeter of an ellipse with semi-axes C{a} and C{b} using the U{AGM
|
|
65
|
-
<https://PaulBourke.net/geometry/ellipsecirc>} (Arithmetic-Geometric Mean) method.
|
|
66
|
-
|
|
67
|
-
@kwarg maxit: Number of iterations (C{int}).
|
|
68
|
-
|
|
69
|
-
@raise ValueError: No convergence for B{C{maxit}} iterations.
|
|
70
|
-
'''
|
|
71
|
-
_, p, a, b = self._pab4(a, b)
|
|
72
|
-
if p is None:
|
|
73
|
-
c_ = []
|
|
74
|
-
ts = self._AGMs(a, b, max(maxit, _DIG53), c_)
|
|
75
|
-
p = fsum(ts, nonfinites=True)
|
|
76
|
-
p *= PI / c_[0]
|
|
77
|
-
return p
|
|
78
|
-
|
|
79
|
-
def _AGMs(self, a, b, maxit, c_):
|
|
80
|
-
'''(INTERNAL) Yield the C{AGM} terms and final C{c}.
|
|
81
|
-
'''
|
|
82
|
-
c = a + b
|
|
83
|
-
yield c**2
|
|
84
|
-
m = -1
|
|
85
|
-
t = self._TOL53
|
|
86
|
-
for _ in range(maxit): # 4..5 trips
|
|
87
|
-
b = sqrt(a * b)
|
|
88
|
-
a = c * _0_5
|
|
89
|
-
c = a + b
|
|
90
|
-
d = a - b
|
|
91
|
-
m *= 2
|
|
92
|
-
yield d**2 * m
|
|
93
|
-
if d <= (b * t):
|
|
94
|
-
break
|
|
95
|
-
else:
|
|
96
|
-
raise self._Error(maxit, d, b * t)
|
|
97
|
-
c_.append(c) # kludge
|
|
98
|
-
|
|
99
|
-
def Arc43(self, a, b):
|
|
100
|
-
'''Return the perimeter (and arcs) of an ellipse with semi-axes C{a} and C{b}
|
|
101
|
-
with the U{4-Arc<https://PaulBourke.net/geometry/ellipsecirc>} approximation.
|
|
102
|
-
|
|
103
|
-
@return: 3-Tuple C{(p, Ra, Rb)} with perimeter C{p}, arc radius C{Ra} at the
|
|
104
|
-
major and arc radius C{Rb} at the minor semi-axis.
|
|
105
|
-
'''
|
|
106
|
-
_r, p, a, b = self._pab4(a, b)
|
|
107
|
-
if p is None:
|
|
108
|
-
h = hypot(a, b)
|
|
109
|
-
p = atan2(b, a)
|
|
110
|
-
s, c = sincos2(p)
|
|
111
|
-
L = (h - b) * _0_5
|
|
112
|
-
Ra = L / c
|
|
113
|
-
Rb = (h - L) / s
|
|
114
|
-
p = Rb * p + Ra * (PI_2 - p)
|
|
115
|
-
p *= _4_0
|
|
116
|
-
else: # circle or flat
|
|
117
|
-
Ra, Rb = a, b
|
|
118
|
-
return (p, Rb, Ra) if _r else (p, Ra, Rb)
|
|
119
|
-
|
|
120
|
-
# def CR(self, a, b):
|
|
121
|
-
# '''Return the perimeter of an ellipse with semi-axes C{a} and C{b} using U{Rackauckas'
|
|
122
|
-
# <https://www.ChrisRackauckas.com/assets/Papers/ChrisRackauckas-The_Circumference_of_an_Ellipse.pdf>}
|
|
123
|
-
# approximation, also U{here<https://ExtremeLearning.com.AU/a-formula-for-the-perimeter-of-an-ellipse>}.
|
|
124
|
-
# '''
|
|
125
|
-
# _, p, a, b = self._pab4(a, b)
|
|
126
|
-
# if p is None:
|
|
127
|
-
# p = a + b
|
|
128
|
-
# h = ((a - b) / p)**2
|
|
129
|
-
# p *= (fhorner(h, 135168, -85760, -5568, 3867) /
|
|
130
|
-
# fhorner(h, 135168, -119552, 22208, 345)) * PI
|
|
131
|
-
# return p
|
|
132
|
-
|
|
133
|
-
def E2k(self, a, b):
|
|
134
|
-
'''Return the perimeter of an ellipse with semi-axes C{a} and C{b} from the complete
|
|
135
|
-
elliptic integral of the 2nd kind L{E(k)<pygeodesy.elliptic.Elliptic.cE>}.
|
|
136
|
-
'''
|
|
137
|
-
return self._ellip2k(a, b, self._ellipE)
|
|
138
|
-
|
|
139
|
-
def e2k(self, a, b, E_alt=None):
|
|
140
|
-
'''Return the perimeter of an ellipse with semi-axes C{a} and C{b} using U{SciPy's
|
|
141
|
-
ellipe<https://www.JohnDCook.com/perimeter_ellipse.html>} function or method
|
|
142
|
-
C{E_alt}, otherwise C{None}.
|
|
143
|
-
|
|
144
|
-
@kwarg E_alt: An other C{Elliperim}C{(a, b)} method to use in case C{SciPy's
|
|
145
|
-
ellipe} is not available.
|
|
146
|
-
'''
|
|
147
|
-
p = self._ellipe
|
|
148
|
-
if p is not None: # i.e. callable
|
|
149
|
-
p = self._ellip2k(a, b, p)
|
|
150
|
-
elif callable(E_alt): # and E_alt is not Elliperim.e2k
|
|
151
|
-
p = E_alt(a, b)
|
|
152
|
-
return p
|
|
153
|
-
|
|
154
|
-
def _ellipE(self, k):
|
|
155
|
-
'''(INTERNAL) Get the complete C{elliptic} integeral C{E(k)}.
|
|
156
|
-
'''
|
|
157
|
-
return _MODS.elliptic.Elliptic(k).cE
|
|
158
|
-
|
|
159
|
-
@property_ROnce
|
|
160
|
-
def _ellipe(self):
|
|
161
|
-
'''(INTERNAL) Wrap function C{scipy.special.ellipe}, I{once}.
|
|
162
|
-
'''
|
|
163
|
-
try:
|
|
164
|
-
from scipy.special import ellipe
|
|
165
|
-
|
|
166
|
-
def _ellipe(k):
|
|
167
|
-
return float(ellipe(k))
|
|
168
|
-
|
|
169
|
-
except (AttributeError, ImportError):
|
|
170
|
-
_ellipe = None
|
|
171
|
-
return _ellipe # overwrite property_ROnce
|
|
172
|
-
|
|
173
|
-
def _ellip2k(self, a, b, _ellip):
|
|
174
|
-
'''(INTERNAL) Helper for methods C{E2k} and C{e2k}.
|
|
175
|
-
'''
|
|
176
|
-
_, p, a, b = self._pab4(a, b)
|
|
177
|
-
if p is None: # see .ellipsoids.Ellipsoid.L
|
|
178
|
-
k = _1_0 - (b / a)**2
|
|
179
|
-
p = _ellip(k) * a * _4_0
|
|
180
|
-
return p
|
|
181
|
-
|
|
182
|
-
def _Error(self, maxit, d, t):
|
|
183
|
-
return _ValueError(maxit=maxit, txt=Fmt.no_convergence(d, t))
|
|
184
|
-
|
|
185
|
-
def GK(self, a, b):
|
|
186
|
-
'''Return the perimeter of an ellipse with semi-axes C{a} and C{b} using the U{Gauss-Kummer
|
|
187
|
-
<https://www.JohnDCook.com/blog/2023/05/28/approximate-ellipse-perimeter>} series, and
|
|
188
|
-
U{here<https://www.MathsIsFun.com/geometry/ellipse-perimeter.html>}, C{B{b / a} > 0.75}.
|
|
189
|
-
'''
|
|
190
|
-
_, p, a, b = self._pab4(a, b)
|
|
191
|
-
if p is None:
|
|
192
|
-
p = a + b
|
|
193
|
-
h = (a - b) / p
|
|
194
|
-
p *= fhorner(h**2, *self._GKs) * PI
|
|
195
|
-
return p
|
|
196
|
-
|
|
197
|
-
@property_ROnce
|
|
198
|
-
def _GKs(self):
|
|
199
|
-
'''(INTERNAL) Compute the Gauss-Kummer coefficients, I{once}.
|
|
200
|
-
'''
|
|
201
|
-
return (1, 1 / 4, 1 / 64, 1 / 256, 25 / 16384, 49 / 65536,
|
|
202
|
-
441 / 1048576, 1089 / 4194304) # overwrite property_ROnce
|
|
203
|
-
|
|
204
|
-
def HG(self, a, b, maxit=_DIG53):
|
|
205
|
-
'''Return the perimeter of an ellipse with semi-axes C{a} and C{b} using the U{HG
|
|
206
|
-
<https://web.Tecnico.ULisboa.PT/~mcasquilho/compute/com/,ellips/PerimeterOfEllipse.pdf>}
|
|
207
|
-
(HyperGeometric Gauss-Kummer) series.
|
|
208
|
-
|
|
209
|
-
@kwarg maxit: Number of iterations (C{int}), sufficient for C{B{b / a} > 0.125}.
|
|
210
|
-
|
|
211
|
-
@raise ValueError: No convergence for B{C{maxit}} iterations.
|
|
212
|
-
'''
|
|
213
|
-
_, p, a, b = self._pab4(a, b)
|
|
214
|
-
if p is None:
|
|
215
|
-
p = a + b
|
|
216
|
-
h = (a - b) / p
|
|
217
|
-
ts = self._HGs(h, max(maxit, _DIG53))
|
|
218
|
-
p *= fsum(ts, nonfinites=True) * PI
|
|
219
|
-
return p
|
|
220
|
-
|
|
221
|
-
def _HGs(self, h, maxit):
|
|
222
|
-
'''(INTERNAL) Yield the C{HG} terms.
|
|
223
|
-
'''
|
|
224
|
-
t = s_ = -1
|
|
225
|
-
s = _1_0
|
|
226
|
-
yield s
|
|
227
|
-
for u in range(-1, maxit * 2, 2):
|
|
228
|
-
t *= u / (u + 3) * h
|
|
229
|
-
t2 = t**2
|
|
230
|
-
s += t2
|
|
231
|
-
yield t2
|
|
232
|
-
if s == s_:
|
|
233
|
-
break
|
|
234
|
-
s_ = s
|
|
235
|
-
else:
|
|
236
|
-
s -= s_ - t2
|
|
237
|
-
raise self._Error(maxit, t2, s)
|
|
238
|
-
|
|
239
|
-
# def LS(self, a, b):
|
|
240
|
-
# '''Return the perimeter of an ellipse with semi-axes C{a} and C{b} using the U{Linderholm-Segal
|
|
241
|
-
# <https://www.JohnDCook.com/blog/2021/03/24/perimeter-of-an-ellipse>} formula, aka C{3/2 norm}.
|
|
242
|
-
# '''
|
|
243
|
-
# _, p, a, b = self._pab4(a, b)
|
|
244
|
-
# if p is None:
|
|
245
|
-
# p = pow(a, _1_5) + pow(b, _1_5)
|
|
246
|
-
# p = pow(p * _0_5, _2_3rd) * PI2
|
|
247
|
-
# return p
|
|
248
|
-
|
|
249
|
-
def _pab4(self, a, b):
|
|
250
|
-
_r = a < b
|
|
251
|
-
if _r:
|
|
252
|
-
a, b = b, a
|
|
253
|
-
if a > b:
|
|
254
|
-
if b > (a * self._TOL53_53):
|
|
255
|
-
p = None
|
|
256
|
-
elif b < 0:
|
|
257
|
-
t = callername() # underOK=True
|
|
258
|
-
t = _DOT_(typename(self), t)
|
|
259
|
-
raise _ValueError(unstr(t, a, b))
|
|
260
|
-
else: # "flat"
|
|
261
|
-
p = a * _4_0
|
|
262
|
-
else: # circle
|
|
263
|
-
p = a * PI2
|
|
264
|
-
return _r, p, a, b
|
|
265
|
-
|
|
266
|
-
def R2(self, a, b):
|
|
267
|
-
'''Return the perimeter of an ellipse with semi-axes C{a} and C{b} using U{Ramanujan's
|
|
268
|
-
2nd<https://PaulBourke.net/geometry/ellipsecirc>} approximation, C{B{b / a} > 0.9}.
|
|
269
|
-
'''
|
|
270
|
-
_, p, a, b = self._pab4(a, b)
|
|
271
|
-
if p is None:
|
|
272
|
-
p = a + b
|
|
273
|
-
h = (a - b) / p
|
|
274
|
-
h *= _3_0 * h
|
|
275
|
-
h /= sqrt(_4_0 - h) + _10_0 # /= chokes PyChecker?
|
|
276
|
-
p *= (h + _1_0) * PI
|
|
277
|
-
return p
|
|
278
|
-
|
|
279
|
-
if not _FOR_DOCS: # PYCHOK force epydoc
|
|
280
|
-
Elliperim = Elliperim() # singleton
|
|
281
|
-
del _FOR_DOCS
|
|
282
|
-
|
|
283
|
-
|
|
284
53
|
def angle2chord(rad, radius=R_M):
|
|
285
54
|
'''Get the chord length of a (central) angle or I{angular} distance.
|
|
286
55
|
|
|
@@ -599,15 +368,6 @@ def _dS(fun_, radius, wrap, *lls, **adjust):
|
|
|
599
368
|
return r * radius
|
|
600
369
|
|
|
601
370
|
|
|
602
|
-
def elliperim(a, b):
|
|
603
|
-
'''Compute the perimeter of an ellipse with semi-axes C{a} and C{b}
|
|
604
|
-
using the C{Elliperim.e2k} or C{Elliperim.AGM} method.
|
|
605
|
-
|
|
606
|
-
@return: The perimeter (C{scalar}, same units as C{a} and C{b}).
|
|
607
|
-
'''
|
|
608
|
-
return Elliperim.e2k(a, b, Elliperim.E2k)
|
|
609
|
-
|
|
610
|
-
|
|
611
371
|
def _ellipsoidal(earth, where):
|
|
612
372
|
'''(INTERNAL) Helper for distances.
|
|
613
373
|
'''
|
|
@@ -1167,7 +927,8 @@ def hartzell(pov, los=False, earth=_WGS84, **name_LatLon_and_kwds):
|
|
|
1167
927
|
n, kwds = _name2__(name_LatLon_and_kwds, name__=hartzell)
|
|
1168
928
|
try:
|
|
1169
929
|
D = _spherical_datum(earth, name__=hartzell)
|
|
1170
|
-
|
|
930
|
+
m = _MODS._triaxials_triaxial5
|
|
931
|
+
r, h, i = m._hartzell3(pov, los, D.ellipsoid._triaxial)
|
|
1171
932
|
|
|
1172
933
|
C = _MODS.cartesianBase.CartesianBase
|
|
1173
934
|
if kwds:
|
pygeodesy/fsums.py
CHANGED
|
@@ -52,9 +52,8 @@ from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DMAIN_, _DOT_, _from_, \
|
|
|
52
52
|
# from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .named
|
|
53
53
|
from pygeodesy.named import _name__, _name2__, _Named, _NamedTuple, \
|
|
54
54
|
_NotImplemented, _ALL_LAZY, _MODS
|
|
55
|
-
from pygeodesy.props import _allPropertiesOf_n, deprecated_method, \
|
|
56
|
-
deprecated_property_RO,
|
|
57
|
-
Property_RO, property_RO
|
|
55
|
+
from pygeodesy.props import _allPropertiesOf_n, deprecated_method, Property, \
|
|
56
|
+
deprecated_property_RO, Property_RO, property_RO
|
|
58
57
|
from pygeodesy.streprs import Fmt, fstr, unstr
|
|
59
58
|
# from pygeodesy.units import Float, Int # from .constants
|
|
60
59
|
|
|
@@ -62,7 +61,7 @@ from math import fabs, isinf, isnan, \
|
|
|
62
61
|
ceil as _ceil, floor as _floor # PYCHOK used! .ltp
|
|
63
62
|
|
|
64
63
|
__all__ = _ALL_LAZY.fsums
|
|
65
|
-
__version__ = '
|
|
64
|
+
__version__ = '26.02.02'
|
|
66
65
|
|
|
67
66
|
from pygeodesy.interns import (
|
|
68
67
|
_PLUS_ as _add_op_, # in .auxilats.auxAngle
|
|
@@ -197,8 +196,7 @@ except ImportError: # PYCHOK DSPACE! Python 3.12-
|
|
|
197
196
|
_2FACTOR = pow(2, (MANT_DIG + 1) // 2) + _1_0 # 134217729 if MANT_DIG == 53
|
|
198
197
|
|
|
199
198
|
def _2split3(x):
|
|
200
|
-
# Split U{Algorithm 3.2
|
|
201
|
-
# <https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
|
|
199
|
+
# Split U{Algorithm 3.2<https://www.TUHH.De/ti3/paper/rump/OgRuOi05.pdf>}
|
|
202
200
|
a = c = x * _2FACTOR
|
|
203
201
|
a -= c - x
|
|
204
202
|
b = x - a
|
|
@@ -326,13 +324,31 @@ def nonfiniterrors(raiser=None):
|
|
|
326
324
|
_xkwds_get1(d, _isfine=_isfinite) is _isfinite) if d else True
|
|
327
325
|
|
|
328
326
|
|
|
329
|
-
def
|
|
330
|
-
|
|
327
|
+
# def _nsum(xs):
|
|
328
|
+
# '''(INTERNAL) U{Neumaier summation
|
|
329
|
+
# <https://StackOverflow.com/questions/78633770/can-neumaier-summation-be-sped-up>},
|
|
330
|
+
# see IV. Verbessertes Kahan-Babuška-Verfahren.
|
|
331
|
+
# '''
|
|
332
|
+
# s = r = _0_0
|
|
333
|
+
# for x in map(float, xs):
|
|
334
|
+
# t = s + x
|
|
335
|
+
# if fabs(x) <= fabs(s):
|
|
336
|
+
# r += (s - t) + x
|
|
337
|
+
# else:
|
|
338
|
+
# r += (x - t) + s
|
|
339
|
+
# s = t
|
|
340
|
+
# return s + r
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def _1primed(xs, *ys): # in .fmath
|
|
344
|
+
'''(INTERNAL) 1-Primed summation of iterable C{xs} less any C{ys}
|
|
331
345
|
items, all I{known} to be C{scalar}.
|
|
332
346
|
'''
|
|
333
347
|
yield _1_0
|
|
334
348
|
for x in xs:
|
|
335
349
|
yield x
|
|
350
|
+
for y in ys:
|
|
351
|
+
yield -y
|
|
336
352
|
yield _N_1_0
|
|
337
353
|
|
|
338
354
|
|
|
@@ -485,10 +501,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
485
501
|
i.e. any C{type} having method C{__float__}.
|
|
486
502
|
|
|
487
503
|
@note: Handling of I{non-finites} as C{inf}, C{INF}, C{NINF}, C{nan} and C{NAN} is
|
|
488
|
-
determined by function L{nonfiniterrors<fsums.nonfiniterrors>}
|
|
489
|
-
|
|
490
|
-
overruling the
|
|
491
|
-
exceptions by default.
|
|
504
|
+
determined globally by function L{nonfiniterrors<fsums.nonfiniterrors>} or
|
|
505
|
+
by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
|
|
506
|
+
overruling the global setting. For backward compatibility, I{non-finites}
|
|
507
|
+
raise exceptions by default.
|
|
492
508
|
|
|
493
509
|
@see: U{Hettinger<https://GitHub.com/ActiveState/code/tree/master/recipes/Python/
|
|
494
510
|
393090_Binary_floating_point_summatiaccurate_full/recipe-393090.py>},
|
|
@@ -1333,11 +1349,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1333
1349
|
H._fadd(c, up=False)
|
|
1334
1350
|
else: # x == 0
|
|
1335
1351
|
H = cs[0] if n else 0
|
|
1336
|
-
self._fadd(H)
|
|
1352
|
+
return self._fadd(H)
|
|
1337
1353
|
except Exception as X:
|
|
1338
1354
|
t = unstr(where, x, *cs, _ELLIPSIS=4, incx=incx)
|
|
1339
1355
|
raise self._ErrorX(X, _add_op_, t)
|
|
1340
|
-
return self
|
|
1341
1356
|
|
|
1342
1357
|
def _finite(self, other, op=None):
|
|
1343
1358
|
'''(INTERNAL) Return B{C{other}} if C{finite}.
|
|
@@ -1449,6 +1464,12 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1449
1464
|
override L{nonfinites<Fsum.nonfinites>} and
|
|
1450
1465
|
the L{nonfiniterrors} default (C{bool}).
|
|
1451
1466
|
'''
|
|
1467
|
+
f = self._fma(other1, other2, **nonfinites)
|
|
1468
|
+
return self._fset(f)
|
|
1469
|
+
|
|
1470
|
+
def _fma(self, other1, other2, **nonfinites): # in .elliptic
|
|
1471
|
+
'''(INTERNAL) Return C{self * B{other1} + B{other2}}.
|
|
1472
|
+
'''
|
|
1452
1473
|
op = typename(self.fma)
|
|
1453
1474
|
_fs = self._ps_other
|
|
1454
1475
|
try:
|
|
@@ -1459,7 +1480,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1459
1480
|
elif _residue(other1) or _residue(other2):
|
|
1460
1481
|
fs = _2split3s(_fs(op, other1))
|
|
1461
1482
|
fs = _2products(s, fs, *_fs(op, other2))
|
|
1462
|
-
f =
|
|
1483
|
+
f = Fsum(fs, name=op, **nonfinites)
|
|
1463
1484
|
else:
|
|
1464
1485
|
f = _fma(s, other1, other2)
|
|
1465
1486
|
f = _2finite(f, **self._isfine)
|
|
@@ -1469,7 +1490,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
1469
1490
|
f = self._mul_reduce(s, other1) # INF, NAN, NINF
|
|
1470
1491
|
f += sum(_fs(op, other2))
|
|
1471
1492
|
f = self._nonfiniteX(X, op, f, **nonfinites)
|
|
1472
|
-
return
|
|
1493
|
+
return f
|
|
1473
1494
|
|
|
1474
1495
|
def fma_(self, *xys, **nonfinites):
|
|
1475
1496
|
'''Fused-multiply-accumulate C{for i in range(0, len(xys), B{2}):
|
|
@@ -2280,7 +2301,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
2280
2301
|
# assert isscalar(s) and isscalar(x)
|
|
2281
2302
|
return self._pow_2_3(s, x, other, op, **raiser_RESIDUAL)
|
|
2282
2303
|
|
|
2283
|
-
def _ps_acc(self, ps, xs, up=True, **unused):
|
|
2304
|
+
def _ps_acc(self, ps, xs, up=True, **unused): # in .geoids._Dotf and ._Hornerf
|
|
2284
2305
|
'''(INTERNAL) Accumulate C{xs} known scalars into list C{ps}.
|
|
2285
2306
|
'''
|
|
2286
2307
|
n = 0
|
|
@@ -2350,15 +2371,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
|
|
|
2350
2371
|
def _ps_1sum(self, *less):
|
|
2351
2372
|
'''(INTERNAL) Return the partials sum, 1-primed C{less} some scalars.
|
|
2352
2373
|
'''
|
|
2353
|
-
|
|
2354
|
-
yield _1_0
|
|
2355
|
-
for p in ps:
|
|
2356
|
-
yield p
|
|
2357
|
-
for p in ls:
|
|
2358
|
-
yield -p
|
|
2359
|
-
yield _N_1_0
|
|
2360
|
-
|
|
2361
|
-
return _fsum(_1psls(self._ps, less))
|
|
2374
|
+
return _fsum(_1primed(self._ps, *less))
|
|
2362
2375
|
|
|
2363
2376
|
def _raiser(self, r, s, raiser=True, **RESIDUAL):
|
|
2364
2377
|
'''(INTERNAL) Does ratio C{r / s} exceed the RESIDUAL threshold
|
|
@@ -2720,7 +2733,7 @@ try:
|
|
|
2720
2733
|
except ImportError:
|
|
2721
2734
|
_sum = sum
|
|
2722
2735
|
|
|
2723
|
-
def _fsum(xs): # in .elliptic
|
|
2736
|
+
def _fsum(xs): # in .elliptic, .geoids
|
|
2724
2737
|
'''(INTERNAL) Precision summation, Python 2.5-.
|
|
2725
2738
|
'''
|
|
2726
2739
|
F = Fsum(name=_fsum.name, f2product=False, nonfinites=True)
|
|
@@ -2861,8 +2874,11 @@ if __name__ == _DMAIN_:
|
|
|
2861
2874
|
# copied from Hettinger, see L{Fsum} reference
|
|
2862
2875
|
from pygeodesy import frandoms, printf
|
|
2863
2876
|
|
|
2877
|
+
# printf(typename(_sum), end=_COMMASPACE_)
|
|
2864
2878
|
printf(typename(_fsum), end=_COMMASPACE_)
|
|
2865
2879
|
printf(typename(_psum), end=_COMMASPACE_)
|
|
2880
|
+
printf(len(Fsum.__dict__), end=_COMMASPACE_)
|
|
2881
|
+
# printf(len(globals()), end=_COMMASPACE_)
|
|
2866
2882
|
|
|
2867
2883
|
F = Fsum()
|
|
2868
2884
|
if F.is_math_fsum():
|
pygeodesy/geod3solve.py
CHANGED
|
@@ -26,7 +26,7 @@ from pygeodesy.units import Degrees, Meter
|
|
|
26
26
|
# from pygeodesy.utily import sincos2d # from .karney
|
|
27
27
|
|
|
28
28
|
__all__ = _ALL_LAZY.geod3solve
|
|
29
|
-
__version__ = '
|
|
29
|
+
__version__ = '26.01.04'
|
|
30
30
|
|
|
31
31
|
_Triaxial3_WGS84 = Triaxial3s.WGS84_3r # a=6378172, b=6378102, c=6356752
|
|
32
32
|
|
|
@@ -48,16 +48,31 @@ class Geod3Solve8Tuple(_GTuple):
|
|
|
48
48
|
_Names_ = ('bet1', 'omg1', 'alp1', 'bet2', 'omg2', 'alp2', _s12_, _a12_)
|
|
49
49
|
_Units_ = ( Deg, Deg, Deg, Deg, Deg, Deg, Meter, Deg)
|
|
50
50
|
|
|
51
|
+
# @Property_RO
|
|
52
|
+
# def A12(self):
|
|
53
|
+
# '''Approximate arc C{A12} as C{Deg}.
|
|
54
|
+
# '''
|
|
55
|
+
# t = self
|
|
56
|
+
# d = t.s12 or _0_0
|
|
57
|
+
# if d:
|
|
58
|
+
# a = hypot(Deg(t.bet2 - t.bet1).degrees,
|
|
59
|
+
# Deg(t.omg2 - t.omg1).degrees)
|
|
60
|
+
# d = (-a) if d < 0 else a
|
|
61
|
+
# return Deg(d)
|
|
62
|
+
|
|
51
63
|
|
|
52
64
|
class _Geodesic3SolveBase(_Solve3Base):
|
|
53
65
|
'''(INTERNAL) Base class for L{Geodesic3Solve} and L{GeodesicLine3Solve}.
|
|
54
66
|
'''
|
|
67
|
+
_a12x = Geod3Solve8Tuple._Names_.index(_a12_) # last
|
|
55
68
|
_Error = Geodesic3Error
|
|
56
69
|
_Names_Direct = _Names_Distance = \
|
|
57
|
-
_Names_Inverse = Geod3Solve8Tuple._Names_[:
|
|
70
|
+
_Names_Inverse = Geod3Solve8Tuple._Names_[:_a12x] # 7 only, always
|
|
58
71
|
_triaxial3 = _Triaxial3_WGS84
|
|
59
72
|
_Xable_name = _Xables.Geod3Solve.__name__ # typename
|
|
60
73
|
_Xable_path = _Xables.Geod3Solve()
|
|
74
|
+
# assert _a12x == len(Geod3Solve8Tuple._Names_) - 1
|
|
75
|
+
del _a12x
|
|
61
76
|
|
|
62
77
|
@Property_RO
|
|
63
78
|
def a(self):
|
|
@@ -162,7 +177,7 @@ class Geodesic3Solve(_Geodesic3SolveBase):
|
|
|
162
177
|
'''
|
|
163
178
|
a = r.s12 or _0_0
|
|
164
179
|
if a:
|
|
165
|
-
t =
|
|
180
|
+
t = self.triaxial3
|
|
166
181
|
z = _toAzi(r.alp1) + _toAzi(r.alp2)
|
|
167
182
|
s, c = sincos2d(z * _0_5)
|
|
168
183
|
a *= hypot(_over(s, t.perimeter4ab), # azimuth!
|