Beispiel #1
0
    def isenclosedBy(self, points):
        '''Check whether this point is enclosed by a (convex) polygon.

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

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

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

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

           @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

           @JSname: I{enclosedBy}.
        '''
        n, points = self.points2(points, closed=True)

        # use normal vector to this point for sign of α
        n0 = self.toNvector()

        if iterNumpy2(points):

            def _subtangles(n, points, n0):  # iterate
                vs = n0.minus(points[n - 1].toNvector())
                for i in range(n):
                    vs1 = n0.minus(points[i].toNvector())
                    yield vs.angleTo(vs1, vSign=n0)  # PYCHOK false
                    vs = vs1

            # sum subtended angles
            s = fsum(_subtangles(n, points, n0))

        else:
            # get vectors from this to each point
            vs = [n0.minus(points[i].toNvector()) for i in range(n)]
            # close the polygon
            vs.append(vs[0])

            # sum subtended angles of each edge (using n0 to determine sign)
            s = fsum(vs[i].angleTo(vs[i + 1], vSign=n0) for i in range(n))

        # Note, this method uses angle summation test: on a plane,
        # angles for an enclosed point will sum to 360°, angles for
        # an exterior point will sum to 0°.  On a sphere, enclosed
        # point angles will sum to less than 360° (due to spherical
        # excess), exterior point angles will be small but non-zero.

        # XXX are winding number optimisations equally applicable to
        # spherical surface?
        return abs(s) > PI
Beispiel #2
0
def sumOf(vectors, Vector=Vector3d, **kwds):
    '''Compute the vectorial sum of several vectors.

       @param vectors: Vectors to be added (L{Vector3d}[]).
       @keyword Vector: Optional class for the vectorial sum (L{Vector3d}).
       @keyword kwds: Optional, additional I{Vector} keyword arguments.

       @return: Vectorial sum (I{Vector}).

       @raise ValueError: No I{vectors}.
    '''
    n, vectors = len2(vectors)
    if n < 1:
        raise ValueError('no vectors: %r' & (n, ))
    return Vector(fsum(v.x for v in vectors), fsum(v.y for v in vectors),
                  fsum(v.z for v in vectors), **kwds)
Beispiel #3
0
def perimeterOf(points, closed=False, radius=R_M):
    '''Compute the perimeter of a (spherical) polygon (with great circle
       arcs joining consecutive points).

       @param points: The polygon points (L{LatLon}[]).
       @keyword closed: Optionally, close the polygon (C{bool}).
       @keyword radius: Optional, mean earth radius (C{meter}).

       @return: Polygon perimeter (C{meter}, same units as B{C{radius}}).

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

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

       @see: L{pygeodesy.perimeterOf}, L{sphericalTrigonometry.perimeterOf}
             and L{ellipsoidalKarney.perimeterOf}.
    '''
    n, points = _Nvll.points2(points, closed=closed)

    def _rads(n, points, closed):  # angular edge lengths in radians
        i, m = _imdex2(closed, n)
        v1 = points[i].toNvector()
        for i in range(m, n):
            v2 = points[i].toNvector()
            yield v1.angleTo(v2)
            v1 = v2

    r = fsum(_rads(n, points, closed))
    return r * float(radius)
def perimeterOf(points, closed=False, radius=R_M, wrap=True):
    '''Compute the perimeter of a polygon/-line defined by an array,
       list, sequence, set or tuple of points.

       @param points: The points defining the polygon (L{LatLon}[]).
       @keyword closed: Optionally, close the polygon/-line (bool).
       @keyword radius: Optional, mean earth radius (meter).
       @keyword wrap: Wrap and unroll longitudes (bool).

       @return: Polygon perimeter (float, same units as radius).

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

       @raise ValueError: Insufficient number of I{points}.

       @note: This perimeter is based on the L{haversine} formula.

       @see: L{pygeodesy.perimeterOf} and L{ellipsoidalVincenty.perimeterOf}.
    '''
    n, points = _Trll.points(points, closed=closed)

    def _rads(n, points, closed):  # angular edge lengths in radians
        if closed:
            m, i = 0, n - 1
        else:
            m, i = 1, 0
        a1, b1 = points[i].to2ab()
        for i in range(m, n):
            a2, b2 = points[i].to2ab()
            db, b2 = unrollPI(b1, b2, wrap=wrap)
            yield haversine_(a2, a1, db)
            a1, b1 = a2, b2

    r = fsum(_rads(n, points, closed))
    return r * float(radius)
