• 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;
    }
  • 相关阅读:
    part11-1 Python图形界面编程(Python GUI库介绍、Tkinter 组件介绍、布局管理器、事件处理)
    part10-3 Python常见模块(正则表达式)
    Cyclic Nacklace HDU
    模拟题 Right turn SCU
    状态DP Doing Homework HDU
    Dp Milking Time POJ
    区间DP Treats for the Cows POJ
    DP Help Jimmy POJ
    Dales and Hills Gym
    Kids and Prizes Gym
  • 原文地址:https://www.cnblogs.com/cniwoq/p/7301469.html
Copyright © 2020-2023  润新知