pygeodesy 24.10.24__py2.py3-none-any.whl → 24.12.12__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 (118) hide show
  1. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.12.12.dist-info}/METADATA +6 -6
  2. PyGeodesy-24.12.12.dist-info/RECORD +118 -0
  3. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.12.12.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +5 -5
  5. pygeodesy/__main__.py +1 -1
  6. pygeodesy/albers.py +5 -5
  7. pygeodesy/auxilats/_CX_4.py +1 -1
  8. pygeodesy/auxilats/_CX_6.py +1 -1
  9. pygeodesy/auxilats/_CX_8.py +1 -1
  10. pygeodesy/auxilats/_CX_Rs.py +1 -1
  11. pygeodesy/auxilats/__init__.py +1 -1
  12. pygeodesy/auxilats/__main__.py +1 -1
  13. pygeodesy/auxilats/auxAngle.py +5 -5
  14. pygeodesy/auxilats/auxDLat.py +6 -6
  15. pygeodesy/auxilats/auxDST.py +2 -2
  16. pygeodesy/auxilats/auxLat.py +5 -5
  17. pygeodesy/auxilats/auxily.py +2 -2
  18. pygeodesy/azimuthal.py +55 -65
  19. pygeodesy/basics.py +35 -34
  20. pygeodesy/booleans.py +37 -37
  21. pygeodesy/cartesianBase.py +26 -65
  22. pygeodesy/clipy.py +1 -1
  23. pygeodesy/constants.py +7 -7
  24. pygeodesy/css.py +8 -9
  25. pygeodesy/datums.py +1 -1
  26. pygeodesy/deprecated/__init__.py +2 -2
  27. pygeodesy/deprecated/bases.py +1 -1
  28. pygeodesy/deprecated/classes.py +10 -10
  29. pygeodesy/deprecated/consterns.py +1 -1
  30. pygeodesy/deprecated/datum.py +1 -1
  31. pygeodesy/deprecated/functions.py +23 -13
  32. pygeodesy/deprecated/nvector.py +1 -1
  33. pygeodesy/deprecated/rhumbBase.py +1 -1
  34. pygeodesy/deprecated/rhumbaux.py +1 -1
  35. pygeodesy/deprecated/rhumbsolve.py +1 -1
  36. pygeodesy/deprecated/rhumbx.py +1 -1
  37. pygeodesy/dms.py +1 -1
  38. pygeodesy/ecef.py +63 -69
  39. pygeodesy/elevations.py +1 -1
  40. pygeodesy/ellipsoidalBase.py +106 -121
  41. pygeodesy/ellipsoidalBaseDI.py +115 -119
  42. pygeodesy/ellipsoidalExact.py +36 -38
  43. pygeodesy/ellipsoidalGeodSolve.py +1 -1
  44. pygeodesy/ellipsoidalKarney.py +1 -1
  45. pygeodesy/ellipsoidalNvector.py +1 -1
  46. pygeodesy/ellipsoidalVincenty.py +6 -5
  47. pygeodesy/ellipsoids.py +7 -8
  48. pygeodesy/elliptic.py +6 -6
  49. pygeodesy/epsg.py +1 -1
  50. pygeodesy/errors.py +25 -25
  51. pygeodesy/etm.py +84 -76
  52. pygeodesy/fmath.py +54 -51
  53. pygeodesy/formy.py +74 -106
  54. pygeodesy/frechet.py +1 -1
  55. pygeodesy/fstats.py +1 -1
  56. pygeodesy/fsums.py +82 -72
  57. pygeodesy/gars.py +1 -1
  58. pygeodesy/geodesici.py +4 -4
  59. pygeodesy/geodesicw.py +16 -15
  60. pygeodesy/geodesicx/_C4_24.py +2 -2
  61. pygeodesy/geodesicx/_C4_27.py +2 -2
  62. pygeodesy/geodesicx/_C4_30.py +2 -2
  63. pygeodesy/geodesicx/__init__.py +3 -3
  64. pygeodesy/geodesicx/__main__.py +1 -1
  65. pygeodesy/geodesicx/gx.py +6 -5
  66. pygeodesy/geodesicx/gxarea.py +2 -2
  67. pygeodesy/geodesicx/gxbases.py +2 -2
  68. pygeodesy/geodesicx/gxline.py +16 -12
  69. pygeodesy/geodsolve.py +8 -17
  70. pygeodesy/geohash.py +1 -1
  71. pygeodesy/geoids.py +6 -6
  72. pygeodesy/hausdorff.py +1 -1
  73. pygeodesy/heights.py +3 -3
  74. pygeodesy/internals.py +64 -80
  75. pygeodesy/interns.py +2 -3
  76. pygeodesy/iters.py +1 -1
  77. pygeodesy/karney.py +4 -4
  78. pygeodesy/ktm.py +20 -21
  79. pygeodesy/latlonBase.py +296 -346
  80. pygeodesy/lazily.py +15 -15
  81. pygeodesy/lcc.py +5 -5
  82. pygeodesy/ltp.py +55 -59
  83. pygeodesy/ltpTuples.py +208 -192
  84. pygeodesy/mgrs.py +9 -10
  85. pygeodesy/named.py +153 -3
  86. pygeodesy/namedTuples.py +58 -7
  87. pygeodesy/nvectorBase.py +122 -105
  88. pygeodesy/osgr.py +10 -13
  89. pygeodesy/points.py +1 -1
  90. pygeodesy/props.py +3 -3
  91. pygeodesy/resections.py +26 -26
  92. pygeodesy/rhumb/__init__.py +2 -2
  93. pygeodesy/rhumb/aux_.py +2 -2
  94. pygeodesy/rhumb/bases.py +2 -2
  95. pygeodesy/rhumb/ekx.py +4 -4
  96. pygeodesy/rhumb/solve.py +4 -4
  97. pygeodesy/simplify.py +291 -403
  98. pygeodesy/solveBase.py +1 -1
  99. pygeodesy/sphericalBase.py +1 -1
  100. pygeodesy/sphericalNvector.py +84 -127
  101. pygeodesy/sphericalTrigonometry.py +66 -71
  102. pygeodesy/streprs.py +10 -5
  103. pygeodesy/trf.py +1 -1
  104. pygeodesy/triaxials.py +23 -16
  105. pygeodesy/units.py +17 -17
  106. pygeodesy/unitsBase.py +1 -1
  107. pygeodesy/ups.py +4 -4
  108. pygeodesy/utily.py +202 -145
  109. pygeodesy/utm.py +10 -10
  110. pygeodesy/utmups.py +1 -1
  111. pygeodesy/utmupsBase.py +1 -1
  112. pygeodesy/vector2d.py +17 -17
  113. pygeodesy/vector3d.py +32 -23
  114. pygeodesy/vector3dBase.py +22 -19
  115. pygeodesy/webmercator.py +5 -5
  116. pygeodesy/wgrs.py +5 -5
  117. PyGeodesy-24.10.24.dist-info/RECORD +0 -118
  118. {PyGeodesy-24.10.24.dist-info → PyGeodesy-24.12.12.dist-info}/top_level.txt +0 -0
