Example #1
0
def fidw(xs, ds, beta=2):
    '''Interpolate using using U{Inverse Distance Weighting
       <https://WikiPedia.org/wiki/Inverse_distance_weighting>} (IDW).

       @arg xs: Known values (C{scalar}[]).
       @arg ds: Non-negative distances (C{scalar}[]).
       @kwarg beta: Inverse distance power (C{int}, 0, 1, 2, or 3).

       @return: Interpolated value C{x} (C{float}).

       @raise ValueError: Invalid B{C{beta}}, negative B{C{ds}} value,
                          weighted B{C{ds}} below L{EPS} or unequal
                          C{len}C{(}B{C{ds}}C{)} and C{len}C{(}B{C{xs}}C{)}.

       @note: Using B{C{beta}}C{=0} returns the mean of B{C{xs}}.
    '''
    n, xs = len2(xs)
    d, ds = len2(ds)
    if n != d or n < 1:
        raise LenError(fidw, xs=n, ds=d)

    d, x = min(zip(ds, xs))
    if d > EPS and n > 1:
        b = -Int_(beta, name=_beta_, low=0, high=3)
        if b < 0:
            ds = tuple(d**b for d in ds)
            d = fsum(ds)
            if d < EPS:
                raise _ValueError(ds=d)
            x = fdot(xs, *ds) / d
        else:
            x = fmean(xs)
    elif d < 0:
        raise _ValueError(_item_sq('ds', ds.index(d)), d)
    return x
