pygeodesy 25.4.8__py2.py3-none-any.whl → 25.5.5__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. pygeodesy/__init__.py +36 -31
  2. pygeodesy/__main__.py +3 -3
  3. pygeodesy/albers.py +29 -36
  4. pygeodesy/auxilats/_CX_4.py +2 -2
  5. pygeodesy/auxilats/_CX_6.py +2 -2
  6. pygeodesy/auxilats/_CX_8.py +2 -2
  7. pygeodesy/auxilats/_CX_Rs.py +9 -9
  8. pygeodesy/auxilats/__init__.py +3 -3
  9. pygeodesy/auxilats/__main__.py +8 -6
  10. pygeodesy/auxilats/auxAngle.py +2 -2
  11. pygeodesy/auxilats/auxLat.py +5 -5
  12. pygeodesy/auxilats/auxily.py +5 -3
  13. pygeodesy/azimuthal.py +7 -6
  14. pygeodesy/basics.py +32 -18
  15. pygeodesy/booleans.py +18 -16
  16. pygeodesy/cartesianBase.py +26 -24
  17. pygeodesy/clipy.py +11 -10
  18. pygeodesy/constants.py +11 -10
  19. pygeodesy/css.py +14 -11
  20. pygeodesy/datums.py +8 -8
  21. pygeodesy/deprecated/bases.py +2 -2
  22. pygeodesy/deprecated/classes.py +2 -2
  23. pygeodesy/deprecated/consterns.py +4 -4
  24. pygeodesy/dms.py +8 -8
  25. pygeodesy/ecef.py +22 -29
  26. pygeodesy/ecefLocals.py +186 -0
  27. pygeodesy/elevations.py +9 -8
  28. pygeodesy/ellipsoidalBase.py +19 -8
  29. pygeodesy/ellipsoidalBaseDI.py +17 -15
  30. pygeodesy/ellipsoidalNvector.py +6 -3
  31. pygeodesy/ellipsoidalVincenty.py +4 -1
  32. pygeodesy/ellipsoids.py +186 -164
  33. pygeodesy/elliptic.py +9 -9
  34. pygeodesy/errors.py +44 -43
  35. pygeodesy/etm.py +7 -7
  36. pygeodesy/fmath.py +30 -14
  37. pygeodesy/formy.py +11 -12
  38. pygeodesy/frechet.py +216 -109
  39. pygeodesy/fstats.py +5 -4
  40. pygeodesy/fsums.py +79 -78
  41. pygeodesy/gars.py +4 -3
  42. pygeodesy/geodesici.py +15 -14
  43. pygeodesy/geodesicw.py +34 -32
  44. pygeodesy/geodesicx/__init__.py +1 -1
  45. pygeodesy/geodesicx/__main__.py +11 -9
  46. pygeodesy/geodesicx/gx.py +30 -33
  47. pygeodesy/geodesicx/gxarea.py +2 -2
  48. pygeodesy/geodesicx/gxline.py +5 -5
  49. pygeodesy/geodsolve.py +18 -17
  50. pygeodesy/geohash.py +5 -5
  51. pygeodesy/geoids.py +34 -31
  52. pygeodesy/hausdorff.py +17 -13
  53. pygeodesy/heights.py +2 -4
  54. pygeodesy/internals.py +28 -44
  55. pygeodesy/interns.py +10 -7
  56. pygeodesy/iters.py +8 -8
  57. pygeodesy/karney.py +68 -62
  58. pygeodesy/ktm.py +5 -5
  59. pygeodesy/latlonBase.py +20 -21
  60. pygeodesy/lazily.py +104 -78
  61. pygeodesy/lcc.py +11 -9
  62. pygeodesy/ltp.py +56 -58
  63. pygeodesy/ltpTuples.py +35 -36
  64. pygeodesy/mgrs.py +7 -6
  65. pygeodesy/named.py +48 -177
  66. pygeodesy/nvectorBase.py +7 -7
  67. pygeodesy/osgr.py +9 -8
  68. pygeodesy/points.py +12 -10
  69. pygeodesy/props.py +25 -25
  70. pygeodesy/resections.py +83 -80
  71. pygeodesy/rhumb/__init__.py +1 -1
  72. pygeodesy/rhumb/aux_.py +7 -7
  73. pygeodesy/rhumb/bases.py +22 -20
  74. pygeodesy/rhumb/ekx.py +6 -6
  75. pygeodesy/rhumb/solve.py +15 -15
  76. pygeodesy/solveBase.py +3 -3
  77. pygeodesy/sphericalBase.py +6 -6
  78. pygeodesy/sphericalNvector.py +6 -5
  79. pygeodesy/sphericalTrigonometry.py +8 -7
  80. pygeodesy/streprs.py +14 -14
  81. pygeodesy/trf.py +14 -12
  82. pygeodesy/triaxials.py +29 -26
  83. pygeodesy/units.py +5 -4
  84. pygeodesy/unitsBase.py +5 -4
  85. pygeodesy/ups.py +3 -3
  86. pygeodesy/utily.py +4 -4
  87. pygeodesy/utmups.py +4 -4
  88. pygeodesy/utmupsBase.py +110 -18
  89. pygeodesy/vector2d.py +20 -13
  90. pygeodesy/vector3d.py +7 -6
  91. pygeodesy/webmercator.py +6 -5
  92. pygeodesy/wgrs.py +6 -5
  93. {pygeodesy-25.4.8.dist-info → pygeodesy-25.5.5.dist-info}/METADATA +30 -25
  94. pygeodesy-25.5.5.dist-info/RECORD +119 -0
  95. pygeodesy-25.4.8.dist-info/RECORD +0 -118
  96. {pygeodesy-25.4.8.dist-info → pygeodesy-25.5.5.dist-info}/WHEEL +0 -0
  97. {pygeodesy-25.4.8.dist-info → pygeodesy-25.5.5.dist-info}/top_level.txt +0 -0
