pygeodesy 24.3.24__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. PyGeodesy-24.3.24.dist-info/METADATA +272 -0
  2. PyGeodesy-24.3.24.dist-info/RECORD +115 -0
  3. PyGeodesy-24.3.24.dist-info/WHEEL +6 -0
  4. PyGeodesy-24.3.24.dist-info/top_level.txt +1 -0
  5. pygeodesy/LICENSE +21 -0
  6. pygeodesy/__init__.py +615 -0
  7. pygeodesy/__main__.py +103 -0
  8. pygeodesy/albers.py +867 -0
  9. pygeodesy/auxilats/_CX_4.py +218 -0
  10. pygeodesy/auxilats/_CX_6.py +314 -0
  11. pygeodesy/auxilats/_CX_8.py +475 -0
  12. pygeodesy/auxilats/__init__.py +54 -0
  13. pygeodesy/auxilats/__main__.py +86 -0
  14. pygeodesy/auxilats/auxAngle.py +548 -0
  15. pygeodesy/auxilats/auxDLat.py +302 -0
  16. pygeodesy/auxilats/auxDST.py +296 -0
  17. pygeodesy/auxilats/auxLat.py +848 -0
  18. pygeodesy/auxilats/auxily.py +272 -0
  19. pygeodesy/azimuthal.py +1150 -0
  20. pygeodesy/basics.py +892 -0
  21. pygeodesy/booleans.py +2031 -0
  22. pygeodesy/cartesianBase.py +1062 -0
  23. pygeodesy/clipy.py +704 -0
  24. pygeodesy/constants.py +516 -0
  25. pygeodesy/css.py +660 -0
  26. pygeodesy/datums.py +752 -0
  27. pygeodesy/deprecated/__init__.py +61 -0
  28. pygeodesy/deprecated/bases.py +40 -0
  29. pygeodesy/deprecated/classes.py +262 -0
  30. pygeodesy/deprecated/consterns.py +54 -0
  31. pygeodesy/deprecated/datum.py +40 -0
  32. pygeodesy/deprecated/functions.py +375 -0
  33. pygeodesy/deprecated/nvector.py +48 -0
  34. pygeodesy/deprecated/rhumbBase.py +32 -0
  35. pygeodesy/deprecated/rhumbaux.py +33 -0
  36. pygeodesy/deprecated/rhumbsolve.py +33 -0
  37. pygeodesy/deprecated/rhumbx.py +33 -0
  38. pygeodesy/dms.py +986 -0
  39. pygeodesy/ecef.py +1348 -0
  40. pygeodesy/elevations.py +279 -0
  41. pygeodesy/ellipsoidalBase.py +1224 -0
  42. pygeodesy/ellipsoidalBaseDI.py +913 -0
  43. pygeodesy/ellipsoidalExact.py +343 -0
  44. pygeodesy/ellipsoidalGeodSolve.py +343 -0
  45. pygeodesy/ellipsoidalKarney.py +403 -0
  46. pygeodesy/ellipsoidalNvector.py +685 -0
  47. pygeodesy/ellipsoidalVincenty.py +590 -0
  48. pygeodesy/ellipsoids.py +2476 -0
  49. pygeodesy/elliptic.py +1198 -0
  50. pygeodesy/epsg.py +243 -0
  51. pygeodesy/errors.py +804 -0
  52. pygeodesy/etm.py +1190 -0
  53. pygeodesy/fmath.py +1013 -0
  54. pygeodesy/formy.py +1818 -0
  55. pygeodesy/frechet.py +865 -0
  56. pygeodesy/fstats.py +760 -0
  57. pygeodesy/fsums.py +1898 -0
  58. pygeodesy/gars.py +358 -0
  59. pygeodesy/geodesicw.py +581 -0
  60. pygeodesy/geodesicx/_C4_24.py +1699 -0
  61. pygeodesy/geodesicx/_C4_27.py +2395 -0
  62. pygeodesy/geodesicx/_C4_30.py +3301 -0
  63. pygeodesy/geodesicx/__init__.py +48 -0
  64. pygeodesy/geodesicx/__main__.py +91 -0
  65. pygeodesy/geodesicx/gx.py +1382 -0
  66. pygeodesy/geodesicx/gxarea.py +535 -0
  67. pygeodesy/geodesicx/gxbases.py +154 -0
  68. pygeodesy/geodesicx/gxline.py +669 -0
  69. pygeodesy/geodsolve.py +426 -0
  70. pygeodesy/geohash.py +914 -0
  71. pygeodesy/geoids.py +1884 -0
  72. pygeodesy/hausdorff.py +892 -0
  73. pygeodesy/heights.py +1155 -0
  74. pygeodesy/interns.py +687 -0
  75. pygeodesy/iters.py +545 -0
  76. pygeodesy/karney.py +919 -0
  77. pygeodesy/ktm.py +633 -0
  78. pygeodesy/latlonBase.py +1766 -0
  79. pygeodesy/lazily.py +960 -0
  80. pygeodesy/lcc.py +684 -0
  81. pygeodesy/ltp.py +1107 -0
  82. pygeodesy/ltpTuples.py +1563 -0
  83. pygeodesy/mgrs.py +721 -0
  84. pygeodesy/named.py +1324 -0
  85. pygeodesy/namedTuples.py +683 -0
  86. pygeodesy/nvectorBase.py +695 -0
  87. pygeodesy/osgr.py +781 -0
  88. pygeodesy/points.py +1686 -0
  89. pygeodesy/props.py +628 -0
  90. pygeodesy/resections.py +1048 -0
  91. pygeodesy/rhumb/__init__.py +46 -0
  92. pygeodesy/rhumb/aux_.py +397 -0
  93. pygeodesy/rhumb/bases.py +1148 -0
  94. pygeodesy/rhumb/ekx.py +563 -0
  95. pygeodesy/rhumb/solve.py +572 -0
  96. pygeodesy/simplify.py +647 -0
  97. pygeodesy/solveBase.py +472 -0
  98. pygeodesy/sphericalBase.py +724 -0
  99. pygeodesy/sphericalNvector.py +1264 -0
  100. pygeodesy/sphericalTrigonometry.py +1447 -0
  101. pygeodesy/streprs.py +627 -0
  102. pygeodesy/trf.py +2079 -0
  103. pygeodesy/triaxials.py +1484 -0
  104. pygeodesy/units.py +969 -0
  105. pygeodesy/unitsBase.py +349 -0
  106. pygeodesy/ups.py +538 -0
  107. pygeodesy/utily.py +1231 -0
  108. pygeodesy/utm.py +762 -0
  109. pygeodesy/utmups.py +318 -0
  110. pygeodesy/utmupsBase.py +517 -0
  111. pygeodesy/vector2d.py +785 -0
  112. pygeodesy/vector3d.py +968 -0
  113. pygeodesy/vector3dBase.py +1049 -0
  114. pygeodesy/webmercator.py +383 -0
  115. pygeodesy/wgrs.py +439 -0
