pygeodesy 24.7.24__py2.py3-none-any.whl → 24.8.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 (57) hide show
  1. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/METADATA +20 -19
  2. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/RECORD +57 -57
  3. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/WHEEL +1 -1
  4. pygeodesy/__init__.py +26 -27
  5. pygeodesy/auxilats/auxAngle.py +2 -2
  6. pygeodesy/auxilats/auxDST.py +3 -3
  7. pygeodesy/azimuthal.py +4 -4
  8. pygeodesy/basics.py +3 -3
  9. pygeodesy/cartesianBase.py +6 -6
  10. pygeodesy/constants.py +11 -11
  11. pygeodesy/css.py +5 -5
  12. pygeodesy/ellipsoidalBase.py +18 -15
  13. pygeodesy/ellipsoidalExact.py +2 -2
  14. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  15. pygeodesy/ellipsoidalKarney.py +2 -2
  16. pygeodesy/ellipsoidalNvector.py +2 -2
  17. pygeodesy/ellipsoidalVincenty.py +7 -6
  18. pygeodesy/ellipsoids.py +3 -3
  19. pygeodesy/epsg.py +3 -3
  20. pygeodesy/fmath.py +2 -1
  21. pygeodesy/formy.py +2 -2
  22. pygeodesy/fsums.py +4 -4
  23. pygeodesy/gars.py +66 -58
  24. pygeodesy/geodesici.py +4 -10
  25. pygeodesy/geodesicx/gx.py +3 -3
  26. pygeodesy/geodesicx/gxarea.py +3 -3
  27. pygeodesy/geodsolve.py +3 -3
  28. pygeodesy/geohash.py +491 -267
  29. pygeodesy/geoids.py +298 -316
  30. pygeodesy/heights.py +176 -194
  31. pygeodesy/internals.py +39 -6
  32. pygeodesy/interns.py +2 -3
  33. pygeodesy/karney.py +2 -2
  34. pygeodesy/latlonBase.py +14 -8
  35. pygeodesy/lazily.py +22 -21
  36. pygeodesy/ltp.py +6 -7
  37. pygeodesy/ltpTuples.py +12 -6
  38. pygeodesy/named.py +5 -4
  39. pygeodesy/namedTuples.py +14 -1
  40. pygeodesy/osgr.py +7 -7
  41. pygeodesy/points.py +2 -2
  42. pygeodesy/resections.py +7 -7
  43. pygeodesy/rhumb/solve.py +3 -3
  44. pygeodesy/simplify.py +10 -10
  45. pygeodesy/sphericalBase.py +3 -3
  46. pygeodesy/sphericalTrigonometry.py +2 -2
  47. pygeodesy/streprs.py +3 -3
  48. pygeodesy/triaxials.py +210 -204
  49. pygeodesy/units.py +36 -19
  50. pygeodesy/unitsBase.py +4 -4
  51. pygeodesy/utmupsBase.py +3 -3
  52. pygeodesy/vector2d.py +158 -51
  53. pygeodesy/vector3d.py +13 -52
  54. pygeodesy/vector3dBase.py +81 -63
  55. pygeodesy/webmercator.py +3 -3
  56. pygeodesy/wgrs.py +109 -101
  57. {PyGeodesy-24.7.24.dist-info → PyGeodesy-24.8.24.dist-info}/top_level.txt +0 -0
pygeodesy/wgrs.py CHANGED
@@ -1,25 +1,26 @@
1
1
 
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
- u'''World Geographic Reference System (WGRS) en-/decoding.
4
+ u'''World Geographic Reference System (WGRS) en-/decoding, aka GEOREF.
5
5
 
6
- Classes L{Georef} and L{WGRSError} and several functions to encode,
7
- decode and inspect WGRS references.
6
+ Class L{Georef} and several functions to encode, decode and inspect WGRS
7
+ (or GEOREF) references.
8
8
 