pygeodesy/azimuthal.py CHANGED
@@ -49,7 +49,7 @@ from pygeodesy.ellipsoidalBase import LatLonEllipsoidalBase as _LLEB, \
49
49
  _xinstanceof
50
50
  from pygeodesy.datums import _spherical_datum, _WGS84
51
51
  from pygeodesy.errors import _ValueError, _xdatum, _xkwds
52
- from pygeodesy.fmath import euclid, hypot as _hypot, Fsum
52
+ from pygeodesy.fmath import euclid, fdot_, hypot as _hypot, Fsum
53
53
  # from pygeodesy.fsums import Fsum # from .fmath
54
54
  # from pygeodesy.formy import antipode # _MODS
55
55
  from pygeodesy.interns import _azimuth_, _datum_, _lat_, _lon_, _scale_, \
@@ -64,13 +64,13 @@ from pygeodesy.props import deprecated_Property_RO, Property_RO, \
64
64
  from pygeodesy.streprs import Fmt, _fstrLL0, unstr
65
65
  from pygeodesy.units import Azimuth, Easting, Lat_, Lon_, Northing, \
66
66
  Scalar, Scalar_
67
- from pygeodesy.utily import asin1, atan1, atan2b, atan2d, sincos2, \
68
- sincos2d, sincos2d_
67
+ from pygeodesy.utily import asin1, atan1, atan2, atan2b, atan2d, \
68
+ sincos2, sincos2d, sincos2d_
69
69
 
70
- from math import acos, atan2, degrees, fabs, sin, sqrt
70
+ from math import acos, degrees, fabs, sin, sqrt
71
71
 
72
72
  __all__ = _ALL_LAZY.azimuthal
73
- __version__ = '24.07.25'
73
+ __version__ = '24.11.24'
74
74
 
75
75
  _EPS_K = _EPStol * _0_1 # Karney's eps_ or _EPSmin * _0_1?
76
76
  _over_horizon_ = 'over horizon'
@@ -154,10 +154,10 @@ class _AzimuthalBase(_NamedBase):
154
154
  s0, c0 = self._sc0
155
155
 
156
156
  cb *= ca
157
- k, t = _k_t_2(s0 * sa + c0 * cb)
157
+ k, t = _k_t_2(fdot_(s0, sa, c0, cb))
158
158
  if t:
159
159
  r = k * self.radius
160
- y = r * (c0 * sa - s0 * cb)
160
+ y = r * fdot_(c0, sa, -s0, cb)
161
161
  e, n, z, _ = _enzh4(r * sb * ca, y, None)
