题意:
CircumscribedCircle表示计算三角形的外接圆
InscribedCircle表示计算三角形的内切圆
TangentLineThroughPoint给定一个圆和一个点,计算过点的圆的所有切线,输出极角
CircleThroughAPointAndTangentToALineWithRadius计算经过定点,与已知直线相切的圆。
CircleTangentToTwoLinesWithRadius给出两个不平行的直线和圆的半径,求出与直线相切的圆。
CircleTangentToTwoDisjointCirclesWithRadius给出两个相离的圆,求出和这两个圆相切,半径为r的圆。
计算几何的题好坑,我找了一下午的bug
#include "bits/stdc++.h" using namespace std; const int maxn = 100; const double eps=1e-6; const double PI = acos(-1.0); struct Point { double x, y; Point(double x = 0, double y = 0):x(x), y(y) {} void in(void) { scanf("%lf%lf", &x, &y);} void out(void) { printf("%lf %lf", x, y);} }; typedef Point Vector; Point operator + (Point A, Point B) { return Point(A.x+B.x, A.y+B.y); } Point operator - (Point A, Point B) { return Point(A.x-B.x, A.y-B.y); } Point operator * (Point A, double p) { return Point(A.x*p, A.y*p); } Point operator / (Point A, double p) { return Point(A.x/p, A.y/p); } bool operator < (const Point& a, const Point& b) { return a.x<b.x || (a.x==b.x && a.y<b.y); } int dcmp(double x) { if (fabs(x)<eps) return 0;return x<0?-1:1; } bool operator == (const Point& a, const Point &b) { return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y)==0; } struct Line { Point p; //直线上一点 Vector v; //方向向量(半平面交中该向量左侧表示相应的半平面) double ang; //极角,即从x正半轴旋转到向量v所需要的角(弧度) Line() {} //构造函数 Line(const Line& L): p(L.p), v(L.v), ang(L.ang) {} Line(const Point& p,const Vector& v):p(p),v(v){ang=atan2(v.y,v.x);} bool operator < (const Line& L) const { //极角排序 return ang < L.ang; } Point point(double t) {return p+v*t;} void in(void) {p.in(); v.in();} }; struct Circle { Point c; double r; Circle() {} Circle (Point c, double r):c(c), r(r) {} Point point(double a) { return Point(c.x+cos(a)*r, c.y+sin(a)*r); } void inr(void) {scanf("%lf", &r);} void in(void) { c.in(); inr();} void out(void) {c.out(); printf(" %lf ", r);} }; double Dot(Point A, Point B) { return A.x*B.x+A.y*B.y; } //带方向的叉积,cross(x,y)=-cross(y,x) double Cross(Point A, Point B) { return A.x*B.y - A.y*B.x; } double Length(Point A) {return sqrt(Dot(A,A));} //向量之间的夹角 double Angle(Vector A, Vector B) { return acos(Dot(A,B/Length(A)/Length(B))); } Vector Normal(Vector A) {return Vector(-A.y, A.x)/Length(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)); } //直线P+tv和Q+tw的交点(参数方程),要保证有解 Point GetLineIntersection(Line A, Line B) { Vector u = A.p - B.p; double t = Cross(B.v,u)/Cross(A.v,B.v); return A.point(t); } //向量的极角 double angle(Vector v) {return atan2(v.y,v.x);} //点到直线的距离 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); else if(dcmp(Dot(v1,v3))>0) return Length(v3); else return fabs(Cross(v1,v2))/Length(v1); } //点到直线的投影 Point GetLineProjection(Point P,Point A, Point B) { Vector v = B-A; return A+v*(Dot(v,P-A)/Dot(v,v)); } //函数返回的是直线和圆交点的个数,sol中存放的是交点 int GetLineCircleIntersection(Line L,Circle C,vector<Point>& sol) { double t1, t2; 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.0*e*g; //判别式 if (dcmp(delta) < 0) return 0;//相离 if (dcmp(delta) == 0) { //相交 t1=t2=-f/(2.0*e); sol.push_back(L.point(t1)); return 1; } t1=(-f-sqrt(delta))/(2.0*e); sol.push_back(L.point(t1)); t2=(-f+sqrt(delta))/(2.0*e); sol.push_back(L.point(t2)); return 2; } //两个圆相交 int GetCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol) { double d = Length(C1.c-C2.c); if (dcmp(d) == 0) {//两圆重合返回-1 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到C1P1(交点)的角度 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; } //将直线向上平移或向下平移d单位 Line LineTransHor(Line L,int d, int dir) { Point v = Normal(L.v); Point p1 = L.p+v*d, p2=L.p-v*d; return dir? Line(p1,L.v): Line(p2, L.v); } //过点p到圆的切线,v[i]是第i条切线的向量,返回切线的条数 int GetTangentsPointWithCircle(Point P,Circle C, Vector* v) { Vector u = C.c - P; double dist = Length(u); if (dist<C.r) return 0;//P在圆上切线只有一条 else if (dcmp(dist-C.r) == 0) { 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,b表示在圆AB上的切点 int GetTangentsCircleWithCircle(Circle A,Circle B,Point* a,Point* b) { int cnt = 0; if (A.r<B.r) {swap(A,B); swap(b,a);} double d2 = Length(A.c-B.c); d2*=d2; double rdiff = A.r-B.r; double rsum = A.r+B.r;//内含 if (dcmp(d2-rdiff*rdiff) < 0) return 0; double base = atan2(B.c.y-A.c.y, B.c.x-A.c.x); //两圆从重合,无数条 if (dcmp(d2)==0 && dcmp(A.r-B.r)) return -1; if (dcmp(d2-rdiff*rdiff) == 0) {//内切 a[cnt] = A.point(base); b[cnt++]=B.point(base); return 1; } double ang = acos((A.r-B.r)/sqrt(d2)); a[cnt]=A.point(base+ang); b[cnt++]=B.point(base+ang); a[cnt]=A.point(base-ang); b[cnt++]=B.point(base-ang); if (dcmp(d2-rsum*rsum) == 0) { //一条公切线 a[cnt]=A.point(base); b[cnt++]=B.point(base+PI); } else if (dcmp(d2-rsum*rsum)>0) { //两条公切线 double ang2 = acos((A.r+B.r)/sqrt(d2)); a[cnt]=A.point(base+ang2); b[cnt++]=B.point(PI+base+ang2); a[cnt]=A.point(base-ang2); b[cnt++]=B.point(PI+base-ang2); } return cnt; } //三角形外接圆 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)); } //三角形内切圆 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)); } char op[100]; Vector v[100]; double ans[100]; vector<Point> res; int main(int argc, char const *argv[]) { Point A, B, C, D; Circle R1, R2; Line L1, L2; while(scanf("%s", &op) != EOF) { if (strcmp(op, "CircumscribedCircle") == 0) { A.in(), B.in(), C.in(); R1 = CircumscribedCircle(A, B, C); printf("(%.6lf,%.6lf,%.6lf) ", R1.c.x, R1.c.y, R1.r); } else if (strcmp(op, "InscribedCircle") == 0) { A.in(),B.in(), C.in(); R1 = InscribedCircle(A, B, C); printf("(%.6lf,%.6lf,%.6lf) ", R1.c.x, R1.c.y, R1.r); } else if (strcmp(op, "TangentLineThroughPoint") == 0) { R1.in(), A.in(); int len = GetTangentsPointWithCircle(A, R1, v); for (int i = 0; i < len; i++) { ans[i] = angle(v[i]); if (dcmp(ans[i]) < 0) ans[i] += PI; else while (dcmp(ans[i]-PI)>=0) ans[i] -= PI; ans[i] = ans[i]/PI*180.0; } sort(ans, ans+len); printf("["); if (len > 0) printf("%.6lf", ans[0]); for (int i = 1; i < len; i++) { printf(",%.6lf", ans[i]); } printf("] "); } else if (strcmp(op, "CircleThroughAPointAndTangentToALineWithRadius") == 0) { C.in(); A.in(); B.in(); double r; scanf("%lf", &r); R1 = Circle(C, r); Point N = Normal(B-A)*r; Point ta = A+N, tb = B+N;L1 = Line(ta, tb-ta); ta = A-N; tb = B-N; L2 = Line(ta, tb - ta); res.clear(); GetLineCircleIntersection(L1, R1, res); GetLineCircleIntersection(L2, R1, res); sort(res.begin(), res.end()); printf("["); int sz=res.size(); for(int i = 0;i < sz; i++) { if(i) putchar(','); printf("(%.6lf,%.6lf)",res[i].x, res[i].y); } printf("] ");; } else if (strcmp(op, " ") == 0) { A.in(); B.in(); L1 = Line(B, B-A); A.in(); B.in(); L2 = Line(B, B-A); double r; scanf("%lf", &r); Line la1=LineTransHor(L1,r,1),la2=LineTransHor(L1,-r, 1); Line lb1=LineTransHor(L2,r, 1),lb2=LineTransHor(L2,-r, 1); res.clear(); res.push_back(GetLineIntersection(la1,lb1)); res.push_back(GetLineIntersection(la1,lb2)); res.push_back(GetLineIntersection(la2,lb1)); res.push_back(GetLineIntersection(la2,lb2)); sort(res.begin(),res.end()); printf("["); int sz = res.size(); for(int i = 0; i < sz; i++) { if(i) printf(","); printf("(%.6lf,%.6lf)",res[i].x,res[i].y); } printf("] "); } else if (strcmp(op, "CircleTangentToTwoDisjointCirclesWithRadius") == 0) { R1.in(); R2.in(); double r;scanf("%lf", &r); R1.r += r; R2.r += r; res.clear(); GetCircleCircleIntersection(R1,R2,res); sort(res.begin(),res.end()); printf("["); int sz = res.size(); for(int i = 0; i < sz; i++) { if(i) printf(","); printf("(%.6lf,%.6lf)",res[i].x,res[i].y); } printf("] "); } } return 0; }