Exemple #1
0
    def toLatLon(self, LatLon, datum=None):
        '''Convert this WM coordinate to a geodetic point.

           @param LatLon: Ellipsoidal (sub-)class to use for the
                          point (C{LatLon}).
           @keyword datum: Optional datum for ellipsoidal or C{None} for
                           spherical I{LatLon} (C{Datum}).

           @return: Point of this WM coordinate (I{LatLon}).

           @raise TypeError: If I{LatLon} and I{datum} are not compatible
                             or if I{datum} is not ellipsoidal.

           @raise ValueError: Invalid I{radius}.

           @example:

           >>> w = Wm(448251.795, 5411932.678)
           >>> from pygeodesy import sphericalTrigonometry as sT
           >>> ll = w.toLatLon(sT.LatLon)  # 43°39′11.58″N, 004°01′36.17″E
        '''
        if issubclass(LatLon, _ELLB):
            if datum:
                return _xnamed(LatLon(*self.to2ll(datum=datum), datum=datum),
                               self.name)
        elif datum is None:
            return _xnamed(LatLon(*self.to2ll(datum=datum)), self.name)
        raise TypeError('%r and %s %r' % (LatLon, 'datum', datum))
Exemple #2
0
def toLcc(latlon, conic=Conics.WRF_Lb, height=None, Lcc=Lcc, name=''):
    '''Convert an (ellipsoidal) geodetic point to a Lambert location.

       @param latlon: Ellipsoidal point (C{LatLon}).
       @keyword conic: Optional Lambert projection to use (L{Conic}).
       @keyword height: Optional height for the point, overriding
                        the default height (C{meter}).
       @keyword Lcc: Optional (sub-)class to use for the Lambert
                     location (L{Lcc}).
       @keyword name: Optional I{Lcc} name (C{str}).

       @return: The Lambert location (L{Lcc}) or 3-tuple (easting,
                northing, height) if I{Lcc} is C{None}.

       @raise TypeError: If I{latlon} is not ellipsoidal.
    '''
    if not isinstance(latlon, _ELLB):
        raise TypeError('%s not %s: %r' % ('latlon', 'ellipsoidal', latlon))

    c = conic.toDatum(latlon.datum)

    lat, lon = latlon.to2ab()
    r = c._rdef(c._tdef(lat))
    t = c._n * (lon - c._lon0) - c._opt3

    e = c._E0 + r * sin(t)
    n = c._N0 + c._r0 - r * cos(t)

    h = latlon.height if height is None else height
    return (e, n, h) if Lcc is None else _xnamed(Lcc(e, n, h=h, conic=c), name
                                                 or _nameof(latlon))
