zoukankan      html  css  js  c++  java
  • 两个圆的切线与切点

    两个圆的切线与切点
    https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_G

    int sgn(double x) {
    	if(fabs(x)<eps)return 0;
    	return x<0?-1:1;
    }
    struct Point { //定义点和基本运算
    	double x,y;
    	double ang;
    	Point() {}
    	Point(double x,double y):x(x),y(y) {}
    	Point operator + (Point B) {
    		return Point(x+B.x,y+B.y);
    	}
    	Point operator - (Point B) {
    		return Point(x-B.x,y-B.y);
    	}
    	Point operator * (double k) {
    		return Point(x*k,y*k);   //长度增大k倍
    	}
    	Point operator / (double k) {
    		return Point(x/k,y/k);   //长度缩小k倍
    	}
    	bool operator == (Point B) {
    		return sgn(x-B.x)==0 && sgn(y-B.y)==0;
    	}
    	double operator ^(Point B) {
    		return x*B.y-y*B.x;
    	}
    	double distance(Point p) {
    		return hypot(x-p.x,y-p.y);
    	}
    };
    
    typedef Point Vector;
    double Cross(Vector A,Vector B) {
    	return A.x*B.y - A.y*B.x;   //叉积
    }
    
    struct Line {
    	Point p1,p2;//线上的两个点
    	Line() {}
    	Line(Point p1,Point p2):p1(p1),p2(p2) {}
    };
    
    struct Circle {
    	Point c;//圆心
    	double r;//半径
    	Circle() {}
    	Circle(Point c,double r):c(c),r(r) {}
    	Circle(double x,double y,double _r) {
    		c=Point(x,y);
    		r = _r;
    	}
    	Point point(double ang) { //圆上与圆心极坐标为ang的点-----------------
    		return Point(c.x+cos(ang)*r,c.y+sin(ang)*r);
    	}
    };
    //0,-1:没有切线 a[]是c1上的切点,b[]是c2
    int getTangents(Circle A, Circle B, Point *a, Point *b) {
    	int cnt = 0;        //存切点用
    	if(sgn(A.r - B.r) < 0) {
    		swap(A, B);
    		swap(a, b);
    	}
    	double d = sqrt((A.c.x - B.c.x) * (A.c.x - B.c.x) + (A.c.y - B.c.y) * (A.c.y - B.c.y));     //圆心距
    	double rdiff = A.r - B.r;      //两圆半径差
    	double rsum = A.r + B.r;       //两圆半径和
    	if(sgn(d - rdiff) < 0) return 0;        //1.内含
    	double base = atan2(B.c.y - A.c.y, B.c.x - A.c.x);      //向量AB的极角
    	if(sgn(d) == 0) return -1;        //2.重合
    	if(sgn(d - rdiff) == 0) {      //3.内切
    		a[cnt] = b[cnt] = A.point(base);
    		cnt++;
    		return 1;
    	}
    	double ang = acos((A.r - B.r) / d);
    	a[cnt] = A.point(base + ang);
    	b[cnt] = B.point(base + ang);
    	cnt++;      //4.相交(外切、外离的外公切线也在此求出)
    	a[cnt] = A.point(base - ang);
    	b[cnt] = B.point(base - ang);
    	cnt++;      //两条外公切线的切点
    	if(sgn(d - rsum) == 0) {       //5.外切
    		a[cnt] = b[cnt] = A.point(base);
    		cnt++;
    	} else if(sgn(d - rsum) > 0) {   //6.外离
    		double ang = acos((A.r + B.r) / d);
    		a[cnt] = A.point(base + ang);
    		b[cnt] = B.point(PI + base + ang);
    		cnt++;
    		a[cnt] = A.point(base - ang);
    		b[cnt] = B.point(PI + base - ang);
    		cnt++;
    	}
    	return cnt;
    
    }
    
    bool cmp(Point a,Point b) {
    	if(sgn(a.x-b.x)!=0)return a.x < b.x;
    	else if(sgn(a.x-b.x)==0)return a.y < b.y;
    }
    
    void work() {
    	Circle a,b;
    	scanf("%lf%lf%lf",&a.c.x,&a.c.y,&a.r);
    	scanf("%lf%lf%lf",&b.c.x,&b.c.y,&b.r);
    	Point p1[5],p2[5];
    	int cnt = getTangents(a,b,p1,p2);
    //	cout << cnt << endl;
    	if(cnt == -1 ||cnt==0)return ;
    	vector<Point>ans;
    	for(int i=0; i<cnt; i++) {
    		ans.push_back(p1[i]);
    	}
    	sort(ans.begin(),ans.end(),cmp);
    	for(int i=0; i<cnt; i++) {
    		printf("%.10f %.10f
    ",ans[i].x,ans[i].y);
    	}
    
    }
    
  • 相关阅读:
    Why Visual Studio Team System Isn't A LoadRunner Killer[转载]
    从键盘判断电脑主人
    LoadRunner中添加weblogic监视器(JMX)
    winrunner事务概念的代码应用(毫秒级)
    Delphi中的线程类
    换工作时如何提高自身的待遇(转贴)
    牛人是怎样用函数实现本地化测试的
    肯德基的见闻
    由 12306.cn 谈谈网站性能技术
    20个优秀的 CSS 网格系统(CSS Grid Systems)推荐
  • 原文地址:https://www.cnblogs.com/LaiYiC/p/15287720.html
Copyright © 2011-2022 走看看