Exemple #1
0
    def __new__(cls,
                arg=None,
                name=NN,
                Error=UnitError,
                low=0,
                high=None,
                **name_arg):
        '''New named C{int} instance with limits.

           @kwarg cls: This class (C{Int_} or sub-class).
           @arg arg: The value (any C{type} convertable to C{int}).
           @kwarg name: Optional instance name (C{str}).
           @kwarg Error: Optional error to raise, overriding the default
                         C{UnitError}.
           @kwarg low: Optional lower B{C{arg}} limit (C{float} or C{None}).
           @kwarg high: Optional upper B{C{arg}} limit (C{float} or C{None}).
           @kwarg name_arg: Optional C{name=arg} keyword argument,
                            inlieu of B{C{name}} and B{C{arg}}.

           @returns: An L{Int_} instance.

           @raise Error: Invalid B{C{arg}} or B{C{arg}} below B{C{low}} or
                         above B{C{high}}.
        '''
        if name_arg:
            name, arg = _xkwds_popitem(name_arg)
        self = Int.__new__(cls, arg=arg, name=name, Error=Error)
        if (low is not None) and self < low:
            txt = Fmt.limit(below=low)
        elif (high is not None) and self > high:
            txt = Fmt.limit(above=high)
        else:
            return self
        raise _Error(cls, arg, name=name, Error=Error, txt=txt)
Exemple #2
0
    def toStr(self, **unused):  # PYCHOK expected
        '''Return this reference frame as a text string.

           @return: This L{RefFrame}'s attributes (C{str}).
        '''
        e = self.ellipsoid
        t = (Fmt.EQUAL(_name_,
                       repr(self.name)), Fmt.EQUAL(_epoch_, self.epoch),
             Fmt.PAREN(Fmt.EQUAL(_ellipsoid_, classname(e)),
                       Fmt.EQUAL(_name_, repr(e.name))))
        return _COMMASPACE_.join(t)
Exemple #3
0
    def trilaterate5(
            self,
            distance1,
            point2,
            distance2,
            point3,
            distance3,  # PYCHOK signature
            area=False,
            eps=EPS1,
            radius=R_M,
            wrap=False):
        '''B{Not implemented} for C{B{area}=True} or C{B{wrap}=True}
           and falls back to method C{trilaterate} otherwise.

           @return: A L{Trilaterate5Tuple}C{(min, minPoint, max, maxPoint, n)}
                    with a single trilaterated intersection C{minPoint I{is}
                    maxPoint}, C{min I{is} max} the nearest intersection
                    margin and count C{n = 1}.

           @raise IntersectionError: No intersection, trilateration failed.

           @raise NotImplementedError: Keyword argument C{B{area}=True} or
                                       B{C{wrap}=True} not (yet) supported.

           @raise TypeError: Invalid B{C{point2}} or B{C{point3}}.

           @raise ValueError: Some B{C{points}} coincide or invalid B{C{distance1}},
                              B{C{distance2}}, B{C{distance3}} or B{C{radius}}.
        '''
        if area or wrap:
            from pygeodesy.named import notImplemented
            notImplemented(self, self.trilaterate5, area=area, wrap=wrap)

        t = _trilaterate(self,
                         distance1,
                         self.others(point2=point2),
                         distance2,
                         self.others(point3=point3),
                         distance3,
                         radius=radius,
                         height=None,
                         useZ=True,
                         LatLon=self.classof)
        # ... and handle B{C{eps}} and C{IntersectionError} as
        # method C{.latlonBase.LatLonBase.trilaterate2}
        d = self.distanceTo(t, radius=radius, wrap=wrap)  # PYCHOK distanceTo
        d = abs(distance1 - d), abs(distance2 - d), abs(distance3 - d)
        d = float(min(d))
        if d < eps:  # min is max, minPoint is maxPoint
            return Trilaterate5Tuple(d, t, d, t, 1)  # n = 1
        t = _SPACE_(_no_(_intersection_),
                    Fmt.PAREN(min.__name__, Fmt.f(d, prec=3)))
        raise IntersectionError(area=area, eps=eps, wrap=wrap, txt=t)
Exemple #4
0
 def __setitem__(self, key, value):
     '''Set item B{C{key}} to B{C{value}}.
     '''
     if key == _name_:
         raise KeyError(
             _EQUAL_(Fmt.SQUARE(self.classname, key), repr(value)))
     dict.__setitem__(self, key, value)