162
162
  else: # 0 or 180
163
163
  e = n = z = _0_0
@@ -233,11 +233,11 @@ class _AzimuthalBase(_NamedBase):
233
233
  Lon_(lon0=lon0, Error=AzimuthalError))
234
234
  self._sc0 = sincos2d(self.lat0)
235
235
 
236
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds): # PYCHOK no cover
236
+ def reverse(self, x, y, **name_LatLon_and_kwds):
237
237
  '''I{Must be overloaded}.'''
238
- self._notOverloaded(x, y, LatLon=LatLon, **name_LatLon_kwds)
238
+ self._notOverloaded(x, y, **name_LatLon_and_kwds) # PYCHOK no cover
239
239
 
240
- def _reverse(self, x, y, _c, lea, LatLon, **name_LatLon_kwds):
240
+ def _reverse(self, x, y, _c, lea, LatLon=None, **name_LatLon_kwds):
241
241
  '''(INTERNAL) Azimuthal (spherical) reverse C{x, y} to C{lat, lon}.
242
242
  '''
243
243
  e, n, z, r = _enzh4(x, y)
@@ -379,15 +379,14 @@ class Equidistant(_AzimuthalBase):
379
379
 
380
380
  return self._forward(lat, lon, name, _k_t)
381
381
 
382
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
382
+ def reverse(self, x, y, **name_LatLon_and_kwds):
383
383
  '''Convert an azimuthal equidistant location to geodetic lat- and longitude.
384
384
 
385
385
  @arg x: Easting of the location (C{meter}).
386
386
  @arg y: Northing of the location (C{meter}).
387
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
388
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} forthe location and
389
- optional, additional B{C{LatLon}} keyword arguments,
390
- ignored if C{B{LatLon} is None}.
387
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
388
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
389
+ ignored if C{B{LatLon} is None}.
391
390
 
392
391
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
393
392
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
@@ -401,7 +400,7 @@ class Equidistant(_AzimuthalBase):
401
400
  def _c(c):
402
401
  return c if c > EPS else None
403
402
 
404
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
403
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
405
404
 
406
405
 
407
406
  def equidistant(lat0, lon0, datum=_WGS84, exact=False, geodsolve=False, **name):
@@ -505,9 +504,8 @@ class _EquidistantBase(_AzimuthalGeodesic):
505
504
  @arg x: Easting of the location (C{meter}).
506
505
  @arg y: Northing of the location (C{meter}).
507
506
  @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
508
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
509
- optional, additional B{C{LatLon}} keyword arguments,
510
- ignored if C{B{LatLon} is None}.
507
+ @kwarg name_LatLon_kwds: Optional C{B{name}=NN} and optionally, additional
508
+ B{C{LatLon}} keyword arguments, ignored if C{B{LatLon} is None}.
511
509
 
512
510
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
513
511
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
@@ -670,15 +668,14 @@ class Gnomonic(_AzimuthalBase):
670
668
 
671
669
  return self._forward(lat, lon, name, _k_t)
672
670
 
673
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
671
+ def reverse(self, x, y, **name_LatLon_and_kwds):
674
672
  '''Convert an azimuthal equidistant location to geodetic lat- and longitude.
675
673
 
676
674
  @arg x: Easting of the location (C{meter}).
677
675
  @arg y: Northing of the location (C{meter}).
678
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
679
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
680
- optional, additional B{C{LatLon}} keyword arguments,
681
- ignored if C{B{LatLon} is None}.
676
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
677
+ for the location and optionally, additional B{C{LatLon}} keyword
678
+ arguments, ignored if C{B{LatLon} is None}.
682
679
 
683
680
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
684
681
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
@@ -692,7 +689,7 @@ class Gnomonic(_AzimuthalBase):
692
689
  def _c(c):
693
690
  return atan1(c) if c > EPS else None
694
691
 
695
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
692
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
696
693
 
697
694
 
698
695
  def gnomonic(lat0, lon0, datum=_WGS84, exact=False, geodsolve=False, **name):
@@ -787,20 +784,18 @@ class _GnomonicBase(_AzimuthalGeodesic):
787
784
  @arg x: Easting of the location (C{meter}).
788
785
  @arg y: Northing of the location (C{meter}).
789
786
  @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
790
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
791
- optional, additional B{C{LatLon}} keyword arguments,
792
- ignored if C{B{LatLon} is None}.
787
+ @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and optionally,
788
+ additional B{C{LatLon}} keyword arguments, ignored if C{B{LatLon} is None}.
793
789
 
794
790
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
795
791
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
796
792
 
797
793
  @raise AzimuthalError: No convergence.
798
794
 
