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/elliptic.py CHANGED
@@ -75,7 +75,7 @@ U{22<https://DLMF.NIST.gov/22>}.
75
75
  # make sure int/int division yields float quotient, see .basics
76
76
  from __future__ import division as _; del _ # PYCHOK semicolon
77
77
 
78
- from pygeodesy.basics import copysign0, map2, neg, neg_
78
+ from pygeodesy.basics import copysign0, map2, neg, neg_, typename
79
79
  from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, _0_0, \
80
80
  _0_25, _0_5, _1_0, _2_0, _N_2_0, _3_0, \
81
81
  _4_0, _6_0, _8_0, _64_0, _180_0, _360_0, \
@@ -84,9 +84,9 @@ from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, _0_0, \
84
84
  # from pygeodesy.errors import _ValueError # from .fmath
85
85
  from pygeodesy.fmath import favg, hypot1, zqrt, _ValueError
86
86
  from pygeodesy.fsums import Fsum, _sum
87
- from pygeodesy.internals import _DUNDER_nameof
88
- from pygeodesy.interns import NN, _delta_, _DOT_, _f_, _invalid_, \
89
- _invokation_, _negative_, _SPACE_
87
+ # from pygeodesy.internals import typename # from .basics
88
+ from pygeodesy.interns import NN, _delta_, _DOT_, _f_, _invalid_, _invokation_, \
89
+ _negative_, _SPACE_
90
90
  from pygeodesy.karney import _K_2_0, _norm180, _signBit, _sincos2
91
91
  # from pygeodesy.lazily import _ALL_LAZY # from .named
92
92
  from pygeodesy.named import _Named, _NamedTuple, _ALL_LAZY, Fmt, unstr
@@ -99,7 +99,7 @@ from math import asin, asinh, atan, ceil, cosh, fabs, floor, radians, \
99
99
  sin, sinh, sqrt, tan, tanh # tan as _tan
100
100
 
101
101
  __all__ = _ALL_LAZY.elliptic
102
- __version__ = '24.11.26'
102
+ __version__ = '25.04.14'
103
103
 
104
104
  _TolRD = zqrt(EPS * 0.002)
105
105
  _TolRF = zqrt(EPS * 0.030)
@@ -678,7 +678,7 @@ class Elliptic(_Named):
678
678
  return (deltaX(sn, cn, dn) + phi) * cX / PI_2
679
679
  # fall through
680
680
  elif cn is None or dn is None:
681
- n = NN(_f_, deltaX.__name__[5:])
681
+ n = NN(_f_, typename(deltaX)[5:])
682
682
  raise _ellipticError(n, sn, cn, dn)
683
683
 
684
684
  if _signBit(cn): # enforce usual trig-like symmetries
@@ -1063,7 +1063,7 @@ def _deltaX(sn, cn, dn, cX, fX):
1063
1063
  return r - atan2(sn, cn)
1064
1064
 
1065
1065
  except Exception as e:
1066
- n = NN(_delta_, fX.__name__[1:])
1066
+ n = NN(_delta_, typename(fX)[1:])
1067
1067
  raise _ellipticError(n, sn, cn, dn, cause=e)
1068
1068
 
1069
1069
 
@@ -1075,8 +1075,8 @@ def _ellipticError(where, *args, **kwds_cause_txt):
1075
1075
 
1076
1076
  x, t, kwds = _x_t_kwds(**kwds_cause_txt)
1077
1077
 
1078
- n = _DUNDER_nameof(where, where)
1079
- n = _DOT_(Elliptic.__name__, n)
1078
+ n = typename(where, where)
1079
+ n = _DOT_(typename(Elliptic), n)
1080
1080
  n = _SPACE_(_invokation_, n)
1081
1081
  u = unstr(n, *args, **kwds)
1082
1082
  return EllipticError(u, cause=x, txt=t)
pygeodesy/errors.py CHANGED
@@ -11,25 +11,26 @@ chaining}, use command line option C{python -X dev} I{OR} set env variable
11
11
  C{PYTHONDEVMODE=1} or to any non-empty string I{OR} set env variable
12
12
  C{PYGEODESY_EXCEPTION_CHAINING=std} or to any non-empty string.
