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
def perimeterOf(points, closed=False, radius=R_M, wrap=True): '''Compute the perimeter of a (spherical) polygon (with great circle arcs joining the points). @param points: The polygon points (L{LatLon}[]). @keyword closed: Optionally, close the polygon (C{bool}). @keyword radius: Mean earth radius (C{meter}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @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}}. @note: This perimeter is based on the L{haversine} formula. @see: L{pygeodesy.perimeterOf}, L{sphericalNvector.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 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 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 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 B{C{Vector}} keyword arguments. @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, )) return Vector(fsum(v.x for v in vectors), fsum(v.y for v in vectors), fsum(v.z for v in vectors), **kwds)
def areaOf(points, radius=R_M, wrap=True): '''Calculate the area of a (spherical) polygon (with great circle arcs joining the points). @arg points: The polygon points (L{LatLon}[]). @kwarg radius: Mean earth radius (C{meter}). @kwarg wrap: Wrap and unroll longitudes (C{bool}). @return: Polygon area (C{meter}, same units as B{C{radius}}, squared). @raise PointsError: Insufficient number of B{C{points}}. @raise TypeError: Some B{C{points}} are not L{LatLon}. @raise ValueError: Invalid B{C{radius}}. @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].philam ta1 = tan_2(a1) for i in range(n): a2, b2 = points[i].philam 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(radius)**2)
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 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 B{C{Vector}} keyword arguments, ignored if C{B{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, **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 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(vectors=n, txt=_Missing) 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(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 VectorError: No B{C{nvectors}}. ''' n, nvectors = len2(nvectors) if n < 1: raise VectorError('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)
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