9
9
  Transcoded from I{Charles Karney}'s C++ class U{Georef
10
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>}.
11
+ but with modified C{precision} and extended with C{height} and C{radius}.
12
+
13
+ @see: U{World Geographic Reference System
14
+ <https://WikiPedia.org/wiki/World_Geographic_Reference_System>}.
14
15
  '''
15
16
  # from pygeodesy.basics import isstr # from .named
16
17
  from pygeodesy.constants import INT0, _float, _off90, _0_001, \
17
18
  _0_5, _1_0, _2_0, _60_0, _1000_0
18
- from pygeodesy.dms import parse3llh # parseDMS2
19
+ from pygeodesy.dms import parse3llh
19
20
  from pygeodesy.errors import _ValueError, _xattr, _xStrError
20
21
  from pygeodesy.interns import NN, _0to9_, _AtoZnoIO_, _COMMA_, \
21
- _height_, _radius_, _SPACE_
22
- from pygeodesy.lazily import _ALL_LAZY, _ALL_OTHER
22
+ _height_, _INV_, _radius_, _SPACE_
23
+ from pygeodesy.lazily import _ALL_DOCS, _ALL_LAZY
23
24
  from pygeodesy.named import _name2__, nameof, isstr, Property_RO
24
25
  from pygeodesy.namedTuples import LatLon2Tuple, LatLonPrec3Tuple
25
26
  # from pygeodesy.props import Property_RO # from .named
@@ -31,21 +32,18 @@ from pygeodesy.utily import ft2m, m2ft, m2NM
31
32
  from math import floor
32
33
 
33
34
  __all__ = _ALL_LAZY.wgrs
34
- __version__ = '24.06.15'
35
+ __version__ = '24.08.15'
35
36
 
36
37
  _Base = 10
37
38
  _BaseLen = 4
38
39
  _DegChar = _AtoZnoIO_.tillQ
39
40
  _Digits = _0to9_
40
- _Height_ = Height.__name__
41
- _INV_ = 'INV' # INValid
42
41
  _LatOrig = -90
43
42
  _LatTile = _AtoZnoIO_.tillM
44
43
  _LonOrig = -180
45
44
  _LonTile = _AtoZnoIO_
46
45
  _60B = 60000000000 # == 60_000_000_000 == 60e9
47
46
  _MaxPrec = 11
48
- _Radius_ = Radius.__name__
49
47
  _Tile = 15 # tile size in degrees
50
48
 
51
49
  _MaxLen = _BaseLen + 2 * _MaxPrec
@@ -68,31 +66,30 @@ def _divmod3(x, _Orig_60B):
68
66
  return xt, xd, x
69
67
 
70
68
 
71
- def _fllh3(lat, lon, height=None):
72
- '''(INTERNAL) Convert lat, lon, height.
69
+ def _2fll(lat, lon):
70
+ '''(INTERNAL) Convert lat, lon.
73
71
  '''
74
72
  # lat, lon = parseDMS2(lat, lon)
75
73
  return (Lat(lat, Error=WGRSError),
76
- Lon(lon, Error=WGRSError), height)
74
+ Lon(lon, Error=WGRSError))
77
75
 
78
76
 
79
- def _geostr2(georef):
77
+ def _2geostr2(georef):
80
78
  '''(INTERNAL) Check a georef string.
81
79
  '''
82
80
  try:
83
- n, geostr = len(georef), georef.upper()
81
+ n, g = len(georef), georef.upper()
84
82
  p, o = divmod(n, 2)
85
83
  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)
84
+ or g.startswith(_INV_) or not g.isalnum():
85
+ raise ValueError()
86
+ return g, _2Precision(p - 1)
90
87
 
91
88
  except (AttributeError, TypeError, ValueError) as x:
92
89
  raise WGRSError(Georef.__name__, georef, cause=x)
93
90
 
94
91
 
