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
def _height(self, lats, lons, Error=HeightError): if isscalar(lats) and isscalar(lons): llis = LatLon_(lats, lons) else: n, lats = len2(lats) m, lons = len2(lons) if n != m: raise Error('non-matching %s: %s vs %s' % ('len', n, m)) llis = [LatLon_(*ll) for ll in zip(lats, lons)] return self(llis) # __call__(lli) or __call__(llis)
def _height(self, lats, lons, Error=HeightError): LLis, d = self._LLis, self.datum if isscalar(lats) and isscalar(lons): llis = LLis(lats, lons, datum=d) else: n, lats = len2(lats) m, lons = len2(lons) if n != m: # format a LenError, but raise an Error e = LenError(self.__class__, lats=n, lons=m, txt=None) raise e if Error is LenError else Error(str(e)) llis = [LLis(*ll, datum=d) for ll in zip(lats, lons)] return self(llis) # __call__(lli) or __call__(llis)
def __init__(self, points, tolerance, radius, shortest, indices, **options): '''New C{Simplify} state. ''' n, self.pts = len2(points) if n > 0: self.n = n self.r = {0: True, n - 1: True} # dict to avoid duplicates if isNumpy2(points) or isTuple2(points): # NOT self.pts self.subset = points.subset if indices: self.indices = True if radius: self.radius = float(radius) if self.radius < self.eps: raise ValueError('%s too small: %.6e' % ('radius', radius)) if options: self.options = options # tolerance converted to degrees squared self.s2 = degrees(tolerance / self.radius)**2 if min(self.s2, tolerance) < self.eps: raise ValueError('%s too small: %.6e' % ('tolerance', tolerance)) self.s2e = self.s2 + 1 # sentinel # compute either the shortest or perpendicular distance self.d2i = self.d2iS if shortest else self.d2iP # PYCHOK false
def hypot_(*xs): '''Compute the norm M{sqrt(sum(xs[i]**2)) for i=0..len(xs)}. @arg xs: X arguments, positional (C{scalar}[]). @return: Norm (C{float}). @raise OverflowError: Partial C{2sum} overflow. @raise ValueError: Invalid or no B{C{xs}} value. @see: Similar to Python 3.8+ U{math.hypot <https://docs.Python.org/3.8/library/math.html#math.hypot>}, but handling of exceptions, C{nan} and C{infinite} values is different. @note: The Python 3.8+ U{math.dist <https://docs.Python.org/3.8/library/math.html#math.dist>} Euclidian distance between 2 I{n}-dimensional points I{p1} and I{p2} can be computed as M{hypot_(*((c1 - c2) for c1, c2 in zip(p1, p2)))}, provided I{p1} and I{p2} have the same, non-zero length I{n}. ''' if xs: n, xs = len2(xs) if n > 0: h = float(max(abs(x) for x in xs)) if h > 0 and n > 1: X = Fsum(1.0) X.fadd((x / h)**2 for x in xs) h *= sqrt(X.fsum_(-1.0)) return h raise _ValueError(xs=xs, txt=_too_few_)
def sumOf(nvectors, Vector=None, h=None, **Vector_kwds): '''Return the vectorial sum of two or more n-vectors. @arg nvectors: Vectors to be added (C{Nvector}[]). @kwarg Vector: Optional class for the vectorial sum (C{Nvector}) or C{None}. @kwarg h: Optional height, overriding the mean height (C{meter}). @kwarg Vector_kwds: Optional, additional B{C{Vector}} keyword arguments, ignored if C{B{Vector}=None}. @return: Vectorial sum (B{C{Vector}}) or a L{Vector4Tuple}C{(x, y, z, h)} if B{C{Vector}} is C{None}. @raise VectorError: No B{C{nvectors}}. ''' n, nvectors = len2(nvectors) if n < 1: raise VectorError(nvectors=n, txt=MISSING) if h is None: h = fsum(v.h for v in nvectors) / float(n) if Vector is None: r = _sumOf(nvectors, Vector=Vector3Tuple).to4Tuple(h) else: r = _sumOf(nvectors, Vector=Vector, h=h, **Vector_kwds) return r
def __init__(self, knots, datum=None, beta=2, wrap=False, name=NN): '''New L{HeightIDWkarney} interpolator. @arg knots: The points with known height (C{LatLon}s). @kwarg datum: Optional datum overriding the default C{Datums.WGS84} and first B{C{knots}}' datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2} or L{a_f2Tuple}). @kwarg beta: Inverse distance power (C{int} 1, 2, or 3). @kwarg wrap: Wrap and L{unroll180} longitudes (C{bool}). @kwarg name: Optional name for this height interpolator (C{str}). @raise HeightError: Insufficient number of B{C{knots}} or an invalid B{C{knot}}, B{C{datum}} or B{C{beta}}. @raise ImportError: Package U{geographiclib <https://PyPI.org/project/geographiclib>} missing. @raise TypeError: Invalid B{C{datum}}. ''' n, self._ks = len2(knots) if n < self._kmin: raise _insufficientError(self._kmin, knots=n) self._datum_setter(datum, self._ks) self._Inverse1 = self.datum.ellipsoid.geodesic.Inverse1 self.beta = beta if wrap: self._wrap = True if name: self.name = name
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
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 ValueError('%s(%s): %s vs %s' % (fidw.__name, 'len', n, d)) d, x = min(zip(ds, xs)) if d > EPS and n > 1: b = -int(beta) if -4 < b < 0: # and b == -beta ds = tuple(d**b for d in ds) d = fsum(ds) if d < EPS: raise ValueError('%s(%s[%s]) invalid: %r' % (fidw.__name, 'ds', '', d)) x = fdot(xs, *ds) / d elif b == 0: x = fmean(xs) else: raise ValueError('%s(%s=%r) invalid' % (fidw.__name, 'beta', beta)) elif d < 0: i = ds.index(d) raise ValueError('%s(%s[%s]) invalid: %r' % (fidw.__name, 'ds', i, d)) return x
def _pts2(points, closed, inull): '''(INTERNAL) Get the points to clip. ''' if closed and inull: n, pts = len2(points) # only remove the final, closing point if n > 1 and _eq(pts[n - 1], pts[0]): n -= 1 pts = pts[:n] if n < 2: raise PointsError(points=n, txt=_too_(_few_)) else: n, pts = points2(points, closed=closed) return n, list(pts)
def _points2(points, closed, inull): '''(INTERNAL) Get the points to clip. ''' if closed and inull: n, pts = len2(points) # only remove the final, closing point if n > 1 and _eq(pts[n - 1], pts[0]): n -= 1 pts = pts[:n] if n < 3: raise PointsError('too few %s: %s' % ('points', n)) else: n, pts = points2(points, closed=closed) return n, list(pts)
def fmean(xs): '''Compute the accurate mean M{sum(xs[i] for i=0..len(xs)) / len(xs)}. @arg xs: Values (C{scalar}s). @return: Mean value (C{float}). @raise OverflowError: Partial C{2sum} overflow. @raise ValueError: No B{C{xs}} values. ''' n, xs = len2(xs) if n > 0: return fsum(xs) / n raise _ValueError(xs=xs)
def __init__(self, corners, name): n, cs = 0, corners try: # check the clip box/region n, cs = len2(cs) if n == 2: # make a box b, l, t, r = boundsOf(cs, wrap=False) cs = LL_(b, l), LL_(t, l), LL_(t, r), LL_(b, r) n, cs = points2(cs, closed=True) self._cs = cs = cs[:n] self._nc = n self._cw = 1 if isclockwise(cs, adjust=False, wrap=False) else -1 if self._cw != isconvex_(cs, adjust=False, wrap=False): raise ClipError except (ClipError, PointsError, TypeError, ValueError): raise ClipError(n, cs, name) self._name = name
def _h_x2(xs): '''(INTERNAL) Helper for L{hypot_} and L{hypot2_}. ''' if xs: n, xs = len2(xs) if n > 0: h = float(max(abs(x) for x in xs)) if h > 0: if n > 1: X = Fsum(_1_0) X.fadd((x / h)**2 for x in xs) x2 = X.fsum_(-_1_0) else: x2 = _1_0 else: h = x2 = _0_0 return h, x2 raise _ValueError(xs=xs, txt=_too_(_few_))
def __init__(self, corners, name=__name__): n, cs = 0, corners try: # check the clip box/region n, cs = len2(cs) if n == 2: # make a box b, l, t, r = boundsOf(cs, wrap=False) cs = LL_(b, l), LL_(t, l), LL_(t, r), LL_(b, r) n, cs = points2(cs, closed=True) self._cs = cs = cs[:n] self._nc = n self._cw = isconvex_(cs, adjust=False, wrap=False) if not self._cw: raise ValueError(_not_convex_) if areaOf(cs, adjust=True, radius=1, wrap=True) < EPS: raise ValueError('near-zero area') except (PointsError, TypeError, ValueError) as x: raise ClipError(name, n, cs, txt=str(x)) self.name = name
def _allis2(llis, m=1, Error=HeightError): # imported by .geoids # dtermine return type and convert lli C{LatLon}s to list if not isinstance(llis, tuple): # llis are *args raise _AssertionError('type(%s): %r' % ('*llis', llis)) n = len(llis) if n == 1: # convert single lli to 1-item list llis = llis[0] try: n, llis = len2(llis) _as = _alist # return list of interpolated heights except TypeError: # single lli n, llis = 1, [llis] _as = _ascalar # return single interpolated heights else: # of 0, 2 or more llis _as = _atuple # return tuple of interpolated heights if n < m: raise _insufficientError(m, Error=Error, llis=n) return _as, llis
def sumOf(vectors, Vector=Vector3d, **Vector_kwds): '''Compute the vectorial sum of several vectors. @arg vectors: Vectors to be added (L{Vector3d}[]). @kwarg Vector: Optional class for the vectorial sum (L{Vector3d}). @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments, ignored if B{C{Vector=None}}. @return: Vectorial sum (B{C{Vector}}). @raise VectorError: No B{C{vectors}}. ''' n, vectors = len2(vectors) if n < 1: raise VectorError('no vectors: %r' & (n, )) r = Vector3Tuple(fsum(v.x for v in vectors), fsum(v.y for v in vectors), fsum(v.z for v in vectors)) if Vector is not None: r = Vector(r.x, r.y, r.z, **Vector_kwds) # PYCHOK x, y, z return r
def sumOf(vectors, Vector=Vector3d, **Vector_kwds): '''Compute the vectorial sum of several vectors. @arg vectors: Vectors to be added (L{Vector3d}[]). @kwarg Vector: Optional class for the vectorial sum (L{Vector3d}). @kwarg Vector_kwds: Optional B{C{Vector}} keyword arguments, ignored if C{B{Vector}=None}. @return: Vectorial sum as B{C{Vector}} or if B{C{Vector}} is C{None}, a L{Vector3Tuple}C{(x, y, z)}. @raise VectorError: No B{C{vectors}}. ''' n, vectors = len2(vectors) if n < 1: raise VectorError(vectors=n, txt=MISSING) v = Vector3Tuple(fsum(v.x for v in vectors), fsum(v.y for v in vectors), fsum(v.z for v in vectors)) return _V_n(v, sumOf.__name__, Vector, Vector_kwds)
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
def __init__(self, AB, x, y): '''(INTERNAL) New Alpha or Beta Krüger series @arg AB: Krüger Alpha or Beta series coefficients (C{4-, 6- or 8-tuple}). @arg x: Eta angle (C{radians}). @arg y: Ksi angle (C{radians}). ''' n, j2 = len2(range(2, len(AB) * 2 + 1, 2)) self._ab = AB self._pq = map2(mul, j2, self._ab) # assert len(self._ab) == len(self._pq) == n x2 = map2(mul, j2, (x,) * n) self._chx = map2(cosh, x2) self._shx = map2(sinh, x2) # assert len(x2) == len(self._chx) == len(self._shx) == n y2 = map2(mul, j2, (y,) * n) self._cy = map2(cos, y2) self._sy = map2(sin, y2)
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('too few %s: %s' % ('points', n)) if base and not (isNumpy2(points) or isTuple2(points)): for i in range(n): base.others(points[i], name='%s[%s]' % ('points', i)) return Points2Tuple(n, points)