799
- @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
800
- in the range C{[-180..180] degrees}. The C{azimuth} is clockwise
801
- from true North. The scale is C{1 / reciprocal**2} in C{radial}
802
- direction and C{1 / reciprocal} in the direction perpendicular
803
- to this.
795
+ @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon} in the range
796
+ C{[-180..180] degrees}. The C{azimuth} is clockwise from true North. The
797
+ scale is C{1 / reciprocal**2} in C{radial} direction and C{1 / reciprocal}
798
+ in the direction perpendicular to this.
804
799
  '''
805
800
  e, n, z, q = _enzh4(x, y)
806
801
 
@@ -974,30 +969,28 @@ class LambertEqualArea(_AzimuthalBase):
974
969
 
975
970
  return self._forward(lat, lon, name, _k_t)
976
971
 
977
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
972
+ def reverse(self, x, y, **name_LatLon_and_kwds):
978
973
  '''Convert an azimuthal Lambert-equal-area location to geodetic lat- and longitude.
979
974
 
980
975
  @arg x: Easting of the location (C{meter}).
981
976
  @arg y: Northing of the location (C{meter}).
982
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
983
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location
984
- and optional, additional B{C{LatLon}} keyword
985
- arguments, ignored if C{B{LatLon} is None}.
977
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
978
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
979
+ ignored if C{B{LatLon} is None}.
986
980
 
987
981
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
988
982
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
989
983
 
990
- @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
991
- in the range C{[-180..180] degrees}. The C{scale} of the
992
- projection is C{1} in I{radial} direction, C{azimuth} clockwise
993
- from true North and is C{1 / reciprocal} in the direction
994
- perpendicular to this.
984
+ @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon} in the
985
+ range C{[-180..180] degrees}. The C{scale} of the projection is C{1}
986
+ in I{radial} direction, C{azimuth} clockwise from true North and is C{1
987
+ / reciprocal} in the direction perpendicular to this.
995
988
  '''
996
989
  def _c(c):
997
990
  c *= _0_5
998
991
  return (asin1(c) * _2_0) if c > EPS else None
999
992
 
1000
- return self._reverse(x, y, _c, True, LatLon, **name_LatLon_kwds)
993
+ return self._reverse(x, y, _c, True, **name_LatLon_and_kwds)
1001
994
 
1002
995
 
1003
996
  class Orthographic(_AzimuthalBase):
@@ -1028,29 +1021,27 @@ class Orthographic(_AzimuthalBase):
1028
1021
 
1029
1022
  return self._forward(lat, lon, name, _k_t)
1030
1023
 
1031
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
1024
+ def reverse(self, x, y, **name_LatLon_and_kwds):
1032
1025
  '''Convert an azimuthal orthographic location to geodetic lat- and longitude.
1033
1026
 
1034
1027
  @arg x: Easting of the location (C{meter}).
1035
1028
  @arg y: Northing of the location (C{meter}).
1036
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
1037
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
1038
- optional, additional B{C{LatLon}} keyword arguments,
1039
- ignored if C{B{LatLon} is None}.
1029
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
1030
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
1031
+ ignored if C{B{LatLon} is None}.
1040
1032
 
1041
1033
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
1042
1034
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
1043
1035
 
1044
- @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
1045
- in the range C{[-180..180] degrees}. The C{scale} of the
1046
- projection is C{1} in I{radial} direction, C{azimuth} clockwise
1047
- from true North and is C{1 / reciprocal} in the direction
1048
- perpendicular to this.
1036
+ @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon} in the
1037
+ range C{[-180..180] degrees}. The C{scale} of the projection is C{1}
1038
+ in I{radial} direction, C{azimuth} clockwise from true North and is C{1
1039
+ / reciprocal} in the direction perpendicular to this.
1049
1040
  '''
1050
1041
  def _c(c):
1051
1042
  return asin1(c) if c > EPS else None
1052
1043
 
1053
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
1044
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
1054
1045
 
1055
1046
 
1056
1047
  class Stereographic(_AzimuthalBase):
@@ -1101,35 +1092,34 @@ class Stereographic(_AzimuthalBase):
1101
1092
  self._k0 = Scalar_(factor, name=n, low=EPS, high=2) # XXX high=1, 2, other?
1102
1093
  self._k02 = self._k0 * _2_0
1103
1094
 
1104
- def reverse(self, x, y, LatLon=None, **name_LatLon_kwds):
1095
+ def reverse(self, x, y, **name_LatLon_and_kwds):
1105
1096
  '''Convert an azimuthal stereographic location to geodetic lat- and longitude.
1106
1097
 
1107
1098
  @arg x: Easting of the location (C{meter}).
1108
1099
  @arg y: Northing of the location (C{meter}).
1109
- @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
1110
- @kwarg name_LatLon_kwds: Optional C{B{name}=NN} for the location and
1111
- optional, additional B{C{LatLon}} keyword arguments,
1112
- ignored if C{B{LatLon} is None}.
1100
+ @kwarg name_LatLon_and_kwds: Optional C{B{name}=NN} and class C{B{LatLon}=None}
1101
+ to use and optionally, additional B{C{LatLon}} keyword arguments,
1102
+ ignored if C{B{LatLon} is None}.
1113
1103
 
