• 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;
    }
  • 相关阅读:
    各个download文件说明
    网页中播放FLV文件的代码
    关于外部样式表中backgroundimage:url()的设置
    C# VS 2010创建、安装、调试 windows服务(windows service)
    HttpUtility.UrlEncode,Server.UrlEncode 的区别
    关于Coolite(EXT)问题之一
    Trace 日志文件
    document对象
    让IE6/IE7/IE8浏览器支持CSS3属性特效
    自定义URL Protocol Handler 呼出应用程序
  • 原文地址:https://www.cnblogs.com/cniwoq/p/7301469.html
Copyright © 2020-2023  润新知