95
- def _Precision(precision):
92
+ def _2Precision(precision):
96
93
  '''(INTERNAL) Return a L{Precision_} instance.
97
94
  '''
98
95
  return Precision_(precision, Error=WGRSError, low=0, high=_MaxPrec)
@@ -108,48 +105,51 @@ class Georef(Str):
108
105
  '''Georef class, a named C{str}.
109
106
  '''
110
107
  # no str.__init__ in Python 3
111
- def __new__(cls, cll, precision=3, name=NN):
108
+ def __new__(cls, lat_gll, lon=None, height=None, precision=3, name=NN):
112
109
  '''New L{Georef} from an other L{Georef} instance or georef
113
110
  C{str} or from a C{LatLon} instance or lat-/longitude C{str}.
114
111
 
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.
112
+ @arg lat_gll: Latitude (C{degrees90}), a georef (L{Georef},
113
+ C{str}) or a location (C{LatLon}, C{LatLon*Tuple}).
114
+ @kwarg lon: Logitude (C{degrees180)}, required if B{C{lat_gll}}
115
+ is C{degrees90}, ignored otherwise.
116
+ @kwarg height: Optional height in C{meter}, used if B{C{lat_gll}}
117
+ is a location.
118
+ @kwarg precision: The desired georef resolution and length (C{int}
119
+ 0..11), see L{encode<pygeodesy.wgrs.encode>}.
120
120
  @kwarg name: Optional name (C{str}).
121
121
 
122
122
  @return: New L{Georef}.
123
123
 
124
- @raise RangeError: Invalid B{C{cll}} lat- or longitude.
124
+ @raise RangeError: Invalid B{C{lat_gll}} or B{C{lon}}.
125
125
 
126
- @raise TypeError: Invalid B{C{cll}}.
126
+ @raise TypeError: Invalid B{C{lat_gll}} or B{C{lon}}.
127
127
 
128
- @raise WGRSError: INValid or non-alphanumeric B{C{cll}}.
128
+ @raise WGRSError: INValid B{C{lat_gll}}.
129
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))
130
+ if lon is None:
131
+ if isinstance(lat_gll, Georef):
132
+ g, ll, p = str(lat_gll), lat_gll.latlon, lat_gll.precision
133
+ elif isstr(lat_gll):
134
+ if _COMMA_ in lat_gll or _SPACE_ in lat_gll:
135
+ lat, lon, h = parse3llh(lat_gll, height=height)
136
+ g, ll, p = _encode3(lat, lon, precision, h=h)
137
+ else:
138
+ g, ll = lat_gll.upper(), None
139
+ try:
140
+ _, p = _2geostr2(g) # validate
141
+ except WGRSError: # R00H00?
142
+ p = None # = decode5(g).precision?
143
+ else: # assume LatLon
144
+ try:
145
+ g, ll, p = _encode3(lat_gll.lat, lat_gll.lon, precision,
146
+ h=_xattr(lat_gll, height=height))
147
+ except AttributeError:
148
+ raise _xStrError(Georef, gll=lat_gll) # Error=WGRSError
149
+ else:
150
+ g, ll, p = _encode3(lat_gll, lon, precision, h=height)
151
+
152
+ self = Str.__new__(cls, g, name=name or nameof(lat_gll))
153
153
  self._latlon = ll
154
154
  self._precision = p
155
155
  return self
@@ -232,8 +232,8 @@ def decode3(georef, center=True):
232
232
  '''Decode a C{georef} to lat-, longitude and precision.
233
233
 
234
234
  @arg georef: To be decoded (L{Georef} or C{str}).
235
- @kwarg center: If C{True} the center, otherwise the south-west,
236
- lower-left corner (C{bool}).
235
+ @kwarg center: If C{True}, use the georef's center, otherwise
236
+ the south-west, lower-left corner (C{bool}).
237
237
 
238
238
  @return: A L{LatLonPrec3Tuple}C{(lat, lon, precision)}.
