UVA-12304 测试圆相关模板

题目
kuangbin模板

#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
const int N=1e5+7;
const double inf=1e200;
const double eps=1e-8;
const double pi =acos(-1.0);
int sgn(double x){
	if(fabs(x)<eps)return 0;
	return x>0?1:-1;
}
double hypot(double x,double y){return sqrt(x*x+y*y);}
struct Point{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
	bool operator ==(const Point& b){return !sgn(x-b.x)&&!sgn(y-b.y);}
	bool operator  <(const Point& b){return !sgn(x-b.x)?y<b.y:x<b.x;}
	double operator ^(const Point& b){return x*b.y-y*b.x;}//叉积
	double operator *(const Point& b){return x*b.x+y*b.y;}//点积
	Point operator +(const Point &b){return Point(x+b.x,y+b.y);}
	Point operator -(const Point& b){return Point(x-b.x,y-b.y);}
	Point operator *(const double &k){return Point(x*k,y*k);}
	Point operator /(const double &k){return Point(x/k,y/k);}
	double len(){return hypot(x,y);}
	double len2(){return x*x+y*y;}
	double rad(Point a,Point b){Point p=*this;return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p)));}//pa和pb夹角
	double distance(Point b){return hypot(x-b.x,y-b.y);}
	Point trunc(double r){//化为长度为r的向量
		double l=len();
		if(!sgn(l))return *this;
		r/=l;return Point(x*r,y*r);
	}
	Point rotleft(){return Point(-y,x);}//逆时针旋转90 度
	Point rotright(){return Point(y,-x);}//顺时针旋转90 度
	void input(){scanf("%lf%lf",&x,&y);}
	void show(){printf("(%.2lf %.2lf)\n",x,y);}
};
typedef Point Vector;
double angle(Vector A,Vector B){return acos(A*B/A.len()/B.len());}//夹角
Vector Normal(Vector A){//向量A左转90°的单位法向量
	double L=A.len();
	return Vector(-A.y/L,A.x/L);
}
Vector Rotate(Vector A,double rad){//rad为弧度 逆时针旋转
	double c=cos(rad),s=sin(rad);
	return Vector(A.x*c-A.y*s,A.x*s+A.y*c);
}
Point Rotate(Point S,Point O,double rad){//S绕O逆时针旋转后点
	Vector v=Rotate(S-O,rad);
	return Point(O.x+v.x,O.y+v.y);
}
struct Line{
	Point s,e;
	Line(){};
	Line(Point s,Point e):s(s),e(e){};
	Line(Point p,double angle){//根据一个点和倾斜角angle 确定直线0<=angle<pi
		s=p;
		if(sgn(angle-pi/2)==0)e=(s+Point(0,1));
		else e=(s+Point(1,tan(angle)));
	}
	Line(double a,double b,double c){//ax+by+c=0
		if(!sgn(a))s=Point(0,-c/b),e=Point(1,-c/b);
		else if(!sgn(b))s=Point(-c/a,0),e=Point(-c/a,1);
		else s=Point(0,-c/b),e=Point(1,(-c-a)/b);
	}
	void adjust(){swap(s,e);}
	int relation(Point p){//点和直线关系1在左侧 2在右侧 3在直线上
		int c=sgn((p-s)^(e-s));
		if(c<0)return 1;
		if(c>0)return 2;
		return 3;
	}
	bool pointonseg(Point p){//点在线段上的判断
		return !sgn((p-s)^(e-s))&&sgn((p-s)*(p-e))<=0;
	}
	bool parallel(Line v){//两向量平行(对应直线平行或重合)
		return !sgn((e-s)^(v.e-v.s));
	}
	int linecrossline(Line v){//两直线关系//0平行//1重合//2相交
		if((*this).parallel(v))return v.relation(s)==3;
		return 2;
	}
	int linecrossseg(Line v){//直线和线段相交判断//v:seg//2规范相交//1非规范相交//0不相交
		int d1=sgn((e-s)^(v.s-s));
		int d2=sgn((e-s)^(v.e-s));
		if((d1^d2)==-2)return 2;
		return !d1||!d2;
	}
	int segcrossseg(Line v){//两线段相交判断//2规范相交//1非规范相交//0不相交
		int d1=sgn((e-s)^(v.s-s));
		int d2=sgn((e-s)^(v.e-s));
		int d3=sgn((v.e-v.s)^(s-v.s));
		int d4=sgn((v.e-v.s)^(e-v.s));
		if((d1^d2)==-2&&(d3^d4)==-2)return 2;
		return (d1==0&&sgn((v.s-s)*(v.s-e))<=0)||(d2==0&&sgn((v.e-s)*(v.e-e))<=0)
		||(d3==0&&sgn((s-v.s)*(s-v.e))<=0)||(d4==0&&sgn((e-v.s)*(e-v.e))<=0);
	}
	double len(){return s.distance(e);}
	double angle(){//返回直线倾斜角0<=angle<pi
		double k=atan2(e.y-s.y,e.x-s.x);
		if(sgn(k)<0)k+=pi;
		if(!sgn(k-pi))k-=pi;
		return k;
	}
	Point crosspoint(Line v){//求两直线的交点//要保证两直线不平行或重合
		double a1=(v.e-v.s)^(s-v.s);
		double a2=(v.e-v.s)^(e-v.s);
		return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
	}
	double dispointtoline(Point p){return fabs((p-s)^(e-s))/len();}//点到直线的距离
	double dispointtoseg(Point p){//点到线段的距离
		if(sgn((p-s)*(e-s))<0||sgn((p-e)*(s-e))<0)return min(p.distance(s),p.distance(e));
		return dispointtoline(p);
	}
	double dissegtoseg(Line v){//返回线段到线段的距离//前提是两线段不相交,相交距离就是0了
		return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
	}
	Point lineprog(Point p){return s+(((e-s)*((e-s)*(p-s)))/((e-s).len2()));}//返回点p 在直线上的投影
	Point symmetrypoint(Point p){//返回点p关于直线的对称点
		Point q = lineprog(p);
		return Point(2*q.x-p.x,2*q.y-p.y);
	}
	void input(){s.input(),e.input();}
	void show(){s.show(),e.show();}
};
struct circle{
	Point p;//圆心
	double r;//半径
	circle(){}
	circle(Point p,double r):p(p),r(r){}
	//三角形的外接圆//利用两条边的中垂线得到圆心//测试:UVA12304
	circle(Point a,Point b,Point c){
		Line u=Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
		Line v=Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
		p=u.crosspoint(v),r=p.distance(a);
	}//三角形的内切圆//参数bool t 没有作用//测试:UVA12304
	circle(Point a,Point b,Point c,bool t){
		Line u,v;
		double m=atan2(b.y-a.y,b.x-a.x),n=atan2(c.y-a.y,c.x-a.x);
		u.s=a,u.e=u.s+Point(cos((n+m)/2),sin((n+m)/2)),v.s=b;
		m=atan2(a.y-b.y,a.x-b.x),n=atan2(c.y-b.y,c.x-b.x);
		v.e=v.s+Point(cos((n+m)/2),sin((n+m)/2));
		p=u.crosspoint(v),r=Line(a,b).dispointtoseg(p);
	}
	void input(){p.input();scanf("%lf",&r);}
	void show(){printf("(%.6lf,%.6lf,%.6lf)\n",p.x,p.y,r);}
	bool operator==(circle v){return (p==v.p)&&!sgn(r-v.r);}
	bool operator <(circle v){return ((p<v.p)||((p==v.p)&&sgn(r-v.r)<0));}
	double area(){return pi*r*r;}
	double circumference(){return 2*pi*r;}//周长
	int relation(Point b){//点和圆的关系//0 圆外//1 圆上//2 圆内
		double dst=b.distance(p);
		if(sgn(dst-r)<0)return 2;
		else if(!sgn(dst-r))return 1;
		return 0;
	}//线段和圆的关系
	int relationseg(Line v){
		double dst=v.dispointtoseg(p);
		if(sgn(dst-r)<0)return 2;
		else if(!sgn(dst-r))return 1;
		return 0;
	}//直线和圆的关系
	int relationline(Line v){
		double dst=v.dispointtoline(p);
		if(sgn(dst-r)<0)return 2;
		else if(!sgn(dst-r))return 1;
		return 0;
	}//两圆的关系//5 相离//4 外切//3 相交//2 内切//1 内含//测试:UVA12304
	int relationcircle(circle v){
		double d=p.distance(v.p);
		if(sgn(d-r-v.r)>0)return 5;
		if(!sgn(d-r-v.r))return 4;
		double l=fabs(r-v.r);
		if(sgn(d-r-v.r)<0&&sgn(d-l)>0)return 3;
		if(!sgn(d-l))return 2;
		if(sgn(d-l)<0)return 1;
	}//求两个圆的交点,返回0 表示没有交点,返回1 是一个交点2 是两个交点//测试:UVA12304
	int pointcrosscircle(circle v,Point &p1,Point &p2){
		int rel=relationcircle(v);
		if(rel==1||rel==5)return 0;
		double d=p.distance(v.p);
		double l=(d*d+r*r-v.r*v.r)/(2*d);
		double h=sqrt(r*r-l*l);
		Point tmp=p+(v.p-p).trunc(l);
		p1=tmp+((v.p-p).rotleft().trunc(h));
		p2=tmp+((v.p-p).rotright().trunc(h));
		if(rel==2||rel==4)return 1;
		return 2;
	}//求直线和圆的交点,返回交点个数
	int pointcrossline(Line v,Point &p1,Point &p2){
		if(!(*this).relationline(v))return 0;
		Point a=v.lineprog(p);
		double d=v.dispointtoline(p);
		d=sqrt(r*r-d*d);
		if(!sgn(d)){p1=p2=a;return 1;}
		p1=a+(v.e-v.s).trunc(d);
		p2=a-(v.e-v.s).trunc(d);
		return 2;
	}//圆上到点sp的最近点
	Point pointtocircle(Point sp){
		Point u,v;
		double len=sp.distance(p);
		if(len<eps)return p;
		u.x=p.x+r*fabs(p.x-sp.x)/len;
		u.y=p.y+r*fabs(p.y-sp.y)/len*((p.x-sp.x)*(p.y-sp.y)<0?-1:1);
		v.x=p.x-r*fabs(p.x-sp.x)/len;
		v.y=p.y-r*fabs(p.y-sp.y)/len*((p.x-sp.x)*(p.y-sp.y)<0?-1:1);
		return sp.distance(u)<sp.distance(v)?u:v;
	}//得到过a,b两点,半径为r1 的两个圆
	int gercircle(Point a,Point b,double r1,circle &c1,circle &c2){
		circle x(a,r1),y(b,r1);
		int t=x.pointcrosscircle(y,c1.p,c2.p);
		if(!t)return 0;
		c1.r=c2.r=r;
		return t;
	}//得到与直线u 相切,过点q, 半径为r1 的圆//测试:UVA12304
	int getcircle(Line u,Point q,double r1,circle &c1,circle &c2){
		double dis=u.dispointtoline(q);
		if(sgn(dis-r1*2)>0)return 0;
		if(!sgn(dis)){
			c1.p=q+((u.e-u.s).rotleft().trunc(r1));
			c2.p=q+((u.e-u.s).rotright().trunc(r1));
			c1.r=c2.r=r1;return 2;
		}
		Line u1=Line((u.s+(u.e-u.s).rotleft().trunc(r1)),(u.e+(u.e-u.s).rotleft().trunc(r1)));
		Line u2=Line((u.s+(u.e-u.s).rotright().trunc(r1)),(u.e+(u.e-u.s).rotright().trunc(r1)));
		circle cc=circle(q,r1);
		Point p1,p2;
		if(!cc.pointcrossline(u1,p1,p2))cc.pointcrossline(u2,p1,p2);
		c1=circle(p1,r1);
		if(p1==p2){c2=c1;return 1;}
		c2=circle(p2,r1);return 2;
	}//同时与直线u,v 相切,半径为r1 的圆//测试:UVA12304
	int getcircle(Line u,Line v,double r1,circle &c1,circle &c2,circle &c3,circle &c4){
		if(u.parallel(v))return 0;//两直线平行
		Line u1=Line(u.s+(u.e-u.s).rotleft().trunc(r1),u.e+(u.e-u.s).rotleft().trunc(r1));
		Line u2=Line(u.s+(u.e-u.s).rotright().trunc(r1),u.e+(u.e-u.s).rotright().trunc(r1));
		Line v1=Line(v.s+(v.e-v.s).rotleft().trunc(r1),v.e+(v.e-v.s).rotleft().trunc(r1));
		Line v2=Line(v.s+(v.e-v.s).rotright().trunc(r1),v.e+(v.e-v.s).rotright().trunc(r1));
		c1.r=c2.r=c3.r=c4.r=r1;
		c1.p=u1.crosspoint(v1);c2.p=u1.crosspoint(v2);
		c3.p=u2.crosspoint(v1);c4.p=u2.crosspoint(v2);
		return 4;
	}//同时与不相交圆cx,cy 相切,半径为r1 的圆//测试:UVA12304
	int getcircle(circle cx,circle cy,double r1,circle &c1,circle &c2){
		circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
		int t=x.pointcrosscircle(y,c1.p,c2.p);
		if(!t)return 0;
		c1.r=c2.r=r1;return t;
	}//过一点作圆的切线(先判断点和圆的关系)//测试:UVA12304
	int tangentline(Point q,Line &u,Line &v){
		int x=relation(q);
		if(x==2)return 0;
		if(x==1){u=Line(q,q+(q-p).rotleft());v=u;return 1;}
		double d=p.distance(q),l=r*r/d;
		double h=sqrt(r*r-l*l);
		u=Line(q,p+((q-p).trunc(l)+(q-p).rotleft().trunc(h)));
		v=Line(q,p+((q-p).trunc(l)+(q-p).rotright().trunc(h)));
		return 2;
	}//求两圆相交的面积
	double areacircle(circle v){
		int rel=relationcircle(v);
		if(rel>=4)return 0.0;
		if(rel<=2)return min(area(),v.area());
		double d=p.distance(v.p);
		double hf=(r+v.r+d)/2.0;
		double ss=2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d));
		double a1=acos((r*r+d*d-v.r*v.r)/(2.0*r*d));
		a1*=r*r;
		double a2=acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d));
		a2*=v.r*v.r;
		return a1+a2-ss;
	}//求圆和三角形pab 的相交面积//测试:POJ3675 HDU3982 HDU2892
	double areatriangle(Point a,Point b){
		if(!sgn((p-a)^(p-b)))return 0.0;
		Point q[5],p1,p2;
		int len=0;
		q[len++]=a;
		Line l(a,b);
		if(pointcrossline(l,q[1],q[2])==2){
			if(sgn((a-q[1])*(b-q[1]))<0)q[len++]=q[1];
			if(sgn((a-q[2])*(b-q[2]))<0)q[len++]=q[2];
		}q[len++]=b;
		if(len==4&&sgn((q[0]+q[1])*(q[2]-q[1]))>0)swap(q[1],q[2]);
		double res=0;
		for(int i=0;i<len-1;++i){
			if(!relation(q[i])||!relation(q[i+1]))res+=r*r*p.rad(q[i],q[i+1])/2.0;
			else res+=fabs((q[i]-p)^(q[i+1]-p))/2.0;
		}return res;
	}
	int cutpoint(Point sp,Point &rp1,Point &rp2){//求切点,返回切点个数
		Point p2;
		p2.x=(p.x+sp.x)/2.0;
		p2.y=(p.y+sp.y)/2.0;
		double dx2,dy2,r2;
		dx2=p2.x-p.x;
		dy2=p2.y-p.y;
		r2=sqrt(dx2*dx2+dy2*dy2);
		return pointcrosscircle(circle(p2,r2),rp1,rp2);
	}
};
char op[128];
Point a,b,c;
circle e,c1,c2,P[4];
Line s,p;
double r,ans1,ans2;
bool cmp(circle a,circle b){
	return !sgn(a.p.x-b.p.x)?a.p.y<b.p.y:a.p.x<b.p.x;
}
int main(){
	while(~scanf("%s",op)){
		switch(strlen(op)){
		case strlen("CircumscribedCircle"):
			a.input(),b.input(),c.input();
			e=circle(a,b,c);
			e.show();
			break;
		case strlen("InscribedCircle"):
			a.input(),b.input(),c.input();
			e=circle(a,b,c,0);
			e.show();
			break;
		case strlen("TangentLineThroughPoint"):
			e.input(),a.input();
			switch(e.tangentline(a,s,p)){
			case 0:
				puts("[]");
				break;
			case 1:
				printf("[%.6lf]\n",s.angle()*180/pi);
				break;
			default:
				ans1=s.angle()*180/pi,ans2=p.angle()*180/pi;
				if(ans1>ans2)swap(ans1,ans2);
				printf("[%.6lf,%.6lf]\n",ans1,ans2);
				break;
			}
			break;
		case strlen("CircleThroughAPointAndTangentToALineWithRadius"):
			a.input(),s.input(),scanf("%lf",&r);
			switch(e.getcircle(s,a,r,P[0],P[1])){
			case 0:
				puts("[]");
				break;
			case 1:
				printf("[(%.6lf,%.6lf)]\n",P[0].p.x,P[0].p.y);
				break;
			default:
				sort(P,P+2,cmp);
				printf("[(%.6lf,%.6lf),(%.6lf,%.6lf)]\n",P[0].p.x,P[0].p.y,P[1].p.x,P[1].p.y);
				break;
			}
			break;
		case strlen("CircleTangentToTwoLinesWithRadius"):
			s.input(),p.input(),scanf("%lf",&r);
			switch(e.getcircle(s,p,r,P[0],P[1],P[2],P[3])){
			case 0:
				puts("[]");
				break;
			default:
				sort(P,P+4,cmp);
				printf("[(%.6lf,%.6lf),(%.6lf,%.6lf),(%.6lf,%.6lf),(%.6lf,%.6lf)]\n",
				P[0].p.x,P[0].p.y,P[1].p.x,P[1].p.y,P[2].p.x,P[2].p.y,P[3].p.x,P[3].p.y);
				break;
			}
			break;
		case strlen("CircleTangentToTwoDisjointCirclesWithRadius"):
			c1.input(),c2.input(),scanf("%lf",&r);
			switch(e.getcircle(c1,c2,r,P[0],P[1])){
			case 0:
				puts("[]");
				break;
			case 1:
				printf("[(%.6lf,%.6lf)]\n",P[0].p.x,P[0].p.y);
				break;
			default:
				sort(P,P+2,cmp);
				printf("[(%.6lf,%.6lf),(%.6lf,%.6lf)]\n",P[0].p.x,P[0].p.y,P[1].p.x,P[1].p.y);
				break;
			}
			break;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值