Coverage for pygeodesy/utm.py : 98%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*-
Classes L{Utm} and L{UTMError} and functions L{parseUTM5}, L{toUtm8} and L{utmZoneBand5}.
Pure Python implementation of UTM / WGS-84 conversion functions using an ellipsoidal earth model, transcoded from JavaScript originals by I{(C) Chris Veness 2011-2016} published under the same MIT Licence**, see U{UTM<https://www.Movable-Type.co.UK/scripts/latlong-utm-mgrs.html>} and U{Module utm<https://www.Movable-Type.co.UK/scripts/geodesy/docs/module-utm.html>}.
The U{UTM<https://WikiPedia.org/wiki/Universal_Transverse_Mercator_coordinate_system>} system is a 2-dimensional Cartesian coordinate system providing another way to identify locations on the surface of the earth. UTM is a set of 60 transverse Mercator projections, normally based on the WGS-84 ellipsoid. Within each zone, coordinates are represented as B{C{easting}}s and B{C{northing}}s, measured in metres.
This module includes some of I{Charles Karney}'s U{'Transverse Mercator with an accuracy of a few nanometers'<https://Arxiv.org/pdf/1002.1417v3.pdf>}, 2011 (building on Krüger's U{'Konforme Abbildung des Erdellipsoids in der Ebene' <https://bib.GFZ-Potsdam.DE/pub/digi/krueger2.pdf>}, 1912) and C++ class U{TransverseMercator <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1TransverseMercator.html>}.
Some other references are U{Universal Transverse Mercator coordinate system <https://WikiPedia.org/wiki/Universal_Transverse_Mercator_coordinate_system>}, U{Transverse Mercator Projection<https://GeographicLib.SourceForge.io/tm.html>} and Henrik Seidel U{'Die Mathematik der Gauß-Krueger-Abbildung' <https://Henrik-Seidel.GMXhome.DE/gausskrueger.pdf>}, 2006. '''
_xkwds_get, _xkwds_not _COMMASPACE_, _float, _NS_, \ _outside_, _range_, _S_, _SPACE_, \ _UTM_, _V_, _X_, _zone_, _0_0, _1_0 UtmUps8Tuple, UtmUpsLatLon5Tuple _to4lldn, _to3zBhp, _to3zll, \ _UTM_LAT_MAX, _UTM_LAT_MIN, \ _UTM_ZONE_MIN, _UTM_ZONE_MAX, \ _UTM_ZONE_OFF_MAX, UtmUpsBase
degrees, radians, sin, sinh, tan, tanh
# Latitude bands C..X of 8° each, covering 80°S to 84°N with X repeated # for 80-84°N
'''Universal Transverse Mercator (UTM parse or other L{Utm} issue. '''
'''(INTERNAL) Alpha or Beta Krüger series.
Krüger series summations for B{C{eta}}, B{C{ksi}}, B{C{p}} and B{C{q}}, caching the C{cos}, C{cosh}, C{sin} and C{sinh} values for the given B{C{eta}} and B{C{ksi}} angles (in C{radians}). ''' '''(INTERNAL) New Alpha or Beta Krüger series
@arg AB: Krüger Alpha or Beta series coefficients (C{4-, 6- or 8-tuple}). @arg x: Eta angle (C{radians}). @arg y: Ksi angle (C{radians}). '''
# assert len(self._ab) == len(self._pq) == n
# assert len(x2) == len(self._chx) == len(self._shx) == n
# self._sy, self._cy = splice(sincos2(*y2)) # PYCHOK false # assert len(y2) == len(self._cy) == len(self._sy) == n
'''(INTERNAL) Eta summation (C{float}). '''
'''(INTERNAL) Ksi summation (C{float}). '''
'''(INTERNAL) P summation (C{float}). '''
'''(INTERNAL) Q summation (C{float}). '''
'''(INTERNAL) Central meridian longitude (C{degrees180}). '''
'''(INTERNAL) False easting and northing. ''' # Karney, "Test data for the transverse Mercator projection (2009)" # <https://GeographicLib.SourceForge.io/html/transversemercator.html> # and <https://Zenodo.org/record/32470#.W4LEJS2ZON8>
'''(INTERNAL) Check and return zone, Band and band latitude.
@arg zone: Zone number or string. @arg band: Band letter. @arg Error: Exception to raise (L{UTMError}).
@return: 3-Tuple (zone, Band, latitude). ''' raise Error(zone=zone)
raise Error(band=band or B) raise Error(band=band, txt=MISSING)
'''(INTERNAL) Return zone, Band and lat- and (central) longitude in degrees.
@arg lat: Latitude (C{degrees}). @arg lon: Longitude (C{degrees}). @kwarg cmoff: Offset B{C{lon}} from zone's central meridian.
@return: 4-Tuple (zone, Band, lat, lon). '''
raise RangeError(lat=degDMS(lat), txt=t)
t = _SPACE_(_outside_, _UTM_, _zone_, str(z), _by_, degDMS(x, prec=6)) raise RangeError(lon=degDMS(lon), txt=t)
'''(INTERNAL) Determine 7-tuple (zone, band, lat, lon, datum, falsed, name) for L{toEtm8} and L{toUtm8}. ''' raise Error(zone=zone)
'''Universal Transverse Mercator (UTM) coordinate. ''' # _band = NN # latitude band letter ('C..X') # _scale = None # grid scale factor (C{scalar}) or C{None}
datum=_WGS84, falsed=True, convergence=None, scale=None, name=NN): '''New L{Utm} UTM coordinate.
@arg zone: Longitudinal UTM zone (C{int}, 1..60) or zone with/-out (latitudinal) Band letter (C{str}, '01C'..'60X'). @arg hemisphere: Northern or southern hemisphere (C{str}, C{'N[orth]'} or C{'S[outh]'}). @arg easting: Easting, see B{C{falsed}} (C{meter}). @arg northing: Northing, see B{C{falsed}} (C{meter}). @kwarg band: Optional, (latitudinal) band (C{str}, 'C'..'X'). @kwarg datum: Optional, this coordinate's datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}). @kwarg falsed: Both B{C{easting}} and B{C{northing}} are falsed (C{bool}). @kwarg convergence: Optional meridian convergence, bearing off grid North, clockwise from true North (C{degrees}) or C{None}. @kwarg scale: Optional grid scale factor (C{scalar}) or C{None}. @kwarg name: Optional name (C{str}).
@raise TypeError: Invalid B{C{datum}}.
@raise UTMError: Invalid B{C{zone}}, B{C{hemishere}}, B{C{easting}}, B{C{northing}}, B{C{band}}, B{C{convergence}} or B{C{scale}}.
@example:
>>> import pygeodesy >>> u = pygeodesy.Utm(31, 'N', 448251, 5411932) '''
raise self._Error(hemisphere=hemisphere)
# if not falsed: # e, n = _false2(e, n, h) # # check easting/northing (with 40km overlap # # between zones) - is this worthwhile? # @raise RangeError: If B{C{easting}} or B{C{northing}} outside # the valid UTM range. # if 120e3 > e or e > 880e3: # raise RangeError(easting=easting) # if 0 > n or n > _FalseNorthing: # raise RangeError(northing=northing)
convergence=convergence, scale=scale)
return isinstance(other, Utm) and other.zone == self.zone \ and other.hemisphere == self.hemisphere \ and other.easting == self.easting \ and other.northing == self.northing \ and other.band == self.band \ and other.datum == self.datum
'''(INTERNAL) Make copy as an B{C{Xtm}} instance.
@arg Xtm: Class to return the copy (C{Xtm=Etm}, C{Xtm=Utm} or C{self.classof}). ''' self.easting, self.northing, band=self.band, datum=self.datum, falsed=self.falsed, scale=self.scale, convergence=self.convergence, name=name or self.name)
'''Get the (latitudinal) band (C{str}, 'C'..'X' or ''). '''
'''(INTERNAL) Cache for L{toEtm}. '''
'''Get the easting and northing falsing (L{EasNor2Tuple}C{(easting, northing)}). '''
'''Get this UTM C{un}-centered (L{Utm}) to its C{lowerleft}. '''
'''(INTERNAL) Cache for L{toMgrs}. '''
'''(INTERNAL) Cache for L{toMgrs}, I{un}-centered. '''
'''Parse a string to a similar L{Utm} instance.
@arg strUTM: The UTM coordinate (C{str}), see function L{parseUTM5}. @kwarg name: Optional instance name (C{str}), overriding this name.
@return: The similar instance (L{Utm}).
@raise UTMError: Invalid B{C{strUTM}}.
@see: Function L{parseUPS5} and L{parseUTMUPS5}. ''' return parseUTM5(strUTM, datum=self.datum, Utm=self.classof, name=name or self.name)
def parseUTM(self, strUTM): # PYCHOK no cover '''DEPRECATED, use method L{Utm.parse}.''' return self.parse(strUTM)
'''Get the top center of (stereographic) projection, C{""} always. '''
'''Copy this UTM to an ETM coordinate.
@return: The ETM coordinate (L{Etm}). '''
'''Convert this UTM coordinate to an (ellipsoidal) geodetic point.
@kwarg LatLon: Optional, ellipsoidal class to return the geodetic point (C{LatLon}) or C{None}. @kwarg eps: Optional convergence limit, L{EPS} or above (C{float}). @kwarg unfalse: Unfalse B{C{easting}} and B{C{northing}} if falsed (C{bool}). @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword arguments, ignored if C{B{LatLon}=None}.
@return: This UTM as (B{C{LatLon}}) or if B{C{LatLon}} is C{None}, as L{LatLonDatum5Tuple}C{(lat, lon, datum, convergence, scale)}.
@raise TypeError: If B{C{LatLon}} is not ellipsoidal.
@raise UTMError: Invalid meridional radius or H-value.
@example:
>>> u = Utm(31, 'N', 448251.795, 5411932.678) >>> from pygeodesy import ellipsoidalVincenty as eV >>> ll = u.toLatLon(eV.LatLon) # 48°51′29.52″N, 002°17′40.20″E '''
# from Karney 2011 Eq 15-22, 36 raise self._Error(meridional=A0)
raise self._Error(H=H)
P -= 1 # else: # P = 0
# convergence: Karney 2011 Eq 26, 27
# scale: Karney 2011 Eq 28
'''(INTERNAL) See C{.toLatLon}, C{toUtm8}, C{_toXtm8}. '''
'''Convert this UTM coordinate to an MGRS grid reference.
@kwarg center: If C{True}, I{un}-center this UTM to its C{lowerleft} (C{bool}) or by C{B{center} meter} (C{scalar}).
@return: The MGRS grid reference (L{Mgrs}).
@see: Function L{toMgrs} in L{mgrs} for more details. ''' self._mgrs_lowerleft if center in (True,) else _toMgrs(_lowerleft(self, center))) # PYCHOK indent
'''Return a string representation of this UTM coordinate.
Note that UTM coordinates are rounded, not truncated (unlike MGRS grid references).
@kwarg prec: Optional number of decimals, unstripped (C{int}). @kwarg fmt: Optional, enclosing backets format (C{str}). @kwarg sep: Optional separator between name:value pairs (C{str}). @kwarg B: Optionally, include latitudinal band (C{bool}). @kwarg cs: Optionally, include meridian convergence and grid scale factor (C{bool} or non-zero C{int} to specify the precison like B{C{prec}}).
@return: This UTM as a string C{"[Z:09[band], H:N|S, E:meter, N:meter]"} plus C{", C:degrees, S:float"} if B{C{cs}} is C{True} (C{str}). '''
'''Return a string representation of this UTM coordinate.
To distinguish from MGRS grid zone designators, a space is left between the zone and the hemisphere.
Note that UTM coordinates are rounded, not truncated (unlike MGRS grid references).
@kwarg prec: Optional number of decimals, unstripped (C{int}). @kwarg sep: Optional separator to join (C{str}) or C{None} to return an unjoined C{tuple} of C{str}s. @kwarg B: Optionally, include latitudinal band (C{bool}). @kwarg cs: Optionally, include meridian convergence and grid scale factor (C{bool} or non-zero C{int} to specify the precison like B{C{prec}}).
@return: This UTM as a string with C{zone[band], hemisphere, easting, northing, [convergence, scale]} in C{"00 N|S meter meter"} plus C{" degrees float"} if B{C{cs}} is C{True} (C{str}).
@example:
>>> u = Utm(3, 'N', 448251, 5411932.0001) >>> u.toStr(4) # 03 N 448251.0 5411932.0001 >>> u.toStr(sep=', ') # 03 N, 448251, 5411932 '''
'''Convert this UTM coordinate to a UPS coordinate.
@kwarg pole: Optional top/center of the UPS projection, (C{str}, 'N[orth]'|'S[outh]'). @kwarg eps: Optional convergence limit, L{EPS} or above (C{float}), see method L{Utm.toLatLon}. @kwarg falsed: False both easting and northing (C{bool}).
@return: The UPS coordinate (L{Ups}). ''' strict=False, name=self.name)
'''Convert this UTM coordinate to a different zone.
@arg zone: New UTM zone (C{int}). @kwarg eps: Optional convergence limit, L{EPS} or above (C{float}), see method L{Utm.toLatLon}. @kwarg falsed: False both easting and northing (C{bool}).
@return: The UTM coordinate (L{Utm}). ''' return self.copy() name=self.name, zone=zone) raise self._Error(zone=zone)
'''Get the (longitudinal) zone (C{int}, 1..60). '''
'''(INTERNAL) I{Un}-center a B{C{utm}} to its C{lowerleft} by C{B{center} meter} or by a I{guess} if B{C{center}} is C{0}. ''' e = n = -center else: (n == c and e in (c, c - 1)): else: return utm # unchanged
convergence=utm.convergence) utm.easting - e, utm.northing - n, band=utm.band, falsed=utm.falsed, **r)
'''(INTERNAL) Parse a string representing a UTM coordinate, consisting of C{"zone[band] hemisphere easting northing"}, see L{parseETM5} and L{parseUTM5}. ''' raise Error(strUTM=strUTM, zone=z, band=B)
else:
'''Parse a string representing a UTM coordinate, consisting of C{"zone[band] hemisphere easting northing"}.
@arg strUTM: A UTM coordinate (C{str}). @kwarg datum: Optional datum to use (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}). @kwarg Utm: Optional class to return the UTM coordinate (L{Utm}) or C{None}. @kwarg falsed: Both easting and northing are falsed (C{bool}). @kwarg name: Optional B{C{Utm}} name (C{str}).
@return: The UTM coordinate (B{C{Utm}}) or if B{C{Utm}} is C{None}, a L{UtmUps5Tuple}C{(zone, hemipole, easting, northing, band)}. The C{hemipole} is the C{'N'|'S'} hemisphere.
@raise UTMError: Invalid B{C{strUTM}}.
@raise TypeError: Invalid B{C{datum}}.
@example:
>>> u = parseUTM5('31 N 448251 5411932') >>> u.toRepr() # [Z:31, H:N, E:448251, N:5411932] >>> u = parseUTM5('31 N 448251.8 5411932.7') >>> u.toStr() # 31 N 448252 5411933 '''
'''(INTERNAL) Convert a L{Utm} to an L{Mgrs} instance. '''
zone=None, **cmoff): '''Convert a lat-/longitude point to a UTM coordinate.
@arg latlon: Latitude (C{degrees}) or an (ellipsoidal) geodetic C{LatLon} point. @kwarg lon: Optional longitude (C{degrees}) or C{None}. @kwarg datum: Optional datum for this UTM coordinate, overriding B{C{latlon}}'s datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}). @kwarg Utm: Optional class to return the UTM coordinate (L{Utm}) or C{None}. @kwarg falsed: False both easting and northing (C{bool}). @kwarg name: Optional B{C{Utm}} name (C{str}). @kwarg zone: Optional UTM zone to enforce (C{int} or C{str}). @kwarg cmoff: DEPRECATED, use B{C{falsed}}. Offset longitude from the zone's central meridian (C{bool}).
@return: The UTM coordinate (B{C{Utm}}) or if B{C{Utm}} is C{None} or not B{C{falsed}}, a L{UtmUps8Tuple}C{(zone, hemipole, easting, northing, band, datum, convergence, scale)}. The C{hemipole} is the C{'N'|'S'} hemisphere.
@raise RangeError: If B{C{lat}} outside the valid UTM bands or if B{C{lat}} or B{C{lon}} outside the valid range and L{rangerrors} set to C{True}.
@raise TypeError: Invalid B{C{datum}} or B{C{latlon}} not ellipsoidal.
@raise UTMError: Invalid B{C{zone}}.
@raise ValueError: If B{C{lon}} value is missing or if B{C{latlon}} is invalid.
@note: Implements Karney’s method, using 8-th order Krüger series, giving results accurate to 5 nm (or better) for distances up to 3900 km from the central meridian.
@example:
>>> p = LatLon(48.8582, 2.2945) # 31 N 448251.8 5411932.7 >>> u = toUtm(p) # 31 N 448252 5411933 >>> p = LatLon(13.4125, 103.8667) # 48 N 377302.4 1483034.8 >>> u = toUtm(p) # 48 N 377302 1483035 ''' falsed, name, zone, UTMError, **cmoff)
# easting, northing: Karney 2011 Eq 7-14, 29, 35
# convergence: Karney 2011 Eq 23, 24
# scale: Karney 2011 Eq 25
B, d, c, k, f, name, latlon, EPS)
name, latlon, eps, Error=UTMError): '''(INTERNAL) Helper for L{toEtm8} and L{toUtm8}. ''' else: convergence=c, scale=k), name)
'''Return the UTM zone number, Band letter, hemisphere and (clipped) lat- and longitude for a given location.
@arg lat: Latitude in degrees (C{scalar} or C{str}). @arg lon: Longitude in degrees (C{scalar} or C{str}). @kwarg cmoff: Offset longitude from the zone's central meridian (C{bool}). @kwarg name: Optional name (C{str}).
@return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole, lat, lon)} where C{hemipole} is the C{'N'|'S'} UTM hemisphere.
@raise RangeError: If B{C{lat}} outside the valid UTM bands or if B{C{lat}} or B{C{lon}} outside the valid range and L{rangerrors} set to C{True}.
@raise ValueError: Invalid B{C{lat}} or B{C{lon}}. '''
# **) MIT License # # Copyright (C) 2016-2021 -- mrJean1 at Gmail -- All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. |