pygeodesy 24.10.10__py2.py3-none-any.whl → 24.11.11__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 (76) hide show
  1. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/METADATA +12 -12
  2. PyGeodesy-24.11.11.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +14 -14
  5. pygeodesy/__main__.py +5 -5
  6. pygeodesy/albers.py +12 -17
  7. pygeodesy/azimuthal.py +51 -61
  8. pygeodesy/basics.py +60 -62
  9. pygeodesy/booleans.py +87 -79
  10. pygeodesy/cartesianBase.py +6 -6
  11. pygeodesy/constants.py +23 -19
  12. pygeodesy/css.py +7 -8
  13. pygeodesy/datums.py +3 -3
  14. pygeodesy/deprecated/__init__.py +1 -1
  15. pygeodesy/deprecated/classes.py +9 -9
  16. pygeodesy/deprecated/functions.py +6 -6
  17. pygeodesy/dms.py +250 -270
  18. pygeodesy/ecef.py +11 -14
  19. pygeodesy/ellipsoidalBase.py +106 -121
  20. pygeodesy/ellipsoidalBaseDI.py +114 -118
  21. pygeodesy/ellipsoidalExact.py +35 -37
  22. pygeodesy/ellipsoidalNvector.py +4 -4
  23. pygeodesy/ellipsoidalVincenty.py +2 -2
  24. pygeodesy/ellipsoids.py +10 -51
  25. pygeodesy/elliptic.py +14 -14
  26. pygeodesy/errors.py +28 -28
  27. pygeodesy/etm.py +92 -68
  28. pygeodesy/fmath.py +42 -40
  29. pygeodesy/formy.py +7 -6
  30. pygeodesy/fsums.py +72 -51
  31. pygeodesy/geodesici.py +43 -40
  32. pygeodesy/geodesicw.py +17 -16
  33. pygeodesy/geodesicx/__init__.py +2 -2
  34. pygeodesy/geodesicx/gxarea.py +3 -2
  35. pygeodesy/geodsolve.py +79 -39
  36. pygeodesy/geohash.py +2 -2
  37. pygeodesy/geoids.py +32 -31
  38. pygeodesy/heights.py +2 -2
  39. pygeodesy/internals.py +201 -147
  40. pygeodesy/interns.py +23 -20
  41. pygeodesy/karney.py +62 -13
  42. pygeodesy/ktm.py +11 -13
  43. pygeodesy/latlonBase.py +18 -20
  44. pygeodesy/lazily.py +210 -218
  45. pygeodesy/lcc.py +4 -4
  46. pygeodesy/ltp.py +10 -10
  47. pygeodesy/ltpTuples.py +74 -75
  48. pygeodesy/mgrs.py +20 -21
  49. pygeodesy/named.py +15 -10
  50. pygeodesy/nvectorBase.py +1 -1
  51. pygeodesy/osgr.py +9 -12
  52. pygeodesy/points.py +2 -2
  53. pygeodesy/props.py +35 -14
  54. pygeodesy/resections.py +9 -10
  55. pygeodesy/rhumb/__init__.py +1 -1
  56. pygeodesy/rhumb/bases.py +5 -5
  57. pygeodesy/rhumb/solve.py +9 -10
  58. pygeodesy/simplify.py +5 -5
  59. pygeodesy/solveBase.py +7 -25
  60. pygeodesy/sphericalBase.py +20 -23
  61. pygeodesy/sphericalNvector.py +103 -145
  62. pygeodesy/sphericalTrigonometry.py +68 -73
  63. pygeodesy/streprs.py +5 -5
  64. pygeodesy/trf.py +6 -4
  65. pygeodesy/triaxials.py +46 -9
  66. pygeodesy/units.py +5 -4
  67. pygeodesy/ups.py +6 -6
  68. pygeodesy/utily.py +2 -2
  69. pygeodesy/utm.py +7 -7
  70. pygeodesy/vector2d.py +13 -13
  71. pygeodesy/vector3d.py +19 -21
  72. pygeodesy/vector3dBase.py +21 -19
  73. pygeodesy/webmercator.py +4 -4
  74. pygeodesy/wgrs.py +4 -4
  75. PyGeodesy-24.10.10.dist-info/RECORD +0 -118
  76. {PyGeodesy-24.10.10.dist-info → PyGeodesy-24.11.11.dist-info}/top_level.txt +0 -0
pygeodesy/fsums.py CHANGED
@@ -48,12 +48,12 @@ from pygeodesy.errors import _AssertionError, _OverflowError, _TypeError, \
48
48
  _ValueError, _xError, _xError2, _xkwds, \
49
49
  _xkwds_get, _xkwds_get1, _xkwds_not, \
50
50
  _xkwds_pop, _xsError
51
- from pygeodesy.internals import _enquote, _passarg
51
+ from pygeodesy.internals import _enquote, _getPYGEODESY, _MODS, _passarg
52
52
  from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DOT_, _from_, \
53
53
  _not_finite_, _SPACE_, _std_, _UNDER_
