Beispiel #1
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 _xnamed(LatLonDatum3Tuple(ll.lat, ll.lon, ll.datum), ll.name)
     elif issubclassof(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))
Beispiel #2
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 _xnamed(LatLonDatum3Tuple(ll.lat, ll.lon, ll.datum),
                        ll.name)
     else:
         _xsubclassof(_LLEB, LatLon=LatLon)
         ll = _xnamed(LatLon(ll.lat, ll.lon, datum=ll.datum), ll.name)
         return _ll2datum(ll, datum, 'LatLon')
Beispiel #3
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(latlon=ll,
                              txt=_item_ps(_no_convertDatum_, datum.name))
         return _xnamed(LatLonDatum3Tuple(ll.lat, ll.lon, ll.datum),
                        ll.name)
     else:
         _xsubclassof(_LLEB, LatLon=LatLon)
         ll = _xnamed(LatLon(ll.lat, ll.lon, datum=ll.datum), ll.name)
         return _ll2datum(ll, datum, _LatLon_)
def meanOf(points, datum=Datums.WGS84, height=None, LatLon=LatLon,
                                                  **LatLon_kwds):
    '''Compute the geographic mean of several points.

       @arg points: Points to be averaged (L{LatLon}[]).
       @kwarg datum: Optional datum to use (L{Datum}).
       @kwarg height: Optional height at mean point, overriding
                      the mean height (C{meter}).
       @kwarg LatLon: Optional class to return the mean point
                      (L{LatLon}) or C{None}.
       @kwarg LatLon_kwds: Optional, additional B{C{LatLon}}
                           keyword arguments, ignored if
                           B{C{LatLon=None}}.

       @return: Geographic mean point and mean height (B{C{LatLon}})
                or a L{LatLon3Tuple}C{(lat, lon, height)} if
                B{C{LatLon}} is C{None}.

       @raise ValueError: Insufficient number of B{C{points}}.
    '''
    _, points = _Nvll.points2(points, closed=False)
    # geographic mean
    m = sumOf(p._N_vector for p in points)
    lat, lon, h = m._N_vector.latlonheight

    if height is not None:
        h = height
    if LatLon is None:
        r = LatLon3Tuple(lat, lon, h)
    else:
        kwds = _xkwds(LatLon_kwds, height=h, datum=datum)
        r = LatLon(lat, lon, **kwds)
    return _xnamed(r, meanOf.__name__)
Beispiel #5
0
    def reverse(self, x, y, name=NN, LatLon=None, **LatLon_kwds):
        '''Convert an azimuthal equidistant location to (ellipsoidal) geodetic lat- and longitude.

           @arg x: Easting of the location (C{meter}).
           @arg y: Northing of the location (C{meter}).
           @kwarg name: Optional name for the location (C{str}).
           @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
           @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
                               arguments, ignored if B{C{LatLon=None}}.

           @return: The geodetic (C{LatLon}) or if B{C{LatLon}} is C{None} an
                    L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.

           @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
                  in the range C{[-180..180] degrees}.  The scale of the projection
                  is C{1} in I{radial} direction, C{azimuth} clockwise from true
                  North and is C{1 / reciprocal} in the direction perpendicular
                  to this.
        '''
        x = Scalar(x, name=_x_)
        y = Scalar(y, name=_y_)

        z = atan2d(x, y)  # (x, y) for azimuth from true North
        s = hypot(x, y)

        r = self.geodesic.Direct(self.lat0, self.lon0, z, s, self._mask)
        t = self._toLatLon(r.lat2, r.lon2, LatLon, LatLon_kwds) if LatLon else \
            Azimuthal7Tuple(x, y, r.lat2, r.lon2, r.azi2, self._1_rk(r), self.datum)
        return _xnamed(t, name or self.name)