Exemple #5
0
    def latlon(self, latlonh):
        '''Set the lat- and longitude and optionally the height.

           @arg latlonh: New lat-, longitude and height (2- or
                        3-tuple of C{degrees} and C{meter}).

           @raise TypeError: Height of B{C{latlonh}} not C{scalar} or
                             B{C{latlonh}} not C{list} or C{tuple}.

           @raise ValueError: Invalid B{C{latlonh}} or M{len(latlonh)}.

           @see: Function L{parse3llh} to parse a B{C{latlonh}} string
                 into a 3-tuple (lat, lon, h).
        '''
        _xinstanceof(list, tuple, latlonh=latlonh)

        if len(latlonh) == 3:
            h = Height(latlonh[2], name=Fmt.SQUARE(latlonh=2))
        elif len(latlonh) != 2:
            raise _ValueError(latlonh=latlonh)
        else:
            h = self._height

        lat = Lat(latlonh[0])  # parseDMS2(latlonh[0], latlonh[1])
        lon = Lon(latlonh[1])
        self._update(lat != self._lat or
                     lon != self._lon or h != self._height)
        self._lat, self._lon, self._height = lat, lon, h
Exemple #6
0
def _notError(inst, name, args, kwds):  # PYCHOK no cover
    '''(INTERNAL) Format an error message.
    '''
    n = _DOT_(classname(inst, prefixed=True), _dunder_name(name, name))
    m = _COMMASPACE_.join(
        modulename(c, prefixed=True) for c in inst.__class__.__mro__[1:-1])
    return _COMMASPACE_(unstr(n, *args, **kwds), Fmt.PAREN(_MRO_, m))
Exemple #7
0
    def _all(globalocals):
        from pygeodesy.interns import NN as _NN, _attribute_, _COMMASPACE_, \
                                     _DOT_, _module_, _s_  # PYCHOK expected
        from pygeodesy.streprs import Fmt as _Fmt  # PYCHOK expected
        # collect all public module and attribute names and check
        # that modules are imported from this package, 'pygeodesy'
        # (but the latter only when not bundled with PyInstaller or
        # Py2Exe, since the file-layout is different.  Courtesy of
        # GilderGeek<https://GitHub.com/mrJean1/PyGeodesy/issues/31>)
        ns = list(lazily._ALL_INIT)
        # XXX   ps = () if _isfrozen else set([_pygeodesy_] + __name__.split(_DOT_))
        for mod, attrs in lazily._ALL_LAZY.enums():
            if mod not in globalocals:
                t = _DOT_(_pygeodesy_, mod)
                raise ImportError('missing %s%s: %s' % (_module_, _NN, t))
            ns.append(mod)
            # check that all other public attributes do exist
            if attrs and isinstance(attrs, tuple):
                t = tuple(a for a in attrs if a not in globalocals)
                if t:
                    s = _Fmt.SQUARE(_s_, len(t)) if len(t) > 1 else _NN
                    t = _COMMASPACE_.join(
                        _DOT_(_pygeodesy_, mod, a) for a in t)
                    raise ImportError('missing %s%s: %s' % (_attribute_, s, t))
                ns.extend(attrs)
# XXX       if ps:  # check that mod is a _pygeodesy_ module
# XXX           m = globalocals[mod]  # assert(m.__name__ == mod)
# XXX           f = getattr(m, '__file__', _NN)
# XXX           d = dirname(abspath(f)) if f else pygeodesy_abspath
# XXX           p = getattr(m, '__package__', _NN) or _pygeodesy_
# XXX           if p not in ps or d != pygeodesy_abspath:
# XXX               raise ImportError('foreign module: %s from %r' % (_DOT_(p, mod), f or p))
        return tuple(set(ns))  # remove duplicates
Exemple #8
0
 def utmupsStr(self, B=False):
     '''Get the UTM/UPS zone, band and hemisphere/-pole (C{str}).
     '''
     b = self.band if B else NN
     h = s = self.hemisphere
     if h:
         s = _SPACE_
     return NN(Fmt.zone(self.zone), b, s, h)
Exemple #9
0
def _xkwds_Error(_xkwds_func, kwds, name_txt, txt='default'):
    # Helper for _xkwds_get and _xkwds_pop below
    from pygeodesy.streprs import Fmt, pairs
    f = _COMMASPACE_.join(pairs(kwds) + pairs(name_txt))
    f = Fmt.PAREN(_xkwds_func.__name__, f)
    t = _multiple_ if name_txt else _no_
    t = _SPACE_(t, _EQUAL_(_name_, txt), 'kwargs')
    return _AssertionError(f, txt=t)