Exemple #3
0
    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 4-tuple (C{zone,
                    hemisphere, easting, northing}) if I{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 = toUtm(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'
        return (self.zone, h, e, n) if Utm is None else _xnamed(
            Utm(self.zone, h, e, n, band=self.band, datum=self.datum),
            self.name)
Exemple #4
0
def parseUTM5(strUTM, datum=Datums.WGS84, Utm=Utm, name=''):
    '''Parse a string representing a UTM coordinate, consisting
       of I{"zone[band] hemisphere easting northing"}.

       @param strUTM: A UTM coordinate (C{str}).
       @keyword datum: Optional datum to use (L{Datum}).
       @keyword Utm: Optional (sub-)class to return the UTM
                     coordinate (L{Utm}) or C{None}.
       @keyword name: Optional I{Utm} name (C{str}).

       @return: The UTM coordinate (L{Utm}) or 5-tuple (C{zone,
                hemisphere, easting, northing, band}) if I{Utm}
                is C{None}.

       @raise UTMError: Invalid I{strUTM}.

       @example:

       >>> u = parseUTM('31 N 448251 5411932')
       >>> u.toStr2()  # [Z:31, H:N, E:448251, N:5411932]
       >>> u = parseUTM('31 N 448251.8 5411932.7')
       >>> u.toStr()  # 31 N 448252 5411933
    '''
    try:
        z, h, e, n, B = _parseUTMUPS(strUTM)
        if _UTM_ZONE_MIN > z or z > _UTM_ZONE_MAX \
                             or (B and B not in _Bands):
            raise ValueError
    except ValueError:
        raise UTMError('%s invalid: %r' % ('strUTM', strUTM))

    return (z, h, e, n, B) if Utm is None else _xnamed(
        Utm(z, h, e, n, band=B, datum=datum), name)
Exemple #5
0
def parseWM(strWM, radius=R_MA, Wm=Wm, name=''):
    '''Parse a string representing a WM coordinate, consisting
       of easting, northing and an optional radius.

       @param strWM: A WM coordinate (C{str}).
       @keyword radius: Optional earth radius (C{meter}).
       @keyword Wm: Optional (sub-)class to use (L{Wm}) or C{None}.
       @keyword name: Optional name (C{str}).

       @return: The WM coordinate (L{Wm}) or 3-tuple (easting,
                northing, radius) if I{Wm} is C{None}.

       @raise ValueError: Invalid I{strWM}.

       @example:

       >>> u = parseWM('448251 5411932')
       >>> u.toStr2()  # [E:448251, N:5411932]
    '''
    w = strWM.strip().replace(',', ' ').split()
    try:
        if len(w) == 2:
            w += [radius]
        elif len(w) != 3:
            raise ValueError  # caught below
        x, y, r = map(float, w)

    except (TypeError, ValueError):
        raise ValueError('%s invalid: %r' % ('strWM', strWM))

    return (x, y, r) if Wm is None else _xnamed(Wm(x, y, radius=r), name)
Exemple #6
0
def parseUPS5(strUPS, datum=Datums.WGS84, Ups=Ups, falsed=True, name=''):
    '''Parse a string representing a UPS coordinate, consisting of
       I{"[zone][band] pole easting northing"} where I{zone} is pseudo
       zone I{"00"|"0"|""} and I{band} is I{'A'|'B'|'Y'|'Z'|''}.

       @param strUPS: A UPS coordinate (C{str}).
       @keyword datum: Optional datum to use (L{Datum}).
       @keyword Ups: Optional (sub-)class to return the UPS
                     coordinate (L{Ups}) or C{None}.
       @keyword falsed: Both I{easting} and I{northing} are falsed (C{bool}).
       @keyword name: Optional I{Ups} name (C{str}).

       @return: The UPS coordinate (L{Ups}) or 5-tuple (C{zone, pole,
                easting, northing, band}) if I{Ups} is C{None}.

       @raise UPSError: Invalid I{strUPS}.
    '''
    try:
        u = strUPS.lstrip()
        if not u.startswith(_UPS_ZONE_STR):
            raise ValueError

        z, p, e, n, B = _parseUTMUPS(u)
        if z != _UPS_ZONE or (B and B not in _Bands):
            raise ValueError
    except (AttributeError, TypeError, ValueError):
        raise UPSError('%s invalid: %r' % ('strUPS', strUPS))

    return (z, p, e, n, B) if Ups is None else _xnamed(Ups(
            z, p, e, n, band=B, falsed=falsed, datum=datum), name)
Exemple #7
0
 def _toLLh(self, LL, height, **kwds):
     '''(INTERNAL) Helper for I{subclass.toLatLon}.
     '''
     a, b = Vector3d.to2ll(self)
     h = self.h if height is None else height
     return (a, b, h) if LL is None else _xnamed(LL(a, b, height=h, **kwds),
                                                 self.name)
Exemple #8
0
 def _latlon5(self, LatLon):
     '''(INTERNAL) Convert cached LatLon
     '''
     ll = self._latlon
     if LatLon is None:
         return ll.lat, ll.lon, ll.datum, ll.convergence, ll.scale
     elif issubclass(LatLon, _LLEB):
         return _xnamed(_xattrs(LatLon(ll.lat, ll.lon, datum=ll.datum),
                                ll, '_convergence', '_scale'), ll.name)
     raise TypeError('%s not ellipsoidal: %r' % ('LatLon', LatLon))
Exemple #9
0
def parseMGRS(strMGRS, datum=Datums.WGS84, Mgrs=Mgrs, name=''):
    '''Parse a string representing a MGRS grid reference,
       consisting of zoneBand, grid, easting and northing.

       @param strMGRS: MGRS grid reference (C{str}).
       @keyword datum: Optional datum to use (L{Datum}).
       @keyword Mgrs: Optional (sub-)class to return the MGRS
                      grid reference (L{Mgrs}) or C{None}.
       @keyword name: Optional I{Mgrs} name (C{str}).

       @return: The MGRS grid reference (L{Mgrs}) or 4-tuple (zone,
                ENdigraph, easting, northing) if I{Mgrs} is C{None}.

       @raise ValueError: Invalid I{strMGRS}.

       @example:

       >>> m = parseMGRS('31U DQ 48251 11932')
       >>> str(m)  # 31U DQ 48251 11932
       >>> m = parseMGRS('31UDQ4825111932')
       >>> repr(m)  # [Z:31U, G:DQ, E:48251, N:11932]
    '''
    def _mg(cre, s):  # return re.match groups
        m = cre.match(s)
        if not m:
            raise ValueError
        return m.groups()

    def _s2m(g):  # e or n string to meter
        f = float(g)
        if f > 0:
            x = int(log10(f))
            if 0 <= x < 4:  # at least 5 digits
                f *= (10000, 1000, 100, 10)[x]
        return f

    m = tuple(strMGRS.strip().replace(',', ' ').split())
    try:
        if len(m) == 1:  # 01ABC1234512345'
            m = _mg(_MGRSre, m[0])
            m = m[:2] + halfs2(m[2])
        elif len(m) == 2:  # 01ABC 1234512345'
            m = _mg(_GZDre, m[0]) + halfs2(m[1])
        elif len(m) == 3:  # 01ABC 12345 12345'
            m = _mg(_GZDre, m[0]) + m[1:]
        if len(m) != 4:  # 01A BC 1234 12345
            raise ValueError
        e, n = map(_s2m, m[2:])
    except ValueError:
        raise ValueError('%s invalid: %r' % ('strMGRS', strMGRS))

    z, EN = m[0], m[1].upper()
    return (z, EN, e, n) if Mgrs is None else _xnamed(
        Mgrs(z, EN, e, n, datum=datum), name)
Exemple #10
0
 def _latlon3(self, LatLon, datum):
     '''(INTERNAL) Convert cached LatLon
     '''
     ll = self._latlon
     if LatLon is None:
         if datum and datum != ll.datum:
             raise TypeError('no %s.convertDatum: %r' % (LatLon, ll))
         return ll.lat, ll.lon, ll.datum
     elif issubclass(LatLon, _LLEB):
         ll = _xnamed(LatLon(ll.lat, ll.lon, datum=ll.datum), ll.name)
         return _ll2datum(ll, datum, 'LatLon')
     raise TypeError('%s not ellipsoidal: %r' % ('LatLon', LatLon))
Exemple #11
0
    def toLatLon(self, LatLon, **kwds):
        '''Return (the center of) this garef cell as an instance
           of the supplied C{LatLon} class.

           @param LatLon: Class to use (C{LatLon}).
           @keyword kwds: Optional keyword arguments for I{LatLon}.

           @return: This garef location (I{LatLon}).

           @raise ValueError: Invalid I{LatLon}.
        '''
        if LatLon is None:
            raise ValueError('%s invalid: %r' % ('LatLon', LatLon))

        return _xnamed(LatLon(*self.latlon, **kwds), self.name)
Exemple #12
0
def toWm(latlon, lon=None, radius=R_MA, Wm=Wm, name=''):
    '''Convert a lat-/longitude point to a WM coordinate.

       @param latlon: Latitude (C{degrees}) or an (ellipsoidal or
                      spherical) geodetic C{LatLon} point.
       @keyword lon: Optional longitude (C{degrees} or C{None}).
       @keyword radius: Optional earth radius (C{meter}).
       @keyword Wm: Optional (sub-)class for the WM coordinate
                    (L{Wm}) or C{None}.
       @keyword name: Optional name (C{str}).

       @return: The WM coordinate (L{Wm}) or 3-tuple (easting,
                northing, radius) if I{Wm} is C{None}.

       @raise ValueError: If I{lon} value is missing, if I{latlon}
                          is not scalar, if I{latlon} is beyond the
                          valid WM range and L{rangerrors} is set
                          to C{True} or if I{radius} is invalid.

       @example:

       >>> p = LatLon(48.8582, 2.2945)  # 448251.8 5411932.7
       >>> w = toWm(p)  # 448252 5411933
       >>> p = LatLon(13.4125, 103.8667)  # 377302.4 1483034.8
       >>> w = toWm(p)  # 377302 1483035
    '''
    r, e = radius, None
    try:
        lat, lon = latlon.lat, latlon.lon
        if isinstance(latlon, _ELLB):
            r = latlon.datum.ellipsoid.a
            e = latlon.datum.ellipsoid.e
            if not name:  # use latlon.name
                name = _nameof(latlon) or name  # PYCHOK no effect
        lat = clipDMS(lat, _LatLimit)
    except AttributeError:
        lat, lon = parseDMS2(latlon, lon, clipLat=_LatLimit)

    s = sin(radians(lat))
    y = atanh(s)  # == log(tan((90 + lat) / 2)) == log(tanPI_2_2(radians(lat)))
    if e:
        y -= e * atanh(e * s)

    e, n = r * radians(lon), r * y
    return (e, n, r) if Wm is None else _xnamed(Wm(e, n, radius=r), name)
Exemple #13
0
    def toLatLon(self, LatLon, **kwds):
        '''Return (the approximate center of) this geohash cell
           as an instance of the supplied C{LatLon} class.

           @param LatLon: Class to use (C{LatLon}).
           @keyword kwds: Optional keyword arguments for I{LatLon}.

           @return: This geohash location (I{LatLon}).

           @example:

           >>> from sphericalTrigonometry import LatLon
           >>> ll = Geohash('u120fxw').toLatLon(LatLon)
           >>> print(repr(ll))  # LatLon(52°12′17.9″N, 000°07′07.64″E)
           >>> print(ll)  # 52.204971°N, 000.11879°E
        '''
        if LatLon is None:
            raise ValueError('%s invalid: %r' % ('LatLon', LatLon))

        return _xnamed(LatLon(*self.latlon, **kwds), self.name)
Exemple #14
0
    def toCartesian(self, Cartesian=Cartesian):
        '''Convert this n-vector to a cartesian point.

           @keyword Cartesian: Optional, cartesion (sub-)class to use
                               for the point (L{Cartesian}).

           @return: Cartesian equivalent to this n-vector (L{Cartesian}).

           @example:

           >>> v = Nvector(0.5, 0.5, 0.7071)
           >>> c = v.toCartesian()  # [3194434, 3194434, 4487327]
           >>> p = c.toLatLon()  # 45.0°N, 45.0°E
        '''
        E = self.datum.ellipsoid

        x, y, z, h = self.to4xyzh()
        # Kenneth Gade eqn (22)
        n = E.b / hypot3(x * E.a_b, y * E.a_b, z)
        r = h + n * E.a_b**2
        return _xnamed(Cartesian(x * r, y * r, z * (n + h)), self.name)
Exemple #15
0
def parseUTM(strUTM, datum=Datums.WGS84, Utm=Utm, name=''):
    '''Parse a string representing a UTM coordinate, consisting
       of zone, hemisphere, easting and northing.

       @param strUTM: A UTM coordinate (C{str}).
       @keyword datum: Optional datum to use (L{Datum}).
       @keyword Utm: Optional (sub-)class to use for the UTM
                     coordinate (L{Utm}) or C{None}.
       @keyword name: Optional I{Utm} name (C{str}).

       @return: The UTM coordinate (L{Utm}) or 4-tuple (zone,
                hemisphere, easting, northing) if I{Utm} is C{None}.

       @raise UTMError: Invalid I{strUTM}.

       @example:

       >>> u = parseUTM('31 N 448251 5411932')
       >>> u.toStr2()  # [Z:31, H:N, E:448251, N:5411932]
       >>> u = parseUTM('31 N 448251.8 5411932.7')
       >>> u.toStr()  # 31 N 448252 5411933
    '''
    u = strUTM.strip().replace(',', ' ').split()
    try:
        if len(u) != 4:
            raise ValueError  # caught below

        z, h = u[:2]
        if z.isdigit():
            z = int(z)
        else:
            z = z.upper()

        e, n = map(float, u[2:])

    except ValueError:
        raise UTMError('%s invalid: %r' % ('strUTM', strUTM))

    return (z, h, e,
            n) if Utm is None else _xnamed(Utm(z, h, e, n, datum=datum), name)
Exemple #16
0
def toCss(latlon, cs0=_CassiniSoldner0, height=None, Css=Css, name=''):
    '''Convert an (ellipsoidal) geodetic point to a Cassini-Soldner location.

       @param latlon: Ellipsoidal point (C{LatLon}).
       @keyword cs0: Optional, the Cassini-Soldner projection to use
                     (L{CassiniSoldner}).
       @keyword height: Optional height for the point, overriding
                        the default height (C{meter}).
       @keyword Css: Optional (sub-)class to return the location
                     (L{Css}) or C{None}.
       @keyword name: Optional I{Css} name (C{str}).

       @return: The Cassini-Soldner location (L{Css}) or 3-tuple
                (C{easting, northing, height}) if I{Css} is C{None}.

       @raise ImportError: Package U{GeographicLib<http://PyPI.org/
                           project/geographiclib>} missing.

       @raise TypeError: If I{latlon} is not ellipsoidal.
    '''
    if not isinstance(latlon, _LLEB):
        raise TypeError('%s not %s: %r' % ('latlon', 'ellipsoidal', latlon))

    cs = _CassiniSoldner(cs0)

    C, E = cs.datum.ellipsoid, latlon.datum.ellipsoid
    if C.a != E.a or C.f != E.f:
        raise ValueError('%s mistmatch %r vs %r' % ('ellipsoidal', C, E))

    e, n, z, rk = cs.forward4(latlon.lat, latlon.lon)
    h = latlon.height if height is None else height

    if Css is None:
        r = e, n, h
    else:
        r = _xnamed(Css(e, n, h=h, cs0=cs), name or _nameof(latlon))
        r._latlon = latlon.lat, latlon.lon
        r._azi, r._rk = z, rk
    return r
Exemple #17
0
def toMgrs(utm, Mgrs=Mgrs, name=''):
    '''Convert a UTM coordinate to an MGRS grid reference.

       @param utm: A UTM coordinate (L{Utm}).
       @keyword Mgrs: Optional (sub-)class to return the MGRS
                      grid reference (L{Mgrs}).

       @return: The MGRS grid reference (L{Mgrs}).
       @keyword name: Optional I{Mgrs} name (C{str}).

       @raise TypeError: If I{utm} is not L{Utm}.

       @raise ValueError: Invalid I{utm}.

       @example:

       >>> u = Utm(31, 'N', 448251, 5411932)
       >>> m = u.toMgrs()  # 31U DQ 48251 11932
    '''
    if not isinstance(utm, Utm):
        raise TypeError('%s not Utm: %s' % ('utm', type(utm)))

    # truncate east-/northing to within 100 km grid square
    # XXX add rounding to nm precision?
    E, e = divmod(utm.easting, _100km)
    N, n = divmod(utm.northing, _100km)

    # columns in zone 1 are A-H, zone 2 J-R, zone 3 S-Z, then
    # repeating every 3rd zone (note -1 because eastings start
    # at 166e3 due to 500km false origin)
    z = utm.zone - 1
    en = (
        _Le100k[z % 3][int(E) - 1] +
        # rows in even zones are A-V, in odd zones are F-E
        _Ln100k[z % 2][int(N) % len(_Ln100k[0])])

    return _xnamed(Mgrs(utm.zone, en, e, n, band=utm.band, datum=utm.datum),
                   name or utm.name)
Exemple #18
0
    def toLatLon(self, LatLon=None, height=None):
        '''Convert this L{Css} to an (ellipsoidal) geodetic point.

           @keyword LatLon: Optional, ellipsoidal (sub-)class to return
                            the geodetic point (C{LatLon}) or C{None}.
           @keyword height: Optional height for the point, overriding
                            the default height (C{meter}).

           @return: The point (I{LatLon}) or 4-tuple (C{degrees90},
                    C{degrees180}, height, datum) if I{LatLon} is C{None}.

           @raise TypeError: If I{LatLon} or I{datum} is not ellipsoidal.
        '''
        if LatLon and not issubclass(LatLon, _LLEB):
            raise TypeError('%s not %s: %r' %
                            ('LatLon', 'ellipsoidal', LatLon))

        a, b = self.latlon
        d = self.cs0.datum
        h = self.height if height is None else height

        return (a, b, h, d) if LatLon is None else _xnamed(
            LatLon(a, b, height=h, datum=d), self.name)
Exemple #19
0
    def toLatLon(self, LatLon=None, datum=None, height=None):
        '''Convert this L{Lcc} to an (ellipsoidal) geodetic point.

           @keyword LatLon: Optional, ellipsoidal (sub-)class to use for
                            the geodetic point (C{LatLon}) or C{None}.
           @keyword datum: Optional datum to use, otherwise use this
                           I{Lcc}'s conic.datum (C{Datum}).
           @keyword height: Optional height for the point, overriding
                            the default height (C{meter}).

           @return: The point (I{LatLon}) or 4-tuple (C{degrees90},
                    C{degrees180}, height, datum) if I{LatLon} is C{None}.

           @raise TypeError: If I{LatLon} or I{datum} is not ellipsoidal.
        '''
        if LatLon and not issubclass(LatLon, _ELLB):
            raise TypeError('%s not %s: %r' %
                            ('LatLon', 'ellipsoidal', LatLon))

        a, b, d = self.to3lld(datum=datum)
        h = self.height if height is None else height

        return (a, b, h, d) if LatLon is None else _xnamed(
            LatLon(a, b, height=h, datum=d), self.name)
Exemple #20
0
 def _toLLhd(self, LL, datum):
     '''(INTERNAL) Helper for I{subclass.toLatLon}.
     '''
     a, b, h = self.to3llh(datum)
     return (a, b, h) if LL is None else _xnamed(
         LL(a, b, height=h, datum=datum), self.name)
Exemple #21
0
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 I{latlon} is a C{LatLon}.
       @keyword datum: Optional datum for this UPS coordinate,
                       overriding I{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 I{lat} to UPS ranges (C{bool}).
       @keyword name: Optional I{Ups} name (C{str}).

       @return: The UPS coordinate (L{Ups}) or a 8-tuple (zone, hemisphere,
                easting, northing, band, datum, convergence, scale) if
                I{Ups} is C{None}.

       @raise RangeError: If I{strict} and I{lat} outside the valid UPS
                          bands or if I{lat} or I{lon} outside the valid
                          range and I{rangerrrors} set to C{True}.

       @raise TypeError: If I{latlon} is not ellipsoidal.

       @raise ValueError: If I{lon} value is missing or if I{latlon}
                          is invalid.

       @see: Karney's C++ class U{UPS
             <http://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)

    p = str(pole or p)[:1]
    N = p in 'Nn'
    E = d.ellipsoid
    A = abs(lat - 90) < _TOL

    t = tan(radians(lat if N else -lat))
    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 = z, p, x, y, B, d, c, k
    else:
        if z != _UPS_ZONE and not strict:
            z = _UPS_ZONE  # ignore UTM zone
        r = _xnamed(Ups(z, p, x, y, band=B, datum=d,
                                    convergence=c, scale=k,
                                    falsed=falsed), name)
        if hasattr(Ups, '_hemisphere'):
            r._hemisphere = _hemi(lat)
    return r
Exemple #22
0
def toUtm8(latlon,
           lon=None,
           datum=None,
           Utm=Utm,
           cmoff=True,
           name='',
           zone=None):
    '''Convert a lat-/longitude point to a UTM coordinate.

       @param latlon: Latitude (C{degrees}) or an (ellipsoidal)
                      geodetic C{LatLon} point.
       @keyword lon: Optional longitude (C{degrees}) or C{None}.
       @keyword datum: Optional datum for this UTM coordinate,
                       overriding I{latlon}'s datum (C{Datum}).
       @keyword Utm: Optional (sub-)class to return the UTM
                     coordinate (L{Utm}) or C{None}.
       @keyword cmoff: Offset longitude from zone's central meridian,
                       apply false easting and false northing (C{bool}).
       @keyword name: Optional I{Utm} name (C{str}).
       @keyword zone: Optional zone to enforce (C{int} or C{str}).

       @return: The UTM coordinate (L{Utm}) or a 8-tuple (C{zone, hemisphere,
                easting, northing, band, datum, convergence, scale}) if
                I{Utm} is C{None} or I{cmoff} is C{False}.

       @raise TypeError: If I{latlon} is not ellipsoidal.

       @raise RangeError: If I{lat} outside the valid UTM bands or if
                          I{lat} or I{lon} outside the valid range and
                          I{rangerrrors} set to C{True}.

       @raise UTMError: Invlid I{zone}.

       @raise ValueError: If I{lon} value is missing or if I{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
    '''
    lat, lon, d, name = _to4lldn(latlon, lon, datum, name)
    z, B, lat, lon = _to3zBll(lat, lon, cmoff=cmoff)
    if zone:  # re-zone for UTM
        r, _, _ = _to3zBhp(zone, band=B)
        if r != z:
            if not _UTM_ZONE_MIN <= r <= _UTM_ZONE_MAX:
                raise UTMError('%s invalid: %r' % ('zone', zone))
            if cmoff:  # re-offset from central meridian
                lon += _cmlon(z) - _cmlon(r)
            z = r

    E = d.ellipsoid

    a, b = radians(lat), radians(lon)
    # easting, northing: Karney 2011 Eq 7-14, 29, 35
    sb, cb = sincos2(b)

    T = tan(a)
    T12 = hypot1(T)
    S = sinh(E.e * atanh(E.e * T / T12))

    T_ = T * hypot1(S) - S * T12
    H = hypot(T_, cb)

    y = atan2(T_, cb)  # ξ' ksi
    x = asinh(sb / H)  # η' eta

    A0 = _K0 * E.A

    Ks = _Kseries(E.AlphaKs, x, y)  # Krüger series
    y = Ks.ys(y) * A0  # ξ
    x = Ks.xs(x) * A0  # η

    if cmoff:
        # Charles Karney, "Test data for the transverse Mercator projection (2009)"
        # <http://GeographicLib.SourceForge.io/html/transversemercator.html>
        # and <http://Zenodo.org/record/32470#.W4LEJS2ZON8>
        x += _FalseEasting  # make x relative to false easting
        if y < 0:
            y += _FalseNorthing  # y relative to false northing in S

    # convergence: Karney 2011 Eq 23, 24
    p_ = Ks.ps(1)
    q_ = Ks.qs(0)
    c = degrees(atan(T_ / hypot1(T_) * tan(b)) + atan2(q_, p_))

    # scale: Karney 2011 Eq 25
    s = E.e2s(sin(a)) * T12 / H * (A0 / E.a * hypot(p_, q_))

    h = _hemi(a)
    if Utm is None or not cmoff:
        r = z, h, x, y, B, d, c, s
    else:
        r = _xnamed(Utm(z, h, x, y, band=B, datum=d, convergence=c, scale=s),
                    name)
    return r
Exemple #23
0
def toOsgr(latlon, lon=None, datum=Datums.WGS84, Osgr=Osgr, name=''):
    '''Convert a lat-/longitude point to an OSGR coordinate.

       @param latlon: Latitude (C{degrees}) or an (ellipsoidal)
                      geodetic C{LatLon} point.
       @keyword lon: Optional longitude in degrees (scalar or C{None}).
       @keyword datum: Optional datum to convert (C{Datum}).
       @keyword Osgr: Optional (sub-)class to return the OSGR
                      coordinate (L{Osgr}) or C{None}.
       @keyword name: Optional I{Osgr} name (C{str}).

       @return: The OSGR coordinate (L{Osgr}) or 2-tuple (easting,
                northing) if I{Osgr} is C{None}.

       @raise TypeError: Non-ellipsoidal I{latlon} or I{datum}
                         conversion failed.

       @raise ValueError: Invalid I{latlon} or I{lon}.

       @example:

       >>> p = LatLon(52.65798, 1.71605)
       >>> r = toOsgr(p)  # TG 51409 13177
       >>> # for conversion of (historical) OSGB36 lat-/longitude:
       >>> r = toOsgr(52.65757, 1.71791, datum=Datums.OSGB36)
    '''
    if not isinstance(latlon, _LLEB):
        # XXX fix failing _LLEB.convertDatum()
        latlon = _LLEB(*parseDMS2(latlon, lon), datum=datum)
    elif lon is not None:
        raise ValueError('%s not %s: %r' % ('lon', None, lon))
    elif not name:  # use latlon.name
        name = _nameof(latlon) or name  # PYCHOK no effect

    E = _OSGB36.ellipsoid

    ll = _ll2datum(latlon, _OSGB36, 'latlon')
    a, b = map1(radians, ll.lat, ll.lon)

    sa, ca = sincos2(a)

    s = E.e2s2(sa)
    v = E.a * _F0 / sqrt(s)  # nu
    r = s / E.e12  # nu / rho == v / (v * E.e12 / s)

    x2 = r - 1  # η2
    ta = tan(a)

    ca3, ca5 = fpowers(ca, 5, 3)  # PYCHOK false!
    ta2, ta4 = fpowers(ta, 4, 2)  # PYCHOK false!

    vsa = v * sa
    I4 = (E.b * _F0 * _M(E.Mabcd, a) + _N0, (vsa / 2) * ca,
          (vsa / 24) * ca3 * fsum_(5, -ta2, 9 * x2),
          (vsa / 720) * ca5 * fsum_(61, ta4, -58 * ta2))

    V4 = (_E0, (v * ca), (v / 6) * ca3 * (r - ta2), (v / 120) * ca5 * fdot(
        (-18, 1, 14, -58), ta2, 5 + ta4, x2, ta2 * x2))

    d, d2, d3, d4, d5, d6 = fpowers(b - _B0, 6)  # PYCHOK false!
    n = fdot(I4, 1, d2, d4, d6)
    e = fdot(V4, 1, d, d3, d5)

    return (e, n) if Osgr is None else _xnamed(Osgr(e, n), name)
Exemple #24
0
def parseOSGR(strOSGR, Osgr=Osgr, name=''):
    '''Parse an OSGR coordinate string to an Osgr instance.

       Accepts standard OS Grid References like 'SU 387 148',
       with or without whitespace separators, from 2- up to
       10-digit references (1 m × 1 m square), or fully
       numeric, comma-separated references in metres, for
       example '438700,114800'.

       @param strOSGR: An OSGR coordinate (C{str}).
       @keyword Osgr: Optional (sub-)class to return the OSGR
                      coordinate (L{Osgr}) or C{None}.
       @keyword name: Optional I{Osgr} name (C{str}).

       @return: The OSGR coordinate (L{Osgr}) or the 2-tuple
                (easting, northing) if I{Osgr} is C{None}.

       @raise ValueError: Invalid I{strOSGR}.

       @example:

       >>> g = parseOSGR('TG 51409 13177')
       >>> str(g)  # TG 51409 13177
       >>> g = parseOSGR('TG5140913177')
       >>> str(g)  # TG 51409 13177
       >>> g = parseOSGR('TG51409 13177')
       >>> str(g)  # TG 51409 13177
       >>> g = parseOSGR('651409,313177')
       >>> str(g)  # TG 51409 13177
       >>> g.toStr(prec=0)  # 651409,313177
    '''
    def _c2i(G):
        g = ord(G.upper()) - ord('A')
        if g > 7:
            g -= 1
        return g

    def _s2f(g):
        return float(g.strip())

    def _s2i(G, g):
        g += '00000'  # std to meter
        return int(str(G) + g[:5])

    s = strOSGR.strip()
    try:
        g = s.split(',')
        if len(g) == 2:  # "easting,northing"
            if len(s) < 13:
                raise ValueError  # caught below
            e, n = map(_s2f, g)

        else:  # "GR easting northing"

            g, s = s[:2], s[2:].strip()

            e, n = map(_c2i, g)
            n, m = divmod(n, 5)
            E = ((e - 2) % 5) * 5 + m
            N = 19 - (e // 5) * 5 - n
            if 0 > E or E > 6 or \
               0 > N or N > 12:
                raise ValueError  # caught below

            g = s.split()
            if len(g) == 1:  # no whitespace
                e, n = halfs2(s)
            elif len(g) == 2:
                e, n = g
            else:
                raise ValueError  # caught below

            e = _s2i(E, e)
            n = _s2i(N, n)

    except ValueError:
        raise ValueError('%s invalid: %r' % ('strOSGR', strOSGR))

    return (e, n) if Osgr is None else _xnamed(Osgr(e, n), name)
Exemple #25
0
def toUtm(latlon, lon=None, datum=None, Utm=Utm, name='', cmoff=True):
    '''Convert a lat-/longitude point to a UTM coordinate.

       @param latlon: Latitude (C{degrees}) or an (ellipsoidal)
                      geodetic C{LatLon} point.
       @keyword lon: Optional longitude (C{degrees} or C{None}).
       @keyword datum: Optional datum for this UTM coordinate,
                       overriding I{latlon}'s datum (C{Datum}).
       @keyword Utm: Optional (sub-)class to use for the UTM
                     coordinate (L{Utm}) or C{None}.
       @keyword name: Optional I{Utm} name (C{str}).
       @keyword cmoff: Offset longitude from zone's central meridian,
                       apply false easting and false northing (C{bool}).

       @return: The UTM coordinate (L{Utm}) or a 6-tuple (zone, easting,
                northing, band, convergence, scale) if I{Utm} is C{None}
                or I{cmoff} is C{False}.

       @raise TypeError: If I{latlon} is not ellipsoidal.

       @raise RangeError: If I{lat} is outside the valid UTM bands or if
                          I{lat} or I{lon} outside the valid range and
                          I{rangerrrors} set to C{True}.

       @raise ValueError: If I{lon} value is missing or if I{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
    '''
    try:
        lat, lon = latlon.lat, latlon.lon
        if not isinstance(latlon, _LLEB):
            raise TypeError('%s not %s: %r' %
                            ('latlon', 'ellipsoidal', latlon))
        if not name:  # use latlon.name
            name = _nameof(latlon) or name  # PYCHOK no effect
        d = datum or latlon.datum
    except AttributeError:
        lat, lon = parseDMS2(latlon, lon)
        d = datum or Datums.WGS84

    E = d.ellipsoid

    z, B, a, b = _toZBab4(lat, lon, cmoff)

    # easting, northing: Karney 2011 Eq 7-14, 29, 35
    cb, sb, tb = cos(b), sin(b), tan(b)

    T = tan(a)
    T12 = hypot1(T)
    S = sinh(E.e * atanh(E.e * T / T12))

    T_ = T * hypot1(S) - S * T12
    H = hypot(T_, cb)

    y = atan2(T_, cb)  # ξ' ksi
    x = asinh(sb / H)  # η' eta

    A0 = _K0 * E.A

    Ks = _Kseries(E.AlphaKs, x, y)  # Krüger series
    y = Ks.ys(y) * A0  # ξ
    x = Ks.xs(x) * A0  # η

    if cmoff:
        # C.F.F. Karney, "Test data for the transverse Mercator projection (2009)",
        # <http://GeographicLib.SourceForge.io/html/transversemercator.html> and
        # <http://Zenodo.org/record/32470#.W4LEJS2ZON8>
        x += _FalseEasting  # make x relative to false easting
        if y < 0:
            y += _FalseNorthing  # y relative to false northing in S

    # convergence: Karney 2011 Eq 23, 24
    p_ = Ks.ps(1)
    q_ = Ks.qs(0)
    c = degrees(atan(T_ / hypot1(T_) * tb) + atan2(q_, p_))

    # scale: Karney 2011 Eq 25
    s = E.e2s(sin(a)) * T12 / H * (A0 / E.a * hypot(p_, q_))

    if cmoff and Utm is not None:
        h = 'S' if a < 0 else 'N'  # hemisphere
        return _xnamed(
            Utm(z, h, x, y, band=B, datum=d, convergence=c, scale=s), name)
    else:  # zone, easting, northing, band, convergence and scale
        return z, x, y, B, c, s