def toUtm(self, Utm=Utm): '''Convert this MGRS grid reference to a UTM coordinate. @keyword Utm: Optional (sub-)class to return the UTM coordinate (L{Utm}) or C{None}. @return: The UTM coordinate (L{Utm}) or a L{UtmUps4Tuple}C{(zone, hemipole, easting, northing)} if B{C{Utm}} is C{None}. @example: >>> m = Mgrs('31U', 'DQ', 448251, 11932) >>> u = m.toUtm() # 31 N 448251 5411932 ''' # get northing of the band bottom, extended to # include entirety of bottom-most 100 km square n = toUtm8(self._bandLat, 0, datum=self._datum).northing nb = int(n / _100km) * _100km e, n = self._en100k2m() # 100 km grid square row letters repeat every 2,000 km north; # add enough 2,000 km blocks to get into required band e += self._easting n += self._northing while n < nb: n += _2000km h = _hemi(self.bandLatitude) # if self._band < 'N' if Utm is None: r = UtmUps4Tuple(self.zone, h, e, n) else: r = Utm(self.zone, h, e, n, band=self.band, datum=self.datum) return self._xnamed(r)
def upsZoneBand5(lat, lon, strict=True): '''Return the UTM/UPS zone number, (polar) Band letter, pole and clipped lat- and longitude for a given location. @param lat: Latitude in degrees (C{scalar} or C{str}). @param lon: Longitude in degrees (C{scalar} or C{str}). @keyword strict: Restrict B{C{lat}} to UPS ranges (C{bool}). @return: A L{UtmUpsLatLon5Tuple}C{(zone, band, hemipole, lat, lon)} where C{hemipole} is the C{'N'|'S'} pole, the UPS projection top/center. @raise RangeError: If B{C{strict}} and B{C{lat}} in the UTM and not the UPS range 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}}. ''' z, lat, lon = _to3zll(*parseDMS2(lat, lon)) if lat < _UPS_LAT_MIN: # includes 30' overlap z, B, p = _UPS_ZONE, _Band(lat, lon), 'S' elif lat > _UPS_LAT_MAX: # includes 30' overlap z, B, p = _UPS_ZONE, _Band(lat, lon), 'N' elif strict: x = '%s [%s, %s]' % ('range', _UPS_LAT_MIN, _UPS_LAT_MAX) raise RangeError('%s inside UTM %s: %s' % ('lat', x, degDMS(lat))) else: B, p = '', _hemi(lat) return UtmUpsLatLon5Tuple(z, B, p, lat, lon)
def _toXtm8(Xtm, zlxyBdckf, name, latlon, eps): '''(INTERNAL) Helper for L{toEtm8} and L{toUtm8}. ''' z, lat, x, y, B, d, c, k, f = zlxyBdckf h = _hemi(lat) if f: x, y = _false2(x, y, h) if Xtm is None: # DEPRECATED r = UtmUps8Tuple(z, h, x, y, B, d, c, k) else: r = Xtm(z, h, x, y, band=B, datum=d, falsed=f, convergence=c, scale=k) if isinstance(latlon, _LLEB) and d is latlon.datum: r._latlon_to(latlon, eps, f) # XXX weakref(latlon)? latlon._convergence = c latlon._scale = k return _xnamed(r, name)
def toLatLon(self, LatLon=None, unfalse=True): '''Convert this UPS coordinate to an (ellipsoidal) geodetic point. @keyword LatLon: Optional, ellipsoidal (sub-)class to return the point (C{LatLon}) or C{None}. @keyword unfalse: Unfalse B{C{easting}} and B{C{northing}} if falsed (C{bool}). @return: This UPS coordinate as (B{C{LatLon}}) or A L{LatLonDatum5Tuple}C{(lat, lon, datum, convergence, scale)} if B{C{LatLon}} is C{None}. @raise TypeError: If B{C{LatLon}} is not ellipsoidal. @raise UPSError: Invalid meridional radius or H-value. ''' if self._latlon and self._latlon_args == unfalse: return self._latlon5(LatLon) E = self.datum.ellipsoid # XXX vs LatLon.datum.ellipsoid x, y = self.to2en(falsed=not unfalse) r = hypot(x, y) t = (r / (2 * self.scale0 * E.a / E.es_c)) if r > 0 else EPS**2 t = E.es_tauf((1 / t - t) * 0.5) if self._pole == 'N': a, b, c = atan(t), atan2(x, -y), 1 else: a, b, c = -atan(t), atan2(x, y), -1 a, b = degrees90(a), degrees180(b) if not self._band: self._band = _Band(a, b) if not self._hemisphere: self._hemisphere = _hemi(a) ll = _LLEB(a, b, datum=self._datum, name=self.name) ll._convergence = b * c # gamma ll._scale = _scale(E, r, t) if r > 0 else self.scale0 self._latlon_to(ll, unfalse) return self._latlon5(LatLon)
def utmZoneBand5(lat, lon, cmoff=False): '''Return the UTM zone number, Band letter, hemisphere and (clipped) lat- and longitude for a given location. @param lat: Latitude in degrees (C{scalar} or C{str}). @param lon: Longitude in degrees (C{scalar} or C{str}). @keyword cmoff: Offset longitude from the zone's central meridian (C{bool}). @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}}. ''' lat, lon = parseDMS2(lat, lon) z, B, lat, lon = _to3zBll(lat, lon, cmoff=cmoff) return UtmUpsLatLon5Tuple(z, B, _hemi(lat), lat, lon)
def toUps8(latlon, lon=None, datum=None, Ups=Ups, pole='', falsed=True, strict=True, name=''): '''Convert a lat-/longitude point to a UPS coordinate. @param latlon: Latitude (C{degrees}) or an (ellipsoidal) geodetic C{LatLon} point. @keyword lon: Optional longitude (C{degrees}) or C{None} if B{C{latlon}} is a C{LatLon}. @keyword datum: Optional datum for this UPS coordinate, overriding B{C{latlon}}'s datum (C{Datum}). @keyword Ups: Optional (sub-)class to return the UPS coordinate (L{Ups}) or C{None}. @keyword pole: Optional top/center of (stereographic) projection (C{str}, C{'N[orth]'} or C{'S[outh]'}). @keyword falsed: False both easting and northing (C{bool}). @keyword strict: Restrict B{C{lat}} to UPS ranges (C{bool}). @keyword name: Optional B{C{Ups}} name (C{str}). @return: The UPS coordinate (B{C{Ups}}) or a L{UtmUps8Tuple}C{(zone, hemipole, easting, northing, band, datum, convergence, scale)} if B{C{Ups}} is C{None}. The C{hemipole} is the C{'N'|'S'} pole, the UPS projection top/center. @raise RangeError: If B{C{strict}} and B{C{lat}} outside the valid UPS bands or if B{C{lat}} or B{C{lon}} outside the valid range and L{rangerrors} set to C{True}. @raise TypeError: If B{C{latlon}} is not ellipsoidal. @raise ValueError: If B{C{lon}} value is missing or if B{C{latlon}} is invalid. @see: Karney's C++ class U{UPS <https://GeographicLib.SourceForge.io/html/classGeographicLib_1_1UPS.html>}. ''' lat, lon, d, name = _to4lldn(latlon, lon, datum, name) z, B, p, lat, lon = upsZoneBand5( lat, lon, strict=strict) # PYCHOK UtmUpsLatLon5Tuple E = d.ellipsoid p = str(pole or p)[:1].upper() N = p == 'N' # is north a = lat if N else -lat A = abs(a - 90) < _TOL # at pole t = tan(radians(a)) T = E.es_taupf(t) r = hypot1(T) + abs(T) if T >= 0: r = 0 if A else 1 / r k0 = getattr(Ups, '_scale0', _K0) # Ups is class or None r *= 2 * k0 * E.a / E.es_c k = k0 if A else _scale(E, r, t) c = lon # [-180, 180) from .upsZoneBand5 x, y = sincos2d(c) x *= r y *= r if N: y = -y else: c = -c if falsed: x += _Falsing y += _Falsing if Ups is None: r = UtmUps8Tuple(z, p, x, y, B, d, c, k) else: if z != _UPS_ZONE and not strict: z = _UPS_ZONE # ignore UTM zone r = Ups(z, p, x, y, band=B, datum=d, falsed=falsed, convergence=c, scale=k) r._hemisphere = _hemi(lat) if isinstance(latlon, _LLEB) and d is latlon.datum: r._latlon_to(latlon, falsed) # XXX weakref(latlon)? return _xnamed(r, name)