zoukankan      html  css  js  c++  java
  • 圆的反演变换(HDU4773)

    题意:给出两个相离的圆O1,O2和圆外一点P,求构造这样的圆:同时与两个圆相外切,且经过点P,输出圆的圆心和半径
    分析:画图很容易看出这样的圆要么存在一个,要么存在两个:此题直接解方程是不容易的,先看看反演的定义:已知一圆C,圆心为O,半径为r,如果P与P’在过圆心O的直线上,且,则称P与P'关于O互为反演。
    反演的性质:
    首先设出反演圆心O和反演半径R
    1、圆外一点P与圆内一点P‘会一一对应的反演OP*OP'=R*R
    2、经过O的圆,反演后成为不经过O的一条直线
    3、不经过O的圆,反演后成为另一个圆,且圆心并不对应
    4、不经过O的直线反演后成为一个经过O的圆
    5、过O的直线反演后不变
    具体参考该http://blog.csdn.net/acdreamers/article/details/16966369
    注意:反演中心圆的半径要设大一点,否则会有精度问题

    代码:
    #include"stdio.h"
    #include"string.h"
    #include"stdlib.h"
    #include"queue"
    #include"algorithm"
    #include"string.h"
    #include"string"
    #include"math.h"
    #include"vector"
    #include"stack"
    #include"map"
    #define eps 1e-4
    #define inf 0x3f3f3f3f
    #define M 609
    #define PI acos(-1.0)
    using namespace std;
    struct node//二维点坐标
    {
        double x,y;
        node(){};
        node(double xx,double yy)
        {
            x=xx;
            y=yy;
        }
        node operator+(node b)
        {
            return node(x+b.x,y+b.y);
        }
        node operator-(node b)
        {
            return node(x-b.x,y-b.y);
        }
        node operator*(double b)
        {
            return node(x*b,y*b);
        }
        double operator*(node b)
        {
            return x*b.x+y*b.y;
        }
        double operator^(node b)
        {
            return x*b.y-y*b.x;
        }
    };
    struct Circle//定义圆心和半径
    {
        node center;
        double r;
    }p[M];
    struct Line//定义直线一般式的三个参数ABC
    {
         double A,B,C;
    };
    struct Line2//定义两条直线
    {
        Line s,e;
    };
    double len(node a)//求向量的长度
    {
        return sqrt(a*a);
    }
    double dis(node a,node b)//求两个点的距离
    {
        return len(a-b);
    }
    double cross(node a,node b,node c)//求叉乘
    {
        return (b-a)^(c-a);
    }
    double dot(node a,node b,node c)//求点乘
    {
        return (b-a)*(c-a);
    }
    Circle InverCircle(node p,double R,Circle c)//已知反演中心和反演半径,求圆c的反形圆
    {
        Circle ret;
        double pc=dis(p,c.center);
        ret.r=R*R/2*(1/(pc-c.r)-1/(pc+c.r));
        double pret=R*R/(pc+c.r)+ret.r;
        ret.center.x=p.x+(pret/pc)*(c.center.x-p.x);
        ret.center.y=p.y+(pret/pc)*(c.center.y-p.y);
        return ret;
    }
    node InterPoint(node p,Line L)//过直线外一点与直线L的垂足
    {
        node ret;
        ret.y=(L.A*L.A*p.y-L.A*L.B*p.x-L.B*L.C)/(L.A*L.A+L.B*L.B);
        ret.x=(L.B*L.B*p.x-L.A*L.B*p.y-L.A*L.C)/(L.A*L.A+L.B*L.B);
        return ret;
    }
    Circle InverLine(node p,double R,Line L)//已知不过反演中心的直线,求其反形圆(反形圆过反演中心)
    {
        Circle ret;
        node q=InterPoint(p,L);
        double l1=dis(p,q);
        double l2=R*R/l1;
        ret.r=l2/2;
        ret.center.x=p.x+ret.r/l1*(q.x-p.x);//利用相似三角形求解
        ret.center.y=p.y+ret.r/l1*(q.y-p.y);
        return ret;
    }
    Line line(node a,node b)//已知两个不同的点,求过这两个点的直线
    {
        Line l;
        l.A=b.y-a.y;
        l.B=a.x-b.x;
        l.C=b.x*a.y-a.x*b.y;
        return l;
    }
    double disLL(Line L1,Line L2)//两条平行线间垂直距离
    {
        return fabs(L1.C-L2.C)/sqrt(L1.A*L1.A+L1.B*L1.B);
    }
    double disPL(node p,Line L)//求点到直线的距离
    {
        return fabs(L.A*p.x+L.B*p.y+L.C)/sqrt(L.A*L.A+L.B*L.B);
    }
    node Ratate(node a,double rad)//向量逆时针旋转rad的角度
    {
        return node(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
    }
    Line PointCutCircle(node p,Circle c,int clock)//过圆外一点p且与圆的切线,clock代表两个不同的切线
    {
        Line ret;
        node she;
        she=c.center-p;
        double pc=dis(c.center,p);
        double rad=asin(c.r/pc);
        if(clock==-1)//逆时针旋转
        {
            node she1=Ratate(she,rad);
            ret.A=she1.y;
            ret.B=-she1.x;
            ret.C=she1.x*p.y-p.x*she1.y;
        }
        if(clock==1)//顺时针旋转
        {
            node she1=Ratate(she,-rad);
            ret.A=she1.y;
            ret.B=-she1.x;
            ret.C=she1.x*p.y-p.x*she1.y;
        }
        return ret;
    }
    Line2 CircleCutCircle(Circle O1,Circle O2)//求两个相离的圆的两条外公切线
    {
        Line2 L;
        Line l1,l2,L1;
        if(fabs(O1.r-O2.r)<eps)//当量圆半径相同时
        {
            L1=line(O1.center,O2.center);
            l1.A=L1.A;
            l1.B=L1.B;
            l1.C=L1.C+fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
            l2.A=L1.A;
            l2.B=L1.B;
            l2.C=L1.C-fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
            L.s=l1;
            L.e=l2;
        }
        else//当两个圆的半径不同时
        {
            if(O1.r>O2.r)
                swap(O1,O2);
            Circle O;
            O.center=O2.center;
            O.r=O2.r-O1.r;
            L1=PointCutCircle(O1.center,O,-1);
            l1.A=L1.A;
            l1.B=L1.B;
            l1.C=L1.C+fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
            l2.A=L1.A;
            l2.B=L1.B;
            l2.C=L1.C-fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
            if(fabs(disPL(O1.center,l1)-O1.r)<eps&&fabs(disPL(O2.center,l1)-O2.r)<eps)
                L.s=l1;
            if(fabs(disPL(O1.center,l2)-O1.r)<eps&&fabs(disPL(O2.center,l2)-O2.r)<eps)
                L.s=l2;
            L1=PointCutCircle(O1.center,O,1);
            l1.A=L1.A;
            l1.B=L1.B;
            l1.C=L1.C+fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
            l2.A=L1.A;
            l2.B=L1.B;
            l2.C=L1.C-fabs(O1.r)*sqrt(L1.A*L1.A+L1.B*L1.B);
            if(fabs(disPL(O1.center,l1)-O1.r)<eps&&fabs(disPL(O2.center,l1)-O2.r)<eps)
                L.e=l1;
            if(fabs(disPL(O1.center,l2)-O1.r)<eps&&fabs(disPL(O2.center,l2)-O2.r)<eps)
                L.e=l2;
        }
        return L;
    }
    int main()
    {
        int T,cnt;
        scanf("%d",&T);
        while(T--)
        {
            Circle C1,C2,C3,C4,C,ans[4];
            Line2 L;
            node P;
            scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&C1.center.x,&C1.center.y,&C1.r,&C2.center.x,&C2.center.y,&C2.r,&P.x,&P.y);
            C3=InverCircle(P,30.0,C1);
            C4=InverCircle(P,30.0,C2);
            L=CircleCutCircle(C3,C4);
    
            cnt=0;
            C=InverLine(P,30.0,L.s);
            if(fabs(dis(C.center,C1.center)-C1.r-C.r)<eps&&fabs(dis(C.center,C2.center)-C2.r-C.r)<eps)
                ans[cnt++]=C;
    
            C=InverLine(P,30.0,L.e);
            if(fabs(dis(C.center,C1.center)-C1.r-C.r)<eps&&fabs(dis(C.center,C2.center)-C2.r-C.r)<eps)
                ans[cnt++]=C;
    
            printf("%d
    ",cnt);
            for(int i=0;i<cnt;i++)
                printf("%.8lf %.8lf %.8lf
    ",ans[i].center.x,ans[i].center.y,ans[i].r);
        }
    }
    


  • 相关阅读:
    Json对象与Json字符串互转(4种转换方式)
    Web.config配置文件详解
    jQuery BlockUI Plugin Demo 6(Options)
    jQuery BlockUI Plugin Demo 5(Simple Modal Dialog Example)
    jQuery BlockUI Plugin Demo 4(Element Blocking Examples)
    jQuery BlockUI Plugin Demo 3(Page Blocking Examples)
    jQuery BlockUI Plugin Demo 2
    <configSections> 位置引起的错误
    关于jQuery的cookies插件2.2.0版设置过期时间的说明
    jQuery插件—获取URL参数
  • 原文地址:https://www.cnblogs.com/mypsq/p/4348115.html
Copyright © 2011-2022 走看看