pygeodesy/wgrs.py ADDED
@@ -0,0 +1,439 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ u'''World Geographic Reference System (WGRS) en-/decoding.
5
+
6
+ Classes L{Georef} and L{WGRSError} and several functions to encode,
7
+ decode and inspect WGRS references.
8
+
9
+ Transcoded from I{Charles Karney}'s C++ class U{Georef
10
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Georef.html>},
11
+ but with modified C{precision} and extended with C{height} and C{radius}. See
12
+ also U{World Geographic Reference System
13
+ <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}.
14
+ '''
15
+ # from pygeodesy.basics import isstr # from .named
16
+ from pygeodesy.constants import INT0, _float, _off90, _0_001, \
17
+ _0_5, _1_0, _2_0, _60_0, _1000_0
18
+ from pygeodesy.dms import parse3llh # parseDMS2
19
+ from pygeodesy.errors import _ValueError, _xattr, _xkwds
20
+ from pygeodesy.interns import NN, _0to9_, _AtoZnoIO_, _COMMA_, \
21
+ _height_, _radius_, _SPACE_
22
+ from pygeodesy.lazily import _ALL_LAZY, _ALL_OTHER
23
+ from pygeodesy.named import nameof, isstr, Property_RO
24
+ from pygeodesy.namedTuples import LatLon2Tuple, LatLonPrec3Tuple
25
+ # from pygeodesy.props import Property_RO # from .named
26
+ from pygeodesy.streprs import Fmt, _0wd
27
+ from pygeodesy.units import Height, Int, Lat, Lon, Precision_, \
28
+ Radius, Scalar_, Str, _xStrError
29
+ from pygeodesy.utily import ft2m, m2ft, m2NM
30
+
31
+ from math import floor
32
+
33
+ __all__ = _ALL_LAZY.wgrs
34
+ __version__ = '23.06.12'
35
+
36
+ _Base = 10
37
+ _BaseLen = 4
38
+ _DegChar = _AtoZnoIO_.tillQ
39
+ _Digits = _0to9_
40
+ _Height_ = Height.__name__
41
+ _INV_ = 'INV' # INValid
42
+ _LatOrig = -90
43
+ _LatTile = _AtoZnoIO_.tillM
44
+ _LonOrig = -180
45
+ _LonTile = _AtoZnoIO_
46
+ _60B = 60000000000 # == 60_000_000_000 == 60e9
47
+ _MaxPrec = 11
48
+ _Radius_ = Radius.__name__
49
+ _Tile = 15 # tile size in degrees
50
+
51
+ _MaxLen = _BaseLen + 2 * _MaxPrec
52
+ _MinLen = _BaseLen - 2
53
+
54
+ _LatOrig_60B = _LatOrig * _60B
55
+ _LonOrig_60B = _LonOrig * _60B
56
+
57
+ _float_Tile = _float(_Tile)
58
+ _LatOrig_Tile = _float(_LatOrig) / _Tile
59
+ _LonOrig_Tile = _float(_LonOrig) / _Tile
60
+
61
+
62
+ def _divmod3(x, _Orig_60B):
63
+ '''(INTERNAL) Convert B{C{x}} to 3_tuple C{(tile, modulo, fraction)}/
64
+ '''
65
+ i = int(floor(x * _60B))
66
+ i, x = divmod(i - _Orig_60B, _60B)
67
+ xt, xd = divmod(i, _Tile)
68
+ return xt, xd, x
69
+
70
+
71
+ def _fllh3(lat, lon, height=None):
72
+ '''(INTERNAL) Convert lat, lon, height.
73
+ '''
74
+ # lat, lon = parseDMS2(lat, lon)
75
+ return (Lat(lat, Error=WGRSError),
76
+ Lon(lon, Error=WGRSError), height)
77
+
78
+
79
+ def _geostr2(georef):
80
+ '''(INTERNAL) Check a georef string.
81
+ '''
82
+ try:
83
+ n, geostr = len(georef), georef.upper()
84
+ p, o = divmod(n, 2)
85
+ if o or n < _MinLen or n > _MaxLen \
86
+ or geostr[:3] == _INV_ \
87
+ or not geostr.isalnum():
88
+ raise ValueError
89
+ return geostr, _Precision(p - 1)
90
+
91
+ except (AttributeError, TypeError, ValueError) as x:
92
+ raise WGRSError(Georef.__name__, georef, cause=x)
93
+
94
+
95
+ def _Precision(precision):
96
+ '''(INTERNAL) Return a L{Precision_} instance.
97
+ '''
98
+ return Precision_(precision, Error=WGRSError, low=0, high=_MaxPrec)
99
+
100
+
101
+ class WGRSError(_ValueError):
102
+ '''World Geographic Reference System (WGRS) encode, decode or other L{Georef} issue.
103
+ '''
104
+ pass
105
+
106
+
107
+ class Georef(Str):
108
+ '''Georef class, a named C{str}.
109
+ '''
110
+ # no str.__init__ in Python 3
111
+ def __new__(cls, cll, precision=3, name=NN):
112
+ '''New L{Georef} from an other L{Georef} instance or georef
113
+ C{str} or from a C{LatLon} instance or lat-/longitude C{str}.
114
+
115
+ @arg cll: Cell or location (L{Georef} or C{str}, C{LatLon}
116
+ or C{str}).
117
+ @kwarg precision: Optional, the desired georef resolution
118
+ and length (C{int} 0..11), see function
119
+ L{wgrs.encode} for more details.
120
+ @kwarg name: Optional name (C{str}).
121
+
122
+ @return: New L{Georef}.
123
+
124
+ @raise RangeError: Invalid B{C{cll}} lat- or longitude.
125
+
126
+ @raise TypeError: Invalid B{C{cll}}.
127
+
128
+ @raise WGRSError: INValid or non-alphanumeric B{C{cll}}.
129
+ '''
130
+ ll = p = None
131
+
132
+ if isinstance(cll, Georef):
133
+ g, p = _geostr2(str(cll))
134
+
135
+ elif isstr(cll):
136
+ if _COMMA_ in cll:
137
+ lat, lon, h = _fllh3(*parse3llh(cll, height=None))
138
+ g = encode(lat, lon, precision=precision, height=h) # PYCHOK false
139
+ ll = lat, lon # original lat, lon
140
+ else:
141
+ g = cll.upper()
142
+
143
+ else: # assume LatLon
144
+ try:
145
+ lat, lon, h = _fllh3(cll.lat, cll.lon)
146
+ except AttributeError:
147
+ raise _xStrError(Georef, cll=cll) # Error=WGRSError
148
+ h = _xattr(cll, height=h)
149
+ g = encode(lat, lon, precision=precision, height=h) # PYCHOK false
150
+ ll = lat, lon # original lat, lon
151
+
152
+ self = Str.__new__(cls, g, name=name or nameof(cll))
153
+ self._latlon = ll
154
+ self._precision = p
155
+ return self
156
+
157
+ @Property_RO
158
+ def decoded3(self):
159
+ '''Get this georef's attributes (L{LatLonPrec3Tuple}).
160
+ '''
161
+ lat, lon = self.latlon
162
+ return LatLonPrec3Tuple(lat, lon, self.precision, name=self.name)
163
+
164
+ @Property_RO
165
+ def decoded5(self):
166
+ '''Get this georef's attributes (L{LatLonPrec5Tuple}) with
167
+ height and radius set to C{None} if missing.
168
+ '''
169
+ return self.decoded3.to5Tuple(self.height, self.radius)
170
+
171
+ @Property_RO
172
+ def _decoded5(self):
173
+ '''(INTERNAL) Initial L{LatLonPrec5Tuple}.
174
+ '''
175
+ return decode5(self)
176
+
177
+ @Property_RO
178
+ def height(self):
179
+ '''Get this georef's height in C{meter} or C{None} if missing.
180
+ '''
181
+ return self._decoded5.height
182
+
183
+ @Property_RO
184
+ def latlon(self):
185
+ '''Get this georef's (center) lat- and longitude (L{LatLon2Tuple}).
186
+ '''
187
+ lat, lon = self._latlon or self._decoded5[:2]
188
+ return LatLon2Tuple(lat, lon, name=self.name)
189
+
190
+ @Property_RO
191
+ def latlonheight(self):
192
+ '''Get this georef's (center) lat-, longitude and height (L{LatLon3Tuple}),
193
+ with height set to C{INT0} if missing.
194
+ '''
195
+ return self.latlon.to3Tuple(self.height or INT0)
196
+
197
+ @Property_RO
198
+ def precision(self):
199
+ '''Get this georef's precision (C{int}).
200
+ '''
201
+ p = self._precision
202
+ return self._decoded5.precision if p is None else p
203
+
204
+ @Property_RO
205
+ def radius(self):
206
+ '''Get this georef's radius in C{meter} or C{None} if missing.
207
+ '''
208
+ return self._decoded5.radius
209
+
210
+ def toLatLon(self, LatLon=None, height=None, **LatLon_kwds):
211
+ '''Return (the center of) this georef cell as an instance
212
+ of the supplied C{LatLon} class.
213
+
214
+ @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
215
+ @kwarg height: Optional height (C{meter}).
216
+ @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
217
+ arguments, ignored if C{B{LatLon} is None}.
218
+
219
+ @return: This georef location (B{C{LatLon}}) or if B{C{LatLon}}
220
+ is C{None}, a L{LatLon3Tuple}C{(lat, lon, height)}.
221
+
222
+ @raise TypeError: Invalid B{C{LatLon}} or B{C{LatLon_kwds}}.
223
+ '''
224
+ if LatLon is None:
225
+ r = self.latlonheight if height is None else \
226
+ self.latlon.to3Tuple(height)
227
+ else:
228
+ h = (self.height or INT0) if height is None else height
229
+ r = LatLon(*self.latlon, height=h, **_xkwds(LatLon_kwds, name=self.name))
230
+ return r
231
+
232
+
233
+ def decode3(georef, center=True):
234
+ '''Decode a C{georef} to lat-, longitude and precision.
235
+
236
+ @arg georef: To be decoded (L{Georef} or C{str}).
237
+ @kwarg center: If C{True} the center, otherwise the south-west,
238
+ lower-left corner (C{bool}).
239
+
240
+ @return: A L{LatLonPrec3Tuple}C{(lat, lon, precision)}.
241
+
242
+ @raise WGRSError: Invalid B{C{georef}}, INValid, non-alphanumeric
243
+ or odd length B{C{georef}}.
244
+ '''
245
+ def _digit(ll, g, i, m):
246
+ d = _Digits.find(g[i])
247
+ if d < 0 or d >= m:
248
+ raise _Error(i)
249
+ return ll * m + d
250
+
251
+ def _Error(i):
252
+ return WGRSError(Fmt.SQUARE(georef=i), georef)
253
+
254
+ def _index(chars, g, i):
255
+ k = chars.find(g[i])
256
+ if k < 0:
257
+ raise _Error(i)
258
+ return k
259
+
260
+ g, precision = _geostr2(georef)
261
+ lon = _index(_LonTile, g, 0) + _LonOrig_Tile
262
+ lat = _index(_LatTile, g, 1) + _LatOrig_Tile
263
+
264
+ u = _1_0
265
+ if precision > 0:
266
+ lon = lon * _Tile + _index(_DegChar, g, 2)
267
+ lat = lat * _Tile + _index(_DegChar, g, 3)
268
+ m, p = 6, precision - 1
269
+ for i in range(_BaseLen, _BaseLen + p):
270
+ lon = _digit(lon, g, i, m)
271
+ lat = _digit(lat, g, i + p, m)
272
+ u *= m
273
+ m = _Base
274
+ u *= _Tile
275
+
276
+ if center:
277
+ lon = lon * _2_0 + _1_0
278
+ lat = lat * _2_0 + _1_0
279
+ u *= _2_0
280
+ u = _Tile / u
281
+ return LatLonPrec3Tuple(Lat(lat * u, Error=WGRSError),
282
+ Lon(lon * u, Error=WGRSError),
283
+ precision, name=nameof(georef))
284
+
285
+
286
+ def decode5(georef, center=True):
287
+ '''Decode a C{georef} to lat-, longitude, precision, height and radius.
288
+
289
+ @arg georef: To be decoded (L{Georef} or C{str}).
290
+ @kwarg center: If C{True} the center, otherwise the south-west,
291
+ lower-left corner (C{bool}).
292
+
293
+ @return: A L{LatLonPrec5Tuple}C{(lat, lon,
294
+ precision, height, radius)} where C{height} and/or
295
+ C{radius} are C{None} if missing.
296
+
297
+ @raise WGRSError: Invalid B{C{georef}}, INValid, non-alphanumeric
298
+ or odd length B{C{georef}}.
299
+ '''
300
+ def _h2m(kft, name):
301
+ return Height(ft2m(kft * _1000_0), name=name, Error=WGRSError)
302
+
303
+ def _r2m(NM, name):
304
+ return Radius(NM / m2NM(1), name=name, Error=WGRSError)
305
+
306
+ def _split2(g, name, _2m):
307
+ i = max(g.find(name[0]), g.rfind(name[0]))
308
+ if i > _BaseLen:
309
+ return g[:i], _2m(int(g[i+1:]), _SPACE_(georef, name))
310
+ else:
311
+ return g, None
312
+
313
+ g = Str(georef, Error=WGRSError)
314
+
315
+ g, h = _split2(g, _Height_, _h2m) # H is last
316
+ g, r = _split2(g, _Radius_, _r2m) # R before H
317
+
318
+ return decode3(g, center=center).to5Tuple(h, r)
319
+
320
+
321
+ def encode(lat, lon, precision=3, height=None, radius=None): # MCCABE 14
322
+ '''Encode a lat-/longitude as a C{georef} of the given precision.
323
+
324
+ @arg lat: Latitude (C{degrees}).
325
+ @arg lon: Longitude (C{degrees}).
326
+ @kwarg precision: Optional, the desired C{georef} resolution and length
327
+ (C{int} 0..11).
328
+ @kwarg height: Optional, height in C{meter}, see U{Designation of area
329
+ <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}.
330
+ @kwarg radius: Optional, radius in C{meter}, see U{Designation of area
331
+ <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}.
332
+
333
+ @return: The C{georef} (C{str}).
334
+
335
+ @raise RangeError: Invalid B{C{lat}} or B{C{lon}}.
336
+
337
+ @raise WGRSError: Invalid B{C{precision}}, B{C{height}} or B{C{radius}}.
338
+
339
+ @note: The B{C{precision}} value differs from U{Georef<https://
340
+ GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Georef.html>}.
341
+ The C{georef} length is M{2 * (precision + 1)} and the
342
+ C{georef} resolution is I{15°} for B{C{precision}} 0, I{1°}
343
+ for 1, I{1′} for 2, I{0.1′} for 3, I{0.01′} for 4, ...
344
+ M{10**(2 - precision)}.
345
+ '''
346
+ def _option(name, m, m2_, K):
347
+ f = Scalar_(m, name=name, Error=WGRSError)
348
+ return NN(name[0].upper(), int(m2_(f * K) + _0_5))
349
+
350
+ p = _Precision(precision)
351
+
352
+ lat, lon, _ = _fllh3(lat, lon)
353
+ lat = _off90(lat)
354
+
355
+ xt, xd, x = _divmod3(lon, _LonOrig_60B)
356
+ yt, yd, y = _divmod3(lat, _LatOrig_60B)
357
+
358
+ g = _LonTile[xt], _LatTile[yt]
359
+ if p > 0:
360
+ g += _DegChar[xd], _DegChar[yd]
361
+ p -= 1
362
+ if p > 0:
363
+ d = pow(_Base, _MaxPrec - p)
364
+ x = _0wd(p, x // d)
365
+ y = _0wd(p, y // d)
366
+ g += x, y
367
+
368
+ if radius is not None: # R before H
369
+ g += _option(_radius_, radius, m2NM, _1_0),
370
+ if height is not None: # H is last
371
+ g += _option(_height_, height, m2ft, _0_001),
372
+
373
+ return NN.join(g) # XXX Georef(''.join(g))
374
+
375
+
376
+ def precision(res):
377
+ '''Determine the L{Georef} precision to meet a required (geographic)
378
+ resolution.
379
+
380
+ @arg res: The required resolution (C{degrees}).
381
+
382
+ @return: The L{Georef} precision (C{int} 0..11).
383
+
384
+ @raise ValueError: Invalid B{C{res}}.
385
+
386
+ @see: Function L{wgrs.encode} for more C{precision} details.
387
+ '''
388
+ r = Scalar_(res=res)
389
+ for p in range(_MaxPrec):
390
+ if resolution(p) <= r:
391
+ return p
392
+ return _MaxPrec
393
+
394
+
395
+ def resolution(prec):
396
+ '''Determine the (geographic) resolution of a given L{Georef} precision.
397
+
398
+ @arg prec: The given precision (C{int}).
399
+
400
+ @return: The (geographic) resolution (C{degrees}).
401
+
402
+ @raise ValueError: Invalid B{C{prec}}.
403
+
404
+ @see: Function L{wgrs.encode} for more C{precision} details.
405
+ '''
406
+ p = Int(prec=prec, Error=WGRSError)
407
+ if p > 1:
408
+ r = _1_0 / (_60_0 * pow(_Base, min(p, _MaxPrec) - 1))
409
+ elif p < 1:
410
+ r = _float_Tile
411
+ else:
412
+ r = _1_0
413
+ return r
414
+
415
+
416
+ __all__ += _ALL_OTHER(decode3, decode5, # functions
417
+ encode, precision, resolution)
418
+
419
+ # **) MIT License
420
+ #
421
+ # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
422
+ #
423
+ # Permission is hereby granted, free of charge, to any person obtaining a
424
+ # copy of this software and associated documentation files (the "Software"),
425
+ # to deal in the Software without restriction, including without limitation
426
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
427
+ # and/or sell copies of the Software, and to permit persons to whom the
428
+ # Software is furnished to do so, subject to the following conditions:
429
+ #
430
+ # The above copyright notice and this permission notice shall be included
431
+ # in all copies or substantial portions of the Software.
432
+ #
433
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
434
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
435
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
436
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
437
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
438
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
439
+ # OTHER DEALINGS IN THE SOFTWARE.