239
239
 
@@ -255,7 +255,7 @@ def decode3(georef, center=True):
255
255
  raise _Error(i)
256
256
  return k
257
257
 
258
- g, precision = _geostr2(georef)
258
+ g, precision = _2geostr2(georef)
259
259
  lon = _index(_LonTile, g, 0) + _LonOrig_Tile
260
260
  lat = _index(_LatTile, g, 1) + _LatOrig_Tile
261
261
 
@@ -285,33 +285,32 @@ def decode5(georef, center=True):
285
285
  '''Decode a C{georef} to lat-, longitude, precision, height and radius.
286
286
 
287
287
  @arg georef: To be decoded (L{Georef} or C{str}).
288
- @kwarg center: If C{True} the center, otherwise the south-west,
289
- lower-left corner (C{bool}).
288
+ @kwarg center: If C{True}, use the georef's center, otherwise the
289
+ south-west, lower-left corner (C{bool}).
290
290
 
291
- @return: A L{LatLonPrec5Tuple}C{(lat, lon,
292
- precision, height, radius)} where C{height} and/or
293
- C{radius} are C{None} if missing.
291
+ @return: A L{LatLonPrec5Tuple}C{(lat, lon, precision, height, radius)}
292
+ where C{height} and/or C{radius} are C{None} if missing.
294
293
 
295
- @raise WGRSError: Invalid B{C{georef}}, INValid, non-alphanumeric
296
- or odd length B{C{georef}}.
294
+ @raise WGRSError: Invalid B{C{georef}}.
297
295
  '''
298
- def _h2m(kft, name):
299
- return Height(ft2m(kft * _1000_0), name=name, Error=WGRSError)
296
+ def _h2m(kft, g_n):
297
+ return Height(ft2m(kft * _1000_0), name=g_n, Error=WGRSError)
300
298
 
301
- def _r2m(NM, name):
302
- return Radius(NM / m2NM(1), name=name, Error=WGRSError)
299
+ def _r2m(NM, g_n):
300
+ return Radius(NM / m2NM(1), name=g_n, Error=WGRSError)
303
301
 
304
- def _split2(g, name, _2m):
305
- i = max(g.find(name[0]), g.rfind(name[0]))
302
+ def _split2(g, Unit, _2m):
303
+ n = Unit.__name__
304
+ i = max(g.find(n[0]), g.rfind(n[0]))
306
305
  if i > _BaseLen:
307
- return g[:i], _2m(int(g[i+1:]), _SPACE_(georef, name))
306
+ return g[:i], _2m(int(g[i+1:]), _SPACE_(georef, n))
308
307
  else:
309
308
  return g, None
310
309
 
311
310
  g = Str(georef, Error=WGRSError)
312
311
 
313
- g, h = _split2(g, _Height_, _h2m) # H is last
314
- g, r = _split2(g, _Radius_, _r2m) # R before H
312
+ g, h = _split2(g, Height, _h2m) # H is last
313
+ g, r = _split2(g, Radius, _r2m) # R before H
315
314
 
316
315
  return decode3(g, center=center).to5Tuple(h, r)
317
316
 
@@ -334,41 +333,49 @@ def encode(lat, lon, precision=3, height=None, radius=None): # MCCABE 14
334
333
 
335
334
  @raise WGRSError: Invalid B{C{precision}}, B{C{height}} or B{C{radius}}.
336
335
 
337
- @note: The B{C{precision}} value differs from U{Georef<https://
336
+ @note: The B{C{precision}} value differs from I{Karney}'s U{Georef<https://
338
337
  GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1Georef.html>}.
