pygeodesy 25.9.9__py2.py3-none-any.whl → 25.11.5__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.
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.7 (with U{geographiclib<https://PyPI.org/project/geographiclib>} 2.1),
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,27 +137,23 @@ 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.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
- 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.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
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
159
  The tests also ran with Python 3.13.7 (and U{geographiclib<https://PyPI.org/project/geographiclib>} 2.1) on
@@ -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-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,
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>}.
@@ -605,7 +605,7 @@ else:
605
605
 
606
606
  from pygeodesy.internals import _version2, _DOT_ # noqa: E402
607
607
  # from pygeodesy.interns import _DOT_ # from .internals
608
- __version__ = '25.09.09'
608
+ __version__ = '25.11.05'
609
609
  # see setup.py for similar logic
610
610
  version = _DOT_(*_version2(__version__, n=3))
611
611
 
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/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.09.04'
48
+ __version__ = '25.10.30'
49
49
 
50
50
  _0EPS = EPS # near-zero, positive
51
51
  _EPS0 = -EPS # near-zero, negative
@@ -1434,17 +1434,14 @@ class _CompositeGH(_CompositeBase):
1434
1434
 
1435
1435
  def _clip(self, corners, s_entry, c_entry, Clas=None,
1436
1436
  **closed_inull_raiser_xtend_eps):
1437
- # Clip this polygon with another one, C{corners}.
1438
-
1439
- # Core of Greiner/Hormann's algorithm, enhanced U{Correia's
1440
- # <https://GitHub.com/helderco/univ-polyclip>} implementation***
1441
- # and extended to optionally handle so-called "degenerate cases"
1437
+ # Clip this polygon with another one, C{corners}, using
1438
+ # Greiner/Hormann's algorithm extended to optionally
1439
+ # handle some so-called "degenerate cases"
1442
1440
  S = self
1443
1441
  C = self._class(corners, closed_inull_raiser_xtend_eps,
1444
1442
  raiser=False, xtend=False)
1445
1443
  bt = C._bottom_top_eps2
1446
1444
  lr = C._left_right_eps2
1447
-
1448
1445
  # 1. find intersections
1449
1446
  for s1, s2, Sc in S._edges3(**closed_inull_raiser_xtend_eps):
1450
1447
  if not (_outside(s1.x, s2.x, *lr) or
@@ -1507,13 +1504,13 @@ class _CompositeGH(_CompositeBase):
1507
1504
 
1508
1505
  @property
1509
1506
  def xtend(self):
1510
- '''Get the option to handle I{degenerate cases} (C{bool}).
1507
+ '''Get the option to handle some I{degenerate cases} (C{bool}).
1511
1508
  '''
1512
1509
  return self._xtend
1513
1510
 
1514
1511
  @xtend.setter # PYCHOK setter!
1515
1512
  def xtend(self, xtend):
1516
- '''Set the option to handle I{degenerate cases} (C{bool}).
1513
+ '''Set the option to handle some I{degenerate cases} (C{bool}).
1517
1514
  '''
1518
1515
  self._xtend = bool(xtend)
1519
1516
 
@@ -1825,9 +1822,7 @@ class BooleanFHP(_CompositeFHP, _BooleanBase):
1825
1822
  class BooleanGH(_CompositeGH, _BooleanBase):
1826
1823
  '''I{Composite} class providing I{boolean} operations between two
1827
1824
  I{composites} using the U{Greiner-Hormann<http://www.Inf.USI.CH/
1828
- hormann/papers/Greiner.1998.ECO.pdf>} algorithm and U{Correia
1829
- <https://GitHub.com/helderco/univ-polyclip>}'s implementation,
1830
- modified and extended.
1825
+ hormann/papers/Greiner.1998.ECO.pdf>} algorithm, extended.
1831
1826
 
1832
1827
  The supported operations between (composite) polygon A and B are:
1833
1828
 
@@ -2003,23 +1998,3 @@ __all__ += _ALL_DOCS(_BooleanBase, _Clip,
2003
1998
  # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2004
1999
  # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005
2000
  # OTHER DEALINGS IN THE SOFTWARE.
2006
-
2007
- # ***) GNU GPL 3
2008
- #
2009
- # Copyright (C) 2011-2012 Helder Correia <Helder.MC@Gmail.com>
2010
- #
2011
- # This program is free software: you can redistribute it and/or
2012
- # modify it under the terms of the GNU General Public License as
2013
- # published by the Free Software Foundation, either version 3 of
2014
- # the License, or any later version.
2015
- #
2016
- # This program is distributed in the hope that it will be useful,
2017
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
2018
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2019
- # GNU General Public License for more details.
2020
- #
2021
- # You should have received a copy of the GNU General Public License
2022
- # along with this program. If not, see <http://www.GNU.org/licenses/>.
2023
- #
2024
- # You should have received the README file along with this program.
2025
- # If not, see <https://GitHub.com/helderco/univ-polyclip>.
pygeodesy/clipy.py CHANGED
@@ -31,7 +31,7 @@ from pygeodesy.units import Bool, FIx, HeightX, Lat, Lon, Number_
31
31
  # from math import fabs # from .fmath
32
32
 
33
33
  __all__ = _ALL_LAZY.clipy
34
- __version__ = '25.05.12'
34
+ __version__ = '25.10.30'
35
35
 
36
36
  _fj_ = 'fj'
37
37
  _original_ = 'original'
@@ -237,9 +237,8 @@ def clipCS4(points, lowerleft, upperight, closed=False, inull=False):
237
237
 
238
238
 
239
239
  class ClipFHP4Tuple(_NamedTuple):
240
- '''4-Tuple C{(lat, lon, height, clipid)} for each point of the
241
- L{clipFHP4} result with the C{lat}-, C{lon}gitude, C{height}
242
- and C{clipid} of the polygon or clip.
240
+ '''4-Tuple C{(lat, lon, height, clipid)} for each point of the L{clipFHP4} result
241
+ with the C{lat}-, C{lon}gitude, C{height} and C{clipid} of the polygon or clip.
243
242
 
244
243
  @note: The C{height} is a L{HeightX} instance if this point is
245
244
  an intersection, otherwise a L{Height} or C{int(0)}.
@@ -275,14 +274,13 @@ def clipFHP4(points, corners, closed=False, inull=False, raiser=False, eps=EPS):
275
274
  as the B{C{points}} and B{C{corners}} coordinates).
276
275
 
277
276
  @return: Yield a L{ClipFHP4Tuple}C{(lat, lon, height, clipid)} for each
278
- clipped point. The result may consist of several clips, each
279
- a (closed) polygon with a unique C{clipid}.
277
+ clipped point. The result may consist of several I{clips}, each
278
+ a (closed) polygon with a unique C{clipid} identifier.
280
279
 
281
280
  @raise ClipError: Insufficient B{C{points}} or B{C{corners}} or an open clip.
282
281
 
283
282
  @see: U{Forster, Hormann and Popa<https://www.ScienceDirect.com/science/
284
- article/pii/S259014861930007X>}, class L{BooleanFHP} and function
285
- L{clipGH4}.
283
+ article/pii/S259014861930007X>} and class L{BooleanFHP}.
286
284
  '''
287
285
  P = _MODS.booleans._CompositeFHP(points, kind=_points_, raiser=raiser,
288
286
  eps=eps, name__=clipFHP4)
@@ -292,12 +290,11 @@ def clipFHP4(points, corners, closed=False, inull=False, raiser=False, eps=EPS):
292
290
 
293
291
 
294
292
  class ClipGH4Tuple(ClipFHP4Tuple):
295
- '''4-Tuple C{(lat, lon, height, clipid)} for each point of the
296
- L{clipGH4} result with the C{lat}-, C{lon}gitude, C{height}
297
- and C{clipid} of the polygon or clip.
293
+ '''4-Tuple C{(lat, lon, height, clipid)} for each point of the L{clipGH4} result
294
+ with the C{lat}-, C{lon}gitude, C{height} and C{clipid} of the polygon or clip.
298
295
 
299
- @note: The C{height} is a L{HeightX} instance if this is
300
- an intersection, otherwise a L{Height} or C{int(0)}.
296
+ @note: The C{height} is a L{HeightX} instance if this is an intersection,
297
+ otherwise a L{Height} or C{int(0)}.
301
298
  '''
302
299
  _Names_ = ClipFHP4Tuple._Names_
303
300
  _Units_ = ClipFHP4Tuple._Units_
@@ -305,8 +302,7 @@ class ClipGH4Tuple(ClipFHP4Tuple):
305
302
 
306
303
  def clipGH4(points, corners, closed=False, inull=False, raiser=True, xtend=False, eps=EPS):
307
304
  '''Clip one or more polygons against a clip region or box using the U{Greiner-Hormann
308
- <http://www.Inf.USI.CH/hormann/papers/Greiner.1998.ECO.pdf>} algorithm, U{Correia
309
- <https://GitHub.com/helderco/univ-polyclip>}'s implementation modified and extended.
305
+ <http://www.Inf.USI.CH/hormann/papers/Greiner.1998.ECO.pdf>} algorithm, extended.
310
306
 
311
307
  @arg points: The polygon points and clips (C{LatLon}[]).
312
308
  @arg corners: Three or more points defining the clip regions (C{LatLon}[])
@@ -320,19 +316,17 @@ def clipGH4(points, corners, closed=False, inull=False, raiser=True, xtend=False
320
316
  as the B{C{points}} and B{C{corners}} coordinates).
321
317
 
322
318
  @return: Yield a L{ClipGH4Tuple}C{(lat, lon, height, clipid)} for each
323
- clipped point. The result may consist of several clips, each
324
- a (closed) polygon with a unique C{clipid}.
319
+ clipped point. The result may consist of several I{clips}, each
320
+ a (closed) polygon with a unique C{clipid} identifier.
325
321
 
326
322
  @raise ClipError: Insufficient B{C{points}} or B{C{corners}}, an open clip,
327
323
  a I{degenerate case} or I{unhandled} intersection.
328
324
 
329
325
  @note: To handle I{degenerate cases} like C{point-edge} and C{point-point}
330
- intersections, use function L{clipFHP4}.
326
+ intersections I{properly}, use function L{clipFHP4}.
331
327
 
332
- @see: U{Greiner-Hormann<https://WikiPedia.org/wiki/Greiner–Hormann_clipping_algorithm>},
333
- U{Ionel Daniel Stroe<https://Davis.WPI.edu/~matt/courses/clipping/>}, I{Correia}'s
334
- U{univ-polyclip<https://GitHub.com/helderco/univ-polyclip>}, class L{BooleanGH}
335
- and function L{clipFHP4}.
328
+ @see: U{Greiner-Hormann<https://WikiPedia.org/wiki/Greiner–Hormann_clipping_algorithm>}
329
+ and class L{BooleanGH}.
336
330
  '''
337
331
  S = _MODS.booleans._CompositeGH(points, raiser=raiser, xtend=xtend, eps=eps,
338
332
  name__=clipGH4, kind=_points_)
pygeodesy/constants.py CHANGED
@@ -11,7 +11,7 @@ L{pygeodesy.isnon0} and L{pygeodesy.remainder}.
11
11
  from __future__ import division as _; del _ # noqa: E702 ;
12
12
 
13
13
  from pygeodesy.basics import _copysign, isbool, iscomplex, isint, signBit
14
- from pygeodesy.errors import _xError, _xError2, _xkwds_get1, _xkwds_item2
14
+ from pygeodesy.errors import _ValueError, _xError, _xkwds_get1, _xkwds_item2
15
15
  # from pygeodesy.fsums import _isFsum_2Tuple # _MODS
16
16
  from pygeodesy.internals import _0_0, _100_0, typename
17
17
  from pygeodesy.interns import _DMAIN_, _INF_, _NAN_
@@ -26,7 +26,7 @@ except ImportError: # Python 2-
26
26
  _inf, _nan = float(_INF_), float(_NAN_)
27
27
 
28
28
  __all__ = _ALL_LAZY.constants
29
- __version__ = '25.09.09'
29
+ __version__ = '25.10.15'
30
30
 
31
31
 
32
32
  def _copysign_0_0(y):
@@ -47,7 +47,7 @@ def _copysignINF(y):
47
47
  return NINF if signBit(y) else INF
48
48
 
49
49
 
50
- def _flipsign(x, y):
50
+ def _flipsign(x, y=-1):
51
51
  '''(INTERNAL) Negate C{x} for negative C{y}.
52
52
  '''
53
53
  return (-x) if signBit(y) else x
@@ -60,65 +60,78 @@ def _Float(**name_arg):
60
60
  return Float(_float(arg), name=n)
61
61
 
62
62
 
63
- def _Radius(**name_arg):
64
- '''(INTERNAL) New named, cached C{Radius}.
63
+ def _float(x): # in .datums, .ellipsoids, ...
64
+ '''(INTERNAL) Cache initial C{float}s.
65
65
  '''
66
- n, arg = _xkwds_item2(name_arg)
67
- return Radius(_float(arg), name=n)
66
+ f = float(x)
67
+ return _floats.setdefault(f, f) # PYCHOK del _floats
68
68
 
69
69
 
70
- def float_(*fs, **sets): # sets=False
71
- '''Get scalars as C{float} or I{intern}'ed C{float}.
70
+ def float_(x, sets=False):
71
+ '''Get scalar as C{float} or I{intern}'ed C{float}.
72
72
 
73
- @arg fs: One more values (C{scalar}), all positional.
74
- @kwarg sets: Use C{B{sets}=True} to C{intern} each
75
- B{C{fs}}, otherwise don't C{intern}.
73
+ @arg x: The scalar (C{scalar}).
74
+ @kwarg sets: Use C{True} to C{intern} the B{C{f}},
75
+ otherwise don't (C{bool}).
76
76
 
77
- @return: A single C{float} if only one B{C{fs}} is
78
- given, otherwise a tuple of C{float}s.
77
+ @return: A C{float}.
79
78
 
80
- @raise TypeError: Some B{C{fs}} is not C{scalar}.
79
+ @raise ValueError: Invalid B{C{x}}.
81
80
  '''
82
- fl = []
83
- _a = fl.append
84
- _f = _floats.setdefault if _xkwds_get1(sets, sets=False) else \
85
- _floats.get
86
81
  try:
87
- for i, f in enumerate(fs):
88
- f = float(f)
89
- _a(_f(f, f))
90
- except Exception as x:
91
- E, t = _xError2(x)
92
- fs_i = Fmt.SQUARE(fs=i)
93
- raise E(fs_i, f, txt=t)
94
- return fl[0] if len(fl) == 1 else tuple(fl)
95
-
96
-
97
- def _float(f): # in .datums, .ellipsoids, ...
98
- '''(INTERNAL) Cache initial C{float}s.
99
- '''
100
- f = float(f)
101
- return _floats.setdefault(f, f) # PYCHOK del _floats
82
+ f = float(x)
83
+ if f:
84
+ _f = _floats.setdefault if sets else _floats.get
85
+ f = _f(f, f)
86
+ else:
87
+ f = _N_0_0 if signBit(f) else _0_0
88
+ except Exception as X:
89
+ raise _ValueError(x=x, cause=X)
90
+ return f
102
91
 
103
92
 
104
93
  def float0_(*xs):
105
94
  '''Yield C{B{x}s} as a non-NEG0 C{float}.
106
95
  '''
107
96
  for x in xs:
108
- yield float(x) if x else _0_0
97
+ yield float(x) or _0_0 # if x else _0_0
109
98
 
110
99
 
111
- def _float0(f): # in .auxilats.auxily, .resections, .vector3dBase, ...
100
+ def _float0(x): # in .auxilats.auxily, .resections, .vector3dBase, ...
112
101
  '''(INTERNAL) Return C{float(B{f})} or C{INT0}.
113
102
  '''
114
- if f:
115
- f = float(f)
103
+ if x:
104
+ f = float(x)
116
105
  f = _floats.get(f, f)
117
- elif f is not INT0:
118
- f = float(f) or _0_0 # force None, NN error
106
+ elif x is INT0:
107
+ f = x
108
+ else:
109
+ f = float(x) or _0_0 # force None, NN error
119
110
  return f
120
111
 
121
112
 
113
+ def floats_(*xs, **sets): # sets=False
114
+ '''Yield each scalar as C{float} or I{intern}'ed C{float}.
115
+
116
+ @arg xs: One more values (C{scalar}), all positional.
117
+ @kwarg sets: Use C{B{sets}=True} to C{intern} each
118
+ B{C{fs}}, otherwise don't C{intern}.
119
+
120
+ @raise ValueError: Some B{C{xs}} is not C{scalar}.
121
+ '''
122
+ if sets:
123
+ sets = _xkwds_get1(sets, sets=False)
124
+ _f = _floats.setdefault if sets else _floats.get
125
+ try:
126
+ for i, x in enumerate(xs):
127
+ f = float(x)
128
+ yield _f(f, f) if f else \
129
+ (_N_0_0 if signBit(f) else _0_0) # preserve NEG0
130
+ except Exception as X:
131
+ xs_i = Fmt.SQUARE(xs=i)
132
+ raise _ValueError(xs_i, x, cause=X)
133
+
134
+
122
135
  def _floatuple(*fs):
123
136
  '''(INTERNAL) Cache a tuple of C{float}s.
124
137
  '''
@@ -172,6 +185,13 @@ def _1_over(x):
172
185
  return NINF if isneg0(x) else INF
173
186
 
174
187
 
188
+ def _Radius(**name_arg):
189
+ '''(INTERNAL) New named, cached C{Radius}.
190
+ '''
191
+ n, arg = _xkwds_item2(name_arg)
192
+ return Radius(_float(arg), name=n)
193
+
194
+
175
195
  _floats = {} # PYCHOK floats cache, in .__main__
176
196
  # _float = float # PYCHOK expected
177
197
  # del _floats # XXX zap floats cache never
@@ -186,6 +206,7 @@ _0_1 = _float( 0.1) # PYCHOK expected
186
206
  _0_125 = _float( 0.125) # PYCHOK expected
187
207
  _0_25 = _float( 0.25) # PYCHOK expected
188
208
  _0_5 = _float( 0.5) # PYCHOK expected
209
+ _0_75 = _float( 0.75) # PYCHOK expected
189
210
  _1_0 = _float( 1) # PYCHOK expected
190
211
  _1_0_1T = _1_0, # PYCHOK 1-tuple
191
212
  _1_5 = _float( 1.5) # PYCHOK expected
@@ -236,40 +257,35 @@ try:
236
257
  # RADIX = Int( RADIX =_f_i.radix) # PYTHON system's float base
237
258
  del _f_i
238
259
  except ImportError: # PYCHOK no cover
239
- DIG = Int( DIG =15) # PYCHOK system's 64-bit float decimal digits
260
+ DIG = Int( DIG =15) # PYCHOK system's 64-bit float decimal digits
240
261
  EPS = _Float(EPS =2.220446049250313e-16) # PYCHOK EPSilon 2**-52, M{EPS +/- 1 != 1}
241
- MANT_DIG = Int( MANT_DIG=53) # PYCHOK float mantissa bits ≈ 53 (C{int})
262
+ MANT_DIG = Int( MANT_DIG=53) # PYCHOK float mantissa bits ≈ 53 (C{int})
242
263
  MAX = _Float(MAX =pow(_2_0, 1023) * (_2_0 - EPS)) # PYCHOK ≈ 10**308
243
- MAX_EXP = Int( MAX_ESP =_log2(MAX)) # 308 base 10
264
+ MAX_EXP = Int( MAX_ESP =_log2(MAX)) # 308 base 10
244
265
  MIN = _Float(MIN =pow(_2_0, -1021)) # PYCHOK ≈ 10**-308
245
- MIN_EXP = Int(MIN_EXP =_log2(MIN)) # -307 base 10
246
- # RADIX = Int(Radix =2) # base
247
-
248
- EPS0 = _Float( EPS0 = EPS**2) # PYCHOK near-/non-zero comparison 4.930381e-32, or EPS or EPS_2
249
- EPS02 = _Float( EPS02 = EPS**4) # PYCHOK near-zero-squared comparison 2.430865e-63
250
- EPS_2 = _Float( EPS_2 = EPS / _2_0) # PYCHOK ≈ 1.110223024625e-16
251
- EPS1 = _Float( EPS1 =_1_0 - EPS) # PYCHOK ≈ 0.9999999999999998
252
- EPS2 = _Float( EPS2 = EPS * _2_0) # PYCHOK ≈ 4.440892098501e-16
253
- EPS4 = _Float( EPS4 = EPS * _4_0) # PYCHOK ≈ 8.881784197001e-16
254
- # _1EPS = _Float(_1EPS =_1_0 + EPS) # PYCHOK ≈ 1.0000000000000002
255
- _1_EPS = _Float(_1_EPS =_1_0 / EPS) # PYCHOK = 4503599627370496.0
256
- # _2_EPS = _Float(_2_EPS =_2_0 / EPS) # PYCHOK = 9007199254740992.0
257
- _EPS2e4 = _Float(_EPS2e4= EPS2 * 1.e4) # PYCHOK ≈ 4.440892098501e-12
258
- _EPS4e8 = _Float(_EPS4e8= EPS4 * 1.e8) # PYCHOK ≈ 8.881784197001e-08
259
- _EPSjam = _Float(_EPSjam= pow(EPS, 0.75)) # PYCHOK = 1.818989403546e-12
260
- _EPSmin = _Float(_EPSmin= sqrt(MIN)) # PYCHOK = 1.49166814624e-154
261
- _EPSqrt = _Float(_EPSqrt= sqrt(EPS)) # PYCHOK = 1.49011611938e5-08
262
- _EPStol = _Float(_EPStol=_EPSqrt * _0_1) # PYCHOK = 1.49011611938e5-09 == sqrt(EPS * _0_01)
266
+ MIN_EXP = Int(MIN_EXP =_log2(MIN)) # -307 base 10
267
+ # RADIX = Int(Radix =2) # base
268
+
269
+ EPS0 = _Float( EPS0 = EPS**2) # PYCHOK near-/non-zero comparison 4.930381e-32, or EPS or EPS_2
270
+ EPS02 = _Float( EPS02 = EPS**4) # PYCHOK near-zero-squared comparison 2.430865e-63
271
+ EPS_2 = _Float( EPS_2 = EPS / _2_0) # PYCHOK ≈ 1.110223024625e-16
272
+ EPS1 = _Float( EPS1 =_1_0 - EPS) # PYCHOK ≈ 0.9999999999999998
273
+ EPS2 = _Float( EPS2 = EPS * _2_0) # PYCHOK ≈ 4.440892098501e-16
274
+ EPS4 = _Float( EPS4 = EPS * _4_0) # PYCHOK ≈ 8.881784197001e-16
275
+ # _1EPS = _Float(_1EPS =_1_0 + EPS) # PYCHOK ≈ 1.0000000000000002
276
+ _1_EPS = _Float(_1_EPS =_1_0 / EPS) # PYCHOK = 4503599627370496.0
277
+ # _2_EPS = _Float(_2_EPS =_2_0 / EPS) # PYCHOK = 9007199254740992.0
278
+ _EPS2e4 = _Float(_EPS2e4= EPS2 * 1.e4) # PYCHOK ≈ 4.440892098501e-12
279
+ _EPS4e8 = _Float(_EPS4e8= EPS4 * 1.e8) # PYCHOK ≈ 8.881784197001e-08
280
+ _EPSjam = _Float(_EPSjam= pow(EPS, _0_75)) # PYCHOK = 1.818989403546e-12
281
+ _EPSmin = _Float(_EPSmin= sqrt(MIN)) # PYCHOK = 1.49166814624e-154
282
+ _EPSqrt = _Float(_EPSqrt= sqrt(EPS)) # PYCHOK = 1.49011611938e5-08
283
+ _EPStol = _Float(_EPStol=_EPSqrt * _0_1) # PYCHOK = 1.49011611938e5-09 == sqrt(EPS * _0_01)
263
284
 
264
285
  _89_999 = _Float(_89_999=_90_0 * EPS1) # just below 90.0
265
286
  # <https://Numbers.Computation.Free.FR/Constants/Miscellaneous/digits.html>
266
287
  # _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
288
  _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
268
-
269
- _1_16th = _Float(_1_16th=_1_0 / _16_0) # PYCHOK in .ellipsoids, .karney
270
- _1_3rd = _Float(_1_3rd =_1_0 / _3_0) # PYCHOK in .fmath
271
- _1_6th = _Float(_1_6th =_1_0 / _6_0) # PYCHOK in .fmath
272
-
273
289
  _K0_UTM = _Float(_K0_UTM = 0.9996) # PYCHOK in .etm, .ktm, .utm, UTM scale at central meridian
274
290
  # sqrt(2) <https://WikiPedia.org/wiki/Square_root_of_2>
275
291
  # 1.414213562373095_048_801_688_724_209_698_078_569_671_875_376_948_073_176_679_737_99
@@ -27,7 +27,7 @@ __all__ = (_ALL_DEPRECATED.deprecated_bases +
27
27
  _ALL_DEPRECATED.deprecated_classes +
28
28
  _ALL_DEPRECATED.deprecated_consterns +
29
29
  _ALL_DEPRECATED.deprecated_functions)
30
- __version__ = '25.05.12'
30
+ __version__ = '25.10.25'
31
31
 
32
32
  if _unLazy0:
33
33
  from pygeodesy.deprecated import bases, datum, nvector, rhumbBase, \
@@ -18,11 +18,12 @@ from pygeodesy.namedTuples import Forward4Tuple as _Forward4Tuple, \
18
18
  UtmUps5Tuple as _UtmUps5Tuple, _NamedTuple
19
19
  from pygeodesy.props import deprecated_class, deprecated_method
20
20
  from pygeodesy.resections import TriAngle5Tuple as _TriAngle5Tuple
21
+ from pygeodesy.triaxials import ConformalSphere, ConformalTriaxial, Conformal2Tuple
21
22
  from pygeodesy.trf import TRFXform7Tuple as _TRFXform7Tuple
22
23
  from pygeodesy.units import Bearing, Int, Lamd, Lat, Lon, Meter, Phid
23
24
 
24
25
  __all__ = _ALL_DEPRECATED.deprecated_classes
25
- __version__ = '25.04.11'
26
+ __version__ = '25.10.25'
26
27
 
27
28
 
28
29
  class _Deprecated_NamedTuple(_NamedTuple):
@@ -235,6 +236,28 @@ def HeightIDWcosineForsytheAndoyerLambert(knots, **kwds): # PYCHOK no cover
235
236
  return HeightIDWcosineForsytheAndoyerLambert(knots, **kwds)
236
237
 
237
238
 
239
+ class JacobiConformal(ConformalTriaxial):
240
+ '''DEPRECATED on 2025.10.25, use class L{ConformalTriaxial}.'''
241
+ def __init__(self, *args, **kwds): # PYCHOK no cover
242
+ deprecated_class(self.__class__)
243
+ ConformalTriaxial.__init__(self, *args, **kwds)
244
+
245
+
246
+ class JacobiConformalSpherical(ConformalSphere):
247
+ '''DEPRECATED on 2025.10.25, use class L{ConformalSphere}.'''
248
+ def __init__(self, *args, **kwds): # PYCHOK no cover
249
+ deprecated_class(self.__class__)
250
+ ConformalSphere.__init__(self, *args, **kwds)
251
+
252
+
253
+ class Jacobi2Tuple(Conformal2Tuple):
254
+ '''DEPRECATED on 25.10.25, use class L{Conformal2Tuple}.
255
+ '''
256
+ def __new__(cls, *args, **kwds):
257
+ deprecated_class(cls)
258
+ return Conformal2Tuple.__new__(cls, *args, **kwds)
259
+
260
+
238
261
  class Lam_(Lamd):
239
262
  '''DEPRECATED on 2024.06.15, use class L{Lamd}.'''
240
263
  def __init__(self, *args, **kwds): # PYCHOK no cover