Beispiel #1
0
    def __init__(self, points, seed=None, name='', units='', **wrap_adjust):
        '''New C{Hausdorff...} calculator.

           @arg points: Initial set of points, aka the C{model} or
                        C{template} (C{LatLon}[], C{Numpy2LatLon}[],
                        C{Tuple2LatLon}[] or C{other}[]).
           @kwarg seed: Random sampling seed (C{any}) or C{None}, C{0}
                        or C{False} for no U{random sampling<https://
                        Publik.TUWien.ac.AT/files/PubDat_247739.pdf>}.
           @kwarg name: Optional name for this interpolator (C{str}).
           @kwarg units: Optional, distance units (C{str}).
           @kwarg wrap_adjust: Optionally, C{wrap} and unroll longitudes, iff
                               applicable (C{bool}) and C{adjust} wrapped,
                               unrolled longitudinal delta by the cosine
                               of the mean latitude, iff applicable.

           @raise HausdorffError: Insufficient number of B{C{points}} or
                                  invalid B{C{seed}} or B{{wrap}} or
                                  B{C{ajust}} not applicable.
        '''
        _, self._model = points2(points, closed=False, Error=HausdorffError)
        if seed:
            self.seed = seed
        if name:
            self.name = name
        if units and not self.units:
            self.units = units
        if wrap_adjust:
            _bkwds(self, Error=HausdorffError, **wrap_adjust)
Beispiel #2
0
def hausdorff_(model,
               target,
               both=False,
               early=True,
               seed=None,
               units=NN,
               distance=None,
               point=_point):
    '''Compute the C{directed} or C{symmetric} U{Hausdorff distance<https://
       WikiPedia.org/wiki/Hausdorff_distance>} between 2 sets of points with or
       without U{early breaking<https://Publik.TUWien.ac.AT/files/PubDat_247739.pdf>}
       and U{random sampling<https://Publik.TUWien.ac.AT/files/PubDat_247739.pdf>}.

       @arg model: First set of points (C{LatLon}[], C{Numpy2LatLon}[],
                   C{Tuple2LatLon}[] or C{other}[]).
       @arg target: Second set of points (C{LatLon}[], C{Numpy2LatLon}[],
                    C{Tuple2LatLon}[] or C{other}[]).
       @kwarg both: Return the C{directed} (forward only) or the C{symmetric}
                    (combined forward and reverse) C{Hausdorff} distance (C{bool}).
       @kwarg early: Enable or disable U{early breaking<https://Publik.TUWien.ac.AT/
                     files/PubDat_247739.pdf>} (C{bool}).
       @kwarg seed: Random sampling seed (C{any}) or C{None}, C{0} or C{False} for no
                    U{random sampling<https://Publik.TUWien.ac.AT/files/PubDat_247739.pdf>}.
       @kwarg units: Optional, the distance units (C{Unit} or C{str}).
       @kwarg distance: Callable returning the distance between a B{C{model}}
                        and B{C{target}} point (signature C{(point1, point2)}).
       @kwarg point: Callable returning the B{C{model}} or B{C{target}} point
                     suitable for B{C{distance}} (signature C{(point)}).

       @return: A L{Hausdorff6Tuple}C{(hd, i, j, mn, md, units)}.

       @raise HausdorffError: Insufficient number of B{C{model}} or B{C{target}} points.

       @raise TypeError: If B{C{distance}} or B{C{point}} is not callable.
    '''
    if not callable(distance):
        raise _IsnotError(callable.__name__, distance=distance)
    if not callable(point):
        raise _IsnotError(callable.__name__, point=point)

    _, ps1 = points2(model, closed=False,
                     Error=HausdorffError)  # PYCHOK non-sequence
    _, ps2 = points2(target, closed=False,
                     Error=HausdorffError)  # PYCHOK non-sequence
    return _hausdorff_(ps1, ps2, both, early, seed, units, distance, point)
