pygeodesy 24.5.24__py2.py3-none-any.whl → 24.6.1__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.5.24.dist-info → PyGeodesy-24.6.1.dist-info}/METADATA +6 -5
- {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.1.dist-info}/RECORD +57 -57
- pygeodesy/__init__.py +4 -4
- pygeodesy/auxilats/__init__.py +1 -1
- pygeodesy/auxilats/__main__.py +2 -2
- pygeodesy/auxilats/auxAngle.py +4 -4
- pygeodesy/basics.py +39 -5
- pygeodesy/booleans.py +3 -3
- pygeodesy/constants.py +3 -3
- pygeodesy/deprecated/functions.py +9 -3
- pygeodesy/ecef.py +22 -21
- pygeodesy/ellipsoidalBase.py +15 -16
- pygeodesy/ellipsoidalGeodSolve.py +2 -2
- pygeodesy/ellipsoidalKarney.py +3 -3
- pygeodesy/ellipsoids.py +6 -5
- pygeodesy/errors.py +19 -9
- pygeodesy/etm.py +16 -21
- pygeodesy/fmath.py +9 -20
- pygeodesy/formy.py +60 -74
- pygeodesy/frechet.py +11 -11
- pygeodesy/fsums.py +59 -25
- pygeodesy/geodesicx/__init__.py +1 -1
- pygeodesy/geodesicx/__main__.py +2 -2
- pygeodesy/geodesicx/gx.py +3 -5
- pygeodesy/geodsolve.py +2 -2
- pygeodesy/geohash.py +14 -14
- pygeodesy/hausdorff.py +12 -12
- pygeodesy/heights.py +5 -5
- pygeodesy/internals.py +3 -3
- pygeodesy/karney.py +8 -7
- pygeodesy/lazily.py +2 -2
- pygeodesy/ltp.py +62 -44
- pygeodesy/ltpTuples.py +202 -147
- pygeodesy/mgrs.py +24 -24
- pygeodesy/named.py +68 -70
- pygeodesy/nvectorBase.py +2 -2
- pygeodesy/osgr.py +40 -48
- pygeodesy/points.py +10 -10
- pygeodesy/props.py +29 -16
- pygeodesy/rhumb/aux_.py +13 -15
- pygeodesy/rhumb/bases.py +12 -5
- pygeodesy/rhumb/ekx.py +24 -18
- pygeodesy/rhumb/solve.py +13 -10
- pygeodesy/simplify.py +16 -16
- pygeodesy/solveBase.py +14 -14
- pygeodesy/sphericalBase.py +17 -21
- pygeodesy/sphericalTrigonometry.py +17 -17
- pygeodesy/trf.py +9 -7
- pygeodesy/triaxials.py +2 -2
- pygeodesy/ups.py +66 -70
- pygeodesy/utily.py +3 -3
- pygeodesy/utm.py +152 -156
- pygeodesy/utmups.py +38 -38
- pygeodesy/utmupsBase.py +102 -106
- pygeodesy/webmercator.py +43 -51
- {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.1.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.1.dist-info}/top_level.txt +0 -0
pygeodesy/utm.py
CHANGED
|
@@ -44,8 +44,7 @@ from pygeodesy.fmath import fdot3, hypot, hypot1, _operator
|
|
|
44
44
|
from pygeodesy.interns import MISSING, NN, _by_, _COMMASPACE_, _N_, \
|
|
45
45
|
_NS_, _outside_, _range_, _S_, _scale0_, \
|
|
46
46
|
_SPACE_, _UTM_, _V_, _X_, _zone_
|
|
47
|
-
|
|
48
|
-
from pygeodesy.named import _name__, _name2__, _ALL_LAZY, _MODS
|
|
47
|
+
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
|
|
49
48
|
from pygeodesy.namedTuples import EasNor2Tuple, UtmUps5Tuple, \
|
|
50
49
|
UtmUps8Tuple, UtmUpsLatLon5Tuple
|
|
51
50
|
from pygeodesy.props import deprecated_method, property_doc_, \
|
|
@@ -64,7 +63,7 @@ from math import asinh, atanh, atan2, cos, cosh, degrees, fabs, \
|
|
|
64
63
|
# import operator as _operator # from .fmath
|
|
65
64
|
|
|
66
65
|
__all__ = _ALL_LAZY.utm
|
|
67
|
-
__version__ = '24.05.
|
|
66
|
+
__version__ = '24.05.31'
|
|
68
67
|
|
|
69
68
|
_Bands = 'CDEFGHJKLMNPQRSTUVWXX' # UTM latitude bands C..X (no
|
|
70
69
|
# I|O) 8° each, covering 80°S to 84°N and X repeated for 80-84°N
|
|
@@ -134,121 +133,6 @@ class _Kseries(object):
|
|
|
134
133
|
return fdot3(self._pq, self._sy, self._shx, start=q0)
|
|
135
134
|
|
|
136
135
|
|
|
137
|
-
def _cmlon(zone):
|
|
138
|
-
'''(INTERNAL) Central meridian longitude (C{degrees180}).
|
|
139
|
-
'''
|
|
140
|
-
return (zone * 6) - 183
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def _false2(e, n, h):
|
|
144
|
-
'''(INTERNAL) False easting and northing.
|
|
145
|
-
'''
|
|
146
|
-
# Karney, "Test data for the transverse Mercator projection (2009)"
|
|
147
|
-
# <https://GeographicLib.SourceForge.io/C++/doc/transversemercator.html>
|
|
148
|
-
# and <https://Zenodo.org/record/32470#.W4LEJS2ZON8>
|
|
149
|
-
e += _FalseEasting # make e relative to central meridian
|
|
150
|
-
if h == _S_:
|
|
151
|
-
n += _FalseNorthing # make n relative to equator
|
|
152
|
-
return e, n
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def _toBand(lat, *unused, **strict_Error): # see ups._toBand
|
|
156
|
-
'''(INTERNAL) Get the I{latitudinal} Band (row) letter.
|
|
157
|
-
'''
|
|
158
|
-
if _UTM_LAT_MIN <= lat < _UTM_LAT_MAX: # [-80, 84) like Veness
|
|
159
|
-
return _Bands[int(lat - _UTM_LAT_MIN) >> 3]
|
|
160
|
-
elif _xkwds_get(strict_Error, strict=True):
|
|
161
|
-
r = _range_(_UTM_LAT_MIN, _UTM_LAT_MAX, ropen=True)
|
|
162
|
-
t = _SPACE_(_outside_, _UTM_, _range_, r)
|
|
163
|
-
E = _xkwds_get(strict_Error, Error=RangeError)
|
|
164
|
-
raise E(lat=degDMS(lat), txt=t)
|
|
165
|
-
else:
|
|
166
|
-
return NN # None
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def _to3zBlat(zone, band, Error=UTMError): # in .mgrs
|
|
170
|
-
'''(INTERNAL) Check and return zone, Band and band latitude.
|
|
171
|
-
|
|
172
|
-
@arg zone: Zone number or string.
|
|
173
|
-
@arg band: Band letter.
|
|
174
|
-
@arg Error: Exception to raise (L{UTMError}).
|
|
175
|
-
|
|
176
|
-
@return: 3-Tuple (zone, Band, latitude).
|
|
177
|
-
'''
|
|
178
|
-
z, B, _ = _to3zBhp(zone, band, Error=Error)
|
|
179
|
-
if not (_UTM_ZONE_MIN <= z <= _UTM_ZONE_MAX or
|
|
180
|
-
(_UPS_ZONE == z and Error is MGRSError)):
|
|
181
|
-
raise Error(zone=zone)
|
|
182
|
-
|
|
183
|
-
b = None
|
|
184
|
-
if B:
|
|
185
|
-
if z == _UPS_ZONE: # polar
|
|
186
|
-
try:
|
|
187
|
-
b = Lat(_UPS_LATS[B], name=_bandLat_)
|
|
188
|
-
except KeyError:
|
|
189
|
-
raise Error(band=band or B, zone=z)
|
|
190
|
-
else: # UTM
|
|
191
|
-
b = _Bands.find(B)
|
|
192
|
-
if b < 0:
|
|
193
|
-
raise Error(band=band or B, zone=z)
|
|
194
|
-
b = Int((b << 3) - 80, name=_bandLat_)
|
|
195
|
-
B = Band(B)
|
|
196
|
-
elif Error is not UTMError:
|
|
197
|
-
raise Error(band=band, txt=MISSING)
|
|
198
|
-
|
|
199
|
-
return Zone(z), B, b
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def _to4zBll(lat, lon, cmoff=True, strict=True, Error=RangeError):
|
|
203
|
-
'''(INTERNAL) Return zone, Band and lat- and (central) longitude in degrees.
|
|
204
|
-
|
|
205
|
-
@arg lat: Latitude (C{degrees}).
|
|
206
|
-
@arg lon: Longitude (C{degrees}).
|
|
207
|
-
@kwarg cmoff: Offset B{C{lon}} from zone's central meridian.
|
|
208
|
-
@kwarg strict: Restrict B{C{lat}} to UTM ranges (C{bool}).
|
|
209
|
-
@kwarg Error: Error for out of UTM range B{C{lat}}s.
|
|
210
|
-
|
|
211
|
-
@return: 4-Tuple (zone, Band, lat, lon).
|
|
212
|
-
'''
|
|
213
|
-
z, lat, lon = _to3zll(lat, lon) # in .utmupsBase
|
|
214
|
-
|
|
215
|
-
x = lon - _cmlon(z) # z before Norway/Svalbard
|
|
216
|
-
if fabs(x) > _UTM_ZONE_OFF_MAX:
|
|
217
|
-
t = _SPACE_(_outside_, _UTM_, _zone_, str(z), _by_, degDMS(x, prec=6))
|
|
218
|
-
raise Error(lon=degDMS(lon), txt=t)
|
|
219
|
-
|
|
220
|
-
B = _toBand(lat, strict=strict, Error=Error)
|
|
221
|
-
if B == _X_: # and 0 <= lon < 42: z = int(lon + 183) // 6 + 1
|
|
222
|
-
x = _SvalbardXzone.get(z, None)
|
|
223
|
-
if x: # Svalbard/Spitsbergen archipelago
|
|
224
|
-
z += 1 if lon >= x else -1
|
|
225
|
-
elif B == _V_ and z == 31 and lon >= 3:
|
|
226
|
-
z += 1 # SouthWestern Norway
|
|
227
|
-
|
|
228
|
-
if cmoff: # lon off central meridian
|
|
229
|
-
lon -= _cmlon(z) # z after Norway/Svalbard
|
|
230
|
-
return Zone(z), (Band(B) if B else None), Lat(lat), Lon(lon)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
def _to7zBlldfn(latlon, lon, datum, falsed, zone, strict, Error, **name_cmoff):
|
|
234
|
-
'''(INTERNAL) Determine 7-tuple (zone, band, lat, lon, datum,
|
|
235
|
-
falsed, name) for methods L{toEtm8} and L{toUtm8}.
|
|
236
|
-
'''
|
|
237
|
-
f, n = _xkwds_pop2(name_cmoff, cmoff=falsed) # DEPRECATED
|
|
238
|
-
n = _name__(**n) # _UnexpectedError
|
|
239
|
-
lat, lon, d, n = _to4lldn(latlon, lon, datum, n)
|
|
240
|
-
z, B, lat, lon = _to4zBll(lat, lon, cmoff=f, strict=strict)
|
|
241
|
-
if zone: # re-zone for ETM/UTM
|
|
242
|
-
r, _, _ = _to3zBhp(zone, B)
|
|
243
|
-
if r != z:
|
|
244
|
-
if not _UTM_ZONE_MIN <= r <= _UTM_ZONE_MAX:
|
|
245
|
-
raise Error(zone=zone)
|
|
246
|
-
if f: # re-offset from central meridian
|
|
247
|
-
lon += _cmlon(z) - _cmlon(r)
|
|
248
|
-
z = r
|
|
249
|
-
return z, B, lat, lon, d, f, n
|
|
250
|
-
|
|
251
|
-
|
|
252
136
|
class Utm(UtmUpsBase):
|
|
253
137
|
'''Universal Transverse Mercator (UTM) coordinate.
|
|
254
138
|
'''
|
|
@@ -276,10 +160,10 @@ class Utm(UtmUpsBase):
|
|
|
276
160
|
@kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}} are
|
|
277
161
|
falsed (C{bool}).
|
|
278
162
|
@kwarg gamma: Optional meridian convergence, bearing off grid North,
|
|
279
|
-
clockwise from true North (C{degrees}) or C{None}.
|
|
280
|
-
@kwarg scale: Optional grid scale factor (C{scalar}) or C{None}.
|
|
163
|
+
clockwise from true North to save (C{degrees}) or C{None}.
|
|
164
|
+
@kwarg scale: Optional grid scale factor to save (C{scalar}) or C{None}.
|
|
281
165
|
@kwarg name_convergence: Optional C{B{name}=NN} (C{str}) and DEPRECATED
|
|
282
|
-
C{B{convergence}=None},
|
|
166
|
+
keyword argument C{B{convergence}=None}, use B{C{gamma}}.
|
|
283
167
|
|
|
284
168
|
@raise TypeError: Invalid or near-spherical B{C{datum}}.
|
|
285
169
|
|
|
@@ -287,17 +171,17 @@ class Utm(UtmUpsBase):
|
|
|
287
171
|
B{C{northing}}, B{C{band}}, B{C{convergence}} or
|
|
288
172
|
B{C{scale}}.
|
|
289
173
|
'''
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
self.name = n
|
|
174
|
+
if name_convergence:
|
|
175
|
+
gamma, name = _xkwds_pop2(name_convergence, convergence=gamma)
|
|
176
|
+
if name:
|
|
177
|
+
self.name = name
|
|
295
178
|
|
|
296
179
|
self._zone, B, _ = _to3zBlat(zone, band)
|
|
297
180
|
|
|
298
181
|
h = str(hemisphere)[:1].upper()
|
|
299
182
|
if h not in _NS_:
|
|
300
183
|
raise self._Error(hemisphere=hemisphere)
|
|
184
|
+
self._hemisphere = h
|
|
301
185
|
|
|
302
186
|
e, n = easting, northing # Easting(easting), ...
|
|
303
187
|
# if not falsed:
|
|
@@ -311,9 +195,8 @@ class Utm(UtmUpsBase):
|
|
|
311
195
|
# if 0 > n or n > _FalseNorthing:
|
|
312
196
|
# raise RangeError(northing=northing)
|
|
313
197
|
|
|
314
|
-
self._hemisphere = h
|
|
315
198
|
UtmUpsBase.__init__(self, e, n, band=B, datum=datum, falsed=falsed,
|
|
316
|
-
|
|
199
|
+
gamma=gamma, scale=scale)
|
|
317
200
|
|
|
318
201
|
def __eq__(self, other):
|
|
319
202
|
return isinstance(other, Utm) and other.zone == self.zone \
|
|
@@ -378,10 +261,8 @@ class Utm(UtmUpsBase):
|
|
|
378
261
|
def parse(self, strUTM, **name):
|
|
379
262
|
'''Parse a string to a similar L{Utm} instance.
|
|
380
263
|
|
|
381
|
-
@arg strUTM: The UTM coordinate (C{str}),
|
|
382
|
-
|
|
383
|
-
@kwarg name: Optional instance name (C{str}),
|
|
384
|
-
overriding this name.
|
|
264
|
+
@arg strUTM: The UTM coordinate (C{str}), see function L{parseUTM5}.
|
|
265
|
+
@kwarg name: Optional instance name (C{str}), overriding this name.
|
|
385
266
|
|
|
386
267
|
@return: The similar instance (L{Utm}).
|
|
387
268
|
|
|
@@ -483,11 +364,12 @@ class Utm(UtmUpsBase):
|
|
|
483
364
|
# gamma and scale: Karney 2011 Eq 26, 27 and 28
|
|
484
365
|
p = neg(K.ps(-1))
|
|
485
366
|
q = K.qs(0)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
367
|
+
g = degrees(atan1(tan(y) * tanh(x)) + atan2(q, p))
|
|
368
|
+
k = hypot(p, q) * E.a / A0
|
|
369
|
+
if k:
|
|
370
|
+
k = E.e2s(sin(a)) * hypot1(T) * H / k # INF?
|
|
489
371
|
ll._iteration = i
|
|
490
|
-
self._latlon5args(ll, _toBand, unfalse, eps)
|
|
372
|
+
self._latlon5args(ll, g, k, _toBand, unfalse, eps)
|
|
491
373
|
|
|
492
374
|
def toRepr(self, prec=0, fmt=Fmt.SQUARE, sep=_COMMASPACE_, B=False, cs=False, **unused): # PYCHOK expected
|
|
493
375
|
'''Return a string representation of this UTM coordinate.
|
|
@@ -540,12 +422,13 @@ class Utm(UtmUpsBase):
|
|
|
540
422
|
(C{str}, 'N[orth]'|'S[outh]').
|
|
541
423
|
@kwarg eps: Optional convergence limit, L{EPS} or above
|
|
542
424
|
(C{float}), see method L{Utm.toLatLon}.
|
|
543
|
-
@kwarg falsed:
|
|
425
|
+
@kwarg falsed: If C{True}, false both easting and northing
|
|
426
|
+
(C{bool}).
|
|
544
427
|
|
|
545
428
|
@return: The UPS coordinate (L{Ups}).
|
|
546
429
|
'''
|
|
547
430
|
u = self._ups
|
|
548
|
-
if u is None or u.pole != (pole or u.pole) or falsed !=
|
|
431
|
+
if u is None or u.pole != (pole or u.pole) or bool(falsed) != u.falsed:
|
|
549
432
|
ll = self.toLatLon(LatLon=_LLEB, eps=eps, unfalse=True)
|
|
550
433
|
ups = _MODS.ups
|
|
551
434
|
self._ups = u = ups.toUps8(ll, Ups=ups.Ups, falsed=falsed,
|
|
@@ -558,7 +441,8 @@ class Utm(UtmUpsBase):
|
|
|
558
441
|
@arg zone: New UTM zone (C{int}).
|
|
559
442
|
@kwarg eps: Optional convergence limit, L{EPS} or above
|
|
560
443
|
(C{float}), see method L{Utm.toLatLon}.
|
|
561
|
-
@kwarg falsed:
|
|
444
|
+
@kwarg falsed: If C{True}, fFalse both easting and northing
|
|
445
|
+
(C{bool}).
|
|
562
446
|
|
|
563
447
|
@return: The UTM coordinate (L{Utm}).
|
|
564
448
|
'''
|
|
@@ -566,7 +450,7 @@ class Utm(UtmUpsBase):
|
|
|
566
450
|
return self.copy()
|
|
567
451
|
elif zone:
|
|
568
452
|
u = self._utm
|
|
569
|
-
if u is None or u.zone != zone or falsed != u.falsed:
|
|
453
|
+
if u is None or u.zone != zone or bool(falsed) != u.falsed:
|
|
570
454
|
ll = self.toLatLon(LatLon=_LLEB, eps=eps, unfalse=True)
|
|
571
455
|
self._utm = u = toUtm8(ll, Utm=self.classof, falsed=falsed,
|
|
572
456
|
name=self.name, zone=zone)
|
|
@@ -580,6 +464,24 @@ class Utm(UtmUpsBase):
|
|
|
580
464
|
return self._zone
|
|
581
465
|
|
|
582
466
|
|
|
467
|
+
def _cmlon(zone):
|
|
468
|
+
'''(INTERNAL) Central meridian longitude (C{degrees180}).
|
|
469
|
+
'''
|
|
470
|
+
return (zone * 6) - 183
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def _false2(e, n, h):
|
|
474
|
+
'''(INTERNAL) False easting and northing.
|
|
475
|
+
'''
|
|
476
|
+
# Karney, "Test data for the transverse Mercator projection (2009)"
|
|
477
|
+
# <https://GeographicLib.SourceForge.io/C++/doc/transversemercator.html>
|
|
478
|
+
# and <https://Zenodo.org/record/32470#.W4LEJS2ZON8>
|
|
479
|
+
e += _FalseEasting # make e relative to central meridian
|
|
480
|
+
if h == _S_:
|
|
481
|
+
n += _FalseNorthing # make n relative to equator
|
|
482
|
+
return e, n
|
|
483
|
+
|
|
484
|
+
|
|
583
485
|
def _parseUTM5(strUTM, datum, Xtm, falsed, Error=UTMError, **name): # imported by .etm
|
|
584
486
|
'''(INTERNAL) Parse a string representing a UTM coordinate,
|
|
585
487
|
consisting of C{"zone[band] hemisphere easting northing"},
|
|
@@ -590,7 +492,7 @@ def _parseUTM5(strUTM, datum, Xtm, falsed, Error=UTMError, **name): # imported
|
|
|
590
492
|
raise Error(strUTM=strUTM, zone=z, band=B)
|
|
591
493
|
|
|
592
494
|
return UtmUps5Tuple(z, h, e, n, B, Error=Error, **name) if Xtm is None else \
|
|
593
|
-
Xtm(z, h, e, n, band=B, datum=datum, falsed=falsed, **name)
|
|
495
|
+
Xtm(z, h, e, n, band=B, datum=datum, falsed=bool(falsed), **name)
|
|
594
496
|
|
|
595
497
|
|
|
596
498
|
def parseUTM5(strUTM, datum=_WGS84, Utm=Utm, falsed=True, **name):
|
|
@@ -602,8 +504,9 @@ def parseUTM5(strUTM, datum=_WGS84, Utm=Utm, falsed=True, **name):
|
|
|
602
504
|
L{Ellipsoid2} or L{a_f2Tuple}).
|
|
603
505
|
@kwarg Utm: Optional class to return the UTM coordinate
|
|
604
506
|
(L{Utm}) or C{None}.
|
|
605
|
-
@kwarg falsed:
|
|
606
|
-
|
|
507
|
+
@kwarg falsed: Use C{B{falsed}=True} if both easting and
|
|
508
|
+
northing are falsed (C{bool}).
|
|
509
|
+
@kwarg name: Optional B{C{Utm}} C{B{name}=NN} (C{str}).
|
|
607
510
|
|
|
608
511
|
@return: The UTM coordinate (B{C{Utm}}) or if B{C{Utm}}
|
|
609
512
|
is C{None}, a L{UtmUps5Tuple}C{(zone, hemipole,
|
|
@@ -633,10 +536,10 @@ def toUtm8(latlon, lon=None, datum=None, Utm=Utm, falsed=True,
|
|
|
633
536
|
@kwarg falsed: False both easting and northing (C{bool}).
|
|
634
537
|
@kwarg strict: Restrict B{C{lat}} to UTM ranges (C{bool}).
|
|
635
538
|
@kwarg zone: Optional UTM zone to enforce (C{int} or C{str}).
|
|
636
|
-
@kwarg name_cmoff: Optional B{C{Utm}} C{B{name}=NN} (C{str})
|
|
637
|
-
|
|
638
|
-
from the zone's central meridian (C{bool}),
|
|
639
|
-
|
|
539
|
+
@kwarg name_cmoff: Optional B{C{Utm}} C{B{name}=NN} (C{str}) and
|
|
540
|
+
DEPRECATED C{B{cmoff}=True} to offset the longitude
|
|
541
|
+
from the zone's central meridian (C{bool}), use
|
|
542
|
+
C{B{falsed}} instead.
|
|
640
543
|
|
|
641
544
|
@return: The UTM coordinate (B{C{Utm}}) or if B{C{Utm}} is
|
|
642
545
|
C{None} or not B{C{falsed}}, a L{UtmUps8Tuple}C{(zone,
|
|
@@ -695,8 +598,22 @@ def toUtm8(latlon, lon=None, datum=None, Utm=Utm, falsed=True,
|
|
|
695
598
|
B, d, g, k, f, n, latlon, EPS)
|
|
696
599
|
|
|
697
600
|
|
|
601
|
+
def _toBand(lat, *unused, **strict_Error): # see ups._toBand
|
|
602
|
+
'''(INTERNAL) Get the I{latitudinal} Band (row) letter.
|
|
603
|
+
'''
|
|
604
|
+
if _UTM_LAT_MIN <= lat < _UTM_LAT_MAX: # [-80, 84) like Veness
|
|
605
|
+
return _Bands[int(lat - _UTM_LAT_MIN) >> 3]
|
|
606
|
+
elif _xkwds_get(strict_Error, strict=True):
|
|
607
|
+
r = _range_(_UTM_LAT_MIN, _UTM_LAT_MAX, ropen=True)
|
|
608
|
+
t = _SPACE_(_outside_, _UTM_, _range_, r)
|
|
609
|
+
E = _xkwds_get(strict_Error, Error=RangeError)
|
|
610
|
+
raise E(lat=degDMS(lat), txt=t)
|
|
611
|
+
else:
|
|
612
|
+
return NN # None
|
|
613
|
+
|
|
614
|
+
|
|
698
615
|
def _toXtm8(Xtm, z, lat, x, y, B, d, g, k, f, # PYCHOK 13+ args
|
|
699
|
-
n, latlon,
|
|
616
|
+
n, latlon, eps_other, Error=UTMError):
|
|
700
617
|
'''(INTERNAL) Helper for methods L{toEtm8} and L{toUtm8}.
|
|
701
618
|
'''
|
|
702
619
|
h = _hemi(lat)
|
|
@@ -708,27 +625,106 @@ def _toXtm8(Xtm, z, lat, x, y, B, d, g, k, f, # PYCHOK 13+ args
|
|
|
708
625
|
r = Xtm(z, h, x, y, band=B, datum=d, falsed=f,
|
|
709
626
|
gamma=g, scale=k, name=n)
|
|
710
627
|
if isinstance(latlon, _LLEB) and d is latlon.datum: # see ups.toUtm8
|
|
711
|
-
r._latlon5args(latlon, _toBand, f,
|
|
712
|
-
latlon._gamma = g
|
|
713
|
-
latlon._scale = k
|
|
628
|
+
r._latlon5args(latlon, g, k, _toBand, f, eps_other) # XXX weakref(latlon)?
|
|
714
629
|
elif not r._band:
|
|
715
630
|
r._band = _toBand(lat)
|
|
716
631
|
return r
|
|
717
632
|
|
|
718
633
|
|
|
634
|
+
def _to3zBlat(zone, band, Error=UTMError): # in .mgrs
|
|
635
|
+
'''(INTERNAL) Check and return zone, Band and band latitude.
|
|
636
|
+
|
|
637
|
+
@arg zone: Zone number or string.
|
|
638
|
+
@arg band: Band letter.
|
|
639
|
+
@arg Error: Exception to raise (L{UTMError}).
|
|
640
|
+
|
|
641
|
+
@return: 3-Tuple (zone, Band, latitude).
|
|
642
|
+
'''
|
|
643
|
+
z, B, _ = _to3zBhp(zone, band, Error=Error)
|
|
644
|
+
if not (_UTM_ZONE_MIN <= z <= _UTM_ZONE_MAX or
|
|
645
|
+
(_UPS_ZONE == z and Error is MGRSError)):
|
|
646
|
+
raise Error(zone=zone)
|
|
647
|
+
|
|
648
|
+
b = None
|
|
649
|
+
if B:
|
|
650
|
+
if z == _UPS_ZONE: # polar
|
|
651
|
+
try:
|
|
652
|
+
b = Lat(_UPS_LATS[B], name=_bandLat_)
|
|
653
|
+
except KeyError:
|
|
654
|
+
raise Error(band=band or B, zone=z)
|
|
655
|
+
else: # UTM
|
|
656
|
+
b = _Bands.find(B)
|
|
657
|
+
if b < 0:
|
|
658
|
+
raise Error(band=band or B, zone=z)
|
|
659
|
+
b = Int((b << 3) - 80, name=_bandLat_)
|
|
660
|
+
B = Band(B)
|
|
661
|
+
elif Error is not UTMError:
|
|
662
|
+
raise Error(band=band, txt=MISSING)
|
|
663
|
+
|
|
664
|
+
return Zone(z), B, b
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def _to4zBll(lat, lon, cmoff=True, strict=True, Error=RangeError):
|
|
668
|
+
'''(INTERNAL) Return zone, Band and lat- and (central) longitude in degrees.
|
|
669
|
+
|
|
670
|
+
@arg lat: Latitude (C{degrees}).
|
|
671
|
+
@arg lon: Longitude (C{degrees}).
|
|
672
|
+
@kwarg cmoff: If C{True}, offset B{C{lon}} from the zone's central meridian.
|
|
673
|
+
@kwarg strict: Restrict B{C{lat}} to the UTM ranges (C{bool}).
|
|
674
|
+
@kwarg Error: Error for out of UTM range B{C{lat}}s.
|
|
675
|
+
|
|
676
|
+
@return: 4-Tuple (zone, Band, lat, lon).
|
|
677
|
+
'''
|
|
678
|
+
z, lat, lon = _to3zll(lat, lon) # in .utmupsBase
|
|
679
|
+
|
|
680
|
+
x = lon - _cmlon(z) # z before Norway/Svalbard
|
|
681
|
+
if fabs(x) > _UTM_ZONE_OFF_MAX:
|
|
682
|
+
t = _SPACE_(_outside_, _UTM_, _zone_, str(z), _by_, degDMS(x, prec=6))
|
|
683
|
+
raise Error(lon=degDMS(lon), txt=t)
|
|
684
|
+
|
|
685
|
+
B = _toBand(lat, strict=strict, Error=Error)
|
|
686
|
+
if B == _X_: # and 0 <= lon < 42: z = int(lon + 183) // 6 + 1
|
|
687
|
+
x = _SvalbardXzone.get(z, None)
|
|
688
|
+
if x: # Svalbard/Spitsbergen archipelago
|
|
689
|
+
z += 1 if lon >= x else -1
|
|
690
|
+
elif B == _V_ and z == 31 and lon >= 3:
|
|
691
|
+
z += 1 # SouthWestern Norway
|
|
692
|
+
|
|
693
|
+
if cmoff: # lon off central meridian
|
|
694
|
+
lon -= _cmlon(z) # z I{after} Norway/Svalbard
|
|
695
|
+
return Zone(z), (Band(B) if B else None), Lat(lat), Lon(lon)
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
def _to7zBlldfn(latlon, lon, datum, falsed, zone, strict, Error, **name_cmoff):
|
|
699
|
+
'''(INTERNAL) Determine 7-tuple (zone, band, lat, lon, datum,
|
|
700
|
+
falsed, name) for methods L{toEtm8} and L{toUtm8}.
|
|
701
|
+
'''
|
|
702
|
+
f, name = _xkwds_pop2(name_cmoff, cmoff=falsed) # DEPRECATED
|
|
703
|
+
lat, lon, d, n = _to4lldn(latlon, lon, datum, name)
|
|
704
|
+
z, B, lat, lon = _to4zBll(lat, lon, cmoff=f, strict=strict)
|
|
705
|
+
if zone: # re-zone for ETM/UTM
|
|
706
|
+
r, _, _ = _to3zBhp(zone, B)
|
|
707
|
+
if r != z:
|
|
708
|
+
if not _UTM_ZONE_MIN <= r <= _UTM_ZONE_MAX:
|
|
709
|
+
raise Error(zone=zone)
|
|
710
|
+
if f: # re-offset from central meridian
|
|
711
|
+
lon += _cmlon(z) - _cmlon(r)
|
|
712
|
+
z = r
|
|
713
|
+
return z, B, lat, lon, d, f, n
|
|
714
|
+
|
|
715
|
+
|
|
719
716
|
def utmZoneBand5(lat, lon, cmoff=False, **name):
|
|
720
717
|
'''Return the UTM zone number, Band letter, hemisphere and
|
|
721
718
|
(clipped) lat- and longitude for a given location.
|
|
722
719
|
|
|
723
720
|
@arg lat: Latitude in degrees (C{scalar} or C{str}).
|
|
724
721
|
@arg lon: Longitude in degrees (C{scalar} or C{str}).
|
|
725
|
-
@kwarg cmoff:
|
|
722
|
+
@kwarg cmoff: If C{True}, offset longitude from the zone's central
|
|
726
723
|
meridian (C{bool}).
|
|
727
|
-
@kwarg name: Optional name (C{str}).
|
|
724
|
+
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
728
725
|
|
|
729
|
-
@return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole,
|
|
730
|
-
|
|
731
|
-
UTM hemisphere.
|
|
726
|
+
@return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole, lat, lon)}
|
|
727
|
+
where C{hemipole} is the C{'N'|'S'} UTM hemisphere.
|
|
732
728
|
|
|
733
729
|
@raise RangeError: If B{C{lat}} outside the valid UTM bands or if
|
|
734
730
|
B{C{lat}} or B{C{lon}} outside the valid range
|
pygeodesy/utmups.py
CHANGED
|
@@ -16,7 +16,7 @@ by I{Charles Karney}.
|
|
|
16
16
|
'''
|
|
17
17
|
# from pygeodesy.basics import map1 # from .namedTuples
|
|
18
18
|
# from pygeodesy.datums import _WGS84 # from .utmupsBase
|
|
19
|
-
from pygeodesy.errors import _IsnotError, RangeError, _ValueError,
|
|
19
|
+
from pygeodesy.errors import _IsnotError, RangeError, _ValueError, _xkwds_pop2
|
|
20
20
|
from pygeodesy.interns import NN, _easting_, _MGRS_, _northing_, _NS_, \
|
|
21
21
|
_outside_, _range_, _SPACE_, _UPS_, _UTM_
|
|
22
22
|
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
|
|
@@ -31,7 +31,7 @@ from pygeodesy.utmupsBase import Fmt, _to4lldn, _to3zBhp, _UPS_ZONE, \
|
|
|
31
31
|
_UTMUPS_ZONE_MAX, _WGS84
|
|
32
32
|
|
|
33
33
|
__all__ = _ALL_LAZY.utmups
|
|
34
|
-
__version__ = '
|
|
34
|
+
__version__ = '24.05.30'
|
|
35
35
|
|
|
36
36
|
_MGRS_TILE = _100km # in .mgrs.Mgrs.tile
|
|
37
37
|
|
|
@@ -73,7 +73,7 @@ class UTMUPSError(_ValueError): # XXX (UTMError, UPSError)
|
|
|
73
73
|
pass
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
def parseUTMUPS5(strUTMUPS, datum=_WGS84, Utm=Utm, Ups=Ups, name
|
|
76
|
+
def parseUTMUPS5(strUTMUPS, datum=_WGS84, Utm=Utm, Ups=Ups, **name):
|
|
77
77
|
'''Parse a string representing a UTM or UPS coordinate, consisting
|
|
78
78
|
of C{"zone[band] hemisphere/pole easting northing"}.
|
|
79
79
|
|
|
@@ -83,13 +83,13 @@ def parseUTMUPS5(strUTMUPS, datum=_WGS84, Utm=Utm, Ups=Ups, name=NN):
|
|
|
83
83
|
or C{None}.
|
|
84
84
|
@kwarg Ups: Optional class to return the UPS coordinate (L{Ups})
|
|
85
85
|
or C{None}.
|
|
86
|
-
@kwarg name: Optional
|
|
86
|
+
@kwarg name: Optional B{C{Utm}} or B{C{Ups}} C{B{name}=NN} (C{str}).
|
|
87
87
|
|
|
88
|
-
@return: The UTM or UPS instance (B{C{Utm}} or B{C{Ups}}) or
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
@return: The UTM or UPS instance (B{C{Utm}} or B{C{Ups}}) or a
|
|
89
|
+
L{UtmUps5Tuple}C{(zone, hemipole, easting, northing, band)}
|
|
90
|
+
if B{C{Utm}} respectively B{C{Ups}} or both are C{None}.
|
|
91
|
+
The C{hemipole} is C{'N'|'S'}, the UTM hemisphere or UPS
|
|
92
|
+
pole, the UPS projection top/center.
|
|
93
93
|
|
|
94
94
|
@raise UTMUPSError: Invalid B{C{strUTMUPS}}.
|
|
95
95
|
|
|
@@ -100,14 +100,13 @@ def parseUTMUPS5(strUTMUPS, datum=_WGS84, Utm=Utm, Ups=Ups, name=NN):
|
|
|
100
100
|
u = parseUTM5(strUTMUPS, datum=datum, Utm=Utm, name=name)
|
|
101
101
|
except UTMError:
|
|
102
102
|
u = parseUPS5(strUTMUPS, datum=datum, Ups=Ups, name=name)
|
|
103
|
-
return u
|
|
104
|
-
|
|
105
103
|
except (UTMError, UPSError) as x:
|
|
106
104
|
raise UTMUPSError(strUTMUPS=strUTMUPS, cause=x)
|
|
105
|
+
return u
|
|
107
106
|
|
|
108
107
|
|
|
109
108
|
def toUtmUps8(latlon, lon=None, datum=None, falsed=True, Utm=Utm, Ups=Ups,
|
|
110
|
-
|
|
109
|
+
pole=NN, **name_cmoff):
|
|
111
110
|
'''Convert a lat-/longitude point to a UTM or UPS coordinate.
|
|
112
111
|
|
|
113
112
|
@arg latlon: Latitude (C{degrees}) or an (ellipsoidal)
|
|
@@ -122,9 +121,10 @@ def toUtmUps8(latlon, lon=None, datum=None, falsed=True, Utm=Utm, Ups=Ups,
|
|
|
122
121
|
or C{None}.
|
|
123
122
|
@kwarg pole: Optional top/center of UPS (stereographic)
|
|
124
123
|
projection (C{str}, C{'N[orth]'} or C{'S[outh]'}).
|
|
125
|
-
@kwarg
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
@kwarg name_cmoff: Optional B{C{Utm}} or B{C{Ups}} C{B{name}=NN}
|
|
125
|
+
(C{str}) and DEPRECATED keyword argument C{B{cmoff}=True}
|
|
126
|
+
to offset the longitude from the zone's central meridian
|
|
127
|
+
(C{bool}), use B{C{falsed}} instead and I{for UTM only}.
|
|
128
128
|
|
|
129
129
|
@return: The UTM or UPS coordinate (B{C{Utm}} respectively B{C{Ups}})
|
|
130
130
|
or a L{UtmUps8Tuple}C{(zone, hemipole, easting, northing,
|
|
@@ -144,19 +144,18 @@ def toUtmUps8(latlon, lon=None, datum=None, falsed=True, Utm=Utm, Ups=Ups,
|
|
|
144
144
|
|
|
145
145
|
@see: Functions L{pygeodesy.toUtm8} and L{pygeodesy.toUps8}.
|
|
146
146
|
'''
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
f = falsed and _xkwds_get(cmoff, cmoff=True)
|
|
147
|
+
f, name = _xkwds_pop2(name_cmoff, cmoff=falsed)
|
|
148
|
+
lat, lon, d, n = _to4lldn(latlon, lon, datum, name)
|
|
149
|
+
z, _, p, lat, lon = utmupsZoneBand5(lat, lon)
|
|
151
150
|
if z == _UPS_ZONE:
|
|
152
|
-
u = toUps8(lat, lon, datum=d, falsed=f, Ups=Ups, name=
|
|
151
|
+
u = toUps8(lat, lon, datum=d, falsed=f, Ups=Ups, name=n, pole=pole or p)
|
|
153
152
|
else:
|
|
154
|
-
u = toUtm8(lat, lon, datum=d, falsed=f, Utm=Utm, name=
|
|
153
|
+
u = toUtm8(lat, lon, datum=d, falsed=f, Utm=Utm, name=n)
|
|
155
154
|
return u
|
|
156
155
|
|
|
157
156
|
|
|
158
157
|
def UtmUps(zone, hemipole, easting, northing, band=NN, datum=_WGS84,
|
|
159
|
-
falsed=True, name
|
|
158
|
+
falsed=True, **name):
|
|
160
159
|
'''Class-like function to create a UTM/UPS coordinate.
|
|
161
160
|
|
|
162
161
|
@kwarg zone: The UTM zone with/-out I{longitudinal} Band or UPS zone C{0}
|
|
@@ -167,9 +166,10 @@ def UtmUps(zone, hemipole, easting, northing, band=NN, datum=_WGS84,
|
|
|
167
166
|
@arg northing: Northing, see B{C{falsed}} (C{meter}).
|
|
168
167
|
@kwarg band: Optional, UTM I{latitudinal} C{'C'|'D'|..|'W'|'X'} or UPS
|
|
169
168
|
I{polar} Band letter C{'A'|'B'|'Y'|'Z'} Band letter (C{str}).
|
|
170
|
-
@kwarg datum:
|
|
171
|
-
@kwarg falsed:
|
|
172
|
-
|
|
169
|
+
@kwarg datum: The coordinate's datum (L{Datum}).
|
|
170
|
+
@kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}} are
|
|
171
|
+
falsed (C{bool}).
|
|
172
|
+
@kwarg name: Optional L{Utm} or L{Ups} C{B{name}=NN} (C{str}).
|
|
173
173
|
|
|
174
174
|
@return: New UTM or UPS instance (L{Utm} or L{Ups}).
|
|
175
175
|
|
|
@@ -183,7 +183,7 @@ def UtmUps(zone, hemipole, easting, northing, band=NN, datum=_WGS84,
|
|
|
183
183
|
z, B, hp = _to3zBhp(zone, band, hemipole=hemipole)
|
|
184
184
|
U = Ups if z in (_UPS_ZONE, _UPS_ZONE_STR) else Utm
|
|
185
185
|
return U(z, hp, easting, northing, band=B, datum=datum,
|
|
186
|
-
falsed=falsed, name
|
|
186
|
+
falsed=falsed, **name)
|
|
187
187
|
|
|
188
188
|
|
|
189
189
|
def utmupsValidate(coord, falsed=False, MGRS=False, Error=UTMUPSError):
|
|
@@ -253,10 +253,11 @@ def utmupsValidateOK(coord, falsed=False, ok=True):
|
|
|
253
253
|
'''Check a UTM or UPS coordinate.
|
|
254
254
|
|
|
255
255
|
@arg coord: The UTM or UPS coordinate (L{Utm}, L{Ups} or C{5+Tuple}).
|
|
256
|
-
@kwarg falsed: C{5+Tuple} easting and
|
|
256
|
+
@kwarg falsed: Use C{B{falsed}=True} if the C{5+Tuple} easting and
|
|
257
|
+
northing are falsed (C{bool}).
|
|
257
258
|
@kwarg ok: Result to return if validation passed (B{C{ok}}).
|
|
258
259
|
|
|
259
|
-
@return: B{C{ok}} if validation passed, the L{UTMUPSError}
|
|
260
|
+
@return: B{C{ok}} if validation passed, otherwise the L{UTMUPSError}.
|
|
260
261
|
|
|
261
262
|
@see: Function L{utmupsValidate}.
|
|
262
263
|
'''
|
|
@@ -267,20 +268,19 @@ def utmupsValidateOK(coord, falsed=False, ok=True):
|
|
|
267
268
|
return x
|
|
268
269
|
|
|
269
270
|
|
|
270
|
-
def utmupsZoneBand5(lat, lon, cmoff=False, name
|
|
271
|
+
def utmupsZoneBand5(lat, lon, cmoff=False, **name):
|
|
271
272
|
'''Return the UTM/UPS zone number, Band letter, hemisphere/pole
|
|
272
273
|
and clipped lat- and longitude for a given location.
|
|
273
274
|
|
|
274
275
|
@arg lat: Latitude in degrees (C{scalar} or C{str}).
|
|
275
276
|
@arg lon: Longitude in degrees (C{scalar} or C{str}).
|
|
276
|
-
@kwarg cmoff:
|
|
277
|
-
meridian, for UTM only (C{bool}).
|
|
278
|
-
@kwarg name: Optional name (C{str}).
|
|
277
|
+
@kwarg cmoff: If C{True}, offset longitude from the zone's central
|
|
278
|
+
meridian, I{for UTM only} (C{bool}).
|
|
279
|
+
@kwarg name: Optional C{B{name}=NN} (C{str}).
|
|
279
280
|
|
|
280
|
-
@return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
top/center.
|
|
281
|
+
@return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole, lat, lon)}
|
|
282
|
+
where C{hemipole} is C{'N'|'S'}, the UTM hemisphere or UPS
|
|
283
|
+
pole, the UPS projection top/center.
|
|
284
284
|
|
|
285
285
|
@raise RangeError: If B{C{lat}} outside the valid UTM or UPS bands
|
|
286
286
|
or if B{C{lat}} or B{C{lon}} outside the valid
|
|
@@ -291,9 +291,9 @@ def utmupsZoneBand5(lat, lon, cmoff=False, name=NN):
|
|
|
291
291
|
@see: Functions L{pygeodesy.utmZoneBand5} and L{pygeodesy.upsZoneBand5}.
|
|
292
292
|
'''
|
|
293
293
|
try:
|
|
294
|
-
return utmZoneBand5(lat, lon, cmoff=cmoff, name
|
|
294
|
+
return utmZoneBand5(lat, lon, cmoff=cmoff, **name)
|
|
295
295
|
except RangeError:
|
|
296
|
-
return upsZoneBand5(lat, lon, name
|
|
296
|
+
return upsZoneBand5(lat, lon, **name)
|
|
297
297
|
|
|
298
298
|
# **) MIT License
|
|
299
299
|
#
|