Пример #1
0
    def destinationNed(self, delta):
        '''Calculates destination point using supplied delta from this point.

           @param delta: Delta from this to the other point in the
                         local tangent plane (LTP) of this point (L{Ned}).

           @return: Destination point (L{Cartesian}).

           @raise TypeError: The delta is not L{Ned}.

           @example:

           >>> a = LatLon(49.66618, 3.45063)
           >>> delta = toNed(116807.681, 222.493, -0.5245)  # [N:-86126, E:-78900, D:1069]
           >>> b = a.destinationNed(delta)  # 48.88667°N, 002.37472°E

           @JSname: I{destinationPoint}.
        '''
        if not isinstance(delta, Ned):
            raise TypeError('type(%s) not %s.%s' %
                            ('delta', Ned.__module__, Ned.__name__))

        n, e, d = self._rotation3()
        # convert NED delta to standard Vector3d in coordinate frame of n-vector
        dn = delta.toVector3d().to3xyz()
        # rotate dn to get delta in cartesian (ECEF) coordinate
        # reference frame using the rotation matrix column vectors
        dc = Cartesian(fdot(dn, n.x, e.x, d.x), fdot(dn, n.y, e.y, d.y),
                       fdot(dn, n.z, e.z, d.z))

        # apply (cartesian) delta to this Cartesian to
        # obtain destination point as cartesian
        v = self.toCartesian().plus(dc)  # the plus() gives a plain vector

        return Cartesian(v.x, v.y, v.z).toLatLon(datum=self.datum)
Пример #2
0
 def Mabcd(self):
     '''Get the OSGR meridional coefficients, Airy130 only (4-tuple).
     '''
     if self._Mabcd is None:
         n = self.n
         n2 = n * n
         n3 = n * n2
         # XXX i/i quotients require  from __future__ import division
         self._Mabcd = (fdot((1, n, n2, n3), 1, 1, 5 / 4,
                             5 / 4), fdot((n, n2, n3), 3, 3, 21 / 8),
                        fdot((n2, n3), 15 / 8, 15 / 8), 35 / 24 * n3)
     return self._Mabcd
Пример #3
0
def _M(Mabcd, a):
    '''(INTERNAL) Compute meridional arc.
    '''
    a_ = a - _A0
    _a = a + _A0
    return _F0 * fdot(Mabcd, a_, -sin(a_)     * cos(_a),
                                  sin(a_ * 2) * cos(_a * 2),
                                 -sin(a_ * 3) * cos(_a * 3))
Пример #4
0
    def dot(self, other):
        '''Dot (scalar) product of this and an other vector.

           @param other: The other vector (L{Vector3d}).

           @return: Dot product (float).
        '''
        self.others(other)

        return fdot(self.to3xyz(), *other.to3xyz())
Пример #5
0
    def transform(self, x, y, z, inverse=False):
        '''Transform a (geocentric) Cartesian point, forward or inverse.

           @param x: X coordinate (meter).
           @param y: Y coordinate (meter).
           @param z: Z coordinate (meter).
           @keyword inverse: Direction, forward or inverse (bool).

           @return: 3-Tuple (x, y, z) transformed.
        '''
        if inverse:
            xyz = -1, -x, -y, -z
            _s1 = self.s1 - 2  # negative inverse: -(1 - s * 1.e-6)
        else:
            xyz = 1, x, y, z
            _s1 = self.s1
        # x', y', z' = (.tx + x * .s1 - y * .rz + z * .ry,
        #               .ty + x * .rz + y * .s1 - z * .rx,
        #               .tz - x * .ry + y * .rx + z * .s1)
        return (fdot(xyz, self.tx, _s1, -self.rz,
                     self.ry), fdot(xyz, self.ty, self.rz, _s1, -self.rx),
                fdot(xyz, self.tz, -self.ry, self.rx, _s1))
