Beispiel #1
0
    def _sigmaInv(self, xi, eta):
        '''(INTERNAL) 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 trip:
            self._iteration = 0
        else:
            U, V = Fsum(u), Fsum(v)
            # min iterations = 2, max = 7, mean = 3.9
            for self._iteration in range(1, _TRIPS):  # GEOGRAPHICLIB_PANIC
                sncndn6 = self._sncndn6(u, v)
                X, E, _ = self._sigma3(v, *sncndn6)
                dw, dv  = self._sigmaDwd( *sncndn6)
                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 = hypot2(du, dv) < _TOL_10
            else:
                t = unstr(self._sigmaInv.__name__, xi, eta)
                raise EllipticError(_no_convergence_, txt=t)
        return u, v
Beispiel #2
0
 def distance(self, p1, p2):
     '''Return the L{equirectangular_} distance in C{radians squared}.
     '''
     r, _ = unrollPI(p1.lam, p2.lam, wrap=self._wrap)
     if self._adjust:
         r *= _scale_rad(p1.phi, p2.phi)
     return hypot2(r, p2.phi - p1.phi)  # like equirectangular_ d2
Beispiel #3
0
    def _zetaInv(self, taup, lam):
        '''(INTERNAL) 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 trip:
            self._iteration = 0
        else:
            stol2 = _TOL_10 / max(psi**2, 1.0)
            U, V = Fsum(u), Fsum(v)
            # min iterations = 2, max = 6, mean = 4.0
            for self._iteration in range(1, _TRIPS):  # GEOGRAPHICLIB_PANIC
                sncndn6 = self._sncndn6(u, v)
                T, L, _ = self._zeta3(  *sncndn6)
                dw, dv  = self._zetaDwd(*sncndn6)
                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 = hypot2(du, dv) < stol2
            else:
                t = unstr(self._zetaInv.__name__, taup, lam)
                raise EllipticError(_no_convergence_, txt=t)
        return u, v
