Ejemplo n.º 1
0
def _intersects2(c1, rad1, c2, rad2, radius=R_M,  # in .ellipsoidalBase._intersects2
                                     height=None, wrap=True, too_d=None,
                                     LatLon=LatLon, **LatLon_kwds):
    # (INTERNAL) Intersect two spherical circles, see L{intersections2}
    # above, separated to allow callers to embellish any exceptions

    def _dest3(bearing, h):
        a, b = _destination2(a1, b1, r1, bearing)
        return _latlon3(degrees90(a), degrees180(b), h,
                        intersections2, LatLon, **LatLon_kwds)

    r1, r2, f = _rads3(rad1, rad2, radius)
    if f:  # swapped
        c1, c2 = c2, c1  # PYCHOK swap

    a1, b1 = c1.philam
    a2, b2 = c2.philam

    db, b2 = unrollPI(b1, b2, wrap=wrap)
    d = vincentys_(a2, a1, db)  # radians
    if d < max(r1 - r2, EPS):
        raise ValueError(_near_concentric_)

    x = fsum_(r1, r2, -d)  # overlap
    if x > EPS:
        sd, cd, sr1, cr1, _, cr2 = sincos2(d, r1, r2)
        x = sd * sr1
        if abs(x) < EPS:
            raise ValueError(_invalid_)
        x = acos1((cr2 - cd * cr1) / x)  # 0 <= x <= PI

    elif x < 0:
        t = (d * radius) if too_d is None else too_d
        raise ValueError(_too_distant_fmt_ % (t,))

    if height is None:  # "radical height"
        f = _radical2(d, r1, r2).ratio
        h = Height(favg(c1.height, c2.height, f=f))
    else:
        h = Height(height)

    b = bearing_(a1, b1, a2, b2, final=False, wrap=wrap)
    if x < _EPS_I2:  # externally ...
        r = _dest3(b, h)
    elif x > _PI_EPS_I2:  # internally ...
        r = _dest3(b + PI, h)
    else:
        return _dest3(b + x, h), _dest3(b - x, h)
    return r, r  # ... abutting circles
Ejemplo n.º 2
0
    def initialBearingTo(self, other, wrap=False, raiser=False):
        '''Compute the initial bearing (forward azimuth) from this
           to an other point.

           @param other: The other point (spherical L{LatLon}).
           @keyword wrap: Wrap and unroll longitudes (C{bool}).
           @keyword raiser: Optionally, raise L{CrossError} (C{bool}),
                            use B{C{raiser}}=C{True} for behavior like
                            C{sphericalNvector.LatLon.initialBearingTo}.

           @return: Initial bearing (compass C{degrees360}).

           @raise CrossError: If this and the B{C{other}} point coincide,
                              provided B{C{raiser}} is C{True} and
                              L{crosserrors} is C{True}.

           @raise TypeError: The B{C{other}} point is not L{LatLon}.

           @example:

           >>> p1 = LatLon(52.205, 0.119)
           >>> p2 = LatLon(48.857, 2.351)
           >>> b = p1.initialBearingTo(p2)  # 156.2

           @JSname: I{bearingTo}.
        '''
        self.others(other)

        a1, b1 = self.to2ab()
        a2, b2 = other.to2ab()

        # XXX behavior like sphericalNvector.LatLon.initialBearingTo
        if raiser and crosserrors() and max(abs(a2 - a1), abs(b2 - b1)) < EPS:
            raise CrossError('%s %s: %r' % ('coincident', 'points', other))

        return degrees(bearing_(a1, b1, a2, b2, final=False, wrap=wrap))
Ejemplo n.º 3
0
def _xb(a1, b1, end, a, b, wrap):
    # difference between the bearing to (a, b) and the given
    # bearing is negative if both are in opposite directions
    r = bearing_(a1, b1, radians(a), radians(b), wrap=wrap)
    return PI_2 - abs(wrapPI(r - radians(end)))
