pygeodesy 25.4.8__py2.py3-none-any.whl → 25.4.25__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 +30 -27
- pygeodesy/__main__.py +3 -3
- pygeodesy/albers.py +29 -36
- pygeodesy/auxilats/_CX_4.py +2 -2
- pygeodesy/auxilats/_CX_6.py +2 -2
- pygeodesy/auxilats/_CX_8.py +2 -2
- pygeodesy/auxilats/_CX_Rs.py +9 -9
- pygeodesy/auxilats/__init__.py +3 -3
- pygeodesy/auxilats/__main__.py +8 -6
- pygeodesy/auxilats/auxAngle.py +2 -2
- pygeodesy/auxilats/auxLat.py +5 -5
- pygeodesy/auxilats/auxily.py +5 -3
- pygeodesy/azimuthal.py +7 -6
- pygeodesy/basics.py +31 -17
- pygeodesy/booleans.py +12 -10
- pygeodesy/cartesianBase.py +21 -20
- pygeodesy/clipy.py +11 -10
- pygeodesy/constants.py +11 -10
- pygeodesy/css.py +14 -11
- pygeodesy/datums.py +8 -8
- pygeodesy/deprecated/bases.py +2 -2
- pygeodesy/deprecated/classes.py +2 -2
- pygeodesy/deprecated/consterns.py +4 -4
- pygeodesy/dms.py +8 -8
- pygeodesy/ecef.py +10 -7
- pygeodesy/elevations.py +9 -8
- pygeodesy/ellipsoidalBase.py +19 -8
- pygeodesy/ellipsoidalBaseDI.py +17 -15
- pygeodesy/ellipsoidalNvector.py +6 -3
- pygeodesy/ellipsoidalVincenty.py +4 -1
- pygeodesy/ellipsoids.py +167 -138
- pygeodesy/elliptic.py +9 -9
- pygeodesy/errors.py +44 -43
- pygeodesy/etm.py +7 -7
- pygeodesy/fmath.py +10 -9
- pygeodesy/formy.py +11 -12
- pygeodesy/frechet.py +216 -109
- pygeodesy/fstats.py +5 -4
- pygeodesy/fsums.py +78 -77
- pygeodesy/gars.py +4 -3
- pygeodesy/geodesici.py +15 -14
- pygeodesy/geodesicw.py +34 -32
- pygeodesy/geodesicx/__init__.py +1 -1
- pygeodesy/geodesicx/__main__.py +11 -9
- pygeodesy/geodesicx/gx.py +30 -33
- pygeodesy/geodesicx/gxarea.py +2 -2
- pygeodesy/geodesicx/gxline.py +5 -5
- pygeodesy/geodsolve.py +18 -17
- pygeodesy/geohash.py +5 -5
- pygeodesy/geoids.py +34 -31
- pygeodesy/hausdorff.py +17 -13
- pygeodesy/heights.py +2 -4
- pygeodesy/internals.py +28 -44
- pygeodesy/interns.py +10 -7
- pygeodesy/iters.py +8 -8
- pygeodesy/karney.py +68 -62
- pygeodesy/ktm.py +5 -5
- pygeodesy/latlonBase.py +14 -18
- pygeodesy/lazily.py +65 -63
- pygeodesy/lcc.py +11 -9
- pygeodesy/ltp.py +8 -7
- pygeodesy/ltpTuples.py +2 -2
- pygeodesy/mgrs.py +7 -6
- pygeodesy/named.py +47 -31
- pygeodesy/nvectorBase.py +7 -7
- pygeodesy/osgr.py +9 -8
- pygeodesy/points.py +12 -10
- pygeodesy/props.py +25 -25
- pygeodesy/resections.py +11 -10
- pygeodesy/rhumb/__init__.py +1 -1
- pygeodesy/rhumb/aux_.py +7 -7
- pygeodesy/rhumb/bases.py +22 -20
- pygeodesy/rhumb/ekx.py +6 -6
- pygeodesy/rhumb/solve.py +15 -15
- pygeodesy/solveBase.py +3 -3
- pygeodesy/sphericalBase.py +6 -6
- pygeodesy/sphericalNvector.py +6 -5
- pygeodesy/sphericalTrigonometry.py +8 -7
- pygeodesy/streprs.py +14 -14
- pygeodesy/trf.py +14 -12
- pygeodesy/triaxials.py +29 -26
- pygeodesy/units.py +5 -4
- pygeodesy/unitsBase.py +5 -4
- pygeodesy/ups.py +3 -3
- pygeodesy/utily.py +4 -4
- pygeodesy/utmups.py +4 -4
- pygeodesy/utmupsBase.py +88 -18
- pygeodesy/vector2d.py +18 -11
- pygeodesy/vector3d.py +7 -6
- pygeodesy/webmercator.py +6 -5
- pygeodesy/wgrs.py +6 -5
- {pygeodesy-25.4.8.dist-info → pygeodesy-25.4.25.dist-info}/METADATA +27 -23
- pygeodesy-25.4.25.dist-info/RECORD +118 -0
- pygeodesy-25.4.8.dist-info/RECORD +0 -118
- {pygeodesy-25.4.8.dist-info → pygeodesy-25.4.25.dist-info}/WHEEL +0 -0
- {pygeodesy-25.4.8.dist-info → pygeodesy-25.4.25.dist-info}/top_level.txt +0 -0
pygeodesy/geodesicw.py
CHANGED
|
@@ -21,7 +21,7 @@ from pygeodesy.datums import _earth_datum, _WGS84, _EWGS84
|
|
|
21
21
|
from pygeodesy.errors import _AssertionError, GeodesicError, \
|
|
22
22
|
IntersectionError
|
|
23
23
|
from pygeodesy.fsums import Fsum, Fmt, unstr
|
|
24
|
-
from pygeodesy.internals import
|
|
24
|
+
from pygeodesy.internals import typename, _under
|
|
25
25
|
from pygeodesy.interns import NN, _DOT_, _SPACE_, _to_, _too_
|
|
26
26
|
from pygeodesy.karney import _atan2d, Caps, Direct9Tuple, GDict, \
|
|
27
27
|
Inverse10Tuple, _kWrapped
|
|
@@ -39,14 +39,14 @@ from contextlib import contextmanager
|
|
|
39
39
|
# from math import fabs # from .utily
|
|
40
40
|
|
|
41
41
|
__all__ = _ALL_LAZY.geodesicw
|
|
42
|
-
__version__ = '
|
|
42
|
+
__version__ = '25.04.14'
|
|
43
43
|
|
|
44
44
|
_plumb_ = 'plumb'
|
|
45
45
|
_TRIPS = 65
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
class _gWrapped(_kWrapped):
|
|
49
|
-
'''
|
|
49
|
+
'''(INTERNAL) Wrapper for some of I{Karney}'s U{geographiclib
|
|
50
50
|
<https://PyPI.org/project/geographiclib>} classes.
|
|
51
51
|
'''
|
|
52
52
|
|
|
@@ -65,6 +65,7 @@ class _gWrapped(_kWrapped):
|
|
|
65
65
|
Caps.REDUCEDLENGTH == _Geodesic.REDUCEDLENGTH and
|
|
66
66
|
Caps.GEODESICSCALE == _Geodesic.GEODESICSCALE and
|
|
67
67
|
Caps.AREA == _Geodesic.AREA and
|
|
68
|
+
Caps.STANDARD == _Geodesic.STANDARD and
|
|
68
69
|
Caps.ALL == _Geodesic.ALL):
|
|
69
70
|
raise _AssertionError(Caps=bin(Caps.ALL),
|
|
70
71
|
Geodesic=bin(_Geodesic.ALL))
|
|
@@ -73,10 +74,11 @@ class _gWrapped(_kWrapped):
|
|
|
73
74
|
'''I{Wrapper} for I{Karney}'s Python U{geodesic.Geodesic
|
|
74
75
|
<https://PyPI.org/project/geographiclib>} class.
|
|
75
76
|
'''
|
|
76
|
-
_datum
|
|
77
|
-
_debug
|
|
78
|
-
LINE_OFF
|
|
79
|
-
_name
|
|
77
|
+
_datum = _WGS84
|
|
78
|
+
_debug = 0 # like .geodesicx.bases._GeodesicBase
|
|
79
|
+
LINE_OFF = 0 # in .azimuthal._GnomonicBase and .css.CassiniSoldner
|
|
80
|
+
_name = NN
|
|
81
|
+
STANDARD_LINE = Caps.STANDARD_LINE
|
|
80
82
|
|
|
81
83
|
def __init__(self, a_ellipsoid=_EWGS84, f=None, **name): # PYCHOK signature
|
|
82
84
|
'''New I{wrapped} C{geodesic.Geodesic} instance.
|
|
@@ -94,14 +96,14 @@ class _gWrapped(_kWrapped):
|
|
|
94
96
|
if name:
|
|
95
97
|
self._name, _ = _name2__(name, _or_nameof=E)
|
|
96
98
|
|
|
97
|
-
def ArcDirect(self, lat1, lon1, azi1, a12, outmask=Caps.
|
|
99
|
+
def ArcDirect(self, lat1, lon1, azi1, a12, outmask=Caps.STANDARD): # PYCHOK no cover
|
|
98
100
|
'''Return the C{_Geodesic.ArcDirect} result as L{GDict}.
|
|
99
101
|
'''
|
|
100
102
|
with _wargs(self, lat1, lon1, azi1, a12, outmask) as args:
|
|
101
103
|
d = _Geodesic.ArcDirect(self, *args)
|
|
102
104
|
return GDict(d)
|
|
103
105
|
|
|
104
|
-
def ArcDirectLine(self, lat1, lon1, azi1, a12, caps=Caps.
|
|
106
|
+
def ArcDirectLine(self, lat1, lon1, azi1, a12, caps=Caps.STANDARD_LINE, **name): # PYCHOK no cover
|
|
105
107
|
'''Return the C{_Geodesic.ArcDirectLine} as I{wrapped} C{GeodesicLine}.
|
|
106
108
|
'''
|
|
107
109
|
return self._GenDirectLine(lat1, lon1, azi1, True, a12, caps, **name)
|
|
@@ -127,7 +129,7 @@ class _gWrapped(_kWrapped):
|
|
|
127
129
|
'''
|
|
128
130
|
self._debug = Caps._DEBUG_ALL if debug else 0
|
|
129
131
|
|
|
130
|
-
def Direct(self, lat1, lon1, azi1, s12=0, outmask=Caps.
|
|
132
|
+
def Direct(self, lat1, lon1, azi1, s12=0, outmask=Caps.STANDARD):
|
|
131
133
|
'''Return the C{_Geodesic.Direct} result as L{GDict}.
|
|
132
134
|
'''
|
|
133
135
|
with _wargs(self, lat1, lon1, azi1, s12, outmask) as args:
|
|
@@ -146,7 +148,7 @@ class _gWrapped(_kWrapped):
|
|
|
146
148
|
'''
|
|
147
149
|
return self.DirectLine(ll1.lat, ll1.lon, azi12, s12, **caps_name)
|
|
148
150
|
|
|
149
|
-
def DirectLine(self, lat1, lon1, azi1, s12, caps=Caps.
|
|
151
|
+
def DirectLine(self, lat1, lon1, azi1, s12, caps=Caps.STANDARD_LINE, **name):
|
|
150
152
|
'''Return the C{_Geodesic.DirectLine} as I{wrapped} C{GeodesicLine}.
|
|
151
153
|
'''
|
|
152
154
|
return self._GenDirectLine(lat1, lon1, azi1, False, s12, caps, **name)
|
|
@@ -163,14 +165,14 @@ class _gWrapped(_kWrapped):
|
|
|
163
165
|
'''
|
|
164
166
|
return getattr(self, _under(Geodesic.f1.name), self.ellipsoid.f1)
|
|
165
167
|
|
|
166
|
-
def _GDictDirect(self, lat, lon, azi, arcmode, s12_a12, outmask=Caps.
|
|
168
|
+
def _GDictDirect(self, lat, lon, azi, arcmode, s12_a12, outmask=Caps.STANDARD):
|
|
167
169
|
'''(INTERNAL) Get C{_Geodesic._GenDirect} result as C{GDict}.
|
|
168
170
|
'''
|
|
169
171
|
with _wargs(self, lat, lon, azi, arcmode, s12_a12, outmask) as args:
|
|
170
172
|
t = _Geodesic._GenDirect(self, *args)
|
|
171
173
|
return Direct9Tuple(t).toGDict() # *t
|
|
172
174
|
|
|
173
|
-
def _GDictInverse(self, lat1, lon1, lat2, lon2, outmask=Caps.
|
|
175
|
+
def _GDictInverse(self, lat1, lon1, lat2, lon2, outmask=Caps.STANDARD):
|
|
174
176
|
'''(INTERNAL) Get C{_Geodesic._GenInverse} result as L{Inverse10Tuple}.
|
|
175
177
|
'''
|
|
176
178
|
with _wargs(self, lat1, lon1, lat2, lon2, outmask) as args:
|
|
@@ -192,7 +194,7 @@ class _gWrapped(_kWrapped):
|
|
|
192
194
|
ll2 = _unrollon(ll1, _Wrap.point(ll2))
|
|
193
195
|
return self.Inverse(ll1.lat, ll1.lon, ll2.lat, ll2.lon, **outmask)
|
|
194
196
|
|
|
195
|
-
def Inverse(self, lat1, lon1, lat2, lon2, outmask=Caps.
|
|
197
|
+
def Inverse(self, lat1, lon1, lat2, lon2, outmask=Caps.STANDARD):
|
|
196
198
|
'''Return the C{_Geodesic.Inverse} result as L{GDict}.
|
|
197
199
|
'''
|
|
198
200
|
with _wargs(self, lat1, lon1, lat2, lon2, outmask) as args:
|
|
@@ -227,14 +229,14 @@ class _gWrapped(_kWrapped):
|
|
|
227
229
|
ll2 = _unrollon(ll1, _Wrap.point(ll2))
|
|
228
230
|
return self.InverseLine(ll1.lat, ll1.lon, ll2.lat, ll2.lon, **caps_name)
|
|
229
231
|
|
|
230
|
-
def InverseLine(self, lat1, lon1, lat2, lon2, caps=Caps.
|
|
232
|
+
def InverseLine(self, lat1, lon1, lat2, lon2, caps=Caps.STANDARD_LINE, **name):
|
|
231
233
|
'''Return the C{_Geodesic.InverseLine} as I{wrapped} C{GeodesicLine}.
|
|
232
234
|
'''
|
|
233
235
|
with _wargs(self, lat1, lon1, lat2, lon2, caps, **name) as args:
|
|
234
236
|
t = _Geodesic.InverseLine(self, *args)
|
|
235
237
|
return self._Line13(t, **name)
|
|
236
238
|
|
|
237
|
-
def Line(self, lat1, lon1, azi1, caps=Caps.
|
|
239
|
+
def Line(self, lat1, lon1, azi1, caps=Caps.STANDARD_LINE, **name):
|
|
238
240
|
'''Set up a I{wrapped} C{GeodesicLine} to compute several points
|
|
239
241
|
along a single, I{wrapped} (this) geodesic.
|
|
240
242
|
'''
|
|
@@ -289,10 +291,10 @@ class _gWrapped(_kWrapped):
|
|
|
289
291
|
@arg lon1: Longitude of the first points (C{degrees}).
|
|
290
292
|
@arg azi1: Azimuth at the first points (compass C{degrees360}).
|
|
291
293
|
@kwarg caps_name_: Optional keyword arguments C{B{caps}=Caps.STANDARD},
|
|
292
|
-
a bit-or'ed combination of L{Caps}
|
|
293
|
-
capabilities the C{GeodesicLine} instance
|
|
294
|
-
an optional C{B{name}=NN} plus C{salp1=NAN} and
|
|
295
|
-
for I{INTERNAL} use.
|
|
294
|
+
a bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
295
|
+
values specifying the capabilities the C{GeodesicLine} instance
|
|
296
|
+
should possess, an optional C{B{name}=NN} plus C{salp1=NAN} and
|
|
297
|
+
C{calp1=NAN} for I{INTERNAL} use.
|
|
296
298
|
'''
|
|
297
299
|
_xinstanceof(_wrapped.Geodesic, geodesic=geodesic)
|
|
298
300
|
with _wargs(self, geodesic, lat1, lon1, azi1, **caps_name_) as args:
|
|
@@ -322,7 +324,7 @@ class _gWrapped(_kWrapped):
|
|
|
322
324
|
'''
|
|
323
325
|
return self.a13
|
|
324
326
|
|
|
325
|
-
def ArcPosition(self, a12, outmask=Caps.
|
|
327
|
+
def ArcPosition(self, a12, outmask=Caps.STANDARD):
|
|
326
328
|
'''Return the position at C{B{a12} degrees} on this line.
|
|
327
329
|
|
|
328
330
|
@arg a12: Angular distance from this line's first point
|
|
@@ -412,12 +414,12 @@ class _gWrapped(_kWrapped):
|
|
|
412
414
|
'''
|
|
413
415
|
return _PlumbTo(self, lat0, lon0, est=est, tol=tol)
|
|
414
416
|
|
|
415
|
-
def Position(self, s12, outmask=Caps.
|
|
417
|
+
def Position(self, s12, outmask=Caps.STANDARD):
|
|
416
418
|
'''Return the position at distance C{B{s12} meter} on this line.
|
|
417
419
|
|
|
418
420
|
@arg s12: Distance from this line's first point (C{meter}).
|
|
419
|
-
@kwarg outmask: Bit-or'ed combination of L{Caps}
|
|
420
|
-
the quantities to be returned.
|
|
421
|
+
@kwarg outmask: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
422
|
+
values specifying the quantities to be returned.
|
|
421
423
|
|
|
422
424
|
@return: A L{GDict} with up to 12 items C{lat1, lon1, azi1, lat2,
|
|
423
425
|
lon2, azi2, m12, a12, s12, M12, M21, S12} with C{lat1},
|
|
@@ -467,7 +469,7 @@ class GeodesicLine(_gWrapped): # overwritten by 1st instance
|
|
|
467
469
|
'''I{Wrapper} around I{Karney}'s class U{geographiclib.geodesicline.GeodesicLine
|
|
468
470
|
<https://GeographicLib.SourceForge.io/Python/doc/code.html>}.
|
|
469
471
|
'''
|
|
470
|
-
def __new__(unused, geodesic, lat1, lon1, azi1, caps=Caps.
|
|
472
|
+
def __new__(unused, geodesic, lat1, lon1, azi1, caps=Caps.STANDARD_LINE, **name):
|
|
471
473
|
'''Return a I{wrapped} C{geodesicline.GeodesicLine} instance from I{Karney}'s
|
|
472
474
|
Python U{geographiclib<https://PyPI.org/project/geographiclib>}, provided
|
|
473
475
|
the latter is installed, otherwise an C{ImportError}.
|
|
@@ -476,9 +478,9 @@ class GeodesicLine(_gWrapped): # overwritten by 1st instance
|
|
|
476
478
|
@arg lat1: Latitude of the first points (C{degrees}).
|
|
477
479
|
@arg lon1: Longitude of the first points (C{degrees}).
|
|
478
480
|
@arg azi1: Azimuth at the first points (compass C{degrees360}).
|
|
479
|
-
@kwarg caps: Optional, bit-or'ed combination of L{Caps}
|
|
480
|
-
the capabilities the C{GeodesicLine} instance
|
|
481
|
-
i.e., which quantities can be returned by methods
|
|
481
|
+
@kwarg caps: Optional, bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
482
|
+
values specifying the capabilities the C{GeodesicLine} instance
|
|
483
|
+
should possess, i.e., which quantities can be returned by methods
|
|
482
484
|
C{GeodesicLine.Position} and C{GeodesicLine.ArcPosition}.
|
|
483
485
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
484
486
|
'''
|
|
@@ -515,10 +517,10 @@ _wargs = _wargs() # PYCHOK singleton
|
|
|
515
517
|
def _Intersecant2(gl, lat0, lon0, radius, tol=_TOL, form=F_D): # MCCABE in LatLonEllipsoidalBaseDI.intersecant2, .geodesicx.gxline.Intersecant2
|
|
516
518
|
# (INTERNAL) Return the intersections of a circle at C{lat0, lon0}
|
|
517
519
|
# and a geodesic line as a 2-Tuple C{(P, Q)}, each a C{GDict}.
|
|
518
|
-
r =
|
|
519
|
-
n =
|
|
520
|
-
_P =
|
|
521
|
-
_I =
|
|
520
|
+
r = Radius_(radius)
|
|
521
|
+
n = typename(_Intersecant2)[1:]
|
|
522
|
+
_P = gl.Position
|
|
523
|
+
_I = gl.geodesic.Inverse
|
|
522
524
|
|
|
523
525
|
def _R3(s):
|
|
524
526
|
# radius, intersection, etc. at distance C{s}
|
pygeodesy/geodesicx/__init__.py
CHANGED
pygeodesy/geodesicx/__main__.py
CHANGED
|
@@ -5,16 +5,16 @@ u'''Print L{geodesicx} version, etc. using C{python -m pygeodesy.geodesicx}.
|
|
|
5
5
|
'''
|
|
6
6
|
|
|
7
7
|
__all__ = ()
|
|
8
|
-
__version__ = '25.04.
|
|
8
|
+
__version__ = '25.04.14'
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _main(**C4order): # PYCHOK no cover
|
|
12
12
|
|
|
13
13
|
try:
|
|
14
|
-
from pygeodesy import GeodesicExact, geodesicx
|
|
15
|
-
from pygeodesy.internals import _fper, _name_version, \
|
|
16
|
-
|
|
17
|
-
from pygeodesy.interns import _COMMASPACE_
|
|
14
|
+
from pygeodesy import ADict, GeodesicExact, geodesicx
|
|
15
|
+
from pygeodesy.internals import _fper, _name_version, printf, \
|
|
16
|
+
_sizeof, typename, _versions
|
|
17
|
+
from pygeodesy.interns import _COMMASPACE_
|
|
18
18
|
try:
|
|
19
19
|
import numpy
|
|
20
20
|
except ImportError:
|
|
@@ -24,10 +24,9 @@ def _main(**C4order): # PYCHOK no cover
|
|
|
24
24
|
cs = geodesicx.gx._C4coeffs(gX.C4order)
|
|
25
25
|
n = len(cs)
|
|
26
26
|
u = n if numpy else len(set(cs))
|
|
27
|
-
p =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
p = list(_EQUAL_(*t) for t in p.items())
|
|
27
|
+
p = ADict(C4order=gX.C4order, C4n=n, C4u=u,
|
|
28
|
+
C4u_n=_fper(u, n), C4x=len(gX._C4x),
|
|
29
|
+
C4t=typename(type(cs)), C4z=_sizeof(cs))._toL()
|
|
31
30
|
if numpy:
|
|
32
31
|
p.append(_name_version(numpy))
|
|
33
32
|
try:
|
|
@@ -47,6 +46,9 @@ def _main(**C4order): # PYCHOK no cover
|
|
|
47
46
|
from sys import argv # .internals._isPyChOK
|
|
48
47
|
_main(C4order=int(argv[1])) if len(argv) == 2 and argv[1].isdigit() else _main()
|
|
49
48
|
|
|
49
|
+
# % python3.13 -m pygeodesy.geodesicx
|
|
50
|
+
# pygeodesy.geodesicx 25.04.14: C4order=30, C4n=5425, C4u=5107, C4u_n=94.1%, C4x=465, C4t=tuple, C4z=166008, geographiclib 2.0 (pygeodesy 25.4.24 Python 3.13.3 64bit arm64 macOS 15.4)
|
|
51
|
+
|
|
50
52
|
# % python3.13 -m pygeodesy.geodesicx 30
|
|
51
53
|
# pygeodesy.geodesicx 24.09.06: C4order=30, C4n=5425, C4u=5107, C4u_n=94.1%, C4x=465, C4t=tuple, C4z=166008 (pygeodesy 24.9.6 Python 3.13.0rc1 64bit arm64 macOS 14.6.1)
|
|
52
54
|
# % python3.12 -m pygeodesy.geodesicx 30
|
pygeodesy/geodesicx/gx.py
CHANGED
|
@@ -36,7 +36,7 @@ from __future__ import division as _; del _ # PYCHOK semicolon
|
|
|
36
36
|
# - a 12 suffix means a difference, e.g., s12 = s2 - s1.
|
|
37
37
|
# - s and c prefixes mean sin and cos
|
|
38
38
|
|
|
39
|
-
from pygeodesy.basics import _copysign, _xinstanceof, _xor, unsigned0
|
|
39
|
+
from pygeodesy.basics import _copysign, _xinstanceof, _xor, unsigned0, typename
|
|
40
40
|
from pygeodesy.constants import EPS, EPS0, EPS02, MANT_DIG, NAN, PI, _EPSqrt, \
|
|
41
41
|
_SQRT2_2, isnan, _0_0, _0_001, _0_01, _0_1, _0_5, \
|
|
42
42
|
_1_0, _N_1_0, _1_75, _2_0, _N_2_0, _2__PI, _3_0, \
|
|
@@ -50,6 +50,7 @@ from pygeodesy.geodesicx.gxbases import _cosSeries, _GeodesicBase, \
|
|
|
50
50
|
_sincos12, _sin1cos2, _sinf1cos2d, \
|
|
51
51
|
_TINY, _xnC4
|
|
52
52
|
from pygeodesy.geodesicx.gxline import _GeodesicLineExact, _update_glXs
|
|
53
|
+
# from pygeodesy.internals import typename # from .basics
|
|
53
54
|
from pygeodesy.interns import NN, _DOT_, _UNDER_
|
|
54
55
|
from pygeodesy.karney import GDict, _around, _atan2d, Caps, _cbrt, _diff182, \
|
|
55
56
|
_fix90, _K_2_0, _norm2, _norm180, _polynomial, \
|
|
@@ -64,7 +65,7 @@ from pygeodesy.utily import atan2, atan2d as _atan2d_reverse, _unrollon, \
|
|
|
64
65
|
from math import copysign, cos, degrees, fabs, radians, sqrt
|
|
65
66
|
|
|
66
67
|
__all__ = ()
|
|
67
|
-
__version__ = '
|
|
68
|
+
__version__ = '25.04.14'
|
|
68
69
|
|
|
69
70
|
_MAXIT1 = 20
|
|
70
71
|
_MAXIT2 = 10 + _MAXIT1 + MANT_DIG # MANT_DIG == C++ digits
|
|
@@ -175,8 +176,8 @@ class GeodesicExact(_GeodesicBase):
|
|
|
175
176
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
176
177
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
177
178
|
@arg a12: Arc length between the points (C{degrees}), can be negative.
|
|
178
|
-
@kwarg outmask: Bit-or'ed combination of L{Caps}
|
|
179
|
-
the quantities to be returned.
|
|
179
|
+
@kwarg outmask: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
180
|
+
values specifying the quantities to be returned.
|
|
180
181
|
|
|
181
182
|
@return: A L{GDict} with up to 12 items C{lat1, lon1, azi1, lat2,
|
|
182
183
|
lon2, azi2, m12, a12, s12, M12, M21, S12} with C{lat1},
|
|
@@ -195,11 +196,10 @@ class GeodesicExact(_GeodesicBase):
|
|
|
195
196
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
196
197
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
197
198
|
@arg a12: Arc length between the points (C{degrees}), can be negative.
|
|
198
|
-
@kwarg caps: Bit-or'ed combination of L{Caps} values
|
|
199
|
-
the capabilities the L{GeodesicLineExact} instance
|
|
200
|
-
should possess, i.e., which quantities can be
|
|
201
|
-
|
|
202
|
-
and L{GeodesicLineExact.ArcPosition}.
|
|
199
|
+
@kwarg caps: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
|
|
200
|
+
specifying the capabilities the L{GeodesicLineExact} instance
|
|
201
|
+
should possess, i.e., which quantities can be returned by methods
|
|
202
|
+
L{GeodesicLineExact.Position} and L{GeodesicLineExact.ArcPosition}.
|
|
203
203
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
204
204
|
|
|
205
205
|
@return: A L{GeodesicLineExact} instance.
|
|
@@ -340,8 +340,8 @@ class GeodesicExact(_GeodesicBase):
|
|
|
340
340
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
341
341
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
342
342
|
@arg s12: Distance between the points (C{meter}), can be negative.
|
|
343
|
-
@kwarg outmask: Bit-or'ed combination of L{Caps}
|
|
344
|
-
the quantities to be returned.
|
|
343
|
+
@kwarg outmask: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
344
|
+
values specifying the quantities to be returned.
|
|
345
345
|
|
|
346
346
|
@return: A L{GDict} with up to 12 items C{lat1, lon1, azi1, lat2,
|
|
347
347
|
lon2, azi2, m12, a12, s12, M12, M21, S12} with C{lat1},
|
|
@@ -374,10 +374,10 @@ class GeodesicExact(_GeodesicBase):
|
|
|
374
374
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
375
375
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
376
376
|
@arg s12: Distance between the points (C{meter}), can be negative.
|
|
377
|
-
@kwarg caps: Bit-or'ed combination of L{Caps} values
|
|
378
|
-
the capabilities the L{GeodesicLineExact} instance
|
|
379
|
-
should possess, i.e., which quantities can be
|
|
380
|
-
|
|
377
|
+
@kwarg caps: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
|
|
378
|
+
specifying the capabilities the L{GeodesicLineExact} instance
|
|
379
|
+
should possess, i.e., which quantities can be returned by methods
|
|
380
|
+
L{GeodesicLineExact.Position}.
|
|
381
381
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
382
382
|
|
|
383
383
|
@return: A L{GeodesicLineExact} instance.
|
|
@@ -734,8 +734,8 @@ class GeodesicExact(_GeodesicBase):
|
|
|
734
734
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
735
735
|
@arg lat2: Latitude of the second point (C{degrees}).
|
|
736
736
|
@arg lon2: Longitude of the second point (C{degrees}).
|
|
737
|
-
@kwarg outmask: Bit-or'ed combination of L{Caps}
|
|
738
|
-
the quantities to be returned.
|
|
737
|
+
@kwarg outmask: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
738
|
+
values specifying the quantities to be returned.
|
|
739
739
|
|
|
740
740
|
@return: A L{GDict} with up to 12 items C{lat1, lon1, azi1, lat2,
|
|
741
741
|
lon2, azi2, m12, a12, s12, M12, M21, S12} with C{lat1},
|
|
@@ -788,11 +788,10 @@ class GeodesicExact(_GeodesicBase):
|
|
|
788
788
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
789
789
|
@arg lat2: Latitude of the second point (C{degrees}).
|
|
790
790
|
@arg lon2: Longitude of the second point (C{degrees}).
|
|
791
|
-
@kwarg caps: Bit-or'ed combination of L{Caps} values
|
|
792
|
-
the capabilities the L{GeodesicLineExact} instance
|
|
793
|
-
should possess, i.e., which quantities can be
|
|
794
|
-
|
|
795
|
-
and L{GeodesicLineExact.ArcPosition}.
|
|
791
|
+
@kwarg caps: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
|
|
792
|
+
specifying the capabilities the L{GeodesicLineExact} instance
|
|
793
|
+
should possess, i.e., which quantities can be returned by methods
|
|
794
|
+
L{GeodesicLineExact.Position} and L{GeodesicLineExact.ArcPosition}.
|
|
796
795
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
797
796
|
|
|
798
797
|
@return: A L{GeodesicLineExact} instance.
|
|
@@ -1103,11 +1102,10 @@ class GeodesicExact(_GeodesicBase):
|
|
|
1103
1102
|
@arg lat1: Latitude of the first point (C{degrees}).
|
|
1104
1103
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
1105
1104
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
1106
|
-
@kwarg caps: Bit-or'ed combination of L{Caps} values
|
|
1107
|
-
the capabilities the L{GeodesicLineExact} instance
|
|
1108
|
-
should possess, i.e., which quantities can be
|
|
1109
|
-
|
|
1110
|
-
and L{GeodesicLineExact.ArcPosition}.
|
|
1105
|
+
@kwarg caps: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
|
|
1106
|
+
specifying the capabilities the L{GeodesicLineExact} instance
|
|
1107
|
+
should possess, i.e., which quantities can be returned by methods
|
|
1108
|
+
L{GeodesicLineExact.Position} and L{GeodesicLineExact.ArcPosition}.
|
|
1111
1109
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
1112
1110
|
|
|
1113
1111
|
@return: A L{GeodesicLineExact} instance.
|
|
@@ -1259,11 +1257,10 @@ class GeodesicLineExact(_GeodesicLineExact):
|
|
|
1259
1257
|
@arg lat1: Latitude of the first point (C{degrees}).
|
|
1260
1258
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
1261
1259
|
@arg azi1: Azimuth at the first points (compass C{degrees}).
|
|
1262
|
-
@kwarg caps: Bit-or'ed combination of L{Caps} values
|
|
1263
|
-
the capabilities the L{GeodesicLineExact} instance
|
|
1264
|
-
should possess, i.e., which quantities can
|
|
1265
|
-
|
|
1266
|
-
and L{GeodesicLineExact.ArcPosition}.
|
|
1260
|
+
@kwarg caps: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
|
|
1261
|
+
specifying the capabilities the L{GeodesicLineExact} instance
|
|
1262
|
+
should possess, i.e., which quantities can bereturned by methods
|
|
1263
|
+
L{GeodesicLineExact.Position} and L{GeodesicLineExact.ArcPosition}.
|
|
1267
1264
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
1268
1265
|
|
|
1269
1266
|
@raise TypeError: Invalid B{C{geodesic}}.
|
|
@@ -1333,7 +1330,7 @@ def _C4coeffs(nC4): # in .geodesicx.__main__
|
|
|
1333
1330
|
'''(INTERNAL) Get the C{C4_24}, C{_27} or C{_30} series coefficients.
|
|
1334
1331
|
'''
|
|
1335
1332
|
try: # from pygeodesy.geodesicx._C4_xx import _coeffs_xx as _coeffs
|
|
1336
|
-
_C4_xx = _DOT_(_MODS.geodesicx
|
|
1333
|
+
_C4_xx = _DOT_(typename(_MODS.geodesicx), _UNDER_('_C4', nC4))
|
|
1337
1334
|
_coeffs = _MODS.getattr(_C4_xx, _UNDER_('_coeffs', nC4))
|
|
1338
1335
|
except (AttributeError, ImportError, TypeError) as x:
|
|
1339
1336
|
raise GeodesicError(nC4=nC4, cause=x)
|
pygeodesy/geodesicx/gxarea.py
CHANGED
|
@@ -19,7 +19,7 @@ from __future__ import division as _; del _ # PYCHOK semicolon
|
|
|
19
19
|
|
|
20
20
|
from pygeodesy.basics import isodd, unsigned0
|
|
21
21
|
from pygeodesy.constants import NAN, _0_0, _0_5, _720_0
|
|
22
|
-
from pygeodesy.internals import printf
|
|
22
|
+
from pygeodesy.internals import printf, typename
|
|
23
23
|
# from pygeodesy.interns import _COMMASPACE_ # from .lazily
|
|
24
24
|
from pygeodesy.karney import Area3Tuple, _diff182, GeodesicError, \
|
|
25
25
|
_norm180, _remainder, _sum3
|
|
@@ -308,7 +308,7 @@ class GeodesicAreaExact(_NamedBase):
|
|
|
308
308
|
self._lat1 = self._lon1 = NAN
|
|
309
309
|
self._num = self._xings = n = 0
|
|
310
310
|
if self.verbose: # PYCHOK no cover
|
|
311
|
-
printf('%s %s: (%s)', self.named2, n, self.Reset
|
|
311
|
+
printf('%s %s: (%s)', self.named2, n, typename(self.Reset))
|
|
312
312
|
return n
|
|
313
313
|
|
|
314
314
|
Clear = Reset
|
pygeodesy/geodesicx/gxline.py
CHANGED
|
@@ -55,7 +55,7 @@ from pygeodesy.utily import atan2, atan2d as _atan2d_reverse, sincos2
|
|
|
55
55
|
from math import cos, degrees, fabs, floor, radians, sin
|
|
56
56
|
|
|
57
57
|
__all__ = ()
|
|
58
|
-
__version__ = '
|
|
58
|
+
__version__ = '25.04.12'
|
|
59
59
|
|
|
60
60
|
_glXs = [] # instances of C{[_]GeodesicLineExact} to be updated
|
|
61
61
|
|
|
@@ -185,8 +185,8 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
185
185
|
|
|
186
186
|
@arg a12: Spherical arc length from the first point to the
|
|
187
187
|
second point (C{degrees}).
|
|
188
|
-
@kwarg outmask: Bit-or'ed combination of L{Caps}
|
|
189
|
-
the quantities to be returned.
|
|
188
|
+
@kwarg outmask: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
189
|
+
values specifying the quantities to be returned.
|
|
190
190
|
|
|
191
191
|
@return: A L{GDict} with up to 12 items C{lat1, lon1, azi1, lat2,
|
|
192
192
|
lon2, azi2, m12, a12, s12, M12, M21, S12} with C{lat1},
|
|
@@ -571,8 +571,8 @@ class _GeodesicLineExact(_GeodesicBase):
|
|
|
571
571
|
'''Find the position on the line given B{C{s12}}.
|
|
572
572
|
|
|
573
573
|
@arg s12: Distance from this this line's first point (C{meter}).
|
|
574
|
-
@kwarg outmask: Bit-or'ed combination of L{Caps}
|
|
575
|
-
the quantities to be returned.
|
|
574
|
+
@kwarg outmask: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>}
|
|
575
|
+
values specifying the quantities to be returned.
|
|
576
576
|
|
|
577
577
|
@return: A L{GDict} with up to 12 items C{lat1, lon1, azi1, lat2,
|
|
578
578
|
lon2, azi2, m12, a12, s12, M12, M21, S12} with C{lat1},
|
pygeodesy/geodsolve.py
CHANGED
|
@@ -9,10 +9,10 @@ Set env variable C{PYGEODESY_GEODSOLVE} to the (fully qualified) path
|
|
|
9
9
|
of the C{GeodSolve} executable.
|
|
10
10
|
'''
|
|
11
11
|
|
|
12
|
-
from pygeodesy.basics import _xinstanceof
|
|
12
|
+
from pygeodesy.basics import _xinstanceof # typename
|
|
13
13
|
# from pygeodesy.constants import NAN, _0_0 # from .karney
|
|
14
14
|
# from pygeodesy.geodesicx import GeodesicAreaExact # _MODS
|
|
15
|
-
from pygeodesy.interns import NN, _UNDER_
|
|
15
|
+
from pygeodesy.interns import _DMAIN_, NN, _UNDER_
|
|
16
16
|
from pygeodesy.karney import Caps, GeodesicError, GeodSolve12Tuple, \
|
|
17
17
|
_sincos2d, _Xables, _0_0, NAN
|
|
18
18
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
@@ -23,7 +23,7 @@ from pygeodesy.solveBase import _SolveGDictBase, _SolveGDictLineBase
|
|
|
23
23
|
from pygeodesy.utily import _unrollon, _Wrap, wrap360
|
|
24
24
|
|
|
25
25
|
__all__ = _ALL_LAZY.geodsolve
|
|
26
|
-
__version__ = '
|
|
26
|
+
__version__ = '25.04.14'
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class _GeodesicSolveBase(_SolveGDictBase):
|
|
@@ -32,7 +32,7 @@ class _GeodesicSolveBase(_SolveGDictBase):
|
|
|
32
32
|
_Error = GeodesicError
|
|
33
33
|
_Names_Direct = \
|
|
34
34
|
_Names_Inverse = GeodSolve12Tuple._Names_
|
|
35
|
-
_Xable_name = _Xables.GeodSolve.__name__
|
|
35
|
+
_Xable_name = _Xables.GeodSolve.__name__ # typename
|
|
36
36
|
_Xable_path = _Xables.GeodSolve()
|
|
37
37
|
|
|
38
38
|
@Property_RO
|
|
@@ -140,8 +140,9 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
140
140
|
@arg azi1: Azimuth at the first point (compass C{degrees}).
|
|
141
141
|
@kwarg caps_name: Optional C{B{name}=NN} (C{str}) and keyword
|
|
142
142
|
argument C{B{caps}=Caps.ALL}, bit-or'ed combination
|
|
143
|
-
of L{Caps} values specifying
|
|
144
|
-
L{GeodesicLineSolve} instance
|
|
143
|
+
of L{Caps<pygeodesy.karney.Caps>} values specifying
|
|
144
|
+
the capabilities the L{GeodesicLineSolve} instance
|
|
145
|
+
should possess.
|
|
145
146
|
|
|
146
147
|
@return: A L{GeodesicLineSolve} instance.
|
|
147
148
|
|
|
@@ -191,8 +192,9 @@ class GeodesicSolve(_GeodesicSolveBase):
|
|
|
191
192
|
@arg lon2: Longitude of the second point (C{degrees}).
|
|
192
193
|
@kwarg caps_name: Optional C{B{name}=NN} (C{str}) and keyword
|
|
193
194
|
argument C{B{caps}=Caps.ALL}, bit-or'ed combination
|
|
194
|
-
of L{Caps} values specifying
|
|
195
|
-
L{GeodesicLineSolve} instance
|
|
195
|
+
of L{Caps<pygeodesy.karney.Caps>} values specifying
|
|
196
|
+
the capabilities the L{GeodesicLineSolve} instance
|
|
197
|
+
should possess.
|
|
196
198
|
|
|
197
199
|
@return: A L{GeodesicLineSolve} instance.
|
|
198
200
|
|
|
@@ -231,16 +233,15 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveGDictLineBase):
|
|
|
231
233
|
@arg lat1: Latitude of the first point (C{degrees}).
|
|
232
234
|
@arg lon1: Longitude of the first point (C{degrees}).
|
|
233
235
|
@arg azi1: Azimuth at the first points (compass C{degrees}).
|
|
234
|
-
@kwarg caps: Bit-or'ed combination of L{Caps} values
|
|
235
|
-
capabilities the L{GeodesicLineSolve} instance
|
|
236
|
-
C{B{caps}=Caps.ALL} always. Include C{Caps.LINE_OFF}
|
|
237
|
-
updates to the B{C{geodesic}} should I{not
|
|
238
|
-
|
|
236
|
+
@kwarg caps: Bit-or'ed combination of L{Caps<pygeodesy.karney.Caps>} values
|
|
237
|
+
specifying the capabilities the L{GeodesicLineSolve} instance
|
|
238
|
+
should possess, C{B{caps}=Caps.ALL} always. Include C{Caps.LINE_OFF}
|
|
239
|
+
if updates to the B{C{geodesic}} should I{not be reflected} in this
|
|
240
|
+
L{GeodesicLineSolve} instance.
|
|
239
241
|
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
240
242
|
|
|
241
|
-
@raise GeodesicError: Invalid path for the C{GeodSolve} executable
|
|
242
|
-
|
|
243
|
-
property C{geodesic.GeodSolve}.
|
|
243
|
+
@raise GeodesicError: Invalid path for the C{GeodSolve} executable or isn't the
|
|
244
|
+
C{GeodSolve} executable, see property C{geodesic.GeodSolve}.
|
|
244
245
|
|
|
245
246
|
@raise TypeError: Invalid B{C{geodesic}}.
|
|
246
247
|
'''
|
|
@@ -384,7 +385,7 @@ class GeodesicLineSolve(_GeodesicSolveBase, _SolveGDictLineBase):
|
|
|
384
385
|
|
|
385
386
|
__all__ += _ALL_DOCS(_GeodesicSolveBase)
|
|
386
387
|
|
|
387
|
-
if __name__ ==
|
|
388
|
+
if __name__ == _DMAIN_:
|
|
388
389
|
|
|
389
390
|
def _main():
|
|
390
391
|
from pygeodesy import printf
|
pygeodesy/geohash.py
CHANGED
|
@@ -21,9 +21,9 @@ from pygeodesy.basics import isstr, map2, _splituple
|
|
|
21
21
|
from pygeodesy.constants import EPS, R_M, _0_0, _0_5, _180_0, _360_0, \
|
|
22
22
|
_90_0, _N_90_0, _N_180_0 # PYCHOK used!
|
|
23
23
|
from pygeodesy.errors import _ValueError, _xkwds, _xStrError
|
|
24
|
-
# from pygeodesy import formy as _formy # _MODS
|
|
25
|
-
from pygeodesy.interns import NN, _DOT_, _E_, _height_, _N_, _NE_,
|
|
26
|
-
_radius_, _S_, _SE_, _SW_, _W_, _width_ # _INV_
|
|
24
|
+
# from pygeodesy import formy as _formy # _MODS.into
|
|
25
|
+
from pygeodesy.interns import NN, _DMAIN_, _DOT_, _E_, _height_, _N_, _NE_, \
|
|
26
|
+
_NW_, _radius_, _S_, _SE_, _SW_, _W_, _width_ # _INV_
|
|
27
27
|
from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY, _ALL_MODS as _MODS
|
|
28
28
|
from pygeodesy.named import _name__, _NamedDict, _NamedTuple, nameof, _xnamed
|
|
29
29
|
from pygeodesy.namedTuples import Bounds2Tuple, Bounds4Tuple, LatLon2Tuple, \
|
|
@@ -37,7 +37,7 @@ from pygeodesy.units import Degrees_, Int, Lat_, Lon_, Meter, Precision_, Str
|
|
|
37
37
|
from math import fabs, ldexp, log10, radians
|
|
38
38
|
|
|
39
39
|
__all__ = _ALL_LAZY.geohash
|
|
40
|
-
__version__ = '25.
|
|
40
|
+
__version__ = '25.04.21'
|
|
41
41
|
|
|
42
42
|
_formy = _MODS.into(formy=__name__)
|
|
43
43
|
_MASK5 = 16, 8, 4, 2, 1 # PYCHOK used!
|
|
@@ -1069,7 +1069,7 @@ __all__ += _ALL_DOCS(bounds, # functions
|
|
|
1069
1069
|
neighbors, precision, resolution2, sizes3, vincentys_,
|
|
1070
1070
|
decode_error, sizes) # DEPRECATED
|
|
1071
1071
|
|
|
1072
|
-
if __name__ ==
|
|
1072
|
+
if __name__ == _DMAIN_:
|
|
1073
1073
|
|
|
1074
1074
|
from pygeodesy.internals import printf, _versions
|
|
1075
1075
|
from timeit import timeit
|