Beispiel #5
0
def perimeterOf(points, closed=False, radius=R_M, wrap=True):
    '''Compute the perimeter of a polygon.

       @param points: The polygon points (L{LatLon}[]).
       @keyword closed: Optionally, close the polygon (C{bool}).
       @keyword radius: Optional, mean earth radius (C{meter}).
       @keyword wrap: Wrap and unroll longitudes (C{bool}).

       @return: Polygon perimeter (C{meter}, same units as I{radius}).

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

       @raise ValueError: Insufficient number of I{points}.

       @note: This perimeter is based on the L{haversine} formula.

       @see: L{pygeodesy.perimeterOf} and L{ellipsoidalKarney.perimeterOf}.
    '''
    n, points = _Trll.points2(points, closed=closed)

    def _rads(n, points, closed):  # angular edge lengths in radians
        i, m = _imdex2(closed, n)
        a1, b1 = points[i].to2ab()
        for i in range(m, n):
            a2, b2 = points[i].to2ab()
            db, b2 = unrollPI(b1, b2, wrap=wrap)
            yield haversine_(a2, a1, db)
            a1, b1 = a2, b2

    r = fsum(_rads(n, points, closed))
    return r * float(radius)
def isPoleEnclosedBy(points, wrap=False):
    '''Test whether a pole is enclosed by a polygon defined by a list,
       sequence, set or tuple of points.

       @param points: The points defining the polygon (L{LatLon}[]).
       @keyword wrap: Wrap and unroll longitudes (bool).

       @return: True if the polygon encloses a pole (bool).

       @raise ValueError: Insufficient number of I{points}.

       @raise TypeError: Some I{points} are not L{LatLon}.
    '''
    n, points = _Trll.points(points)

    def _cds(n, points):  # iterate over course deltas
        p1 = points[n - 1]
        b1 = p1.initialBearingTo(
            points[0], wrap=wrap)  # XXX p1.finalBearingTo(points[0])?
        for i in range(n):
            p2 = points[i]
            if not p2.equals(p1, EPS):
                b = p1.initialBearingTo(p2, wrap=wrap)
                yield wrap180(b - b1)  # (b - b1 + 540) % 360 - 180
                b2 = p1.finalBearingTo(p2, wrap=wrap)
                yield wrap180(b2 - b)  # (b2 - b + 540) % 360 - 180
                p1, b1 = p2, b2

    # sum of course deltas around pole is 0° rather than normally ±360°
    # <http://blog.element84.com/determining-if-a-spherical-polygon-contains-a-pole.html>
    s = fsum(_cds(n, points))

    # XXX fix (intermittant) edge crossing pole - eg (85,90), (85,0), (85,-90)
    return abs(s) < 90  # "zero-ish"
Beispiel #7
0
 def _hIDW(self, x, y):
     # interpolate height at (x, y) radians
     ws = tuple(self._distances(x, y))
     w, h = min(zip(ws, self._hs))
     if w > EPS:
         ws = tuple(w**self._b for w in ws)
         h = fdot(ws, *self._hs) / fsum(ws)
     return h