54
- from pygeodesy.lazily import _ALL_LAZY, _getenv, _sys_version_info2
54
+ # from pygeodesy.lazily import _ALL_LAZY # from .named
55
55
  from pygeodesy.named import _name__, _name2__, _Named, _NamedTuple, \
56
- _NotImplemented
56
+ _NotImplemented, _ALL_LAZY
57
57
  from pygeodesy.props import _allPropertiesOf_n, deprecated_method, \
58
58
  deprecated_property_RO, Property, \
59
59
  Property_RO, property_RO
@@ -64,7 +64,7 @@ from math import fabs, isinf, isnan, \
64
64
  ceil as _ceil, floor as _floor # PYCHOK used! .ltp
65
65
 
66
66
  __all__ = _ALL_LAZY.fsums
67
- __version__ = '24.10.09'
67
+ __version__ = '24.11.11'
68
68
 
69
69
  from pygeodesy.interns import (
70
70
  _PLUS_ as _add_op_, # in .auxilats.auxAngle
@@ -79,15 +79,15 @@ from pygeodesy.interns import (
79
79
  )
80
80
  _floordiv_op_ = _truediv_op_ * 2 # _DSLASH_
81
81
  _divmod_op_ = _floordiv_op_ + _mod_op_
82
- _F2PRODUCT = _getenv('PYGEODESY_FSUM_F2PRODUCT', NN)
82
+ _F2PRODUCT = _getPYGEODESY('FSUM_F2PRODUCT')
83
83
  _iadd_op_ = _add_op_ + _fset_op_ # in .auxilats.auxAngle, .fstats
84
84
  _integer_ = 'integer'
85
85
  _isub_op_ = _sub_op_ + _fset_op_ # in .auxilats.auxAngle
86
86
  _NONFINITEr = _0_0 # NOT INT0!
87
- _NONFINITES = _getenv('PYGEODESY_FSUM_NONFINITES', NN)
87
+ _NONFINITES = _getPYGEODESY('FSUM_NONFINITES')
88
88
  _non_zero_ = 'non-zero'
89
89
  _pow_op_ = _mul_op_ * 2 # _DSTAR_
90
- _RESIDUAL_0_0 = _getenv('PYGEODESY_FSUM_RESIDUAL', _0_0)
90
+ _RESIDUAL_0_0 = _getPYGEODESY('FSUM_RESIDUAL', _0_0)
91
91
  _significant_ = 'significant'
92
92
  _threshold_ = 'threshold'
93
93
 
@@ -163,9 +163,11 @@ except ImportError: # PYCHOK DSPACE! Python 3.12-
163
163
 
164
164
  _2n_d = None # redef
165
165
 
166
- def _fmaX(r, *a_b_c): # like Python 3.13+ I{Modules/mathmodule.c}:
167
- # raise a ValueError for a NAN result from non-NAN C{a_b_c}s or an
168
- # OverflowError for a non-NAN non-finite from all finite C{a_b_c}s.
166
+ def _fmaX(r, *a_b_c): # PYCHOK no cover
167
+ # handle non-finite as Python 3.13+ C-function U{math_fma_impl<https://
168
+ # GitHub.com/python/cpython/blob/main/Modules/mathmodule.c#L2305>}:
169
+ # raise a ValueError for a NAN result from non-NAN C{a_b_c}s or an
170
+ # OverflowError for a non-NAN non-finite from all finite C{a_b_c}s.
169
171
  if isnan(r):
170
172
  def _x(x):
171
173
  return not isnan(x)
@@ -212,11 +214,11 @@ except ImportError: # PYCHOK DSPACE! Python 3.12-
212
214
  return map(_2split3, xs)
213
215
 
214
216
 
215
- def f2product(*two):
217
+ def f2product(two=None):
216
218
  '''Turn accurate I{TwoProduct} multiplication on or off.
217
219
 
218
- @arg two: If C{True}, turn I{TwoProduct} on, if C{False} off or
219
- if C{None} or omitted, keep the current setting.
220
+ @kwarg two: If C{True}, turn I{TwoProduct} on, if C{False} off or
221
+ if C{None} or omitted, keep the current setting.
220
222
 
221
223
  @return: The previous setting (C{bool}).
222
224
 
@@ -226,8 +228,8 @@ def f2product(*two):
226
228
  equivalent, slower implementation when not available.
227
229
  '''
228
230
  t = Fsum._f2product
229
- if two and two[0] is not None:
230
- Fsum._f2product = bool(two[0])
231
+ if two is not None:
232
+ Fsum._f2product = bool(two)
231
233
  return t
232
234
 
233
235
 
@@ -318,14 +320,14 @@ def _NonfiniteError(x):
318
320
  _ValueError if isnan(x) else _AssertionError)
319
321
 
320
322
 
