UVA12304 2D Geometry 110 in 1!

题意

PDF

分析

三角形的外接圆

维基百科上给出了计算公式,可以解方程推。

三角形的内切圆

维基百科上也给出了现成的公式,照样是可以推的。

后三个操作

都可以转化为直线、圆之间的交点问题。

时间复杂度\(O(T)\)

精度问题

对于第四个操作,如果不改现有的代码,精度必须调整至\(10^{-6}\)

要改的话可以特判直线与圆相切,求出对精确度要求很高的那个点。

代码

这大概是我写过的除数据结构题之外最长的代码了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>T read(T&x)
{
    return x=read<T>();
}
using namespace std;
typedef long long ll;

co double eps=1e-6;
int dcmp(double x)
{
    if(fabs(x)<eps)
        return 0;
    else
        return x<0?-1:1;
}

struct Point
{
    double x,y;
    
    Point(double x=0,double y=0)
    :x(x),y(y){}
    
    bool operator<(co Point&rhs)co // edit 1
    {
        return dcmp(x-rhs.x)?x<rhs.x:y<rhs.y;
    }
    
    bool operator==(co Point&rhs)co
    {
        return dcmp(x-rhs.x)==0&&dcmp(y-rhs.y)==0;
    }
    
    double angle()
    {
        return atan2(y,x);
    }
};
typedef Point Vector;

Vector operator+(Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}

Vector operator-(Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}

Vector operator*(Vector A,double p) 
{
    return Vector(A.x*p,A.y*p);
}

Vector operator/(Vector A,double p)
{
    return Vector(A.x/p,A.y/p);
}

double Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}

double Length(Vector A)
{
    return sqrt(Dot(A,A));
}

double Angle(Vector A,Vector B)
{
    return acos(Dot(A,B)/Length(A)/Length(B));
}

double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}

double Area2(Point A,Point B,Point C)
{
    return Cross(B-A,C-A);
}

Vector Rotate(Vector A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}

Vector Normal(Vector A)
{
    double L=Length(A);
    return Vector(-A.y/L,A.x/L);
}

Point LineLineIntersection(Point P,Vector v,Point Q,Vector w)
{
    Vector u=P-Q;
    double t=Cross(w,u)/Cross(v,w);
    return P+v*t;
}

double DistanceToLine(Point P,Point A,Point B)
{
    Vector v1=B-A,v2=P-A;
    return fabs(Cross(v1,v2))/Length(v1);
}

double DistanceToSegment(Point P,Point A,Point B)
{
    if(A==B)
        return Length(P-A);
    Vector v1=B-A,v2=P-A,v3=P-B;
    if(dcmp(Dot(v1,v2))<0)
        return Length(v2);
    if(dcmp(Dot(v1,v3))>0)
        return Length(v3);
    return DistanceToLine(P,A,B);
}

Point PointLineProjection(Point P,Point A,Point B)
{
    Vector v=B-A;
    return A+v*(Dot(v,P-A)/Dot(v,v));
}

bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),
            c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
}

bool OnSegment(Point p,Point a1,Point a2)
{
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}

double PolygonArea(Point*p,int n)
{
    double area=0;
    for(int i=1;i<n-1;++i)
        area+=Cross(p[i]-p[0],p[i+1]-p[0]);
    return area/2;
}

struct Line
{
    Point p;
    Vector v;
    
    Line(Point p=0,Vector v=0)
    :p(p),v(v){}
    
    Line(double x1,double y1,double x2,double y2)
    {
    	Point p1(x1,y1);
    	Point p2(x2,y2);
    	p=p1;
    	v=p2-p1;
	}
    
    Point point(double t)
    {
        return p+v*t;
    }
    
    Line move(double d)
    {
    	return Line(p+Normal(v)*d,v);
	}
};

struct Circle
{
    Point c;
    double r;
    
    Circle(Point c=0,double r=0)
    :c(c),r(r){}
    
    Point point(double a)
    {
        return Point(c.x+cos(a)*r,c.y+sin(a)*r);
    }
};

