HDU - 5572 An Easy Physics Problem(计算几何)

//设入射线的极角方程为x=vx*t+ax,y=vy*t+ay
//圆的方程为(x-ox)^2+(y-oy)^2 = r^2
//联立两个方程组得到(vx^2+vy^2)*t^2+2*((ax-ox)*vx+(ay-oy)*vy)*t+((ax-ox)^2+(ay-oy)^2-r^2) = 0

/*计算几何*/
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;
#define eps 1e-8
double ox,oy,r;
double ax,ay,vx,vy;
double bx,by;

int sgn( double x)
{
if( fabs(x) < eps)
return 0;
if( x > 0)
return 1;
return -1;
}

inline double sqr( double x)
{
return x*x;
}

int main()
{
int T;
scanf("%d",&T);
while( T--)
{
scanf("%lf%lf%lf",&ox,&oy,&r);
scanf("%lf%lf%lf%lf",&ax,&ay,&vx,&vy);
scanf("%lf%lf",&bx,&by);
static int cas = 1;
printf("Case #%d: ",cas++);

//设入射线的极角方程为x=vx*t+ax,y=vy*t+ay
//圆的方程为(x-ox)^2+(y-oy)^2 = r^2
//联立两个方程组得到(vx^2+vy^2)*t^2+2*((ax-ox)*vx+(ay-oy)*vy)*t+((ax-ox)^2+(ay-oy)^2-r^2) = 0
double a = sqr(vx)+sqr(vy);
double b = 2*((ax-ox)*vx+(ay-oy)*vy);
double c = sqr(ax-ox)+sqr(ay-oy)-sqr(r);
//delta大于0,表示有两个根,-b/2a>0(使方程有两个正根)
if( sgn( b*b-4*a*c) > 0 && sgn(b) < 0)
{
double tp = (-b-sqrt(b*b-4*a*c))/(2.0*a);//取较小的根,因为第一个交点肯定距离A点近一点
double px = vx*tp+ax;//入射线与圆的交点
double py = vy*tp+ay;
//判断B是否在入射线上
if( vx != 0)
{
double t = (bx-ax)/vx;
if( sgn(by-vy*t-ay) == 0 && sgn(t-tp) <= 0)
{
puts("Yes");
continue;
}
}
else if( vy != 0)
{
double t = (by-ay)/vy;
if( sgn(bx-vx*t-ax) == 0 && sgn(t-tp) <= 0)
{
puts("Yes");
continue;
}
}
//求切线方程Ax+By+C=0
double A = px-ox;
double B = py-oy;
double C = (ox-px)*px+(oy-py)*py;
//求B点关于法线的反对称点
double cx = bx-2.0*A*(A*bx+B*by+C)/(sqr(A)+sqr(B));
double cy = by-2.0*B*(A*bx+B*by+C)/(sqr(A)+sqr(B));
if( sgn(vx) != 0)
{
double t = (cx-ax)/vx;
if( sgn(cy-vy*t-ay) == 0 && sgn(t) > 0)//>0???
puts("Yes");
else
puts("No");
}
else if( sgn(vy) != 0)
{
double t = (cy-ay)/vy;
if( sgn(cx-vx*t-ax) == 0 && sgn(t) > 0)
puts("Yes");
else
puts("No");
}
}
else//射线
{
if( sgn(vx) != 0)
{
double t = (bx-ax)/vx;
if( sgn(by-vy*t-ay) == 0 && sgn(t) > 0)
puts("Yes");
else
puts("No");
}
else if( sgn(vy) != 0)
{
double t = (by-ay)/vy;
if( sgn(bx-vx*t-ax) == 0 && sgn(t) > 0)
puts("Yes");
else
puts("No");
}
}
}

return 0;
}