321
- def nonfiniterrors(*raiser):
323
+ def nonfiniterrors(raiser=None):
322
324
  '''Throw C{OverflowError} and C{ValueError} exceptions for or
323
325
  handle I{non-finite} C{float}s as C{inf}, C{INF}, C{NINF},
324
326
  C{nan} and C{NAN} in summations and multiplications.
325
327
 
326
- @arg raiser: If C{True}, throw exceptions, if C{False} handle
327
- I{non-finites} or if C{None} or omitted, leave
328
- the setting unchanged.
328
+ @kwarg raiser: If C{True}, throw exceptions, if C{False} handle
329
+ I{non-finites} or if C{None} or omitted, leave
330
+ the setting unchanged.
329
331
 
330
332
  @return: Previous setting (C{bool}).
331
333
 
@@ -333,8 +335,8 @@ def nonfiniterrors(*raiser):
333
335
  C{nan} and C{NAN} a C{ValueError}.
334
336
  '''
335
337
  d = Fsum._isfine
336
- if raiser and raiser[0] is not None:
337
- Fsum._isfine = {} if bool(raiser[0]) else Fsum._nonfinites_isfine_kwds[True]
338
+ if raiser is not None:
339
+ Fsum._isfine = {} if bool(raiser) else Fsum._nonfinites_isfine_kwds[True]
338
340
  return (False if d is Fsum._nonfinites_isfine_kwds[True] else
339
341
  _xkwds_get1(d, _isfine=_isfinite) is _isfinite) if d else True
340
342
 
@@ -516,7 +518,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
516
518
  @see: Module L{fsums<pygeodesy.fsums>} for env variables C{PYGEODESY_FSUM_F2PRODUCT},
517
519
  C{PYGEODESY_FSUM_NONFINITES} and C{PYGEODESY_FSUM_RESIDUAL}.
518
520
  '''
519
- _f2product = _sys_version_info2 > (3, 12) or bool(_F2PRODUCT)
521
+ _f2product = _MODS.sys_version_info2 > (3, 12) or bool(_F2PRODUCT)
520
522
  _isfine = {} # == _isfinite, see nonfiniterrors()
521
523
  _n = 0
522
524
  # _ps = [] # partial sums
@@ -645,10 +647,6 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
645
647
  f = self._copy_2(self.__floordiv__)
646
648
  return f._floordiv(other, _floordiv_op_)
647
649
 
648
- def __format__(self, *other): # PYCHOK no cover
649
- '''Not implemented.'''
650
- return _NotImplemented(self, *other)
651
-
652
650
  def __ge__(self, other):
653
651
  '''Return C{(B{self} >= B{other})}, see C{__eq__}.