13
13
  '''
14
- # from pygeodesy.basics import isint, isodd, issubclassof, itemsorted, _xinstanceof, _zip # _MODS
14
+ # from pygeodesy import basics as _basics # _MODS.into
15
15
  # from pygeodesy.ellipsoidalBase import CartesianEllipsoidalBase, LatLonEllipsoidalBase # _MODS
16
16
  # from pygeodesy import errors # _MODS, _MODS.getattr
17
- from pygeodesy.internals import _DUNDER_nameof_, _getPYGEODESY, _plural, _tailof
17
+ from pygeodesy.internals import _envPYGEODESY, _plural, _tailof, typename
18
18
  from pygeodesy.interns import MISSING, NN, _a_, _an_, _and_, _clip_, _COLON_, _COLONSPACE_, \
19
19
  _COMMASPACE_, _datum_, _ELLIPSIS_, _ellipsoidal_, _incompatible_, \
20
20
  _invalid_, _keyword_, _LatLon_, _len_, _not_, _or_, _SPACE_, \
21
21
  _specified_, _UNDER_, _vs_, _with_
22
22
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _PYTHON_X_DEV
23
- # from pygeodesy import streprs as _streprs # _MODS
23
+ # from pygeodesy import streprs as _streprs # _MODS.into
24
24
  # from pygeodesy.unitsBase import Str # _MODS
25
25
  # from pygeodesy.vector3dBase import Vector3dBase # _MODS
26
26
 
27
27
  from copy import copy as _copy
28
28
 
29
29
  __all__ = _ALL_LAZY.errors # _ALL_DOCS('_InvalidError', '_IsnotError') _under
30
- __version__ = '24.11.02'
30
+ __version__ = '25.04.21'
31
31
 
32
32
  _argument_ = 'argument'
33
+ _basics = _MODS.into(basics=__name__)
33
34
  _box_ = 'box'
34
35
  _expected_ = 'expected'
35
36
  _limiterrors = True # in .formy
@@ -43,7 +44,7 @@ try:
43
44
  _exception_chaining = None # not available
44
45
  _ = Exception().__cause__ # Python 3.9+ exception chaining
45
46
 
46
- if _PYTHON_X_DEV or _getPYGEODESY('EXCEPTION_CHAINING'): # == _std_
47
+ if _PYTHON_X_DEV or _envPYGEODESY('EXCEPTION_CHAINING'): # == _std_
47
48
  _exception_chaining = True # turned on, std
48
49
  raise AttributeError() # allow exception chaining
49
50
 
@@ -143,8 +144,8 @@ def _TypesError(name, value, *Types, **kwds):
143
144
  '''
144
145
  # no longer C{class _TypesError} to avoid missing value
145
146
  # argument errors in _XError line ...E = Error(str(e))
146
- t = _not_(_an(_or(*(t.__name__ for t in Types))))
147
- return _TypeError(name, value, txt=t, **kwds)
147
+ t = _an(_or(*map(typename, Types, Types)))
148
+ return _TypeError(name, value, txt=_not_(t), **kwds)
148
149
 
149
150
 
150
151
  class _UnexpectedError(TypeError): # note, a TypeError!
@@ -240,12 +241,12 @@ class LenError(_ValueError): # in .ecef, .fmath, .heights, .iters, .named
240
241
  (C{keyword arguments}).
241
242
  '''
242
243
  def _ns_vs_txt_x(cause=None, txt=_invalid_, **kwds):
243
- ns, vs = zip(*_MODS.basics.itemsorted(kwds)) # unzip
244
+ ns, vs = zip(*_basics.itemsorted(kwds)) # unzip
244
245
  return ns, vs, txt, cause
245
246
 
246
247
  ns, vs, txt, x = _ns_vs_txt_x(**lens_txt)
247
248
  ns = _COMMASPACE_.join(ns)
248
- t = _streprs.Fmt.PAREN(where.__name__, ns)
249
+ t = _streprs.Fmt.PAREN(typename(where), ns)
249
250
  vs = _vs__.join(map(str, vs))
250
251
  t = _SPACE_(t, _len_, vs)
251
252
  _ValueError.__init__(self, t, txt=txt, cause=x)
@@ -379,8 +380,8 @@ def _and_or(last, *words):
379
380
  def crosserrors(raiser=None):
380
381
  '''Report or ignore vectorial cross product errors.
