コード例 #1
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)
コード例 #2
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
コード例 #3
0
    def _zetaInv(self, taup, lam):
        '''Invert C{zeta} using Newton's method.

           @return: 2-Tuple C{(u, v)}.

           @see: C{void TMExact::zetainv(real taup, real lam,
                                         real &u, real &v)}.

           @raise EllipticError: No convergence.
        '''
        psi = asinh(taup)
        sca = 1.0 / hypot1(taup)
        u, v, trip = self._zetaInv0(psi, lam)
        if not trip:
            stol2 = _TOL_10 / max(psi, 1.0)**2
            U, V = Fsum(u), Fsum(v)
            # min iterations = 2, max = 6, mean = 4.0
            for _ in range(self._trips_):  # GEOGRAPHICLIB_PANIC
                snu, cnu, dnu = self._Eu.sncndn(u)
                snv, cnv, dnv = self._Ev.sncndn(v)
                T, L, _ = self._zeta3(snu, cnu, dnu, snv, cnv, dnv)
                dw, dv = self._zetaDwd(snu, cnu, dnu, snv, cnv, dnv)
                T = (taup - T) * sca
                L -= lam
                u, du = U.fsum2_(T * dw, L * dv)
                v, dv = V.fsum2_(T * dv, -L * dw)
                if trip:
                    break
                trip = (du**2 + dv**2) < stol2
            else:
                raise EllipticError('no %s convergence' % ('zetaInv', ))
        return u, v
コード例 #4
0
    def _sigmaInv(self, xi, eta):
        '''Invert C{sigma} using Newton's method.

           @return: 2-Tuple C{(u, v)}.

           @see: C{void TMExact::sigmainv(real xi, real eta,
                                          real &u, real &v)}.

           @raise EllipticError: No convergence.
        '''
        u, v, trip = self._sigmaInv0(xi, eta)
        if not trip:
            U, V = Fsum(u), Fsum(v)
            # min iterations = 2, max = 7, mean = 3.9
            for _ in range(self._trips_):  # GEOGRAPHICLIB_PANIC
                snu, cnu, dnu = self._Eu.sncndn(u)
                snv, cnv, dnv = self._Ev.sncndn(v)
                X, E, _ = self._sigma3(v, snu, cnu, dnu, snv, cnv, dnv)
                dw, dv = self._sigmaDwd(snu, cnu, dnu, snv, cnv, dnv)
                X = xi - X
                E -= eta
                u, du = U.fsum2_(X * dw, E * dv)
                v, dv = V.fsum2_(X * dv, -E * dw)
                if trip:
                    break
                trip = (du**2 + dv**2) < _TOL_10
            else:
                raise EllipticError('no %s convergence' % ('sigmaInv', ))
        return u, v
コード例 #5
0
ファイル: points.py プロジェクト: GliderGeek/PyGeodesy
def centroidOf(points, wrap=True, LatLon=None):
    '''Determine the centroid of a polygon.

       @param points: The polygon points (C{LatLon}[]).
       @keyword wrap: Wrap lat-, wrap and unroll longitudes (C{bool}).
       @keyword LatLon: Optional (sub-)class to return the centroid
                        (L{LatLon}) or C{None}.

       @return: Centroid location (I{LatLon}) or as 2-tuple (C{lat, lon})
                in C{degrees} if I{LatLon} is C{None}.

       @raise TypeError: Some I{points} are not C{LatLon}.

       @raise ValueError: Insufficient number of I{points} or I{points}
                          enclose a pole or zero area.

       @see: U{Centroid<http://WikiPedia.org/wiki/Centroid#Of_a_polygon>}
             and U{Calculating The Area And Centroid Of A Polygon
             <http://www.Seas.UPenn.edu/~sys502/extra_materials/
             Polygon%20Area%20and%20Centroid.pdf>}.
    '''
    # setting radius=1 converts degrees to radians
    pts = LatLon2psxy(points, closed=True, radius=1, wrap=wrap)
    n = len(pts)

    A, X, Y = Fsum(), Fsum(), Fsum()

    x1, y1, _ = pts[n-1]
    for i in range(n):
        x2, y2, _ = pts[i]
        if wrap and i < (n - 1):
            _, x2 = unrollPI(x1, x2, wrap=True)
        t = x1 * y2 - x2 * y1
        A += t
        X += t * (x1 + x2)
        Y += t * (y1 + y2)
        # XXX more elaborately:
        # t1, t2 = x1 * y2, -(x2 * y1)
        # A.fadd_(t1, t2)
        # X.fadd_(t1 * x1, t1 * x2, t2 * x1, t2 * x2)
        # Y.fadd_(t1 * y1, t1 * y2, t2 * y1, t2 * y2)
        x1, y1 = x2, y2

    A = A.fsum() * 3.0  # 6.0 / 2.0
    if abs(A) < EPS:
        raise ValueError('polar or zero area: %r' % (pts,))
    Y, X = degrees90(Y.fsum() / A), degrees180(X.fsum() / A)
    return (Y, X) if LatLon is None else LatLon(Y, X)
