pygeodesy 25.8.25__py2.py3-none-any.whl → 25.10.10__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 (48) hide show
  1. pygeodesy/__init__.py +21 -20
  2. pygeodesy/auxilats/__init__.py +1 -1
  3. pygeodesy/auxilats/auxAngle.py +4 -3
  4. pygeodesy/auxilats/auxily.py +1 -1
  5. pygeodesy/azimuthal.py +10 -12
  6. pygeodesy/basics.py +4 -4
  7. pygeodesy/booleans.py +25 -25
  8. pygeodesy/constants.py +59 -33
  9. pygeodesy/deprecated/functions.py +1 -0
  10. pygeodesy/dms.py +2 -2
  11. pygeodesy/ecef.py +3 -3
  12. pygeodesy/ellipsoidalExact.py +4 -4
  13. pygeodesy/ellipsoidalGeodSolve.py +3 -3
  14. pygeodesy/ellipsoids.py +52 -41
  15. pygeodesy/elliptic.py +9 -12
  16. pygeodesy/errors.py +18 -5
  17. pygeodesy/etm.py +10 -10
  18. pygeodesy/fmath.py +5 -3
  19. pygeodesy/geodesicx/__init__.py +1 -1
  20. pygeodesy/geodesicx/__main__.py +1 -0
  21. pygeodesy/geodesicx/gx.py +40 -46
  22. pygeodesy/geodesicx/gxarea.py +4 -4
  23. pygeodesy/geodesicx/gxbases.py +1 -5
  24. pygeodesy/geodesicx/gxline.py +43 -34
  25. pygeodesy/geodsolve.py +10 -17
  26. pygeodesy/geohash.py +6 -6
  27. pygeodesy/geoids.py +2 -2
  28. pygeodesy/heights.py +2 -2
  29. pygeodesy/internals.py +42 -19
  30. pygeodesy/karney.py +27 -26
  31. pygeodesy/ktm.py +1 -1
  32. pygeodesy/lazily.py +12 -11
  33. pygeodesy/lcc.py +5 -5
  34. pygeodesy/named.py +11 -14
  35. pygeodesy/rhumb/__init__.py +1 -1
  36. pygeodesy/rhumb/aux_.py +1 -1
  37. pygeodesy/rhumb/bases.py +7 -8
  38. pygeodesy/rhumb/ekx.py +9 -9
  39. pygeodesy/solveBase.py +14 -3
  40. pygeodesy/sphericalTrigonometry.py +4 -4
  41. pygeodesy/streprs.py +9 -9
  42. pygeodesy/trf.py +4 -4
  43. pygeodesy/utily.py +200 -159
  44. pygeodesy/vector3dBase.py +6 -6
  45. {pygeodesy-25.8.25.dist-info → pygeodesy-25.10.10.dist-info}/METADATA +21 -20
  46. {pygeodesy-25.8.25.dist-info → pygeodesy-25.10.10.dist-info}/RECORD +48 -48
  47. {pygeodesy-25.8.25.dist-info → pygeodesy-25.10.10.dist-info}/WHEEL +0 -0
  48. {pygeodesy-25.8.25.dist-info → pygeodesy-25.10.10.dist-info}/top_level.txt +0 -0
pygeodesy/__init__.py CHANGED
@@ -17,7 +17,7 @@ and a geocentric B{C{Cartesian}} class with methods and functions to compute dis
17
17
  forward and reverse azimuth, initial and final bearing, intermediate and nearest points, intersections of geodesic,
18
18
  great circle and rhumb lines, circle intersections and secants, U{3-point resections
19
19
  <https://WikiPedia.org/wiki/Position_resection_and_intersection>}, triangulation, trilateration (by intersection,
20
- by overlap and in 3-D), conversions and unrolling, among other things.
20
+ by overlap and in 3-D), among other things.
21
21
 
22
22
  Also included are modules for conversions to and from U{Cassini-Soldner
23
23
  <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1CassiniSoldner.html>},
