def compassAngle(lat1, lon1, lat2, lon2, adjust=True, wrap=False): '''Return the angle from North for the direction vector M{(lon2 - lon1, lat2 - lat1)} between two points. Suitable only for short, non-near-polar vectors up to a few hundred Km or Miles. Use function L{bearing} for longer vectors. @param lat1: From latitude (C{degrees}). @param lon1: From longitude (C{degrees}). @param lat2: To latitude (C{degrees}). @param lon2: To longitude (C{degrees}). @keyword adjust: Adjust the longitudinal delta by the cosine of the mean latitude (C{bool}). @keyword wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Compass angle from North (C{degrees360}). @note: Courtesy Martin Schultz. @see: U{Local, flat earth approximation <http://www.EdWilliams.org/avform.htm#flat>}. ''' d_lon, _ = unroll180(lon1, lon2, wrap=wrap) if adjust: # scale delta lon d_lon *= _scaled(lat1, lat2) return degrees360(atan2(d_lon, lat2 - lat1))
def haversine(lat1, lon1, lat2, lon2, radius=R_M, wrap=False): '''Compute the distance between two (spherical) points using the U{Haversine<https://www.Movable-Type.co.UK/scripts/latlong.html>} formula. @param lat1: Start latitude (C{degrees}). @param lon1: Start longitude (C{degrees}). @param lat2: End latitude (C{degrees}). @param lon2: End longitude (C{degrees}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as B{C{radius}}). @see: U{Distance between two (spherical) points <https://www.EdWilliams.org/avform.htm#Dist>}, functions L{equirectangular}, L{euclidean} and L{vincentys} and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}. @note: See note under L{vincentys_}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) r = haversine_(radians(lat2), radians(lat1), radians(d)) return r * float(radius)
def equirectangular_(lat1, lon1, lat2, lon2, adjust=True, limit=45, wrap=False): '''Compute the distance between two points using the U{Equirectangular Approximation / Projection <http://www.Movable-Type.co.UK/scripts/latlong.html>}. This approximation is valid for short distance of several hundred Km or Miles, see the I{limit} keyword argument and the L{LimitError}. @param lat1: Start latitude (C{degrees}). @param lon1: Start longitude (C{degrees}). @param lat2: End latitude (C{degrees}). @param lon2: End longitude (C{degrees}). @keyword adjust: Adjust the wrapped, unrolled longitudinal delta by the cosine of the mean latitude (C{bool}). @keyword limit: Optional limit for lat- and longitudinal deltas (C{degrees}) or C{None} or C{0} for unlimited. @keyword wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: 4-Tuple (distance2, delta_lat, delta_lon, unroll_lon2) with the distance in C{degrees squared}, the latitudinal delta I{lat2}-I{lat1}, the wrapped, unrolled, and adjusted longitudinal delta I{lon2}-I{lon1} and the unrollment for I{lon2}. Use Function L{degrees2m} to convert C{degrees squared} to distance in C{meter} as M{degrees2m(sqrt(distance2), ...)} or M{degrees2m(hypot(delta_lat, delta_lon), ...)}. @raise LimitError: If the lat- and/or longitudinal delta exceeds the I{-limit..+limit} range and L{limiterrors} set to C{True}. @see: U{Local, flat earth approximation <http://www.EdWilliams.org/avform.htm#flat>}, functions L{equirectangular} and L{haversine}, L{Ellipsoid} method C{distance2} and C{LatLon} methods C{distanceTo*} for more accurate and/or larger distances. ''' d_lat = lat2 - lat1 d_lon, ulon2 = unroll180(lon1, lon2, wrap=wrap) if limit and _limiterrors \ and max(abs(d_lat), abs(d_lon)) > limit > 0: t = fStr((lat1, lon1, lat2, lon2), prec=4) raise LimitError('%s(%s, limit=%s) delta exceeds limit' % ('equirectangular_', t, fStr(limit, prec=2))) if adjust: # scale delta lon d_lon *= cos(radians(lat1 + lat2) * 0.5) d2 = d_lat**2 + d_lon**2 # degrees squared! return d2, d_lat, d_lon, ulon2 - lon2
def equirectangular_(lat1, lon1, lat2, lon2, adjust=True, limit=45, wrap=False): '''Compute the distance between two points using the U{Equirectangular Approximation / Projection <https://www.Movable-Type.co.UK/scripts/latlong.html>}. This approximation is valid for short distance of several hundred Km or Miles, see the B{C{limit}} keyword argument and the L{LimitError}. @param lat1: Start latitude (C{degrees}). @param lon1: Start longitude (C{degrees}). @param lat2: End latitude (C{degrees}). @param lon2: End longitude (C{degrees}). @keyword adjust: Adjust the wrapped, unrolled longitudinal delta by the cosine of the mean latitude (C{bool}). @keyword limit: Optional limit for lat- and longitudinal deltas (C{degrees}) or C{None} or C{0} for unlimited. @keyword wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: A L{Distance4Tuple}C{(distance2, delta_lat, delta_lon, unroll_lon2)}. @raise LimitError: If the lat- and/or longitudinal delta exceeds the B{C{-limit..+limit}} range and L{limiterrors} set to C{True}. @see: U{Local, flat earth approximation <https://www.EdWilliams.org/avform.htm#flat>}, functions L{equirectangular}, L{euclidean}, L{haversine} and L{vincentys} and methods L{Ellipsoid.distance2}, C{LatLon.distanceTo*} and C{LatLon.equirectangularTo}. ''' d_lat = lat2 - lat1 d_lon, ulon2 = unroll180(lon1, lon2, wrap=wrap) if limit and _limiterrors \ and max(abs(d_lat), abs(d_lon)) > limit > 0: t = fStr((lat1, lon1, lat2, lon2), prec=4) raise LimitError('%s(%s, limit=%s) delta exceeds limit' % ('equirectangular_', t, fStr(limit, prec=2))) if adjust: # scale delta lon d_lon *= _scaled(lat1, lat2) d2 = d_lat**2 + d_lon**2 # degrees squared! return Distance4Tuple(d2, d_lat, d_lon, ulon2 - lon2)
def _inverse(self, other, azis, wrap): '''(INTERNAL) Inverse Karney method. @raise TypeError: The other point is not L{LatLon}. @raise ValueError: If this and the I{other} point's L{Datum} ellipsoids are not compatible. ''' g = self.ellipsoids(other).geodesic m = g.DISTANCE if azis: m |= g.AZIMUTH _, lon = unroll180(self.lon, other.lon, wrap=wrap) r = g.Inverse(self.lat, self.lon, other.lat, lon, m) t = r['s12'] if azis: # forward and reverse azimuth t = t, wrap360(r['azi1']), wrap360(r['azi2']) return t
def vincentys(lat1, lon1, lat2, lon2, radius=R_M, wrap=False): '''Compute the distance between two (spherical) points using U{Vincenty's<http://WikiPedia.org/wiki/Great-circle_distance>} spherical formula. @param lat1: Start latitude (C{degrees}). @param lon1: Start longitude (C{degrees}). @param lat2: End latitude (C{degrees}). @param lon2: End longitude (C{degrees}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as I{radius}). @see: Functions L{equirectangular}, L{euclidean} and L{haversine} and methods L{Ellipsoid.distance2}, C{LatLon} I{distanceTo*} and I{equirectangularTo}. @note: See note under L{vincentys_}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) r = vincentys_(radians(lat2), radians(lat1), radians(d)) return r * float(radius)
def euclidean(lat1, lon1, lat2, lon2, radius=R_M, adjust=True, wrap=False): '''Approximate the C{Euclidian} distance between two (spherical) points. @param lat1: Start latitude (C{degrees}). @param lon1: Start longitude (C{degrees}). @param lat2: End latitude (C{degrees}). @param lon2: End longitude (C{degrees}). @keyword radius: Optional, mean earth radius (C{meter}). @keyword adjust: Adjust the longitudinal delta by the cosine of the mean latitude (C{bool}). @keyword wrap: Wrap and L{unroll180} longitudes (C{bool}). @return: Distance (C{meter}, same units as I{radius}). @see: U{Distance between two (spherical) points <http://www.EdWilliams.org/avform.htm#Dist>}, functions L{equirectangular}, L{haversine} and L{vincentys} and methods L{Ellipsoid.distance2}, C{LatLon} I{distanceTo*} and I{equirectangularTo}. ''' d, _ = unroll180(lon1, lon2, wrap=wrap) r = euclidean_(radians(lat2), radians(lat1), radians(d), adjust=adjust) return r * float(radius)
def _dxy(x1, i): x2, y2, _ = pts[i] dx, x2 = unroll180(x1, x2, wrap=i < (n - 1)) return dx, x2, y2
def _unroll_adjust(x1, y1, x2, y2, wrap): x21, x2 = unroll180(x1, x2, wrap=wrap) if adjust: x21 *= cos(radians(y1 + y2) * 0.5) return x21, x2
def _unroll_adjust(x1, y1, x2, y2, wrap): x21, x2 = unroll180(x1, x2, wrap=wrap) if adjust: y = radians(y1 + y2) * 0.5 x21 *= cos(y) if abs(y) < PI_2 else 0 return x21, x2
def _inverse(self, other, azis, wrap): '''(INTERNAL) Inverse Vincenty method. @raise TypeError: The other point is not L{LatLon}. @raise ValueError: If this and the I{other} point's L{Datum} ellipsoids are not compatible. @raise VincentyError: Vincenty fails to converge for the current L{LatLon.epsilon} and L{LatLon.iterations} limit and/or if this and the I{other} point are near-antipodal or coincide. ''' E = self.ellipsoids(other) c1, s1, _ = _r3(self.lat, E.f) c2, s2, _ = _r3(other.lat, E.f) c1c2, s1c2 = c1 * c2, s1 * c2 c1s2, s1s2 = c1 * s2, s1 * s2 dl, _ = unroll180(self.lon, other.lon, wrap=wrap) ll = dl = radians(dl) for _ in range(self._iterations): cll, sll, ll_ = cos(ll), sin(ll), ll ss = hypot(c2 * sll, c1s2 - s1c2 * cll) if ss < EPS: # coincident, ... d = 0.0 # like Karney, ... if azis: # return zeros d = d, 0, 0 return d cs = s1s2 + c1c2 * cll s = atan2(ss, cs) sa = c1c2 * sll / ss c2a = 1 - sa**2 if abs(c2a) < EPS: c2a = 0 # equatorial line ll = dl + E.f * sa * s else: c2sm = cs - 2 * s1s2 / c2a ll = dl + _dl(E.f, c2a, sa, s, cs, ss, c2sm) if abs(ll - ll_) < self._epsilon: break # <http://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-vincenty.js> # omitted and applied only after failure to converge, see footnote under # Inverse at <http://WikiPedia.org/wiki/Vincenty's_formulae> # elif abs(ll) > PI and self.isantipodeTo(other, eps=self._epsilon): # raise VincentyError('%r antipodal to %r' % (self, other)) else: t = 'antipodal ' if self.isantipodeTo(other, eps=self._epsilon) else '' raise VincentyError('no convergence, %r %sto %r' % (self, t, other)) if c2a: # e22 == (a / b)**2 - 1 A, B = _p2(c2a * E.e22) s = A * (s - _ds(B, cs, ss, c2sm)) b = E.b # if self.height or other.height: # b += self._havg(other) d = b * s if azis: # forward and reverse azimuth cll, sll = cos(ll), sin(ll) f = degrees360(atan2(c2 * sll, c1s2 - s1c2 * cll)) r = degrees360(atan2(c1 * sll, -s1c2 + c1s2 * cll)) d = d, f, r return d