339
- The C{georef} length is M{2 * (precision + 1)} and the
340
- C{georef} resolution is I{15°} for B{C{precision}} 0, I{1°}
341
- for 1, I{1′} for 2, I{0.1′} for 3, I{0.01′} for 4, ...
342
- M{10**(2 - precision)}.
338
+ The C{georef} length is M{2 * (precision + 1)} and the C{georef}
339
+ resolution is I{15°} for B{C{precision}} 0:, I{1°} for 1, I{1′} for 2,
340
+ I{0.1′} for 3, I{0.01′} for 4, ... up to I{10**(2 - precision)′}.
343
341
  '''
344
342
  def _option(name, m, m2_, K):
345
343
  f = Scalar_(m, name=name, Error=WGRSError)
346
344
  return NN(name[0].upper(), int(m2_(f * K) + _0_5))
347
345
 
348
- p = _Precision(precision)
346
+ g, _, _ = _encode3(lat, lon, precision)
347
+ if radius is not None: # R before H
348
+ g += _option(_radius_, radius, m2NM, _1_0)
349
+ if height is not None: # H is last
350
+ g += _option(_height_, height, m2ft, _0_001)
351
+ return g
352
+
349
353
 
350
- lat, lon, _ = _fllh3(lat, lon)
351
- lat = _off90(lat)
354
+ def _encode3(lat, lon, precision, h=None):
355
+ '''Return 3-tuple C{(georef, (lat, lon), p)}.
356
+ '''
357
+ p = _2Precision(precision)
352
358
 
353
- xt, xd, x = _divmod3(lon, _LonOrig_60B)
354
- yt, yd, y = _divmod3(lat, _LatOrig_60B)
359
+ lat, lon = _2fll(lat, lon)
355
360
 
356
- g = _LonTile[xt], _LatTile[yt]
357
- if p > 0:
358
- g += _DegChar[xd], _DegChar[yd]
359
- p -= 1
360
- if p > 0:
361
- d = pow(_Base, _MaxPrec - p)
362
- x = _0wd(p, x // d)
363
- y = _0wd(p, y // d)
364
- g += x, y
361
+ if h is None:
362
+ xt, xd, x = _divmod3( lon, _LonOrig_60B)
363
+ yt, yd, y = _divmod3(_off90(lat), _LatOrig_60B)
365
364
 
366
- if radius is not None: # R before H
367
- g += _option(_radius_, radius, m2NM, _1_0),
368
- if height is not None: # H is last
369
- g += _option(_height_, height, m2ft, _0_001),
365
+ g = _LonTile[xt], _LatTile[yt]
366
+ if p > 0:
367
+ g += _DegChar[xd], _DegChar[yd]
368
+ p -= 1
369
+ if p > 0:
370
+ d = pow(_Base, _MaxPrec - p)
371
+ x = _0wd(p, x // d)
372
+ y = _0wd(p, y // d)
373
+ g += x, y
374
+ g = NN.join(g)
375
+ else:
376
+ g = encode(lat, lon, precision=p, height=h)
370
377
 
371
- return NN.join(g) # XXX Georef(''.join(g))
378
+ return g, (lat, lon), p # XXX Georef(''.join(g))
372
379
 
373
380
 
374
381
  def precision(res):
@@ -403,7 +410,8 @@ def resolution(prec):
403
410
  '''
404
411
  p = Int(prec=prec, Error=WGRSError)
405
412
  if p > 1:
406
- r = _1_0 / (_60_0 * pow(_Base, min(p, _MaxPrec) - 1))
413
+ p = min(p, _MaxPrec) - 1
414
+ r = _1_0 / (pow(_Base, p) * _60_0)
407
415
  elif p < 1:
408
416
  r = _float_Tile
409
417
  else:
@@ -411,8 +419,8 @@ def resolution(prec):
411
419
  return r
412
420
 
413
421
 
414
- __all__ += _ALL_OTHER(decode3, decode5, # functions
415
- encode, precision, resolution)
422
+ __all__ += _ALL_DOCS(decode3, decode5, # functions
423
+ encode, precision, resolution)
416
424
 
417
425
  # **) MIT License
418
426
  #