381
382
 
382
- @kwarg raiser: Use C{True} to throw or C{False} to ignore
383
- L{CrossError} exceptions. Use C{None} to
383
+ @kwarg raiser: Use C{True} to throw, C{False} to ignore
384
+ L{CrossError} exceptions or C{None} to
384
385
  leave the setting unchanged.
385
386
 
386
387
  @return: Previous setting (C{bool}).
@@ -389,8 +390,8 @@ def crosserrors(raiser=None):
389
390
  '''
390
391
  V = _MODS.vector3dBase.Vector3dBase
391
392
  t = V._crosserrors # XXX class attr!
392
- if raiser in (True, False):
393
- V._crosserrors = raiser
393
+ if raiser is not None:
394
+ V._crosserrors = bool(raiser)
394
395
  return t
395
396
 
396
397
 
@@ -419,7 +420,7 @@ def _error_init(Error, inst, args, fmt_name_value='%s (%r)', txt_not_=NN,
419
420
  t, n = (), len(args)
420
421
  if n > 2:
421
422
  t = _fmtuple(zip(args[0::2], args[1::2]))
422
- s = _MODS.basics.isodd(n)
423
+ s = _basics.isodd(n)
423
424
  if s: # XXX _xzip(..., strict=s)
424
425
  t += args[-1:]
425
426
  elif n == 2:
@@ -427,11 +428,11 @@ def _error_init(Error, inst, args, fmt_name_value='%s (%r)', txt_not_=NN,
427
428
  elif n: # == 1
428
429
  t = str(args[0]),
429
430
  if kwds:
430
- t += _fmtuple(_MODS.basics.itemsorted(kwds))
431
+ t += _fmtuple(_basics.itemsorted(kwds))
431
432
  t = _or(*t) if t else _SPACE_(_name_value_, MISSING)
432
433
 
433
434
  x = _not_(txt_not_) if txt_not_ else (txt if txt__ is None
434
- else txt__.__name__)
435
+ else typename(txt__))
435
436
  if x is not None:
436
437
  x = str(x) or (str(cause) if cause else _invalid_)
437
438
  C = _COMMASPACE_ if _COLON_ in t else _COLONSPACE_
@@ -447,9 +448,10 @@ def _error_init(Error, inst, args, fmt_name_value='%s (%r)', txt_not_=NN,
447
448
  def _error_under(inst):
448
449
  '''(INTERNAL) Remove leading underscore from instance' class name.
449
450
  '''
450
- n = inst.__class__.__name__ # _tailof?
451
+ t = type(inst)
452
+ n = typename(t) # _tailof?
451
453
  if n.startswith(_UNDER_):
452
- inst.__class__.__name__ = n.lstrip(_UNDER_)
454
+ t.__name__ = n.lstrip(_UNDER_)
453
455
  return inst
454
456
 
455
457
 
@@ -469,7 +471,7 @@ def exception_chaining(exc=None):
469
471
  non-empty value prior to C{import pygeodesy}.
470
472
  '''
471
473
  return _exception_chaining if exc is None else \
472
- getattr(exc, '__cause__', None)
474
+ getattr(exc, '__cause__', None) # _DCAUSE_
473
475
 
474
476
 
475
477
  def _incompatible(this):
@@ -504,9 +506,9 @@ def isError(exc):
504
506
  def _X(exc):
505
507
  X = type(exc)
506
508
  m = X.__module__
507
- return _MODS.basics.issubclassof(X, *_XErrors) or \
509
+ return _basics.issubclassof(X, *_XErrors) or \
508
510
  ((m is __name__ or m == __name__) and
509
- _tailof(X.__name__).startswith(_UNDER_))
511
+ _tailof(typename(X)).startswith(_UNDER_))
510
512
 
511
513
  return True if isinstance(exc, _XErrors) else (
512
514
  _X(exc) if isinstance(exc, Exception) else None)
