计算几何中的圆与圆相切和圆与直线相切

来源:互联网 发布:甘肃 预约挂号软件 编辑:程序博客网 时间:2024/05/24 07:20

定义常用点,圆,向量的运算:


const double eps = 1e-9;const double PI = acos(-1.0);const int MAXN = 60;struct Point {    double x, y;    int id;    //点标号,标记是否在同一个圆上    Point() { }    Point( double x, double y ):x(x), y(y) { }    Point( double x, double y, int id ):x(x), y(y), id(id) { }    void readPoint() {        scanf( "%lf%lf", &x, &y );        return;    }};int dcmp( double x );struct Circle {    Point c;   //圆心坐标    double r;  //半径    Circle() {}    Circle( Point c, double r ): c(c), r(r) {}    Point getPoint( double theta ) { //根据极角返回圆上一点的坐标        double co=cos(theta)*r;        double si=sin(theta)*r;        if(fabs(co-0.0)<=eps) co=0.0;        if(fabs(si-0.0)<=eps) si=0.0;        return Point( c.x + co, c.y + si );    }    void readCircle() {        scanf("%lf%lf%lf", &c.x, &c.y, &r );        return;    }};typedef Point Vector;Vector operator+( Vector A, Vector B ) {     //向量加    return Vector( A.x + B.x, A.y + B.y );}Vector operator-( Vector A, Vector B ) {     //向量减    return Vector( A.x - B.x, A.y - B.y );}Vector operator*( Vector A, double p ) {    //向量数乘    return Vector( A.x * p, A.y * p );}Vector operator/( Vector A, double p ) {    //向量数除    return Vector( A.x / p, A.y / p );}int dcmp( double x ) {  //控制精度    if ( fabs(x) < eps ) return 0;    else return x < 0 ? -1 : 1;}bool operator<( const Point& A, const Point& B ) { //两点比较    return dcmp( A.x - B.x) < 0 || ( dcmp(A.x - B.x ) == 0 && dcmp( A.y - B.y ) < 0 );}bool operator>( const Point& A, const Point& B ) { //两点比较    return dcmp( A.x - B.x) > 0 || ( dcmp(A.x - B.x ) == 0 && dcmp( A.y - B.y ) > 0 );}bool operator==( const Point& a, const Point& b ) { //两点相等    return dcmp( a.x - b.x ) == 0 && dcmp( a.y - b.y ) == 0;}double Cross( Vector A, Vector B ) { //向量叉积    return A.x * B.y - A.y * B.x;}double PointDis( Point a, Point b ) { //两点距离的平方    return (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y);}


线与圆相切:


//过定点做圆的切线,得到切点,返回切点个数//tps保存切点坐标int getTangentPoints( Point p, Circle C, Point *tps ) {    int cnt = 0;    double dis = sqrt( PointDis( p, C.c ) );    int aa = dcmp( dis - C.r );    if ( aa < 0 ) return 0;  //点在圆内    else if ( aa == 0 ) { //点在圆上,该点就是切点        tps[cnt] = p;        ++cnt;        return cnt;    }    //点在圆外,有两个切点    double base = atan2( p.y - C.c.y, p.x - C.c.x );    double ang = acos( C.r / dis );    tps[cnt] = C.getPoint( base - ang ), ++cnt;    tps[cnt] = C.getPoint( base + ang ), ++cnt;    return cnt;}



圆与圆相切:


//求两圆"外公切线切点",返回切线个数//p是圆c2在圆c1上的切点,要求c1在c2的切点翻过来就求得int makeCircle( Circle c1, Circle c2, Point *p ) {    int cnt = 0;    double d = sqrt( PointDis(c1.c, c2.c) ), dr = c1.r - c2.r;    double b = acos(dr / d);    double a = atan2( c2.c.y - c1.c.y, c2.c.x - c1.c.x );    double a1 = a - b, a2 = a + b;    double aa,bb,cc,dd;    aa=cos(a1);    bb=sin(a1);    cc=cos(a2);    dd=sin(a2);    if(fabs(aa-0)<=eps) aa=0.0;    if(fabs(bb-0)<=eps) bb=0.0;    if(fabs(cc-0)<=eps) cc=0.0;    if(fabs(dd-0)<=eps) dd=0.0;    p[cnt++] = Point( aa * c1.r, bb * c1.r)+c1.c;//切点的坐标    p[cnt++] = Point( cc * c1.r, dd * c1.r)+c1.c;//切点的坐标    return cnt;}



0 0