Пример #6
0
    def rotate(self, axis, theta):
        '''Rotate this vector by a specified angle around an axis.

           See U{Rotation matrix from axis and angle<http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix/Rodrigues'_rotation_formula...>}

           @param axis: The axis being rotated around (L{Vector3d}).
           @param theta: The angle of rotation (radians).

           @return: New, rotated vector (L{Vector3d}).
        '''
        self.others(axis, name='axis')

        c = cos(theta)
        a = axis.unit()  # axis being rotated around
        b = a.times(1 - c)
        s = a.times(sin(theta))

        p = self.unit().to3xyz()  # point being rotated
        # multiply p by a quaternion-derived rotation matrix
        return self.topsub(
            fdot(p, a.x * b.x + c, a.x * b.y - s.z, a.x * b.z + s.y),
            fdot(p, a.y * b.x + s.z, a.y * b.y + c, a.y * b.z - s.x),
            fdot(p, a.z * b.x - s.y, a.z * b.y + s.x, a.z * b.z + c))
Пример #7
0
    def _K6(self, *fs6):
        '''(INTERNAL) Compute 6th-order Krüger Alpha or Beta series
           per Karney 2011, 'Transverse Mercator with an accuracy
           of a few nanometers', page 7, equations 35 and 36, see
           <https://arxiv.org/pdf/1002.1417v3.pdf>.

           @param fs6: 6-Tuple of coefficent tuples.

           @return: 6th-Order Krüger (7-tuple, 1-origin).
        '''
        ns = [self.n]  # 3rd flattening: n, n**2, ... n**6
        for i in range(len(fs6) - 1):
            ns.append(ns[0] * ns[i])

        k6 = [0]  # 1-origin
        for fs in fs6:
            i = len(ns) - len(fs)
            k6.append(fdot(fs, *ns[i:]))

        return tuple(k6)
Пример #8
0
def toOsgr(latlon, lon=None, datum=Datums.WGS84):
    '''Convert lat-/longitude to a OSGR coordinate.

       @param latlon: Latitude in degrees (scalar) or an
                      ellipsoidal LatLon location.
       @keyword lon: Longitude in degrees (scalar or None).
       @keyword datum: Datum to use (L{Datum}).

       @return: The OSGR coordinate (L{Osgr}).

       @raise TypeError: If latlon is not ellipsoidal.

       @raise ValueError: If lon is invalid, not None.

       @example:

       >>> p = LatLon(52.65798, 1.71605)
       >>> r = toOsgr(p)  # TG 51409 13177
       >>> # for conversion of (historical) OSGB36 lat-/longitude:
       >>> r = toOsgr(52.65757, 1.71791, datum=Datums.OSGB36)
    '''
    if isscalar(latlon) and isscalar(lon):
        # XXX any ellipsoidal LatLon with .convertDatum
        latlon = LatLonEllipsoidalBase(latlon, lon, datum=datum)
    elif not hasattr(latlon, 'convertDatum'):
        raise TypeError('%s not ellipsoidal: %r' % ('latlon', latlon))
    elif lon is not None:
        raise ValueError('%s not %s: %r' % ('lon', None, lon))

    if latlon.datum != _OSGB36:
        latlon = latlon.convertDatum(_OSGB36)

    E = _OSGB36.ellipsoid

    a, b = radians(latlon.lat), radians(latlon.lon)

    ca, sa, ta = cos(a), sin(a), tan(a)

    s = 1 - E.e2 * sa * sa
    v = E.a * _F0 / sqrt(s)
    r = s / E.e12  # = v / r = v / (v * E.e12 / s)

    ca3 = ca * ca * ca
    ca5 = ca * ca * ca3

    ta2 = ta  * ta
    ta4 = ta2 * ta2

    x2 = r - 1  # η

    I4 = (E.b * _M(E.Mabcd, a) + _N0,
         (v /   2) * sa * ca,
         (v /  24) * sa * ca3 * (5 - ta2 + 9 * x2),
         (v / 720) * sa * ca5 * (61 - 58 * ta2 + ta4))

    V4 = (_E0,
          v * ca,
         (v /   6) * ca3 * (r - ta2),
         (v / 120) * ca5 * (5 - 18 * ta2 + ta4 + 14 * x2 - 58 * ta2 * x2))

    d = b - _B0
    d2 = d  * d
    d3 = d2 * d
    d5 = d2 * d3

    n = fdot(I4, 1, d2, d3 * d, d5 * d)
    e = fdot(V4, 1, d,  d3,     d5)

    return Osgr(e, n)