コード例 #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)
コード例 #7
0
    def fEinv(self, x):
        '''The inverse of the incomplete integral of the second kind.

           @param x: Argument (C{float}).

           @return: φ = 1 / E(B{C{x}}, k), such that E(φ, k) = B{C{x}}.
        '''
        E2 = self.cE * 2.0
        n  = floor(x / E2 + 0.5)
        x -= E2 * n  # x now in [-ec, ec)
        # linear approximation
        phi = PI * x / E2  # phi in [-pi/2, pi/2)
        P   = Fsum(phi)
        # first order correction
        phi = P.fsum(-self._eps * sin(2 * phi) * 0.5)
        # For kp2 close to zero use asin(x/.cE) or J. P. Boyd,
        # Applied Math. and Computation 218, 7005-7013 (2012)
        # <https://DOI.org/10.1016/j.amc.2011.12.021>
        for _ in range(self._trips_):  # GEOGRAPHICLIB_PANIC
            sn, cn, dn = self._sncndn3(phi)
            phi, e = P.fsum2_((x - self.fE(sn, cn, dn)) / dn)
            if abs(e) < _tolJAC:
                return n * PI + phi
        raise EllipticError('no %s convergence' % ('fEinv',))
コード例 #8
0
def isenclosedBy(point, points, wrap=False):  # MCCABE 15
    '''Determine whether a point is enclosed by a polygon.

       @param point: The point (C{LatLon} or 2-tuple (lat, lon)).
       @param points: The polygon points (C{LatLon}[]).
       @keyword wrap: Wrap lat-, wrap and unroll longitudes (C{bool}).

       @return: C{True} if I{point} is inside the polygon, C{False}
                otherwise.

       @raise TypeError: Some I{points} are not C{LatLon}.

       @raise ValueError: Insufficient number of I{points} or invalid
                          I{point}.

       @see: L{sphericalNvector.LatLon.isEnclosedBy},
             L{sphericalTrigonometry.LatLon.isEnclosedBy} and
             U{MultiDop GeogContainPt<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>}).
    '''
    try:
        y0, x0 = point.lat, point.lon
    except AttributeError:
        try:
            y0, x0 = map1(float, *point[:2])
        except (IndexError, TypeError, ValueError):
            raise ValueError('%s invalid: %r' % ('point', point))

    pts = LatLon2psxy(points, closed=True, radius=None, wrap=wrap)
    n = len(pts)

    if wrap:
        x0, y0 = wrap180(x0), wrap90(y0)

        def _dxy(x1, i):
            x2, y2, _ = pts[i]
            dx, x2 = unroll180(x1, x2, wrap=i < (n - 1))
            return dx, x2, y2

    else:
        x0 = fmod(x0, 360.0)  # not x0 % 360

        def _dxy(x1, i):  # PYCHOK expected
            x, y, _ = pts[i]
            x %= 360.0
            if x < (x0 - 180):
                x += 360
            elif x >= (x0 + 180):
                x -= 360
            return (x - x1), x, y

    e = m = False
    s = Fsum()

    _, x1, y1 = _dxy(x0, n - 1)
    for i in range(n):
        dx, x2, y2 = _dxy(x1, i)
        # ignore duplicate and near-duplicate pts
        if max(abs(dx), abs(y2 - y1)) > EPS:
            # determine if polygon edge (x1, y1)..(x2, y2) straddles
            # point (lat, lon) or is on boundary, but do not count
            # edges on boundary as more than one crossing
            if abs(dx) < 180 and (x1 < x0 <= x2 or x2 < x0 <= x1):
                m = not m
                dy = (x0 - x1) * (y2 - y1) - (y0 - y1) * dx
                if (dy > 0 and dx >= 0) or (dy < 0 and dx <= 0):
                    e = not e

            s.fadd(sin(radians(y2)))
            x1, y1 = x2, y2

    # An odd number of meridian crossings means, the polygon
    # contains a pole.  Assume it is the pole on the hemisphere
    # containing the polygon mean point and if the polygon does
    # contain the North Pole, flip the result.
    if m and s.fsum() > 0:
        e = not e
    return e