Beispiel #6
0
    def forward(self, lat, lon, name=NN):
        '''Convert an (ellipsoidal) geodetic location to azimuthal equidistant east- and northing.

           @arg lat: Latitude of the location (C{degrees90}).
           @arg lon: Longitude of the location (C{degrees180}).
           @kwarg name: Optional name for the location (C{str}).

           @return: An L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}
                    with C{x} and C{y} in C{meter} and C{lat} and C{lon} in
                    C{degrees}.  The C{scale} of the projection is C{1} in I{radial}
                    direction, C{azimuth} clockwise from true North and is C{1 /
                    reciprocal} in the direction perpendicular to this.

           @see: Method L{EquidistantKarney.reverse}.  A call to C{.forward}
                 followed by a call to C{.reverse} will return the original
                 C{lat, lon} to within roundoff.

            @raise AzimuthalError: Invalid B{C{lat}} or B{C{lon}}.
       '''
        r = self.geodesic.Inverse(self.lat0, self.lon0, Lat_(lat), Lon_(lon),
                                  self._mask)
        x, y = sincos2d(r.azi1)
        t = Azimuthal7Tuple(x * r.s12, y * r.s12, r.lat2, r.lon2, r.azi2,
                            self._1_rk(r), self.datum)
        return _xnamed(t, name or self.name)
Beispiel #7
0
def _toXtm8(
        Xtm,
        z,
        lat,
        x,
        y,
        B,
        d,
        c,
        k,
        f,  # PYCHOK 13+ args
        name,
        latlon,
        eps,
        Error=UTMError):
    '''(INTERNAL) Helper for L{toEtm8} and L{toUtm8}.
    '''
    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, Error=Error)
    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)
Beispiel #8
0
def parse3d(str3d, sep=_COMMA_, name=NN, Vector=Vector3d, **Vector_kwds):
    '''Parse an C{"x, y, z"} string.

       @arg str3d: X, y and z values (C{str}).
       @kwarg sep: Optional separator (C{str}).
       @kwarg name: Optional instance name (C{str}).
       @kwarg Vector: Optional class (L{Vector3d}).
       @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments,
                           ignored if B{C{Vector=None}}.

       @return: New B{C{Vector}} or if B{C{Vector}} is C{None},
                a L{Vector3Tuple}C{(x, y, z)}.

       @raise VectorError: Invalid B{C{str3d}}.
    '''
    try:
        v = [float(v.strip()) for v in str3d.split(sep)]
        if len(v) != 3:
            raise ValueError
    except (TypeError, ValueError) as x:
        raise VectorError(str3d=str3d, txt=str(x))

    r = Vector3Tuple(*v) if Vector is None else \
              Vector(*v, **Vector_kwds)
    return _xnamed(r, name, force=True)
Beispiel #9
0
    def _OSGR_(strOSGR, Osgr, name):
        s = strOSGR.strip()
        g = s.split(_COMMA_)
        if len(g) == 2:  # "easting,northing"
            if len(s) < 13:
                raise ValueError
            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

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

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

        r = _EasNor2Tuple(e, n) if Osgr is None else Osgr(e, n)
        return _xnamed(r, name, force=True)
Beispiel #10
0
def parseUTM5(strUTM, datum=Datums.WGS84, Utm=Utm, falsed=True, name=''):
    '''Parse a string representing a UTM coordinate, consisting
       of C{"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 falsed: Both easting and northing are falsed (C{bool}).
       @keyword name: Optional B{C{Utm}} name (C{str}).

       @return: The UTM coordinate (B{C{Utm}}) or a
                L{UtmUps5Tuple}C{(zone, hemipole,
                easting, northing, band)} if B{C{Utm}} is
                C{None}.  The C{hemipole} is the hemisphere
                C{'N'|'S'}.

       @raise UTMError: Invalid B{C{strUTM}}.

       @example:

       >>> u = parseUTM5('31 N 448251 5411932')
       >>> u.toStr2()  # [Z:31, H:N, E:448251, N:5411932]
       >>> u = parseUTM5('31 N 448251.8 5411932.7')
       >>> u.toStr()  # 31 N 448252 5411933
    '''
    r = _parseUTM5(strUTM, UTMError)
    if Utm is not None:
        z, h, e, n, B = r
        r = Utm(z, h, e, n, band=B, datum=datum, falsed=falsed)
    return _xnamed(r, name)