pygeodesy/props.py CHANGED
@@ -13,20 +13,20 @@ choices, see callable L{DeprecationWarnings} below.
13
13
  from pygeodesy.basics import isclass as _isclass
14
14
  from pygeodesy.errors import _AssertionError, _AttributeError, \
15
15
  _xcallable, _xkwds_get
16
- # from pygeodesy.internals import _tailof # from .lazily
16
+ from pygeodesy.internals import _tailof, typename
17
17
  from pygeodesy.interns import MISSING, NN, _an_, _COMMASPACE_, \
18
18
  _DEPRECATED_, _DOT_, _EQUALSPACED_, \
19
19
  _immutable_, _invalid_, _module_, \
20
20
  _N_A_, _NL_, _not_, _SPACE_, _UNDER_
21
21
  # from pygeodesy.named import callname # _MODS, avoid circular
22
22
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, \
23
- _FOR_DOCS, _WARNINGS_X_DEV, _tailof
23
+ _FOR_DOCS, _WARNINGS_X_DEV
24
24
  # from pygeodesy.streprs import Fmt # _MODS
25
25
 
26
26
  from functools import wraps as _wraps
27
27
 
28
28
  __all__ = _ALL_LAZY.props
29
- __version__ = '24.11.06'
29
+ __version__ = '25.04.14'
30
30
 
31
31
  _class_ = 'class'
32
32
  _DNL_ = _NL_ * 2 # PYCHOK used!
@@ -45,7 +45,7 @@ def _allPropertiesOf(Clas_or_inst, *Bases, **excls):
45
45
  S = Clas_or_inst, # just this Clas
46
46
  else: # class and super-classes of inst
47
47
  try:
48
- S = Clas_or_inst.__class__.__mro__[:-1] # not object
48
+ S = type(Clas_or_inst).__mro__[:-1] # not object
49
49
  except AttributeError:
50
50
  raise
51
51
  S = () # not an inst
@@ -162,7 +162,7 @@ class _PropertyBase(property):
162
162
  _xcallable(getter=method, fget=fget)
163
163
 
164
164
  self.method = method
165
- self.name = method.__name__
165
+ self.name = typename(method)
166
166
  d = doc or method.__doc__
167
167
  if _FOR_DOCS and d:
168
168
  self.__doc__ = d # PYCHOK no cover
@@ -173,8 +173,8 @@ class _PropertyBase(property):
173
173
  '''(INTERNAL) Return an C{AttributeError} instance.
174
174
  '''
175
175
  if farg:
176
- n = _DOT_(self.name, nameter.__name__)
177
- n = _SPACE_(n, farg.__name__)
176
+ n = _DOT_(self.name, typename(nameter))
177
+ n = _SPACE_(n, typename(farg))
178
178
  else:
179
179
  n = nameter
180
180
  e = _SPACE_(kind, _MODS.named.classname(self))
@@ -349,7 +349,7 @@ class property_RO(_PropertyBase):
349
349
  else:
350
350
  d = getattr(inst.__class__, uname, MISSING)
351
351
  # if d is MISSING: # XXX superfluous
352
- # for c in inst.__class__.__mro__[:-1]:
352
+ # for c in type(inst).__mro__[:-1]:
353
353
  # if uname in c.__dict__:
354
354
  # d = c.__dict__[uname]
355
355
  # break
@@ -409,7 +409,7 @@ class property_ROver(_property_RO___):
409
409
  setattr(c, n, v) # overwrite property_ROver
410
410
  break
411
411
  else:
412
- n = _DOT_(C.__name__, n)
412
+ n = _DOT_(typename(C), n)
413
413
  raise _AssertionError(_EQUALSPACED_(n, v))
414
414
  return v
415
415
 
@@ -421,7 +421,7 @@ class _NamedProperty(property): # in .named
421
421
  def name(self):
422
422
  '''Get the name of this C{property} (C{str}).
423
423
  '''
424
- return self.fget.__name__
424
+ return typename(self.fget)
425
425
 
426
426
 
427
427
  def property_doc_(doc):
@@ -460,16 +460,16 @@ def _deprecated(call, kind, qual_d):
460
460
  @see: Brett Slatkin, "Effective Python", 2019 page 105, 2nd
