Collision point of two non-rotating polygons

A couple of threads recently on Compuserve have dealt with how to determine 
when two non-rotating polygon objects collide.  Below is a short discussion of 
one algorithm to determine when and where the collision happens.  The algorithm 
will work for both convex and concave figures with any number of line 
segments.  The algorithm works entirely by intersecting lines, and thus does 
not rely on time-consuming iterative methods.  One special case we need to 
handle is when we compare two line segments which are parallel or 
nearly-parallel.  Finally, the algorithm works even for objects that pass 
completely through each other in the course of one frame.

I don't get into rotating polygons, transfering momentum between the objects 
(see collid.zip for ball collisions.  Much of that info will apply to this 
as long as the objects are nearly circular,) accelerations during the frame, 
nor multiple collisions within one frame of action.

The trick to making this simple and quick is to recognize that the "point of 
intersection" between the two line segments changes over the course of the 
frame.  The path of the point of intersection describes a line.  Intersect 
that line with the line described by the path of one of the endpoints and you 
have a possible collision point.  This is fairly difficult to explain in 
words, but the figures included in this zip file will help you visualize 
what's happening.

Prior to Figure 1 you'll want to perform some bounding box tests to cull out 
most of the line segments on the screen.  First, you'll want to test each 
object against each other object.  Be sure to include the full extents of the 
objects motion for the current frame.  Next, for any object pairs which pass 
that test you'll want to test each line segement in one object with each line 
segment in the other object. In most situations you'll probably be down to a 
very few lines to compare.

Figure 1 shows two objects and their velocity vectors.  Figure 2 highlights 
one line segment on each object.

In Figure 3, we've extended the line segments indefinately in each direction.  
This gives us our initial point of intersection.

In Figure 4, we've moved the line segments to their position at the end of the 
frame and again extended the lines.  This time we get the final point of 
intersection. Over the course of the frame, the path of this point of 
intersection will describe a line from the initial to the final point.

In Figure 5, we've shown the path of the endpoints and where they intersect 
with path of intersection.  We end up with four possible points of collision.  
At this point, you probably want to sort the four points by distance to the 
initial initial point of intersection.  The closest happens earliest in the 
frame (neglecting acceleration.)

In Figure 6, we've determined that Point 1 lies outside of the blue line 
segment.  The easiest way to determine this is to calculate the distance from 
Point 1 to each of the endpoints of the blue line segment.  If either distance 
is greater than the length of the blue line segment then the point lies 
outside the line segment.

In Figure 7, we've determined that Point 2 does lie within the red line 
segment.  This is our point of impact.  The distance along the path of 
intersection is proportional to the time within the frame when the collision 
occurred.  IOW, in Figure 7, Point 2 appears to lie just about halfway from 
the Initial point to the Final point.  Therefore, the collision happened 
halfway through the frame (again, neglecting acceleration.)

That's all there is to it.  The figures make it pretty straightforward.

You may remember that I mentioned a special case.  If the line segments in 
question are parallel then you won't have a path of intersection to play with.  
Instead, the lines containing the line segments will overlap at only one 
instant during the frame.

Another, problem arises if the lines are nearly parallel.  In that case, the 
Initial and Final points of intersection may be so far away that you risk 
overflowing your variables.  I suggest that you treat nearly parallel lines as 
parallel and perform the following special case algorithm.

The trick for parallel lines is to recognize that the fact that they're 
parallel in effect removes one dimension from the problem.  We've gone from a 
two-dimensional system with intersection lines to a one-dimensional system 
where two lines are closing on each other.

Actually, they may not be headed directly at each other, as shown in Figure 8.  
But, since the lines are known to be parallel, then the velocity vector 
perpendicular to the line's slope is by definition the closing speed relative 
to the other line segment.  These are the dotted lines in Figure 9.  Once we 
know these closing speeds, the problem becomes a simple one-dimensional 
rate-distance problem.

  rate1 * t + rate2 * t = distance
  t = distance / (rate1 + rate2)

Once you've calculate t you need to test the line segments to verify that they 
have in fact overlapped.  Take one endpoint from the red line segment and 
calculate the distance to both endpoints of the blue line segment.  If the 
distance to both is less than the length of the blue line segment then the red 
endpoint falls inside the blue line segment and you have a successful 
collision.  Otherwise, perform the same test with all the other endpoints.  If 
any of the endpoints falls on the other line segment, then you have a 
successful collision.

Optimizations:

At the beginning of this document I mentioned using bounding boxes to cut down 
the number of lines to test.  Bounding box tests are cheap, and even with 50+ 
objects on the screen the time spent comparing bounding boxes will probably be 
completely swamped by simply drawing things on the screen.  You'll only need 
something more sophisticated when you get a lot more objects on the screen.

Similarly, once you get two entire objects which satisfy the bounding box 
test, you'll likely only end up with a small number of line segments which 
actually need to be tested with each other.

A couple of quick optimization ideas in the calculations.  These will happen 
so rarely that we probably wouldn't even notice the extra work.  But they're 
so obvious I just had to mention them.

In Figure 5, where we compare the distance to each of the possible collision 
points.  In this instance, we don't need to know the actual distance.  We 
simply need the ranking from lowest to highest.  Therefore, we don't need to 
take the square root of each of those calculations.  When it comes time to 
determine the time within the frame then we will need to take the square root.

Similarly, we don't need to take the square root when determining if the 
possible point of impact is on the line segment.  Compare against the square 
of the length of the line segment.

Well, I think that's enough to get you started.  I'd like to throw together 
some example code, but I'm completely swamped at work, so I'll leave that as 
an exercise.  If anyone posts some code that's based on these ideas, please 
let me know and I'll include a pointer in this document.

References:

Be sure to check out IMPACT21.ZIP by John Henckel henckel@vnet.ibm.com.  It's 
available in GAMDEV on Compuserve and shows up on internet searches.  It's a 
nifty polygon collision example, including source code.  He handles rotating 
polygons, and momentum transfer.

Thanks to Kevin J Hoffman 102547,3560 for spurring this line of thought and 
brainstorming with me. It was an interesting problem.

Drake Christensen 71251.433@compuserve.com
