Ejemplo n.º 1
0
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))
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
 def _dxy(x1, i):
     x2, y2, _ = pts[i]
     dx, x2 = unroll180(x1, x2, wrap=i < (n - 1))
     return dx, x2, y2
Ejemplo n.º 9
0
 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
Ejemplo n.º 10
0
 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
Ejemplo n.º 11
0
    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