@@ -527,23 +529,23 @@ def _IsnotError(*types__, **name_value_Error_cause): # name=value [, Error=Type
527
529
  n, v = _xkwds_item2(kwds)
528
530
 
529
531
  n = _streprs.Fmt.PARENSPACED(n, repr(v))
530
- t = _not_(_an(_or(*_DUNDER_nameof_(*types__))) if types__ else _specified_)
531
- return _XError(E, n, txt=t, cause=x)
532
+ t = _an(_or(*map(typename, types__, types__))) if types__ else _specified_
533
+ return _XError(E, n, txt=_not_(t), cause=x)
532
534
 
533
535
 
534
536
  def limiterrors(raiser=None):
535
537
  '''Get/set the throwing of L{LimitError}s.
536
538
 
537
- @kwarg raiser: Choose C{True} to raise or C{False} to
538
- ignore L{LimitError} exceptions. Use
539
+ @kwarg raiser: Use C{True} to raise, C{False} to
540
+ ignore L{LimitError} exceptions or
539
541
  C{None} to leave the setting unchanged.
540
542
 
541
543
  @return: Previous setting (C{bool}).
542
544
  '''
543
545
  global _limiterrors
544
546
  t = _limiterrors
545
- if raiser in (True, False):
546
- _limiterrors = raiser
547
+ if raiser is not None:
548
+ _limiterrors = bool(raiser)
547
549
  return t
548
550
 
549
551
 
@@ -576,16 +578,16 @@ def _parseX(parser, *args, **Error_name_values): # name=value[, ..., Error=Pars
576
578
  def rangerrors(raiser=None):
577
579
  '''Get/set the throwing of L{RangeError}s.
578
580
 
579
- @kwarg raiser: Choose C{True} to raise or C{False} to ignore
580
- L{RangeError} exceptions. Use C{None} to leave
581
+ @kwarg raiser: Use C{True} to raise or C{False} to ignore
582
+ L{RangeError} exceptions or C{None} to leave
581
583
  the setting unchanged.
582
584
 
583
585
  @return: Previous setting (C{bool}).
584
586
  '''
585
587
  global _rangerrors
586
588
  t = _rangerrors
587
- if raiser in (True, False):
588
- _rangerrors = raiser
589
+ if raiser is not None:
590
+ _rangerrors = bool(raiser)
589
591
  return t
590
592
 
591
593
 
@@ -648,7 +650,7 @@ def _xcallable(**names_callables):
648
650
  '''
649
651
  for n, c in names_callables.items():
650
652
  if not callable(c):
651
- raise _TypeError(n, c, txt_not_=callable.__name__) # txt__
653
+ raise _TypeError(n, c, txt_not_=typename(callable)) # txt__
652
654
 
653
655
 
654
656
  def _xdatum(datum1, datum2, Error=None):
@@ -685,9 +687,8 @@ def _xellipsoidall(point): # ... elel, see _xellipsoidal
685
687
  m = _MODS.ellipsoidalBase
686
688
  ll = isinstance(point, m.LatLonEllipsoidalBase)
687
689
  if not ll:
688
- b = _MODS.basics
689
- b._xinstanceof(m.CartesianEllipsoidalBase,
690
- m.LatLonEllipsoidalBase, point=point)
690
+ _basics._xinstanceof(m.CartesianEllipsoidalBase,
691
+ m.LatLonEllipsoidalBase, point=point)
691
692
  return ll
692
693
 
693
694
 
@@ -734,7 +735,7 @@ def _xError2(exc): # in .constants, .fsums, .lazily, .vector2d
734
735
  elif x is None:
735
736
  E = _AssertionError
736
737
  else: # get _Error from Error
737
- n = NN(_UNDER_, _tailof(type(exc).__name__))
738
+ n = NN(_UNDER_, _tailof(typename(type(exc))))
738
739
  E = _MODS.getattr(__name__, n, _NotImplementedError)
739
740
  x = E is not _NotImplementedError
740
741
  return E, (str(exc) if x else repr(exc))
@@ -783,9 +784,9 @@ except AttributeError:
783
784
  # for n, v in kwds.items():
784
785
  # b = getattr(inst, n, None)
785
786
  # if b is None: # invalid bool attr
786
- # t = _SPACE_(_EQUAL_(n, repr(v)), 'for', inst.__class__.__name__) # XXX .classname
787
+ # t = _SPACE_(_EQUAL_(n, repr(v)), 'for', typename(type(inst)) # XXX .classname
787
788
  # raise _AttributeError(t, txt_not_='applicable')
788
- # if v in (False, True) and v != b:
789
+ # if _basics.isbool(v) and v != b:
789
790
  # setattr(inst, NN(_UNDER_, n), v)
790
791
 
791
792
 
@@ -819,7 +820,7 @@ def _xkwds_get(kwds, **name_default):
819
820
  # '''
