pygeodesy 25.7.25__py2.py3-none-any.whl → 25.9.9__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 (44) hide show
  1. pygeodesy/__init__.py +10 -9
  2. pygeodesy/auxilats/__init__.py +1 -1
  3. pygeodesy/auxilats/auxAngle.py +4 -3
  4. pygeodesy/auxilats/auxily.py +1 -1
  5. pygeodesy/basics.py +4 -4
  6. pygeodesy/booleans.py +25 -25
  7. pygeodesy/cartesianBase.py +21 -20
  8. pygeodesy/constants.py +37 -7
  9. pygeodesy/deprecated/functions.py +1 -0
  10. pygeodesy/dms.py +2 -2
  11. pygeodesy/ecef.py +324 -260
  12. pygeodesy/ellipsoidalExact.py +4 -4
  13. pygeodesy/ellipsoidalGeodSolve.py +3 -3
  14. pygeodesy/ellipsoids.py +79 -52
  15. pygeodesy/elliptic.py +8 -11
  16. pygeodesy/errors.py +18 -5
  17. pygeodesy/etm.py +8 -8
  18. pygeodesy/fmath.py +1 -1
  19. pygeodesy/geodesicx/__init__.py +1 -1
  20. pygeodesy/geodesicx/__main__.py +1 -0
  21. pygeodesy/geodesicx/gx.py +30 -37
  22. pygeodesy/geodesicx/gxbases.py +1 -5
  23. pygeodesy/geodesicx/gxline.py +43 -34
  24. pygeodesy/geodsolve.py +10 -17
  25. pygeodesy/internals.py +39 -15
  26. pygeodesy/karney.py +19 -18
  27. pygeodesy/ktm.py +3 -3
  28. pygeodesy/latlonBase.py +4 -4
  29. pygeodesy/lazily.py +14 -13
  30. pygeodesy/lcc.py +5 -5
  31. pygeodesy/named.py +10 -13
  32. pygeodesy/nvectorBase.py +4 -4
  33. pygeodesy/rhumb/__init__.py +1 -1
  34. pygeodesy/rhumb/aux_.py +1 -1
  35. pygeodesy/rhumb/bases.py +7 -8
  36. pygeodesy/rhumb/ekx.py +9 -9
  37. pygeodesy/solveBase.py +14 -3
  38. pygeodesy/sphericalTrigonometry.py +8 -8
  39. pygeodesy/utily.py +200 -159
  40. pygeodesy/vector3dBase.py +10 -8
  41. {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/METADATA +12 -11
  42. {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/RECORD +44 -44
  43. {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/WHEEL +0 -0
  44. {pygeodesy-25.7.25.dist-info → pygeodesy-25.9.9.dist-info}/top_level.txt +0 -0
pygeodesy/__init__.py CHANGED
@@ -125,7 +125,7 @@ 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.13.7 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.1),
129
129
  Python 3.12.7 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.0,
130
130
  U{numpy<https://PyPI.org/project/numpy>} 2.1.0, U{scipy<https://PyPI.org/project/scipy>} 1.14.1,
131
131
  U{GeodSolve<https://GeographicLib.SourceForge.io/C++/doc/utilities.html>} 2.5,
@@ -143,20 +143,20 @@ 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.5 Sequoia.
146
+ macOS 15.6.1 Sequoia.
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
152
  Test coverage has been measured with U{coverage<https://PyPI.org/project/coverage>} 7.6.1 using Python
153
- 3.13.4, 3.12.7, 3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in
153
+ 3.13.7, 3.12.7, 3.11.5 and 3.10.8. The complete coverage report in HTML and a PDF summary are included in
154
154
  the 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.13.7, 3.12.7, 3.11.5 and 3.10.8 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-5, 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-4 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-5 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
@@ -190,7 +190,7 @@ All Python source code has been statically U{checked<https://GitHub.com/ActiveSt
190
190
  546532_PyChecker_postprocessor>} with U{Ruff<https://GitHub.com/astral-sh/ruff>} using Python 3.13.5 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.5 Sequoia.
193
+ 2.7.18, both in 64-bit on macOS 15.6.1 Sequoia.
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.07.25'
608
+ __version__ = '25.09.09'
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/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):
@@ -27,11 +27,11 @@ from pygeodesy.interns import _COMMASPACE_, _datum_, _no_, _phi_
27
27
  from pygeodesy.interns import _ellipsoidal_, _spherical_ # PYCHOK used!
28
28
  from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
29
29
  from pygeodesy.named import _name2__, _Pass
30
- from pygeodesy.namedTuples import LatLon4Tuple, _NamedTupleTo , Vector3Tuple, \
30
+ from pygeodesy.namedTuples import LatLon4Tuple, _NamedTupleTo, Vector3Tuple, \
31
31
  Vector4Tuple
32
- # from pygeodesy.nvectorBase import _N_vector # _MODS
33
- from pygeodesy.props import deprecated_method, Property, Property_RO, property_doc_, \
34
- property_RO, _update_all
32
+ # from pygeodesy.nvectorBase import _N_Vector # _MODS
33
+ from pygeodesy.props import deprecated_method, Property, Property_RO, \
34
+ property_doc_, property_RO, _update_all
35
35
  # from pygeodesy import resections as _resections # _MODS.into
36
36
  # from pygeodesy.streprs import Fmt # from .fsums
37
37
  # from pygeodesy.triaxials import Triaxial_ # _MODS
@@ -39,12 +39,11 @@ from pygeodesy.units import Degrees, Height, _heigHt, _isMeter, Meter, Radians
39
39
  from pygeodesy.utily import acos1, atan2, sincos2d, sincos2_, degrees, radians
40
40
  from pygeodesy.vector3d import Vector3d, _xyzhdlln4
41
41
  # from pygeodesy.vector3dBase import _xyz3 # _MODS
42
- # from pygeodesy import ltp # _MODS
43
42
 
44
43
  # from math import degrees, fabs, radians, sqrt # from .fmath, .utily
45
44
 
46
45
  __all__ = _ALL_LAZY.cartesianBase
47
- __version__ = '25.05.07'
46
+ __version__ = '25.08.24'
48
47
 
49
48
  _r_ = 'r'
50
49
  _resections = _MODS.into(resections=__name__)
@@ -172,12 +171,13 @@ class CartesianBase(Vector3d, _EcefLocal):
172
171
  @raise TypeError: The B{C{datum}} is not a L{Datum}.
173
172
  '''
174
173
  d = _spherical_datum(datum, name=self.name)
175
- if self._datum: # is not None
176
- if d.isEllipsoidal and not self._datum.isEllipsoidal:
174
+ D = self._datum
175
+ if D: # is not None
176
+ if d.isEllipsoidal and not D.isEllipsoidal:
177
177
  raise _IsnotError(_ellipsoidal_, datum=datum)
178
- elif d.isSpherical and not self._datum.isSpherical:
178
+ elif d.isSpherical and not D.isSpherical:
179
179
  raise _IsnotError(_spherical_, datum=datum)
180
- if self._datum != d:
180
+ if D != d: # or (D and D.name != d.name)
181
181
  _update_all(self)
182
182
  self._datum = d
183
183
 
@@ -302,8 +302,6 @@ class CartesianBase(Vector3d, _EcefLocal):
302
302
  @note: Include keyword argument C{B{datum}=None} if class B{C{Cartesian}}
303
303
  does not accept a B{C{datum}} keyword agument.
304
304
 
305
- @raise TriaxialError: No convergence in triaxial root finding.
306
-
307
305
  @raise TypeError: Invalid or undefined B{C{earth}} or C{datum}.
308
306
  '''
309
307
  n = typename(self.height3)
@@ -410,13 +408,12 @@ class CartesianBase(Vector3d, _EcefLocal):
410
408
 
411
409
  @Property_RO
412
410
  def _N_vector(self):
413
- '''(INTERNAL) Get the (C{nvectorBase._N_vector_}).
411
+ '''(INTERNAL) Get the (C{nvectorBase._N_Vector}).
414
412
  '''
415
- _N = _MODS.nvectorBase._N_vector_
416
- x, y, z, h = self._n_xyzh4(self.datum)
417
- return _N(x, y, z, h=h, name=self.name)
413
+ _N = _MODS.nvectorBase._N_Vector
414
+ return self._n_xyzh4(self.datum, Vector=_N)
418
415
 
419
- def _n_xyzh4(self, datum):
416
+ def _n_xyzh4(self, datum, Vector=Vector4Tuple):
420
417
  '''(INTERNAL) Get the n-vector components as L{Vector4Tuple}.
421
418
  '''
422
419
  def _ErrorEPS0(x):
@@ -434,7 +431,11 @@ class CartesianBase(Vector3d, _EcefLocal):
434
431
  p = hypot2(x, y) * E.a2_
435
432
  q = z**2 * E.e21 * E.a2_
436
433
  r = fsumf_(p, q, -E.e4) / _6_0
434
+ if isnear0(r):
435
+ raise _ErrorEPS0(r)
437
436
  s = (p * q * E.e4) / (_4_0 * r**3)
437
+ if s < 0:
438
+ raise _ErrorEPS0(s)
438
439
  t = cbrt(fsumf_(_1_0, s, sqrt(s * (_2_0 + s))))
439
440
  if isnear0(t):
440
441
  raise _ErrorEPS0(t)
@@ -458,7 +459,7 @@ class CartesianBase(Vector3d, _EcefLocal):
458
459
  raise _ErrorEPS0(t)
459
460
  h = fsumf_(k, E.e2, _N_1_0) / k * t
460
461
  s = e / t # == e * tmp
461
- return Vector4Tuple(x * s, y * s, z / t, h, name=self.name)
462
+ return Vector(x * s, y * s, z / t, h, name=self.name)
462
463
 
463
464
  @Property_RO
464
465
  def philam(self):
@@ -980,8 +981,8 @@ def xyz2rtp_(x_xyz, y=0, z=0, **name):
980
981
  @kwarg name: Optional C{B{name}=NN} (C{str}).
981
982
 
982
983
  @return: L{RadiusThetaPhi3Tuple}C{(r, theta, phi)} with radial distance C{r} (C{meter},
983
- same units as C{x}, C{y} and C{z}), inclination C{theta} (with respect to the
984
- positive z-axis) and azimuthal angle C{phi}, both in L{Radians}.
984
+ same units as C{x}, C{y} and C{z}), inclination C{theta} (polar angle with
985
+ respect to the positive z-axis) and azimuthal angle C{phi}, both in L{Radians}.
985
986
 
986
987
  @see: U{Physics convention<https://WikiPedia.org/wiki/Spherical_coordinate_system>}
987
988
  (ISO 80000-2:2019), class L{RadiusThetaPhi3Tuple} and function L{xyz2rtp}.
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.09'
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
  '''
@@ -245,7 +263,7 @@ _EPStol = _Float(_EPStol=_EPSqrt * _0_1) # PYCHOK = 1.49011611938e5-09 == sqr
245
263
 
246
264
  _89_999 = _Float(_89_999=_90_0 * EPS1) # just below 90.0
247
265
  # <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
266
+ # _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
267
  _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
268
 
251
269
  _1_16th = _Float(_1_16th=_1_0 / _16_0) # PYCHOK in .ellipsoids, .karney
@@ -273,6 +291,7 @@ PI3_2 = _Float(PI3_2=_pi * _1_5) # PYCHOK PI and a half, M{PI * 3 / 2}
273
291
  PI_3 = _Float(PI_3 =_pi / _3_0) # PYCHOK One third PI, M{PI / 3}
274
292
  PI4 = _Float(PI4 =_pi * _4_0) # PYCHOK Four PI, M{PI * 4}
275
293
  PI_4 = _Float(PI_4 =_pi / _4_0) # PYCHOK Quarter PI, M{PI / 4}
294
+ PI_6 = _Float(PI_6 =_pi / _6_0) # PYCHOK One sixth PI, M{PI / 6}
276
295
 
277
296
  R_MA = _Radius(R_MA=6378137.0) # PYCHOK equatorial earth radius (C{meter}), WGS84, EPSG:3785
278
297
  R_MB = _Radius(R_MB=6356752.3) # PYCHOK polar earth radius (C{meter}), WGS84, EPSG:3785
@@ -417,6 +436,17 @@ def isnear90(x, eps90=EPS0):
417
436
  return bool(eps90 > (x - _90_0) > -eps90)
418
437
 
419
438
 
439
+ def isneg(x):
440
+ '''Check for negative C{x}, including L{NEG0}.
441
+
442
+ @arg x: Value (C{scalar}).
443
+
444
+ @return: C{True} if C{B{x} < 0 or NEG0},
445
+ C{False} otherwise.
446
+ '''
447
+ return signBit(x)
448
+
449
+
420
450
  def isneg0(x):
421
451
  '''Check for L{NEG0}, negative C{0.0}.
422
452
 
@@ -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'