POJ 1375 圆切线

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 5E2 + 10;
struct Point
{
	double x, y;
	Point(double x = 0, double y = 0): x(x), y(y) {}
};
typedef Point Vector;
//typedef vector<Point> Polygon;
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.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);
}
bool operator <(const Point &a, const Point &b)//有修改
{
	return a.x < b.x;
}
const double eps = 1e-10;
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.y - b.y) == 0;
}
double Dot(Vector A, Vector B)//
{
	return A.x * B.x + A.y * B.y;
}
double Length(Vector A)//
{
	return sqrt(Dot(A, A));
}
double Cross(Vector A, Vector B)//
{
	return A.x * B.y - A.y * B.x;
}
Vector Rotate(Vector A, double rad) //
{
	return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad));
}
struct Line
{
	Point P;
	Vector v;
	double ang;
	Line() {};
	Line(Point P, Vector v): P(P), v(v) {ang = atan2(v.y, v.x);}
	bool operator < (const Line& L) const
	{
		return ang < L.ang;
	}
};
Point GetLineIntersection(const Line &A, const Line &B) //
{
	Vector u = A.P - B.P;
	double t = Cross(B.v, u) / Cross(A.v, B.v);
	return A.P + A.v * t;
}
struct Circle
{
	Point c;
	double r;
	Circle(Point c = 0, double r = 0): c(c), r(r) {}
	Point point(double a)
	{
		return Point(c.x + cos(a) * r, c.y + sin(a) * r);
	}
};
//过点作圆形的切线
int getTangents(Point p, Circle C, Vector *v)
{
	Vector u = C.c - p;
	double dist = Length(u);
	if (dist < C.r) return 0;
	else if (dcmp(dist - C.r) == 0)
	{
		v[0] = Rotate(u, PI / 2);
		return 1;
	}
	else
	{
		double ang = asin(C.r / dist);
		v[0] = Rotate(u, -ang);
		v[1] = Rotate(u, +ang);
		return 2;
	}
}
Point read_point()
{
	double X, Y;
	scanf("%lf%lf", &X, &Y);
	return Point(X, Y);
}
int n;
double R;
Point P, A[maxn];
Circle C[maxn];
int main(int argc, char const *argv[])
{
	while (~scanf("%d", &n) && n)
	{
		Point P = read_point();
		for (int i = 0; i < n; i++)
		{
			Point t = read_point();
			scanf("%lf", &R);
			C[i] = Circle(t, R);
		}
		Line L = Line(Point(0, 0), Point(1, 0) - Point(0, 0));
		for (int i = 0; i < n; i++)
		{
			Vector V[2];
			int m = getTangents(P, C[i], V);
			Line L1 = Line(P, V[0]), L2 = Line(P, V[1]);
			Point p1 = GetLineIntersection(L, L1), p2 = GetLineIntersection(L, L2);
			if (p2 < p1) swap(p1, p2);
			A[i].x = p1.x, A[i].y = p2.x;
		}
		sort(A, A + n);
		A[n].x = INF, A[n].y = INF;
		double left = A[0].x , right = A[0].y;
		for (int i = 1; i <= n; i++)
		{
			if (A[i].x > right)
			{
				printf("%.2lf %.2lf\n", left, right);
				left = A[i].x, right = A[i].y;
			}
			if (A[i].y > right) right = A[i].y;
		}
		printf("\n");
	}
	return 0;
}


要注意好点的覆盖问题,只有断开时才要输出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值