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/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__ = '25.12.23'
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, EPS_2, PI, PI2, PI3, PI_2, R_M, \
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_, fhorner, fprod, hypot, hypot2, sqrt0
24
- from pygeodesy.fsums import fsum, fsumf_, Fmt, unstr
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_, _DOT_, _inside_, _SPACE_, _too_
27
- from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _FOR_DOCS
28
- from pygeodesy.named import callername, _name__, _name2__, _NamedTuple, \
29
- _xnamed, typename
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__ = '25.12.31'
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
- r, h, i = _MODS.triaxials.triaxial5._hartzell3(pov, los, D.ellipsoid._triaxial)
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, Property, \
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__ = '25.12.24'
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 _1primed(xs): # in .fmath
330
- '''(INTERNAL) 1-Primed summation of iterable C{xs}
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>} for the default
489
- or by method L{nonfinites<Fsum.nonfinites>} for individual C{Fsum} instances,
490
- overruling the default. For backward compatibility, I{non-finites} raise
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 = _Psum(self._ps_acc([], fs, up=False), name=op)
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 self._fset(f)
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
- def _1psls(ps, ls):
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__ = '25.12.31'
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_[:7] # 7 only, always
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 = self.triaxial3
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!