UVa 123042D Geometry 110 in 1! [平面几何]

2D Geometry 110 in 1!

题意:

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;
}
原文地址:https://www.cnblogs.com/cniwoq/p/7301469.html