Пример #9
0
    def toLatLon(self, LatLon, datum=Datums.WGS84):
        '''Convert this OSGR coordinate to an ellipsoidal lat-/longitude
           point.

           Note formulation implemented here due to Thomas, Redfearn, etc.
           is as published by OS, but is inferior to Krüger as used by
           e.g. Karney 2011.

           @param LatLon: Ellipsoidal LatLon class to use (L{LatLon}).
           @param datum: Darum to use (L{Datum}).

           @return: The elliposoidal point (L{LatLon}).

           @raise TypeError: If L{LatLon} is not ellipsoidal.

           @example:

           >>> from pygeodesy import ellipsoidalVincenty as eV
           >>> g = Osgr(651409.903, 313177.270)
           >>> p = g.toLatLon(ev.LatLon)  # 52°39′28.723″N, 001°42′57.787″E
           >>> # to obtain (historical) OSGB36 lat-/longitude point
           >>> p = g.toLatLon(ev.LatLon, datum=Datums.OSGB36)  # 52°39′27.253″N, 001°43′04.518″E
        '''
        if self._latlon and self._latlon.__class__ is LatLon \
                        and self._latlon.datum == datum:
            return self._latlon  # set below

        if not issubclass(LatLon, LatLonEllipsoidalBase):
            raise TypeError('%s not %s: %r' % ('LatLon', 'ellipsoidal', LatLon))

        E = _OSGB36.ellipsoid  # Airy130
        Mabcd = E.Mabcd

        e, n = self._easting, self._northing

        a, M = _A0, 0
        while True:
            t = n - _N0 - M
            if t < _10um:
                break
            a += t / (E.a * _F0)
            M = E.b * _M(Mabcd, a)

        ca, sa, ta = cos(a), sin(a), tan(a)

        s = 1 - E.e2 * sa * sa
        v = E.a * _F0 / sqrt(s)
        r = v * E.e12 / s

        x2 = v / r - 1  # η

        v3 = v * v * v
        v5 = v * v * v3
        v7 = v * v * v5

        ta2 = ta  * ta
        ta4 = ta2 * ta2
        ta6 = ta4 * ta2

        V4 = (a,
              ta / (  2 * r * v),
              ta / ( 24 * r * v3) * fdot((5, 3, 1, -9), 1, ta2, x2, x2 * ta2),
              ta / (720 * r * v5) * fdot((61, 90, 45), 1, ta2, ta4))

        sca = 1 / ca
        X5 = (_B0,
              sca / v,
              sca / (   6 * v3) * (v / r + 2 * ta),
              sca / ( 120 * v5) * fdot((5, 28, 24), 1, ta2, ta4),
              sca / (5040 * v7) * fdot((61, 662, 1320, 720), ta, ta2, ta4, ta6))

        d  = e - _E0
        d2 = d  * d
        d4 = d2 * d2
        d6 = d2 * d4

        a = fdot(V4, 1,    -d2,     d4,     -d6)
        b = fdot(X5, 1, d, -d2 * d, d4 * d, -d6 * d)

        ll = LatLon(degrees90(a), degrees180(b), datum=_OSGB36)
        if datum != _OSGB36:
            ll = ll.convertDatum(datum)
            ll = LatLon(ll.lat, ll.lon, datum=datum)

        self._latlon = ll
        return ll