• UVA-10674 Tangents(求圆和圆的切线)(计算几何)


    题意:求圆和圆的切线,并将每根直线按在第一个圆的切点排序。

    分析:排序可以使用冒泡,记住比较大小的时候要处理精度问题

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    const double eps = 1e-8;
    const double PI = acos(-1.0);
    struct Point
    {
    	double x, y;
    	Point(double x = 0, double y = 0) : x(x), y(y){}
    };
    
    typedef Point Vector;
    
    Vector operator+(Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
    Vector operator-(Point A, Point B) { return Vector(A.x - B.x, A.y - B.x); }
    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); }
    
    double Dot(Vector A, Vector B)
    {
    	return A.x * B.x + A.y + B.y;
    }
    
    double Length(Vector A)
    {
    	return sqrt(Dot(A, A));
    }
    
    Vector Normal(Vector A)
    {
    	double L = Length(A);
    	return Vector(-A.y / L, A.x / L);
    }
    
    double dist(Point a, Point b)
    {
    	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    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;
    }
    
    struct Circle
    {
    	Point c;
    	double r;
    	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);
    	}
    };
    
    struct Line
    {
    	Point p;
    	Vector v;
    	Line(Point p, Vector v):p(p),v(v){}
    	Point point(double t)
    	{
    		return p + v * t;
    	}
    	Line move(double d)
    	{
    		return Line(p + Normal(v) * d, v);
    	}
    };
    
    int getTangents(Circle A, Circle B, Point* a, Point* b)
    {
    	//存储切点
    	int cnt = 0;
    	if (dcmp(A.r - B.r) < 0) { swap(A, B); swap(a, b); }
    	double d2 = (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 (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) == 0) return -1;
    	//内切,一条切线
    	if (dcmp(d2 - rdiff * rdiff) == 0)
    	{
    		a[cnt] = A.point(base); b[cnt] = B.point(base); ++cnt;
    		return 1;
    	}
    	//有外公切线
    	double ang = acos((A.r - B.r) / sqrt(d2));
    	a[cnt] = A.point(base + ang); b[cnt] = B.point(base + ang); ++cnt;
    	a[cnt] = A.point(base - ang); b[cnt] = B.point(base - ang); ++cnt;
    	if (dcmp(d2 - rsum * rsum) == 0)
    	{
    		a[cnt] = A.point(base); b[cnt] = B.point(PI + base); ++cnt;
    	}
    	else if (dcmp(d2 - rsum * rsum) > 0)
    	{
    		double ang = acos((A.r + B.r) / sqrt(d2));
    		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 check(Circle A)
    {
    	if (A.c.x == 0 && A.c.y == 0 && A.r == 0)
    		return 1;
    	return 0;
    }
    
    int main()
    {
    	double x1, y1, r1, x2, y2, r2;
    	while (scanf("%lf%lf%lf%lf%lf%lf", &x1, &y1, &r1, &x2, &y2, &r2) != EOF)
    	{
    		Circle A(Point(x1, y1), r1);
    		Circle B(Point(x2, y2), r2);
    
    		if (check(A) && check(B)) break;
    
    		Point a[10], b[10];
    
    		int res = getTangents(A, B, a, b);
    		if (res == -1)
    		{
    			puts("-1");
    			continue;
    		}
    
    		printf("%d
    ", res);
    
    		//冒泡
    		for (int i = 0; i < res; ++i)
    		{
    			for (int j = res - 1; j > i; --j)
    			{
    				if (a[j] < a[j - 1])
    				{
    					swap(a[j - 1], a[j]);
    					swap(b[j - 1], b[j]);
    				}
    			}
    		}
    
    		for (int i = 0; i < res; ++i)
    		{
    			printf("%.5lf %.5lf %.5lf %.5lf %.5lf
    ", a[i].x, a[i].y, b[i].x, b[i].y, dist(a[i], b[i]));
    		}
    	}
    
    
    
    	return 0;
    }
    
  • 相关阅读:
    17 电话号码的字母组合(LeetCode HOT 100)
    11 盛最多水的容器(LeetCode HOT 100)
    20 有效的括号(LeetCode HOT 100)
    22 括号生成(LeetCode HOT 100)
    31 下一个排列(LeetCode HOT 100)
    20191324网络对抗EXP2后门原理与实践
    20191324《网络对抗》Exp3免杀原理与实践
    20191324hash碰撞实例
    Golang 可以运行 但是 github 包标红
    Redishash基本使用
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13272964.html
Copyright © 2020-2023  润新知