461
461
  ed, Addison-Wesley.
462
462
  '''
463
- doc = _docof(call)
463
+ doc = _DOCof(call)
464
464
 
465
465
  @_wraps(call) # PYCHOK self?
466
466
  def _deprecated_call(*args, **kwds):
467
467
  if qual_d: # function
468
- q = qual_d
468
+ q = qual_d
469
469
  elif args: # method
470
- q = _qualified(args[0], call.__name__)
470
+ q = _qualified(args[0], typename(call))
471
471
  else: # PYCHOK no cover
472
- q = call.__name__
472
+ q = typename(call)
473
473
  _throwarning(kind, q, doc)
474
474
  return call(*args, **kwds)
475
475
 
@@ -484,8 +484,8 @@ def deprecated_class(cls_or_class):
484
484
  @note: NOT a decorator!
485
485
  '''
486
486
  if _WARNINGS_X_DEV:
487
- q = _DOT_(cls_or_class.__module__, cls_or_class.__name__)
488
- _throwarning(_class_, q, cls_or_class.__doc__)
487
+ q = _DOT_(cls_or_class.__module__, typename(cls_or_class))
488
+ _throwarning(_class_, q, cls_or_class.__doc__) # _DDOC_
489
489
 
490
490
 
491
491
  def deprecated_function(call):
@@ -496,7 +496,7 @@ def deprecated_function(call):
496
496
  @return: The B{C{call}} DEPRECATED.
497
497
  '''
498
498
  return _deprecated(call, _function_, _DOT_(
499
- call.__module__, call.__name__)) if \
499
+ call.__module__, typename(call))) if \
500
500
  _WARNINGS_X_DEV else call
501
501
 
502
502
 
@@ -524,13 +524,13 @@ if _WARNINGS_X_DEV:
524
524
  def __init__(self, method):
525
525
  '''Decorator for a DEPRECATED C{property} or C{Property} getter.
526
526
  '''
527
- doc = _docof(method)
527
+ doc = _DOCof(method)
528
528
 
529
529
  def _fget(inst): # PYCHOK no cover
530
530
  '''Get the C{property} or C{Property} value.
531
531
  '''
532
532
  q = _qualified(inst, self.name)
533
- _throwarning(property.__name__, q, doc)
533
+ _throwarning(typename(property), q, doc)
534
534
  return self.method(inst) # == method
535
535
 
536
536
  _PropertyBase.__init__(self, method, _fget, None, doc=doc)
@@ -554,7 +554,7 @@ if _WARNINGS_X_DEV:
554
554
  '''Set the C{property} or C{Property} value.
555
555
  '''
556
556
  q = _qualified(inst, self.name)
557
- _throwarning(property.__name__, q, _docof(method))
557
+ _throwarning(typename(property), q, _DOCof(method))
558
558
  method(inst, val)
559
559
  # self._update(inst) # un-cache this item
560
560
 
@@ -594,7 +594,7 @@ def deprecated_property_RO(method):
594
594
  def _deprecated_RO(method, _RO):
595
595
  '''(INTERNAL) Create a DEPRECATED C{property_RO} or C{Property_RO}.
596
596
  '''
597
- doc = _docof(method)
597
+ doc = _DOCof(method)
598
598
 
599
599
  if _WARNINGS_X_DEV:
600
600
 
@@ -606,7 +606,7 @@ def _deprecated_RO(method, _RO):
606
606
 
607
607
  def _fget(self, inst): # PYCHOK no cover
608
608
  q = _qualified(inst, self.name)
609
- _throwarning(_RO.__name__, q, doc)
609
+ _throwarning(typename(_RO), q, doc)
610
610
  return self.method(inst)
611
611
 
612
612
  return _Deprecated_RO(method)
@@ -614,7 +614,7 @@ def _deprecated_RO(method, _RO):
614
614
  return _RO(method, doc=doc)
615
615
 
616
616
 
617
- def _docof(obj):
617
+ def _DOCof(obj):
618
618
  '''(INTERNAL) Get uniform DEPRECATED __doc__ string.
619
619
  '''
620
620
  try:
@@ -629,8 +629,8 @@ def _qualified(inst, name):
629
629
  '''(INTERNAL) Fully qualify a name.
