pygeodesy 24.7.24__py2.py3-none-any.whl → 24.8.4__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/wgrs.py CHANGED
@@ -1,21 +1,22 @@
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
7
+ WGRS (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
22
  _height_, _radius_, _SPACE_
@@ -31,13 +32,12 @@ 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.02'
35
36
 
36
37
  _Base = 10
37
38
  _BaseLen = 4
38
39
  _DegChar = _AtoZnoIO_.tillQ
39
40
  _Digits = _0to9_
40
- _Height_ = Height.__name__
41
41
  _INV_ = 'INV' # INValid
42
42
  _LatOrig = -90
43
43
  _LatTile = _AtoZnoIO_.tillM
@@ -45,7 +45,6 @@ _LonOrig = -180
45
45
  _LonTile = _AtoZnoIO_
46
46
  _60B = 60000000000 # == 60_000_000_000 == 60e9
47
47
  _MaxPrec = 11
48
- _Radius_ = Radius.__name__
49
48
  _Tile = 15 # tile size in degrees
50
49
 
51
50
  _MaxLen = _BaseLen + 2 * _MaxPrec
@@ -68,15 +67,15 @@ def _divmod3(x, _Orig_60B):
68
67
  return xt, xd, x
69
68
 
70
69
 
71
- def _fllh3(lat, lon, height=None):
72
- '''(INTERNAL) Convert lat, lon, height.
70
+ def _2fll(lat, lon):
71
+ '''(INTERNAL) Convert lat, lon.
73
72
  '''
74
73
  # lat, lon = parseDMS2(lat, lon)
75
74
  return (Lat(lat, Error=WGRSError),
76
- Lon(lon, Error=WGRSError), height)
75
+ Lon(lon, Error=WGRSError))
77
76
 
78
77
 
79
- def _geostr2(georef):
78
+ def _2geostr2(georef):
80
79
  '''(INTERNAL) Check a georef string.
81
80
  '''
82
81
  try:
@@ -85,14 +84,14 @@ def _geostr2(georef):
85
84
  if o or n < _MinLen or n > _MaxLen \
86
85
  or geostr[:3] == _INV_ \
87
86
  or not geostr.isalnum():
88
- raise ValueError
89
- return geostr, _Precision(p - 1)
87
+ raise ValueError()
88
+ return geostr, _2Precision(p - 1)
90
89
 
91
90
  except (AttributeError, TypeError, ValueError) as x:
92
91
  raise WGRSError(Georef.__name__, georef, cause=x)
93
92
 
94
93
 
95
- def _Precision(precision):
94
+ def _2Precision(precision):
96
95
  '''(INTERNAL) Return a L{Precision_} instance.
97
96
  '''
98
97
  return Precision_(precision, Error=WGRSError, low=0, high=_MaxPrec)
@@ -108,48 +107,51 @@ class Georef(Str):
108
107
  '''Georef class, a named C{str}.
109
108
  '''
110
109
  # no str.__init__ in Python 3
111
- def __new__(cls, cll, precision=3, name=NN):
110
+ def __new__(cls, lat_gll, lon=None, height=None, precision=3, name=NN):
112
111
  '''New L{Georef} from an other L{Georef} instance or georef
113
112
  C{str} or from a C{LatLon} instance or lat-/longitude C{str}.
114
113
 
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.
114
+ @arg lat_gll: Latitude (C{degrees90}), a georef (L{Georef},
115
+ C{str}) or a location (C{LatLon}, C{LatLon*Tuple}).
116
+ @kwarg lon: Logitude (C{degrees180)}, required if B{C{lat_gll}}
117
+ is C{degrees90}, ignored otherwise.
118
+ @kwarg height: Optional height in C{meter}, used if B{C{lat_gll}}
119
+ is a location.
120
+ @kwarg precision: The desired georef resolution and length (C{int}
121
+ 0..11), see L{encode<pygeodesy.wgrs.encode>}.
120
122
  @kwarg name: Optional name (C{str}).
121
123
 
122
124
  @return: New L{Georef}.
123
125
 
124
- @raise RangeError: Invalid B{C{cll}} lat- or longitude.
126
+ @raise RangeError: Invalid B{C{lat_gll}} or B{C{lon}}.
125
127
 
126
- @raise TypeError: Invalid B{C{cll}}.
128
+ @raise TypeError: Invalid B{C{lat_gll}} or B{C{lon}}.
127
129
 
128
- @raise WGRSError: INValid or non-alphanumeric B{C{cll}}.
130
+ @raise WGRSError: INValid B{C{lat_gll}}.
129
131
  '''
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))
132
+ if lon is None:
133
+ if isinstance(lat_gll, Georef):
134
+ g, ll, p = str(lat_gll), lat_gll.latlon, lat_gll.precision
135
+ elif isstr(lat_gll):
136
+ if _COMMA_ in lat_gll or _SPACE_ in lat_gll:
137
+ lat, lon, h = parse3llh(lat_gll, height=height)
138
+ g, ll, p = _encode3(lat, lon, precision, h=h)
139
+ else:
140
+ g, ll = lat_gll.upper(), None
141
+ try:
142
+ _, p = _2geostr2(g) # validate
143
+ except WGRSError: # R00H00?
144
+ p = None # = decode5(g).precision?
145
+ else: # assume LatLon
146
+ try:
147
+ g, ll, p = _encode3(lat_gll.lat, lat_gll.lon, precision,
148
+ h=_xattr(lat_gll, height=height))
149
+ except AttributeError:
150
+ raise _xStrError(Georef, gll=lat_gll) # Error=WGRSError
151
+ else:
152
+ g, ll, p = _encode3(lat_gll, lon, precision, h=height)
153
+
154
+ self = Str.__new__(cls, g, name=name or nameof(lat_gll))
153
155
  self._latlon = ll
154
156
  self._precision = p
155
157
  return self
@@ -255,7 +257,7 @@ def decode3(georef, center=True):
255
257
  raise _Error(i)
256
258
  return k
257
259
 
258
- g, precision = _geostr2(georef)
260
+ g, precision = _2geostr2(georef)
259
261
  lon = _index(_LonTile, g, 0) + _LonOrig_Tile
260
262
  lat = _index(_LatTile, g, 1) + _LatOrig_Tile
261
263
 
@@ -288,30 +290,29 @@ def decode5(georef, center=True):
288
290
  @kwarg center: If C{True} the center, otherwise the south-west,
289
291
  lower-left corner (C{bool}).
290
292
 
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.
293
+ @return: A L{LatLonPrec5Tuple}C{(lat, lon, precision, height, radius)}
294
+ where C{height} and/or C{radius} are C{None} if missing.
294
295
 
295
- @raise WGRSError: Invalid B{C{georef}}, INValid, non-alphanumeric
296
- or odd length B{C{georef}}.
296
+ @raise WGRSError: Invalid B{C{georef}}.
297
297
  '''
298
- def _h2m(kft, name):
299
- return Height(ft2m(kft * _1000_0), name=name, Error=WGRSError)
298
+ def _h2m(kft, g_n):
299
+ return Height(ft2m(kft * _1000_0), name=g_n, Error=WGRSError)
300
300
 
301
- def _r2m(NM, name):
302
- return Radius(NM / m2NM(1), name=name, Error=WGRSError)
301
+ def _r2m(NM, g_n):
302
+ return Radius(NM / m2NM(1), name=g_n, Error=WGRSError)
303
303
 
304
- def _split2(g, name, _2m):
305
- i = max(g.find(name[0]), g.rfind(name[0]))
304
+ def _split2(g, Unit, _2m):
305
+ n = Unit.__name__
306
+ i = max(g.find(n[0]), g.rfind(n[0]))
306
307
  if i > _BaseLen:
307
- return g[:i], _2m(int(g[i+1:]), _SPACE_(georef, name))
308
+ return g[:i], _2m(int(g[i+1:]), _SPACE_(georef, n))
308
309
  else:
309
310
  return g, None
310
311
 
311
312
  g = Str(georef, Error=WGRSError)
312
313
 
313
- g, h = _split2(g, _Height_, _h2m) # H is last
314
- g, r = _split2(g, _Radius_, _r2m) # R before H
314
+ g, h = _split2(g, Height, _h2m) # H is last
315
+ g, r = _split2(g, Radius, _r2m) # R before H
315
316
 
316
317
  return decode3(g, center=center).to5Tuple(h, r)
317
318
 
@@ -345,30 +346,39 @@ def encode(lat, lon, precision=3, height=None, radius=None): # MCCABE 14
345
346
  f = Scalar_(m, name=name, Error=WGRSError)
346
347
  return NN(name[0].upper(), int(m2_(f * K) + _0_5))
347
348
 
348
- p = _Precision(precision)
349
+ g, _, _ = _encode3(lat, lon, precision)
350
+ if radius is not None: # R before H
351
+ g += _option(_radius_, radius, m2NM, _1_0)
352
+ if height is not None: # H is last
353
+ g += _option(_height_, height, m2ft, _0_001)
354
+ return g
355
+
349
356
 
350
- lat, lon, _ = _fllh3(lat, lon)
351
- lat = _off90(lat)
357
+ def _encode3(lat, lon, precision, h=None):
358
+ '''Return 3-tuple C{(georef, (lat, lon), p)}.
359
+ '''
360
+ p = _2Precision(precision)
352
361
 
353
- xt, xd, x = _divmod3(lon, _LonOrig_60B)
354
- yt, yd, y = _divmod3(lat, _LatOrig_60B)
362
+ lat, lon = _2fll(lat, lon)
355
363
 
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
364
+ if h is None:
365
+ xt, xd, x = _divmod3( lon, _LonOrig_60B)
366
+ yt, yd, y = _divmod3(_off90(lat), _LatOrig_60B)
365
367
 
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),
368
+ g = _LonTile[xt], _LatTile[yt]
369
+ if p > 0:
370
+ g += _DegChar[xd], _DegChar[yd]
371
+ p -= 1
372
+ if p > 0:
373
+ d = pow(_Base, _MaxPrec - p)
374
+ x = _0wd(p, x // d)
375
+ y = _0wd(p, y // d)
376
+ g += x, y
377
+ g = NN.join(g)
378
+ else:
379
+ g = encode(lat, lon, precision=p, height=h)
370
380
 
371
- return NN.join(g) # XXX Georef(''.join(g))
381
+ return g, (lat, lon), p # XXX Georef(''.join(g))
372
382
 
373
383
 
374
384
  def precision(res):