思路:将每一条线段看成一条直线和圆联立起来解方程,无解则直接false,有解的话就判断两个端点是否在交点的同一侧,在同一侧说明与线段不想交,否则就相交
也可以通过求圆心到直线距离然后求垂足,也一样判断线段两点是否在交点的同一侧来求解、
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
double x[5],y[5];
const double eps = 1e-15;
int cmp(double x){
if(fabs(x)<eps) return 0;
if(x>0) return 1;
return -1;
}
int judge(double a, double b, double c, double &x1, double &x2){
double tmp = b*b-4*a*c;
if(cmp(tmp)<0) return 0;
x1 = (-b+sqrt(tmp))/(2*a);
x2 = (-b-sqrt(tmp))/(2*a);
return 1;
}
bool f(int i, int j, double xc, double yc, double R){
double k,b;
if(cmp(x[i]-x[j])==0){
double t = R*R-(xc-x[i])*(xc-x[i]);
if(t<0) return false;
double maxn = max(y[i], y[j]),minx = min(y[i], y[j]),y1=sqrt(t)+yc,y2=yc-sqrt(t);
if(cmp(minx-y1)<=0&&cmp(y1-maxn)<=0) return true;
if(cmp(minx-y2)<=0&&cmp(y2-maxn)<=0) return true;
return false;
}
k = (y[i]-y[j])/(x[i]-x[j]);
b = y[i] - k*x[i];
double x1,x2;
int flag = judge(1+k*k, 2*k*b-2*yc*k-2*xc, xc*xc+b*b-2*yc*b+yc*yc-R*R, x1, x2);
if(flag == 0) return false;
int maxn = max(x[i], x[j]), minx = min(x[i], x[j]);
if(cmp(minx-x1)<=0&&cmp(x1-maxn)<=0) return true;
if(cmp(minx-x2)<=0&&cmp(x2-maxn)<=0) return true;
return false;
}
int main(){
int t;scanf("%d",&t);
while(t--){
double xc, yc, R;scanf("%lf%lf%lf",&xc,&yc,&R);
for(int i=0; i<3; ++i) scanf("%lf%lf",x+i,y+i);
int flag = 0;
for(int j,i=0; i<3; ++i)
for(j=i+1; j<3; ++j)
if(f(i, j, xc, yc, R)) flag = 1;
if(flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}