示例#1
0
    def _inverse(self, other, azis):
        '''(INTERNAL) Inverse Vincenty method.

           @raise TypeError: The other point is not L{LatLon}.

           @raise ValueError: If this and the 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 or this and the other point coincide.
        '''
        E = self.ellipsoids(other)

        c1, s1, _ = _r3(self.lat, E.f)
        c2, s2, _ = _r3(other.lat, E.f)

        c1c2, s1s2 = c1 * c2, s1 * s2
        c1s2, s1c2 = c1 * s2, s1 * c2

        ll = dl = radians(other.lon - self.lon)
        for _ in range(self._iterations):
            cll, sll, ll_ = cos(ll), sin(ll), ll

            ss = hypot(c2 * sll, c1s2 - s1c2 * cll)
            if ss < EPS:
                raise VincentyError('%r coincident with %r' % (self, other))
            cs = s1s2 + c1c2 * cll
            s = atan2(ss, cs)

            sa = c1c2 * sll / ss
            c2a = 1 - (sa * sa)
            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
        else:
            raise VincentyError('no convergence %r to %r' % (self, 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._alter(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
示例#2
0
    def initialBearingTo(self, other, **unused):
        '''Compute the initial bearing (aka forward azimuth) from this
           to an other point.

           @param other: The other point (L{LatLon}).
           @param unused: Optional keyword argument I{wrap} ignored.

           @return: Initial bearing (compass degrees).

           @raise TypeError: The I{other} point is not L{LatLon}.

           @raise Valuerror: Points or polar coincidence.

           @example:

           >>> p1 = LatLon(52.205, 0.119)
           >>> p2 = LatLon(48.857, 2.351)
           >>> b = p1.bearingTo(p2)  # 156.2

           @JSname: I{bearingTo}.
        '''
        gc1 = self.greatCircleTo(other)
        gc2 = self.toNvector().cross(NorthPole, raiser='pole')
        #       gc2 = self.greatCircleTo(NorthPole)

        return degrees360(gc1.angleTo(gc2, vSign=self.toNvector()))
    def initialBearingTo(self, other, wrap=False):
        '''Compute the initial bearing (aka forward azimuth) from
           this to an other point.

           @param other: The other point (L{LatLon}).
           @keyword wrap: Wrap and unroll longitudes (bool).

           @return: Initial bearing (compass degrees).

           @raise TypeError: The I{other} point is not L{LatLon}.

           @example:

           >>> p1 = LatLon(52.205, 0.119)
           >>> p2 = LatLon(48.857, 2.351)
           >>> b = p1.initialBearingTo(p2)  # 156.2

           @JSname: I{bearingTo}.
        '''
        self.others(other)

        a1, b1 = self.to2ab()
        a2, b2 = other.to2ab()

        db, b2 = unrollPI(b1, b2, wrap=wrap)
        ca1, ca2, cdb = map1(cos, a1, a2, db)
        sa1, sa2, sdb = map1(sin, a1, a2, db)

        # see <http://mathforum.org/library/drmath/view/55417.html>
        x = ca1 * sa2 - sa1 * ca2 * cdb
        y = sdb * ca2

        return degrees360(atan2(y, x))
示例#4
0
    def _direct(self, distance, bearing, llr, height=None):
        '''(INTERNAL) Direct Vincenty method.

           @raise VincentyError: Vincenty fails to converge for the current
                                 L{LatLon.epsilon} and L{LatLon.iterations}
                                 limit.
        '''
        E = self.ellipsoid()

        c1, s1, t1 = _r3(self.lat, E.f)

        i = radians(bearing)  # initial bearing (forward azimuth)
        ci, si = cos(i), sin(i)
        s12 = atan2(t1, ci) * 2

        sa = c1 * si
        c2a = 1 - sa**2
        if c2a < EPS:
            c2a = 0
            A, B = 1, 0
        else:  # e22 == (a / b)**2 - 1
            A, B = _p2(c2a * E.e22)

        s = d = distance / (E.b * A)
        for _ in range(self._iterations):
            cs, ss, c2sm = cos(s), sin(s), cos(s12 + s)
            s_, s = s, d + _ds(B, cs, ss, c2sm)
            if abs(s - s_) < self._epsilon:
                break
        else:
            raise VincentyError('no convergence %r' % (self, ))

        t = s1 * ss - c1 * cs * ci
        # final bearing (reverse azimuth +/- 180)
        r = degrees360(atan2(sa, -t))
        if llr:
            # destination latitude in [-270, 90)
            a = degrees90(
                atan2(s1 * cs + c1 * ss * ci, (1 - E.f) * hypot(sa, t)))
            # destination longitude in [-180, 180)
            b = degrees180(
                atan2(ss * si, c1 * cs - s1 * ss * ci) -
                _dl(E.f, c2a, sa, s, cs, ss, c2sm) + radians(self.lon))
            h = self.height if height is None else height
            r = self.classof(a, b, height=h, datum=self.datum), r
        return r
示例#5
0
    def rhumbBearingTo(self, other):
        '''Return the initial bearing (forward azimuth) from this
           to an other point along a rhumb (loxodrome) line.

           @param other: The other point (spherical LatLon).

           @return: Initial bearing (compass degrees).

           @raise TypeError: The other point is not spherical.

           @example:

           >>> p = LatLon(51.127, 1.338)
           >>> q = LatLon(50.964, 1.853)
           >>> b = p.rhumbBearingTo(q)  # 116.7
        '''
        _, db, dp = self._rhumb3(other)

        return degrees360(atan2(db, dp))
示例#6
0
def compassAngle(lat0, lon0, lat1, lon1):
    '''Return the angle from North for the direction vector
       M{(lon1 - lon0, lat1 - lat0)} between two points.

       Suitable only for short, non-near-polar vectors up to a few
       hundred Km or Miles.  Use I{LatLon} methods I{initialBearingTo}
       or I{forward azimuth} for larger distances.

       @param lat0: From latitude (degrees).
       @param lon0: From longitude (degrees).
       @param lat1: To latitude (degrees).
       @param lon1: To longitude (degrees).

       @return: Angle from North (degrees360).

       @note: Courtesy Martin Schultz.

       @see: U{Local, Flat Earth<http://www.edwilliams.org/avform.htm#flat>}.
    '''
    return degrees360(atan2(lon1 - lon0, lat1 - lat0))
示例#7
0
    def bearingTo(self, other):
        '''Computes the initial bearing (aka forward azimuth) from this
           to an other point.

           @param other: The other point (L{LatLon}).

           @return: Initial bearing (compass degrees).

           @raise TypeError: The other point is not L{LatLon}.

           @example:

           >>> p1 = LatLon(52.205, 0.119)
           >>> p2 = LatLon(48.857, 2.351)
           >>> b = p1.bearingTo(p2)  # 156.2
        '''
        gc1 = self.greatCircleTo(other)
        gc2 = self.toNvector().cross(NorthPole)
        #       gc2 = self.greatCircleTo(NorthPole)

        return degrees360(gc1.angleTo(gc2, vSign=self.toNvector()))
示例#8
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:
                raise VincentyError('%r coincides with %r' % (self, other))
            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://en.wikipedia.org/wiki/Vincenty's_formulae>


#           elif abs(ll) > PI and self.isantipode(other, eps=self._epsilon):
#              raise VincentyError('%r antipodal to %r' % (self, other))
        else:
            t = 'antipodal ' if self.isantipode(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
示例#9
0
 def bearing(self):
     '''Get bearing of this NED vector in compass degrees (degrees360).
     '''
     if self._bearing is None:
         self._bearing = degrees360(atan2(self.east, self.north))
     return self._bearing