Exemple #10
0
 def __getattr__(self, name):
     '''Get the value of an attribute or item by B{C{name}}.
     '''
     try:
         return tuple.__getitem__(self, self._Names_.index(name))
     except IndexError:
         raise _IndexError(_DOT_(self.classname, Fmt.ANGLE(_name_)), name)
     except ValueError:
         return tuple.__getattribute__(self, name)
Exemple #11
0
    def toRepr(self, **kwds):  # PYCHOK expected
        '''(INTERNAL) I{Could be overloaded}.

           @kwarg kwds: Optional, keyword arguments.

           @return: C{toStr}() with keyword arguments (as C{str}).
        '''
        t = self.toStr(**kwds).lstrip('([{').rstrip('}])')
        return Fmt.PAREN(self.classname, t)  # XXX (self.named, t)
Exemple #12
0
def _intersects2(center1, r1, center2, r2, sphere=True, too_d=None,  # in .ellipsoidalBase._intersections2
                                           Vector=None, **Vector_kwds):
    # (INTERNAL) Intersect two spheres or circles, see L{intersections2}
    # above, separated to allow callers to embellish any exceptions

    def _V3(x, y, z):
        v = Vector3d(x, y, z)
        n = intersections2.__name__
        return _V_n(v, n, Vector, Vector_kwds)

    def _xV3(c1, u, x, y):
        xy1 = x, y, _1_0  # transform to original space
        return _V3(fdot(xy1, u.x, -u.y, c1.x),
                   fdot(xy1, u.y,  u.x, c1.y), _0_0)

    c1 = _otherV3d(sphere=sphere, center1=center1)
    c2 = _otherV3d(sphere=sphere, center2=center2)

    if r1 < r2:  # r1, r2 == R, r
        c1, c2 = c2, c1
        r1, r2 = r2, r1

    m = c2.minus(c1)
    d = m.length
    if d < max(r2 - r1, EPS):
        raise ValueError(_near_concentric_)

    o = fsum_(-d, r1, r2)  # overlap == -(d - (r1 + r2))
    # compute intersections with c1 at (0, 0) and c2 at (d, 0), like
    # <https://MathWorld.Wolfram.com/Circle-CircleIntersection.html>
    if o > EPS:  # overlapping, r1, r2 == R, r
        x = _radical2(d, r1, r2).xline
        y = _1_0 - (x / r1)**2
        if y > EPS:
            y = r1 * sqrt(y)  # y == a / 2
        elif y < 0:
            raise ValueError(_invalid_)
        else:  # abutting
            y = _0_0
    elif o < 0:
        t = d if too_d is None else too_d
        raise ValueError(_too_(Fmt.distant(t)))
    else:  # abutting
        x, y = r1, _0_0

    u = m.unit()
    if sphere:  # sphere center and radius
        c = c1 if x < EPS  else (
            c2 if x > EPS1 else c1.plus(u.times(x)))
        t = _V3(c.x, c.y, c.z), Radius(y)

    elif y > 0:  # intersecting circles
        t = _xV3(c1, u, x, y), _xV3(c1, u, x, -y)
    else:  # abutting circles
        t = _xV3(c1, u, x, 0)
        t = t, t
    return t
Exemple #13
0
def _callname(name, class_name, self_name, up=1):  # imported by .points
    '''(INTERNAL) Assemble the name for an invokation.
    '''
    n, c = class_name, callername(up=up + 1)
    if c:
        n = _DOT_(n, Fmt.PAREN(c, name))
    if self_name:
        n = _SPACE_(n, repr(self_name))
    return n