コード例 #9
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)
コード例 #10
0
ファイル: utm.py プロジェクト: robinrowe/PyGeodesy
    def toLatLon(self, LatLon=None):
        '''Convert this UTM coordinate to an (ellipsoidal) geodetic point.

           @keyword LatLon: Optional, ellipsoidal (sub-)class to use
                            for the point (C{LatLon}) or C{None}.

           @return: This UTM coordinate as (I{LatLon}) or 5-tuple
                    (lat, lon, datum, convergence, scale) if I{LatLon}
                    is C{None}.

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

           @raise UTMError: Invalid meridional radius or H-value.

           @example:

           >>> u = Utm(31, 'N', 448251.795, 5411932.678)
           >>> from pygeodesy import ellipsoidalVincenty as eV
           >>> ll = u.toLatLon(eV.LatLon)  # 48°51′29.52″N, 002°17′40.20″E
        '''
        if self._latlon:
            return self._latlon5(LatLon)

        E = self._datum.ellipsoid  # XXX vs LatLon.datum.ellipsoid

        x = self._easting - _FalseEasting  # relative to central meridian
        y = self._northing
        if self._hemi == 'S':  # relative to equator
            y -= _FalseNorthing

        # from Karney 2011 Eq 15-22, 36
        A0 = _K0 * E.A
        if A0 < EPS:
            raise UTMError('%s invalid: %r' % ('meridional', E.A))
        x /= A0  # η eta
        y /= A0  # ξ ksi

        Ks = _Kseries(E.BetaKs, x, y)  # Krüger series
        y = -Ks.ys(-y)  # ξ'
        x = -Ks.xs(-x)  # η'

        shx = sinh(x)
        cy, sy = cos(y), sin(y)

        H = hypot(shx, cy)
        if H < EPS:
            raise UTMError('%s invalid: %r' % ('H', H))

        T = t0 = sy / H  # τʹ
        q = 1.0 / E.e12
        d = 1
        sd = Fsum(T)
        # toggles on +/-1.12e-16 eg. 31 N 400000 5000000
        while abs(d) > EPS:  # 1e-12
            h = hypot1(T)
            s = sinh(E.e * atanh(E.e * T / h))
            t = T * hypot1(s) - s * h
            d = (t0 - t) / hypot1(t) * (q + T**2) / h
            T = sd.fsum_(d)  # τi

        a = atan(T)  # lat
        b = atan2(shx, cy) + radians(_cmlon(self._zone))
        ll = _LLEB(degrees90(a),
                   degrees180(b),
                   datum=self._datum,
                   name=self.name)

        # convergence: Karney 2011 Eq 26, 27
        p = -Ks.ps(-1)
        q = Ks.qs(0)
        ll._convergence = degrees(atan(tan(y) * tanh(x)) + atan2(q, p))

        # scale: Karney 2011 Eq 28
        ll._scale = E.e2s(sin(a)) * hypot1(T) * H * (A0 / E.a / hypot(p, q))

        self._latlon = ll
        return self._latlon5(LatLon)