1114
1104
  @return: The geodetic (C{LatLon}) or if C{B{LatLon} is None} an
1115
1105
  L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.
1116
1106
 
1117
1107
  @note: The C{lat} will be in range C{[-90..90] degrees}, C{lon} in range
1118
- C{[-180..180] degrees} and C{azimuth} clockwise from true North.
1119
- The C{scale} of the projection is C{1} in I{radial} direction and
1120
- is C{1 / reciprocal} in the direction perpendicular to this.
1108
+ C{[-180..180] degrees} and C{azimuth} clockwise from true North. The
1109
+ C{scale} of the projection is C{1} in I{radial} direction and is C{1
1110
+ / reciprocal} in the direction perpendicular to this.
1121
1111
  '''
1122
1112
  def _c(c):
1123
1113
  return (atan2(c, self._k02) * _2_0) if c > EPS else None
1124
1114
 
1125
- return self._reverse(x, y, _c, False, LatLon, **name_LatLon_kwds)
1115
+ return self._reverse(x, y, _c, False, **name_LatLon_and_kwds)
1126
1116
 
1127
1117
 
1128
1118
  __all__ += _ALL_DOCS(_AzimuthalBase, _AzimuthalGeodesic, _EquidistantBase, _GnomonicBase)
1129
1119
 
1130
1120
  # **) MIT License
1131
1121
  #
1132
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1122
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1133
1123
  #
1134
1124
  # Permission is hereby granted, free of charge, to any person obtaining a
1135
1125
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/basics.py CHANGED
@@ -37,7 +37,7 @@ from math import copysign as _copysign
37
37
  # import inspect as _inspect # _MODS
38
38
 
39
39
  __all__ = _ALL_LAZY.basics
40
- __version__ = '24.10.14'
40
+ __version__ = '24.11.02'
41
41
 
42
42
  _below_ = 'below'
43
43
  _list_tuple_types = (list, tuple)
@@ -111,29 +111,29 @@ except NameError: # Python 3+
111
111
  return ub
112
112
 
113
113
 
114
- def _args_kwds_count2(func, exelf=True):
115
- '''(INTERNAL) Get a C{func}'s args and kwds count as 2-tuple
116
- C{(nargs, nkwds)}, including arg C{self} for methods.
117
-
118
- @kwarg exelf: If C{True}, exclude C{self} in the C{args}
119
- of a method (C{bool}).
120
- '''
121
- i = _MODS.inspect
122
- try: # PYCHOK no cover
123
- a = k = 0
124
- for _, p in i.signature(func).parameters.items():
125
- if p.kind is p.POSITIONAL_OR_KEYWORD:
126
- if p.default is p.empty:
127
- a += 1
128
- else:
129
- k += 1
130
- except AttributeError: # Python 2-
131
- s = i.getargspec(func)
132
- k = len(s.defaults or ())
133
- a = len(s.args) - k
134
- if exelf and a > 0 and i.ismethod(func):
135
- a -= 1
136
- return a, k
114
+ # def _args_kwds_count2(func, exelf=True): # in .formy
115
+ # '''(INTERNAL) Get a C{func}'s args and kwds count as 2-tuple
116
+ # C{(nargs, nkwds)}, including arg C{self} for methods.
117
+ #
118
+ # @kwarg exelf: If C{True}, exclude C{self} in the C{args}
119
+ # of a method (C{bool}).
120
+ # '''
121
+ # i = _MODS.inspect
122
+ # try:
123
+ # a = k = 0
124
+ # for _, p in i.signature(func).parameters.items():
125
+ # if p.kind is p.POSITIONAL_OR_KEYWORD:
126
+ # if p.default is p.empty:
127
+ # a += 1
128
+ # else:
129
+ # k += 1
130
+ # except AttributeError: # Python 2-
131
+ # s = i.getargspec(func)
132
+ # k = len(s.defaults or ())
133
+ # a = len(s.args) - k
134
+ # if exelf and a > 0 and i.ismethod(func):
135
+ # a -= 1
136
+ # return a, k
137
137
 
138
138
 
139
139
  def _args_kwds_names(func, splast=False):
@@ -222,7 +222,7 @@ def halfs2(str2):
222
222
  return str2[:h], str2[h:]
223
223
 
224
224
 
225
- def int1s(x):
225
+ def int1s(x): # PYCHOK no cover
226
226
  '''Count the number of 1-bits in an C{int}, I{unsigned}.
227
227
 
228
228
  @note: C{int1s(-B{x}) == int1s(abs(B{x}))}.
@@ -736,7 +736,7 @@ def _xcopy(obj, deep=False):
736
736
  return _deepcopy(obj) if deep else _copy(obj)
737
737
 
738
738
 
739
- def _xcoverage(where, *required):
739
+ def _xcoverage(where, *required): # in .__main__ # PYCHOK no cover
740
740
  '''(INTERNAL) Import C{coverage} and check required version.
