pygeodesy 24.5.15__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.15.dist-info → PyGeodesy-24.6.1.dist-info}/METADATA +6 -5
- PyGeodesy-24.6.1.dist-info/RECORD +116 -0
- pygeodesy/__init__.py +4 -4
- pygeodesy/albers.py +41 -41
- pygeodesy/auxilats/__init__.py +1 -1
- pygeodesy/auxilats/__main__.py +2 -2
- pygeodesy/auxilats/auxAngle.py +32 -31
- pygeodesy/auxilats/auxLat.py +80 -51
- pygeodesy/azimuthal.py +123 -124
- pygeodesy/basics.py +46 -10
- pygeodesy/booleans.py +13 -14
- pygeodesy/cartesianBase.py +25 -23
- pygeodesy/clipy.py +3 -3
- pygeodesy/constants.py +3 -3
- pygeodesy/css.py +50 -42
- pygeodesy/datums.py +42 -41
- pygeodesy/deprecated/functions.py +9 -3
- pygeodesy/dms.py +6 -6
- pygeodesy/ecef.py +41 -41
- pygeodesy/ellipsoidalBase.py +41 -41
- pygeodesy/ellipsoidalBaseDI.py +3 -4
- pygeodesy/ellipsoidalGeodSolve.py +2 -2
- pygeodesy/ellipsoidalKarney.py +3 -3
- pygeodesy/ellipsoidalNvector.py +11 -12
- pygeodesy/ellipsoids.py +45 -38
- pygeodesy/elliptic.py +3 -4
- pygeodesy/epsg.py +4 -3
- pygeodesy/errors.py +52 -20
- pygeodesy/etm.py +68 -65
- pygeodesy/fmath.py +44 -49
- pygeodesy/formy.py +129 -115
- pygeodesy/frechet.py +118 -103
- pygeodesy/fstats.py +21 -14
- pygeodesy/fsums.py +124 -80
- pygeodesy/gars.py +10 -9
- pygeodesy/geodesicw.py +19 -17
- pygeodesy/geodesicx/__init__.py +1 -1
- pygeodesy/geodesicx/__main__.py +2 -2
- pygeodesy/geodesicx/gx.py +39 -33
- pygeodesy/geodesicx/gxarea.py +12 -9
- pygeodesy/geodesicx/gxbases.py +3 -4
- pygeodesy/geodesicx/gxline.py +6 -8
- pygeodesy/geodsolve.py +29 -28
- pygeodesy/geohash.py +60 -57
- pygeodesy/geoids.py +34 -32
- pygeodesy/hausdorff.py +114 -101
- pygeodesy/heights.py +137 -130
- pygeodesy/internals.py +16 -11
- pygeodesy/interns.py +3 -6
- pygeodesy/iters.py +19 -17
- pygeodesy/karney.py +21 -17
- pygeodesy/ktm.py +25 -18
- pygeodesy/latlonBase.py +12 -11
- pygeodesy/lazily.py +6 -6
- pygeodesy/lcc.py +24 -25
- pygeodesy/ltp.py +143 -113
- pygeodesy/ltpTuples.py +207 -150
- pygeodesy/mgrs.py +26 -26
- pygeodesy/named.py +172 -90
- pygeodesy/namedTuples.py +33 -25
- pygeodesy/nvectorBase.py +8 -8
- pygeodesy/osgr.py +40 -48
- pygeodesy/points.py +18 -18
- pygeodesy/props.py +29 -16
- pygeodesy/rhumb/__init__.py +1 -1
- 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 +18 -18
- pygeodesy/sphericalBase.py +17 -21
- pygeodesy/sphericalTrigonometry.py +21 -21
- pygeodesy/streprs.py +5 -5
- pygeodesy/trf.py +13 -11
- pygeodesy/triaxials.py +68 -64
- pygeodesy/units.py +35 -35
- pygeodesy/unitsBase.py +24 -11
- pygeodesy/ups.py +66 -70
- pygeodesy/utily.py +3 -3
- pygeodesy/utm.py +183 -187
- pygeodesy/utmups.py +38 -38
- pygeodesy/utmupsBase.py +104 -106
- pygeodesy/vector2d.py +6 -7
- pygeodesy/vector3d.py +16 -17
- pygeodesy/vector3dBase.py +4 -5
- pygeodesy/webmercator.py +43 -51
- PyGeodesy-24.5.15.dist-info/RECORD +0 -116
- {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/WHEEL +0 -0
- {PyGeodesy-24.5.15.dist-info → PyGeodesy-24.6.1.dist-info}/top_level.txt +0 -0
pygeodesy/utm.py
CHANGED
|
@@ -35,17 +35,16 @@ and Henrik Seidel U{'Die Mathematik der Gauß-Krueger-Abbildung'
|
|
|
35
35
|
|
|
36
36
|
from pygeodesy.basics import len2, map2, neg # splice
|
|
37
37
|
from pygeodesy.constants import EPS, EPS0, _K0_UTM, _0_0, _0_0001
|
|
38
|
-
from pygeodesy.datums import _ellipsoidal_datum, _WGS84
|
|
38
|
+
from pygeodesy.datums import _ellipsoidal_datum, _WGS84, _under
|
|
39
39
|
from pygeodesy.dms import degDMS, parseDMS2
|
|
40
40
|
from pygeodesy.errors import MGRSError, RangeError, _ValueError, \
|
|
41
|
-
_xkwds_get
|
|
41
|
+
_xkwds_get, _xkwds_pop2
|
|
42
42
|
from pygeodesy.fmath import fdot3, hypot, hypot1, _operator
|
|
43
|
-
# from pygeodesy.internals import _under # from .
|
|
43
|
+
# from pygeodesy.internals import _under # from .datums
|
|
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
47
|
from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS
|
|
48
|
-
# from pygeodesy.named import _xnamed # from .utmupsBase
|
|
49
48
|
from pygeodesy.namedTuples import EasNor2Tuple, UtmUps5Tuple, \
|
|
50
49
|
UtmUps8Tuple, UtmUpsLatLon5Tuple
|
|
51
50
|
from pygeodesy.props import deprecated_method, property_doc_, \
|
|
@@ -55,8 +54,8 @@ from pygeodesy.units import Band, Int, Lat, Lon, Meter, Zone
|
|
|
55
54
|
from pygeodesy.utily import atan1, degrees90, degrees180, sincos2
|
|
56
55
|
from pygeodesy.utmupsBase import _hemi, _LLEB, _parseUTMUPS5, _to4lldn, \
|
|
57
56
|
_to3zBhp, _to3zll, _UPS_LATS, _UPS_ZONE, \
|
|
58
|
-
_UTM_LAT_MAX, _UTM_ZONE_MAX,
|
|
59
|
-
_UTM_LAT_MIN, _UTM_ZONE_MIN,
|
|
57
|
+
_UTM_LAT_MAX, _UTM_ZONE_MAX, \
|
|
58
|
+
_UTM_LAT_MIN, _UTM_ZONE_MIN, \
|
|
60
59
|
_UTM_ZONE_OFF_MAX, UtmUpsBase
|
|
61
60
|
|
|
62
61
|
from math import asinh, atanh, atan2, cos, cosh, degrees, fabs, \
|
|
@@ -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.
|
|
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,120 +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, name, zone, strict, Error, **cmoff):
|
|
234
|
-
'''(INTERNAL) Determine 7-tuple (zone, band, lat, lon, datum,
|
|
235
|
-
falsed, name) for methods L{toEtm8} and L{toUtm8}.
|
|
236
|
-
'''
|
|
237
|
-
f = falsed and _xkwds_get(cmoff, cmoff=True) # DEPRECATED
|
|
238
|
-
lat, lon, d, name = _to4lldn(latlon, lon, datum, name)
|
|
239
|
-
z, B, lat, lon = _to4zBll(lat, lon, cmoff=f, strict=strict)
|
|
240
|
-
if zone: # re-zone for ETM/UTM
|
|
241
|
-
r, _, _ = _to3zBhp(zone, B)
|
|
242
|
-
if r != z:
|
|
243
|
-
if not _UTM_ZONE_MIN <= r <= _UTM_ZONE_MAX:
|
|
244
|
-
raise Error(zone=zone)
|
|
245
|
-
if f: # re-offset from central meridian
|
|
246
|
-
lon += _cmlon(z) - _cmlon(r)
|
|
247
|
-
z = r
|
|
248
|
-
return z, B, lat, lon, d, f, name
|
|
249
|
-
|
|
250
|
-
|
|
251
136
|
class Utm(UtmUpsBase):
|
|
252
137
|
'''Universal Transverse Mercator (UTM) coordinate.
|
|
253
138
|
'''
|
|
@@ -260,7 +145,7 @@ class Utm(UtmUpsBase):
|
|
|
260
145
|
|
|
261
146
|
def __init__(self, zone=31, hemisphere=_N_, easting=166022, # PYCHOK expected
|
|
262
147
|
northing=0, band=NN, datum=_WGS84, falsed=True,
|
|
263
|
-
gamma=None, scale=None,
|
|
148
|
+
gamma=None, scale=None, **name_convergence):
|
|
264
149
|
'''New L{Utm} UTM coordinate.
|
|
265
150
|
|
|
266
151
|
@kwarg zone: Longitudinal UTM zone (C{int}, 1..60) or zone with/-out
|
|
@@ -275,10 +160,10 @@ class Utm(UtmUpsBase):
|
|
|
275
160
|
@kwarg falsed: If C{True}, both B{C{easting}} and B{C{northing}} are
|
|
276
161
|
falsed (C{bool}).
|
|
277
162
|
@kwarg gamma: Optional meridian convergence, bearing off grid North,
|
|
278
|
-
clockwise from true North (C{degrees}) or C{None}.
|
|
279
|
-
@kwarg scale: Optional grid scale factor (C{scalar}) or C{None}.
|
|
280
|
-
@kwarg
|
|
281
|
-
|
|
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}.
|
|
165
|
+
@kwarg name_convergence: Optional C{B{name}=NN} (C{str}) and DEPRECATED
|
|
166
|
+
keyword argument C{B{convergence}=None}, use B{C{gamma}}.
|
|
282
167
|
|
|
283
168
|
@raise TypeError: Invalid or near-spherical B{C{datum}}.
|
|
284
169
|
|
|
@@ -286,14 +171,17 @@ class Utm(UtmUpsBase):
|
|
|
286
171
|
B{C{northing}}, B{C{band}}, B{C{convergence}} or
|
|
287
172
|
B{C{scale}}.
|
|
288
173
|
'''
|
|
289
|
-
if
|
|
290
|
-
|
|
174
|
+
if name_convergence:
|
|
175
|
+
gamma, name = _xkwds_pop2(name_convergence, convergence=gamma)
|
|
176
|
+
if name:
|
|
177
|
+
self.name = name
|
|
291
178
|
|
|
292
179
|
self._zone, B, _ = _to3zBlat(zone, band)
|
|
293
180
|
|
|
294
181
|
h = str(hemisphere)[:1].upper()
|
|
295
182
|
if h not in _NS_:
|
|
296
183
|
raise self._Error(hemisphere=hemisphere)
|
|
184
|
+
self._hemisphere = h
|
|
297
185
|
|
|
298
186
|
e, n = easting, northing # Easting(easting), ...
|
|
299
187
|
# if not falsed:
|
|
@@ -307,9 +195,8 @@ class Utm(UtmUpsBase):
|
|
|
307
195
|
# if 0 > n or n > _FalseNorthing:
|
|
308
196
|
# raise RangeError(northing=northing)
|
|
309
197
|
|
|
310
|
-
self._hemisphere = h
|
|
311
198
|
UtmUpsBase.__init__(self, e, n, band=B, datum=datum, falsed=falsed,
|
|
312
|
-
|
|
199
|
+
gamma=gamma, scale=scale)
|
|
313
200
|
|
|
314
201
|
def __eq__(self, other):
|
|
315
202
|
return isinstance(other, Utm) and other.zone == self.zone \
|
|
@@ -325,7 +212,7 @@ class Utm(UtmUpsBase):
|
|
|
325
212
|
def __str__(self):
|
|
326
213
|
return self.toStr()
|
|
327
214
|
|
|
328
|
-
def _xcopy2(self, Xtm, name
|
|
215
|
+
def _xcopy2(self, Xtm, **name):
|
|
329
216
|
'''(INTERNAL) Make copy as an B{C{Xtm}} instance.
|
|
330
217
|
|
|
331
218
|
@arg Xtm: Class to return the copy (C{Xtm=Etm}, C{Xtm=Utm} or
|
|
@@ -333,7 +220,7 @@ class Utm(UtmUpsBase):
|
|
|
333
220
|
'''
|
|
334
221
|
return Xtm(self.zone, self.hemisphere, self.easting, self.northing,
|
|
335
222
|
band=self.band, datum=self.datum, falsed=self.falsed,
|
|
336
|
-
gamma=self.gamma, scale=self.scale, name=
|
|
223
|
+
gamma=self.gamma, scale=self.scale, name=self._name__(name))
|
|
337
224
|
|
|
338
225
|
@property_doc_(''' the I{latitudinal} band.''')
|
|
339
226
|
def band(self):
|
|
@@ -371,13 +258,11 @@ class Utm(UtmUpsBase):
|
|
|
371
258
|
n = _FalseNorthing
|
|
372
259
|
return EasNor2Tuple(e, n)
|
|
373
260
|
|
|
374
|
-
def parse(self, strUTM, name
|
|
261
|
+
def parse(self, strUTM, **name):
|
|
375
262
|
'''Parse a string to a similar L{Utm} instance.
|
|
376
263
|
|
|
377
|
-
@arg strUTM: The UTM coordinate (C{str}),
|
|
378
|
-
|
|
379
|
-
@kwarg name: Optional instance name (C{str}),
|
|
380
|
-
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.
|
|
381
266
|
|
|
382
267
|
@return: The similar instance (L{Utm}).
|
|
383
268
|
|
|
@@ -386,7 +271,7 @@ class Utm(UtmUpsBase):
|
|
|
386
271
|
@see: Functions L{pygeodesy.parseUPS5} and L{pygeodesy.parseUTMUPS5}.
|
|
387
272
|
'''
|
|
388
273
|
return parseUTM5(strUTM, datum=self.datum, Utm=self.classof,
|
|
389
|
-
name=
|
|
274
|
+
name=self._name__(name))
|
|
390
275
|
|
|
391
276
|
@deprecated_method
|
|
392
277
|
def parseUTM(self, strUTM): # PYCHOK no cover
|
|
@@ -479,11 +364,12 @@ class Utm(UtmUpsBase):
|
|
|
479
364
|
# gamma and scale: Karney 2011 Eq 26, 27 and 28
|
|
480
365
|
p = neg(K.ps(-1))
|
|
481
366
|
q = K.qs(0)
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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?
|
|
485
371
|
ll._iteration = i
|
|
486
|
-
self._latlon5args(ll, _toBand, unfalse, eps)
|
|
372
|
+
self._latlon5args(ll, g, k, _toBand, unfalse, eps)
|
|
487
373
|
|
|
488
374
|
def toRepr(self, prec=0, fmt=Fmt.SQUARE, sep=_COMMASPACE_, B=False, cs=False, **unused): # PYCHOK expected
|
|
489
375
|
'''Return a string representation of this UTM coordinate.
|
|
@@ -536,12 +422,13 @@ class Utm(UtmUpsBase):
|
|
|
536
422
|
(C{str}, 'N[orth]'|'S[outh]').
|
|
537
423
|
@kwarg eps: Optional convergence limit, L{EPS} or above
|
|
538
424
|
(C{float}), see method L{Utm.toLatLon}.
|
|
539
|
-
@kwarg falsed:
|
|
425
|
+
@kwarg falsed: If C{True}, false both easting and northing
|
|
426
|
+
(C{bool}).
|
|
540
427
|
|
|
541
428
|
@return: The UPS coordinate (L{Ups}).
|
|
542
429
|
'''
|
|
543
430
|
u = self._ups
|
|
544
|
-
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:
|
|
545
432
|
ll = self.toLatLon(LatLon=_LLEB, eps=eps, unfalse=True)
|
|
546
433
|
ups = _MODS.ups
|
|
547
434
|
self._ups = u = ups.toUps8(ll, Ups=ups.Ups, falsed=falsed,
|
|
@@ -554,7 +441,8 @@ class Utm(UtmUpsBase):
|
|
|
554
441
|
@arg zone: New UTM zone (C{int}).
|
|
555
442
|
@kwarg eps: Optional convergence limit, L{EPS} or above
|
|
556
443
|
(C{float}), see method L{Utm.toLatLon}.
|
|
557
|
-
@kwarg falsed:
|
|
444
|
+
@kwarg falsed: If C{True}, fFalse both easting and northing
|
|
445
|
+
(C{bool}).
|
|
558
446
|
|
|
559
447
|
@return: The UTM coordinate (L{Utm}).
|
|
560
448
|
'''
|
|
@@ -562,7 +450,7 @@ class Utm(UtmUpsBase):
|
|
|
562
450
|
return self.copy()
|
|
563
451
|
elif zone:
|
|
564
452
|
u = self._utm
|
|
565
|
-
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:
|
|
566
454
|
ll = self.toLatLon(LatLon=_LLEB, eps=eps, unfalse=True)
|
|
567
455
|
self._utm = u = toUtm8(ll, Utm=self.classof, falsed=falsed,
|
|
568
456
|
name=self.name, zone=zone)
|
|
@@ -576,7 +464,25 @@ class Utm(UtmUpsBase):
|
|
|
576
464
|
return self._zone
|
|
577
465
|
|
|
578
466
|
|
|
579
|
-
def
|
|
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
|
+
|
|
485
|
+
def _parseUTM5(strUTM, datum, Xtm, falsed, Error=UTMError, **name): # imported by .etm
|
|
580
486
|
'''(INTERNAL) Parse a string representing a UTM coordinate,
|
|
581
487
|
consisting of C{"zone[band] hemisphere easting northing"},
|
|
582
488
|
see L{pygeodesy.parseETM5} and L{parseUTM5}.
|
|
@@ -585,16 +491,11 @@ def _parseUTM5(strUTM, datum, Xtm, falsed, Error=UTMError, name=NN): # imported
|
|
|
585
491
|
if _UTM_ZONE_MIN > z or z > _UTM_ZONE_MAX or (B and B not in _Bands):
|
|
586
492
|
raise Error(strUTM=strUTM, zone=z, band=B)
|
|
587
493
|
|
|
588
|
-
if Xtm is None
|
|
589
|
-
|
|
590
|
-
else:
|
|
591
|
-
r = Xtm(z, h, e, n, band=B, datum=datum, falsed=falsed)
|
|
592
|
-
if name:
|
|
593
|
-
r = _xnamed(r, name, force=True)
|
|
594
|
-
return r
|
|
494
|
+
return UtmUps5Tuple(z, h, e, n, B, Error=Error, **name) if Xtm is None else \
|
|
495
|
+
Xtm(z, h, e, n, band=B, datum=datum, falsed=bool(falsed), **name)
|
|
595
496
|
|
|
596
497
|
|
|
597
|
-
def parseUTM5(strUTM, datum=_WGS84, Utm=Utm, falsed=True, name
|
|
498
|
+
def parseUTM5(strUTM, datum=_WGS84, Utm=Utm, falsed=True, **name):
|
|
598
499
|
'''Parse a string representing a UTM coordinate, consisting
|
|
599
500
|
of C{"zone[band] hemisphere easting northing"}.
|
|
600
501
|
|
|
@@ -603,8 +504,9 @@ def parseUTM5(strUTM, datum=_WGS84, Utm=Utm, falsed=True, name=NN):
|
|
|
603
504
|
L{Ellipsoid2} or L{a_f2Tuple}).
|
|
604
505
|
@kwarg Utm: Optional class to return the UTM coordinate
|
|
605
506
|
(L{Utm}) or C{None}.
|
|
606
|
-
@kwarg falsed:
|
|
607
|
-
|
|
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}).
|
|
608
510
|
|
|
609
511
|
@return: The UTM coordinate (B{C{Utm}}) or if B{C{Utm}}
|
|
610
512
|
is C{None}, a L{UtmUps5Tuple}C{(zone, hemipole,
|
|
@@ -615,28 +517,29 @@ def parseUTM5(strUTM, datum=_WGS84, Utm=Utm, falsed=True, name=NN):
|
|
|
615
517
|
|
|
616
518
|
@raise TypeError: Invalid B{C{datum}}.
|
|
617
519
|
'''
|
|
618
|
-
return _parseUTM5(strUTM, datum, Utm, falsed, name
|
|
520
|
+
return _parseUTM5(strUTM, datum, Utm, falsed, **name)
|
|
619
521
|
|
|
620
522
|
|
|
621
523
|
def toUtm8(latlon, lon=None, datum=None, Utm=Utm, falsed=True,
|
|
622
|
-
|
|
623
|
-
zone=None, **cmoff):
|
|
524
|
+
strict=True, zone=None, **name_cmoff):
|
|
624
525
|
'''Convert a lat-/longitude point to a UTM coordinate.
|
|
625
526
|
|
|
626
527
|
@arg latlon: Latitude (C{degrees}) or an (ellipsoidal)
|
|
627
528
|
geodetic C{LatLon} point.
|
|
628
|
-
@kwarg lon: Optional longitude (C{degrees})
|
|
529
|
+
@kwarg lon: Optional longitude (C{degrees}), required
|
|
530
|
+
if B{C{latlon}} is in C{degrees}.
|
|
629
531
|
@kwarg datum: Optional datum for this UTM coordinate,
|
|
630
532
|
overriding B{C{latlon}}'s datum (L{Datum},
|
|
631
533
|
L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}).
|
|
632
534
|
@kwarg Utm: Optional class to return the UTM coordinate
|
|
633
535
|
(L{Utm}) or C{None}.
|
|
634
536
|
@kwarg falsed: False both easting and northing (C{bool}).
|
|
635
|
-
@kwarg name: Optional B{C{Utm}} name (C{str}).
|
|
636
537
|
@kwarg strict: Restrict B{C{lat}} to UTM ranges (C{bool}).
|
|
637
538
|
@kwarg zone: Optional UTM zone to enforce (C{int} or C{str}).
|
|
638
|
-
@kwarg
|
|
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,
|
|
@@ -651,17 +554,17 @@ def toUtm8(latlon, lon=None, datum=None, Utm=Utm, falsed=True,
|
|
|
651
554
|
|
|
652
555
|
@raise UTMError: Invalid B{C{zone}}.
|
|
653
556
|
|
|
654
|
-
@raise ValueError: If B{C{lon}} value is missing or
|
|
655
|
-
|
|
557
|
+
@raise ValueError: If B{C{lon}} value is missing or B{C{latlon}}
|
|
558
|
+
is invalid.
|
|
656
559
|
|
|
657
560
|
@note: Implements Karney’s method, using 8-th order Krüger series,
|
|
658
561
|
giving results accurate to 5 nm (or better) for distances
|
|
659
562
|
up to 3,900 Km from the central meridian.
|
|
660
563
|
'''
|
|
661
|
-
z, B, lat, lon, d, f,
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
d = _ellipsoidal_datum(d, name=
|
|
564
|
+
z, B, lat, lon, d, f, n = _to7zBlldfn(latlon, lon, datum,
|
|
565
|
+
falsed, zone, strict,
|
|
566
|
+
UTMError, **name_cmoff)
|
|
567
|
+
d = _ellipsoidal_datum(d, name=n)
|
|
665
568
|
E = d.ellipsoid
|
|
666
569
|
|
|
667
570
|
a, b = radians(lat), radians(lon)
|
|
@@ -681,8 +584,8 @@ def toUtm8(latlon, lon=None, datum=None, Utm=Utm, falsed=True,
|
|
|
681
584
|
A0 = E.A * getattr(Utm, _under(_scale0_), _K0_UTM) # Utm is class or None
|
|
682
585
|
|
|
683
586
|
K = _Kseries(E.AlphaKs, x, y) # Krüger series
|
|
684
|
-
y =
|
|
685
|
-
x =
|
|
587
|
+
y = K.ys(y) * A0 # ξ
|
|
588
|
+
x = K.xs(x) * A0 # η
|
|
686
589
|
|
|
687
590
|
# convergence: Karney 2011 Eq 23, 24
|
|
688
591
|
p_ = K.ps(1)
|
|
@@ -692,43 +595,136 @@ def toUtm8(latlon, lon=None, datum=None, Utm=Utm, falsed=True,
|
|
|
692
595
|
k = E.e2s(sin(a)) * T12 / H * (A0 / E.a * hypot(p_, q_))
|
|
693
596
|
|
|
694
597
|
return _toXtm8(Utm, z, lat, x, y,
|
|
695
|
-
B, d, g, k, f,
|
|
598
|
+
B, d, g, k, f, n, latlon, EPS)
|
|
599
|
+
|
|
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
|
|
696
613
|
|
|
697
614
|
|
|
698
615
|
def _toXtm8(Xtm, z, lat, x, y, B, d, g, k, f, # PYCHOK 13+ args
|
|
699
|
-
|
|
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)
|
|
703
620
|
if f:
|
|
704
621
|
x, y = _false2(x, y, h)
|
|
705
622
|
if Xtm is None: # DEPRECATED
|
|
706
|
-
r = UtmUps8Tuple(z, h, x, y, B, d, g, k, Error=Error, name=
|
|
623
|
+
r = UtmUps8Tuple(z, h, x, y, B, d, g, k, Error=Error, name=n)
|
|
707
624
|
else:
|
|
708
|
-
r =
|
|
709
|
-
|
|
625
|
+
r = Xtm(z, h, x, y, band=B, datum=d, falsed=f,
|
|
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
|
|
|
719
|
-
def
|
|
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
|
+
|
|
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
|
|
@@ -738,7 +734,7 @@ def utmZoneBand5(lat, lon, cmoff=False, name=NN):
|
|
|
738
734
|
'''
|
|
739
735
|
lat, lon = parseDMS2(lat, lon)
|
|
740
736
|
z, B, lat, lon = _to4zBll(lat, lon, cmoff=cmoff)
|
|
741
|
-
return UtmUpsLatLon5Tuple(z, B, _hemi(lat), lat, lon, name
|
|
737
|
+
return UtmUpsLatLon5Tuple(z, B, _hemi(lat), lat, lon, **name)
|
|
742
738
|
|
|
743
739
|
# **) MIT License
|
|
744
740
|
#
|