Calculating the time of impact or time of closest approach of two moving circles or spheres is a common problem in game physics. The solution to this problem can be used to solve the collisions of billiard balls on a pool table, the collision of a bullet fired with high velocity at a target in the distance, or a number of other common game scenarios in which the exact time and location of impact must be known with a high degree of accuracy.
It's a simple enough problem to solve as long as we enforce a couple key constraints. First, we assume that the circles or spheres will be moving at some constant linear velocity. Secondly, we assume that they don't change size; their radius remains constant. In the future, I'll talk about how to solve collisions between circles or spheres with non-linear trajectories and variable radii. But, for now, let's set up the problem with these constraints in mind.
The first step to solving this problem is to write down the functions that describe the linear trajectories of the objects. If we let Pa and Pb be the initial positions of two circles or spheres, A and B, and let Va and Vb be the linear velocity of A and B, then their position at any time, t, are the linear parametric functions A(t) and B(t):
Next, we need the function that describes the distance between the two trajectories at any time, t. That function is simply the Euclidean distance between A(t) and B(t) minus the sum of the circle's radii, Ra and Rb.
The goal is to find time, t, where d(t) = 0. In other words, we need to find the roots of d(t). As it turns out, d(t) is quadratic, so the roots will be easy to find. We can simply expand the equation, find the quadratic terms, and then use the quadratic formula to find the roots.
We start the expansion by setting d(t) to zero and replacing the straight bracket term with the Euclidean formula.
The first step we're forced to make is to move the (Ra + Rb) term to the left side and then square both sides to eliminate the square root.
Next, we'll substitute in the equations for A(t) and B(t), combine like terms, and then collapse the position and velocity terms into single variables. This will give us a very simple equation that we can easily expand into a quadratic form.
Now we can expand the right-hand side without it being too gnarly. We'll also move the (Ra+Rb) term back to the right side. An important thing to remember here is that Pab and Vab are vector terms, so when we expand the square we use the Dot Product instead of multiplication. This is perfectly valid for two reasons: First, the dot product of a vector dotted with itself is the length of the vector squared (i.e. a.a = |a|*|a|). Second, the dot product operation is distributive (i.e. a.(b+c) = a.b + a.c). So, when we expand the right-hand side, here is what we get:
It's a nice, neat quadratic equation with simple terms. We can now pump the terms into the quadratic formula and find the roots.
There are three cases that arise from the quadratic formula. The first case is where there are no real roots. The second case is when there is exactly one real root. And the third, and final, case is where there are exactly two real roots. These cases are decided by the value of the quadratic discriminant.
Case #1: Discriminant is negative.
If the discriminant is negative, then d(t) has no real roots. The circles do not intersect at any time in the past or future. They either pass each other or are traveling with parallel trajectories. In this case, two imaginary roots are created. These complex roots are conjugates of each other. In the special case of quadratic functions, they are always precisely the same distance away from the critical point that marks the time where the distance function is minimized. Therefore, the time of closest approach is literally the average of these two imaginary roots.
However, a better way to get the location of the critical point is to take the first-derivative of the function, set it equal to zero, and solve for t. Either way, we'll get the same answer in this case.
Time, t, in this case is the time of closest approach of the two circles or spheres.
Case #2: Discriminant is zero.
If the discriminant is zero, then there is exactly one real root. That means that the circles or spheres just barely graze each other at a single point. In this case, everything under the square root in the quadratic formula goes away, and you're left with the same answer as in case #1.
But, the meaning of this time is different than in the first case. In this case, t is the exact time of the collision event.
Case #3: Discriminant is positive.
If the discriminant is positive, then there are exactly two real roots. That means that the circles or spheres pass through each other at some point in the past or future. The roots are the times when the distance between the object's surfaces equals zero. The root that produces the smallest time is the initial impact.
Time, t, in this case is the time of the initial impact.
In all three cases, it's worth noting that the time that is calculated can be negative, which means that the event occurred in the past. But, because most games are only concerned with future collision events, you may want to include a conditional statement in your program that returns a "no collision" response in that case.
I would like to start a series of posts describing in detail the time of closest approach of other primitives, including cones and planes. I may write a few articles on difficult collision detection problems solved via Lagrangian methods and iterative optimization techniques.
Please feel free to e-mail me or post a comment here in this blog if you find any errors or have any concerns with the material presented here. I always try to be accurate with everything I say, but I'm not a mathematician. Sometimes I end up being right, but for the wrong reasons. And, sometimes, I'm just totally wrong. :)
I created an interactable demonstration program coded in C# for Microsoft's XNA framework. You can download that demo from the Google Code archive here:
Thank you for reading. I hope you've found this information useful. :)