820
821
  # if not isinstance(kwds, dict):
821
822
  # raise _xAssertionError(_xkwds_get_, kwds)
822
- # for n, v in _MODS.basics.itemsorted(names_defaults):
823
+ # for n, v in _basics.itemsorted(names_defaults):
823
824
  # yield kwds.get(n, v)
824
825
 
825
826
 
@@ -886,7 +887,7 @@ def _Xorder(_Coeffs, Error, **Xorder): # in .auxLat, .ktm, .rhumb.bases, .rhumb
886
887
  '''(INTERNAL) Validate C{RAorder} or C{TMorder}.
887
888
  '''
888
889
  X, m = _xkwds_item2(Xorder)
889
- if m in _Coeffs and _MODS.basics.isint(m):
890
+ if m in _Coeffs and _basics.isint(m):
890
891
  return m
891
892
  t = sorted(map(str, _Coeffs.keys()))
892
893
  raise Error(X, m, txt_not_=_or(*t))
@@ -908,9 +909,9 @@ def _xsError(X, xs, i, x, *n, **kwds): # in .fmath, ._fstats, .fsums
908
909
  def _xStrError(*Refs, **name_value_Error): # in .gars, .geohash, .wgrs
909
910
  '''(INTERNAL) Create a C{TypeError} for C{Garef}, C{Geohash}, C{Wgrs}.
910
911
  '''
911
- S = _MODS.unitsBase.Str
912
- r = tuple(r.__name__ for r in Refs) + (S.__name__, _LatLon_, 'LatLon*Tuple')
913
- return _IsnotError(*r, **name_value_Error)
912
+ s = typename(_MODS.unitsBase.Str)
913
+ t = tuple(map(typename, Refs)) + (s, _LatLon_, 'LatLon*Tuple')
914
+ return _IsnotError(*t, **name_value_Error)
914
915
 
915
916
  # **) MIT License
916
917
  #
pygeodesy/etm.py CHANGED
@@ -63,7 +63,7 @@ which maintains accuracy near C{phi = pi/2}. Such changes are noted in the code
63
63
  # make sure int/int division yields float quotient, see .basics
64
64
  from __future__ import division as _; del _ # PYCHOK semicolon
65
65
 
66
- from pygeodesy.basics import map1, neg, neg_, _xinstanceof
66
+ from pygeodesy.basics import _isin, map1, neg, neg_, _xinstanceof
67
67
  from pygeodesy.constants import EPS, EPS02, PI_2, PI_4, _K0_UTM, \
68
68
  _1_EPS, _0_0, _0_1, _0_5, _1_0, _2_0, \
69
69
  _3_0, _90_0, isnear0, isnear90
@@ -74,9 +74,9 @@ from pygeodesy.datums import _ellipsoidal_datum, _WGS84, _EWGS84
74
74
  # from pygeodesy.errors import _incompatible # from .named
75
75
  # from pygeodesy.fsums import Fsum # from .fmath
76
76
  from pygeodesy.fmath import cbrt, hypot, hypot1, hypot2, Fsum
77
- from pygeodesy.interns import _COMMASPACE_, _near_, _SPACE_, _spherical_
78
- from pygeodesy.karney import _K_2_4, _copyBit, _diff182, _fix90, \
79
- _norm2, _norm180, _tand, _unsigned2
77
+ from pygeodesy.interns import _COMMASPACE_, _DMAIN_, _near_, _SPACE_, _spherical_
78
+ from pygeodesy.karney import _K_2_4, _copyBit, _diff182, _fix90, _norm2, \
79
+ _norm180, _tand, _unsigned2
80
80
  # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .named
