Esempio n. 1
0
    def reverse(self, x, y, name=NN, LatLon=None, **LatLon_kwds):
        '''Convert an azimuthal gnomonic location to (ellipsoidal) geodetic lat- and longitude.

           @arg x: Easting of the location (C{meter}).
           @arg y: Northing of the location (C{meter}).
           @kwarg name: Optional name for the location (C{str}).
           @kwarg LatLon: Class to use (C{LatLon}) or C{None}.
           @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
                               arguments, ignored if C{B{LatLon}=None}.

           @return: The geodetic (C{LatLon}) or if B{C{LatLon}} is C{None} an
                    L{Azimuthal7Tuple}C{(x, y, lat, lon, azimuth, scale, datum)}.

           @raise AzimuthalError: No convergence.

           @note: The C{lat} will be in the range C{[-90..90] degrees} and C{lon}
                  in the range C{[-180..180] degrees}.  The C{azimuth} is clockwise
                  from true North.  The scale is C{1 / reciprocal**2} in C{radial}
                  direction and C{1 / reciprocal} in the direction perpendicular
                  to this.
        '''
        x = Scalar(x=x)
        y = Scalar(y=y)

        z = atan2d(x, y)  # (x, y) for azimuth from true North
        q = hypot(x, y)

        d = e = self.equatoradius
        s = e * atan(q / e)
        if q > e:

            def _d(r, q):
                return (r.M12 - q * r.m12) * r.m12  # negated

            q = 1 / q
        else:  # little == True

            def _d(r, q):  # PYCHOK _d
                return (q * r.M12 - r.m12) * r.M12  # negated

        e *= _Karney_eps

        S = Fsum(s)
        g = self.geodesic.Line(self.lat0, self.lon0, z, self._mask)
        for self._iteration in range(1, _TRIPS):
            r = g.Position(s, self._mask)
            if abs(d) < e:
                break
            s, d = S.fsum2_(_d(r, q))
        else:
            raise AzimuthalError(x=x, y=y, txt=_no_(Fmt.convergence(e)))

        t = self._7Tuple(x, y, r, r.M12) if LatLon is None else \
            self._toLatLon(r.lat2, r.lon2, LatLon, LatLon_kwds)

        t._iteration = self._iteration
        return self._xnamed(t, name=name)
Esempio n. 2
0
    def _tanf(self, txi):  # called from .Ellipsoid.auxAuthalic
        '''(INTERNAL) Function M{tan-phi from tan-xi}.
        '''
        tol = _tol(_TOL, txi)

        e2 = self.datum.ellipsoid.e2
        qx = self._qx

        ta = txi
        Ta = Fsum(ta)
        for self._iteration in range(1, _NUMIT):  # max 2, mean 1.99
            # dtxi/dta = (scxi / sca)^3 * 2 * (1 - e^2) / (qZ * (1 - e^2 * sa^2)^2)
            ta2 = ta**2
            sca2 = ta2 + _1_0
            txia = self._txif(ta)
            s3qx = sqrt3(sca2 / (_1_0 + txia**2)) * qx
            ta, d = Ta.fsum2_(
                (txi - txia) * s3qx * (_1_0 - e2 * ta2 / sca2)**2)
            if abs(d) < tol:
                return ta
        raise AlbersError(iteration=_NUMIT, txt=_no_(Fmt.convergence(tol)))