int LineCircleIntersection(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);
    t2=(-f+sqrt(delta))/(2*e);
    sol.push_back(L.point(t1));
    sol.push_back(L.point(t2));
    return 2;
}

int CircleCircleIntersection(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=(C2.c-C1.c).angle();
    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;
}

co double PI=acos(-1);

int PointCircleTangent(Point p,Circle C,vector<Vector>&sol)
{
    Vector u=C.c-p;
    double dist=Length(u);
    if(dcmp(dist-C.r)<0)
        return 0;
    if(dcmp(dist-C.r)==0)
    {
        sol.push_back(Rotate(u,PI/2));
        return 1;
    }
    double ang=asin(C.r/dist);
    sol.push_back(Rotate(u,-ang));
    sol.push_back(Rotate(u,ang));
    return 2;
}

int CircleCircleTangent(Circle A,Circle B,vector<pair<Point,Point> >&sol)
{
    int cnt=0;
    if(dcmp(A.r-B.r)<0) // notice the result here
        swap(A,B);
    double d=Length(A.c-B.c);
    double rdiff=A.r-B.r;
    double rsum=A.r+B.r;
    if(dcmp(d-rdiff)<0)
        return 0;
    
    double base=(B.c-A.c).angle();
    if(dcmp(d)==0&&dcmp(A.r-B.r)==0)
        return -1;
    if(dcmp(d-rdiff)==0)
    {
        sol.push_back(make_pair(A.point(base),B.point(base)));
        ++cnt;
        return 1;
    }
    
    double ang=acos((A.r-B.r)/d);
    sol.push_back(make_pair(A.point(base+ang),B.point(base+ang)));
    ++cnt;
    sol.push_back(make_pair(A.point(base-ang),B.point(base-ang)));
    ++cnt;
    if(dcmp(d-rsum)==0)
    {
        sol.push_back(make_pair(A.point(base),B.point(base+PI)));
        ++cnt;
    }
    else if(dcmp(d-rsum)>0)
    {
        double ang=acos((A.r+B.r)/d);
        sol.push_back(make_pair(A.point(base+ang),B.point(base+ang+PI)));
        ++cnt;
        sol.push_back(make_pair(A.point(base-ang),B.point(base-ang+PI)));
        ++cnt;
    }
    return cnt;
}

// Problem 1
Circle CircumscribedCircle(Point p1,Point p2,Point p3)
{
	double Bx=p2.x-p1.x,By=p2.y-p1.y;
	double Cx=p3.x-p1.x,Cy=p3.y-p1.y;
	double D=2*(Bx*Cy-By*Cx);
	double cx=(Cy*(Bx*Bx+By*By)-By*(Cx*Cx+Cy*Cy))/D+p1.x;
	double cy=(Bx*(Cx*Cx+Cy*Cy)-Cx*(Bx*Bx+By*By))/D+p1.y;
	Point p=Point(cx,cy);
	return Circle(p,Length(p1-p));
}

// Problem 2
Circle InscribedCircle(Point p1,Point p2,Point p3)
{
	double a=Length(p2-p3);
	double b=Length(p3-p1);
	double c=Length(p1-p2);
	Point p=(p1*a+p2*b+p3*c)/(a+b+c);
	return Circle(p,DistanceToLine(p,p1,p2));
}

// Problem 3
// PointCircleTangent()

// Problem 4
vector<Point> CircleThroughPointTangentToLine(Point p,Line L,double r)
{ // require precision to be adjusted to 1e-6 here
	vector<Point>ans;
	double t1,t2;
	LineCircleIntersection(L.move(-r),Circle(p,r),t1,t2,ans);
	LineCircleIntersection(L.move(r),Circle(p,r),t1,t2,ans);
	return ans;
}

