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