一、通过圆心角求坐标的函数
struct Circle{
Point c;
double r;
Circle(Point c,double r):c(c),r(r) {}
Point getPoint(double a){
return Point(c.x+cos(a)*r,c.y+sin(s)*r);
}
};
二、直线和圆的交点
int getLineCircleIntersection(Line L,Circle C,double& t1,double& t2,vector<Point>& sol){
double a = L.v.x,b = L.p.x-C.c.x,c = L.v.y,d = L.p.y-C.c.y;
double e = a*a+c*c,f = 2*(a*b+c*d),g = b*b+d*d-C.r*C.r;
double delta = f*f-4*e*g; //判别式
if(dcmp(delta) < 0) //相离
return 0; //相切
if(dcmp(delta) == 0){
t1 = t2 = -f/(2*e);
sol.push_back(L.point(t1));
return 1;
}
//相交
t1 = (-f-sqrt(delta))/(2*e);
sol.push_back(L.point(t1));
t2 = (-f+sqrt(delta))/(2*e);
sol.push_back(L.point(t2));
return 2;
}
//函数返回的是交点的个数,参数sol存放的是交点本身。 注意上述代码并没有清空sol
三、计算向量极角的方法
double angle(Vector v){
return atan2(v.y,v.x);
}
四、两圆相交的代码
int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point>& sol){
double d = Length(C1.c-C2.c);
if(dcmp(d) == 0){
if(dcmp(C1.r-C2.r) == 0) //两圆重合
return -1;
return 0;
}
if(dcmp(C1.r+C2.r-d) < 0)
return 0;
if(dcmp(fabs(C1.r-C2.r)-d) > 0)
return 0;
double a = angle(C2.c-C1.c); //向量C1C2的极角
double da = acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d)); //C1C2到C1P1的角
Point p1 = C1.point(a-da),p2 = C1.point(a+da);
sol.push_back(p1);
if(p1 == p2)
return 1;
sol.push_back(p2);
return 2;
}
五、两圆相交的面积
double area(Point c1,double r1,Point c2,double r2){
double d = dis(c1,c2);
if (r1+r2 < d+exs)
return 0;//相离
if (d < fabs(r1-r2)+exp){//内含
double r = min(r1,r2);
return PI*r*r;
}
double x = (d*d+r1*r1-r2*r2)/(2*d);
double t1 = acos(x/r1);
double t2 = acos((d-x)/r2);
return r1*r1*t1+r2*r2*t2-d*r1*sin(t1);//相交
}
六、过定点作圆的切线
//过点p到圆C的切线。v[i]是第i条切线的向量。返回切线条数
int getTangents(Point p,Circle C,Vector* v){
Vector u=C.c-p;
double dist=Length(u);
if(dist<C.r)
return 0;
else if(dcmp(dist-C.r)==0){
//p在圆上,只有一条切线
v[0]=Rotate(u,PI/2);
return 1;
}
else{
double ang=asin(C.r/dist);
v[0]=Rotate(u,-ang);
v[1]=Rotate(u,+ang);
trturn 2;
}
}
七、外公切线(假定r1>=r2)
//返回切线的条数。-1表示无穷条切线
//a[i]和b[i]分别是第i条切线在圆A和圆B上的切点
int getTangents(Circle A,Circle B,Point* a,Point* b){
int cnt = 0;
if(A.r < B.r){
swap(A,B);
swap(a,b);
}
int d2 = (A.c.x-B.c.x)*(A.c.x-B.c.x)+(A.c.y-B.c.y)*(A.c.y-B.c.y);
int rdiff = A.r-B.r;
int rsum = A.r+B.r;
if(d2 < rdiff*rdiff)
return 0; //内含
double base = atan2(B.c.y-A.c.y,B.c.x-A.c.x);
if(d2==0 && A.r==B.r)
return -1; //无限条切线
if(d2 == rdiff*rdiff){
//内切,1条切线
a[cnt] = A.getPoint(base); b[cnt] = B.getPoint(base); ++cnt;
return 1;
}
//有外公切线
double ang = acos((A.r-B.r)/sqrt(d2));
a[cnt] = A.getPoint(base+ang); b[cnt] = B.getPoint(base+ang); ++cnt;
a[cnt] = A.getPoint(base-ang); b[cnt] = B.getPoint(base-ang); ++cnt;
if(d2 == rsum*rsum){
//一条公切线
a[cnt] = A.getPoint(base); b[cnt] = B.getPoint(pi+base); ++cnt;
}
else if(d2 > rsum*rsum){
//两条公切线
double ang = acos((A.r+B.r)/sqrt(d2));
a[cnt] = A.getPoint(base+ang); b[cnt] = B.getPoint(pi+base+ang); ++cnt;
a[cnt] = A.getPoint(base-ang); b[cnt] = B.getPoint(pi+base-ang); ++cnt;
}
return cnt;
}