poj1375 圓的切線

給一個源點s,給一些圓,源點和s相切會形成陰影,求陰影並。


如果能求出所有的圓構成的陰影,sort掃一遍就好了。


怎麼求,我們可以看成是s到圓的切線的直線和x正半軸求交點。

我們可以計算圓心到s的距離,也可以得到那條直線,利用arcsin(r/d)得到一個角度,把直線旋轉這個角度就得到了s和圓的切線(順指針逆時針各得到一條),一段陰影就求到了。


多段陰影拆成進邊和出邊,然後sort掃一遍(類似於掃描線)。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
const int maxn=505;
using namespace std;
struct point
{
	double x,y,r;
	int k;
	point(){}
	point (double _x,double _y)
	{
		x=_x;
		y=_y;
	}
	point operator +(const point &b)
	{
		return point(x+b.x,y+b.y);
	}
	point operator -(const point &b)
	{
		return point(x-b.x,y-b.y);
	}
	point operator *(const double &b)
	{
		return point(x*b,y*b);
	}
	bool operator <(const point &b)const
	{
		return x<b.x;
	}
};
struct line
{
	point a,b;
	line(){}
	line(point _a,point _b)
	{
		a=_a;
		b=_b;
	}
};
double dot(point a,point b)
{
	return a.x*b.x+a.y*b.y;
}
double cross(point a,point b)
{
	return a.x*b.y-a.y*b.x;
}
point rot(point a,double rad){return point(a.x*cos(rad)+a.y*sin(rad),a.y*cos(rad)-a.x*sin(rad));}
double lenth(point a){return sqrt(dot(a,a));}
int n;
point p[maxn];
point S;
line L[maxn];
vector<point>q;
point getsec(point p1,point v1,point p2,point v2)
{
	double x=cross(p2-p1,v2)/cross(v1,v2);
	return v1*x+p1;
}
void work(point a)
{
	point v=a-S;
	double rad=asin(a.r/lenth(v));
	point p1=getsec(point(0,0),point(1,0),S,rot(v,rad));
	point p2=getsec(point(0,0),point(1,0),S,rot(v,-rad));
	p1.k=1,p2.k=-1;
	q.push_back(p1);
	q.push_back(p2);
}
void solve()
{
	sort(q.begin(),q.end());
	int kk=0;
	int i=0;
	while(i<q.size())
	{
		kk+=q[i].k;
		if(kk)
		{
			double st=q[i].x;	
			i++;			
			while(i<q.size())
			{
				kk+=q[i].k;
				if(kk==0)break;
				i++;
			}
			double ft=q[i].x;
			printf("%.2f %.2f\n",st,ft);
		}
		i++;
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF&&n)
	{
		scanf("%lf%lf",&S.x,&S.y);
		q.clear();
		for(int i=1;i<=n;i++)
		{
			scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].r);
			work(p[i]);
		}
		solve();
		printf("\n");
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章