Beispiel #4
0
    def _sigmaInv(self, xi, eta):
        '''(INTERNAL) 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
                sncndn6 = self._sncndn6(u, v)
                X, E, _ = self._sigma3(v, *sncndn6)
                dw, dv  = self._sigmaDwd( *sncndn6)
                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 = hypot2(du, dv) < _TOL_10
            else:
                raise EllipticError('no %s%r convergence' %
                                    ('_sigmaInv', (xi, eta)))
        return u, v
Beispiel #5
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#equirectangular>}.

       This approximation is valid for short distance of several
       hundred Km or Miles, see the B{C{limit}} keyword argument and
       the L{LimitError}.

       @arg lat1: Start latitude (C{degrees}).
       @arg lon1: Start longitude (C{degrees}).
       @arg lat2: End latitude (C{degrees}).
       @arg lon2: End longitude (C{degrees}).
       @kwarg adjust: Adjust the wrapped, unrolled longitudinal delta
                      by the cosine of the mean latitude (C{bool}).
       @kwarg limit: Optional limit for lat- and longitudinal deltas
                     (C{degrees}) or C{None} or C{0} for unlimited.
       @kwarg 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{cosineAndoyerLambert},
             L{cosineForsytheAndoyerLambert}, L{cosineLaw}, L{euclidean},
             L{flatLocal}/L{hubeny}, L{flatPolar}, L{haversine}, L{thomas}
             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 = unstr(equirectangular_.__name__,
                  lat1,
                  lon1,
                  lat2,
                  lon2,
                  limit=limit)
        raise LimitError('delta exceeds limit', txt=t)

    if adjust:  # scale delta lon
        d_lon *= _scale_deg(lat1, lat2)

    d2 = hypot2(d_lat, d_lon)  # degrees squared!
    return Distance4Tuple(d2, d_lat, d_lon, ulon2 - lon2)
Beispiel #6
0
    def toNvector(self,
                  Nvector=None,
                  datum=None,
                  **kwds):  # PYCHOK Datums.WGS84
        '''Convert this cartesian to C{n-vector} components.

           @keyword Nvector: Optional (sub-)class to return the
                             C{n-vector} components (C{Nvector})
                             or C{None}.
           @keyword datum: Optional datum (L{Datum}) overriding this
                           cartesian's datum.
           @keyword kwds: Optional, additional B{C{Nvector}} keyword
                          arguments, ignored if C{B{Nvector}=None}.

           @return: Unit vector B{C{Nvector}} or a L{Vector4Tuple}C{(x,
                    y, z, h)} if B{C{Nvector}=None}.

           @raise ValueError: The B{C{Cartesian}} at origin.
        '''
        d = datum or self.datum
        r = self._v4t
        if r is None or self.datum != d:
            E = d.ellipsoid
            x, y, z = self.to3xyz()

            # Kenneth Gade eqn 23
            p = hypot2(x, y) * 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)

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

            s = e / t
            r = Vector4Tuple(x * s, y * s, z / t, h)
            self._v4t = r if d == self.datum else None

        if Nvector is not None:
            r = Nvector(r.x, r.y, r.z, h=r.h, datum=d, **kwds)
        return self._xnamed(r)
Beispiel #7
0
    def _sigmaInv0(self, xi, eta):
        '''(INTERNAL) Starting point for C{sigmaInv}.

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

           @see: C{bool TMExact::sigmainv0(real xi, real eta,
                                           real &u, real &v)}.
        '''
        trip = False
        if eta > self._Ev_cKE_5_4 or xi < min(- self._Eu_cE_1_4,
                                          eta - self._Ev.cKE):
            # sigma as a simple pole at
            #  w = w0 = Eu.K() + i * Ev.K()
            # and sigma is approximated by
            #  sigma = (Eu.E() + i * Ev.KE()) + 1 / (w - w0)
            x = xi  - self._Eu.cE
            y = eta - self._Ev.cKE
            d = hypot2(x, y)
            u = self._Eu.cK + x / d
            v = self._Ev.cK - y / d

        elif eta > self._Ev.cKE or (xi < self._Eu_cE_1_4 and
                                   eta > self._Ev_cKE_3_4):
            # At w = w0 = i * Ev.K(), we have
            #  sigma  = sigma0  = i * Ev.KE()
            #  sigma' = sigma'' = 0
            #
            # including the next term in the Taylor series gives:
            #  sigma = sigma0 - _mv / 3 * (w - w0)^3
            #
            # When inverting this, we map arg(w - w0) = [-pi/2, -pi/6]
            # to arg(sigma - sigma0) = [-pi/2, pi/2]
            # mapping arg = [-pi/2, -pi/6] to [-pi/2, pi/2]
            d = eta - self._Ev.cKE
            r = hypot(xi, d)
            # Error using this guess is about 0.068 * rad^(5/3)
            trip = r < _TAYTOL2
            # Map the range [-90, 180] in sigma space to [-90, 0] in
            # w space.  See discussion in zetainv0 on the cut for ang.
            r = cbrt(r * self._3_mv)
            a = atan2(d - xi, xi + d) / 3.0 - PI_4
            s, c = sincos2(a)
            u = r * c
            v = r * s + self._Ev.cK

        else:  # use w = sigma * Eu.K/Eu.E (correct in the limit _e -> 0)
            u = xi  * self._Eu_cK_cE
            v = eta * self._Eu_cK_cE

        return u, v, trip
Beispiel #8
0
 def _distances(self, x, y):  # (x, y) radians**2
     for xk, yk in zip(self._xs, self._ys):
         d, _ = unrollPI(xk, x, wrap=self._wrap)
         if self._adjust:
             d *= _scale_rad(yk, y)
         yield hypot2(d, yk - y)  # like equirectangular_ distance2
Beispiel #9
0
    def toNvector(self,
                  Nvector=None,
                  datum=None,
                  **Nvector_kwds):  # PYCHOK Datums.WGS84
        '''Convert this cartesian to C{n-vector} components.

           @kwarg Nvector: Optional class to return the C{n-vector}
                           components (C{Nvector}) or C{None}.
           @kwarg datum: Optional datum (L{Datum}, L{Ellipsoid}, L{Ellipsoid2}
                         or L{a_f2Tuple}) overriding this cartesian's datum.
           @kwarg Nvector_kwds: Optional, additional B{C{Nvector}} keyword
                                arguments, ignored if B{C{Nvector=None}}.

           @return: The C{unit, n-vector} components (B{C{Nvector}}) or a
                    L{Vector4Tuple}C{(x, y, z, h)} if B{C{Nvector}} is C{None}.

           @raise TypeError: Invalid B{C{datum}}.

           @raise ValueError: The B{C{Cartesian}} at origin.

           @example:

           >>> c = Cartesian(3980581, 97, 4966825)
           >>> n = c.toNvector()  # (x=0.622818, y=0.00002, z=0.782367, h=0.242887)
        '''
        d = _ellipsoidal_datum(datum or self.datum, name=self.name)
        r = self._v4t
        if r is None or d != self.datum:
            # <https://www.Movable-Type.co.UK/scripts/geodesy/docs/
            #        latlon-nvector-ellipsoidal.js.html#line309>
            E = d.ellipsoid
            x, y, z = self.xyz

            # Kenneth Gade eqn 23
            p = hypot2(x, y) * 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_0, t, _1_0 / 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(origin=self)
            e = k / (k + E.e2)
            #           d = e * hypot(x, y)

            #           tmp = 1 / hypot(d, z) == 1 / hypot(e * hypot(x, y), z)
            t = hypot_(e * x, e * y, z)  # == 1 / tmp
            if t < EPS:
                raise _ValueError(origin=self)
            h = fsum_(k, E.e2, -_1_0) / k * t

            s = e / t  # == e * tmp
            r = Vector4Tuple(x * s, y * s, z / t, h)
            self._v4t = r if d == self.datum else None

        if Nvector is not None:
            r = Nvector(r.x, r.y, r.z, h=r.h, datum=d, **Nvector_kwds)
        return self._xnamed(r)