654
652
  '''
@@ -913,6 +911,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
913
911
  f = self._copy_2r(other, self.__rdivmod__)
914
912
  return f._fdivmod2(self, _divmod_op_)
915
913
 
914
+ # turned off, called by _deepcopy and _copy
915
+ # def __reduce__(self): # Python 3.8+
916
+ # ''' Pickle, like std C{fractions.Fraction}, see U{__reduce__
917
+ # <https://docs.Python.org/3/library/pickle.html#object.__reduce__>}
918
+ # '''
919
+ # dict_ = self._Fsum_as().__dict__ # no __setstate__
920
+ # return (self.__class__, self.partials, dict_)
921
+
916
922
  # def __repr__(self):
917
923
  # '''Return the default C{repr(this)}.
918
924
  # '''
@@ -926,7 +932,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
926
932
  f = self._copy_2r(other, self.__rfloordiv__)
927
933
  return f._floordiv(self, _floordiv_op_)
928
934
 
929
- def __rmatmul__(self, other): # PYCHOK no cover
935
+ def __rmatmul__(self, other): # PYCHOK no coveS
930
936
  '''Not implemented.'''
931
937
  return _NotImplemented(self, other)
932
938
 
@@ -1015,7 +1021,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1015
1021
 
1016
1022
  __trunc__ = __int__
1017
1023
 
1018
- if _sys_version_info2 < (3, 0): # PYCHOK no cover
1024
+ if _MODS.sys_version_info2 < (3, 0): # PYCHOK no cover
1019
1025
  # <https://docs.Python.org/2/library/operator.html#mapping-operators-to-functions>
1020
1026
  __div__ = __truediv__
1021
1027
  __idiv__ = __itruediv__
@@ -1101,7 +1107,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1101
1107
  def _copy_2(self, which, name=NN):
1102
1108
  '''(INTERNAL) Copy for I{dyadic} operators.
1103
1109
  '''
1104
- n = name or which.__name__ # _dunder_nameof
1110
+ n = name or which.__name__ # _DUNDER_nameof
1105
1111
  # NOT .classof due to .Fdot(a, *b) args, etc.
1106
1112
  f = _Named.copy(self, deep=False, name=n)
1107
1113
  f._ps = list(self._ps) # separate list
@@ -1152,6 +1158,8 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1152
1158
  fs = _xs(xs, **kwds) # PYCHOK yield
1153
1159
  ps = self._ps
1154
1160
  ps[:] = self._ps_acc(list(ps), fs, up=up)
1161
+ # if len(ps) > 16:
1162
+ # _ = _psum(ps, **self._isfine)
1155
1163
  return self
1156
1164
 
1157
1165
  def _facc_args(self, xs, **up):
@@ -1161,6 +1169,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1161
1169
  return self._fadd(xs[0], **up) if len(xs) == 1 else \
1162
1170
  self._facc(xs, **up) # origin=1?
1163
1171
 
1172
+ def _facc_dot(self, n, xs, ys, **kwds): # in .fmath
1173
+ '''(INTERNAL) Accumulate C{fdot(B{xs}, *B{ys})}.
1174
+ '''
1175
+ if n > 0:
1176
+ _f = Fsum(**kwds)
1177
+ self._facc(_f(x).fmul(y) for x, y in zip(xs, ys)) # PYCHOK attr?
1178
+ return self
1179
+
1164
1180
  def _facc_neg(self, xs, **up_origin):
1165
1181
  '''(INTERNAL) Accumulate more C{xs}, negated.
1166
1182
  '''
@@ -1452,7 +1468,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1452
1468
  try:
1453
1469
  s, r = self._fprs2
1454
1470
  if r:
1455
- f = self._f2mul(self.fma, other1, **nonfinites)
1471
+ f = self._f2mul(self.fma, (other1,), **nonfinites)
1456
1472
  f += other2
1457
1473
  elif _residue(other1) or _residue(other2):
1458
1474
  fs = _2split3s(_fs(op, other1))
@@ -1491,36 +1507,41 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1491
1507
  @deprecated_method
1492
1508
  def f2mul(self, *others, **raiser):
1493
1509
  '''DEPRECATED on 2024.09.13, use method L{f2mul_<Fsum.f2mul_>}.'''
1494
- return self._fset(self.f2mul_(*others, **raiser))
1510
+ return self._fset(self.f2mul_(others, **raiser))
1495
1511
 
1496
- def f2mul_(self, *others, **nonfinites): # in .fmath.f2mul
1512
+ def f2mul_(self, *others, **f2product_nonfinites): # in .fmath.f2mul
1497
1513
  '''Return C{B{self} * B{other} * B{other} ...} for all B{C{others}} using cascaded,
1498
- accurate multiplication like with L{f2product<Fsum.f2product>} set to C{True}.
1514
+ accurate multiplication like with L{f2product<Fsum.f2product>}C{(B{True})}.
1499
1515
 
1500
1516
  @arg others: Multipliers (each C{scalar}, an L{Fsum} or L{Fsum2Tuple}), all
1501
1517
  positional.
1502
- @kwarg nonfinites: Use C{B{nonfinites}=True} or C{False}, to override both
1503
- L{nonfinites<Fsum.nonfinites>} and the L{nonfiniterrors}
1504
- default (C{bool}).
1518
+ @kwarg f2product_nonfinites: Use C{B{f2product=False}} to override the default
1519
+ C{True} and C{B{nonfinites}=True} or C{False}, to override
1520
+ settings L{nonfinites<Fsum.nonfinites>} and L{nonfiniterrors}.
1505
1521
 
1506
1522
  @return: The cascaded I{TwoProduct} (L{Fsum} or C{float}).
1507
1523
 
1508
1524
  @see: U{Equations 2.3<https://www.TUHH.De/ti3/paper/rump/OzOgRuOi06.pdf>}
1509
1525
  '''
1510
- return self._f2mul(self.f2mul_, *others, **nonfinites)
1526
+ return self._f2mul(self.f2mul_, others, **f2product_nonfinites)
1511
1527
 
1512
- def _f2mul(self, where, *others, **nonfinites_raiser):
1528
+ def _f2mul(self, where, others, f2product=True, **nonfinites_raiser):
1513
1529
  '''(INTERNAL) See methods C{fma} and C{f2mul_}.
1514
1530
  '''
1515
- f = self._copy_2(where)
1516
- ps = f._ps
1517
- if ps and others:
1518
- op = where.__name__
1519
- try:
1531
+ f = _Psum(self._ps, f2product=f2product, name=where.__name__)
1532
+ if others and f:
1533
+ if f.f2product():
1534
+ def _pfs(f, ps):
1535
+ return _2products(f, _2split3s(ps))
1536
+ else:
1537
+ def _pfs(f, ps): # PYCHOK redef
1538
+ return (f * p for p in ps)
1539
+
1540
+ op, ps = where.__name__, f._ps
1541
+ try: # as if self.f2product(True)
1520
1542
  for other in others: # to pinpoint errors
1521
1543
  for p in self._ps_other(op, other):
1522
- pfs = _2products(p, _2split3s(ps))
1523
- ps[:] = f._ps_acc([], pfs, up=False)
1544
+ ps[:] = f._ps_acc([], _pfs(p, ps), update=False)
1524
1545
  f._update()
1525
1546
  except TypeError as X:
1526
1547
  raise self._ErrorX(X, op, other)
@@ -2299,11 +2320,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
2299
2320
  return (p * f for f in fs)
2300
2321
 
2301
2322
  for p in ps:
2302
- for f in _pfs(p, fs):
2303
- yield f if _isfine(f) else _nfError(f)
2323
+ for x in _pfs(p, fs):
2324
+ yield x if _isfine(x) else _nfError(x)
2304
2325
 
2305
- fs = _psfs(self._ps, factors, **self._isfine)
2306
- f = _Psum(self._ps_acc([], fs, up=False), name=op)
2326
+ xs = _psfs(self._ps, factors, **self._isfine)
2327
+ f = _Psum(self._ps_acc([], xs, up=False), name=op)
2307
2328
  return f
2308
2329
 
2309
2330
  @property_RO
@@ -2774,7 +2795,7 @@ def _xs(xs, _X=_X_ps, _x=float, _isfine=_isfinite, # defaults for Fsum._facc
2774
2795
  i, x = 0, xs
2775
2796
  try:
2776
2797
  for i, x in enumerate(_xiterable(xs)):
2777
- if isinstance(x, _Fsum_2Tuple_types):
2798
+ if _isFsum_2Tuple(x):
2778
2799
  for p in _X(x):
2779
2800
  yield p if _isfine(p) else _nfError(p)
2780
2801
  else:
@@ -2803,7 +2824,7 @@ def _xsum(which, xs, nonfinites=None, primed=0, **floats): # origin=0
2803
2824
  # delete all decorators, etc.
2804
2825
  del _allPropertiesOf_n, deprecated_method, deprecated_property_RO, \
2805
2826
  Property, Property_RO, property_RO, _ALL_LAZY, _F2PRODUCT, \
2806
- MANT_DIG, _NONFINITES, _RESIDUAL_0_0, _getenv, _std_
2827
+ MANT_DIG, _NONFINITES, _RESIDUAL_0_0, _getPYGEODESY, _std_
2807
2828
 
2808
2829
  if __name__ == '__main__':
2809
2830
 
pygeodesy/geodesici.py CHANGED
@@ -38,11 +38,10 @@ from pygeodesy.errors import GeodesicError, IntersectionError, _an, \
38
38
  # from pygeodesy.errors import exception_chaining # _MODS
39
39
  from pygeodesy.fmath import euclid, fdot
40
40
  from pygeodesy.fsums import Fsum, fsum1_, _ceil
41
- from pygeodesy.interns import NN, _A_, _B_, _c_, _COMMASPACE_, \
42
- _HASH_, _M_, _not_, _SPACE_, _too_
43
- from pygeodesy.karney import Caps, _diff182, GDict, _sincos2de
44
- from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS, \
45
- _getenv, _PYGEODESY_INTERSECTTOOL_
41
+ from pygeodesy.interns import NN, _A_, _B_, _c_, _COMMASPACE_, _HASH_, \
42
+ _M_, _not_, _SPACE_, _too_
43
+ from pygeodesy.karney import Caps, _diff182, GDict, _sincos2de, _Xables
44
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
46
45
  from pygeodesy.named import ADict, _NamedBase, _NamedTuple, _Pass
47
46
  # from pygeodesy.namedTuples import _LL4Tuple # _MODS
48
47
  from pygeodesy.props import deprecated_method, Property, \
@@ -57,7 +56,7 @@ from pygeodesy.utily import sincos2, atan2, fabs, radians
57
56
  # from math import atan2, ceil as _ceil, fabs, radians # .fsums, .utily
58
57
 
59
58
  __all__ = _ALL_LAZY.geodesici
60
- __version__ = '24.08.28'
59
+ __version__ = '24.10.22'
61
60
 
62
61
  _0t = 0, # int
63
62
  _1_1t = -1, +1
@@ -470,8 +469,8 @@ class Intersectool(_IntersectBase, _SolveCapsBase):
470
469
  _Names_ABs = _latA_, _lonA_, 'latB', 'lonB', _sAB_ # -C to stderr
471
470
  _Names_XDict = 'sA', 'sB', _c_ # plus 'k' from -i or 'sX0' from -R
472
471
  _o_alt = _o__, # Offset latA lonA aziA latB lonB aziB x0 y0
473
- _Xable_name = 'IntersectTool'
474
- _Xable_path = _getenv(_PYGEODESY_INTERSECTTOOL_, _PYGEODESY_INTERSECTTOOL_)
472
+ _Xable_name = _Xables.IntersectTool.__name__
473
+ _Xable_path = _Xables.IntersectTool()
475
474
 
476
475
  def __init__(self, a_geodesic=None, f=None, **name):
477
476
  '''New L{IntersectTool}.
@@ -1547,7 +1546,7 @@ if __name__ == '__main__': # MCCABE 14
1547
1546
  ll4 += ll4.replace(_A_, _B_)
1548
1547
  llz = _SPACE_(NN, _latA_, _lonA_, 'aziA')
1549
1548
  llz2 = llz + llz.replace(_A_, _B_)
1550
- return dict(opts='-Verbose|V--version|v--help|h--Tool|T--Check|C-R meter-',
1549
+ return dict(opts='-Verbose|V--version|v--help|h--Tool|T--Check|C-R <meter>-',
1551
1550
  alts=((_c_ + llz2),
1552
1551
  (_i_ + ll4),
1553
1552
  (_m_ + ll4),
@@ -1587,8 +1586,8 @@ if __name__ == '__main__': # MCCABE 14
1587
1586
  I = Intersectool() # PYCHOK I
1588
1587
  if _V:
1589
1588
  I.verbose = True
1590
- if I.IntersectTool in (_PYGEODESY_INTERSECTTOOL_, None): # not set
1591
- I.IntersectTool = '/opt/local/bin/IntersectTool' # '/opt/local/Cellar/geographiclib/2.3/bin/IntersectTool' # HomeBrew
1589
+ if not _Xables.X_OK(I.IntersectTool):
1590
+ I.IntersectTool = _Xables.IntersectTool(_Xables.bin_)
1592
1591
  elif _V:
1593
1592
  _ = I.version
1594
1593
  M, _T = None, True
@@ -1640,38 +1639,42 @@ if __name__ == '__main__': # MCCABE 14
1640
1639
  for i, X in enumerate(X):
1641
1640
  printf(_COLONSPACE_(Fmt.INDEX(m, i), repr(X)))
1642
1641
 
1642
+ def _examples():
1643
+
1644
+ from pygeodesy.internals import _usage_argv
1645
+
1646
+ s = _SPACE_(*_usage_argv(__file__))
1647
+ for t in ('-h', '-h -n',
1648
+ '-c 0 0 45 40 10 135',
1649
+ '-C -c 0 0 45 40 10 135',
1650
+ '-T -R 2.6e7 -c 0 0 45 40 10 135',
1651
+ '-c 50 -4 -147.7 0 0 90',
1652
+ '-C -c 50 -4 -147.7 0 0 90',
1653
+ '# % echo 0 0 10 10 50 -4 50S 4W | IntersectTool -i -p 0 -C',
1654
+ '# -631414 5988887 0 -3',
1655
+ '# -4.05187 -4.00000 -4.05187 -4.00000 0',
1656
+ '-m 0 0 10 10 50 -4 50S 4W',
1657
+ '-C -m 0 0 10 10 50 -4 50S 4W',
1658
+ '-i 0 0 10 10 50 -4 50S 4W',
1659
+ '-T -i 0 0 10 10 50 -4 50S 4W',
1660
+ '-C -i 0 0 10 10 50 -4 50S 4W',
1661
+ '-T -C -i 0 0 10 10 50 -4 50S 4W',
1662
+ '-V -T -i 0 0 10 10 50 -4 -50 -4',
1663
+ '-C -R 4e7 -c 50 -4 -147.7 0 0 90',
1664
+ '-T -C -R 4e7 -c 50 -4 -147.7 0 0 90',
1665
+ '-R 4e7 -i 0 0 10 10 50 -4 -50 -4',
1666
+ '-T -R 4e7 -i 0 0 10 10 50 -4 -50 -4'):
1667
+ if t.startswith(_HASH_):
1668
+ printf(t, nl=int(t[2] == '%'))
1669
+ else:
1670
+ printf(_SPACE_(_HASH_, s, t), nl=1)
1671
+ argv[1:] = t = t.split()
1672
+ _main(t)
1673
+
1643
1674
  from sys import argv, stderr
1644
1675
  try:
1645
1676
  if len(argv) == 2 and argv[1] == __help_:
1646
- from pygeodesy.internals import _usage_argv
1647
-
1648
- s = _SPACE_(*_usage_argv(__file__))
1649
- for t in ('-h', '-h -n',
1650
- '-c 0 0 45 40 10 135',
1651
- '-C -c 0 0 45 40 10 135',
1652
- '-T -R 2.6e7 -c 0 0 45 40 10 135',
1653
- '-c 50 -4 -147.7 0 0 90',
1654
- '-C -c 50 -4 -147.7 0 0 90',
1655
- '# % echo 0 0 10 10 50 -4 50S 4W | IntersectTool -i -p 0 -C',
1656
- '# -631414 5988887 0 -3',
1657
- '# -4.05187 -4.00000 -4.05187 -4.00000 0',
1658
- '-m 0 0 10 10 50 -4 50S 4W',
1659
- '-C -m 0 0 10 10 50 -4 50S 4W',
1660
- '-i 0 0 10 10 50 -4 50S 4W',
1661
- '-T -i 0 0 10 10 50 -4 50S 4W',
1662
- '-C -i 0 0 10 10 50 -4 50S 4W',
1663
- '-T -C -i 0 0 10 10 50 -4 50S 4W',
1664
- '-V -T -i 0 0 10 10 50 -4 -50 -4',
1665
- '-C -R 4e7 -c 50 -4 -147.7 0 0 90',
1666
- '-T -C -R 4e7 -c 50 -4 -147.7 0 0 90',
1667
- '-R 4e7 -i 0 0 10 10 50 -4 -50 -4',
1668
- '-T -R 4e7 -i 0 0 10 10 50 -4 -50 -4'):
1669
- if t.startswith(_HASH_):
1670
- printf(t, nl=int(t[2] == '%'))
1671
- else:
1672
- printf(_SPACE_(_HASH_, s, t), nl=1)
1673
- argv[1:] = t = t.split()
1674
- _main(t)
1677
+ _examples()
1675
1678
  else:
1676
1679
  _main(argv[1:])
1677
1680
 
pygeodesy/geodesicw.py CHANGED
@@ -21,7 +21,7 @@ from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
21
21
  from pygeodesy.errors import _AssertionError, GeodesicError, \
22
22
  IntersectionError
23
23
  from pygeodesy.fsums import Fsum, Fmt, unstr
24
- from pygeodesy.internals import _dunder_nameof, _under
24
+ from pygeodesy.internals import _DUNDER_nameof, _under
25
25
  from pygeodesy.interns import NN, _DOT_, _SPACE_, _to_, _too_
26
26
  from pygeodesy.karney import _atan2d, Caps, Direct9Tuple, GDict, \
27
27
  Inverse10Tuple, _kWrapped
@@ -39,7 +39,7 @@ from contextlib import contextmanager
39
39
  # from math import fabs # from .utily
40
40
 
41
41
  __all__ = _ALL_LAZY.geodesicw
42
- __version__ = '24.07.12'
42
+ __version__ = '24.11.02'
43
43
 
44
44
  _plumb_ = 'plumb'
45
45
  _TRIPS = 65
@@ -94,14 +94,14 @@ class _gWrapped(_kWrapped):
94
94
  if name:
95
95
  self._name, _ = _name2__(name, _or_nameof=E)
96
96
 
97
- def ArcDirect(self, lat1, lon1, azi1, a12, outmask=Caps._STD):
97
+ def ArcDirect(self, lat1, lon1, azi1, a12, outmask=Caps._STD): # PYCHOK no cover
98
98
  '''Return the C{_Geodesic.ArcDirect} result as L{GDict}.
99
99
  '''
100
100
  with _wargs(self, lat1, lon1, azi1, a12, outmask) as args:
101
101
  d = _Geodesic.ArcDirect(self, *args)
102
102
  return GDict(d)
103
103
 
104
- def ArcDirectLine(self, lat1, lon1, azi1, a12, caps=Caps._STD_LINE, **name):
104
+ def ArcDirectLine(self, lat1, lon1, azi1, a12, caps=Caps._STD_LINE, **name): # PYCHOK no cover
105
105
  '''Return the C{_Geodesic.ArcDirectLine} as I{wrapped} C{GeodesicLine}.
106
106
  '''
107
107
  return self._GenDirectLine(lat1, lon1, azi1, True, a12, caps, **name)
@@ -445,7 +445,7 @@ _wrapped = _gWrapped() # PYCHOK singleton, .ellipsoids, .test/base.py
445
445
 
446
446
  class Geodesic(_gWrapped): # overwritten by 1st instance
447
447
  '''I{Wrapper} around I{Karney}'s class U{geographiclib.geodesic.Geodesic
448
- <https://geographiclib.sourceforge.io/Python/doc/code.html>}.
448
+ <https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
449
449
  '''
450
450
  def __new__(unused, a_ellipsoid=_EWGS84, f=None, **name):
451
451
  '''Return a I{wrapped} C{geodesic.Geodesic} instance from I{Karney}'s
@@ -465,7 +465,7 @@ class Geodesic(_gWrapped): # overwritten by 1st instance
465
465
 
466
466
  class GeodesicLine(_gWrapped): # overwritten by 1st instance
467
467
  '''I{Wrapper} around I{Karney}'s class U{geographiclib.geodesicline.GeodesicLine
468
- <https://geographiclib.sourceforge.io/Python/doc/code.html>}.
468
+ <https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
469
469
  '''
470
470
  def __new__(unused, geodesic, lat1, lon1, azi1, caps=Caps._STD_LINE, **name):
471
471
  '''Return a I{wrapped} C{geodesicline.GeodesicLine} instance from I{Karney}'s
@@ -516,16 +516,15 @@ def _Intersecant2(gl, lat0, lon0, radius, tol=_TOL, form=F_D): # MCCABE in LatL
516
516
  # (INTERNAL) Return the intersections of a circle at C{lat0, lon0}
517
517
  # and a geodesic line as a 2-Tuple C{(P, Q)}, each a C{GDict}.
518
518
  r = Radius_(radius)
519
- n = _dunder_nameof(_Intersecant2)[1:]
519
+ n = _DUNDER_nameof(_Intersecant2)[1:]
520
520
  _P = gl.Position
521
521
  _I = gl.geodesic.Inverse
522
- _a = fabs
523
522
 
524
523
  def _R3(s):
525
524
  # radius, intersection, etc. at distance C{s}
526
525
  P = _P(s)
527
526
  d = _I(lat0, lon0, P.lat2, P.lon2)
528
- return _a(d.s12), P, d
527
+ return fabs(d.s12), P, d
529
528
 
530
529
  def _bisect2(s, c, Rc, r, tol, _R3):
531
530
  _s = Fsum(c).fsumf_
@@ -536,18 +535,20 @@ def _Intersecant2(gl, lat0, lon0, radius, tol=_TOL, form=F_D): # MCCABE in LatL
536
535
  break
537
536
  else: # b >>> s and c >>> s
538
537
  raise ValueError(Fmt.no_convergence(b, s))
539
- __2 = _0_5 # Rb > r > Rc
538
+ # Rb > r > Rc
540
539
  for i in range(_TRIPS): # 47-48
541
- s = (b + c) * __2
540
+ s = (b + c) * _0_5
542
541
  R, P, d = _R3(s)
543
542
  if Rb > R > r:
544
543
  b, Rb = s, R
545
544
  elif Rc < R < r:
546
545
  c, Rc = s, R
547
- t = _a(b - c)
548
- if t < tol: # or _a(R - r) < tol:
546
+ # else:
547
+ # break
548
+ t = fabs(b - c)
549
+ if t < tol: # or fabs(R - r) < tol:
549
550
  break
550
- else: # t = min(t, _a(R - r))
551
+ else: # t = min(t, fabs(R - r))
551
552
  raise ValueError(Fmt.no_convergence(t, tol))
552
553
  i += C.iteration # combine iterations
553
554
  P.set_(lat0=lat0, lon0=lon0, azi0=d.azi1, iteration=i,
@@ -558,13 +559,13 @@ def _Intersecant2(gl, lat0, lon0, radius, tol=_TOL, form=F_D): # MCCABE in LatL
558
559
  # one the plumb, pseudo-rhumb line to the other
559
560
  C = _PlumbTo(gl, lat0, lon0, tol=tol)
560
561
  try:
561
- a = _a(C.s02) # distance between centers
562
+ a = fabs(C.s02) # distance between centers
562
563
  if a < r:
563
564
  c = C.s12 # distance along pseudo-rhumb line
564
565
  h = _copysign(r, c) # past half chord length
565
566
  P, p = _bisect2( h, c, a, r, tol, _R3)
566
567
  Q, q = _bisect2(-h, c, a, r, tol, _R3)
567
- if _a(p - q) < max(EPS, tol):
568
+ if fabs(p - q) < max(EPS, tol):
568
569
  Q = P
569
570
  elif a > r:
570
571
  raise ValueError(_too_(Fmt.distant(a)))
@@ -4,7 +4,7 @@
4
4
  u'''A pure Python version of I{Karney}'s C++ classes U{GeodesicExact
5
5
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>}
6
6
  and U{GeodesicLineExact
7
- <https://geographiclib.sourceforge.io/C++/doc/classGeographicLib_1_1GeodesicLine.html>}.
7
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicLine.html>}.
8
8
 
9
9
  For more details, see the C++ U{GeographicLib<https://GeographicLib.SourceForge.io/C++/doc/index.html>}
10
10
  documentation, especially the U{Class List<https://GeographicLib.SourceForge.io/C++/doc/annotated.html>}
@@ -23,7 +23,7 @@ from pygeodesy.karney import Caps, GeodesicError
23
23
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
24
24
 
25
25
  __all__ = _ALL_LAZY.geodesicx + _ALL_DOCS(Caps, GeodesicError)
26
- __version__ = '24.09.06'
26
+ __version__ = '24.11.02'
27
27
 
28
28
  # **) MIT License
29
29
  #
@@ -19,10 +19,11 @@ from __future__ import division as _; del _ # PYCHOK semicolon
19
19
 
20
20
  from pygeodesy.basics import isodd, unsigned0
21
21
  from pygeodesy.constants import NAN, _0_0, _0_5, _720_0
22
+ from pygeodesy.internals import printf
22
23
  # from pygeodesy.interns import _COMMASPACE_ # from .lazily
23
24
  from pygeodesy.karney import Area3Tuple, _diff182, GeodesicError, \
24
25
  _norm180, _remainder, _sum3
25
- from pygeodesy.lazily import _ALL_DOCS, printf, _COMMASPACE_
26
+ from pygeodesy.lazily import _ALL_DOCS, _COMMASPACE_
26
27
  from pygeodesy.named import ADict, callername, _NamedBase, pairs
27
28
  from pygeodesy.props import Property, Property_RO, property_RO
28
29
  # from pygeodesy.streprs import pairs # from .named
@@ -30,7 +31,7 @@ from pygeodesy.props import Property, Property_RO, property_RO
30
31
  from math import fmod as _fmod
31
32
 
32
33
  __all__ = ()
33
- __version__ = '24.09.04'
34
+ __version__ = '24.10.14'
34
35
 
35
36
 
36
37
  class GeodesicAreaExact(_NamedBase):