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.
Files changed (57) hide show
  1. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.1.dist-info}/METADATA +6 -5
  2. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.1.dist-info}/RECORD +57 -57
  3. pygeodesy/__init__.py +4 -4
  4. pygeodesy/auxilats/__init__.py +1 -1
  5. pygeodesy/auxilats/__main__.py +2 -2
  6. pygeodesy/auxilats/auxAngle.py +4 -4
  7. pygeodesy/basics.py +39 -5
  8. pygeodesy/booleans.py +3 -3
  9. pygeodesy/constants.py +3 -3
  10. pygeodesy/deprecated/functions.py +9 -3
  11. pygeodesy/ecef.py +22 -21
  12. pygeodesy/ellipsoidalBase.py +15 -16
  13. pygeodesy/ellipsoidalGeodSolve.py +2 -2
  14. pygeodesy/ellipsoidalKarney.py +3 -3
  15. pygeodesy/ellipsoids.py +6 -5
  16. pygeodesy/errors.py +19 -9
  17. pygeodesy/etm.py +16 -21
  18. pygeodesy/fmath.py +9 -20
  19. pygeodesy/formy.py +60 -74
  20. pygeodesy/frechet.py +11 -11
  21. pygeodesy/fsums.py +59 -25
  22. pygeodesy/geodesicx/__init__.py +1 -1
  23. pygeodesy/geodesicx/__main__.py +2 -2
  24. pygeodesy/geodesicx/gx.py +3 -5
  25. pygeodesy/geodsolve.py +2 -2
  26. pygeodesy/geohash.py +14 -14
  27. pygeodesy/hausdorff.py +12 -12
  28. pygeodesy/heights.py +5 -5
  29. pygeodesy/internals.py +3 -3
  30. pygeodesy/karney.py +8 -7
  31. pygeodesy/lazily.py +2 -2
  32. pygeodesy/ltp.py +62 -44
  33. pygeodesy/ltpTuples.py +202 -147
  34. pygeodesy/mgrs.py +24 -24
  35. pygeodesy/named.py +68 -70
  36. pygeodesy/nvectorBase.py +2 -2
  37. pygeodesy/osgr.py +40 -48
  38. pygeodesy/points.py +10 -10
  39. pygeodesy/props.py +29 -16
  40. pygeodesy/rhumb/aux_.py +13 -15
  41. pygeodesy/rhumb/bases.py +12 -5
  42. pygeodesy/rhumb/ekx.py +24 -18
  43. pygeodesy/rhumb/solve.py +13 -10
  44. pygeodesy/simplify.py +16 -16
  45. pygeodesy/solveBase.py +14 -14
  46. pygeodesy/sphericalBase.py +17 -21
  47. pygeodesy/sphericalTrigonometry.py +17 -17
  48. pygeodesy/trf.py +9 -7
  49. pygeodesy/triaxials.py +2 -2
  50. pygeodesy/ups.py +66 -70
  51. pygeodesy/utily.py +3 -3
  52. pygeodesy/utm.py +152 -156
  53. pygeodesy/utmups.py +38 -38
  54. pygeodesy/utmupsBase.py +102 -106
  55. pygeodesy/webmercator.py +43 -51
  56. {PyGeodesy-24.5.24.dist-info → PyGeodesy-24.6.1.dist-info}/WHEEL +0 -0
  57. {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
- # from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .named
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.21'
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}, instead use C{B{gamma}=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
- c = name_convergence
291
- if c:
292
- n, c = _name2__(**c)
293
- if n:
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
- gamma=gamma, scale=scale, **c)
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
- see function L{parseUTM5}.
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
- s = hypot(p, q) * E.a / A0
487
- ll._gamma = degrees(atan1(tan(y) * tanh(x)) + atan2(q, p))
488
- ll._scale = (E.e2s(sin(a)) * hypot1(T) * H / s) if s else s # INF?
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: False both easting and northing (C{bool}).
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 != bool(u.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: False both easting and northing (C{bool}).
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: Both easting and northing are falsed (C{bool}).
606
- @kwarg name: Optional B{C{Utm}} name (C{str}).
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
- and DEPRECATED C{B{cmoff}=True} to offset longitude
638
- from the zone's central meridian (C{bool}), instead
639
- use C{B{falsed}=True}.
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, eps, Error=UTMError):
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, eps) # XXX weakref(latlon)?
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: Offset longitude from the zone's central
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
- lat, lon)} where C{hemipole} is the C{'N'|'S'}
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, _xkwds_get
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__ = '23.05.03'
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=NN):
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 instance name (C{str}).
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
- a L{UtmUps5Tuple}C{(zone, hemipole, easting, northing,
90
- band)} if B{C{Utm}} respectively B{C{Ups}} or both are
91
- C{None}. The C{hemipole} is C{'N'|'S'}, the UTM hemisphere
92
- or UPS pole, the UPS projection top/center.
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
- pole=NN, name=NN, **cmoff):
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 name: Optional name (C{str}).
126
- @kwarg cmoff: DEPRECATED, use B{C{falsed}}. Offset longitude
127
- from zone's central meridian, for UTM only (C{bool}).
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
- lat, lon, d, name = _to4lldn(latlon, lon, datum, name)
148
- z, B, p, lat, lon = utmupsZoneBand5(lat, lon)
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=name, pole=pole or p)
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=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=NN):
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: Optional, the coordinate's datum (L{Datum}).
171
- @kwarg falsed: Both B{C{easting}} and B{C{northing}} are falsed (C{bool}).
172
- @kwarg name: Optional name (C{str}).
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=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 northing are falsed (C{bool}).
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} otherwise.
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=NN):
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: Offset longitude from the zone's central
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
- lat, lon)} where C{hemipole} is C{'N'|'S'}, the
282
- UTM hemisphere or UPS pole, the UPS projection
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=name)
294
+ return utmZoneBand5(lat, lon, cmoff=cmoff, **name)
295
295
  except RangeError:
296
- return upsZoneBand5(lat, lon, name=name)
296
+ return upsZoneBand5(lat, lon, **name)
297
297
 
298
298
  # **) MIT License
299
299
  #