Exemple #14
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 C{B{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=x)
        y = Scalar(y=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 *= _Karney_eps

        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_(Fmt.convergence(e)))

        t = self._7Tuple(x, y, r, r.M12) if LatLon is None else \
            self._toLatLon(r.lat2, r.lon2, LatLon, LatLon_kwds)

        t._iteration = self._iteration
        return self._xnamed(t, name=name)
Exemple #15
0
def _xml(tag, xml):
    '''(INTERNAL) Get a <tag>value</tag> from XML.
    '''
    # b'<?xml version="1.0" encoding="utf-8" ?>
    #   <USGS_Elevation_Point_Query_Service>
    #    <Elevation_Query x="-121.914200" y="37.881600">
    #     <Data_Source>3DEP 1/3 arc-second</Data_Source>
    #     <Elevation>3851.03</Elevation>
    #     <Units>Feet</Units>
    #    </Elevation_Query>
    #   </USGS_Elevation_Point_Query_Service>'
    i = xml.find(Fmt.TAG(tag))
    if i > 0:
        i += len(tag) + 2
        j = xml.find(Fmt.TAGEND(tag), i)
        if j > i:
            return Str(xml[i:j].strip(), name=tag)
    return _no_(_XML_, Fmt.TAG(tag))
Exemple #16
0
    def __init__(self, knots, weight=None, name=NN):
        '''New L{HeightLSQBiSpline} interpolator.

           @arg knots: The points with known height (C{LatLon}s).
           @kwarg weight: Optional weight or weights for each B{C{knot}}
                          (C{scalar} or C{scalar}s).
           @kwarg name: Optional name for this height interpolator (C{str}).

           @raise HeightError: Insufficient number of B{C{knots}} or
                               an invalid B{C{knot}} or B{C{weight}}.

           @raise LenError: Unequal number of B{C{knots}} and B{C{weight}}s.

           @raise ImportError: Package C{numpy} or C{scipy} not found
                               or not installed.

           @raise SciPyError: A C{LSQSphereBivariateSpline} issue.

           @raise SciPyWarning: A C{LSQSphereBivariateSpline} warning
                                as exception.
        '''
        np, spi = self._NumSciPy()

        xs, ys, hs = self._xyhs3(knots)
        n = len(hs)

        w = weight
        if isscalar(w):
            w = float(w)
            if w <= 0:
                raise HeightError(weight=w)
            w = [w] * n
        elif w is not None:
            m, w = len2(w)
            if m != n:
                raise LenError(HeightLSQBiSpline, weight=m, knots=n)
            w = map2(float, w)
            m = min(w)
            if m <= 0:
                raise HeightError(Fmt.SQUARE(weight=w.find(m)), m)
        try:
            T = 1.0e-4  # like SciPy example
            ps = np.array(_ordedup(xs, T, PI2 - T))
            ts = np.array(_ordedup(ys, T, PI - T))
            self._ev = spi.LSQSphereBivariateSpline(ys,
                                                    xs,
                                                    hs,
                                                    ts,
                                                    ps,
                                                    eps=EPS,
                                                    w=w).ev
        except Exception as x:
            raise _SciPyIssue(x)

        if name:
            self.name = name
Exemple #17
0
    def _DDDMMSS_(strDDDMMSS, suffix, sep, clip):
        S = suffix.upper()
        if isstr(strDDDMMSS):
            t = strDDDMMSS.strip()
            if sep:
                t = t.replace(sep, NN).strip()

            s = t[:1]  # sign or digit
            P = t[-1:]  # compass point, digit or dot

            t = t.lstrip(_PLUSMINUS_).rstrip(S).strip()
            f = t.split(_DOT_)
            d = len(f[0])
            f = NN.join(f)
            if 1 < d < 8 and f.isdigit() and (
                (P in S and s.isdigit()) or
                (P.isdigit() and s in '-0123456789+'  # PYCHOK indent
                 and S in ((_NS_, _EW_) + _WINDS))):
                # check [D]DDMMSS form and compass point
                X = _EW_ if (d & 1) else _NS_
                if not (P in X or (S in X and (P.isdigit() or P == _DOT_))):
                    t = 'DDDMMSS'[d & 1 ^ 1:d | 1], X[:1], X[1:]
                    raise ParseError('form %s applies %s-%s' % t)
                f = 0  # fraction
            else:  # try other forms
                return _DMS2deg(strDDDMMSS, S, sep, clip)

        else:  # float or int to [D]DDMMSS[.fff]
            f = float(strDDDMMSS)
            s = _MINUS_ if f < 0 else NN
            P = _0_  # anything except _SW_
            f, i = modf(abs(f))
            t = Fmt.f(i, prec=0)  # str(i) == 'i.0'
            d = len(t)
            # bump number of digits to match
            # the given, valid compass point
            if S in (_NS_ if (d & 1) else _EW_):
                t = _0_ + t
                d += 1
            #   P = S
            # elif d > 1:
            #   P = (_EW_ if (d & 1) else _NS_)[0]

        if d < 4:  # [D]DD[.ddd]
            if f:
                t = float(t) + f
            t = t, 0, 0
        else:
            f += float(t[d - 2:])
            if d < 6:  # [D]DDMM[.mmm]
                t = t[:d - 2], f, 0
            else:  # [D]DDMMSS[.sss]
                t = t[:d - 4], t[d - 4:d - 2], f
        d = _dms2deg(s, P, *map2(float, t))

        return clipDegrees(d, float(clip)) if clip else d
Exemple #18
0
 def _points2(self, points):
     '''(INTERNAL) Check a set of points.
     '''
     np, ps = Hausdorff._points2(self, points)
     for i, p in enumerate(ps):
         if not callable(getattr(p, _distanceTo_, None)):
             raise HausdorffError(Fmt.SQUARE(_points_, i),
                                  p,
                                  txt=_distanceTo_)
     return np, ps
Exemple #19
0
 def _txt(c1, r1, c2, r2):
     # check for concentric or too distant spheres
     d = c1.minus(c2).length
     if d < abs(r1 - r2):
         t = _near_concentric_
     elif d > (r1 + r2):
         t = _too_(Fmt.distant(d))
     else:
         return NN
     return _SPACE_(c1.name, 'and', c2.name, t)
Exemple #20
0
    def __new__(cls,
                arg=None,
                name=_degrees_,
                Error=UnitError,
                suffix=_NSEW_,
                low=None,
                high=None,
                **name_arg):
        '''New named C{Degrees} instance.

           @arg cls: This class (C{Degrees_} or sub-class).
           @kwarg arg: The value (any C{type} convertable to C{float} or
                       parsable by L{parseDMS}).
           @kwarg name: Optional instance name (C{str}).
           @kwarg Error: Optional error to raise, overriding the default
                         L{UnitError}.
           @kwarg suffix: Optional, valid compass direction suffixes (C{NSEW}).
           @kwarg low: Optional lower B{C{arg}} limit (C{float} or C{None}).
           @kwarg high: Optional upper B{C{arg}} limit (C{float} or C{None}).
           @kwarg name_arg: Optional C{name=arg} keyword argument,
                            inlieu of B{C{name}} and B{C{arg}}.

           @returns: A C{Degrees} instance.

           @raise Error: Invalid B{C{arg}} or B{C{abs(deg)}} below B{C{low}}
                         or above B{C{high}}.
        '''
        if name_arg:
            name, arg = _xkwds_popitem(name_arg)
        self = Degrees.__new__(cls,
                               arg=arg,
                               name=name,
                               Error=Error,
                               suffix=suffix,
                               clip=0)
        if (low is not None) and self < low:
            txt = Fmt.limit(below=low)
        elif (high is not None) and self > high:
            txt = Fmt.limit(above=high)
        else:
            return self
        raise _Error(cls, arg, name=name, Error=Error, txt=txt)
Exemple #21
0
 def _toStr(self, hemipole, B, cs, prec, sep):
     '''(INTERNAL) Return a string for this ETM/UTM/UPS coordinate.
     '''
     z = NN(Fmt.zone(self.zone), (self.band if B else NN))  # PYCHOK band
     t = (z, hemipole) + _fstrENH2(self, prec, None)[0]
     if cs:
         prec = cs if isint(cs) else 8  # for backward compatibility
         t += (_n_a_ if self.convergence is None else degDMS(
             self.convergence, prec=prec, pos=_PLUS_),
               _n_a_ if self.scale is None else fstr(self.scale, prec=prec))
     return t if sep is None else sep.join(t)
Exemple #22
0
 def _instr(self, prec, *attrs, **kwds):
     '''(INTERNAL) Format, used by C{Conic}, C{Ellipsoid}, C{Transform}.
     '''
     t = Fmt.EQUAL(_name_, repr(self.name)),
     if attrs:
         t += pairs(((a, getattr(self, a)) for a in attrs),
                    prec=prec,
                    ints=True)
     if kwds:
         t += pairs(kwds, prec=prec)
     return _COMMASPACE_.join(t)
Exemple #23
0
    def toStr(self, prec=6, sep=_COMMASPACE_, **unused):  # PYCHOK signature
        '''Return this C{Named-Tuple} items as string(s).

           @kwarg prec: The C{float} precision, number of decimal digits (0..9).
                        Trailing zero decimals are stripped for B{C{prec}} values
                        of 1 and above, but kept for negative B{C{prec}} values.
           @kwarg sep: Optional separator to join (C{str}).

           @return: Tuple items (C{str}).
        '''
        return Fmt.PAREN(sep.join(reprs(self, prec=prec)))
Exemple #24
0
    def _validate(self, _OK=False):  # see .EcefMatrix
        '''(INTERNAL) One-time check of C{_Names_} and C{_Units_}
           for each C{_NamedUnit} I{sub-class separately}.
        '''
        ns = self._Names_
        if not (isinstance(ns, tuple) and len(ns) > 1):  # XXX > 0
            raise _TypeError(_DOT_(self.classname, _Names_), ns)
        for i, n in enumerate(ns):
            if not _xvalid(n, _OK=_OK):
                t = Fmt.SQUARE(_Names_, i)
                raise _ValueError(_DOT_(self.classname, t), n)

        us = self._Units_
        if not isinstance(us, tuple):
            raise _TypeError(_DOT_(self.classname, _Units_), us)
        if len(us) != len(ns):
            raise LenError(self.__class__, _Units_=len(us), _Names_=len(ns))
        for i, u in enumerate(us):
            if not (u is None or callable(u)):
                t = Fmt.SQUARE(_Units_, i)
                raise _TypeError(_DOT_(self.classname, t), u)

        self.__class__._validated = True
Exemple #25
0
def _xyhs(lls, off=True, name='llis'):
    # map (lat, lon, h) to (x, y, h) in radians, offset as
    # x: 0 <= lon <= PI2, y: 0 <= lat <= PI if off is True
    # else x: -PI <= lon <= PI, y: -PI_2 <= lat <= PI_2
    if off:
        xf = yf = _0_0
    else:  # undo offset
        xf, yf = PI, PI_2
    try:
        for i, ll in enumerate(lls):
            yield (max(0.0, radiansPI2(ll.lon + 180.0)) - xf), \
                  (max(0.0, radiansPI( ll.lat +  90.0)) - yf), ll.height
    except AttributeError as x:
        raise HeightError(Fmt.SQUARE(name, i), ll, txt=str(x))
Exemple #26
0
    def add(self, key, value, *values):
        '''Add C{[key] = value}, typically C{[attr] = mod}.

           @raise AssertionError: The B{C{key}} already
                                  exists with different
                                  B{C{value}}.
        '''
        if key in self:
            val = self[key]  # duplicate OK
            if val != value and val not in values:  # PYCHOK no cover
                from pygeodesy.streprs import Fmt as _Fmt
                t = _Fmt.SQUARE(_imports_, key), val, value
                raise AssertionError('%s: %r, not %r' % t)
        else:
            self[key] = value
Exemple #27
0
    def __init__(self, where, **lens_txt):  # txt=None
        '''New L{LenError}.

           @arg where: Object with C{.__name__} attribute
                       (C{class}, C{method}, or C{function}).
           @kwarg lens_txt: Two or more C{name=len(name)} pairs
                            (C{keyword arguments}).
        '''
        from pygeodesy.streprs import Fmt as _Fmt
        x = _xkwds_pop(lens_txt, txt=_invalid_)
        ns, vs = zip(*sorted(lens_txt.items()))
        ns = _COMMASPACE_.join(ns)
        vs = ' vs '.join(map(str, vs))
        t = _SPACE_(_Fmt.PAREN(where.__name__, ns), _len_, vs)
        _ValueError.__init__(self, t, txt=x)
Exemple #28
0
def elevation2(lat, lon, timeout=2.0):
    '''Get the geoid elevation at an C{NAD83} to C{NAVD88} location.

       @arg lat: Latitude (C{degrees}).
       @arg lon: Longitude (C{degrees}).
       @kwarg timeout: Optional, query timeout (seconds).

       @return: An L{Elevation2Tuple}C{(elevation, data_source)}
                or (C{None, "error"}) in case of errors.

       @raise ValueError: Invalid B{C{timeout}}.

       @note: The returned C{elevation} is C{None} if B{C{lat}} or B{C{lon}}
              is invalid or outside the C{Conterminous US (CONUS)},
              if conversion failed or if the query timed out.  The
              C{error} is the C{HTTP-, IO-, SSL-, Type-, URL-} or
              C{ValueError} as a string (C{str}).

       @see: U{USGS National Map<https://NationalMap.gov/epqs>},
             the U{FAQ<https://www.USGS.gov/faqs/what-are-projection-
             horizontal-and-vertical-datum-units-and-resolution-3dep-standard-dems>},
             U{geoid.py<https://Gist.GitHub.com/pyRobShrk>}, module
             L{geoids}, classes L{GeoidG2012B}, L{GeoidKarney} and
             L{GeoidPGM}.
    '''
    try:
        x = _qURL('https://NED.USGS.gov/epqs/pqs.php',  # 'https://NationalMap.gov/epqs/pqs.php'
                         x=Lon(lon).toStr(prec=6),
                         y=Lat(lat).toStr(prec=6),
                         units='Meters',  # 'Feet', capitalized
                         output=_XML_.lower(),  # _JSON_, lowercase only
                         timeout=Scalar(timeout=timeout))
        if x[:6] == '<?xml ':
            e = _xml('Elevation', x)
            try:
                e = float(e)
                if -1000000 < e < 1000000:
                    return Elevation2Tuple(e, _xml('Data_Source', x))
                e = 'non-CONUS %.2F' % (e,)
            except (TypeError, ValueError):
                pass
        else:
            e = _no_(_XML_, Fmt.QUOTE2(clips(x, limit=128, white=_SPACE_)))
    except (HTTPError, IOError, TypeError, ValueError) as x:
        e = repr(x)
    e = _error(elevation2, lat, lon, e)
    return Elevation2Tuple(None, e)
Exemple #29
0
def _qURL(url, timeout=2, **params):
    '''(INTERNAL) Build B{C{url}} query, get and verify response.
    '''
    if params:  # build url query, don't map(quote, params)!
        p = '&'.join(Fmt.EQUAL(p, v) for p, v in params.items() if v)
        if p:
            url = NN(url, '?', p)
    u = urlopen(url, timeout=timeout)  # secs

    s = u.getcode()
    if s != 200:  # http.HTTPStatus.OK or http.client.OK
        raise IOError('code %d: %s' % (s, u.geturl()))

    r = u.read()
    u.close()
    # urlcleanup()
    return ub2str(r).strip()
Exemple #30
0
def geoidHeight2(lat, lon, model=0, timeout=2.0):
    '''Get the C{NAVD88} geoid height at an C{NAD83} location.

       @arg lat: Latitude (C{degrees}).
       @arg lon: Longitude (C{degrees}).
       @kwarg model: Optional, geoid model ID (C{int}).
       @kwarg timeout: Optional, query timeout (seconds).

       @return: An L{GeoidHeight2Tuple}C{(height, model_name)}
                or C{(None, "error"}) in case of errors.

       @raise ValueError: Invalid B{C{timeout}}.

       @note: The returned C{height} is C{None} if B{C{lat}} or B{C{lon}} is
              invalid or outside the C{Conterminous US (CONUS)}, if the
              B{C{model}} was invalid, if conversion failed or if the
              query timed out.  The C{error} is the C{HTTP-, IO-, SSL-,
              Type-, URL-} or C{ValueError} as a string (C{str}).

       @see: U{NOAA National Geodetic Survey
             <https://www.NGS.NOAA.gov/INFO/geodesy.shtml>},
             U{Geoid<https://www.NGS.NOAA.gov/web_services/geoid.shtml>},
             U{USGS10mElev.py<https://Gist.GitHub.com/pyRobShrk>}, module
             L{geoids}, classes L{GeoidG2012B}, L{GeoidKarney} and
             L{GeoidPGM}.
    '''
    try:
        j = _qURL('https://Geodesy.NOAA.gov/api/geoid/ght',
                         lat=Lat(lat).toStr(prec=6),
                         lon=Lon(lon).toStr(prec=6),
                         model=(model if model else NN),
                         timeout=Scalar(timeout=timeout))  # PYCHOK indent
        if j[:1] == '{' and j[-1:] == '}' and j.find('"error":') > 0:
            d, e = _json(j), 'geoidHeight'
            if isinstance(_xkwds_get(d, error=_n_a_), float):
                h = d.get(e, None)
                if h is not None:
                    m = _xkwds_get(d, geoidModel=_n_a_)
                    return GeoidHeight2Tuple(h, m)
        else:
            e = _JSON_
        e = _no_(e, Fmt.QUOTE2(clips(j, limit=256, white=_SPACE_)))
    except (HTTPError, IOError, ParseError, TypeError, ValueError) as x:
        e = repr(x)
    e = _error(geoidHeight2, lat, lon, e)
    return GeoidHeight2Tuple(None, e)