pygeodesy 25.5.5__py2.py3-none-any.whl → 25.5.28__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 (88) hide show
  1. pygeodesy/__init__.py +186 -186
  2. pygeodesy/__main__.py +4 -3
  3. pygeodesy/albers.py +4 -4
  4. pygeodesy/auxilats/_CX_Rs.py +3 -3
  5. pygeodesy/auxilats/auxAngle.py +2 -2
  6. pygeodesy/auxilats/auxDLat.py +2 -2
  7. pygeodesy/auxilats/auxDST.py +2 -2
  8. pygeodesy/auxilats/auxLat.py +2 -2
  9. pygeodesy/auxilats/auxily.py +2 -2
  10. pygeodesy/azimuthal.py +2 -2
  11. pygeodesy/booleans.py +11 -11
  12. pygeodesy/cartesianBase.py +2 -2
  13. pygeodesy/clipy.py +2 -2
  14. pygeodesy/constants.py +7 -7
  15. pygeodesy/css.py +1 -1
  16. pygeodesy/datums.py +2 -2
  17. pygeodesy/deprecated/__init__.py +8 -8
  18. pygeodesy/deprecated/bases.py +2 -2
  19. pygeodesy/deprecated/rhumbBase.py +2 -2
  20. pygeodesy/deprecated/rhumbaux.py +2 -2
  21. pygeodesy/deprecated/rhumbsolve.py +2 -2
  22. pygeodesy/deprecated/rhumbx.py +2 -2
  23. pygeodesy/ecef.py +3 -4
  24. pygeodesy/ellipsoidalBase.py +2 -2
  25. pygeodesy/ellipsoidalBaseDI.py +7 -6
  26. pygeodesy/ellipsoidalExact.py +24 -29
  27. pygeodesy/ellipsoidalGeodSolve.py +19 -19
  28. pygeodesy/ellipsoidalKarney.py +22 -27
  29. pygeodesy/ellipsoidalNvector.py +4 -4
  30. pygeodesy/ellipsoidalVincenty.py +17 -15
  31. pygeodesy/ellipsoids.py +4 -4
  32. pygeodesy/elliptic.py +16 -11
  33. pygeodesy/errors.py +1 -1
  34. pygeodesy/etm.py +2 -2
  35. pygeodesy/fmath.py +9 -9
  36. pygeodesy/formy.py +2 -2
  37. pygeodesy/frechet.py +6 -6
  38. pygeodesy/fstats.py +2 -2
  39. pygeodesy/fsums.py +37 -28
  40. pygeodesy/gars.py +2 -3
  41. pygeodesy/geodesici.py +4 -4
  42. pygeodesy/geodesicw.py +27 -8
  43. pygeodesy/geodesicx/__init__.py +3 -3
  44. pygeodesy/geodesicx/gx.py +52 -48
  45. pygeodesy/geodesicx/gxarea.py +54 -65
  46. pygeodesy/geodesicx/gxbases.py +12 -2
  47. pygeodesy/geodesicx/gxline.py +10 -7
  48. pygeodesy/geoids.py +6 -6
  49. pygeodesy/hausdorff.py +5 -5
  50. pygeodesy/heights.py +5 -5
  51. pygeodesy/internals.py +2 -2
  52. pygeodesy/interns.py +5 -5
  53. pygeodesy/iters.py +1 -1
  54. pygeodesy/karney.py +28 -12
  55. pygeodesy/ktm.py +2 -2
  56. pygeodesy/latlonBase.py +3 -4
  57. pygeodesy/lazily.py +1 -1
  58. pygeodesy/lcc.py +3 -3
  59. pygeodesy/ltp.py +5 -5
  60. pygeodesy/mgrs.py +3 -3
  61. pygeodesy/namedTuples.py +3 -3
  62. pygeodesy/nvectorBase.py +2 -2
  63. pygeodesy/osgr.py +2 -2
  64. pygeodesy/points.py +2 -3
  65. pygeodesy/props.py +18 -18
  66. pygeodesy/resections.py +30 -24
  67. pygeodesy/rhumb/aux_.py +2 -2
  68. pygeodesy/rhumb/bases.py +3 -3
  69. pygeodesy/rhumb/ekx.py +3 -4
  70. pygeodesy/rhumb/solve.py +2 -2
  71. pygeodesy/simplify.py +2 -2
  72. pygeodesy/solveBase.py +2 -2
  73. pygeodesy/sphericalBase.py +8 -8
  74. pygeodesy/sphericalNvector.py +19 -16
  75. pygeodesy/sphericalTrigonometry.py +24 -24
  76. pygeodesy/trf.py +4 -4
  77. pygeodesy/triaxials.py +2 -2
  78. pygeodesy/units.py +7 -8
  79. pygeodesy/utily.py +2 -2
  80. pygeodesy/utmupsBase.py +2 -2
  81. pygeodesy/vector2d.py +14 -8
  82. pygeodesy/vector3d.py +3 -3
  83. pygeodesy/webmercator.py +2 -2
  84. {pygeodesy-25.5.5.dist-info → pygeodesy-25.5.28.dist-info}/METADATA +16 -16
  85. pygeodesy-25.5.28.dist-info/RECORD +119 -0
  86. pygeodesy-25.5.5.dist-info/RECORD +0 -119
  87. {pygeodesy-25.5.5.dist-info → pygeodesy-25.5.28.dist-info}/WHEEL +0 -0
  88. {pygeodesy-25.5.5.dist-info → pygeodesy-25.5.28.dist-info}/top_level.txt +0 -0