コード例 #11
0
ファイル: points.py プロジェクト: qdhqf/PyGeodesy
def isenclosedby(latlon, points, wrap=False):  # MCCABE 14
    '''Determine whether a point is enclosed by a polygon defined by
       an array, list, sequence, set or tuple of points.

       @param latlon: The point (I{LatLon} or 2-tuple (lat, lon)).
       @param points: The points defining the polygon (I{LatLon}[]).
       @keyword wrap: Wrap lat-, wrap and unroll longitudes (bool).

       @return: True if I{latlon} is inside the polygon, False otherwise.

       @raise TypeError: Some I{points} are not I{LatLon}.

       @raise ValueError: Insufficient number of I{points} or invalid
                          I{latlon}.

       @see: L{sphericalNvector.LatLon.isEnclosedBy},
             L{sphericalTrigonometry.LatLon.isEnclosedBy} and
             U{MultiDop GeogContainPt<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>}).
    '''
    pts = LatLon2psxy(points, closed=True, radius=None, wrap=wrap)

    def _xy(i):
        x, y, _ = pts[i]
        if not wrap:
            x %= 360.0
            if x < (x0 - 180):
                x += 360
            elif x >= (x0 + 180):
                x -= 360
        return x, y

    try:
        y0, x0 = latlon.lat, latlon.lon
    except AttributeError:
        try:
            y0, x0 = latlon[:2]
        except (IndexError, TypeError, ValueError):
            raise ValueError('%s invalid: %r' % ('latlon', latlon))

    if wrap:
        x0, y0 = wrap180(x0), wrap90(y0)
    else:
        x0 %= 360.0

    n = len(pts)
    e = m = False
    s = Fsum()

    x1, y1 = _xy(n - 1)
    for i in range(n):
        x2, y2 = _xy(i)
        dx, x2 = unroll180(x1, x2, wrap=wrap)
        # determine if polygon edge (x1, y1)..(x2, y2) straddles
        # point (lat, lon) or is on boundary, but do not count
        # edges on boundary as more than one crossing
        if abs(dx) < 180 and (x1 < x0 <= x2 or x2 < x0 <= x1):
            m = not m
            dy = (x0 - x1) * (y2 - y1) - (y0 - y1) * dx
            if (dy > 0 and dx >= 0) or (dy < 0 and dx <= 0):
                e = not e

        s.fadd(sin(radians(y2)))
        x1, y1 = x2, y2

    # an odd number of meridian crossings means polygon contains
    # a pole, assume that is the hemisphere containing the polygon
    # mean and if polygon contains North Pole, flip the result
    if m and s.fsum() > 0:
        e = not e

    return e
コード例 #12
0
ファイル: utm.py プロジェクト: GliderGeek/PyGeodesy
    def toLatLon(self, LatLon=None, eps=EPS, unfalse=True):
        '''Convert this UTM coordinate to an (ellipsoidal) geodetic point.

           @keyword LatLon: Optional, ellipsoidal (sub-)class to return
                            the point (C{LatLon}) or C{None}.
           @keyword eps: Optional convergence limit, L{EPS} or above
                         (C{float}).
           @keyword unfalse: Unfalse I{easting} and I{northing} if falsed
                             (C{bool}).

           @return: This UTM coordinate as (I{LatLon}) or 5-tuple
                    (lat, lon, datum, convergence, scale) if I{LatLon}
                    is C{None}.

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

           @raise UTMError: Invalid meridional radius or H-value.

           @example:

           >>> u = Utm(31, 'N', 448251.795, 5411932.678)
           >>> from pygeodesy import ellipsoidalVincenty as eV
           >>> ll = u.toLatLon(eV.LatLon)  # 48°51′29.52″N, 002°17′40.20″E
        '''
        if eps < EPS:
            eps = EPS  # less doesn't converge

        if self._latlon and self._latlon_eps == eps:
            return self._latlon5(LatLon)

        E = self._datum.ellipsoid  # XXX vs LatLon.datum.ellipsoid

        x = self._easting
        y = self._northing
        if unfalse and self._falsed:
            x -= _FalseEasting  # relative to central meridian
            if self._hemisphere == 'S':  # relative to equator
                y -= _FalseNorthing

        # from Karney 2011 Eq 15-22, 36
        A0 = _K0 * E.A
        if A0 < EPS:
            raise UTMError('%s invalid: %r' % ('meridional', E.A))
        x /= A0  # η eta
        y /= A0  # ξ ksi

        Ks = _Kseries(E.BetaKs, x, y)  # Krüger series
        y = -Ks.ys(-y)  # ξ'
        x = -Ks.xs(-x)  # η'

        shx = sinh(x)
        sy, cy = sincos2(y)

        H = hypot(shx, cy)
        if H < EPS:
            raise UTMError('%s invalid: %r' % ('H', H))

        d = 1.0 + eps
        q = 1.0 / E.e12
        T = t0 = sy / H  # τʹ
        sd = Fsum(T)
        while abs(d) > eps:
            h = hypot1(T)
            s = sinh(E.e * atanh(E.e * T / h))
            t = T * hypot1(s) - s * h
            d = (t0 - t) / hypot1(t) * ((q + T**2) / h)
            T, d = sd.fsum2_(d)  # τi, (τi - τi-1)

        a = atan(T)  # lat
        b = atan2(shx, cy) + radians(_cmlon(self._zone))
        ll = _LLEB(degrees90(a),
                   degrees180(b),
                   datum=self._datum,
                   name=self.name)

        # convergence: Karney 2011 Eq 26, 27
        p = -Ks.ps(-1)
        q = Ks.qs(0)
        ll._convergence = degrees(atan(tan(y) * tanh(x)) + atan2(q, p))

        # scale: Karney 2011 Eq 28
        ll._scale = E.e2s(sin(a)) * hypot1(T) * H * (A0 / E.a / hypot(p, q))

        self._latlon, self._latlon_eps = ll, eps
        return self._latlon5(LatLon)