Esempio n. 3
0
    def __init__(self, sa1, ca1, sa2, ca2, k, datum, name):
        '''(INTERNAL) New C{AlbersEqualArea...} instance.
        '''
        if datum not in (None, self._datum):
            self._datum = _ellipsoidal_datum(datum, name=name)
        if name:
            self.name = name

        E = self.datum.ellipsoid
        b_a = E.b_a  # fm  = 1 - E.f
        e2 = E.e2
        e12 = E.e12  # e2m = 1 - E.e2

        self._qZ = qZ = _1_0 + e12 * self._atanhee(1)
        self._qZa2 = qZ * E.a2
        self._qx = qZ / (_2_0 * e12)

        c = min(ca1, ca2)
        if c < 0:
            raise AlbersError(clat1=ca1, clat2=ca2)
        polar = c < _EPS__2  # == 0
        # determine hemisphere of tangent latitude
        if sa1 < 0:  # and sa2 < 0:
            self._sign = -1
            # internally, tangent latitude positive
            sa1, sa2 = -sa1, neg(sa2)
        if sa1 > sa2:  # make phi1 < phi2
            sa1, sa2 = sa2, sa1
            ca1, ca2 = ca2, ca1
        if sa1 < 0:  # or sa2 < 0:
            raise AlbersError(slat1=sa1, slat2=sa2)
        # avoid singularities at poles
        ca1, ca2 = max(_EPS__2, ca1), max(_EPS__2, ca2)
        ta1, ta2 = sa1 / ca1, sa2 / ca2

        par1 = abs(ta1 - ta2) < _EPS__4  # ta1 == ta2
        if par1 or polar:
            C, ta0 = _1_0, ta2
        else:
            s1_qZ, C = self._s1_qZ_C2(ca1, sa1, ta1, ca2, sa2, ta2)

            ta0 = (ta2 + ta1) * _0_5
            Ta0 = Fsum(ta0)
            tol = _tol(_TOL0, ta0)
            for self._iteration in range(1, _NUMIT0):
                ta02 = ta0**2
                sca02 = ta02 + _1_0
                sca0 = sqrt(sca02)
                sa0 = ta0 / sca0
                sa01 = sa0 + _1_0
                sa02 = sa0**2
                # sa0m = 1 - sa0 = 1 / (sec(a0) * (tan(a0) + sec(a0)))
                sa0m = _1_0 / (sca0 * (ta0 + sca0))  # scb0^2 * sa0
                g = (_1_0 + (b_a * ta0)**2) * sa0
                dg = e12 * sca02 * (_1_0 + 2 * ta02) + e2
                D = sa0m * (_1_0 - e2 *
                            (_1_0 + sa01 * 2 * sa0)) / (e12 * sa01)  # dD/dsa0
                dD = -2 * (_1_0 - e2 * sa02 *
                           (_3_0 + 2 * sa0)) / (e12 * sa01**2)
                sa02_ = _1_0 - e2 * sa02
                sa0m_ = sa0m / (_1_0 - e2 * sa0)
                BA = sa0m_ * (self._atanhx1(e2 * sa0m_**2) * e12 - e2 * sa0m) \
                   - sa0m**2 * e2 * (2 + (_1_0 + e2) * sa0) / (e12 * sa02_)  # == B + A
                dAB = 2 * e2 * (2 - e2 *
                                (_1_0 + sa02)) / (e12 * sa02_**2 * sca02)
                u_du = fsum_(s1_qZ *  g,  -D,  g * BA) \
                     / fsum_(s1_qZ * dg, -dD, dg * BA, g * dAB)  # == u/du
                ta0, d = Ta0.fsum2_(-u_du * (sca0 * sca02))
                if abs(d) < tol:
                    break
            else:
                raise AlbersError(iteration=_NUMIT0,
                                  txt=_no_(Fmt.convergence(tol)))

        self._txi0 = txi0 = self._txif(ta0)
        self._scxi0 = hypot1(txi0)
        self._sxi0 = sxi0 = txi0 / self._scxi0
        self._m02 = m02 = _1_0 / (_1_0 + (b_a * ta0)**2)
        self._n0 = n0 = ta0 / hypot1(ta0)
        if polar:
            self._polar = True
            self._nrho0 = self._m0 = _0_0
        else:
            self._m0 = sqrt(m02)  # == nrho0 / E.a
            self._nrho0 = E.a * self._m0  # == E.a * sqrt(m02)
        self._k0_(_1_0 if par1 else (k * sqrt(C / (m02 + n0 * qZ * sxi0))))
        self._lat0 = _Lat(lat0=self._sign * atand(ta0))
Esempio n. 4
0
def _nearestOn(p,
               p1,
               p2,
               within=True,
               height=None,
               wrap=True,
               equidistant=None,
               tol=_TOL_M,
               LatLon=None,
               **LatLon_kwds):
    # (INTERNAL) Get closet point, like L{_intersects2} above,
    # separated to allow callers to embellish any exceptions

    from pygeodesy.sphericalNvector import LatLon as _LLS
    from pygeodesy.vector3d import _nearestOn as _vnOn, Vector3d

    def _v(t, h):
        return Vector3d(t.x, t.y, h)

    _ = p.ellipsoids(p1)
    E = p.ellipsoids(p2)

    if wrap:
        p1 = _unrollon(p, p1)
        p2 = _unrollon(p, p2)
        p2 = _unrollon(p1, p2)

    r = E.rocMean(fmean_(p.lat, p1.lat, p2.lat))
    e = max(m2degrees(tol, radius=r), EPS)

    # get the azimuthal equidistant projection
    A = _Equidistant2(equidistant, p.datum)

    # gu-/estimate initial nearestOn, spherically ... wrap=False
    t = _LLS(p.lat, p.lon, height=p.height).nearestOn(_LLS(p1.lat,
                                                           p1.lon,
                                                           height=p1.height),
                                                      _LLS(p2.lat,
                                                           p2.lon,
                                                           height=p2.height),
                                                      within=within,
                                                      height=height)
    n = t.name

    h = h1 = h2 = 0
    if height is False:  # use height as Z component
        h = t.height
        h1 = p1.height
        h2 = p2.height

    # ... and then iterate like Karney suggests to find
    # tri-points of median lines, @see: references under
    # method LatLonEllipsoidalBase.intersections2 above
    c = None  # force first d == c to False
    # closest to origin, .z to interpolate height
    p = Vector3d(0, 0, h)
    for i in range(1, _TRIPS):
        A.reset(t.lat, t.lon)  # gu-/estimate as origin
        # convert points to projection space
        t1 = A.forward(p1.lat, p1.lon)
        t2 = A.forward(p2.lat, p2.lon)
        # compute nearestOn in projection space
        v = _vnOn(p, _v(t1, h1), _v(t2, h2), within=within)
        # convert nearestOn back to geodetic
        r = A.reverse(v.x, v.y)
        d = euclid(r.lat - t.lat, r.lon - t.lon)
        # break if below tolerance or if unchanged
        t = r
        if d < e or d == c:
            t._iteration = i  # _NamedTuple._iteration
            if height is False:
                h = v.z  # nearest interpolated
            break
        c = d
    else:
        raise ValueError(_no_(Fmt.convergence(tol)))

    r = _LatLon4Tuple(t.lat, t.lon, h, t.datum, LatLon, LatLon_kwds)
    r._iteration = t.iteration  # ._iteration for tests
    return _xnamed(r, n)
