Search code examples
c#mathvectorgeometrycollision-detection

Predict Circle to Circle intersection in Time


I need to find if two round objects will collide and if yes when in time they will.

My approach is this:

if (Vector3.DistanceSquared(a.Position, b.Position) < Math.Pow(a.Radius + b.Radius,2))
            {
                return 0;
            }
            else
            {
                float result;
                for (int t = 1; t < 150; t++)
                {
                    result = Vector3.DistanceSquared(a.Position + t * a.LinearVelocity, b.Position + t * b.LinearVelocity);
                    if (float.IsInfinity(result))
                    {
                        return float.PositiveInfinity;
                    }
                    if (result <= Math.Pow(a.Radius+b.Radius,2))
                    {
                        return t;
                    }
                }
                
                return float.PositiveInfinity;
            }

I am clearly missing something, or I am totally wrong cause the results are not as expected.

I also think performance wise the loop might be wrong but I am not sure how could I avoid it.


Solution

  • If we write squared distance between circle centers:

    (x2-x1+t*(vx2-vx1))^2+(y2-y1+t*(vy2-vy1))^2=(r1+r2)^2
    let dx = x2-x1, dy = y2-y1, dvx = vx2-vx1, dvy = vy2-vy1, rr = r1+r2
    (dx+t*dvx)^2+(dy+t*dvy)^2=rr^2
    dx^2+2*dx*t*dvx+t^2*dvx^2+dy^2+2*dy*t*dvy+t^2*dvy^2-rr^2=0
    t^2*(dvx^2+dvy^2) + t*(2*dx*dvx+2*dy*dvy) + (dx^2+dy^2-rr^2)=0
    t^2*a +             t*b +                   c               =0
    

    This is quadratic equation for unknown t

    D = b^2 - 4*a*c
    if D<0 there are no collisions
    if D=0 there is one touching in moment t = -b/(2*a)
    else there are two solutions
    t1 = (-b - sqrt(D)) / (2*a)
    t2 = (-b + sqrt(D)) / (2*a)
    

    One or both times might be negative - means collision "was in the past"

    Smaller time is moment of collision, larger time - moment of "leaving", I think it is not needed here