Example #2
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=_item_sq(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
Example #3
0
 def _points2(self, points):
     '''(INTERNAL) Check a set of points.
     '''
     np, ps = Frechet._points2(self, points)
     for i, p in enumerate(ps):
         if not callable(getattr(p, _distanceTo_, None)):
             raise FrechetError(_item_sq(_points_, i), p, txt=_distanceTo_)
     return np, ps
Example #4
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: Number of B{C{knots}} and B{C{weight}}s
                            don't match.

           @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(_item_sq(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
Example #5
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(_item_sq(name, i), ll, txt=str(x))
Example #6
0
    def __init__(self, knots, beta=2, name=NN, **distanceTo_kwds):
        '''New L{HeightIDWdistanceTo} interpolator.

           @arg knots: The points with known height (C{LatLon}s).
           @kwarg beta: Inverse distance power (C{int} 1, 2, or 3).
           @kwarg name: Optional name for this height interpolator (C{str}).
           @kwarg distanceTo_kwds: Optional keyword arguments for the
                                   B{C{points}}' C{LatLon.distanceTo}
                                   method.

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

           @raise ImportError: Package U{geographiclib
                  <https://PyPI.org/project/geographiclib>} missing
                  iff B{C{points}} are L{ellipsoidalKarney.LatLon}s.

           @note: All B{C{points}} I{must} be instances of the same
                  ellipsoidal or spherical C{LatLon} class, I{not
                  checked however}.
        '''
        n, self._ks = len2(knots)
        if n < self._kmin:
            raise _insufficientError(self._kmin, knots=n)
        for i, k in enumerate(self._ks):
            if not callable(getattr(k, _distanceTo_, None)):
                raise HeightError(_item_sq(_knots_, i), k, txt=_distanceTo_)

        # use knots[0] class and datum to create
        # compatible points in _HeightBase._height
        # instead of class LatLon_ and datum None
        self._datum = self._ks[0].datum
        self._LLis = self._ks[0].classof

        self.beta = beta
        if name:
            self.name = name
        if distanceTo_kwds:
            self._distanceTo_kwds = distanceTo_kwds
Example #7
0
def points2(points, closed=True, base=None, Error=PointsError):
    '''Check a path or polygon represented by points.

       @arg points: The path or polygon points (C{LatLon}[])
       @kwarg closed: Optionally, consider the polygon closed,
                      ignoring any duplicate or closing final
                      B{C{points}} (C{bool}).
       @kwarg base: Optionally, check all B{C{points}} against
                    this base class, if C{None} don't check.
       @kwarg Error: Exception to raise (C{ValueError}).

       @return: A L{Points2Tuple}C{(number, points)} with the number
                of points and the points C{list} or C{tuple}.

       @raise PointsError: Insufficient number of B{C{points}}.

       @raise TypeError: Some B{C{points}} are not B{C{base}}
                         compatible.
    '''
    n, points = len2(points)

    if closed:
        # remove duplicate or closing final points
        while n > 1 and points[n - 1] in (points[0], points[n - 2]):
            n -= 1
        # XXX following line is unneeded if points
        # are always indexed as ... i in range(n)
        points = points[:n]  # XXX numpy.array slice is a view!

    if n < (3 if closed else 1):
        raise Error(points=n, txt=_too_few_)

    if base and not (isNumpy2(points) or isTuple2(points)):
        for i in range(n):
            base.others(points[i], name=_item_sq(points=i))

    return Points2Tuple(n, points)
Example #8
0
def _all_imports(**more):
    '''(INTERNAL) Build C{dict} of all lazy imports.
    '''
    # imports naming conventions stored below - [<key>] = <from>:
    #  import <module>                        - [<module>] = <module>
    #  from <module> import <attr>            - [<attr>] = <module>
    #  from pygeodesy import <attr>           - [<attr>] = <attr>
    #  from <module> import <attr> as <name>  - [<name>] = <module>.<attr>
    imports = {}
    for _all_ in (_ALL_LAZY, _ALL_OVERRIDING, more):
        for mod, attrs in _all_.items():
            if isinstance(attrs, tuple) and not mod.startswith(_UNDERSCORE_):
                if mod not in imports:
                    imports[mod] = mod
                elif imports[mod] != mod:
                    t = _item_sq('imports', 'mod'), imports[mod], mod
                    raise AssertionError('%s: %r, not %r' % t)
                for attr in attrs:
                    attr, _, _as_ = attr.partition(' as ')
                    if _as_:
                        imports[_as_] = mod + _DOT_ + attr
                    else:
                        imports[attr] = mod
    return imports
Example #9
0
 def _xy2(lls):
     try:  # like _xyhs above, but keeping degrees
         for i, ll in enumerate(lls):
             yield ll.lon, ll.lat
     except AttributeError as x:
         raise HeightError(_item_sq('llis', i), ll, txt=str(x))
Example #10
0
 def __setitem__(self, key, value):
     if key == _name_:
         raise KeyError('%s = %r' % (_item_sq(self.classname, key), value))
     dict.__setitem__(self, key, value)
Example #11
0
 def __getitem__(self, key):
     if key == _name_:
         raise KeyError(_item_sq(self.classname, key))
     return dict.__getitem__(self, key)
Example #12
0
 def _Error(i):
     return WGRSError(_item_sq(georef=i), georef)
    def isenclosedBy(self, points):
        '''Check whether a (convex) polygon encloses this point.

           @arg points: The polygon points (L{LatLon}[]).

           @return: C{True} if the polygon encloses this point,
                    C{False} otherwise.

           @raise PointsError: Insufficient number of B{C{points}}.

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

           @raise ValueError: Invalid B{C{points}}, non-convex polygon.

           @example:

           >>> b = LatLon(45,1), LatLon(45,2), LatLon(46,2), LatLon(46,1)
           >>> p = LatLon(45,1, 1.1)
           >>> inside = p.isEnclosedBy(b)  # True
        '''
        n, points = self.points2(points, closed=True)

        n0 = self._N_vector

        if iterNumpy2(points):

            v1 = points[n - 1]._N_vector
            v2 = points[n - 2]._N_vector
            gc1 = v2.cross(v1)
            t0 = gc1.angleTo(n0) > PI_2
            for i in range(n):
                v2 = points[i]._N_vector
                gc = v1.cross(v2)
                v1 = v2

                ti = gc.angleTo(n0) > PI_2
                if ti != t0:
                    return False  # outside

                if gc1.angleTo(gc, vSign=n0) < 0:
                    raise _ValueError(_item_sq(points=i),
                                      points[i],
                                      txt=_not_convex_)
                gc1 = gc

        else:
            # get great-circle vector for each edge
            gc, v1 = [], points[n - 1]._N_vector
            for i in range(n):
                v2 = points[i]._N_vector
                gc.append(v1.cross(v2))
                v1 = v2

            # check whether this point on same side of all
            # polygon edges (to the left or right depending
            # on anti-/clockwise polygon direction)
            t0 = gc[0].angleTo(n0) > PI_2  # True if on the right
            for i in range(1, n):
                ti = gc[i].angleTo(n0) > PI_2
                if ti != t0:  # different sides of edge i
                    return False  # outside

            # check for convex polygon (otherwise
            # the test above is not reliable)
            gc1 = gc[n - 1]
            for i, gc2 in enumerate(gc):
                # angle between gc vectors, signed by direction of n0
                if gc1.angleTo(gc2, vSign=n0) < 0:
                    raise _ValueError(_item_sq(points=i),
                                      points[i],
                                      txt=_not_convex_)
                gc1 = gc2

        return True  # inside
Example #14
0
 def _Error(i):
     return GARSError(garef=_item_sq(repr(garef), i))