Question: A point A(ax,ay) moves along a certain direction (vx,vy). There is a circle whose center is O(ox,oy) radius is r. If a point collides with a circle, it will rebound without energy loss. Can it pass through point B(bx,by)?
Analysis: When you get the title, you think of two situations: one is not hitting the circle; the other is hitting the circle.
In the case of no collision with the circle, just judge whether point B will pass in the process of going down.
If it hits a circle, it depends on whether it will pass through B before it hits the circle. If it doesn't, it depends on whether it will pass through B after rebound.
// Let the polar angle equation of the incident line be x=vx*t+ax and y=vy*t+ay.
// The equation of a circle is (x-ox)^2+(y-oy)^2 = r^2
// By combining two systems of equations, we get (vx^2+vy^2)*t^2+2*((ax-ox)*vx+(ay-oy)*vy)*t+((ax-ox)^2+(ay-oy)^2-r^2) = 0.
Firstly, the equation of straight line (using polar angle equation) and circle is set up to see whether delta is greater than 0. If delta is greater than 0 and B is less than 0 (both roots are greater than 0, i.e. -b/a > 0), the smaller t (think about why), then the intersection point can be obtained. Then the tangent equation (emmm itself is the normal result wa for a long time), and the antisymmetric point C of point B about the tangent equation can be obtained to see whether C is on the ray of A.
Reference code:
/*Computational geometry*/ #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++); //Let the polar angle equation of the incident line be x=vx*t+ax and y=vy*t+ay. //The equation of a circle is (x-ox)^2+(y-oy)^2 = r^2 //By combining two systems of equations, we get (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 greater than 0 means two roots, - b/2a > 0 (so that the equation has two positive roots) if( sgn( b*b-4*a*c) > 0 && sgn(b) < 0) { double tp = (-b-sqrt(b*b-4*a*c))/(2.0*a);//Take a smaller root, because the first intersection must be a little closer to point A. double px = vx*tp+ax;//The intersection of incident line and circle double py = vy*tp+ay; //Judging whether B is on the incident line 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; } } //Finding Tangent Equation Ax+By+C=0 double A = px-ox; double B = py-oy; double C = (ox-px)*px+(oy-py)*py; //Finding the Antisymmetric Point of Point B on Normal Line 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//radial { 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; }