pygeodesy/fsums.py CHANGED
@@ -37,7 +37,7 @@ respectively C{ValueError} exceptions. However, in that case I{non-finite}
37
37
  results may differ from Python's C{math.fsum} results.
38
38
  '''
39
39
  # make sure int/int division yields float quotient, see .basics
40
- from __future__ import division as _; del _ # PYCHOK semicolon
40
+ from __future__ import division as _; del _ # noqa: E702 ;
41
41
 
42
42
  from pygeodesy.basics import _gcd, isbool, iscomplex, isint, isscalar, \
43
43
  _signOf, itemsorted, signOf, _xiterable
@@ -48,7 +48,7 @@ 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, _envPYGEODESY, _passarg, typename
51
+ from pygeodesy.internals import _enquote, _envPYGEODESY, _passarg, typename # _sizeof
52
52
  from pygeodesy.interns import NN, _arg_, _COMMASPACE_, _DMAIN_, _DOT_, _from_, \
53
53
  _not_finite_, _SPACE_, _std_, _UNDER_
54
54
  # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .named
@@ -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__ = '25.04.26'
67
+ __version__ = '25.05.12'
68
68
 
69
69
  from pygeodesy.interns import (
70
70
  _PLUS_ as _add_op_, # in .auxilats.auxAngle
@@ -230,13 +230,13 @@ def f2product(two=None):
230
230
  def _Fsumf_(*xs): # in .auxLat, ...
231
231
  '''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
232
232
  '''
233
- return Fsum()._facc_scalarf(xs, up=False)
233
+ return Fsum()._facc_xsum(xs, up=False)
234
234
 
235
235
 
236
236
  def _Fsum1f_(*xs): # in .albers
237
237
  '''(INTERNAL) An C{Fsum(xs)}, all C{scalar}, an L{Fsum} or L{Fsum2Tuple}, 1-primed.
