• 两个圆的切线与切点


    两个圆的切线与切点
    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);
    	}
    
    }
    
  • 相关阅读:
    Python文件基础
    Python字符串基础操作
    Python ===if while for语句 以及一个小小网络爬虫实例
    Python 常用函数大体分类
    Atlas安装及配置
    (转)VS无法启动调试:“生成下面的模块时,启用了优化或没有调试信息“
    (转)数据库中视图的作用
    (转)ASP.NET MVC 学习第一天
    (转)介绍几个C#正则表达式工具
    关于textbox.attributes["value"]的问题
  • 原文地址:https://www.cnblogs.com/LaiYiC/p/15287720.html
Copyright © 2020-2023  润新知