741
741
  '''
742
742
  try:
@@ -847,15 +847,16 @@ def _xor(x, *xs):
847
847
  return x
848
848
 
849
849
 
850
- def _xpackages(_xpkg):
850
+ def _xpackages(_xpkgf):
851
851
  '''(INTERNAL) Check dependency to be excluded.
852
852
  '''
853
- n = _xpkg.__name__[2:] # _DUNDER_nameof, less '_x'
854
- if n in _XPACKAGES: # n.lower() in _XPACKAGES
855
- E = _PYGEODESY(_xpackages)
856
- x = _SPACE_(n, _in_, E)
857
- e = _enquote(_getenv(E, NN))
858
- raise ImportError(_EQUAL_(x, e))
853
+ if _XPACKAGES: # PYCHOK no cover
854
+ n = _xpkgf.__name__[2:] # _DUNDER_nameof, less '_x'
855
+ if n.lower() in _XPACKAGES:
856
+ E = _PYGEODESY(_xpackages)
857
+ x = _SPACE_(n, _in_, E)
858
+ e = _enquote(_getenv(E, NN))
859
+ raise ImportError(_EQUAL_(x, e))
859
860
 
860
861
 
861
862
  def _xscalar(**names_values):
@@ -933,7 +934,7 @@ _XPACKAGES = _splituple(_getenv(_PYGEODESY(_xpackages), NN).lower()) # test/bas
933
934
 
934
935
  # **) MIT License
935
936
  #
936
- # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
937
+ # Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
937
938
  #
938
939
  # Permission is hereby granted, free of charge, to any person obtaining a
939
940
  # copy of this software and associated documentation files (the "Software"),
pygeodesy/booleans.py CHANGED
@@ -21,7 +21,7 @@ from pygeodesy.basics import isodd, issubclassof, map2, _xscalar
21
21
  from pygeodesy.constants import EPS, EPS2, INT0, _0_0, _0_5, _1_0
22
22
  from pygeodesy.errors import ClipError, _IsnotError, _TypeError, \
23
23
  _ValueError, _xattr, _xkwds_get, _xkwds_pop2
24
- from pygeodesy.fmath import favg, hypot, hypot2
24
+ from pygeodesy.fmath import favg, fdot_, hypot, hypot2
25
25
  # from pygeodesy.fsums import fsum1 # _MODS
26
26
  from pygeodesy.interns import NN, _BANG_, _clipid_, _COMMASPACE_, \
27
27
  _composite_, _DOT_, _duplicate_, _e_, \
@@ -43,12 +43,12 @@ from pygeodesy.utily import fabs, _unrollon, _Wrap
43
43
  # from math import fabs # from .utily
44
44
 
45
45
  __all__ = _ALL_LAZY.booleans
46
- __version__ = '24.10.22'
46
+ __version__ = '24.11.07'
47
47
 
48
- _0_EPS = EPS # near-zero, positive
49
- _EPS_0 = -EPS # near-zero, negative
50
- _1_EPS = _1_0 + EPS # near-one, over
51
- _EPS_1 = _1_0 - EPS # near-one, under
48
+ _0EPS = EPS # near-zero, positive
49
+ _EPS0 = -EPS # near-zero, negative
50
+ _1EPS = _1_0 + EPS # near-one, over
51
+ _EPS1 = _1_0 - EPS # near-one, under
52
52
  _10EPS = EPS * 10 # see ._2Abs, ._10eps
53
53
 
54
54
  _alpha_ = 'alpha'
@@ -162,7 +162,7 @@ class _LatLonBool(_Named):
162
162
  other.x == self.x and
163
163
  other.y == self.y)
164
164
 
165
- def __ne__(self, other): # required for Python 2
165
+ def __ne__(self, other): # required for Python 2 # PYCHOK no cover
166
166
  return not self.__eq__(other)
167
167
 
168
168
  def __repr__(self):
@@ -316,11 +316,11 @@ class LatLonFHP(_LatLonBool):
316
316
 
317
317
  def __mod__(self, other): # cross product
318
318
  _other(self, other)
319
- return self.x * other.y - self.y * other.x
319
+ return fdot_(self.x, other.y, -self.y, other.x)
320
320
 
321
321
  def __mul__(self, other): # dot product
322
322
  _other(self, other)
323
- return self.x * other.x + self.y * other.y
323
+ return fdot_(self.x, other.x, self.y, other.y)
324
324
 
325
325
  def __rmul__(self, other): # scalar product
326
326
  _xscalar(other=other)
@@ -424,7 +424,7 @@ class LatLonFHP(_LatLonBool):
424
424
  def _prev_next2(self):
425
425
  # Adjust 2-tuple (._prev, ._next) iff a I{duplicate} intersection
426
426
  p, n = self, self._next
427
- if self._isduplicate:
427
+ if self._isduplicate: # PYCHOK no cover
428
428
  p = self._dupof
429
429
  while p._isduplicate:
430
430
  p = p._dupof
@@ -580,7 +580,7 @@ class _Clip(_Named):
580
580
  '''