Beispiel #8
0
def areaOf(points, radius=R_M, wrap=True):
    '''Calculate the area of a (spherical) polygon (with great circle
       arcs joining the points).

       @param points: The polygon points (L{LatLon}[]).
       @keyword radius: Optional, mean earth radius (C{meter}).
       @keyword wrap: Wrap and unroll longitudes (C{bool}).

       @return: Polygon area (C{meter}, same units as B{C{radius}}, squared).

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

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

       @note: The area is based on Karney's U{'Area of a spherical polygon'
              <https://OSGeo-org.1560.x6.nabble.com/
              Area-of-a-spherical-polygon-td3841625.html>}.

       @see: L{pygeodesy.areaOf}, L{sphericalNvector.areaOf} and
             L{ellipsoidalKarney.areaOf}.

       @example:

       >>> b = LatLon(45, 1), LatLon(45, 2), LatLon(46, 2), LatLon(46, 1)
       >>> areaOf(b)  # 8666058750.718977

       >>> c = LatLon(0, 0), LatLon(1, 0), LatLon(0, 1)
       >>> areaOf(c)  # 6.18e9
    '''
    n, points = _Trll.points2(points, closed=True)

    # Area method due to Karney: for each edge of the polygon,
    #
    #                tan(Δλ/2) · (tan(φ1/2) + tan(φ2/2))
    #     tan(E/2) = ------------------------------------
    #                     1 + tan(φ1/2) · tan(φ2/2)
    #
    # where E is the spherical excess of the trapezium obtained by
    # extending the edge to the equator-circle vector for each edge

    def _exs(n, points):  # iterate over spherical edge excess
        a1, b1 = points[n - 1].to2ab()
        ta1 = tan_2(a1)
        for i in range(n):
            a2, b2 = points[i].to2ab()
            db, b2 = unrollPI(b1, b2, wrap=wrap)
            ta2, tdb = map1(tan_2, a2, db)
            yield atan2(tdb * (ta1 + ta2), 1 + ta1 * ta2)
            ta1, b1 = ta2, b2

    s = fsum(_exs(n, points)) * 2

    if isPoleEnclosedBy(points):
        s = abs(s) - PI2

    return abs(s * radius**2)
Beispiel #9
0
def perimeterOf(points, closed=False, adjust=True, radius=R_M, wrap=True):
    '''Approximate the perimeter of a polygon/-line defined by an array,
       list, sequence, set or tuple of points.

       @param points: The points defining the polygon/-line (I{LatLon}[]).
       @keyword closed: Optionally, close the polygon/-line (bool).
       @keyword adjust: Adjust the wrapped, unrolled longitudinal delta
                        by the cosine of the mean latitude (bool).
       @keyword radius: Optional, mean earth radius (meter).
       @keyword wrap: Wrap lat-, wrap and unroll longitudes (bool).

       @return: Approximate perimeter (meter, same units as I{radius}).

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

       @raise ValueError: Insufficient number of I{points}.

       @note: This perimeter is based on the L{equirectangular_}
       distance approximation and is ill-suited for regions exceeding
       several hundred Km or Miles or with near-polar latitudes.

       @see: L{sphericalTrigonometry.perimeterOf} and
             L{ellipsoidalVincenty.perimeterOf}.
    '''
    pts = LatLon2psxy(points, closed=closed, radius=None, wrap=False)

    def _degs(n, pts, closed):  # angular edge lengths in degrees
        u = 0  # previous x2's unroll/wrap
        if closed:
            j, i = 0, n - 1
        else:
            j, i = 1, 0
        x1, y1, _ = pts[i]
        for i in range(j, n):
            x2, y2, _ = pts[i]
            # apply previous x2's unroll/wrap to new x1
            d2, _, _, u = equirectangular_(y1,
                                           x1 + u,
                                           y2,
                                           x2,
                                           adjust=adjust,
                                           limit=None,
                                           wrap=wrap)
            yield sqrt(d2)
            x1, y1 = x2, y2

    d = fsum(_degs(len(pts), pts, closed))
    return radians(d) * float(radius)