630
630
  '''
631
631
  # _DOT_(inst.classname, name), not _DOT_(inst.named4, name)
632
- c = inst.__class__
633
- q = _DOT_(c.__module__, c.__name__, name)
632
+ t = type(inst)
633
+ q = _DOT_(t.__module__, typename(t), name) # _DMODULE_
634
634
  return q
635
635
 
636
636
 
pygeodesy/resections.py CHANGED
@@ -12,17 +12,17 @@ L{triAngle}, L{triAngle5}, L{triSide}, L{triSide2} and L{triSide4}.
12
12
  # make sure int/int division yields float quotient
13
13
  from __future__ import division as _; del _ # PYCHOK semicolon
14
14
 
15
- from pygeodesy.basics import map1, map2, _zip, _ALL_LAZY
15
+ from pygeodesy.basics import map1, map2, _zip, _ALL_LAZY, typename
16
16
  from pygeodesy.constants import EPS, EPS0, EPS02, INT0, PI, PI2, PI_2, PI_4, \
17
17
  _0_0, _0_5, _1_0, _N_1_0, _2_0, _N_2_0, _4_0, \
18
18
  _16_0, _180_0, _360_0, isnear0, _over, _umod_360
19
19
  from pygeodesy.errors import _and, _or, TriangleError, _ValueError, _xcallable, \
20
20
  _xkwds, _xkwds_pop2
21
- from pygeodesy.fmath import favg, Fdot, fidw, fmean, hypot, hypot2_
21
+ from pygeodesy.fmath import favg, Fdot, Fdot_, fidw, _fma, fmean, hypot, hypot2_
22
22
  from pygeodesy.fsums import _Fsumf_, fsumf_, fsum1, fsum1f_
23
+ # from pygeodesy.internals import typename # from .basics
23
24
  from pygeodesy.interns import _a_, _A_, _area_, _b_, _B_, _c_, _C_, _coincident_, \
24
- _colinear_, _d_, _invalid_, _negative_, _not_, \
25
- _rIn_, _SPACE_
25
+ _colinear_, _d_, _invalid_, _negative_, _rIn_, _SPACE_
26
26
  # from pygeodesy.lazily import _ALL_LAZY # from .basics
27
27
  from pygeodesy.named import _NamedTuple, _Pass, Fmt
28
28
  # from pygeodesy.streprs import Fmt # from .named
@@ -34,7 +34,7 @@ from pygeodesy.vector3d import _otherV3d, Vector3d
34
34
  from math import cos, degrees, fabs, radians, sin, sqrt
35
35
 
36
36
  __all__ = _ALL_LAZY.resections
37
- __version__ = '24.11.27'
37
+ __version__ = '25.05.04'
38
38
 
39
39
  _concyclic_ = 'concyclic'
40
40
  _PA_ = 'PA'
@@ -42,7 +42,6 @@ _PB_ = 'PB'
42
42
  _PC_ = 'PC'
43
43
  _pointH_ = 'pointH'
44
44
  _pointP_ = 'pointP'
45
- _positive_ = 'positive'
46
45
  _radA_ = 'radA'
47
46
  _radB_ = 'radB'
48
47
  _radC_ = 'radC'
@@ -169,11 +168,9 @@ def cassini(pointA, pointB, pointC, alpha, beta, useZ=False, **Clas_and_kwds):
169
168
 
170
169
  A, B, C = _ABC3(useZ, pointA, pointB, pointC)
171
170
  try:
172
- sa, sb = map1(float, alpha, beta)
173
- if min(sa, sb) < 0:
174
- raise ValueError(_negative_)
171
+ sa, sb = _noneg(alpha, beta)
175
172
  if fsumf_(_360_0, -sa, -sb) < EPS0:
176
- raise ValueError()
173
+ raise ValueError(_colinear_)
177
174
 
178
175
  x1, y1 = _H(A, C, sa)
179
176
  x2, y2 = _H(B, C, -sb)
@@ -204,7 +201,7 @@ def _Clas(which, point, Clas_and_kwds, *args):
204
201
  '''(INTERNAL) Return a C{B{Clas}=point.classof} survey point.