Ejemplo n.º 4
0
def intersections2(
        center1,
        rad1,
        center2,
        rad2,
        radius=R_M,  # MCCABE 13
        height=None,
        wrap=False,
        LatLon=LatLon,
        **LatLon_kwds):
    '''Compute the intersection points of two circles each defined
       by a center point and radius.

       @arg center1: Center of the first circle (L{LatLon}).
       @arg rad1: Radius of the second circle (C{meter} or C{radians},
                  see B{C{radius}}).
       @arg center2: Center of the second circle (L{LatLon}).
       @arg rad2: Radius of the second circle (C{meter} or C{radians},
                  see B{C{radius}}).
       @kwarg radius: Mean earth radius (C{meter} or C{None} if both
                      B{C{rad1}} and B{C{rad2}} are given in C{radians}).
       @kwarg height: Optional height for the intersection point,
                      overriding the mean height (C{meter}).
       @kwarg wrap: Wrap and unroll longitudes (C{bool}).
       @kwarg LatLon: Optional class to return the intersection
                      points (L{LatLon}) or C{None}.
       @kwarg LatLon_kwds: Optional, additional B{C{LatLon}} keyword
                           arguments, ignored if B{C{LatLon=None}}.

       @return: 2-Tuple of the intersection points, each a B{C{LatLon}}
                instance or L{LatLon3Tuple}C{(lat, lon, height)} if
                B{C{LatLon}} is C{None}.  The intersection points are
                the same instance for abutting circles.

       @raise IntersectionError: Concentric, antipodal, invalid or
                                 non-intersecting circles.

       @raise TypeError: If B{C{center1}} or B{C{center2}} not L{LatLon}.

       @raise ValueError: Invalid B{C{rad1}}, B{C{rad2}}, B{C{radius}} or
                          B{C{height}}.

       @note: Courtesy U{Samuel Čavoj<https://GitHub.com/mrJean1/PyGeodesy/issues/41>}.

       @see: This U{Answer<https://StackOverflow.com/questions/53324667/
             find-intersection-coordinates-of-two-circles-on-earth/53331953>}.
    '''
    def _destination1(bearing):
        a, b = _destination2(a1, b1, r1, bearing)
        return _latlon3(degrees90(a), degrees180(b), h, intersections2, LatLon,
                        **LatLon_kwds)

    _Trll.others(center1, name='center1')
    _Trll.others(center2, name='center2')

    a1, b1 = center1.philam
    a2, b2 = center2.philam
    r1, r2, x = _rads3(rad1, rad2, radius)
    if x:
        a1, b1, a2, b2 = a2, b2, a1, b1

    db, _ = unrollPI(b1, b2, wrap=wrap)
    d = vincentys_(a2, a1, db)  # radians
    if d < max(r1 - r2, EPS):
        raise IntersectionError(center1=center1,
                                rad1=rad1,
                                center2=center2,
                                rad2=rad2,
                                txt=_near_concentric_)

    x = fsum_(r1, r2, -d)
    if x > EPS:
        try:
            sd, cd, s1, c1, _, c2 = sincos2(d, r1, r2)
            x = sd * s1
            if abs(x) < EPS:
                raise ValueError
            x = acos1((c2 - cd * c1) / x)
        except ValueError:
            raise IntersectionError(center1=center1,
                                    rad1=rad1,
                                    center2=center2,
                                    rad2=rad2)
    elif x < 0:
        raise IntersectionError(center1=center1,
                                rad1=rad1,
                                center2=center2,
                                rad2=rad2,
                                txt=_too_distant_)

    b = bearing_(a1, b1, a2, b2, final=False, wrap=wrap)
    if height is None:
        h = fmean((center1.height, center2.height))
    else:
        Height(height)
    if abs(x) > EPS:
        return _destination1(b + x), _destination1(b - x)
    else:  # abutting circles
        x = _destination1(b)
        return x, x