Esempio n. 5
0
def _intersects2(
        c1,
        r1,
        c2,
        r2,
        height=None,
        wrap=True,  # MCCABE 17
        equidistant=None,
        tol=_TOL_M,
        LatLon=None,
        **LatLon_kwds):
    # (INTERNAL) Intersect two spherical circles, see L{_intersections2}
    # above, separated to allow callers to embellish any exceptions

    from pygeodesy.sphericalTrigonometry import _intersects2 as _si2, LatLon as _LLS
    from pygeodesy.vector3d import _intersects2 as _vi2

    def _latlon4(t, h, n):
        r = _LatLon4Tuple(t.lat, t.lon, h, t.datum, LatLon, LatLon_kwds)
        r._iteration = t.iteration  # ._iteration for tests
        return _xnamed(r, n)

    if r1 < r2:
        c1, c2 = c2, c1
        r1, r2 = r2, r1

    E = c1.ellipsoids(c2)
    if r1 > (min(E.b, E.a) * PI):
        raise ValueError(_exceed_PI_radians_)

    if wrap:  # unroll180 == .karney._unroll2
        c2 = _unrollon(c1, c2)

    # distance between centers and radii are
    # measured along the ellipsoid's surface
    m = c1.distanceTo(c2, wrap=False)  # meter
    if m < max(r1 - r2, EPS):
        raise ValueError(_near_concentric_)
    if fsum_(r1, r2, -m) < 0:
        raise ValueError(_too_(Fmt.distant(m)))

    f = _radical2(m, r1, r2).ratio  # "radical fraction"
    r = E.rocMean(favg(c1.lat, c2.lat, f=f))
    e = max(m2degrees(tol, radius=r), EPS)

    # get the azimuthal equidistant projection
    A = _Equidistant2(equidistant, c1.datum)

    # gu-/estimate initial intersections, spherically ...
    t1, t2 = _si2(_LLS(c1.lat, c1.lon, height=c1.height),
                  r1,
                  _LLS(c2.lat, c2.lon, height=c2.height),
                  r2,
                  radius=r,
                  height=height,
                  wrap=False,
                  too_d=m)
    h, n = t1.height, t1.name

    # ... and then iterate like Karney suggests to find
    # tri-points of median lines, @see: references under
    # method LatLonEllipsoidalBase.intersections2 above
    ts, ta = [], None
    for t in ((t1, ) if t1 is t2 else (t1, t2)):
        p = None  # force first d == p to False
        for i in range(1, _TRIPS):
            A.reset(t.lat, t.lon)  # gu-/estimate as origin
            # convert centers to projection space
            t1 = A.forward(c1.lat, c1.lon)
            t2 = A.forward(c2.lat, c2.lon)
            # compute intersections in projection space
            v1, v2 = _vi2(
                t1,
                r1,  # XXX * t1.scale?,
                t2,
                r2,  # XXX * t2.scale?,
                sphere=False,
                too_d=m)
            # convert intersections back to geodetic
            t1 = A.reverse(v1.x, v1.y)
            d1 = euclid(t1.lat - t.lat, t1.lon - t.lon)
            if v1 is v2:  # abutting
                t, d = t1, d1
            else:
                t2 = A.reverse(v2.x, v2.y)
                d2 = euclid(t2.lat - t.lat, t2.lon - t.lon)
                # consider only the closer intersection
                t, d = (t1, d1) if d1 < d2 else (t2, d2)
            # break if below tolerance or if unchanged
            if d < e or d == p:
                t._iteration = i  # _NamedTuple._iteration
                ts.append(t)
                if v1 is v2:  # abutting
                    ta = t
                break
            p = d
        else:
            raise ValueError(_no_(Fmt.convergence(tol)))

    if ta:  # abutting circles
        r = _latlon4(ta, h, n)
    elif len(ts) == 2:
        return _latlon4(ts[0], h, n), _latlon4(ts[1], h, n)
    elif len(ts) == 1:  # XXX assume abutting
        r = _latlon4(ts[0], h, n)
    else:
        raise _AssertionError(ts=ts)
    return r, r