81
81
  from pygeodesy.named import callername, _incompatible, _NamedBase, \
82
82
  _ALL_LAZY, _MODS
@@ -93,7 +93,7 @@ from pygeodesy.utm import _cmlon, _LLEB, _parseUTM5, _toBand, _toXtm8, \
93
93
  from math import asinh, degrees, radians, sinh, sqrt
94
94
 
95
95
  __all__ = _ALL_LAZY.etm
96
- __version__ = '25.01.12'
96
+ __version__ = '25.04.14'
97
97
 
98
98
  _OVERFLOW = _1_EPS**2 # ~2e+31
99
99
  _TAYTOL = pow(EPS, 0.6)
@@ -268,7 +268,7 @@ class ExactTransverseMercator(_NamedBase):
268
268
  self.raiser = True
269
269
 
270
270
  TM = ExactTransverseMercator
271
- if datum not in (TM._datum, TM._E, None):
271
+ if not _isin(datum, None, TM._datum, TM._E):
272
272
  self.datum = datum # invokes ._resets
273
273
  if lon0 or lon0 != TM._lon0:
274
274
  self.lon0 = lon0
@@ -1101,7 +1101,7 @@ def toEtm8(latlon, lon=None, datum=None, Etm=Etm, falsed=True,
1101
1101
  n, latlon, d.exactTM, Error=ETMError)
1102
1102
 
1103
1103
 
1104
- if __name__ == '__main__': # MCCABE 16
1104
+ if __name__ == _DMAIN_: # MCCABE 16
1105
1105
 
1106
1106
  def _main():
1107
1107
 