238
238
  '''
239
- return Fsum()._facc_scalarf(_1primed(xs), origin=-1, up=False)
239
+ return Fsum()._facc_xsum(_1primed(xs), origin=-1, up=False)
240
240
 
241
241
 
242
242
  def _halfeven(s, r, p):
@@ -585,7 +585,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
585
585
  with quotient C{div} an C{int} in Python 3+ or C{float}
586
586
  in Python 2- and remainder C{mod} an L{Fsum} instance.
587
587
 
588
- @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} modulus.
588
+ @arg other: Modulus (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
589
589
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
590
590
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
591
591
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
@@ -623,7 +623,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
623
623
  def __floordiv__(self, other):
624
624
  '''Return C{B{self} // B{other}} as an L{Fsum}.
625
625
 
626
- @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
626
+ @arg other: Divisor (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
627
627
 
628
628
  @return: The C{floor} quotient (L{Fsum}).
629
629
 
@@ -632,6 +632,10 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
632
632
  f = self._copyd(self.__floordiv__)
633
633
  return f._floordiv(other, _floordiv_op_)
634
634
 
635
+ # def __format__(self, *other): # PYCHOK no cover
636
+ # '''Not implemented.'''
637
+ # return _NotImplemented(self, *other)
638
+
635
639
  def __ge__(self, other):
636
640
  '''Return C{(B{self} >= B{other})}, see C{__eq__}.
637
641
  '''
@@ -672,7 +676,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
672
676
  def __ifloordiv__(self, other):
673
677
  '''Apply C{B{self} //= B{other}} to this instance.
674
678
 
675
- @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
679
+ @arg other: Divisor (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
676
680
 
677
681
  @return: This instance, updated (L{Fsum}).
678
682
 
@@ -696,7 +700,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
696
700
  def __imod__(self, other):
697
701
  '''Apply C{B{self} %= B{other}} to this instance.
698
702
 
699
- @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} modulus.
703
+ @arg other: Modulus (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
700
704
 
701
705
  @return: This instance, updated (L{Fsum}).
702
706
 
@@ -707,7 +711,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
707
711
  def __imul__(self, other):
708
712
  '''Apply C{B{self} *= B{other}} to this instance.
709
713
 
710
- @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} factor.
714
+ @arg other: Factor (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
711
715
 
712
716
  @return: This instance, updated (L{Fsum}).
713
717
 
@@ -736,7 +740,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
736
740
  def __ipow__(self, other, *mod, **raiser_RESIDUAL): # PYCHOK 2 vs 3 args
737
741
  '''Apply C{B{self} **= B{other}} to this instance.
738
742
 
739
- @arg other: The exponent (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
743
+ @arg other: Exponent (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
740
744
  @arg mod: Optional modulus (C{int} or C{None}) for the 3-argument
741
745
  C{pow(B{self}, B{other}, B{mod})} version.
742
746
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
@@ -798,7 +802,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
798
802
  def __itruediv__(self, other, **raiser_RESIDUAL):
799
803
  '''Apply C{B{self} /= B{other}} to this instance.
800
804
 
801
- @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
805
+ @arg other: Divisor (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
802
806
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
803
807
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
804
808
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
@@ -917,7 +921,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
917
921
  f = self._rcopyd(other, self.__rfloordiv__)
918
922
  return f._floordiv(self, _floordiv_op_)
919
923
 
920
- def __rmatmul__(self, other): # PYCHOK no coveS
924
+ def __rmatmul__(self, other): # PYCHOK no cover
921
925
  '''Not implemented.'''
922
926
  return _NotImplemented(self, other)
923
927
 
@@ -970,6 +974,11 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
970
974
  f = self._rcopyd(other, self.__rtruediv__)
971
975
  return f._ftruediv(self, _truediv_op_, **raiser_RESIDUAL)
972
976
 
977
+ # def __sizeof__(self):
978
+ # '''Return the size of this instance (C{int} bytes}).
979
+ # '''
980
+ # return _sizeof(self._ps) + _sizeof(self._n)
981
+
973
982
  def __str__(self):
974
983
  '''Return the default C{str(self)}.
975
984
  '''
@@ -990,7 +999,7 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
990
999
  def __truediv__(self, other, **raiser_RESIDUAL):
991
1000
  '''Return C{B{self} / B{other}} as an L{Fsum}.
992
1001
 
993
- @arg other: An L{Fsum}, L{Fsum2Tuple} or C{scalar} divisor.
1002
+ @arg other: Divisor (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
994
1003
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
995
1004
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
996
1005
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
@@ -1221,14 +1230,6 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1221
1230
  '''
1222
1231
  return self._facc_scalar(xs, **up)
1223
1232
 
1224
- def _facc_scalarf(self, xs, up=True, **origin_which):
1225
- '''(INTERNAL) Accumulate all C{xs}, each C{scalar}, an L{Fsum} or
1226
- L{Fsum2Tuple}, like function C{_xsum}.
1227
- '''
1228
- fs = _xs(xs, **_x_isfine(self.nonfinitesOK, _Cdot=type(self),
1229
- **origin_which)) # PYCHOK yield
1230
- return self._facc_scalar(fs, up=up)
1231
-
1232
1233
  # def _facc_up(self, up=True):
1233
1234
  # '''(INTERNAL) Update the C{partials}, by removing
1234
1235
  # and re-accumulating the final C{partial}.
@@ -1243,6 +1244,14 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1243
1244
  # break
1244
1245
  # return self._update() if up else self
1245
1246
 
1247
+ def _facc_xsum(self, xs, up=True, **origin_which):
1248
+ '''(INTERNAL) Accumulate all C{xs}, each C{scalar}, an L{Fsum}
1249
+ or L{Fsum2Tuple}, like function C{_xsum}.
1250
+ '''
1251
+ fs = _xs(xs, **_x_isfine(self.nonfinitesOK, _Cdot=type(self),
1252
+ **origin_which)) # PYCHOK yield
1253
+ return self._facc_scalar(fs, up=up)
1254
+
1246
1255
  def fadd(self, xs=()):
1247
1256
  '''Add an iterable's items to this instance.
1248
1257
 
@@ -1533,17 +1542,17 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1533
1542
  def fover(self, over, **raiser_RESIDUAL):
1534
1543
  '''Apply C{B{self} /= B{over}} and summate.
1535
1544
 
1536
- @arg over: An L{Fsum} or C{scalar} denominator.
1545
+ @arg over: Divisor (C{scalar}, an L{Fsum} or L{Fsum2Tuple}).
1537
1546
  @kwarg raiser_RESIDUAL: Use C{B{raiser}=False} to ignore
1538
1547
  L{ResidualError}s (C{bool}) and C{B{RESIDUAL}=scalar}
1539
1548
  to override the current L{RESIDUAL<Fsum.RESIDUAL>}.
1540
1549
 
1541
- @return: Precision running sum (C{float}).
1550
+ @return: Precision running quotient sum (C{float}).
1542
1551
 
1543
1552
  @raise ResidualError: Non-zero, significant residual or invalid
1544
1553
  B{C{RESIDUAL}}.
1545
1554
 
1546
- @see: Methods L{Fsum.fsum} and L{Fsum.__itruediv__}.
1555
+ @see: Methods L{Fsum.fdiv}, L{Fsum.__itruediv__} and L{Fsum.fsum}.
1547
1556
  '''
1548
1557
  return float(self.fdiv(over, **raiser_RESIDUAL)._fprs)
1549
1558
 
@@ -1837,19 +1846,19 @@ class Fsum(_Named): # sync __methods__ with .vector3dBase.Vector3dBase, .fstats
1837
1846
  '''Like method L{Fsum.fsum_} iff I{all} C{B{xs}}, each I{known to be}
1838
1847
  C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
1839
1848
  '''
1840
- return self._facc_scalarf(xs, which=self.fsumf_)._fprs # origin=1?
1849
+ return self._facc_xsum(xs, which=self.fsumf_)._fprs # origin=1?
1841
1850
 
1842
1851
  def Fsumf_(self, *xs):
1843
1852
  '''Like method L{Fsum.Fsum_} iff I{all} C{B{xs}}, each I{known to be}
1844
1853
  C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
1845
1854
  '''
1846
- return self._facc_scalarf(xs, which=self.Fsumf_)._copyd(self.Fsumf_) # origin=1?
1855
+ return self._facc_xsum(xs, which=self.Fsumf_)._copyd(self.Fsumf_) # origin=1?
1847
1856
 
1848
1857
  def fsum2f_(self, *xs):
1849
1858
  '''Like method L{Fsum.fsum2_} iff I{all} C{B{xs}}, each I{known to be}
1850
1859
  C{scalar}, an L{Fsum} or L{Fsum2Tuple}.
1851
1860
  '''
1852
- return self._fsum2(xs, self._facc_scalarf, which=self.fsum2f_) # origin=1?
1861
+ return self._fsum2(xs, self._facc_xsum, which=self.fsum2f_) # origin=1?
1853
1862
 
1854
1863
  # ftruediv = __itruediv__ # for naming consistency?
1855
1864
 
pygeodesy/gars.py CHANGED
@@ -15,8 +15,7 @@ Transcoded from I{Charles Karney}'s C++ class U{GARS
15
15
  '''
16
16
 
17
17
  from pygeodesy.basics import isstr, _splituple, typename
18
- from pygeodesy.constants import _off90, _1_over, _0_5, \
19
- _1_0 # PYCHOK used!
18
+ from pygeodesy.constants import _off90, _1_over, _0_5
20
19
  from pygeodesy.errors import _ValueError, _xkwds, _xStrError
21
20
  # from pygeodesy.internals import typename # from .basics
22
21
  from pygeodesy.interns import NN, _0to9_, _AtoZnoIO_, _INV_
@@ -30,7 +29,7 @@ from pygeodesy.units import Int_, Lat, Lon, Precision_, Scalar_, Str
30
29
  from math import floor
31
30
 
32
31
  __all__ = _ALL_LAZY.gars
33
- __version__ = '25.04.14'
32
+ __version__ = '25.05.07'
34
33
 
35
34
  _Digits = _0to9_
36
35
  _LatLen = 2
pygeodesy/geodesici.py CHANGED
@@ -23,7 +23,7 @@ and I{S. Baselga Moreno & J.C. Martinez-Llario}'s U{Intersection and point-to-li
23
23
  on the ellipsoid<https://riunet.UPV.ES/bitstream/handle/10251/122902/Revised_Manuscript.pdf>}.
24
24
  '''
25
25
  # make sure int/int division yields float quotient
26
- from __future__ import division as _; del _ # PYCHOK semicolon
26
+ from __future__ import division as _; del _ # noqa: E702 ;
27
27
 
28
28
  from pygeodesy.basics import _copy, _enumereverse, map1, \
29
29
  _xinstanceof, _xor, typename
@@ -57,7 +57,7 @@ from pygeodesy.utily import atan2, sincos2, fabs, radians
57
57
  # from math import ceil as _ceil, fabs, radians # .fsums, .utily
58
58
 
59
59
  __all__ = _ALL_LAZY.geodesici
60
- __version__ = '25.04.14'
60
+ __version__ = '25.05.12'
61
61
 
62
62
  _0t = 0, # int
63
63
  _1_1t = -1, +1
@@ -1560,7 +1560,7 @@ if __name__ == _DMAIN_: # MCCABE 14
1560
1560
 
1561
1561
  _isopt = re.compile('^[-]+[a-z]*$', flags=re.IGNORECASE).match
1562
1562
 
1563
- I = Intersector(GeodesicExact()) # PYCHOK I
1563
+ I = Intersector(GeodesicExact()) # noqa: E741 I is eye
1564
1564
  M = m = _R = None
1565
1565
  _T = _V = _h = _C = False
1566
1566
 
@@ -1584,7 +1584,7 @@ if __name__ == _DMAIN_: # MCCABE 14
1584
1584
  elif arg == _R__ and args:
1585
1585
  _R = args.pop(0)
1586
1586
  elif _starts('--Tool', arg):
1587
- I = Intersectool() # PYCHOK I
1587
+ I = Intersectool() # noqa: E741 I is eye
1588
1588
  if _V:
1589
1589
  I.verbose = True
1590
1590
  if not _Xables.X_OK(I.IntersectTool):
pygeodesy/geodesicw.py CHANGED
@@ -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__ = '25.04.14'
42
+ __version__ = '25.05.28'
43
43
 
44
44
  _plumb_ = 'plumb'
45
45
  _TRIPS = 65
@@ -96,6 +96,28 @@ class _gWrapped(_kWrapped):
96
96
  if name:
97
97
  self._name, _ = _name2__(name, _or_nameof=E)
98
98
 
99
+ def Area(self, polyline=False, **name): # like GeodesicExact.Area
100
+ '''Return a C{PolygonArea} instance with method C{Compute} extended.
101
+ '''
102
+ _AreaBase = _wrapped._PolygonArea # in .karney._kwrapped
103
+
104
+ class _PolygonArea(_AreaBase):
105
+ # def __init__(self, *earth_polyline):
106
+ # _PolygonArea.__init__(self, *earth_polyline)
107
+
108
+ def Compute(self, reverse=False, sign=True, polar=False):
109
+ '''Use C{B{polar}=True} to adjust the area, see function
110
+ L{areaOf<pygeodesy.geodesicx.gxarea.areaOf>}.
111
+ '''
112
+ n, p, a = _AreaBase.Compute(self, reverse=reverse, sign=sign)
113
+ if polar: # see .geodesicx.gxarea.GeodesicAreaExact._reduced
114
+ a += _copysign(self.area0 * _0_5 * n, a)
115
+ return n, p, a
116
+
117
+ A = _PolygonArea(self, polyline)
118
+ A.name = _name2__(name, _or_nameof=self)
119
+ return A
120
+
99
121
  def ArcDirect(self, lat1, lon1, azi1, a12, outmask=Caps.STANDARD): # PYCHOK no cover
100
122
  '''Return the C{_Geodesic.ArcDirect} result as L{GDict}.
101
123
  '''
@@ -108,8 +130,6 @@ class _gWrapped(_kWrapped):
108
130
  '''
109
131
  return self._GenDirectLine(lat1, lon1, azi1, True, a12, caps, **name)
110
132
 
111
- Area = _Geodesic.Polygon # like GeodesicExact.Area
112
-
113
133
  @property_RO
114
134
  def datum(self):
115
135
  '''Get this geodesic's datum (C{Datum}).
@@ -257,9 +277,8 @@ class _gWrapped(_kWrapped):
257
277
  '''
258
278
  return self._name
259
279
 
260
- # Polygon = _Geodesic.Polygon
261
-
262
- WGS84 = None # _EWGS84.geodesicw recusion
280
+ Polygon = Area
281
+ WGS84 = None # _EWGS84.geodesicw recusion
263
282
 
264
283
  # Geodesic.ArcDirect.__doc__ = _Geodesic.ArcDirect.__doc__
265
284
  # Geodesic.Direct.__doc__ = _Geodesic.Direct.__doc__
@@ -461,7 +480,7 @@ class Geodesic(_gWrapped): # overwritten by 1st instance
461
480
  @kwarg name: Optional C{B{name}=NN} (C{str}).
462
481
  '''
463
482
  g = _wrapped.Geodesic(a_ellipsoid, f=f, **name)
464
- _MODS.geodesicw.Geodesic = g.__class__ # overwrite class
483
+ _MODS.geodesicw.Geodesic = type(g) # overwrite class
465
484
  return g
466
485
 
467
486
 
@@ -485,7 +504,7 @@ class GeodesicLine(_gWrapped): # overwritten by 1st instance
485
504
  @kwarg name: Optional C{B{name}=NN} (C{str}).
486
505
  '''
487
506
  gl = _wrapped.GeodesicLine(geodesic, lat1, lon1, azi1, caps=caps, **name)
488
- _MODS.geodesicw.GeodesicLine = gl.__class__ # overwrite class
507
+ _MODS.geodesicw.GeodesicLine = type(gl) # overwrite class
489
508
  return gl
490
509
 
491
510
 
@@ -17,13 +17,13 @@ respectively C{GeodesicLine} from I{Karney}'s Python implementation U{geographic
17
17
  L{pygeodesy.geodesicw} and L{pygeodesy.karney}.
18
18
  '''
19
19
 
20
- from pygeodesy.geodesicx.gx import GeodesicExact, GeodesicLineExact # PYCHOK exported
21
- from pygeodesy.geodesicx.gxarea import GeodesicAreaExact, PolygonArea # PYCHOK exported
20
+ from pygeodesy.geodesicx.gx import GeodesicExact, GeodesicLineExact # noqa: F401
21
+ from pygeodesy.geodesicx.gxarea import GeodesicAreaExact, PolygonArea # noqa: F401
22
22
  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__ = '25.04.14'
26
+ __version__ = '25.05.12'
27
27
 
28
28
  # **) MIT License
29
29
  #
pygeodesy/geodesicx/gx.py CHANGED
@@ -13,7 +13,7 @@ and licensed under the MIT/X11 License. For more information, see the
13
13
  U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
14
14
  '''
15
15
  # make sure int/int division yields float quotient
16
- from __future__ import division as _; del _ # PYCHOK semicolon
16
+ from __future__ import division as _; del _ # noqa: E702 ;
17
17
 
18
18
  # A copy of comments from Karney's C{GeodesicExact.cpp}:
19
19
  #
@@ -44,11 +44,11 @@ from pygeodesy.constants import EPS, EPS0, EPS02, MANT_DIG, NAN, PI, _EPSqrt, \
44
44
  from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
45
45
  # from pygeodesy.ellipsoids import _EWGS84 # from .datums
46
46
  from pygeodesy.errors import GeodesicError, _xkwds_pop2
47
- from pygeodesy.fmath import hypot as _hypot, Fmt
47
+ from pygeodesy.fmath import fdot_, hypot, hypot2, Fmt
48
48
  from pygeodesy.fsums import fsumf_, fsum1f_
49
49
  from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
50
50
  _sincos12, _sin1cos2, _sinf1cos2d, \
51
- _TINY, _xnC4
51
+ _TINY, _toNAN, _xnC4
52
52
  from pygeodesy.geodesicx.gxline import _GeodesicLineExact, _update_glXs
53
53
  # from pygeodesy.internals import typename # from .basics
54
54
  from pygeodesy.interns import NN, _DOT_, _UNDER_
@@ -65,7 +65,7 @@ from pygeodesy.utily import atan2, atan2d as _atan2d_reverse, _unrollon, \
65
65
  from math import copysign, cos, degrees, fabs, radians, sqrt
66
66
 
67
67
  __all__ = ()
68
- __version__ = '25.04.14'
68
+ __version__ = '25.05.28'
69
69
 
70
70
  _MAXIT1 = 20
71
71
  _MAXIT2 = 10 + _MAXIT1 + MANT_DIG # MANT_DIG == C++ digits
@@ -96,15 +96,12 @@ def _eTOL2(f):
96
96
  # (bet1 + bet2) / 2, the relative error in the azimuth
97
97
  # consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2.
98
98
  # (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000.
99
-
100
- # For a given f and sig12, the max error occurs for lines
101
- # near the pole. If the old rule for computing dnm = (dn1
102
- # + dn2)/2 is used, then the error increases by a factor of
103
- # 2.) Setting this equal to epsilon gives sig12 = etol2.
104
-
105
- # Here 0.1 is a safety factor (error decreased by 100) and
106
- # max(0.001, abs(f)) stops etol2 getting too large in the
107
- # nearly spherical case.
99
+ # For a given f and sig12, the max error occurs for lines
100
+ # near the pole. If the old rule for computing dnm = (dn1 +
101
+ # dn2)/2 is used, then the error increases by a factor of 2.)
102
+ # Setting this equal to epsilon gives sig12 = eTOL2. Here,
103
+ # safety factor 0.1 (error decreased by 100) and max(0.001, abs(f))
104
+ # stops eTOL2 getting too large in the nearly spherical case.
108
105
  t = min(_1_0, _1_0 - f * _0_5) * max(_0_001, fabs(f)) * _0_5
109
106
  return _TOL3 / (sqrt(t) if t > EPS02 else EPS0)
110
107
 
@@ -216,11 +213,10 @@ class GeodesicExact(_GeodesicBase):
216
213
  return GeodesicLineExact(self, lat1, lon1, azi1, caps=caps, **name)._GenSet(self._debug, a12=a12)
217
214
 
218
215
  def Area(self, polyline=False, **name):
219
- '''Set up a L{GeodesicAreaExact} to compute area and
220
- perimeter of a polygon.
216
+ '''Set up a L{GeodesicAreaExact} to compute area and perimeter of a polygon.
221
217
 
222
- @kwarg polyline: If C{True}, compute the perimeter only, otherwise
223
- the perimeter and area (C{bool}).
218
+ @kwarg polyline: If C{True}, compute the perimeter only, otherwise the
219
+ perimeter and area (C{bool}).
224
220
  @kwarg name: Optional C{B{name}=NN} (C{str}).
225
221
 
226
222
  @return: A L{GeodesicAreaExact} instance.
@@ -429,17 +425,21 @@ class GeodesicExact(_GeodesicBase):
429
425
  def _eF_reset_cHe2_f1(self, x, y):
430
426
  '''(INTERNAL) Reset elliptic function and return M{cH * e2 / f1 * ...}.
431
427
  '''
432
- self._eF_reset_k2(x)
433
- return y * self._eF.cH * self._e2_f1
428
+ if isnan(x):
429
+ y = NAN
430
+ else:
431
+ self._eF_reset_k2(x)
432
+ y *= self._eF.cH * self._e2_f1
433
+ return y
434
434
 
435
435
  def _eF_reset_k2(self, x):
436
436
  '''(INTERNAL) Reset elliptic function and return C{k2}.
437
437
  '''
438
438
  ep2 = self.ep2
439
- k2 = x**2 * ep2 # see .gxline._GeodesicLineExact._eF
440
- self._eF.reset(k2=-k2, alpha2=-ep2) # kp2, alphap2 defaults
439
+ x *= x * ep2 # see .gxline._GeodesicLineExact._eF
440
+ self._eF.reset(k2=-x, alpha2=-ep2) # kp2, alphap2 defaults
441
441
  _update_glXs(self) # zap cached/memoized _GeodesicLineExact attrs
442
- return k2
442
+ return x
443
443
 
444
444
  @Property_RO
445
445
  def ellipsoid(self):
@@ -499,6 +499,7 @@ class GeodesicExact(_GeodesicBase):
499
499
  if self._debug: # PYCHOK no cover
500
500
  outmask |= Cs._DEBUG_INVERSE & self._debug
501
501
  outmask &= Cs._OUT_MASK # incl. _SALP_CALPs_ and _DEBUG_
502
+ toNAN = _toNAN(outmask, lat1, lon1, lat2, lon2)
502
503
  # compute longitude difference carefully (with _diff182):
503
504
  # result is in [-180, +180] but -180 is only for west-going
504
505
  # geodesics, +180 is for east-going and meridional geodesics
@@ -700,7 +701,9 @@ class GeodesicExact(_GeodesicBase):
700
701
  eFk2=eF.k2, eFa2=eF.alpha2)
701
702
  p.update(r) # r overrides p
702
703
  r = p.toGDict()
703
- return self._iter2tion(r, **p)
704
+
705
+ r = self._iter2tion(r, **p)
706
+ return r._toNAN(outmask) if toNAN else r
704
707
 
705
708
  def _GenDirect(self, lat1, lon1, azi1, arcmode, s12_a12, outmask=Caps.STANDARD):
706
709
  '''(INTERNAL) The general I{Inverse} geodesic calculation.
@@ -805,8 +808,7 @@ class GeodesicExact(_GeodesicBase):
805
808
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1GeodesicExact.html>} and
806
809
  Python U{Geodesic.InverseLine<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
807
810
  '''
808
- Cs = Caps
809
- r = self._GDictInverse(lat1, lon1, lat2, lon2, caps | Cs._SALP_CALPs_)
811
+ r = self._GDictInverse(lat1, lon1, lat2, lon2, caps | Caps._SALP_CALPs_)
810
812
  return GeodesicLineExact(self, lat1, lon1, None, caps=caps, _s_calp1=(r.salp1, r.calp1),
811
813
  **name)._GenSet(self._debug, **r)
812
814
 
@@ -839,12 +841,12 @@ class GeodesicExact(_GeodesicBase):
839
841
  # (tan(bet1/2) + tan(bet2/2)) /
840
842
  # (tan(bet1/2) * tan(bet2/2) + 1))
841
843
  # with tan(x/2) = sin(x) / (1 + cos(x))
842
- dbet1 = p.cbet1 + _1_0
843
- dbet2 = p.cbet2 + _1_0
844
- domg12 = comg12 + _1_0
845
- salp12 = (p.sbet1 * dbet2 + dbet1 * p.sbet2) * somg12
846
- calp12 = (p.sbet1 * p.sbet2 + dbet1 * dbet2) * domg12
847
- alp12 = atan2(salp12, calp12) * _2_0
844
+ dbet1 = p.cbet1 + _1_0
845
+ dbet2 = p.cbet2 + _1_0
846
+ domg12 = comg12 + _1_0
847
+ salp12 = fdot_(p.sbet1, dbet2, dbet1, p.sbet2) * somg12
848
+ calp12 = fdot_(p.sbet1, p.sbet2, dbet1, dbet2) * domg12
849
+ alp12 = atan2(salp12, calp12) * _2_0
848
850
  else:
849
851
  # alp12 = alp2 - alp1, used in atan2, no need to normalize
850
852
  salp12, calp12 = _sincos12(salp1, calp1, salp2, calp2)
@@ -870,7 +872,7 @@ class GeodesicExact(_GeodesicBase):
870
872
  and C{p.set_sigs} updated for Newton, C{sig12=None}.
871
873
  '''
872
874
  sig12 = None # use Newton
873
- salp1 = calp1 = salp2 = calp2 = dnm = NAN
875
+ salp1 = calp1 = salp2 = calp2 = NAN
874
876
 
875
877
  # bet12 = bet2 - bet1 in [0, PI)
876
878
  sbet12, cbet12 = _sincos12(p.sbet1, p.cbet1, p.sbet2, p.cbet2)
@@ -878,12 +880,15 @@ class GeodesicExact(_GeodesicBase):
878
880
  if shortline:
879
881
  # sin((bet1 + bet2)/2)^2 = (sbet1 + sbet2)^2 / (
880
882
  # (cbet1 + cbet2)^2 + (sbet1 + sbet2)^2)
881
- t = (p.sbet1 + p.sbet2)**2
882
- s = t / ((p.cbet1 + p.cbet2)**2 + t)
883
- dnm = sqrt(_1_0 + self.ep2 * s)
883
+ t = p.sbet1 + p.sbet2
884
+ if t:
885
+ t *= t / hypot2(t, p.cbet1 + p.cbet2)
886
+ dnm = sqrt(self.ep2 * t + _1_0)
887
+ else:
888
+ dnm = _1_0
884
889
  somg12, comg12 = _sincos2(lam12 / (self.f1 * dnm))
885
890
  else:
886
- somg12, comg12 = p.slam12, p.clam12
891
+ somg12, comg12, dnm = p.slam12, p.clam12, NAN
887
892
 
888
893
  # bet12a = bet2 + bet1 in (-PI, 0], note -sbet1
889
894
  sbet12a, cbet12a = _sincos12(-p.sbet1, p.cbet1, p.sbet2, p.cbet2)
@@ -894,8 +899,8 @@ class GeodesicExact(_GeodesicBase):
894
899
  salp1 = p.cbet2 * somg12
895
900
  calp1 = (sbet12a - t) if comg12 < 0 else (sbet12 + t)
896
901
 
897
- ssig12 = _hypot(salp1, calp1)
898
- csig12 = p.sbet1 * p.sbet2 + p.cbet1 * p.cbet2 * comg12
902
+ ssig12 = hypot(salp1, calp1)
903
+ csig12 = fdot_(p.sbet1, p.sbet2, p.cbet1, p.cbet2 * comg12)
899
904
 
900
905
  if shortline and ssig12 < self._eTOL2: # really short lines
901
906
  t = c if comg12 < 0 else s
@@ -970,8 +975,8 @@ class GeodesicExact(_GeodesicBase):
970
975
  #
971
976
  # omg12 is near PI, estimate work with omg12a = PI - omg12
972
977
  k = _Astroid(x, y)
973
- sca *= (y * (k + _1_0) / k) if f < 0 else \
974
- (x * k / (k + _1_0))
978
+ k1 = _1_0 + k
979
+ sca *= (y * k1 / k) if f < 0 else (x * k / k1)
975
980
  s, c = _sincos2(-sca) # omg12a
976
981
  # update spherical estimate of alp1 using omg12 instead of lam12
977
982
  salp1 = p.cbet2 * s
@@ -1082,16 +1087,15 @@ class GeodesicExact(_GeodesicBase):
1082
1087
  # Missing a factor of self.b. Add parens around
1083
1088
  # (csig1 * ssig2) and (ssig1 * csig2) to ensure
1084
1089
  # accurate cancellation for coincident points.
1085
- m12b = fsum1f_(p.dn2 * (p.csig1 * p.ssig2),
1086
- -p.dn1 * (p.ssig1 * p.csig2),
1087
- J12 * (p.csig1 * p.csig2))
1090
+ m12b = fdot_(p.dn2, (p.csig1 * p.ssig2),
1091
+ -p.dn1, (p.ssig1 * p.csig2),
1092
+ J12, (p.csig1 * p.csig2))
1088
1093
  if (outmask & Cs.GEODESICSCALE):
1089
- M12 = M21 = p.ssig1 * p.ssig2 + \
1090
- p.csig1 * p.csig2
1094
+ M12 = M21 = fdot_(p.ssig1, p.ssig2, p.csig1, p.csig2)
1091
1095
  t = (p.cbet1 - p.cbet2) * self.ep2 * \
1092
1096
  (p.cbet1 + p.cbet2) / (p.dn1 + p.dn2)
1093
- M12 += (p.ssig2 * t + p.csig2 * J12) * p.ssig1 / p.dn1
1094
- M21 -= (p.ssig1 * t + p.csig1 * J12) * p.ssig2 / p.dn2
1097
+ M12 += fdot_(p.ssig2, t, p.csig2, J12) * p.ssig1 / p.dn1
1098
+ M21 -= fdot_(p.ssig1, t, p.csig1, J12) * p.ssig2 / p.dn2
1095
1099
 
1096
1100
  return s12b, m12b, m0, M12, M21
1097
1101
 
@@ -1310,7 +1314,7 @@ def _Astroid(x, y):
1310
1314
  u = _cbrt(S * _2_0) # == T3 + _copysign(abs(S), T3)
1311
1315
  else:
1312
1316
  u = _0_0
1313
- v = _hypot(u, y) # sqrt(u**2 + q)
1317
+ v = hypot(u, y) # sqrt(u**2 + q)
1314
1318
  # avoid loss of accuracy when u < 0
1315
1319
  u = (q / (v - u)) if u < 0 else (v + u)
1316
1320
  w = (u - q) / (v + v) # positive?