def meanOf(points, height=None, LatLon=LatLon):
    '''Compute the geographic mean of several points.

       @param points: Points to be averaged (L{LatLon}[]).
       @keyword height: Optional height at mean point, overriding
                        the mean height (C{meter}).
       @keyword LatLon: Optional (sub-)class to return the mean
                        point (L{LatLon}) or C{None}.

       @return: Point at geographic mean and height (B{C{LatLon}}) or
                a L{LatLon3Tuple}C{(lat, lon, height)} if
                B{C{LatLon}} is C{None}.

       @raise TypeError: Some B{C{points}} are not L{LatLon}.

       @raise ValueError: No B{C{points}}.
    '''
    # geographic mean
    n, points = _Trll.points2(points, closed=False)

    m = sumOf(points[i].toVector3d() for i in range(n))
    a, b = m.to2ll()

    if height is None:
        h = fmean(points[i].height for i in range(n))
    else:
        h = height
    r = LatLon3Tuple(a, b, h) if LatLon is None else \
              LatLon(a, b, height=h)
    return _xnamed(r, meanOf.__name__)
Beispiel #12
0
def parseUTM5(strUTM, datum=Datums.WGS84, Utm=Utm, falsed=True, name=NN):
    '''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.toStr2()  # [Z:31, H:N, E:448251, N:5411932]
       >>> u = parseUTM5('31 N 448251.8 5411932.7')
       >>> u.toStr()  # 31 N 448252 5411933
    '''
    r = _parseUTM5(strUTM, datum, Utm, falsed)
    return _xnamed(r, name, force=True)
