hznu1865 判断点是否存在一条射线经过A圆而不经过B圆

这道题目由于是射线,所以用直线斜率去做可能会分错方向。首先肯定是要求出四个切点的坐标的。假设这个圆外一点坐标是(a,b),那么可以设另一个点(a+1,b),然后以每个切点分别作第三个点形成夹角。要求这个夹角的角度可以先根据三点求出三边,再套用cosx=(a2+b2-c2)/2ab求出arccosx,这样即可求出四个弧角。最后只要根据这两对弧角判断情况即可(不过分的情况还是蛮多的。。。)

#include <bits/stdc++.h>
using namespace std;
struct POINT{
    double x,y;
};
void  c2point(POINT p1,double r1,POINT p2,double r2,POINT &rp1,POINT &rp2) 
{ 
    double a,b,r; 
    a=p2.x-p1.x; 
    b=p2.y-p1.y; 
    r=(a*a+b*b+r1*r1-r2*r2)/2; 
    if(a==0&&b!=0) 
    { 
        rp1.y=rp2.y=r/b; 
        rp1.x=sqrt(r1*r1-rp1.y*rp1.y); 
        rp2.x=-rp1.x; 
    } 
    else if(a!=0&&b==0) 
    { 
        rp1.x=rp2.x=r/a; 
        rp1.y=sqrt(r1*r1-rp1.x*rp2.x); 
        rp2.y=-rp1.y; 
    } 
    else if(a!=0&&b!=0) 
    { 
        double delta; 
        delta=b*b*r*r-(a*a+b*b)*(r*r-r1*r1*a*a); 
        rp1.y=(b*r+sqrt(delta))/(a*a+b*b); 
        rp2.y=(b*r-sqrt(delta))/(a*a+b*b); 
        rp1.x=(r-b*rp1.y)/a; 
        rp2.x=(r-b*rp2.y)/a; 
    } 
    rp1.x+=p1.x; 
    rp1.y+=p1.y; 
    rp2.x+=p1.x; 
    rp2.y+=p1.y; 
} 
//求切点: 
// p---圆心坐标, r---圆半径, sp---圆外一点, rp1,rp2---切点坐标 
void cutpoint(POINT p,double r,POINT sp,POINT &rp1,POINT &rp2) 
{ 
    POINT p2; 
    p2.x=(p.x+sp.x)/2; 
    p2.y=(p.y+sp.y)/2; 
     
    double dx2,dy2,r2; 
    dx2=p2.x-p.x; 
    dy2=p2.y-p.y; 
    r2=sqrt(dx2*dx2+dy2*dy2); 
    c2point(p,r,p2,r2,rp1,rp2); 
}
 
int main(){
    POINT a,b,c;
    double r1,r2;
    while(cin>>a.x>>a.y>>b.x>>b.y>>r1>>c.x>>c.y>>r2){
        POINT g1,g2,h1,h2;
        cutpoint(b,r1,a,g1,g2);
        cutpoint(c,r2,a,h1,h2);
        double aa,bb,cc;
        aa=sqrt((g1.y-a.y)*(g1.y-a.y)+(g1.x-a.x)*(g1.x-a.x));
        bb=1;
        cc=sqrt((g1.y-a.y)*(g1.y-a.y)+(g1.x-a.x-1)*(g1.x-a.x-1));
        double d1=acos((aa*aa+1-cc*cc)/(2*aa));
        if(g1.y<a.y) d1=3.1415926535*2-d1; //判在三四象限的情况(因为acos只有0~π)
         
        aa=sqrt((g2.y-a.y)*(g2.y-a.y)+(g2.x-a.x)*(g2.x-a.x));
        bb=1;
        cc=sqrt((g2.y-a.y)*(g2.y-a.y)+(g2.x-a.x-1)*(g2.x-a.x-1));
        double d2=acos((aa*aa+1-cc*cc)/(2*aa));
        if(g2.y<a.y) d2=3.1415926535*2-d2;
         
        aa=sqrt((h1.y-a.y)*(h1.y-a.y)+(h1.x-a.x)*(h1.x-a.x));
        bb=1;
        cc=sqrt((h1.y-a.y)*(h1.y-a.y)+(h1.x-a.x-1)*(h1.x-a.x-1));
        double d3=acos((aa*aa+1-cc*cc)/(2*aa));
        if(h1.y<a.y) d3=3.1415926535*2-d3;
         
        aa=sqrt((h2.y-a.y)*(h2.y-a.y)+(h2.x-a.x)*(h2.x-a.x));
        bb=1;
        cc=sqrt((h2.y-a.y)*(h2.y-a.y)+(h2.x-a.x-1)*(h2.x-a.x-1));
        double d4=acos((aa*aa+1-cc*cc)/(2*aa));
        if(h2.y<a.y) d4=3.1415926535*2-d4;
                 
        if(fabs(d2-d1)>3.1415926535){  //判两条射线的夹角是哪一个(大于π的那个肯定不是)
            if(d1<d2) d1+=3.14*2;
            else d2+=3.14*2;
        }   
        if(fabs(d4-d3)>3.1415926535){
            if(d3<d4) d3+=3.14*2;
            else d4+=3.14*2;
        }
        if(d1>3.1415926535*2||d2>3.1415926535*2){  //注意如果某对的一个在2π以上,另一对假如都在一二象限那么也要加2π
            if(d3<3.1415926535&&d4<3.1415926535){
                d3+=3.1415926535*2;
                d4+=3.1415926535*2;
            }
        }
        if(d3>3.1415926535*2||d4>3.1415926535*2){
            if(d1<3.1415926535&&d2<3.1415926535){
                d1+=3.1415926535*2;
                d2+=3.1415926535*2;
            }
        }
        if(min(d1,d2)<=min(d3,d4)&&max(d1,d2)>=max(d3,d4)) cout<<"No"<<endl;
        else cout<<"Yes"<<endl;
    }   
    return 0;
}  
/*
3 5 5 6 2 8 8 3
No
*/   


你可能感兴趣的:(hznu1865 判断点是否存在一条射线经过A圆而不经过B圆)