Beispiel #10
0
def perimeterOf(points, closed=False, adjust=True, radius=R_M, wrap=True):
    '''Approximate the perimeter of a path or polygon.

       @param points: The path or polygon points (C{LatLon}[]).
       @keyword closed: Optionally, close the path or polygon (C{bool}).
       @keyword adjust: Adjust the wrapped, unrolled longitudinal delta
                        by the cosine of the mean latitude (C{bool}).
       @keyword radius: Optional, mean earth radius (C{meter}).
       @keyword wrap: Wrap lat-, wrap and unroll longitudes (C{bool}).

       @return: Approximate perimeter (C{meter}, same units as I{radius}).

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

       @raise ValueError: Insufficient number of I{points}.

       @note: This perimeter is based on the L{equirectangular_}
              distance approximation and is ill-suited for regions
              exceeding several hundred Km or Miles or with
              near-polar latitudes.

       @see: L{sphericalTrigonometry.perimeterOf} and
             L{ellipsoidalKarney.perimeterOf}.
    '''
    pts = LatLon2psxy(points, closed=closed, radius=None, wrap=False)

    def _degs(n, pts, closed):  # angular edge lengths in degrees
        i, m = _imdex2(closed, n)
        x1, y1, _ = pts[i]
        u = 0  # previous x2's unroll/wrap
        for i in range(m, n):
            x2, y2, _ = pts[i]
            w = wrap if (not closed or i < (n - 1)) else False
            # apply previous x2's unroll/wrap to new x1
            _, dy, dx, u = equirectangular_(y1,
                                            x1 + u,
                                            y2,
                                            x2,
                                            adjust=adjust,
                                            limit=None,
                                            wrap=w)
            yield hypot(dx, dy)
            x1, y1 = x2, y2

    d = fsum(_degs(len(pts), pts, closed))
    return degrees2m(d, radius)
Beispiel #11
0
def sumOf(nvectors, Vector=Nvector, h=None, **kwds):
    '''Return the vectorial sum of two or more n-vectors.

       @param nvectors: Vectors to be added (L{Nvector}[]).
       @keyword Vector: Optional class for the vectorial sum (L{Nvector}).
       @keyword kwds: Optional, additional B{C{Vector}} keyword arguments.
       @keyword h: Optional height, overriding the mean height (C{meter}).

       @return: Vectorial sum (B{C{Vector}}).

       @raise ValueError: No B{C{nvectors}}.
    '''
    n, nvectors = len2(nvectors)
    if n < 1:
        raise ValueError('no nvectors: %r' & (n, ))

    if h is None:
        h = fsum(v.h for v in nvectors) / float(n)
    return _sumOf(nvectors, Vector=Vector, h=h, **kwds)
Beispiel #12
0
def sumOf(nvectors, Vector=Nvector, h=None, **kwds):
    '''Return the vectorial sum of any number of n-vectors.

       @param nvectors: Vectors to be added (L{Nvector}[]).
       @keyword Vector: Optional class for the vectorial sum (L{Nvector}).
       @keyword kwds: Optional, additional I{Vector} keyword argments.
       @keyword h: Optional height, overriding the mean height (meter).

       @return: Vectorial sum (I{Vector}).

       @raise ValueError: No I{nvectors}.
    '''
    n, nvectors = len2(nvectors)
    if n < 1:
        raise ValueError('no nvectors: %r' & (n, ))
    if h is None:
        m = fsum(v.h for v in nvectors) / float(n)
    else:
        m = h
    return _sumOf(nvectors, Vector=Vector, h=m, **kwds)
Beispiel #13
0
def _area2(points, adjust, wrap):
    # return the signed area in radians squared

    # setting radius=1 converts degrees to radians
    pts = LatLon2psxy(points, closed=True, radius=1, wrap=wrap)

    def _rads2(n, pts):  # trapezoidal areas in rads**2
        x1, y1, _ = pts[n - 1]
        for i in range(n):
            x2, y2, _ = pts[i]
            w, x2 = unrollPI(x1, x2, wrap=wrap if i < (n - 1) else False)
            # approximate trapezoid by a rectangle, adjusting
            # the top width by the cosine of the latitudinal
            # average and bottom width by some fudge factor
            h = (y2 + y1) * 0.5
            if adjust:
                w *= (cos(h) + 1.2876) * 0.5
            yield h * w  # signed trapezoidal area

            x1, y1 = x2, y2

    return fsum(_rads2(len(pts), pts)), pts