コード例 #13
0
    def toLatLon(self, LatLon=None, eps=EPS, unfalse=True):
        '''Convert this UTM coordinate to an (ellipsoidal) geodetic point.

           @keyword LatLon: Optional, ellipsoidal (sub-)class to return
                            the point (C{LatLon}) or C{None}.
           @keyword eps: Optional convergence limit, L{EPS} or above
                         (C{float}).
           @keyword unfalse: Unfalse B{C{easting}} and B{C{northing}}
                             if falsed (C{bool}).

           @return: This UTM coordinate as (B{C{LatLon}}) or a
                    L{LatLonDatum5Tuple}C{(lat, lon, datum,
                    convergence, scale)} if B{C{LatLon}} is C{None}.

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

           @raise UTMError: Invalid meridional radius or H-value.

           @example:

           >>> u = Utm(31, 'N', 448251.795, 5411932.678)
           >>> from pygeodesy import ellipsoidalVincenty as eV
           >>> ll = u.toLatLon(eV.LatLon)  # 48°51′29.52″N, 002°17′40.20″E
        '''
        if eps < EPS:
            eps = EPS  # less doesn't converge

        if self._latlon and self._latlon_args == (eps, unfalse):
            return self._latlon5(LatLon)

        E = self.datum.ellipsoid  # XXX vs LatLon.datum.ellipsoid

        x, y = self.to2en(falsed=not unfalse)

        # from Karney 2011 Eq 15-22, 36
        A0 = self.scale0 * E.A
        if A0 < EPS:
            raise self._Error('%s invalid: %r' % ('meridional', E.A))
        x /= A0  # η eta
        y /= A0  # ξ ksi

        K = _Kseries(E.BetaKs, x, y)  # Krüger series
        y = -K.ys(-y)  # ξ'
        x = -K.xs(-x)  # η'

        shx = sinh(x)
        sy, cy = sincos2(y)

        H = hypot(shx, cy)
        if H < EPS:
            raise self._Error('%s invalid: %r' % ('H', H))

        T = t0 = sy / H  # τʹ
        S = Fsum(T)
        q = 1.0 / E.e12
        P = 7  # -/+ toggle trips
        d = 1.0 + eps
        while abs(d) > eps and P > 0:
            p = -d  # previous d, toggled
            h = hypot1(T)
            s = sinh(E.e * atanh(E.e * T / h))
            t = T * hypot1(s) - s * h
            d = (t0 - t) / hypot1(t) * ((q + T**2) / h)
            T, d = S.fsum2_(d)  # τi, (τi - τi-1)
            if d == p:  # catch -/+ toggling of d
                P -= 1
            # else:
            #   P = 0

        a = atan(T)  # lat
        b = atan2(shx, cy)
        if unfalse and self.falsed:
            b += radians(_cmlon(self.zone))
        ll = _LLEB(degrees90(a),
                   degrees180(b),
                   datum=self.datum,
                   name=self.name)

        # convergence: Karney 2011 Eq 26, 27
        p = -K.ps(-1)
        q = K.qs(0)
        ll._convergence = degrees(atan(tan(y) * tanh(x)) + atan2(q, p))

        # scale: Karney 2011 Eq 28
        ll._scale = E.e2s(sin(a)) * hypot1(T) * H * (A0 / E.a / hypot(p, q))

        self._latlon_to(ll, eps, unfalse)
        return self._latlon5(LatLon)