// Problem 5
vector<Point> CircleTangentToLine(Line a,Line b,double r)
{
	vector<Point>ans;
	Line L1=a.move(-r),L2=a.move(r);
	Line L3=b.move(-r),L4=b.move(r);
	ans.push_back(LineLineIntersection(L1.p,L1.v,L3.p,L3.v));
	ans.push_back(LineLineIntersection(L1.p,L1.v,L4.p,L4.v));
	ans.push_back(LineLineIntersection(L2.p,L2.v,L3.p,L3.v));
	ans.push_back(LineLineIntersection(L2.p,L2.v,L4.p,L4.v));
	return ans;
}

// Problem 6
vector<Point> CircleTangentToCircle(Circle c1,Circle c2,double r)
{
	vector<Point>ans;
	Vector v=c2.c-c1.c;
	double dist=Length(v);
	if(dcmp(dist-c1.r-c2.r-r*2)>0)
		return ans;
	CircleCircleIntersection(Circle(c1.c,c1.r+r),Circle(c2.c,c2.r+r),ans);
	return ans;
}

// Format
double LineAngleDegree(Vector v)
{
	double ang=v.angle()*180/PI;
	while(dcmp(ang)<0)
		ang+=360;
	while(dcmp(ang-180)>=0)
		ang-=180;
	return ang;
}

void format(Circle c)
{
	printf("(%lf,%lf,%lf)\n",c.c.x,c.c.y,c.r);
}

void format(vector<double> ans)
{
	int n=ans.size();
	sort(ans.begin(),ans.end());
	printf("[");
	if(n)
	{
		printf("%lf",ans[0]);
		for(int i=1;i<n;++i)
			printf(",%lf",ans[i]);
	}
	printf("]\n");
}

void format(vector<Point> ans)
{
	int n=ans.size();
	sort(ans.begin(),ans.end());
	printf("[");
	if(n)
	{
		printf("(%lf,%lf)",ans[0].x,ans[0].y);
		for(int i=1;i<n;++i)
			printf(",(%lf,%lf)",ans[i].x,ans[i].y);
	}
	printf("]\n");
}

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
	string cmd;
	double x1,y1,x2,y2,x3,y3,x4,y4,xp,yp,xc,yc,r1,r2,r;
	while(cin>>cmd)
	{
		if(cmd=="CircumscribedCircle")
		{
			cin>>x1>>y1>>x2>>y2>>x3>>y3;
			format(CircumscribedCircle(Point(x1,y1),Point(x2,y2),Point(x3,y3)));
		}
		else if(cmd=="InscribedCircle")
		{
			cin>>x1>>y1>>x2>>y2>>x3>>y3;
			format(InscribedCircle(Point(x1,y1),Point(x2,y2),Point(x3,y3)));
		}
		else if(cmd=="TangentLineThroughPoint")
		{
			cin>>xc>>yc>>r>>xp>>yp;
			vector<Vector>sol;
			vector<double>ans;
			int cnt=PointCircleTangent(Point(xp,yp),Circle(Point(xc,yc),r),sol);
			for(int i=0;i<cnt;++i)
				ans.push_back(LineAngleDegree(sol[i]));
			format(ans);
		}
// CircleThroughAPointAndTangentToALineWithRadius 75 190 75 190 185 65 100
		else if(cmd=="CircleThroughAPointAndTangentToALineWithRadius")
		{
			cin>>xp>>yp>>x1>>y1>>x2>>y2>>r;
			format(CircleThroughPointTangentToLine(Point(xp,yp),Line(x1,y1,x2,y2),r));
		}
		else if(cmd=="CircleTangentToTwoLinesWithRadius")
		{
			cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4>>r;
			format(CircleTangentToLine(Line(x1,y1,x2,y2),Line(x3,y3,x4,y4),r));
		}
		else if(cmd=="CircleTangentToTwoDisjointCirclesWithRadius")
		{
			cin>>x1>>y1>>r1>>x2>>y2>>r2>>r;
			format(CircleTangentToCircle(Circle(Point(x1,y1),r1),Circle(Point(x2,y2),r2),r));
		}
	}
    return 0;
}

posted on 2018-12-19 14:02  autoint  阅读(174)  评论(0编辑  收藏  举报

导航