Beispiel #3
0
def clipCS3(points,
            lowerleft,
            upperright,
            closed=False,
            inull=False):  # MCCABE 25
    '''Clip a path against a rectangular clip box using the
       U{Cohen-Sutherland
       <https://WikiPedia.org/wiki/Cohen-Sutherland_algorithm>} algorithm.

       @param points: The points (C{LatLon}[]).
       @param lowerleft: Bottom-left corner of the clip box (C{LatLon}).
       @param upperright: Top-right corner of the clip box (C{LatLon}).
       @keyword closed: Optionally, close the path (C{bool}).
       @keyword inull: Optionally, include null edges if inside (C{bool}).

       @return: Yield a L{ClipCS3Tuple}C{(start, end, index)} for each
                edge of the clipped path.

       @raise ValueError: The B{C{lowerleft}} corner is not below and/or
                          not to the left of the B{C{upperright}} corner.
    '''

    cs = _CS(lowerleft, upperright)
    n, points = points2(points, closed=closed)

    i, m = _imdex2(closed, n)
    cmbp = cs.code4(points[i])
    for i in range(m, n):
        c1, m1, b1, p1 = cmbp
        c2, m2, b2, p2 = cmbp = cs.code4(points[i])
        if c1 & c2:  # edge outside
            continue

        if not cs.edge(p1, p2):
            if inull:  # null edge
                if not c1:
                    yield ClipCS3Tuple(p1, p1, i)
                elif not c2:
                    yield ClipCS3Tuple(p2, p2, i)
            continue

        for _ in range(5):
            if c1:  # clip p1
                c1, m1, b1, p1 = m1(b1, p1)
            elif c2:  # clip p2
                c2, m2, b2, p2 = m2(b2, p2)
            else:  # inside
                if inull or _neq(p1, p2):
                    yield ClipCS3Tuple(p1, p2, i)
                break
            if c1 & c2:  # edge outside
                break
        else:  # should never get here
            raise AssertionError('clipCS3.for _')
Beispiel #4
0
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)
Beispiel #5
0
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)
Beispiel #6
0
    def symmetric(self, points, early=True):
        '''Compute the combined C{forward and reverse Hausdorff} distance.

           @arg points: Second set of points, aka the C{target} (C{LatLon}[],
                        C{Numpy2LatLon}[], C{Tuple2LatLon}[] or C{other}[]).
           @kwarg early: Enable or disable U{early breaking<https://
                         Publik.TUWien.ac.AT/files/PubDat_247739.pdf>} (C{bool}).

           @return: A L{Hausdorff6Tuple}C{(hd, i, j, mn, md, units)}.

           @raise HausdorffError: Insufficient number of B{C{points}}.
        '''
        _, ps2 = points2(points, closed=False, Error=HausdorffError)
        return _hausdorff_(self._model, ps2, True, early, self.seed,
                           self.units, self.distance, self.point)
Beispiel #7
0
 def __init__(self, corners):
     n = ''
     try:
         n, cs = len2(corners)
         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._corners = 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 ValueError
     except ValueError:
         raise ValueError('%s[%s] invalid: %r' % ('corners', n, corners))
     self._clipped = self._points = []
    def points2(self, points, closed=True):
        '''Check a path or polygon represented by points.

           @param points: The path or polygon points (C{LatLon}[])
           @keyword closed: Optionally, consider the polygon closed,
                            ignoring any duplicate or closing final
                            B{C{points}} (C{bool}).

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

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

           @raise ValueError: Insufficient number of B{C{points}}.
        '''
        return points2(points, closed=closed, base=self)
Beispiel #9
0
 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
Beispiel #10
0
 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
Beispiel #11
0
def _geodesic(datum, points, closed, line, wrap):
    # Compute the area or perimeter of a polygon,
    # using the GeographicLib package, iff installed
    g = datum.ellipsoid.geodesic

    if not wrap:  # capability LONG_UNROLL can't be off
        raise ValueError('%s invalid: %s' % ('wrap', wrap))

    _, points = points2(points,
                        closed=closed)  # base=LatLonEllipsoidalBase(0, 0)

    g = g.Polygon(line)

    # note, lon deltas are unrolled, by default
    for p in points:
        g.AddPoint(p.lat, p.lon)
    if closed and line:
        p = points[0]
        g.AddPoint(p.lat, p.lon)

    # g.Compute returns (number_of_points, perimeter, signed area)
    return g.Compute(False, True)[1 if line else 2]
Beispiel #12
0
    def __init__(self, points, seed=None, name='', units=''):
        '''New L{Hausdorff} calculator.

           @param points: Initial set of points, aka the C{model} or
                          C{template} (C{LatLon}[], C{Numpy2LatLon}[],
                          C{Tuple2LatLon}[] or C{other}[]).
           @keyword seed: Random sampling seed (C{any}) or C{None}, C{0}
                          or C{False} for no U{random sampling<https://
                          Publik.TUWien.ac.AT/files/PubDat_247739.pdf>}.
           @keyword name: Optional calculator name (C{str}).
           @keyword units: Optional, distance units (C{str}).

           @raise HausdorffError: Insufficient number of B{C{points}} or
                                  invalid B{C{seed}}.
        '''
        _, self._model = points2(points, closed=False, Error=HausdorffError)
        if seed:
            self.seed = seed
        if name:
            self.name = name
        if units:
            self.units = units
Beispiel #13
0
 def _points2(self, points):
     '''(INTERNAL) Check a set of points.
     '''
     return points2(points, closed=False, Error=HausdorffError)