pygeodesy/fmath.py CHANGED
@@ -1,19 +1,21 @@
1
1
 
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- u'''Utilities using precision floating point summation.
4
+ u'''Utilities for precision floating point summation, multiplication,
5
+ C{fused-multiply-add}, polynomials, roots, etc.
5
6
  '''
6
7
  # make sure int/int division yields float quotient, see .basics
7
8
  from __future__ import division as _; del _ # PYCHOK semicolon
8
9
 
9
10
  from pygeodesy.basics import _copysign, copysign0, isbool, isint, isscalar, \
10
- len2, map1, _xiterable
11
+ len2, map1, _xiterable, typename
11
12
  from pygeodesy.constants import EPS0, EPS02, EPS1, NAN, PI, PI_2, PI_4, \
12
13
  _0_0, _0_125, _1_6th, _0_25, _1_3rd, _0_5, _1_0, \
13
14
  _1_5, _copysign_0_0, isfinite, remainder
14
15
  from pygeodesy.errors import _IsnotError, LenError, _TypeError, _ValueError, \
15
16
  _xError, _xkwds, _xkwds_pop2, _xsError
16
17
  from pygeodesy.fsums import _2float, Fsum, fsum, _isFsum_2Tuple, Fmt, unstr
18
+ # from pygeodesy.internals import typename # from .basics
17
19
  from pygeodesy.interns import MISSING, _negative_, _not_scalar_
18
20
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
19
21
  # from pygeodesy.streprs import Fmt, unstr # from .fsums
@@ -23,10 +25,10 @@ from math import fabs, sqrt # pow
23
25
  import operator as _operator # in .datums, .trf, .utm
24
26
 
25
27
  __all__ = _ALL_LAZY.fmath
26
- __version__ = '25.01.09'
28
+ __version__ = '25.04.30'
27
29
 
28
30
  # sqrt(2) - 1 <https://WikiPedia.org/wiki/Square_root_of_2>
29
- _0_4142 = 0.41421356237309504880 # ... ~ 3730904090310553 / 9007199254740992
31
+ _0_4142 = 0.41421356237309504880 # ~ 3_730_904_090_310_553 / 9_007_199_254_740_992
30
32
  _2_3rd = _1_3rd * 2
31
33
  _h_lt_b_ = 'abs(h) < abs(b)'
32
34
 
@@ -64,13 +66,27 @@ class Fdot(Fsum):
64
66
  self._facc_dot(n, a, b, **kwds)
65
67
 
66
68
 
69
+ class Fdot_(Fdot):
70
+ '''Precision dot product.
71
+ '''
72
+ def __init__(self, *xys, **start_name_f2product_nonfinites_RESIDUAL):
73
+ '''New L{Fdot_} precision dot product M{sum(xys[i] * xys[i+1] for i in
74
+ range(0, len(xys), B{2}))}.
75
+
76
+ @arg xys: Pairwise values (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
77
+ all positional.
78
+
79
+ @see: Class L{Fdot<Fdot.__init__>} for further details.
80
+ '''
81
+ Fdot.__init__(self, xys[0::2], *xys[1::2], **start_name_f2product_nonfinites_RESIDUAL)
82
+
83
+
67
84
  class Fhorner(Fsum):
68
85
  '''Precision polynomial evaluation using the Horner form.
69
86
  '''
70
87
  def __init__(self, x, *cs, **incx_name_f2product_nonfinites_RESIDUAL):
71
- '''New L{Fhorner} form evaluation of polynomial M{sum(cs[i] * x**i for
72
- i=0..n)} with in- or decreasing exponent M{sum(... i=n..0)}, where C{n
73
- = len(cs) - 1}.
88
+ '''New L{Fhorner} form evaluation of polynomial M{sum(cs[i] * x**i for i=0..n)}
89
+ with in- or decreasing exponent M{sum(... i=n..0)}, where C{n = len(cs) - 1}.
74
90
 
75
91
  @arg x: Polynomial argument (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
76
92
  @arg cs: Polynomial coeffients (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}),
@@ -294,9 +310,8 @@ def euclid(x, y):
294
310
  @see: Function L{euclid_}.
295
311
  '''
296
312
  x, y = abs(x), abs(y) # NOT fabs!
297
- if y > x:
298
- x, y = y, x
299
- return x + y * _0_4142 # * _0_5 before 20.10.02
313
+ return (x + y * _0_4142) if x > y else \
314
+ (y + x * _0_4142) # * _0_5 before 20.10.02
300
315
 
301
316
 
302
317
  def euclid_(*xs):
@@ -453,7 +468,8 @@ def fdot_(*xys, **start_f2product_nonfinites):
453
468
 
454
469
  @return: Dot product (C{float}).
455
470
  '''
456
- return fdot(xys[0::2], *xys[1::2], **start_f2product_nonfinites)
471
+ D = Fdot_(*xys, **_xkwds(start_f2product_nonfinites, nonfinites=True))
472
+ return float(D)
457
473
 
458
474
 
459
475
  def fdot3(xs, ys, zs, **start_f2product_nonfinites):
@@ -554,7 +570,7 @@ def fidw(xs, ds, beta=2):
554
570
 
555
571
 
556
572
  try:
557
- from math import fma as _fma
573
+ from math import fma as _fma # in .resections
558
574
  except ImportError: # PYCHOK DSPACE!
559
575
 
560
576
  def _fma(x, y, z): # no need for accuracy
@@ -656,7 +672,7 @@ def fpowers(x, n, alts=0):
656
672
  @raise ValueError: Non-finite B{C{x}} or invalid B{C{n}}.
657
673
  '''
658
674
  if not isint(n):
659
- raise _IsnotError(int.__name__, n=n)
675
+ raise _IsnotError(typename(int), n=n)
660
676
  elif n < 1:
661
677
  raise _ValueError(n=n)
662
678
 
@@ -736,7 +752,7 @@ def frange(start, number, step=1):
736
752
  numpy/reference/generated/numpy.arange.html>}.
737
753
  '''
738
754
  if not isint(number):
739
- raise _IsnotError(int.__name__, number=number)
755
+ raise _IsnotError(typename(int), number=number)
740
756
  for i in range(number):
741
757
  yield start + (step * i)
742
758
 
pygeodesy/formy.py CHANGED
@@ -6,25 +6,24 @@ u'''Formulary of basic geodesy functions and approximations.
6
6
  # make sure int/int division yields float quotient, see .basics