Beispiel #14
0
def ispolar(points, wrap=False):
    '''Check whether a polygon encloses a pole.

       @param points: The polygon points (C{LatLon}[]).
       @keyword wrap: Wrap and unroll longitudes (C{bool}).

       @return: C{True} if a pole is enclosed by the polygon,
                C{False} otherwise.

       @raise ValueError: Insufficient number of I{points}.

       @raise TypeError: Some I{points} are not C{LatLon} or don't
                         have C{bearingTo2}, C{initialBearingTo}
                         and C{finalBearingTo} methods.
    '''
    n, points = points2(points, closed=True)

    def _cds(n, points):  # iterate over course deltas
        p1 = points[n - 1]
        try:  # LatLon must have initial- and finalBearingTo
            b1, _ = p1.bearingTo2(points[0], wrap=wrap)
        except AttributeError:
            raise TypeError('invalid %s: %r' % ('points', p1))

        for i in range(n):
            p2 = points[i]
            if not p2.isequalTo(p1, EPS):
                b, b2 = p1.bearingTo2(p2, wrap=wrap)
                yield wrap180(b - b1)  # (b - b1 + 540) % 360 - 180
                yield wrap180(b2 - b)  # (b2 - b + 540) % 360 - 180
                p1, b1 = p2, b2

    # sum of course deltas around pole is 0° rather than normally ±360°
    # <http://blog.Element84.com/determining-if-a-spherical-polygon-contains-a-pole.html>
    s = fsum(_cds(n, points))

    # XXX fix (intermittant) edge crossing pole - eg (85,90), (85,0), (85,-90)
    return abs(s) < 90  # "zero-ish"
Beispiel #15
0
def areaOf(points, radius=R_M):
    '''Calculate the area of a (spherical) polygon (with great circle
       arcs joining consecutive points).

       @param points: The polygon points (L{LatLon}[]).
       @keyword radius: Optional, mean earth radius (C{meter}).

       @return: Polygon area (C{meter}, same units as B{C{radius}}, squared).

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

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

       @see: L{pygeodesy.areaOf}, L{sphericalTrigonometry.areaOf} and
             L{ellipsoidalKarney.areaOf}.

       @example:

       >>> b = LatLon(45, 1), LatLon(45, 2), LatLon(46, 2), LatLon(46, 1)
       >>> areaOf(b)  # 8666058750.718977
    '''
    n, points = _Nvll.points2(points, closed=True)

    # use vector to 1st point as plane normal for sign of α
    n0 = points[0].toNvector()

    if iterNumpy2(points):

        def _interangles(n, points, n0):  # iterate
            v2 = points[n - 2].toNvector()
            v1 = points[n - 1].toNvector()
            gc = v2.cross(v1)
            for i in range(n):
                v2 = points[i].toNvector()
                gc1 = v1.cross(v2)
                v1 = v2

                yield gc.angleTo(gc1, vSign=n0)
                gc = gc1

        # sum interior angles
        s = fsum(_interangles(n, points, n0))

    else:
        # get great-circle vector for each edge
        gc, v1 = [], points[n - 1].toNvector()
        for i in range(n):
            v2 = points[i].toNvector()
            gc.append(v1.cross(v2))  # PYCHOK false, does have .cross
            v1 = v2
        gc.append(gc[0])  # XXX needed?

        # sum interior angles: depending on whether polygon is cw or ccw,
        # angle between edges is π−α or π+α, where α is angle between
        # great-circle vectors; so sum α, then take n·π − |Σα| (cannot
        # use Σ(π−|α|) as concave polygons would fail)
        s = fsum(gc[i].angleTo(gc[i + 1], vSign=n0) for i in range(n))

    # using Girard’s theorem: A = [Σθᵢ − (n−2)·π]·R²
    # (PI2 - abs(s) == (n*PI - abs(s)) - (n-2)*PI)
    return abs(PI2 - abs(s)) * radius**2