Beispiel #13
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 return the WM coordinate
                    (L{Wm}) or C{None}.
       @keyword name: Optional name (C{str}).

       @return: The WM coordinate (B{C{Wm}}) or an
                L{EasNorRadius3Tuple}C{(easting, northing, radius)}
                if B{C{Wm}} is C{None}.

       @raise WebMercatorError: Invalid B{C{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 WebMercatorError('%s invalid: %r' % ('strWM', strWM))

    r = EasNorRadius3Tuple(x, y, r) if Wm is None else \
                        Wm(x, y, radius=r)
    return _xnamed(r, name)
Beispiel #14
0
    def _reverse(self, x, y, name, LatLon, LatLon_kwds, _c_t, lea):
        '''(INTERNAL) Azimuthal (spherical) reverse C{x, y} to C{lat, lon}.
        '''
        x = Scalar(x, name=_x_)
        y = Scalar(y, name=_y_)

        r = hypot(x, y)
        c, t = _c_t(r / self.radius)
        if t:
            s0, c0 = self._sc0
            sc, cc = sincos2(c)
            k = c / sc
            z = atan2d(x, y)  # (x, y) for azimuth from true North

            lat = degrees(asin1(s0 * cc + c0 * sc * (y / r)))
            if lea or abs(c0) > EPS:
                lon = atan2(x * sc, c0 * cc * r - s0 * sc * y)
            else:
                lon = atan2(x, (y if s0 < 0 else -y))
            lon = _norm180(self.lon0 + degrees(lon))
        else:
            k, z = 1, 0
            lat, lon = self.latlon0

        t = self._toLatLon(lat, lon, LatLon, LatLon_kwds) if LatLon else \
            Azimuthal7Tuple(x, y, lat, lon, z, k, self.datum)
        return _xnamed(t, name or self.name)
Beispiel #15
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 return the Lambert
                     location (L{Lcc}).
       @keyword name: Optional B{C{Lcc}} name (C{str}).

       @return: The Lambert location (L{Lcc}) or an
                L{EasNor3Tuple}C{(easting, northing, height)}
                if B{C{Lcc}} is C{None}.

       @raise TypeError: If B{C{latlon}} is not ellipsoidal.
    '''
    if not isinstance(latlon, _LLEB):
        raise _IsNotError(_LLEB.__name__, latlon=latlon)

    a, b = latlon.to2ab()
    c = conic.toDatum(latlon.datum)

    t = c._n * (b - c._lon0) - c._opt3
    st, ct = sincos2(t)

    r = c._rdef(c._tdef(a))
    e = c._E0         + r * st
    n = c._N0 + c._r0 - r * ct

    h = latlon.height if height is None else height
    r = EasNor3Tuple(e, n, h) if Lcc is None else \
                 Lcc(e, n, h=h, conic=c)
    return _xnamed(r, name or nameof(latlon))
def toNed(distance, bearing, elevation, Ned=Ned, name=NN):
    '''Create an NED vector from distance, bearing and elevation
       (in local coordinate system).

       @arg distance: NED vector length (C{meter}).
       @arg bearing: NED vector bearing (compass C{degrees360}).
       @arg elevation: NED vector elevation from local coordinate
                       frame horizontal (C{degrees}).
       @kwarg Ned: Optional class to return the NED (L{Ned}) or
                   C{None}.
       @kwarg name: Optional name (C{str}).

       @return: An NED vector equivalent to this B{C{distance}},
                B{C{bearing}} and B{C{elevation}} (L{Ned}) or
                if B{C{Ned=None}}, an L{Ned3Tuple}C{(north, east,
                down)}.

       @raise ValueError: Invalid B{C{distance}}, B{C{bearing}}
                          or B{C{elevation}}.

       @JSname: I{fromDistanceBearingElevation}.
    '''
    d = Distance(distance)

    sb, cb, se, ce = sincos2d(Bearing(bearing), Height(elevation=elevation))
    n = cb * d * ce
    e = sb * d * ce
    d *= se

    r = Ned3Tuple(n, e, -d) if Ned is None else \
              Ned(n, e, -d)
    return _xnamed(r, name)
Beispiel #17
0
def parseUPS5(strUPS, datum=Datums.WGS84, Ups=Ups, falsed=True, name=NN):
    '''Parse a string representing a UPS coordinate, consisting of
       C{"[zone][band] pole easting northing"} where B{C{zone}} is
       pseudo zone C{"00"|"0"|""} and C{band} is C{'A'|'B'|'Y'|'Z'|''}.

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

       @return: The UPS coordinate (B{C{Ups}}) or a
                L{UtmUps5Tuple}C{(zone, hemipole, easting, northing,
                band)} if B{C{Ups}} is C{None}.  The C{hemipole} is
                the C{'N'|'S'} pole, the UPS projection top/center.

       @raise UPSError: Invalid B{C{strUPS}}.
    '''
    z, p, e, n, B = _parseUTMUPS5(strUPS, _UPS_ZONE_STR, Error=UPSError)
    if z != _UPS_ZONE or (B and B not in _Bands):
        raise UPSError(strUPS=strUPS, zone=z, band=B)

    r = UtmUps5Tuple(z, p, e, n, B, Error=UPSError) if Ups is None else \
                 Ups(z, p, e, n, band=B, falsed=falsed, datum=datum)
    return _xnamed(r, name, force=True)
def meanOf(points, datum=Datums.WGS84, height=None, LatLon=LatLon):
    '''Compute the geographic mean of several points.

       @param points: Points to be averaged (L{LatLon}[]).
       @keyword datum: Optional datum to use (L{Datum}).
       @keyword height: Optional height at mean point, overriding
                        the mean height (C{meter}).
       @keyword LatLon: Optional (sub-)class to return the mean
                        point (L{LatLon}) or C{None}.

       @return: Geographic mean point and mean height (B{C{LatLon}})
                or a L{LatLon3Tuple}C{(lat, lon, height)} if
                B{C{LatLon}} is C{None}.

       @raise ValueError: Insufficient number of B{C{points}}.
    '''
    _, points = _Nvll.points2(points, closed=False)
    # geographic mean
    m = sumOf(p.toNvector() for p in points)
    a, b, h = m.to3llh()

    if height is not None:
        h = height
    r = LatLon3Tuple(a, b, h) if LatLon is None else \
              LatLon(a, b, height=h, datum=datum)
    return _xnamed(r, meanOf.__name__)
Beispiel #19
0
def _V_n(v, name, Vector, Vector_kwds):
    # return a named Vector instance
    if Vector is None:
        v = _xnamed(v, name)
    else:
        kwds = _xkwds(Vector_kwds, name=name)
        v = Vector(v.x, v.y, v.z, **kwds)
    return v
Beispiel #20
0
 def _latlon4(t, h, n):
     if LatLon is None:
         r = LatLon4Tuple(t.lat, t.lon, h, t.datum)
     else:
         kwds = _xkwds(LatLon_kwds, datum=t.datum, height=h)
         r = LatLon(t.lat, t.lon, **kwds)
     r._iteration = t.iteration  # ._iteration for tests
     return _xnamed(r, n)
Beispiel #21
0
def _latlon3(lat, lon, height, func, LatLon, **LatLon_kwds):
    '''(INTERNAL) Helper for L{intersection} and L{meanof}.
    '''
    if LatLon is None:
        r = LatLon3Tuple(lat, lon, height)
    else:
        kwds = _xkwds(LatLon_kwds, height=height)
        r = LatLon(lat, lon, **kwds)
    return _xnamed(r, func.__name__)
Beispiel #22
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.

       @arg strMGRS: MGRS grid reference (C{str}).
       @kwarg datum: Optional datum to use (L{Datum}).
       @kwarg Mgrs: Optional class to return the MGRS grid
                    reference (L{Mgrs}) or C{None}.
       @kwarg name: Optional B{C{Mgrs}} name (C{str}).

       @return: The MGRS grid reference (B{L{Mgrs}}) or an
                L{Mgrs4Tuple}C{(zone, digraph, easting, northing)}
                if B{C{Mgrs}} is C{None}.

       @raise MGRSError: Invalid B{C{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]
       >>> m = mgrs.parseMGRS('42SXD0970538646')
       >>> str(m)  # 42S XD 09705 38646
       >>> m = mgrs.parseMGRS('42SXD9738')  # Km
       >>> str(m)  # 42S XD 97000 38000
    '''
    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 float meter
        # convert to meter if less than 5 digits
        m = g + '00000'
        return float(m[:5])

    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(_ZBGre, m[0]) + halfs2(m[1])
        elif len(m) == 3:  # 01ABC 12345 12345'
            m = _mg(_ZBGre, m[0]) + m[1:]
        if len(m) != 4:  # 01A BC 1234 12345
            raise ValueError
        e, n = map(_s2m, m[2:])
    except (TypeError, ValueError):
        raise InvalidError(strMGRS=strMGRS, Error=MGRSError)

    z, EN = m[0], m[1].upper()
    r = Mgrs4Tuple(z, EN, e, n) if Mgrs is None else \
              Mgrs(z, EN, e, n, datum=datum)
    return _xnamed(r, name)
Beispiel #23
0
    def reverse(self, x, y, name=NN, LatLon=None, **LatLon_kwds):
        '''Convert an azimuthal gnomonic location to (ellipsoidal) geodetic lat- and longitude.

           @arg x: Easting of the location (C{meter}).
           @arg y: Northing of the location (C{meter}).
           @kwarg name: Optional name for the location (C{str}).
           @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
           @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
                               arguments, ignored if B{C{LatLon=None}}.

           @return: The geodetic (C{LatLon}) or if B{C{LatLon}} is C{None} an
                    L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.

           @raise AzimuthalError: No convergence.

           @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
                  in the range C{[-180..180] degrees}.  The C{azimuth} is clockwise
                  from true North.  The scale is C{1 / reciprocal**2} in C{radial}
                  direction and C{1 / reciprocal} in the direction perpendicular
                  to this.
        '''
        x = Scalar(x, name=_x_)
        y = Scalar(y, name=_y_)

        z = atan2d(x, y)  # (x, y) for azimuth from true North
        q = hypot(x, y)

        d = e = self.equatoradius
        s = e * atan(q / e)
        if q > e:

            def _d(r, q):
                return (r.M12 - q * r.m12) * r.m12  # negated

            q = 1 / q
        else:  # little == True

            def _d(r, q):  # PYCHOK _d
                return (q * r.M12 - r.m12) * r.M12  # negated

        e *= _EPS_Karney

        S = Fsum(s)
        g = self.geodesic.Line(self.lat0, self.lon0, z, self._mask)
        for self._iteration in range(1, _TRIPS):
            r = g.Position(s, self._mask)
            if abs(d) < e:
                break
            s, d = S.fsum2_(_d(r, q))
        else:
            raise AzimuthalError(x=x, y=y, txt=_no_convergence_fmt_ % (e, ))

        t = self._toLatLon(r.lat2, r.lon2, LatLon, LatLon_kwds) if LatLon else \
            Azimuthal7Tuple(x, y, r.lat2, r.lon2, r.azi2, r.M12, self.datum)
        t._iteration = self._iteration
        return _xnamed(t, name or self.name)
Beispiel #24
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 B{C{Mgrs}} name (C{str}).

       @return: The MGRS grid reference (B{L{Mgrs}}) or an
                L{Mgrs4Tuple}C{(zone, digraph, easting, northing)}
                if B{C{Mgrs}} is C{None}.

       @raise MGRSError: Invalid B{C{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 (TypeError, ValueError):
        raise MGRSError('%s invalid: %r' % ('strMGRS', strMGRS))

    z, EN = m[0], m[1].upper()
    r = Mgrs4Tuple(z, EN, e, n) if Mgrs is None else \
              Mgrs(z, EN, e, n, datum=datum)
    return _xnamed(r, name)
Beispiel #25
0
    def forward(self, lat, lon, lon0=0, name=NN):
        '''Convert a geodetic location to east- and northing.

           @arg lat: Latitude of the location (C{degrees}).
           @arg lon: Longitude of the location (C{degrees}).
           @kwarg lon0: Optional central meridian longitude (C{degrees}).
           @kwarg name: Optional name for the location (C{str}).

           @return: An L{Albers7Tuple}C{(x, y, lat, lon, gamma, scale, datum)}.

           @note: The origin latitude is returned by C{property lat0}.  No
                  false easting or northing is added.  The value of B{C{lat}}
                  should be in the range C{[-90..90] degrees}.  The returned
                  values C{x} and C{y} will be large but finite for points
                  projecting to infinity, i.e. one or both of the poles.
        '''
        E = self.datum.ellipsoid
        s = self._sign

        k0 = self._k0
        n0 = self._n0
        nrho0 = self._nrho0
        txi0 = self._txi0

        sa, ca = sincos2d(_Lat_(lat) * s)
        ca = max(_EPSX, ca)
        ta = sa / ca

        _, sxi, txi = self._cstxif3(ta)
        dq = self._qZ * _Dsn(txi, txi0, sxi, self._sxi0) * (txi - txi0)
        drho = -E.a * dq / (sqrt(self._m02 - n0 * dq) + self._m0)

        lon = _Lon_(lon)
        if lon0:
            lon, _ = _diff182(_Lon_(lon0, name=_lon0_), lon)
        b = radians(lon)

        th = self._k02n0 * b
        sth, cth = sincos2(th)  # XXX sin, cos
        if n0:
            x = sth / n0
            y = (1 - cth if cth < 0 else sth**2 / (1 + cth)) / n0
        else:
            x = self._k02 * b
            y = 0
        t = nrho0 + n0 * drho
        x = t * x / k0
        y = s * (nrho0 * y - drho * cth) / k0

        g = degrees360(s * th)
        if t:
            k0 *= t * hypot1(E.b_a * ta) / E.a
        t = Albers7Tuple(x, y, lat, lon, g, k0, self.datum)
        return _xnamed(t, name or self.name)
Beispiel #26
0
def toWm(latlon, lon=None, radius=R_MA, Wm=Wm, name='', **Wm_kwds):
    '''Convert a lat-/longitude point to a WM coordinate.

       @arg latlon: Latitude (C{degrees}) or an (ellipsoidal or
                    spherical) geodetic C{LatLon} point.
       @kwarg lon: Optional longitude (C{degrees} or C{None}).
       @kwarg radius: Optional earth radius (C{meter}).
       @kwarg Wm: Optional class to return the WM coordinate
                  (L{Wm}) or C{None}.
       @kwarg name: Optional name (C{str}).
       @kwarg Wm_kwds: Optional, additional B{C{Wm}} keyword
                       arguments, ignored if B{C{Wm=None}}.

       @return: The WM coordinate (B{C{Wm}}) or an
                L{EasNorRadius3Tuple}C{(easting, northing, radius)}
                if B{C{Wm}} is C{None}.

       @raise ValueError: If B{C{lon}} value is missing, if B{C{latlon}}
                          is not scalar, if B{C{latlon}} is beyond the
                          valid WM range and L{rangerrors} is set
                          to C{True} or if B{C{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
    '''
    e, r = None, Radius(radius)
    try:
        lat, lon = latlon.lat, latlon.lon
        if isinstance(latlon, _LLEB):
            r = latlon.datum.ellipsoid.a
            e = latlon.datum.ellipsoid.e
            if not name:  # use latlon.name
                name = nameof(latlon)
        lat = clipDegrees(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
    if Wm is None:
        r = EasNorRadius3Tuple(e, n, r)
    else:
        kwds = _xkwds(Wm_kwds, radius=r)
        r = Wm(e, n, **kwds)
    return _xnamed(r, name)
Beispiel #27
0
    def _WM_(strWM, radius, Wm, name):
        w = strWM.replace(_COMMA_, _SPACE_).strip().split()

        if len(w) == 2:
            w += [radius]
        elif len(w) != 3:
            raise ValueError
        x, y, r = map(float, w)

        r = EasNorRadius3Tuple(x, y, r) if Wm is None else \
                            Wm(x, y, radius=r)
        return _xnamed(r, name, force=True)
Beispiel #28
0
def decode3(garef, center=True):
    '''Decode a C{garef} to lat-, longitude and precision.

       @param garef: To be decoded (L{Garef} or C{str}).
       @keyword center: If C{True} the center, otherwise the south-west,
                        lower-left corner (C{bool}).

       @return: A L{LatLonPrec3Tuple}C{(lat, lon, precision)}.

       @raise GARSError: Invalid B{C{garef}}, INValid, non-alphanumeric
                         or bad length B{C{garef}}.
    '''
    def _Error(i):
        return GARSError('%s invalid: %r[%s]' % ('garef', garef, i))

    def _ll(chars, g, i, j, lo, hi):
        ll, b = 0, len(chars)
        for i in range(i, j):
            d = chars.find(g[i])
            if d < 0:
                raise _Error(i)
            ll = ll * b + d
        if ll < lo or ll > hi:
            raise _Error(j)
        return ll

    def _ll2(lon, lat, g, i, m):
        d = _Digits.find(g[i])
        if d < 1 or d > m * m:
            raise _Error(i)
        d, r = divmod(d - 1, m)
        lon = lon * m + r
        lat = lat * m + (m - 1 - d)
        return lon, lat

    g, precision = _2garstr2(garef)

    lon = _ll(_Digits,  g,       0, _LonLen, 1, 720) + _LonOrig_M1_1
    lat = _ll(_Letters, g, _LonLen, _MinLen, 0, 359) + _LatOrig_M1
    if precision > 0:
        lon, lat = _ll2(lon, lat, g, _MinLen, _M2)
        if precision > 1:
            lon, lat = _ll2(lon, lat, g, _MinLen + 1, _M3)

    r = _Resolutions[precision]  # == 1.0 / unit
    if center:
        lon = lon * 2 + 1
        lat = lat * 2 + 1
        r *= 0.5
    lon *= r
    lat *= r
    return _xnamed(LatLonPrec3Tuple(lat, lon, precision), nameof(garef))
Beispiel #29
0
 def _latlon3(self, LatLon, datum):
     '''(INTERNAL) Convert cached latlon to C{LatLon}
     '''
     ll = self._latlon
     if LatLon is None:
         r = _ll2datum(ll, datum, LatLonDatum3Tuple.__name__)
         r = LatLonDatum3Tuple(r.lat, r.lon, r.datum)
     else:  # must be ellipsoidal
         _xsubclassof(_LLEB, LatLon=LatLon)
         r = _ll2datum(ll, datum, LatLon.__name__)
         r = LatLon(r.lat, r.lon, datum=r.datum)
     r._iteration = ll._iteration
     return _xnamed(r, ll)
Beispiel #30
0
 def _latlon5(self, LatLon, **LatLon_kwds):
     '''(INTERNAL) Convert cached LatLon
     '''
     ll = self._latlon
     if LatLon is None:
         r = LatLonDatum5Tuple(ll.lat, ll.lon, ll.datum, ll.convergence,
                               ll.scale)
     else:
         _xsubclassof(_LLEB, LatLon=LatLon)
         kwds = _xkwds(LatLon_kwds, datum=ll.datum)
         r = _xattrs(LatLon(ll.lat, ll.lon, **kwds), ll, '_convergence',
                     '_scale')
     return _xnamed(r, ll.name)