205
202
  '''
206
203
  Clas, kwds = _xkwds_pop2(Clas_and_kwds, Clas=point.classof)
207
- return Clas(*args, **_xkwds(kwds, name=which.__name__))
204
+ return Clas(*args, **_xkwds(kwds, name=typename(which)))
208
205
 
209
206
 
210
207
  def collins5(pointA, pointB, pointC, alpha, beta, useZ=False, **Clas_and_kwds):
@@ -252,15 +249,15 @@ def collins5(pointA, pointB, pointC, alpha, beta, useZ=False, **Clas_and_kwds):
252
249
 
253
250
  def _xyz(d, r, A, B, C, useZ):
254
251
  s, c = sincos2(r)
255
- x = d * s + A.x # fma(d, s, A.x)
256
- y = d * c + A.y # fma(d, c, A.y)
252
+ x = _fma(d, s, A.x)
253
+ y = _fma(d, c, A.y)
257
254
  z = _zidw(x, y, useZ, A, B, C)
258
255
  return x, y, z
259
256
 
260
257
  A, B, C = _ABC3(useZ, pointA, pointB, pointC)
261
258
  try:
262
- ra, rb = radians(alpha), radians(beta)
263
- if min(ra, rb) < 0:
259
+ ra, rb = t = radians(alpha), radians(beta)
260
+ if min(t) < 0:
264
261
  raise ValueError(_negative_)
265
262
 
266
263
  sra, srH = sin(ra), sin(ra + rb - PI) # rH = PI - ((PI - ra) + (PI - rb))
@@ -286,13 +283,22 @@ def collins5(pointA, pointB, pointC, alpha, beta, useZ=False, **Clas_and_kwds):
286
283
  P = _Clas(collins5, pointA, Clas_and_kwds, *P)
287
284
  H = _Clas(collins5, pointA, Clas_and_kwds, *H)
288
285
  a = B.minus(C).length
289
- return Collins5Tuple(P, H, a, b, c, name=collins5.__name__)
286
+ return Collins5Tuple(P, H, a, b, c, name=typename(collins5))
290
287
 
291
288
  except (TypeError, ValueError) as x:
292
289
  raise ResectionError(pointA=pointA, pointB=pointB, pointC=pointC,
293
290
  alpha=alpha, beta=beta, cause=x)
294
291
 
295
292
 
293
+ def _noneg(*xs):
294
+ '''(INTERNAL) Return non-negative C{float}s.
295
+ '''
296
+ xs = tuple(map(float, xs))
297
+ if min(xs) < 0:
298
+ raise ValueError(_negative_)
299
+ return xs
300
+
301
+
296
302
  def pierlot(point1, point2, point3, alpha12, alpha23, useZ=False, eps=EPS,
297
303
  **Clas_and_kwds):
298
304
  '''3-Point resection using U{Pierlot<http://www.Telecom.ULg.ac.BE/publi/publications/
@@ -341,7 +347,7 @@ def pierlot(point1, point2, point3, alpha12, alpha23, useZ=False, eps=EPS,
341
347
  if eps > 0:
342
348
  return c / (min(s, -eps) if s < 0 else max(s, eps))
343
349
  t = Fmt.PARENSPACED(eps=eps)
344
- raise ValueError(_SPACE_(t, _not_, _positive_))
350
+ raise ValueError(_SPACE_(t, _invalid_))
345
351
 
346
352
  B1, B2, B3 = _B3(useZ, point1, point2, point3)
347
353
  try:
@@ -399,8 +405,8 @@ def _pierlot3(B1, B2, B3, a12, a23, useZ, _cot):
399
405
  # = (x31 - x23) * (y12 - y23) - (x12 - x23) * (y31 - y23)
400
406
  # x = (d * B2.x + K * Y12_23).fover(d)
401
407
  # y = (d * B2.y - K * X12_23).fover(d)
402
- x, y = _pierlotxy2(B2, -K, Y12_23, X12_23, (X31_23 * Y12_23 -
403
- X12_23 * Y31_23))
408
+ x, y = _pierlotxy2(B2, -K, Y12_23, X12_23, Fdot_(X31_23, Y12_23,
409
+ -X12_23, Y31_23))
404
410
  else:
405
411
  x, y, _ = B2.xyz3
406
412
  return x, y, _zidw(x, y, useZ, B1, B2, B3)
@@ -491,11 +497,11 @@ def _pierlotx3(a_z_Bs, useZ, _cot, Cs):
491
497
  if K:
492
498
  cot23 = _cot(*sincos2d(a23))
493
499
 
494
- # x23 = x2_ + cot23 * y2_
495
- # y23 = y2_ - cot23 * x2_
500
+ # x23 = x2_ + cot23 * y2_ # _fma( cot23, y2_, x2_)
501
+ # y23 = y2_ - cot23 * x2_ # _fma(-cot23, x2_, y2_)
496
502
 
497
- # x31 = x1_ + cot23 * y1_
498
- # y31 = y1_ - cot23 * x1_
503
+ # x31 = x1_ + cot23 * y1_ # _fma( cot23, y1_, x1_)
504
+ # y31 = y1_ - cot23 * x1_ # _fma(-cot23, x1_, y1_)
499
505
 
500
506
  # x31 - x23 = x1_ + cot23 * y1_ - x2_ - cot23 * y2_
501
507
  X31_23 = _Fsumf_(x1_, cot23 * y1_, -x2_, -cot23 * y2_)
@@ -503,10 +509,10 @@ def _pierlotx3(a_z_Bs, useZ, _cot, Cs):
503
509
  Y31_23 = _Fsumf_(y1_, -cot23 * x1_, -y2_, cot23 * x2_)
504
510
 
505
511
  # d = (x31 - x23) * (x2_ - x1_) + (y31 - y23) * (y2_ - y1_)
506
- # x = (D * B3.x - K * Y31_23).fover(d)
507
- # y = (D * B3.y + K * X31_23).fover(d)
508
- x, y = _pierlotxy2(B3, K, Y31_23, X31_23, (X31_23 * _Fsumf_(x2_, -x1_) +
509
- Y31_23 * _Fsumf_(y2_, -y1_)))
512
+ # x = (d * B3.x - K * Y31_23).fover(d)
513
+ # y = (d * B3.y + K * X31_23).fover(d)
514
+ x, y = _pierlotxy2(B3, K, Y31_23, X31_23, Fdot_(X31_23, _Fsumf_(x2_, -x1_),
515
+ Y31_23, _Fsumf_(y2_, -y1_)))
510
516
  else:
511
517
  x, y, _ = B3.xyz3
512
518
  return x, y, _zidw(x, y, useZ, B1, B2, B3)
@@ -518,8 +524,8 @@ def _pierlotxy2(B, K, X, Y, D):
518
524
  d = float(D)
519
525
  if isnear0(d):
520
526
  raise ValueError(_or(_coincident_, _colinear_, _concyclic_))
521
- x = (D * B.x - K * X).fover(d)
522
- y = (D * B.y + K * Y).fover(d)
527
+ x = Fdot_(D, B.x, -K, X).fover(d)
528
+ y = Fdot_(D, B.y, K, Y).fover(d)
523
529
  return x, y
524
530
 
525
531
 
@@ -550,9 +556,7 @@ def snellius3(a, b, degC, alpha, beta):
550
556
  @see: Function L{wildberger3}.
551
557
  '''
552
558
  try:
553
- a, b, degC, alpha, beta = t = map1(float, a, b, degC, alpha, beta)
554
- if min(t) < 0:
555
- raise ValueError(_negative_)
559
+ a, b, degC, alpha, beta = _noneg(a, b, degC, alpha, beta)
556
560
  ra, rb, rC = map1(radians, alpha, beta, degC)
557
561
 
558
562
  r = fsum1f_(ra, rb, rC) * _0_5
@@ -576,7 +580,7 @@ def snellius3(a, b, degC, alpha, beta):
576
580
 
577
581
  pa = _triSide(b, pc, fsumf_(PI, -ra, -pa))
578
582
  pb = _triSide(a, pc, fsumf_(PI, -rb, -pb))
579
- return Survey3Tuple(pa, pb, pc, name=snellius3.__name__)
583
+ return Survey3Tuple(pa, pb, pc, name=typename(snellius3))
580
584
 
581
585
  except (TypeError, ValueError) as x:
582
586
  raise TriangleError(a=a, b=b, degC=degC, alpha=alpha, beta=beta, cause=x)
@@ -672,7 +676,7 @@ def tienstra7(pointA, pointB, pointC, alpha, beta=None, gamma=None,
672
676
  z = _zidw(x, y, useZ, A, B, C)
673
677
 
674
678
  P = _Clas(tienstra7, pointA, Clas_and_kwds, x, y, z)
675
- return Tienstra7Tuple(P, dA, dB, dC, a, b, c, name=tienstra7.__name__)
679
+ return Tienstra7Tuple(P, dA, dB, dC, a, b, c, name=typename(tienstra7))
676
680
 
677
681
  except (TypeError, ValueError) as x:
678
682
  raise ResectionError(pointA=pointA, pointB=pointB, pointC=pointC,
@@ -704,17 +708,15 @@ def triAngle(a, b, c):
704
708
 
705
709
  def _triAngle(a, b, c):
706
710
  # (INTERNAL) To allow callers to embellish errors
707
- a, b, c = map1(float, a, b, c)
708
- if a < b:
711
+ a, b, c = _noneg(a, b, c)
712
+ if b > a:
709
713
  a, b = b, a
710
- if b < 0 or c < 0:
711
- raise ValueError(_negative_)
712
714
  if a < EPS0:
713
715
  raise ValueError(_coincident_)
714
716
  b_a = b / a
715
717
  if b_a < EPS0:
716
718
  raise ValueError(_coincident_)
717
- t = fsumf_(_1_0, b_a**2, -(c / a)**2) / (b_a * _2_0)
719
+ t = _Fsumf_(_1_0, b_a**2, -(c / a)**2).fover(b_a * _2_0)
718
720
  return acos1(t)
719
721
 
720
722
 
@@ -732,7 +734,7 @@ def triAngle5(a, b, c):
732
734
  C{radA}, C{radB} and C{radC} at triangle corners C{A}, C{B}
733
735
  and C{C}, all in C{radians}, the C{InCircle} radius C{rIn}
734
736
  aka C{inradius}, same units as triangle sides B{C{a}},
735
- B{C{b}} and B{C{c}} and the triangle C{area} in those same
737
+ B{C{b}} and B{C{c}} and the triangle C{area} in the same
736
738
  units I{squared}.
737
739
 
738
740
  @raise TriangleError: Invalid or negative B{C{a}}, B{C{b}} or B{C{c}}.
@@ -771,7 +773,7 @@ def triAngle5(a, b, c):
771
773
  rB, rC = rC, rB
772
774
  if ab:
773
775
  rA, rB = rB, rA
774
- return TriAngle5Tuple(rA, rB, rC, r, s, name=triAngle5.__name__)
776
+ return TriAngle5Tuple(rA, rB, rC, r, s, name=typename(triAngle5))
775
777
 
776
778
  except (TypeError, ValueError) as x:
777
779
  raise TriangleError(a=a, b=b, c=c, cause=x)
@@ -796,15 +798,15 @@ def triArea(a, b, c):
796
798
  try:
797
799
  r, y, x = sorted(map1(float, a, b, c))
798
800
  if r > 0: # r = min(a, b, c)
799
- ab = x - y
800
- bc = y - r
801
- y += r
802
- r = (x + y) * (r - ab) * (r + ab) * (x + bc)
801
+ z = r
802
+ d = x - y
803
+ r = (z + d) * (z - d)
803
804
  if r:
804
- r = sqrt(r / _16_0)
805
- elif r < 0:
805
+ x += y
806
+ r *= (x + z) * (x - z)
807
+ if r < 0:
806
808
  raise ValueError(_negative_)
807
- return r
809
+ return sqrt(r / _16_0) if r else _0_0
808
810
 
809
811
  except (TypeError, ValueError) as x:
810
812
  raise TriangleError(a=a, b=b, c=c, cause=x)
@@ -836,11 +838,8 @@ def triSide(a, b, radC):
836
838
 
837
839
  def _triSide(a, b, radC):
838
840
  # (INTERNAL) To allow callers to embellish errors
839
- a, b, r = t = map1(float, a, b, radC)
840
- if min(t) < 0:
841
- raise ValueError(_negative_)
842
-
843
- if a < b:
841
+ a, b, r = _noneg(a, b, radC)
842
+ if b < a:
844
843
  a, b = b, a
845
844
  if a > EPS0:
846
845
  ba = b / a
@@ -879,20 +878,23 @@ def triSide2(b, c, radB):
879
878
 
880
879
  def _triSide2(b, c, radB):
881
880
  # (INTERNAL) To allow callers to embellish errors
882
- b, c, rB = map1(float, b, c, radB)
883
- if min(b, c, rB) < 0:
884
- raise ValueError(_negative_)
881
+ b, c, rB = _noneg(b, c, radB)
885
882
  sB, cB = sincos2(rB)
886
- if isnear0(sB):
887
- if not isnear0(b):
883
+ if isnear0(b) or isnear0(sB):
884
+ if isnear0(b) and isnear0(sB):
885
+ if cB < 0:
886
+ rA = PI
887
+ a = b + c
888
+ else:
889
+ rA = _0_0
890
+ a = fabs(b - c)
891
+ else:
888
892
  raise ValueError(_invalid_)
889
- a, rA = ((b + c), PI) if cB < 0 else (fabs(b - c), _0_0)
890
- elif isnear0(b):
891
- raise ValueError(_invalid_)
892
893
  else:
893
- rA = fsumf_(PI, -rB, -asin1(c * sB / b))
894
+ rC = asin1(c * sB / b)
895
+ rA = max(fsumf_(PI, -rB, -rC), _0_0)
894
896
  a = sin(rA) * b / sB
895
- return TriSide2Tuple(a, rA, name=triSide2.__name__)
897
+ return TriSide2Tuple(a, rA, name=typename(triSide2))
896
898
 
897
899
 
898
900
  def triSide4(radA, radB, c):
@@ -917,9 +919,9 @@ def triSide4(radA, radB, c):
917
919
  and functions L{sqrt_a}, L{triSide} and L{triSide2}.
918
920
  '''
919
921
  try:
920
- rA, rB, c = map1(float, radA, radB, c)
922
+ rA, rB, c = _noneg(radA, radB, c)
921
923
  rC = fsumf_(PI, -rA, -rB)
922
- if min(rC, rA, rB, c) < 0:
924
+ if rC < 0:
923
925
  raise ValueError(_negative_)
924
926
  sa, ca, sb, cb = sincos2_(rA, rB)
925
927
  sc = fsum1f_(sa * cb, sb * ca)
@@ -927,7 +929,7 @@ def triSide4(radA, radB, c):
927
929
  raise ValueError(_invalid_)
928
930
  sc = c / sc
929
931
  return TriSide4Tuple((sa * sc), (sb * sc), rC, (sa * sb * sc),
930
- name=triSide4.__name__)
932
+ name=typename(triSide4))
931
933
 
932
934
  except (TypeError, ValueError) as x:
933
935
  raise TriangleError(radA=radA, radB=radB, c=c, cause=x)
@@ -964,18 +966,18 @@ def wildberger3(a, b, c, alpha, beta, R3=min):
964
966
  return sin(x)**2
965
967
 
966
968
  def _vpa(r3, q2, q3, s2, s3):
967
- r1 = s2 * q3 / s3
968
- r = r1 * r3 * _4_0
969
- n = (r - _Fsumf_(r1, r3, -q2)**2).fover(s3)
969
+ r1 = s2 * q3 / s3
970
+ r = r1 * r3 * _4_0
971
+ R = _Fsumf_(r1, r3, -q2)
972
+ R *= R # -(R**2 ...
973
+ R -= r # ... - r) / s3
974
+ n = -R.fover(s3)
970
975
  if n < 0 or r < EPS0:
971
976
  raise ValueError(_coincident_)
972
977
  return sqrt((n / r) * q3) if n else _0_0
973
978
 
974
979
  try:
975
- a, b, c, da, db = q = map1(float, a, b, c, alpha, beta)
976
- if min(q) < 0:
977
- raise ValueError(_negative_)
978
-
980
+ a, b, c, da, db = _noneg(a, b, c, alpha, beta)
979
981
  q1, q2, q3 = q = a**2, b**2, c**2
980
982
  if min(q) < EPS02:
981
983
  raise ValueError(_coincident_)
@@ -985,24 +987,25 @@ def wildberger3(a, b, c, alpha, beta, R3=min):
985
987
  if min(s) < EPS02:
986
988
  raise ValueError(_or(_coincident_, _colinear_))
987
989
 
988
- q4 = hypot2_(*q) * _2_0 # a**4 + ...
989
- Qs = _Fsumf_(*q) # == hypot2_(a, b, c)
990
- d0 = (Qs**2 - q4).fmul(s1 * s2).fover(s3)
991
- if d0 < 0:
992
- raise ValueError(_negative_)
990
+ Q = _Fsumf_(*q) # == a**2 + b**2 + ...
993
991
  s += _Fsumf_(*s), # == fsum1(s),
994
- C0 = Fdot(s, q1, q2, q3, -Qs * _0_5)
992
+ C0 = Fdot(s, q1, q2, q3, -Q * _0_5)
995
993
  r3 = C0.fover(-s3) # C0 /= -s3
994
+ Q *= Q # Q**2 - 2 * (a**4 + b**4 ...
995
+ Q -= hypot2_(*q) *_2_0 # ... + c**4)
996
+ d0 = Q.fmul(s1 * s2).fover(s3)
996
997
  if d0 > EPS02: # > c0
997
998
  _xcallable(R3=R3)
998
999
  d0 = sqrt(d0)
999
1000
  r3 = R3(float(C0 + d0), float(C0 - d0)) # XXX min or max
1001
+ elif d0 < (-EPS02):
1002
+ raise ValueError(_negative_)
1000
1003
 
1001
1004
  pa = _vpa(r3, q2, q3, s2, s3)
1002
1005
  pb = _vpa(r3, q1, q3, s1, s3)
1003
1006
  pc = favg(_triSide2(b, pa, ra).a,
1004
1007
  _triSide2(a, pb, rb).a)
1005
- return Survey3Tuple(pa, pb, pc, name=wildberger3.__name__)
1008
+ return Survey3Tuple(pa, pb, pc, name=typename(wildberger3))
1006
1009
 
1007
1010
  except (TypeError, ValueError) as x:
1008
1011
  raise TriangleError(a=a, b=b, c=c, alpha=alpha, beta=beta, R3=R3, cause=x)
@@ -9,7 +9,7 @@ u'''Package of lazily imported C{rhumb} modules L{rhumb.aux_}, L{rhumb.ekx} and
9
9
  from pygeodesy.lazily import _ALL_LAZY, _ALL_OTHER, _lazy_import_as, _unLazy0
10
10
 
11
11
  __all__ = _ALL_LAZY.rhumb
12
- __version__ = '25.01.15'
12
+ __version__ = '25.04.14'
13
13
 
14
14
  if _unLazy0: # or _isfrozen
15
15
  from pygeodesy.rhumb.aux_ import RhumbAux, RhumbLineAux
pygeodesy/rhumb/aux_.py CHANGED
@@ -48,7 +48,7 @@ from pygeodesy.rhumb.bases import RhumbBase, RhumbLineBase, \
48
48
  from math import ceil as _ceil, fabs, radians
49
49
 
50
50
  __all__ = _ALL_LAZY.rhumb_aux_
51
- __version__ = '25.01.15'
51
+ __version__ = '25.04.12'
52
52
 
53
53
  # DIGITS = (sizeof(real) * 8) bits
54
54
  # = (ctypes.sizeof(ctypes.c_double(1.0)) * 8) bits
@@ -216,11 +216,11 @@ class RhumbLineAux(RhumbLineBase):
216
216
  @kwarg lat1: Latitude of the start point (C{degrees90}).
217
217
  @kwarg lon1: Longitude of the start point (C{degrees180}).
218
218
  @kwarg azi12: Azimuth of this rhumb line (compass C{degrees}).
219
- @kwarg caps_name: Optional keyword arguments C{B{name}=NN} and
220
- C{B{caps}=0}, a bit-or'ed combination of L{Caps}
221
- values specifying the required capabilities. Include
222
- C{Caps.LINE_OFF} if updates to the B{C{rhumb}} should
223
- I{not} be reflected in this rhumb line.
219
+ @kwarg caps_name: Optional keyword arguments C{B{name}=NN} and C{B{caps}=0},
220
+ a bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
221
+ specifying the required capabilities. Include C{Caps.LINE_OFF}
222
+ if updates to the B{C{rhumb}} should I{not be reflected} in this
223
+ rhumb line.
224
224
  '''
225
225
  RhumbLineBase.__init__(self, rhumb, lat1, lon1, azi12, **caps_name)
226
226
 
@@ -296,7 +296,7 @@ def _RAintegrate(auxD):
296
296
  def _RAseries(auxD):
297
297
  # Series expansions in n for Fourier coeffients of the integral
298
298
  # @see: U{"Series expansions for computing rhumb areas"
299
- # <https:#DOI.org/10.5281/zenodo.7685484>}.
299
+ # <https://DOI.org/10.5281/zenodo.7685484>}.
300
300
  d = n = auxD._n
301
301
  i = 0
302
302
  aL = auxD.ALorder