def nearestOn2(self, points, closed=False, radius=R_M, height=None): '''Locate the point on a polygon (with great circle arcs joining consecutive points) closest to this point. If this point is within the extent of any great circle arc, the closest point is on that arc. Otherwise, the closest is the nearest of the arc's end points. @param points: The polygon points (L{LatLon}[]). @keyword closed: Optionally, close the polygon (C{bool}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword height: Optional height, overriding the mean height for a point within the arc (C{meter}). @return: 2-Tuple (closest, distance) of the closest point (L{LatLon}) on the polygon and the distance to that point from the given point in C{meter}, same units of B{C{radius}}. @raise TypeError: Some B{C{points}} are not C{LatLon}. @raise ValueError: No B{C{points}}. ''' n, points = self.points2(points, closed=closed) i, m = _imdex2(closed, n) c = p2 = points[i] d = self.distanceTo(c, radius=radius) for i in range(m, n): p1, p2 = p2, points[i] p = self.nearestOn(p1, p2, height=height) t = self.distanceTo(p, radius=radius) if t < d: c, d = p, t return c, d
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
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
def _rads(n, points, closed): # angular edge lengths in radians i, m = _imdex2(closed, n) a1, b1 = points[i].philam for i in range(m, n): a2, b2 = points[i].philam db, b2 = unrollPI(b1, b2, wrap=wrap) yield vincentys_(a2, a1, db) a1, b1 = a2, b2
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 _')
def clipCS3(points, lowerleft, upperright, closed=False, inull=False): '''Clip a path against a rectangular clip box using the U{Cohen-Sutherland <https://WikiPedia.org/wiki/Cohen-Sutherland_algorithm>} algorithm. @arg points: The points (C{LatLon}[]). @arg lowerleft: Bottom-left corner of the clip box (C{LatLon}). @arg upperright: Top-right corner of the clip box (C{LatLon}). @kwarg closed: Optionally, close the path (C{bool}). @kwarg 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 ClipError: The B{C{lowerleft}} and B{C{upperright}} corners specify an invalid clip box. @raise PointsError: Insufficient number of B{C{points}}. ''' cs = _CS(lowerleft, upperright, clipCS3.__name__) n, pts = _points2(points, closed, inull) i, m = _imdex2(closed, n) cmbp = cs.code4(pts[i]) for i in range(m, n): c1, m1, b1, p1 = cmbp c2, m2, b2, p2 = cmbp = cs.code4(pts[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: # PYCHOK no cover raise AssertionError(_dot_(cs._name, 'for_else'))
def nearestOn3(self, points, closed=False, radius=R_M, height=None): '''Locate the point on a polygon (with great circle arcs joining consecutive points) closest to this point. If this point is within the extent of any great circle arc, the closest point is on that arc. Otherwise, the closest is the nearest of the arc's end points. @arg points: The polygon points (L{LatLon}[]). @kwarg closed: Optionally, close the polygon (C{bool}). @kwarg radius: Mean earth radius (C{meter}). @kwarg height: Optional height, overriding the mean height for a point within the arc (C{meter}). @return: A L{NearestOn3Tuple}C{(closest, distance, angle)} of the C{closest} point (L{LatLon}), the C{distance} between this and the C{closest} point in C{meter}, same units as B{C{radius}} and the C{angle} from this to the C{closest} point in compass C{degrees360}. @raise TypeError: Some B{C{points}} are not C{LatLon}. @raise ValueError: No B{C{points}}. ''' n, points = self.points2(points, closed=closed) i, m = _imdex2(closed, n) c = p2 = points[i] r = self.distanceTo(c, radius=1) # force radians for i in range(m, n): p1, p2 = p2, points[i] p = self.nearestOn(p1, p2, height=height) t = self.distanceTo(p, radius=1) # force radians if t < r: c, r = p, t return NearestOn3Tuple(c, r * Radius(radius), degrees360(r))
def clipLB6(points, lowerleft, upperright, closed=False, inull=False): '''Clip a path against a rectangular clip box using the U{Liang-Barsky <https://www.CSE.UNT.edu/~renka/4230/LineClipping.pdf>} algorithm. @arg points: The points (C{LatLon}[]). @arg lowerleft: Bottom-left corner of the clip box (C{LatLon}). @arg upperright: Top-right corner of the clip box (C{LatLon}). @kwarg closed: Optionally, close the path (C{bool}). @kwarg inull: Optionally, retain null edges if inside (C{bool}). @return: Yield a L{ClipLB6Tuple}C{(start, end, i, fi, fj, j)} for each edge of the I{clipped} path. @raise ClipError: The B{C{lowerleft}} and B{C{upperright}} corners specify an invalid clip box. @raise PointsError: Insufficient number of B{C{points}}. @see: U{Liang-Barsky Line Clipping<https://www.CS.Helsinki.FI/group/goa/ viewing/leikkaus/intro.html>}, U{Liang-Barsky line clipping algorithm <https://www.Skytopia.com/project/articles/compsci/clipping.html>} and U{Liang–Barsky algorithm<https://WikiPedia.org/wiki/Liang–Barsky_algorithm>}. ''' xmin, ymin, \ xmax, ymax = _box4(lowerleft, upperright, clipLB6.__name__) n, pts = _pts2(points, closed, inull) fin = n if closed else None # wrapping fi [n] to [0] _LB = _LBtrim i, m = _imdex2(closed, n) pi = pts[i] for j in range(m, n): p1 = pi y1 = p1.lat x1 = p1.lon p2 = pi = pts[j] dy = float(p2.lat - y1) dx = float(p2.lon - x1) if abs(dx) > EPS or abs(dy) > EPS: # non-null edge pts[i]...pts[j] t = [_0_0, _1_0] if _LB(-dx, -xmin + x1, t) and \ _LB( dx, xmax - x1, t) and \ _LB(-dy, -ymin + y1, t) and \ _LB( dy, ymax - y1, t): # clip edge pts[i]...pts[j] # at fractions t[0] to t[1] if t[0] > _0_0: # EPS p1 = p1.classof(y1 + t[0] * dy, x1 + t[0] * dx) fi = i + t[0] else: fi = i if t[0] < t[1]: if t[1] < _1_0: # EPS1 p2 = p2.classof(y1 + t[1] * dy, x1 + t[1] * dx) fj = i + t[1] else: fj = j fi = FIx(fi, fin=fin) fj = FIx(fj, fin=fin) yield ClipLB6Tuple(p1, p2, i, fi, fj, j) elif inull and (t[0] + EPS) > t[1]: fi = FIx(fi, fin=fin) yield ClipLB6Tuple(p1, p1, i, fi, fi, j) # else: # outside # pass elif inull: # null edge yield ClipLB6Tuple(p1, p2, i, FIx(i, fin=fin), FIx(j, fin=fin), j) i = j