给一个源点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;
}