@@ -51,9 +51,9 @@ resources/hull:8338>} and the U{Reumann-Witkam<https://psimpl.SourceForge.net/re
51
51
  algorithms and modified versions of the former.
52
52
 
53
53
  Plus modules and classes to U{interpolate<https://docs.SciPy.org/doc/scipy/reference/interpolate.html>} the
54
- L{height<pygeodesy.heights>} of C{LatLon} points and L{Geoid<pygeodesy.geoids>} models, compute various U{Fréchet
54
+ L{height<pygeodesy.heights>} of C{LatLon} points and L{Geoid<pygeodesy.geoids>} models, to compute various U{Fréchet
55
55
  <https://WikiPedia.org/wiki/Frechet_distance>} or U{Hausdorff<https://WikiPedia.org/wiki/Hausdorff_distance>}
56
- distances or perform I{boolean} operations between (composite) polygons.
56
+ distances or to perform I{boolean} operations between (composite) polygons of C{LatLon} points.
57
57
 
58
58
  For further details see the U{documentation<https://mrJean1.GitHub.io/PyGeodesy>}, the descriptions of
59
59
  U{Latitude/Longitude<https://www.Movable-Type.co.UK/scripts/latlong.html>}, U{Vincenty
@@ -125,7 +125,11 @@ C{epydoc --html --no-private --no-source --name=pygeodesy --url=... -v pygeodesy
125
125
  Tests
126
126
  =====
127
127
 
128
- The tests ran with Python 3.13.5 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0),
128
+ The tests ran with Python 3.14 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.1),
129
+ Python 3.13.7 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.1),
130
+ U{numpy<https://PyPI.org/project/numpy>} 2.3.3, U{scipy<https://PyPI.org/project/scipy>} 1.16.2,
131
+ U{GeoConvert<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5 and
132
+ U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5),
129
133
  Python 3.12.7 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0,
130
134
  U{numpy<https://PyPI.org/project/numpy>} 2.1.0, U{scipy<https://PyPI.org/project/scipy>} 1.14.1,
131
135
  U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5,
@@ -133,30 +137,26 @@ U{IntersectTool<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.
133
137
  U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5),
134
138
  Python 3.11.5 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0,
135
139
  U{numpy<https://PyPI.org/project/numpy>} 1.24.2 and U{scipy<https://PyPI.org/project/scipy>} 1.10.1),
136
- Python 3.10.8 (with U{geographiclib <https://PyPI.org/project/geographiclib>} 2.0,
137
- U{numpy<https://PyPI.org/project/numpy>} 1.23.3, U{scipy<https://PyPI.org/project/scipy>} 1.9.1,
138
- U{GeoConvert<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5,
139
- U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5) and
140
- Python 2.7.18 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 1.50,
140
+ and with Python 2.7.18 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 1.50,
141
141
  U{numpy<https://PyPI.org/project/numpy>} 1.16.6, U{scipy<https://PyPI.org/project/scipy>} 1.2.2,
142
142
  U{GeoConvert<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5,
143
143
  U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5,
144
144
  U{IntersectTool<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5 and
145
145
  U{RhumbSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5), all in 64-bit on
146
- macOS 15.6.1 Sequoia.
146
+ macOS 26.0.1 Tahoe.
147
147
 
148
148
  All tests ran with and without C{lazy import} for Python 3 and with command line option C{-W default} and
149
149
  env variable C{PYGEODESY_WARNINGS=on} for all Python versions. The results of those tests are included in
150
150
  the distribution files.
151
151
 
152
- Test coverage has been measured with U{coverage<https://PyPI.org/project/coverage>} 7.6.1 using Python
153
- 3.13.5, 3.12.7, 3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in
154
- the distribution files.
152
+ Test coverage has been measured with U{coverage<https://PyPI.org/project/coverage>} 7.10.7 using Python
153
+ 3.14, 3.13.7 and 3.12.7. The complete coverage report in HTML and a PDF summary are included in the
154
+ distribution files.
155
155
 
156
- Python 3.13.5, 3.12.7, 3.11.5 and 3.10.8 run on Apple M4 Si (C{arm64}), I{natively}. Python 2.7.18 runs
156
+ Python 3.14, 3.13.7, 3.12.7 and 3.11.5 run on Apple M4 Si (C{arm64}), I{natively}. Python 2.7.18 runs
157
157
  on Intel (C{x86_64}) or Intel I{emulation} ("C{arm64_x86_64}", see function L{machine<pygeodesy.machine>}).
158
158
 
159
- The tests also ran with Python 3.13.5 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on
159
+ The tests also ran with Python 3.13.7 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.1) on
160
160
  U{Debian 12<https://Cirrus-CI.com/github/mrJean1/PyGeodesy/master>} in 64-bit only, with Python 3.12.8 (and
161
161
  U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0) on U{Windows 2019Server
162
162
  <https://CI.AppVeyor.com/project/mrJean1/pygeodesy>} in 64-bit only and with Python 2.7.18 (and U{geographiclib
@@ -166,7 +166,7 @@ in 64- and 32-bit.
166
166
  A single-File and single-Directory application with C{pygeodesy} has been bundled using U{PyInstaller
167
167
  <https://PyPI.org/project/pyinstaller>} 3.4 and 64-bit Python 3.7.3 on macOS 10.13.6 High Sierra.
168
168
 
169
- Previously, the tests were run with Python 3.13.0-4, 3.12.0-6, 3.11.2-4, 3.10.1-7, 3.9.6, 3.9.1, 3.8.7, 3.7.1, 2.7.15,
169
+ Previously, the tests were run with Python 3.13.0-6, 3.12.0-6, 3.11.2-4, 3.10.1-7, 3.9.6, 3.9.1, 3.8.7, 3.7.1, 2.7.15,
170
170
  U{PyPy<https://PyPy.org>} 7.3.12 (Python 3.10.12), 7.3.1 (Python 3.6.9) and U{PyPy<https://PyPy.org>} 7.1.1 (Python
171
171
  2.7.13) (and U{geographiclib <https://PyPI.org/project/geographiclib>} 1.52, U{numpy<https://PyPI.org/project/numpy>}
172
172
  1.16.3, 1.16.4, 1.16.6, 1.19.0, 1.19.4, 1.19.5 or 1.22.4 and U{scipy<https://PyPI.org/project/scipy>} 1.2.1, 1.4.1,
@@ -175,7 +175,7 @@ U{PyPy<https://PyPy.org>} 7.3.12 (Python 3.10.12), 7.3.1 (Python 3.6.9) and U{Py
175
175
  1.16.5, 1.16.2, 1.15.2, 1.14.0, 1.13.1, 1.8.0rc1 or 1.6.2 and U{scipy<https://PyPI.org/project/scipy>} 1.5.0), U{PyPy
176
176
  <https://PyPy.org>} 7.3.0 (Python 2.7.13 and 3.6.9), U{PyPy<https://PyPy.org>} 6.0.0 (Python 2.7.13 and 3.5.3)
177
177
  and U{Intel-Python<https://software.Intel.com/en-us/distribution-for-python>} 3.5.3 (and U{numpy
178
- <https://PyPI.org/project/numpy>} 1.11.3) on macOS 15.0-5 Sequoia, 14.0-6.1 Sonoma, 13.0-5.2 Ventura, 12.1-6 Monterey,
178
+ <https://PyPI.org/project/numpy>} 1.11.3) on macOS 15.0-6 Sequoia, 14.0-6.1 Sonoma, 13.0-5.2 Ventura, 12.1-6 Monterey,
179
179
  11.0-5.2-6.1 Big Sur (aka 10.16), 10.15.3, 10.15.5-7 Catalina, 10.14 Mojave, 10.13.6 High Sierra and 10.12 Sierra,
180
180
  MacOS X 10.11 El Capitan and/or MacOS X 10.10 Yosemite, with U{Pythonista<https://OMZ-Software.com/pythonista>}3.2
181
181
  (with geographiclib 1.50 or 1.49 and numpy 1.8.0) on iOS 14.4.2, 11.4.1, 12.0-3 on iPad4, iPhone6, iPhone10 and/or
@@ -187,10 +187,10 @@ Notes
187
187
  =====
188
188
 
189
189
  All Python source code has been statically U{checked<https://GitHub.com/ActiveState/code/tree/master/recipes/Python/
190
- 546532_PyChecker_postprocessor>} with U{Ruff<https://GitHub.com/astral-sh/ruff>} using Python 3.13.5 and with
190
+ 546532_PyChecker_postprocessor>} with U{Ruff<https://GitHub.com/astral-sh/ruff>} using Python 3.13.7 and with
191
191
  U{PyChecker<https://PyPI.org/project/pychecker>}, U{PyFlakes<https://PyPI.org/project/pyflakes>}, U{PyCodeStyle
192
192
  <https://PyPI.org/project/pycodestyle>} (formerly Pep8) and U{McCabe<https://PyPI.org/project/mccabe>} using Python
193
- 2.7.18, both in 64-bit on macOS 15.6.1 Sequoia.
193
+ 2.7.18, both in 64-bit on macOS 26.0.1 Tahoe.
194
194
 
195
195
  For a summary of all I{Karney}-based functionality in C{pygeodesy}, see module U{karney
196
196
  <https://mrJean1.GitHub.io/PyGeodesy/docs/pygeodesy.karney-module.html>}.
@@ -329,6 +329,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.}
329
329
  @var PI_3: One third PI, M{PI / 3} (C{float}).
330
330
  @var PI4: Four PI, M{PI * 4} (C{float}).
331
331
  @var PI_4: Quarter PI, M{PI / 4} (C{float}).
332
+ @var PI_6: One sixth PI, M{PI / 6} (C{float}).
332
333
 
333
334
  @var R_MA: Equatorial earth radius (C{meter}), WGS84, EPSG:3785.
334
335
  @var R_MB: Polar earth radius (C{meter}), WGS84, EPSG:3785.
@@ -604,7 +605,7 @@ else:
604
605
 
605
606
  from pygeodesy.internals import _version2, _DOT_ # noqa: E402
606
607
  # from pygeodesy.interns import _DOT_ # from .internals
607
- __version__ = '25.08.25'
608
+ __version__ = '25.10.10'
608
609
  # see setup.py for similar logic
609
610
  version = _DOT_(*_version2(__version__, n=3))
610
611
 
@@ -29,7 +29,7 @@ from pygeodesy.lazily import _ALL_OTHER
29
29
  # no modules: auxAngle, auxDLat, auxDST, auxily, auxLat
30
30
  __all__ = _ALL_OTHER(Aux, AuxAngle, AuxDLat, AuxDST, AuxLat,
31
31
  AuxBeta, AuxChi, AuxMu, AuxPhi, AuxTheta, AuxXi)
32
- __version__ = '25.04.14'
32
+ __version__ = '25.08.28'
33
33
 
34
34
  # **) MIT License
35
35
  #
@@ -17,7 +17,7 @@ from __future__ import division as _; del _ # noqa: E702 ;
17
17
  from pygeodesy.auxilats.auxily import Aux, _Aux2Greek, AuxError
18
18
  from pygeodesy.basics import map1, map2, _xinstanceof
19
19
  from pygeodesy.constants import EPS, _INF_NAN_NINF, MAX, NAN, _0_0, _0_5, _1_0, \
20
- _copysign_1_0, _over, _pos_self, isfinite, isnan
20
+ _copysign_1_0, isfinite, isnan, _over, _pos_self
21
21
  # from pygeodesy.errors import AuxError # from .auxilats.auxily
22
22
  from pygeodesy.fmath import hypot, unstr
23
23
  from pygeodesy.fsums import _add_op_, _iadd_op_, _isub_op_, _sub_op_
@@ -32,7 +32,7 @@ from pygeodesy.utily import atan2, atan2d, sincos2, sincos2d
32
32
  from math import asinh, copysign, degrees, fabs, radians, sinh
33
33
 
34
34
  __all__ = ()
35
- __version__ = '25.05.12'
35
+ __version__ = '25.08.31'
36
36
 
37
37
  _0_INF_NAN_NINF = (0, _0_0) + _INF_NAN_NINF
38
38
  _MAX_2 = MAX * _0_5 # PYCHOK used!
@@ -505,6 +505,7 @@ _AUXClass = {Aux.BETA: AuxBeta,
505
505
  Aux.CHI: AuxChi,
506
506
  Aux.MU: AuxMu,
507
507
  Aux.PHI: AuxPhi,
508
+ # Aux.PSI: AuxPSI, # Isometric
508
509
  Aux.THETA: AuxTheta,
509
510
  Aux.XI: AuxXi}
510
511
 
@@ -525,7 +526,7 @@ def _yx2(yx):
525
526
  return y, x
526
527
 
527
528
 
528
- __all__ += _ALL_DOCS(AuxAngle, AuxBeta, AuxChi, AuxMu, AuxPhi, AuxTheta, AuxXi)
529
+ __all__ += _ALL_DOCS(AuxAngle, *_AUXClass.values())
529
530
 
530
531
  # **) MIT License
531
532
  #
@@ -29,7 +29,7 @@ from pygeodesy.utily import atan1
29
29
  from math import asinh, copysign
30
30
 
31
31
  __all__ = ()
32
- __version__ = '25.05.12'
32
+ __version__ = '25.08.31'
33
33
 
34
34
 
35
35
  class Aux(object):
pygeodesy/azimuthal.py CHANGED
@@ -49,7 +49,7 @@ from pygeodesy.ellipsoidalBase import LatLonEllipsoidalBase as _LLEB, \
49
49
  _isin, _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, fdot_, hypot as _hypot, Fsum
52
+ from pygeodesy.fmath import euclid, 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.internals import typename # from .karney
@@ -71,7 +71,7 @@ from pygeodesy.utily import asin1, atan1, atan2, atan2b, atan2d, \
71
71
  from math import acos, degrees, fabs, sin, sqrt
72
72
 
73
73
  __all__ = _ALL_LAZY.azimuthal
74
- __version__ = '25.05.12'
74
+ __version__ = '25.09.29'
75
75
 
76
76
  _EPS_K = _EPStol * _0_1 # Karney's eps_ or _EPSmin * _0_1?
77
77
  _over_horizon_ = 'over horizon'
@@ -147,7 +147,7 @@ class _AzimuthalBase(_NamedBase):
147
147
  '''I{Must be overloaded}.'''
148
148
  self._notOverloaded(lat, lon, **name)
149
149
 
150
- def _forward(self, lat, lon, name, _k_t_2):
150
+ def _forward(self, lat, lon, name, _k_t):
151
151
  '''(INTERNAL) Azimuthal (spherical) forward C{lat, lon} to C{x, y}.
152
152
  '''
153
153
  lat, lon = Lat_(lat), Lon_(lon)
@@ -155,16 +155,16 @@ class _AzimuthalBase(_NamedBase):
155
155
  s0, c0 = self._sc0
156
156
 
157
157
  cb *= ca
158
- k, t = _k_t_2(fdot_(s0, sa, c0, cb))
158
+ k, t = _k_t(c0 * cb + s0 * sa)
159
159
  if t:
160
160
  r = k * self.radius
161
- y = r * fdot_(c0, sa, -s0, cb)
161
+ y = r * (c0 * sa - s0 * cb)
162
162
  e, n, z, _ = _enzh4(r * sb * ca, y, None)
163
163
  else: # 0 or 180
164
164
  e = n = z = _0_0
165
165
 
166
166
  t = Azimuthal7Tuple(e, n, lat, lon, z, k, self.datum,
167
- name=self._name__(name))
167
+ name=self._name__(name))
168
168
  return t
169
169
 
170
170
  def _forwards(self, *lls):
@@ -258,7 +258,7 @@ class _AzimuthalBase(_NamedBase):
258
258
  if lea or fabs(c0) > EPS:
259
259
  d = atan2d(e * sc, r * c0 * cc - n * s0 * sc)
260
260
  else:
261
- d = atan2d(e, (n if s0 < 0 else -n))
261
+ d = atan2d(e, (n if s0 < 0 else -n))
262
262
  lon = _norm180(self.lon0 + d)
263
263
 
264
264
  if LatLon is None:
@@ -745,8 +745,8 @@ class _GnomonicBase(_AzimuthalGeodesic):
745
745
 
746
746
  @arg lat: Latitude of the location (C{degrees90}).
747
747
  @arg lon: Longitude of the location (C{degrees180}).
748
- @kwarg raiser: Do or don't throw an error (C{bool}) if
749
- the location lies over the horizon.
748
+ @kwarg raiser: If C{False}, do not throw an error if the location lies
749
+ over the horizon (C{bool}).
750
750
  @kwarg name: Optional C{B{name}=NN} for the location (C{str}).
751
751
 
752
752
  @return: An L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}
@@ -760,8 +760,6 @@ class _GnomonicBase(_AzimuthalGeodesic):
760
760
  @raise AzimuthalError: Invalid B{C{lat}}, B{C{lon}} or the location lies
761
761
  over the horizon and C{B{raiser}=True}.
762
762
  '''
763
- self._iteration = 0
764
-
765
763
  r = self.geodesic.Inverse(self.lat0, self.lon0,
766
764
  Lat_(lat), Lon_(lon), outmask=self._mask)
767
765
  M = r.M21
@@ -776,7 +774,7 @@ class _GnomonicBase(_AzimuthalGeodesic):
776
774
  e = n = NAN
777
775
 
778
776
  t = self._7Tuple(e, n, r, _name__(name), M=M)
779
- t._iteraton = 0
777
+ t._iteration = self._iteration = 0
780
778
  return t
781
779
 
782
780
  def reverse(self, x, y, LatLon=None, **name_LatLon_kwds): # PYCHOK signature
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__ = '25.04.14'
40
+ __version__ = '25.09.04'
41
41
 
42
42
  _below_ = 'below'
43
43
  _list_tuple_types = (list, tuple)
@@ -201,7 +201,7 @@ def copytype(x, y):
201
201
 
202
202
 
203
203
  def _enumereverse(iterable):
204
- '''(INTERNAL) Reversed C{enumberate}.
204
+ '''(INTERNAL) Reversed C{enumerate}.
205
205
  '''
206
206
  for j in _reverange(len(iterable)):
207
207
  yield j, iterable[j]
@@ -714,11 +714,11 @@ def _reverange(n, stop=-1, step=-1):
714
714
 
715
715
 
716
716
  def signBit(x):
717
- '''Return C{signbit(B{x})}, like C++.
717
+ '''Return C{signbit(B{x})}, like C++, see also L{isneg}.
718
718
 
719
719
  @return: C{True} if C{B{x} < 0} or C{NEG0} (C{bool}).
720
720
  '''
721
- return x < 0 or _MODS.constants.isneg0(x)
721
+ return (x or _copysign(1, x)) < 0
722
722
 
723
723
 
724
724
  def _signOf(x, ref): # in .fsums
pygeodesy/booleans.py CHANGED
@@ -45,7 +45,7 @@ from pygeodesy.utily import fabs, _unrollon, _Wrap
45
45
  # from math import fabs # from .utily
46
46
 
47
47
  __all__ = _ALL_LAZY.booleans
48
- __version__ = '25.05.26'
48
+ __version__ = '25.09.04'
49
49
 
50
50
  _0EPS = EPS # near-zero, positive
51
51
  _EPS0 = -EPS # near-zero, negative
@@ -60,26 +60,26 @@ _corners_ = 'corners'
60
60
  _open_ = 'open'
61
61
 
62
62
 
63
- def _Enum(txt, enum): # PYCHOK unused
63
+ def _Cnum(txt, enum): # PYCHOK unused
64
64
  return txt # NN(txt, _TILDE_, enum)
65
65
 
66
66
 
67
67
  class _L(object): # Intersection labels
68
- CROSSING = _Enum(_X_, 1) # C++ enum
69
- CROSSING_D = _Enum(_X_ + _d_, 8)
68
+ CROSSING = _Cnum(_X_, 1) # C++ enum
69
+ CROSSING_D = _Cnum(_X_ + _d_, 8)
70
70
  CROSSINGs = (CROSSING, CROSSING_D)
71
- BOUNCING = _Enum(_B_, 2)
72
- BOUNCING_D = _Enum(_B_ + _d_, 9)
71
+ BOUNCING = _Cnum(_B_, 2)
72
+ BOUNCING_D = _Cnum(_B_ + _d_, 9)
73
73
  BOUNCINGs = (BOUNCING, BOUNCING_D) + CROSSINGs
74
- LEFT_ON = _Enum('Lo', 3)
75
- ON_ON = _Enum('oo', 5)
76
- ON_LEFT = _Enum('oL', 6)
77
- ON_RIGHT = _Enum('oR', 7)
78
- RIGHT_ON = _Enum('Ro', 4)
74
+ LEFT_ON = _Cnum('Lo', 3)
75
+ ON_ON = _Cnum('oo', 5)
76
+ ON_LEFT = _Cnum('oL', 6)
77
+ ON_RIGHT = _Cnum('oR', 7)
78
+ RIGHT_ON = _Cnum('Ro', 4)
79
79
  RIGHT_LEFT_ON = (RIGHT_ON, LEFT_ON)
80
80
  # Entry/Exit flags
81
- ENTRY = _Enum(_e_, 1)
82
- EXIT = _Enum(_x_, 0)
81
+ ENTRY = _Cnum(_e_, 1)
82
+ EXIT = _Cnum(_x_, 0)
83
83
  Toggle = {ENTRY: EXIT,
84
84
  EXIT: ENTRY,
85
85
  None: None}
@@ -88,10 +88,10 @@ _L = _L() # PYCHOK singleton
88
88
 
89
89
 
90
90
  class _RP(object): # RelativePositions
91
- IS_Pm = _Enum('Pm', 2) # C++ enum
92
- IS_Pp = _Enum('Pp', 3)
93
- LEFT = _Enum('L', 0)
94
- RIGHT = _Enum(_R_, 1)
91
+ IS_Pm = _Cnum('Pm', 2) # C++ enum
92
+ IS_Pp = _Cnum('Pp', 3)
93
+ LEFT = _Cnum('L', 0)
94
+ RIGHT = _Cnum(_R_, 1)
95
95
 
96
96
  _RP = _RP() # PYCHOK singleton
97
97
 
@@ -1521,16 +1521,16 @@ class _CompositeGH(_CompositeBase):
1521
1521
  class _EdgeFHP(object):
1522
1522
  # An edge between two L{LatLonFHP} points.
1523
1523
 
1524
- X_INTERSECT = _Enum('Xi', 1) # C++ enum
1525
- X_OVERLAP = _Enum('Xo', 5)
1526
- P_INTERSECT = _Enum('Pi', 3)
1527
- P_OVERLAP = _Enum('Po', 7)
1524
+ X_INTERSECT = _Cnum('Xi', 1) # C++ enum
1525
+ X_OVERLAP = _Cnum('Xo', 5)
1526
+ P_INTERSECT = _Cnum('Pi', 3)
1527
+ P_OVERLAP = _Cnum('Po', 7)
1528
1528
  Ps = (P_INTERSECT, P_OVERLAP, X_OVERLAP)
1529
- Q_INTERSECT = _Enum('Qi', 2)
1530
- Q_OVERLAP = _Enum('Qo', 6)
1529
+ Q_INTERSECT = _Cnum('Qi', 2)
1530
+ Q_OVERLAP = _Cnum('Qo', 6)
1531
1531
  Qs = (Q_INTERSECT, Q_OVERLAP, X_OVERLAP)
1532
- V_INTERSECT = _Enum('Vi', 4)
1533
- V_OVERLAP = _Enum('Vo', 8)
1532
+ V_INTERSECT = _Cnum('Vi', 4)
1533
+ V_OVERLAP = _Cnum('Vo', 8)
1534
1534
  Vs = (V_INTERSECT, V_OVERLAP)
1535
1535
 
1536
1536
  def __init__(self, p1, p2, **unused):
pygeodesy/constants.py CHANGED
@@ -10,7 +10,7 @@ L{pygeodesy.isnon0} and L{pygeodesy.remainder}.
10
10
  # make sure int/int division yields float quotient, see .basics
11
11
  from __future__ import division as _; del _ # noqa: E702 ;
12
12
 
13
- from pygeodesy.basics import _copysign, isbool, iscomplex, isint
13
+ from pygeodesy.basics import _copysign, isbool, iscomplex, isint, signBit
14
14
  from pygeodesy.errors import _xError, _xError2, _xkwds_get1, _xkwds_item2
15
15
  # from pygeodesy.fsums import _isFsum_2Tuple # _MODS
16
16
  from pygeodesy.internals import _0_0, _100_0, typename
@@ -26,25 +26,31 @@ except ImportError: # Python 2-
26
26
  _inf, _nan = float(_INF_), float(_NAN_)
27
27
 
28
28
  __all__ = _ALL_LAZY.constants
29
- __version__ = '25.05.26'
29
+ __version__ = '25.09.11'
30
30
 
31
31
 
32
32
  def _copysign_0_0(y):
33
33
  '''(INTERNAL) copysign(0.0, y), only C{float}.
34
34
  '''
35
- return _N_0_0 if y < 0 else _0_0
35
+ return _N_0_0 if signBit(y) else _0_0
36
36
 
37
37
 
38
38
  def _copysign_1_0(y):
39
39
  '''(INTERNAL) copysign(1.0, y), only C{float}.
40
40
  '''
41
- return _N_1_0 if y < 0 else _1_0
41
+ return _N_1_0 if signBit(y) else _1_0
42
42
 
43
43
 
44
44
  def _copysignINF(y):
45
45
  '''(INTERNAL) copysign(INF, y), only C{float}.
46
46
  '''
47
- return NINF if y < 0 else INF
47
+ return NINF if signBit(y) else INF
48
+
49
+
50
+ def _flipsign(x, y):
51
+ '''(INTERNAL) Negate C{x} for negative C{y}.
52
+ '''
53
+ return (-x) if signBit(y) else x
48
54
 
49
55
 
50
56
  def _Float(**name_arg):
@@ -137,7 +143,7 @@ def _naninf(p, *xs):
137
143
 
138
144
 
139
145
  def _over(p, q):
140
- '''(INTERNAL) Return C{B{p} / B{q}} avoiding C{ZeroDivisionError} exceptions.
146
+ '''(INTERNAL) Return C{B{p} / B{q}} without C{ZeroDivisionError} exceptions.
141
147
  '''
142
148
  try:
143
149
  return (p / q) # if p else _copysign_0_0(q)
@@ -145,6 +151,18 @@ def _over(p, q):
145
151
  return (_copysignINF(p) if isfinite(p) else NAN) if p else p
146
152
 
147
153
 
154
+ def _over_1(p, q):
155
+ '''(INTERNAL) Return C{B{p} / B{q}} with exact C{1.0} and without C{ZeroDivisionError} exceptions.
156
+ '''
157
+ if fabs(p) != fabs(q):
158
+ r = _over(p, q)
159
+ else:
160
+ r = _flipsign(p, q)
161
+ if p:
162
+ r = _copysign_1_0(r)
163
+ return r
164
+
165
+
148
166
  def _1_over(x):
149
167
  '''(INTERNAL) Return reciprocal C{1 / B{x}} avoiding C{ZeroDivisionError} exceptions.
150
168
  '''
@@ -168,6 +186,7 @@ _0_1 = _float( 0.1) # PYCHOK expected
168
186
  _0_125 = _float( 0.125) # PYCHOK expected
169
187
  _0_25 = _float( 0.25) # PYCHOK expected
170
188
  _0_5 = _float( 0.5) # PYCHOK expected
189
+ _0_75 = _float( 0.75) # PYCHOK expected
171
190
  _1_0 = _float( 1) # PYCHOK expected
172
191
  _1_0_1T = _1_0, # PYCHOK 1-tuple
173
192
  _1_5 = _float( 1.5) # PYCHOK expected
@@ -218,40 +237,35 @@ try:
218
237
  # RADIX = Int( RADIX =_f_i.radix) # PYTHON system's float base
219
238
  del _f_i
220
239
  except ImportError: # PYCHOK no cover
221
- DIG = Int( DIG =15) # PYCHOK system's 64-bit float decimal digits
240
+ DIG = Int( DIG =15) # PYCHOK system's 64-bit float decimal digits
222
241
  EPS = _Float(EPS =2.220446049250313e-16) # PYCHOK EPSilon 2**-52, M{EPS +/- 1 != 1}
223
- MANT_DIG = Int( MANT_DIG=53) # PYCHOK float mantissa bits ≈ 53 (C{int})
242
+ MANT_DIG = Int( MANT_DIG=53) # PYCHOK float mantissa bits ≈ 53 (C{int})
224
243
  MAX = _Float(MAX =pow(_2_0, 1023) * (_2_0 - EPS)) # PYCHOK ≈ 10**308
225
- MAX_EXP = Int( MAX_ESP =_log2(MAX)) # 308 base 10
244
+ MAX_EXP = Int( MAX_ESP =_log2(MAX)) # 308 base 10
226
245
  MIN = _Float(MIN =pow(_2_0, -1021)) # PYCHOK ≈ 10**-308
227
- MIN_EXP = Int(MIN_EXP =_log2(MIN)) # -307 base 10
228
- # RADIX = Int(Radix =2) # base
229
-
230
- EPS0 = _Float( EPS0 = EPS**2) # PYCHOK near-/non-zero comparison 4.930381e-32, or EPS or EPS_2
231
- EPS02 = _Float( EPS02 = EPS**4) # PYCHOK near-zero-squared comparison 2.430865e-63
232
- EPS_2 = _Float( EPS_2 = EPS / _2_0) # PYCHOK ≈ 1.110223024625e-16
233
- EPS1 = _Float( EPS1 =_1_0 - EPS) # PYCHOK ≈ 0.9999999999999998
234
- EPS2 = _Float( EPS2 = EPS * _2_0) # PYCHOK ≈ 4.440892098501e-16
235
- EPS4 = _Float( EPS4 = EPS * _4_0) # PYCHOK ≈ 8.881784197001e-16
236
- # _1EPS = _Float(_1EPS =_1_0 + EPS) # PYCHOK ≈ 1.0000000000000002
237
- _1_EPS = _Float(_1_EPS =_1_0 / EPS) # PYCHOK = 4503599627370496.0
238
- # _2_EPS = _Float(_2_EPS =_2_0 / EPS) # PYCHOK = 9007199254740992.0
239
- _EPS2e4 = _Float(_EPS2e4= EPS2 * 1.e4) # PYCHOK ≈ 4.440892098501e-12
240
- _EPS4e8 = _Float(_EPS4e8= EPS4 * 1.e8) # PYCHOK ≈ 8.881784197001e-08
241
- _EPSjam = _Float(_EPSjam= pow(EPS, 0.75)) # PYCHOK = 1.818989403546e-12
242
- _EPSmin = _Float(_EPSmin= sqrt(MIN)) # PYCHOK = 1.49166814624e-154
243
- _EPSqrt = _Float(_EPSqrt= sqrt(EPS)) # PYCHOK = 1.49011611938e5-08
244
- _EPStol = _Float(_EPStol=_EPSqrt * _0_1) # PYCHOK = 1.49011611938e5-09 == sqrt(EPS * _0_01)
246
+ MIN_EXP = Int(MIN_EXP =_log2(MIN)) # -307 base 10
247
+ # RADIX = Int(Radix =2) # base
248
+
249
+ EPS0 = _Float( EPS0 = EPS**2) # PYCHOK near-/non-zero comparison 4.930381e-32, or EPS or EPS_2
250
+ EPS02 = _Float( EPS02 = EPS**4) # PYCHOK near-zero-squared comparison 2.430865e-63
251
+ EPS_2 = _Float( EPS_2 = EPS / _2_0) # PYCHOK ≈ 1.110223024625e-16
252
+ EPS1 = _Float( EPS1 =_1_0 - EPS) # PYCHOK ≈ 0.9999999999999998
253
+ EPS2 = _Float( EPS2 = EPS * _2_0) # PYCHOK ≈ 4.440892098501e-16
254
+ EPS4 = _Float( EPS4 = EPS * _4_0) # PYCHOK ≈ 8.881784197001e-16
255
+ # _1EPS = _Float(_1EPS =_1_0 + EPS) # PYCHOK ≈ 1.0000000000000002
256
+ _1_EPS = _Float(_1_EPS =_1_0 / EPS) # PYCHOK = 4503599627370496.0
257
+ # _2_EPS = _Float(_2_EPS =_2_0 / EPS) # PYCHOK = 9007199254740992.0
258
+ _EPS2e4 = _Float(_EPS2e4= EPS2 * 1.e4) # PYCHOK ≈ 4.440892098501e-12
259
+ _EPS4e8 = _Float(_EPS4e8= EPS4 * 1.e8) # PYCHOK ≈ 8.881784197001e-08
260
+ _EPSjam = _Float(_EPSjam= pow(EPS, _0_75)) # PYCHOK = 1.818989403546e-12
261
+ _EPSmin = _Float(_EPSmin= sqrt(MIN)) # PYCHOK = 1.49166814624e-154
262
+ _EPSqrt = _Float(_EPSqrt= sqrt(EPS)) # PYCHOK = 1.49011611938e5-08
263
+ _EPStol = _Float(_EPStol=_EPSqrt * _0_1) # PYCHOK = 1.49011611938e5-09 == sqrt(EPS * _0_01)
245
264
 
246
265
  _89_999 = _Float(_89_999=_90_0 * EPS1) # just below 90.0
247
266
  # <https://Numbers.Computation.Free.FR/Constants/Miscellaneous/digits.html>
248
- _1__90 = _Float(_1__90 =_1_0 / _90_0) # PYCHOK = 0.011_111_111_111_111_111_111_111_111_111_111_111_111_111_111_11111
267
+ # _1__90 = _Float(_1__90 =_1_0 / _90_0) # PYCHOK = 0.011_111_111_111_111_111_111_111_111_111_111_111_111_111_111_11111
249
268
  _2__PI = _Float(_2__PI =_2_0 / _pi) # PYCHOK = 0.636_619_772_367_581_343_075_535_053_490_057_448_137_838_582_96182
250
-
251
- _1_16th = _Float(_1_16th=_1_0 / _16_0) # PYCHOK in .ellipsoids, .karney
252
- _1_3rd = _Float(_1_3rd =_1_0 / _3_0) # PYCHOK in .fmath
253
- _1_6th = _Float(_1_6th =_1_0 / _6_0) # PYCHOK in .fmath
254
-
255
269
  _K0_UTM = _Float(_K0_UTM = 0.9996) # PYCHOK in .etm, .ktm, .utm, UTM scale at central meridian
256
270
  # sqrt(2) <https://WikiPedia.org/wiki/Square_root_of_2>
257
271
  # 1.414213562373095_048_801_688_724_209_698_078_569_671_875_376_948_073_176_679_737_99
@@ -273,6 +287,7 @@ PI3_2 = _Float(PI3_2=_pi * _1_5) # PYCHOK PI and a half, M{PI * 3 / 2}
273
287
  PI_3 = _Float(PI_3 =_pi / _3_0) # PYCHOK One third PI, M{PI / 3}
274
288
  PI4 = _Float(PI4 =_pi * _4_0) # PYCHOK Four PI, M{PI * 4}
275
289
  PI_4 = _Float(PI_4 =_pi / _4_0) # PYCHOK Quarter PI, M{PI / 4}
290
+ PI_6 = _Float(PI_6 =_pi / _6_0) # PYCHOK One sixth PI, M{PI / 6}
276
291
 
277
292
  R_MA = _Radius(R_MA=6378137.0) # PYCHOK equatorial earth radius (C{meter}), WGS84, EPSG:3785
278
293
  R_MB = _Radius(R_MB=6356752.3) # PYCHOK polar earth radius (C{meter}), WGS84, EPSG:3785
@@ -417,6 +432,17 @@ def isnear90(x, eps90=EPS0):
417
432
  return bool(eps90 > (x - _90_0) > -eps90)
418
433
 
419
434
 
435
+ def isneg(x):
436
+ '''Check for negative C{x}, including L{NEG0}.
437
+
438
+ @arg x: Value (C{scalar}).
439
+
440
+ @return: C{True} if C{B{x} < 0 or NEG0},
441
+ C{False} otherwise.
442
+ '''
443
+ return signBit(x)
444
+
445
+
420
446
  def isneg0(x):
421
447
  '''Check for L{NEG0}, negative C{0.0}.
422
448
 
@@ -4,6 +4,7 @@
4
4
  u'''DEPRECATED functions kept for backward compatibility.
5
5
  '''
6
6
 
7
+ # from pygeodesy.basics import copysign0 # _MODS_
7
8
  from pygeodesy.constants import EPS, R_M, float0_
8
9
  from pygeodesy.deprecated.classes import ClipCS3Tuple, TriAngle4Tuple, _TriAngle5Tuple
9
10
  from pygeodesy.interns import NN, _area_, _COMMASPACE_, _negative_, \
pygeodesy/dms.py CHANGED
@@ -63,7 +63,7 @@ U{Vector-based geodesy<https://www.Movable-Type.co.UK/scripts/latlong-vectors.ht
63
63
 
64
64
  from pygeodesy.basics import copysign0, isLatLon, isodd, issequence, isstr, \
65
65
  neg as _neg, typename # in .ups
66
- from pygeodesy.constants import _umod_360, _0_0, _0_5, _60_0, _360_0, _3600_0
66
+ from pygeodesy.constants import _0_0, _0_5, _60_0, _360_0, _3600_0, _umod_360
67
67
  from pygeodesy.errors import ParseError, RangeError, _TypeError, _ValueError, \
68
68
  _parseX, rangerrors, _xError, _xkwds, _envPYGEODESY
69
69
  # from pygeodesy.internals import _envPYGEODESY, typename # from .errors
@@ -86,7 +86,7 @@ except ImportError: # Python 3+
86
86
  from string import ascii_letters as _LETTERS
87
87
 
88
88
  __all__ = _ALL_LAZY.dms
89
- __version__ = '25.04.14'
89
+ __version__ = '25.08.31'
90
90
 
91
91
  _beyond_ = 'beyond'
92
92
  _deg_min_ = 'deg+min'
pygeodesy/ecef.py CHANGED
@@ -62,8 +62,8 @@ plane} as opposed to I{geocentric} (ECEF) ones.
62
62
  from pygeodesy.basics import copysign0, _isin, isscalar, issubclassof, neg, map1, \
63
63
  _xinstanceof, _xsubclassof, typename # _args_kwds_names
64
64
  from pygeodesy.constants import EPS, EPS0, EPS02, EPS1, INT0, PI, PI_2, _0_0, \
65
- _0_5, _1_0, _1_0_1T, _2_0, _3_0, _4_0, _6_0, \
66
- _90_0, _copysign_1_0, isnon0 # PYCHOK used!
65
+ _0_5, _1_0, _1_0_1T, _2_0, _3_0, _4_0, _6_0, _90_0, \
66
+ _copysign_1_0, isnon0 # PYCHOK used!
67
67
  from pygeodesy.datums import _ellipsoidal_datum, _WGS84, a_f2Tuple, _EWGS84
68
68
  from pygeodesy.ecefLocals import _EcefLocal
69
69
  # from pygeodesy.ellipsoids import a_f2Tuple, _EWGS84 # from .datums
@@ -91,7 +91,7 @@ from pygeodesy.utily import atan1, atan1d, atan2, atan2d, degrees90, degrees180,
91
91
  from math import cos, degrees, fabs, radians, sqrt
92
92
 
93
93
  __all__ = _ALL_LAZY.ecef
94
- __version__ = '25.08.25'
94
+ __version__ = '25.08.31'
95
95
 
96
96
  _Ecef_ = 'Ecef'
97
97
  _prolate_ = 'prolate'
@@ -11,20 +11,20 @@ L{GeodesicExact}, L{GeodesicAreaExact} and L{GeodesicLineExact}.
11
11
 
12
12
  # from pygeodesy.datums import _WGS84 # from .ellipsoidalBase
13
13
  from pygeodesy.ellipsoidalBase import CartesianEllipsoidalBase, \
14
- _nearestOn, _WGS84
14
+ _nearestOn, Property_RO, _WGS84
15
15
  from pygeodesy.ellipsoidalBaseDI import LatLonEllipsoidalBaseDI, \
16
16
  _intersection3, _intersections2, \
17
17
  _TOL_M, intersecant2
18
18
  # from pygeodesy.errors import _xkwds # from .karney
19
- from pygeodesy.karney import _polygon, fabs, Property_RO, _xkwds
19
+ from pygeodesy.karney import _polygon, fabs, _xkwds
20
20
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _ALL_OTHER
21
21
  from pygeodesy.points import _areaError, ispolar # PYCHOK exported
22
- # from pygeodesy.props import Property_RO # from .karney
22
+ # from pygeodesy.props import Property_RO # from .ellipsoidalBase
23
23
 
24
24
  # from math import fabs # from .karney
25
25
 
26
26
  __all__ = _ALL_LAZY.ellipsoidalExact
27
- __version__ = '25.05.28'
27
+ __version__ = '25.08.28'
28
28
 
29
29
 
30
30
  class Cartesian(CartesianEllipsoidalBase):
@@ -12,11 +12,11 @@ L{geodsolve}, a wrapper invoking I{Karney}'s U{GeodSolve
12
12
 
13
13
  # from pygeodesy.datums import _WGS84 # from .ellipsoidalBase
14
14
  from pygeodesy.ellipsoidalBase import CartesianEllipsoidalBase, \
15
- _nearestOn, _WGS84
15
+ _nearestOn, Property_RO, _WGS84
16
16
  from pygeodesy.ellipsoidalBaseDI import LatLonEllipsoidalBaseDI, _TOL_M, \
17
17
  _intersection3, _intersections2
18
18
  # from pygeodesy.errors import _xkwds # from .karney
19
- from pygeodesy.karney import fabs, _polygon, Property_RO, _xkwds
19
+ from pygeodesy.karney import fabs, _polygon, _xkwds
20
20
  from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS, _ALL_OTHER
21
21
  from pygeodesy.points import _areaError, ispolar # PYCHOK exported
22
22
  # from pygeodesy.props import Property_RO # from .karney
@@ -24,7 +24,7 @@ from pygeodesy.points import _areaError, ispolar # PYCHOK exported
24
24
  # from math import fabs # from .karney
25
25
 
26
26
  __all__ = _ALL_LAZY.ellipsoidalGeodSolve
27
- __version__ = '25.05.28'
27
+ __version__ = '25.08.28'
28
28
 
29
29
 
30
30
  class Cartesian(CartesianEllipsoidalBase):