581
581
  return self._bltr4 > _other(self, other)._bltr4
582
582
 
583
- def __hash__(self): # PYCHOK no over
583
+ def __hash__(self): # PYCHOK no cover
584
584
  return hash(self._bltr4)
585
585
 
586
586
  def __iter__(self):
@@ -610,7 +610,7 @@ class _Clip(_Named):
610
610
  '''
611
611
  return self._bltr4 < _other(self, other)._bltr4
612
612
 
613
- def __ne__(self, other): # required for Python 2
613
+ def __ne__(self, other): # required for Python 2 # PYCHOK no cover
614
614
  '''See method C{__eq__}.
615
615
  '''
616
616
  return not self.__eq__(other)
@@ -1551,10 +1551,10 @@ class _EdgeFHP(object):
1551
1551
  p1, p2 = self._p1_p2
1552
1552
  ap1 = p1._2A(q1, q2)
1553
1553
  ap2_1 = p2._2A(q1, q2) - ap1
1554
- if fabs(ap2_1) > _0_EPS: # non-parallel edges
1554
+ if fabs(ap2_1) > _0EPS: # non-parallel edges
1555
1555
  aq1 = q1._2A(p1, p2)
1556
1556
  aq2_1 = q2._2A(p1, p2) - aq1
1557
- if fabs(aq2_1) > _0_EPS:
1557
+ if fabs(aq2_1) > _0EPS:
1558
1558
  # compute and classify alpha and beta
1559
1559
  a, a_0, a_0_1, _ = _alpha4(-ap1 / ap2_1)
1560
1560
  b, b_0, b_0_1, _ = _alpha4(-aq1 / aq2_1)
@@ -1564,7 +1564,7 @@ class _EdgeFHP(object):
1564
1564
  _E.Q_INTERSECT if a_0 and b_0_1 else (
1565
1565
  _E.V_INTERSECT if a_0 and b_0 else None)))
1566
1566
 
1567
- elif fabs(ap1) < _0_EPS: # parallel or colinear edges
1567
+ elif fabs(ap1) < _0EPS: # parallel or colinear edges
1568
1568
  dp = self._dp
1569
1569
  d1 = q1 - p1
1570
1570
  # compute and classify alpha and beta
@@ -1610,8 +1610,8 @@ class _EdgeGH(object):
1610
1610
 
1611
1611
  def _alpha2(self, x, y, dx, dy):
1612
1612
  # Return C{(alpha)}, see .points.nearestOn5
1613
- a = (y * dy + x * dx) / self._hypot2
1614
- d = (y * dx - x * dy) / self._hypot0
1613
+ a = fdot_(y, dy, x, dx) / self._hypot2
1614
+ d = fdot_(y, dx, -x, dy) / self._hypot0
1615
1615
  return a, fabs(d)
1616
1616
 
1617
1617
  def _Error(self, n, *args, **kwds): # PYCHOK no cover
@@ -1622,7 +1622,7 @@ class _EdgeGH(object):
1622
1622
  @Property_RO
1623
1623
  def _hypot0(self):
1624
1624
  _, sx, _, sy = self._x_sx_y_sy
1625
- return hypot(sx, sy) * _0_EPS
1625
+ return hypot(sx, sy) * _0EPS
1626
1626
 
1627
1627
  @Property_RO
1628
1628
  def _hypot2(self):
@@ -1650,33 +1650,33 @@ class _EdgeGH(object):
1650
1650
  cy = c2.y - c1_y
1651
1651
  d = cy * sx - cx * sy
1652
1652
 
1653
- if fabs(d) > _0_EPS: # non-parallel edges
1653
+ if fabs(d) > _0EPS: # non-parallel edges
1654
1654
  dx = x - c1_x
1655
1655
  dy = y - c1_y
1656
- ca = (sx * dy - sy * dx) / d
1657
- if _0_EPS < ca < _EPS_1 or (self._xtend and
1658
- _EPS_0 < ca < _1_EPS):
1659
- sa = (cx * dy - cy * dx) / d
1660
- if _0_EPS < sa < _EPS_1 or (self._xtend and
1661
- _EPS_0 < sa < _1_EPS):
1656
+ ca = fdot_(sx, dy, -sy, dx) / d
1657
+ if _0EPS < ca < _EPS1 or (self._xtend and
1658
+ _EPS0 < ca < _1EPS):
1659
+ sa = fdot_(cx, dy, -cy, dx) / d
1660
+ if _0EPS < sa < _EPS1 or (self._xtend and
1661
+ _EPS0 < sa < _1EPS):
1662
1662
  yield (y + sa * sy), (x + sa * sx), sa, ca
1663
1663
 
1664
1664
  # unhandled, "degenerate" cases 1, 2 or 3
1665
- elif self._raiser and not (sa < _EPS_0 or sa > _1_EPS): # PYCHOK no cover
1665
+ elif self._raiser and not (sa < _EPS0 or sa > _1EPS): # PYCHOK no cover
1666
1666
  raise self._Error(1, c1, c2, sa=sa) # intersection at s1 or s2
1667
1667
 
1668
- elif self._raiser and not (ca < _EPS_0 or ca > _1_EPS): # PYCHOK no cover
1668
+ elif self._raiser and not (ca < _EPS0 or ca > _1EPS): # PYCHOK no cover
1669
1669
  # intersection at c1 or c2 or at c1 or c2 and s1 or s2
1670
- sa = (cx * dy - cy * dx) / d
1671
- e = 2 if sa < _EPS_0 or sa > _1_EPS else 3
1670
+ sa = fdot_(cx, dy, -cy, dx) / d
1671
+ e = 2 if sa < _EPS0 or sa > _1EPS else 3
1672
1672
  raise self._Error(e, c1, c2, ca=ca)
1673
1673
 
1674
1674
  elif parallel and (sx or sy) and (cx or cy): # PYCHOK no cover
1675
1675
  # non-null, parallel or colinear edges
1676
1676
  sa1, d1 = self._alpha2(c1_x - x, c1_y - y, sx, sy)
1677
1677
  sa2, d2 = self._alpha2(c2.x - x, c2.y - y, sx, sy)
1678
- if max(d1, d2) < _0_EPS:
1679
- if self._xtend and not _outside(sa1, sa2, _EPS_0, _1_EPS):
1678
+ if max(d1, d2) < _0EPS:
1679
+ if self._xtend and not _outside(sa1, sa2, _EPS0, _1EPS):
1680
1680
  if sa1 > sa2: # anti-parallel
1681
1681
  sa1, sa2 = sa2, sa1
1682
1682
  ca1, ca2 = _1_0, _0_0
@@ -1694,7 +1694,7 @@ class _EdgeGH(object):
1694
1694
  yield (y + sy), (x + sx), ca2, _alpha1(ca2 - ca)
1695
1695
  else: # c2 is between s1 and s2
1696
1696
  yield (y + sa2 * sy), (x + sa2 * sx), sa2, ca2
1697
- elif self._raiser and not _outside(sa1, sa2, _0_0, _1_EPS):
1697
+ elif self._raiser and not _outside(sa1, sa2, _0_0, _1EPS):
1698
1698
  raise self._Error(4, c1, c2, d1=d1, d2=d2)
1699
1699
 
1700
1700
 
@@ -1887,9 +1887,9 @@ class BooleanGH(_CompositeGH, _BooleanBase):
1887
1887
  return self._boolean(other, True, False, self.__sub__)
1888
1888
 
1889
1889
 
1890
- def _alpha1(alpha):
1890
+ def _alpha1(alpha): # PYCHOK no cover
1891
1891
  # Return C{alpha} in C{[0..1]} range
1892
- if _EPS_0 < alpha < _1_EPS:
1892
+ if _EPS0 < alpha < _1EPS:
1893
1893
  return max(_0_0, min(alpha, _1_0))
1894
1894
  t = _not_(Fmt.SQUARE(_ELLIPSIS_(0, 1)))
1895
1895
  raise ClipError(_alpha_, alpha, txt=t)
@@ -1899,8 +1899,8 @@ def _alpha4(a):
1899
1899
  # Return 4-tuple (alpha, -EPS < alpha < EPS,
1900
1900
  # 0 < alpha < 1,
1901
1901
  # not 0 < alpha < 1)
1902
- a_EPS = bool(_EPS_0 < a < _0_EPS)
1903
- a_0_1 = bool(_0_EPS < a < _EPS_1)
1902
+ a_EPS = bool(_EPS0 < a < _0EPS)
1903
+ a_0_1 = bool(_0EPS < a < _EPS1)
1904
1904
  return a, a_EPS, a_0_1, (not a_0_1)
1905
1905
 
1906
1906
 
@@ -1982,7 +1982,7 @@ __all__ += _ALL_DOCS(_BooleanBase, _Clip,
1982
1982
 
1983
1983
  # **) MIT License
1984
1984
  #
1985
- # Copyright (C) 2018-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1985
+ # Copyright (C) 2018-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1986
1986
  #
1987
1987
  # Permission is hereby granted, free of charge, to any person obtaining a
1988
1988
  # copy of this software and associated documentation files (the "Software"),