def distanceTo(self, other, radius=R_M, wrap=False): '''Compute the distance from this to an other point. @param other: The other point (L{LatLon}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @return: Distance between this and the I{other} point (C{meter}, same units as I{radius}). @raise TypeError: The I{other} point is not L{LatLon}. @example: >>> p1 = LatLon(52.205, 0.119) >>> p2 = LatLon(48.857, 2.351); >>> d = p1.distanceTo(p2) # 404300 ''' self.others(other) a1, b1 = self.to2ab() a2, b2 = other.to2ab() db, b2 = unrollPI(b1, b2, wrap=wrap) r = haversine_(a2, a1, db) return r * float(radius)
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 intermediateTo(self, other, fraction, height=None, wrap=False): '''Locate the point at given fraction between this and an other point. @param other: The other point (L{LatLon}). @param fraction: Fraction between both points (float, 0.0 = this point, 1.0 = the other point). @keyword height: Optional height, overriding the fractional height (C{meter}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @return: Intermediate point (L{LatLon}). @raise TypeError: The I{other} point is not L{LatLon}. @example: >>> p1 = LatLon(52.205, 0.119) >>> p2 = LatLon(48.857, 2.351) >>> p = p1.intermediateTo(p2, 0.25) # 51.3721°N, 000.7073°E @JSname: I{intermediatePointTo}. ''' self.others(other) a1, b1 = self.to2ab() a2, b2 = other.to2ab() db, b2 = unrollPI(b1, b2, wrap=wrap) r = haversine_(a2, a1, db) sr = sin(r) if abs(sr) > EPS: cb1, cb2, ca1, ca2 = map1(cos, b1, b2, a1, a2) sb1, sb2, sa1, sa2 = map1(sin, b1, b2, a1, a2) A = sin((1 - fraction) * r) / sr B = sin(fraction * r) / sr x = A * ca1 * cb1 + B * ca2 * cb2 y = A * ca1 * sb1 + B * ca2 * sb2 z = A * sa1 + B * sa2 a = atan2(z, hypot(x, y)) b = atan2(y, x) else: # points too close a = favg(a1, a2, f=fraction) b = favg(b1, b2, f=fraction) if height is None: h = self._havg(other, f=fraction) else: h = height return self.classof(degrees90(a), degrees180(b), height=h)
def distance3To(self, other, radius=R_M, wrap=False): '''Compute the great-circle distance between this and an other geohash using the U{Haversine <http://www.Movable-Type.co.UK/scripts/latlong.html>} formula. @param other: The other geohash (L{Geohash}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @return: Great-circle distance (C{meter}, same units as I{radius}). @raise TypeError: The I{other} is not a L{Geohash}, C{LatLon} or C{str}. ''' other = _2Geohash(other) a1, b1 = self.ab a2, b2 = other.ab db, b2 = unrollPI(b1, b2, wrap=wrap) return haversine_(a2, a1, db) * float(radius)
def intersection(start1, end1, start2, end2, height=None, wrap=False, LatLon=LatLon): '''Compute the intersection point of two paths both defined by two points or a start point and bearing from North. @param start1: Start point of the first path (L{LatLon}). @param end1: End point ofthe first path (L{LatLon}) or the initial bearing at the first start point (compass C{degrees360}). @param start2: Start point of the second path (L{LatLon}). @param end2: End point of the second path (L{LatLon}) or the initial bearing at the second start point (compass C{degrees360}). @keyword height: Optional height for the intersection point, overriding the mean height (C{meter}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @keyword LatLon: Optional (sub-)class for the intersection point (L{LatLon}) or C{None}. @return: The intersection point (I{LatLon}) or 3-tuple (C{degrees90}, C{degrees180}, height) if I{LatLon} is C{None}. An alternate intersection point might be the L{antipode} to the returned result. @raise TypeError: Start or end point(s) not L{LatLon}. @raise ValueError: Intersection is ambiguous or infinite or the paths are parallel, coincident or null. @example: >>> p = LatLon(51.8853, 0.2545) >>> s = LatLon(49.0034, 2.5735) >>> i = intersection(p, 108.547, s, 32.435) # '50.9078°N, 004.5084°E' ''' _Trll.others(start1, name='start1') _Trll.others(start2, name='start2') a1, b1 = start1.to2ab() a2, b2 = start2.to2ab() db, b2 = unrollPI(b1, b2, wrap=wrap) r12 = haversine_(a2, a1, db) if abs(r12) < EPS: # [nearly] coincident points a, b = map1(degrees, favg(a1, a2), favg(b1, b2)) # see <http://www.EdWilliams.org/avform.htm#Intersection> elif isscalar(end1) and isscalar(end2): # both bearings ca1, ca2, cr12 = map1(cos, a1, a2, r12) sa1, sa2, sr12 = map1(sin, a1, a2, r12) x1, x2 = (sr12 * ca1), (sr12 * ca2) if abs(x1) < EPS or abs(x2) < EPS: raise ValueError('intersection %s: %r vs %r' % ('parallel', (start1, end1), (start2, end2))) # handle domain error for equivalent longitudes, # see also functions asin_safe and acos_safe at # <http://www.EdWilliams.org/avform.htm#Math> t1, t2 = map1(acos1, (sa2 - sa1 * cr12) / x1, (sa1 - sa2 * cr12) / x2) if sin(db) > 0: t12, t21 = t1, PI2 - t2 else: t12, t21 = PI2 - t1, t2 t13, t23 = map1(radiansPI2, end1, end2) x1, x2 = map1( wrapPI, t13 - t12, # angle 2-1-3 t21 - t23) # angle 1-2-3 sx1, sx2 = map1(sin, x1, x2) if sx1 == 0 and sx2 == 0: # max(abs(sx1), abs(sx2)) < EPS raise ValueError('intersection %s: %r vs %r' % ('infinite', (start1, end1), (start2, end2))) sx3 = sx1 * sx2 # if sx3 < 0: # raise ValueError('intersection %s: %r vs %r' % ('ambiguous', # (start1, end1), (start2, end2))) cx1, cx2 = map1(cos, x1, x2) x3 = acos1(cr12 * sx3 - cx2 * cx1) r13 = atan2(sr12 * sx3, cx2 + cx1 * cos(x3)) a, b = _destination2(a1, b1, r13, t13) # choose antipode for opposing bearings if _xb(a1, b1, end1, a, b, wrap) < 0 or \ _xb(a2, b2, end2, a, b, wrap) < 0: a, b = antipode(a, b) else: # end point(s) or bearing(s) x1, d1 = _x3d2(start1, end1, wrap, '1') x2, d2 = _x3d2(start2, end2, wrap, '2') x = x1.cross(x2) if x.length < EPS: # [nearly] colinear or parallel paths raise ValueError('intersection %s: %r vs %r' % ('colinear', (start1, end1), (start2, end2))) a, b = x.to2ll() # choose intersection similar to sphericalNvector d1 = _xdot(d1, a1, b1, a, b, wrap) d2 = _xdot(d2, a2, b2, a, b, wrap) if (d1 < 0 and d2 > 0) or (d1 > 0 and d2 < 0): a, b = antipode(a, b) h = start1._havg(start2) if height is None else height return (a, b, h) if LatLon is None else LatLon(a, b, height=h)
def _distances(self, x, y): # (x, y) radians for xk, yk in zip(self._xs, self._ys): d, _ = unrollPI(xk, x, wrap=self._wrap) yield haversine_(y, yk, d)
def intersection(start1, bearing1, start2, bearing2, height=None, wrap=False, LatLon=LatLon): '''Compute the intersection point of two paths each defined by a start point and an initial bearing. @param start1: Start point of first path (L{LatLon}). @param bearing1: Initial bearing from start1 (compass C{degrees360}). @param start2: Start point of second path (L{LatLon}). @param bearing2: Initial bearing from start2 (compass C{degrees360}). @keyword height: Optional height for the intersection point, overriding the mean height (C{meter}). @keyword wrap: Wrap and unroll longitudes (C{bool}). @keyword LatLon: Optional (sub-)class for the intersection point (L{LatLon}) or C{None}. @return: Intersection point (L{LatLon}) or 3-tuple (C{degrees90}, C{degrees180}, height) if C{LatLon} is C{None}. @raise TypeError: Point I{start1} or I{start2} is not L{LatLon}. @raise ValueError: Intersection is ambiguous or infinite or the paths are parallel or coincident. @example: >>> p = LatLon(51.8853, 0.2545) >>> s = LatLon(49.0034, 2.5735) >>> i = intersection(p, 108.547, s, 32.435) # '50.9078°N, 004.5084°E' ''' _Trll.others(start1, name='start1') _Trll.others(start2, name='start2') # see <http://www.EdWilliams.org/avform.htm#Intersection> a1, b1 = start1.to2ab() a2, b2 = start2.to2ab() db, b2 = unrollPI(b1, b2, wrap=wrap) r12 = haversine_(a2, a1, db) if abs(r12) < EPS: # [nearly] coincident points a, b = map1(degrees, favg(a1, a2), favg(b1, b2)) else: ca1, ca2, cr12 = map1(cos, a1, a2, r12) sa1, sa2, sr12 = map1(sin, a1, a2, r12) x1, x2 = (sr12 * ca1), (sr12 * ca2) if abs(x1) < EPS or abs(x2) < EPS: raise ValueError('intersection %s: %r vs %r' % ('parallel', start1, start2)) # handle domain error for equivalent longitudes, # see also functions asin_safe and acos_safe at # <http://www.EdWilliams.org/avform.htm#Math> t1, t2 = map1(acos1, (sa2 - sa1 * cr12) / x1, (sa1 - sa2 * cr12) / x2) if sin(db) > 0: t12, t21 = t1, PI2 - t2 else: t12, t21 = PI2 - t1, t2 t13, t23 = map1(radiansPI2, bearing1, bearing2) x1, x2 = map1(wrapPI, t13 - t12, # angle 2-1-3 t21 - t23) # angle 1-2-3 sx1, sx2 = map1(sin, x1, x2) if sx1 == 0 and sx2 == 0: raise ValueError('intersection %s: %r vs %r' % ('infinite', start1, start2)) sx3 = sx1 * sx2 if sx3 < 0: raise ValueError('intersection %s: %r vs %r' % ('ambiguous', start1, start2)) cx1, cx2 = map1(cos, x1, x2) x3 = acos1(cr12 * sx3 - cx2 * cx1) r13 = atan2(sr12 * sx3, cx2 + cx1 * cos(x3)) a, b = _destination2(a1, b1, r13, t13) h = start1._havg(start2) if height is None else height return (a, b, h) if LatLon is None else LatLon(a, b, height=h)