Exemple #1
0
def toOsgr(latlon, lon=None, datum=Datums.WGS84, Osgr=Osgr):
    '''Convert a lat-/longitude point to an OSGR coordinate.

       @param latlon: Latitude (degrees) or an (ellipsoidal)
                      geodetic I{LatLon} point.
       @keyword lon: Optional longitude in degrees (scalar or None).
       @keyword datum: Optional datum to convert (I{Datum}).
       @keyword Osgr: Optional Osgr class to use for the
                      OSGR coordinate (L{Osgr}).

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

       @raise TypeError: If I{latlon} is not ellipsoidal or if
                         I{datum} conversion failed.

       @raise ValueError: Invalid I{latlon} or I{lon}.

       @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 not isinstance(latlon, _eLLb):
        # XXX fix failing _eLLb.convertDatum()
        latlon = _eLLb(*parseDMS2(latlon, lon), datum=datum)
    elif lon is not None:
        raise ValueError('%s not %s: %r' % ('lon', None, lon))

    E = _OSGB36.ellipsoid

    ll = _ll2datum(latlon, _OSGB36, 'latlon')
    a, b = map1(radians, ll.lat, ll.lon)

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

    s = E.e2s2(sa)
    v = E.a * _F0 / sqrt(s)  # nu
    r = s / E.e12  # nu / rho == v / (v * E.e12 / s)

    x2 = r - 1  # η2

    ca3, ca5 = fpowers(ca, 5, 3)  # PYCHOK false!
    ta2, ta4 = fpowers(ta, 4, 2)  # PYCHOK false!

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

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

    d, d2, d3, d4, d5, d6 = fpowers(b - _B0, 6)  # PYCHOK false!
    n = fdot(I4, 1, d2, d4, d6)
    e = fdot(V4, 1, d, d3, d5)

    return Osgr(e, n)
Exemple #2
0
def _Hf(e0, e1, e2, e3, e4, e5):
    '''(INTERNAL) Horner form for C{_RD} and C{_RJ} below.
    '''
    # Polynomial is <https://DLMF.NIST.gov/19.36.E2>
    # (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26
    #    - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272
    #    - 9*(E3*E4+E2*E5)/68)
    return fsum_(fsum_(471240,      -540540 * e2) * e5,
                 fsum_(612612 * e2, -540540 * e3,    -556920) * e4,
                 fsum_(306306 * e3,  675675 * e2**2, -706860 * e2, 680680) * e3,
                 fsum_(417690 * e2, -255255 * e2**2, -875160) * e2,
                 4084080) / (4084080 * e1) + e0
Exemple #3
0
def _RG(x, y, z=None):
    '''Symmetric integral of the second kind C{_RG}.

       @return: C{_RG(x, y, z)}.

       @see: U{C{_RG} definition<https://DLMF.NIST.gov/19.16.E3>}
             and in Carlson, eq. 1.5.
    '''
    if z is None:
        # Carlson, eqs 2.36 - 2.39
        a, b = sqrt(x), sqrt(y)
        if a < b:
            a, b = b, a
        S = Fsum(0.25 * (a + b)**2)
        m = -0.25  # note, negative
        while abs(a - b) > (_tolRG0 * a):  # max 4 trips
            b, a = sqrt(a * b), (a + b) * 0.5
            m *= 2
            S.fadd_(m * (a - b)**2)
        return S.fsum() * PI_2 / (a + b)

    if not z:
        y, z = z, y
    # Carlson, eq 1.7
    return fsum_(_RF(x, y, z) * z,
                 _RD_3(x, y, z) * (x - z) * (z - y),
                 sqrt(x * y / z)) * 0.5
Exemple #4
0
def _RD(x, y, z):
    '''Degenerate symmetric integral of the third kind C{_RD}.

       @return: C{_RD(x, y, z) = _RJ(x, y, z, z)}.

       @see: U{C{_RD} definition<https://DLMF.NIST.gov/19.16.E5>}.
    '''
    # Carlson, eqs 2.28 - 2.34
    m = 1.0
    S = Fsum()
    A = fsum_(x, y, z, z, z) * 0.2
    T = [A, x, y, z]
    Q = _Q(A, T, _tolRD)
    for _ in range(_TRIPS):
        if Q < abs(m * T[0]):  # max 7 trips
            break
        t = T[3]  # z0
        r, s, T = _rsT(T)
        S.fadd_(1.0 / (m * s[2] * (t + r)))
        m *= 4
    else:
        raise EllipticError('no %s convergence' % ('RD',))

    S *= 3
    m *= T[0]  # An
    x = (x - A) / m
    y = (y - A) / m
    z = (x + y) / 3.0
    z2 = z**2
    xy = x * y
    return _Hf(S.fsum(), m * sqrt(T[0]),
               xy - 6 * z2,
              (xy * 3 - 8 * z2) * z,
              (xy - z2) * 3 * z2,
               xy * z2 * z)
Exemple #5
0
def heightOf(angle, distance, radius=R_M):
    '''Determine the height above the (spherical) earth after
       traveling along a straight line at a given tilt.

       @param angle: Tilt angle above horizontal (C{degrees}).
       @param distance: Distance along the line (C{meter} or same units
                        as I{radius}).
       @keyword radius: Optional mean earth radius (C{meter}).

       @return: Height (C{meter}, same units as I{distance} and I{radius}).

       @raise ValueError: Invalid I{angle}, I{distance} or I{radius}.

       @see: U{MultiDop GeogBeamHt<http://GitHub.com/NASA/MultiDop>}
             (U{Shapiro et al. 2009, JTECH
             <http://journals.AMetSoc.org/doi/abs/10.1175/2009JTECHA1256.1>}
             and U{Potvin et al. 2012, JTECH
             <http://journals.AMetSoc.org/doi/abs/10.1175/JTECH-D-11-00019.1>}).
    '''
    d, r = distance, radius
    if d > r:
        d, r = r, d

    if d > EPS:
        d = d / float(r)
        s = sin(radians(angle))
        s = fsum_(1, 2 * s * d, d**2)
        if s > 0:
            return r * sqrt(s) - float(radius)

    raise ValueError('%s%r' % ('heightOf', (angle, distance, radius)))
Exemple #6
0
def _RJ(x, y, z, p):
    '''Symmetric integral of the third kind C{_RJ}.

       @return: C{_RJ(x, y, z, p)}.

       @see: U{C{_RJ} definition<https://DLMF.NIST.gov/19.16.E2>}.
    '''
    def _xyzp(x, y, z, p):
        return (x + p) * (y + p) * (z + p)

    # Carlson, eqs 2.17 - 2.25
    m = m3 = 1.0
    S = Fsum()
    D = -_xyzp(x, y, z, -p)
    A = fsum_(x, y, z, 2 * p) * 0.2
    T = [A, x, y, z, p]
    Q = _Q(A, T, _tolRD)
    for _ in range(_TRIPS):
        if Q < abs(m * T[0]):  # max 7 trips
            break
        _, s, T = _rsT(T)
        d = _xyzp(*s)
        e = D / (m3 * d**2)
        S.fadd_(_RC(1, 1 + e) / (m * d))
        m *= 4
        m3 *= 64
    else:
        raise EllipticError('no %s convergence' % ('RJ',))

    S *= 6
    m *= T[0]  # An
    x = (A - x) / m
    y = (A - y) / m
    z = (A - z) / m
    xyz = x * y * z
    p = -(x + y + z) * 0.5
    p2 = p**2

    e2 = fsum_(x * y, x * z, y * z, -3 * p2)
    return _Hf(S.fsum(), m * sqrt(T[0]),
               e2,
               fsum_(xyz, 2 * p * e2, 4 * p * p2),
               fsum_(xyz * 2, p * e2, 3 * p * p2) * p,
               p2 * xyz)
Exemple #7
0
def _RF(x, y, z=None):
    '''Symmetric integral of the first kind C{_RF}.

       @return: C{_RF(x, y, z)}.

       @see: U{C{_RF} definition<https://DLMF.NIST.gov/19.16.E1>}.
    '''
    if z is None:
        # Carlson, eqs 2.36 - 2.38
        a, b = sqrt(x), sqrt(y)
        if a < b:
            a, b = b, a
        while abs(a - b) > (_tolRG0 * a):  # max 4 trips
            b, a = sqrt(a * b), (a + b) * 0.5
        return PI / (a + b)

    # Carlson, eqs 2.2 - 2.7
    m = 1.0
    A = fsum_(x, y, z) / 3.0
    T = [A, x, y, z]
    Q = _Q(A, T, _tolRF)
    for _ in range(_TRIPS):
        if Q < abs(m * T[0]):  # max 6 trips
            break
        _, _, T = _rsT(T)
        m *= 4
    else:
        raise EllipticError('no %s convergence' % ('RF',))

    m *= T[0]  # An
    x = (A - x) / m
    y = (A - y) / m
    z = -(x + y)

    e2 = x * y - z**2
    e3 = x * y * z
    # Polynomial is <https://DLMF.NIST.gov/19.36.E1>
    # (1 - E2/10 + E3/14 + E2^2/24 - 3*E2*E3/44
    #    - 5*E2^3/208 + 3*E3^2/104 + E2^2*E3/16)
    # convert to Horner form ...
    return fsum_(fsum_( 6930 * e3, 15015 * e2**2, -16380 * e2, 17160) * e3,
                 fsum_(10010 * e2, -5775 * e2**2, -24024) * e2,
                 240240) / (240240 * sqrt(T[0]))
    def to3llh(self, datum=Datums.WGS84):
        '''Convert this (geocentric) Cartesian (x/y/z) point to
           (ellipsoidal) geodetic lat-, longitude and height on
           the given datum.

           Uses Bowring’s (1985) formulation for μm precision in concise
           form: U{'The accuracy of geodetic latitude and height equations'
           <http://www.researchgate.net/publication/
           233668213_The_Accuracy_of_Geodetic_Latitude_and_Height_Equations>},
           B. R. Bowring, Survey Review, Vol 28, 218, Oct 1985.

           See also Ralph M. Toms U{'An Efficient Algorithm for Geocentric
           to Geodetic Coordinate Conversion'
           <http://www.osti.gov/scitech/biblio/110235>}, Sept 1995 and
           U{'An Improved Algorithm for Geocentric to Geodetic Coordinate
           Conversion'<http://www.osti.gov/scitech/servlets/purl/231228>},
           Apr 1996, from Lawrence Livermore National Laboratory.

           @keyword datum: Optional datum to use (L{Datum}).

           @return: 3-Tuple (lat, lon, heigth) in (degrees90,
                    degrees180, meter).
        '''
        E = datum.ellipsoid
        x, y, z = self.to3xyz()

        p = hypot(x, y)  # distance from minor axis
        r = hypot(p, z)  # polar radius

        if min(p, r) > EPS:
            # parametric latitude (Bowring eqn 17, replaced)
            t = (E.b * z) / (E.a * p) * (1 + E.e22 * E.b / r)
            c = 1 / hypot1(t)
            s = t * c

            # geodetic latitude (Bowring eqn 18)
            a = atan2(z + E.e22 * E.b * s**3,
                      p - E.e2  * E.a * c**3)
            b = atan2(y, x)  # ... and longitude

            # height above ellipsoid (Bowring eqn 7)
            ca, sa = cos(a), sin(a)
#           r = E.a / E.e2s(sa)  # length of normal terminated by minor axis
#           h = p * ca + z * sa - (E.a * E.a / r)
            h = fsum_(p * ca, z * sa, -E.a * E.e2s(sa))

            a, b = degrees90(a), degrees180(b)

        # see <http://GIS.StackExchange.com/questions/28446/>
        elif p > EPS:  # latitude arbitrarily zero
            a, b, h = 0.0, degrees180(atan2(y, x)), p - E.a
        else:  # polar latitude, longitude arbitrarily zero
            a, b, h = copysign(90.0, z), 0.0, abs(z) - E.b

        return a, b, h
Exemple #9
0
 def _fE(sn, cn, dn):
     sn2, cn2, dn2 = sn**2, cn**2, dn**2
     kp2, k2 = self._kp2, self._k2
     if k2 <= 0:
         # Carlson, eq. 4.6 and <https://DLMF.NIST.gov/19.25.E9>
         ei = _RF(cn2, dn2, 1) - k2 * sn2 * _RD_3(cn2, dn2, 1)
     elif kp2 >= 0:
         # <https://DLMF.NIST.gov/19.25.E10>
         ei = fsum_(kp2 * _RF(cn2, dn2, 1),
                    kp2 * k2 * sn2 * _RD_3(cn2, 1, dn2),
                    k2 * abs(cn) / dn)
     else:
         # <https://DLMF.NIST.gov/19.25.E11>
         ei = dn / abs(cn) - kp2 * sn2 * _RD_3(dn2, 1, cn2)
     return ei * abs(sn)
Exemple #10
0
 def intersect(self, p1, p2, edge):  # compute intersection
     # of polygon edge p1 to p2 and the current clip edge,
     # where p1 and p2 are known to NOT be located on the
     # same side of or on the current clip edge
     # <https://StackOverflow.com/questions/563198/
     #       how-do-you-detect-where-two-line-segments-intersect>
     fy = float(p2.lat - p1.lat)
     fx = float(p2.lon - p1.lon)
     fp = fy * self._dx - fx * self._dy
     if abs(fp) < EPS:
         raise AssertionError('clipSH.intersect')
     h = fsum_(self._xy, -p1.lat * self._dx, p1.lon * self._dy) / fp
     y = p1.lat + h * fy
     x = p1.lon + h * fx
     return _LLi_(y, x, p1.classof, edge)
Exemple #11
0
    def rhumbMidpointTo(self, other, height=None):
        '''Return the (loxodromic) midpoint between this and
           an other point.

           @param other: The other point (spherical LatLon).
           @keyword height: Optional height, overriding the mean height
                            (C{meter}).

           @return: The midpoint (spherical C{LatLon}).

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

           @example:

           >>> p = LatLon(51.127, 1.338)
           >>> q = LatLon(50.964, 1.853)
           >>> m = p.rhumb_midpointTo(q)
           >>> m.toStr()  # '51.0455°N, 001.5957°E'
        '''
        self.others(other)

        # see <https://MathForum.org/library/drmath/view/51822.html>
        a1, b1 = self.to2ab()
        a2, b2 = other.to2ab()
        if abs(b2 - b1) > PI:
            b1 += PI2  # crossing anti-meridian

        a3 = favg(a1, a2)
        b3 = favg(b1, b2)

        f1 = tanPI_2_2(a1)
        if abs(f1) > EPS:
            f2 = tanPI_2_2(a2)
            f = f2 / f1
            if abs(f) > EPS:
                f = log(f)
                if abs(f) > EPS:
                    f3 = tanPI_2_2(a3)
                    b3 = fsum_(b1 * log(f2), -b2 * log(f1),
                               (b2 - b1) * log(f3)) / f

        h = self._havg(other) if height is None else height
        return self.classof(degrees90(a3), degrees180(b3), height=h)
Exemple #12
0
    def toNvector(self, datum=Datums.WGS84):
        '''Convert this cartesian to an (ellipsoidal) n-vector.

           @keyword datum: Optional datum to use (L{Datum}).

           @return: The ellipsoidal n-vector (L{Nvector}).

           @raise ValueError: The I{Cartesian} at origin.

           @example:

           >>> from ellipsoidalNvector import LatLon
           >>> c = Cartesian(3980581, 97, 4966825)
           >>> n = c.toNvector()  # (0.62282, 0.000002, 0.78237, +0.24)
        '''
        if self._Nv is None or datum != self._Nv.datum:
            E = datum.ellipsoid
            x, y, z = self.to3xyz()

            # Kenneth Gade eqn 23
            p = (x**2 + y**2) * E.a2_
            q = (z**2 * E.e12) * E.a2_
            r = fsum_(p, q, -E.e4) / 6
            s = (p * q * E.e4) / (4 * r**3)
            t = cbrt(fsum_(1, s, sqrt(s * (2 + s))))

            u = r * fsum_(1, t, 1 / t)
            v = sqrt(u**2 + E.e4 * q)
            w = E.e2 * fsum_(u, v, -q) / (2 * v)

            k = sqrt(fsum_(u, v, w**2)) - w
            if abs(k) < EPS:
                raise ValueError('%s: %r' % ('origin', self))
            e = k / (k + E.e2)
            d = e * hypot(x, y)

            t = hypot(d, z)
            if t < EPS:
                raise ValueError('%s: %r' % ('origin', self))
            h = fsum_(k, E.e2, -1) / k * t

            s = e / t
            self._Nv = Nvector(x * s,
                               y * s,
                               z / t,
                               h=h,
                               datum=datum,
                               name=self.name)
        return self._Nv
Exemple #13
0
def horizon(height, radius=R_M, refraction=False):
    '''Determine the distance to the horizon from a given altitude
       above the (spherical) earth.

       @param height: Altitude (C{meter} or same units as I{radius}).
       @keyword radius: Optional mean earth radius (C{meter}).
       @keyword refraction: Consider atmospheric refraction (C{bool}).

       @return: Distance (C{meter}, same units as I{height} and I{radius}).

       @raise ValueError: Invalid I{height} or I{radius}.

       @see: U{Distance to horizon<http://www.EdWilliams.org/avform.htm#Horizon>}.
    '''
    if min(height, radius) < 0:
        raise ValueError('%s%r' % ('horizon', (height, radius)))

    if refraction:
        d2 = 2.415750694528 * height * radius  # 2.0 / 0.8279
    else:
        d2 = height * fsum_(radius, radius, height)
    return sqrt(d2)
Exemple #14
0
def trilaterate(point1,
                distance1,
                point2,
                distance2,
                point3,
                distance3,
                radius=R_M,
                height=None,
                LatLon=LatLon,
                useZ=False):
    '''Locate a point at given distances from three other points.
       See also U{Trilateration<https://WikiPedia.org/wiki/Trilateration>}.

       @param point1: First point (L{LatLon}).
       @param distance1: Distance to the first point (C{meter}, same units
                         as B{C{radius}}).
       @param point2: Second point (L{LatLon}).
       @param distance2: Distance to the second point (C{meter}, same units
                         as B{C{radius}}).
       @param point3: Third point (L{LatLon}).
       @param distance3: Distance to the third point (C{meter}, same units
                         as B{C{radius}}).
       @keyword radius: Optional, mean earth radius (C{meter}).
       @keyword height: Optional height at the trilaterated point, overriding
                        the IDW height (C{meter}, same units as B{C{radius}}).
       @keyword LatLon: Optional (sub-)class to return the trilaterated
                        point (L{LatLon}).
       @keyword useZ: Include Z component iff non-NaN, non-zero (C{bool}).

       @return: Trilaterated point (B{C{LatLon}}).

       @raise TypeError: If B{C{point1}}, B{C{point2}} or B{C{point3}}
                         is not L{LatLon}.

       @raise ValueError: Invalid B{C{radius}}, some B{C{distances}} exceed
                          trilateration or some B{C{points}} coincide.
    '''
    def _nd2(p, d, name, *qs):
        # return Nvector and radial distance squared
        _Nvll.others(p, name=name)
        for q in qs:
            if p.isequalTo(q, EPS):
                raise ValueError('%s %s: %r' % ('coincident', 'points', p))
        return p.toNvector(), (float(d) / radius)**2

    if float(radius or 0) < EPS:
        raise ValueError('%s %s: %r' % ('radius', 'invalid', radius))

    n1, d12 = _nd2(point1, distance1, 'point1')
    n2, d22 = _nd2(point2, distance2, 'point2', point1)
    n3, d32 = _nd2(point3, distance3, 'point3', point1, point2)

    # the following uses x,y coordinate system with origin at n1, x axis n1->n2
    y = n3.minus(n1)
    x = n2.minus(n1)

    d = x.length  # distance n1->n2
    if d > EPS_2:  # and y.length > EPS_2:
        X = x.unit()  # unit vector in x direction n1->n2
        i = X.dot(y)  # signed magnitude of x component of n1->n3
        Y = y.minus(X.times(i)).unit()  # unit vector in y direction
        j = Y.dot(y)  # signed magnitude of y component of n1->n3
        if abs(j) > EPS_2:
            # courtesy Carlos Freitas <https://GitHub.com/mrJean1/PyGeodesy/issues/33>
            x = fsum_(d12, -d22, d**2) / (2 * d)  # n1->intersection x- and ...
            y = fsum_(d12, -d32, i**2, j**2) / (2 * j) - (x * i / j
                                                          )  # ... y-component

            n = n1.plus(X.times(x)).plus(Y.times(y))  # .plus(Z.times(z))
            if useZ:  # include non-NaN, non-zero Z component
                z = fsum_(d12, -(x**2), -(y**2))
                if z > EPS:
                    Z = X.cross(Y)  # unit vector perpendicular to plane
                    n = n.plus(Z.times(sqrt(z)))

            if height is None:
                h = fidw((point1.height, point2.height, point3.height),
                         map1(fabs, distance1, distance2, distance3))
            else:
                h = height
            return n.toLatLon(
                height=h,
                LatLon=LatLon)  # Nvector(n.x, n.y, n.z).toLatLon(...)

    # no intersection, d < EPS_2 or j < EPS_2
    raise ValueError('no %s for %r, %r, %r at %r, %r, %r' %
                     ('trilaterate', point1, point2, point3, distance1,
                      distance2, distance3))
Exemple #15
0
def toOsgr(latlon, lon=None, datum=Datums.WGS84, Osgr=Osgr, name=''):
    '''Convert a lat-/longitude point to an OSGR coordinate.

       @param latlon: Latitude (C{degrees}) or an (ellipsoidal)
                      geodetic C{LatLon} point.
       @keyword lon: Optional longitude in degrees (scalar or C{None}).
       @keyword datum: Optional datum to convert (C{Datum}).
       @keyword Osgr: Optional (sub-)class to return the OSGR
                      coordinate (L{Osgr}) or C{None}.
       @keyword name: Optional I{Osgr} name (C{str}).

       @return: The OSGR coordinate (L{Osgr}) or 2-tuple (easting,
                northing) if I{Osgr} is C{None}.

       @raise TypeError: Non-ellipsoidal I{latlon} or I{datum}
                         conversion failed.

       @raise ValueError: Invalid I{latlon} or I{lon}.

       @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 not isinstance(latlon, _LLEB):
        # XXX fix failing _LLEB.convertDatum()
        latlon = _LLEB(*parseDMS2(latlon, lon), datum=datum)
    elif lon is not None:
        raise ValueError('%s not %s: %r' % ('lon', None, lon))
    elif not name:  # use latlon.name
        name = _nameof(latlon) or name  # PYCHOK no effect

    E = _OSGB36.ellipsoid

    ll = _ll2datum(latlon, _OSGB36, 'latlon')
    a, b = map1(radians, ll.lat, ll.lon)

    sa, ca = sincos2(a)

    s = E.e2s2(sa)
    v = E.a * _F0 / sqrt(s)  # nu
    r = s / E.e12  # nu / rho == v / (v * E.e12 / s)

    x2 = r - 1  # η2
    ta = tan(a)

    ca3, ca5 = fpowers(ca, 5, 3)  # PYCHOK false!
    ta2, ta4 = fpowers(ta, 4, 2)  # PYCHOK false!

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

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

    d, d2, d3, d4, d5, d6 = fpowers(b - _B0, 6)  # PYCHOK false!
    n = fdot(I4, 1, d2, d4, d6)
    e = fdot(V4, 1, d, d3, d5)

    return (e, n) if Osgr is None else _xnamed(Osgr(e, n), name)
Exemple #16
0
    def toLatLon(self, LatLon=None, datum=Datums.WGS84):
        '''Convert this OSGR coordinate to an (ellipsoidal) geodetic
           point.

           I{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.}

           @keyword LatLon: Optional ellipsoidal LatLon class to use
                            for the point (I{LatLon}).
           @keyword datum: Optional datum to use (I{Datum}).

           @return: The geodetic point (I{LatLon}) or 3-tuple (lat,
                    lon, datum) if I{LatLon} is None.

           @raise TypeError: If I{LatLon} is not ellipsoidal or if
                             I{datum} conversion failed.

           @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:
            return self._latlon3(LatLon, datum)

        E = _OSGB36.ellipsoid  # Airy130
        a_F0 = E.a * _F0
        b_F0 = E.b * _F0

        e, n = self._easting, self._northing
        n_N0 = n - _N0

        a, M = _A0, 0
        sa = Fsum(a)
        while True:
            t = n_N0 - M
            if t < _10um:
                break
            sa.fadd(t / a_F0)
            a = sa.fsum()
            M = b_F0 * _M(E.Mabcd, a)

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

        s = E.e2s2(sa)
        v = a_F0 / sqrt(s)  # nu
        r = v * E.e12 / s  # rho

        vr = v / r  # == s / E.e12
        x2 = vr - 1  # η2

        v3, v5, v7 = fpowers(v, 7, 3)  # PYCHOK false!
        ta2, ta4, ta6 = fpowers(ta**2, 3)  # PYCHOK false!

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

        csa = 1.0 / ca
        X5 = (_B0, csa / v, csa / (6 * v3) * fsum_(vr, ta, ta),
              csa / (120 * v5) * fdot(
                  (5, 28, 24), 1, ta2, ta4), csa / (5040 * v7) * fdot(
                      (61, 662, 1320, 720), ta, ta2, ta4, ta6))

        d, d2, d3, d4, d5, d6, d7 = fpowers(e - _E0, 7)  # PYCHOK false!
        a = fdot(V4, 1, -d2, d4, -d6)
        b = fdot(X5, 1, d, -d3, d5, -d7)

        self._latlon = _eLLb(degrees90(a), degrees180(b), datum=_OSGB36)
        return self._latlon3(LatLon, datum)
def trilaterate(point1,
                distance1,
                point2,
                distance2,
                point3,
                distance3,
                radius=R_M,
                height=None,
                LatLon=LatLon):
    '''Locate a point at given distances from three other points.
       See also U{Trilateration<http://WikiPedia.org/wiki/Trilateration>}.

       @param point1: First point (L{LatLon}).
       @param distance1: Distance to the first point (C{meter}, same units
                         as I{radius}).
       @param point2: Second point (L{LatLon}).
       @param distance2: Distance to the second point (C{meter}, same units
                         as I{radius}).
       @param point3: Third point (L{LatLon}).
       @param distance3: Distance to the third point (C{meter}, same units
                         as I{radius}).
       @keyword radius: Optional, mean earth radius (C{meter}).
       @keyword height: Optional height at the trilaterated point, overriding
                        the mean height (C{meter}, same units as I{radius}).
       @keyword LatLon: Optional (sub-)class for the trilaterated point
                        (L{LatLon}).

       @return: Trilaterated point (L{LatLon}).

       @raise TypeError: One of the I{points} is not L{LatLon}.

       @raise ValueError: Invalid I{radius}, some I{distances} exceed
                          trilateration or some I{points} coincide.
    '''
    def _nd2(p, d, name, *qs):
        # return Nvector and radial distance squared
        _Nvll.others(p, name=name)
        for q in qs:
            if p.isequalTo(q, EPS):
                raise ValueError('%s %s: %r' % ('coincident', 'points', p))
        return p.toNvector(), (float(d) / radius)**2

    if float(radius or 0) < EPS:
        raise ValueError('%s %s: %r' % ('radius', 'invalid', radius))

    n1, d12 = _nd2(point1, distance1, 'point1')
    n2, d22 = _nd2(point2, distance2, 'point2', point1)
    n3, d32 = _nd2(point3, distance3, 'point3', point1, point2)

    # the following uses x,y coordinate system with origin at n1, x axis n1->n2
    x = n2.minus(n1)
    y = n3.minus(n1)
    z = 0

    d = x.length  # distance n1->n2
    if d > EPS:  # and (y.length * 2) > EPS:
        X = x.unit()  # unit vector in x direction n1->n2
        i = X.dot(y)  # signed magnitude of x component of n1->n3
        Y = y.minus(X.times(i)).unit()  # unit vector in y direction
        j = Y.dot(y)  # signed magnitude of y component of n1->n3
        if abs(j) > EPS:
            x = fsum_(d12, -d22, d**2) / d  # n1->intersection x- and ...
            y = fsum_(d12, -d32, i**2, j**2, -2 * x * i) / j  # ... y-component
            z = (x**2 + y**2) * 0.25

#   z = sqrt(d12 - z)  # z will be NaN for no intersections
    if not 0 < z < d12:
        raise ValueError('no %s for %r, %r, %r at %r, %r, %r' %
                         ('trilaterate', point1, point2, point3, distance1,
                          distance2, distance3))
#   Z = X.cross(Y)  # unit vector perpendicular to plane
# note don't use Z component; assume points at same height
    n = n1.plus(X.times(x)).plus(Y.times(y))  # .plus(Z.times(z))

    if height is None:
        h = fmean((point1.height, point2.height, point3.height))
    else:
        h = height
    return n.toLatLon(height=h,
                      LatLon=LatLon)  # Nvector(n.x, n.y, n.z).toLatLon(...)