HDU-5572 An Easy Physics Problem (Computational Geometry)

Keywords: PHP less

Let me see the topic.

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;
}



Posted by trp on Thu, 14 Feb 2019 15:57:18 -0800