7
7
  from __future__ import division as _; del _ # PYCHOK semicolon
8
8
 
9
- # from pygeodesy.basics import _args_kwds_count2, _copysign # from .constants
9
+ from pygeodesy.basics import _copysign, _isin # _args_kwds_count2
10
10
  # from pygeodesy.cartesianBase import CartesianBase # _MODS
11
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
- _90_0, _180_0, _360_0, _copysign
14
+ _90_0, _180_0, _360_0
15
15
  from pygeodesy.datums import Datum, Ellipsoid, _ellipsoidal_datum, \
16
16
  _mean_radius, _spherical_datum, _WGS84, _EWGS84
17
17
  # from pygeodesy.ellipsoids import Ellipsoid, _EWGS84 # from .datums
18
18
  from pygeodesy.errors import IntersectionError, LimitError, limiterrors, \
19
19
  _TypeError, _ValueError, _xattr, _xError, \
20
- _xcallable,_xkwds, _xkwds_pop2
20
+ _xcallable, _xkwds, _xkwds_pop2
21
21
  from pygeodesy.fmath import euclid, fdot_, fprod, hypot, hypot2, sqrt0
22
22
  from pygeodesy.fsums import fsumf_, Fmt, unstr
23
- # from pygeodesy.internals import _DUNDER_nameof # from .named
23
+ # from pygeodesy.internals import typename # from .named
24
24
  from pygeodesy.interns import _delta_, _distant_, _inside_, _SPACE_, _too_
25
25
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
26
- from pygeodesy.named import _name__, _name2__, _NamedTuple, _xnamed, \
27
- _DUNDER_nameof
26
+ from pygeodesy.named import _name__, _name2__, _NamedTuple, _xnamed, typename
28
27
  from pygeodesy.namedTuples import Bearing2Tuple, Distance4Tuple, LatLon2Tuple, \
29
28
  Intersection3Tuple, PhiLam2Tuple
30
29
  # from pygeodesy.streprs import Fmt, unstr # from .fsums
@@ -43,7 +42,7 @@ from contextlib import contextmanager
43
42
  from math import atan, cos, degrees, fabs, radians, sin, sqrt # pow
44
43
 
45
44
  __all__ = _ALL_LAZY.formy
46
- __version__ = '25.01.05'
45
+ __version__ = '25.04.14'
47
46
 
48
47
  _RADIANS2 = radians(_1_0)**2 # degree to radians-squared
49
48
  _ratio_ = 'ratio'
@@ -371,9 +370,9 @@ def _dS(fun_, radius, wrap, *lls, **adjust):
371
370
  def _ellipsoidal(earth, where):
372
371
  '''(INTERNAL) Helper for distances.
373
372
  '''
374
- return _EWGS84 if earth in (_WGS84, _EWGS84) else (
375
- earth if isinstance(earth, Ellipsoid) else
376
- (earth if isinstance(earth, Datum) else # PYCHOK indent
373
+ return _EWGS84 if _isin(earth, _EWGS84, _WGS84) else (
374
+ earth if isinstance(earth, Ellipsoid) else
375
+ (earth if isinstance(earth, Datum) else # PYCHOK indent
377
376
  _ellipsoidal_datum(earth, name__=where)).ellipsoid)
378
377
 
379
378
 
@@ -1077,8 +1076,8 @@ class _idllmn6(object): # see also .geodesicw._wargs, .latlonBase._toCartesian3
1077
1076
  if wrap:
1078
1077
  _, lat2, lon2 = _Wrap.latlon3(lon1, lat2, lon2, wrap)
1079
1078
  kwds = _xkwds(kwds, wrap=wrap) # for _xError
1080
- m = small if small is _100km else Meter_(small=small)
1081
- n = _DUNDER_nameof(intersections2 if s else intersection2)
1079
+ m = small if small is _100km else Meter_(small=small)
1080
+ n = typename(intersections2 if s else intersection2)
1082
1081
  if datum is None or euclidean(lat1, lon1, lat2, lon2) < m:
1083
1082
  d, m = None, _MODS.vector3d
1084
1083
  _i = m._intersects2 if s else m._intersect3d3