圆相关计算(模板)

struct Circle{
	Point c;
	double r;
	Circle(Point cc,double rr):c(cc),r(rr){}
	Point point(double a){//通过圆心角a求圆上坐标 
		return Point(c.x+cos(a)*r,c.y+sin(a)*r);
	}
};

//直线和圆交点,解一元二次方程,注意sol没有清空 
int getLineCircleIntersection(Point P,Vector v,Circle C,double& t1,double& t2,vector<Point>& sol){
	double a=v.x,b=P.x-C.c.x,c=v.y,d=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(P+v*t1);
		return 1;
	}
	//相交
	t1=(-f-sqrt(delta))/(2*e);sol.push_back(P+v*t1);
	t2=(-f+sqrt(delta))/(2*e);sol.push_back(P+v*t2);
	return 2;
}

//向量极角 
double angle(Vector v){ return atan2(v.y,v.x); }

//两圆交点,注意sol没有清空 
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));
	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;//相交 
}

//过点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);
		return 2;
	}
}

//两圆公切线,返回切线条数,-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); }
	double d=Length(B.c-A.c);
	double rdiff=A.r-B.r;
	double rsum=A.r+B.r;
	if(dcmp(d-rdiff)==-1) return 0;//内含
	
	double base=angle(B.c-A.c); 
	if(dcmp(d)==0 && dcmp(A.r-B.r)==0) return -1;//无数条公切线 
	if(dcmp(d-rdiff)==0){//内切
		a[cnt]=A.point(base);
		b[cnt]=B.point(base);
		++cnt; 
		return 1;
	}
	//有外公切线
	double ang=acos((A.r-B.r)/d);
	a[cnt]=A.point(base+ang);b[cnt]=B.point(base+ang);++cnt;
	a[cnt]=A.point(base-ang);b[cnt]=B.point(base-ang);++cnt;
	if(dcmp(d-rsum)==0){//一条内公切线 
		a[cnt]=A.point(base);
		b[cnt]=B.point(base+PI);
		++cnt;
	}
	else if(dcmp(d-rsum)>0){//两条内公切线 
		ang=acos((A.r+B.r)/d);
		a[cnt]=A.point(base+ang);b[cnt]=B.point(base+ang+PI);++cnt;
		a[cnt]=A.point(base-ang);b[cnt]=B.point(base-ang+PI);++cnt;
	}
	return cnt;
}
posted @ 2019-02-15 21:46  不想吃WA的咸鱼  阅读(325)  评论(0编辑  收藏  举报