2D Collision Detection and Handling with Python
I built a python package for detecting and handling collisions of circles in 2D. The code defines a class for the objects and handles the velocity updates using basic elastic collision mechanics. The code can be downloaded from my GitHub repository and an example output using Pygame as a display is shown below. For details on the physics along with a discussion of how this problem relates to Quantum Mechanics, keep reading!
I have been taking a course in Quantum Mechanics as part of my PhD. The mathematical machinery is quite elegant and although this project doesn’t require QM, the problem solving method is quite similar: cast the equations into a convenient representation, solve, then convert back to original representation.
There’s a pretty nice Wikipedia article on the mechanics of a 2D elastic collision, but the punch-line is this: if you re-frame the coordinate system to be in the collision direction and other directions orthogonal to this, then the only velocities that need updated are the ones in the collision direction; the others remain constant since there are no forces in their direction. This means you’ve reduced the problem to 1D. Here’s the flow I used:
- Calculate the collision direction. Since the circle positions are defined by a vector pointing from the upper-left point of the screen to their center, this is as simple as subtracting one vector from the other. This results in a vector that’s in the direction of collision and equal in magnitude to the distance between the centers. I normalize the vector by dividing by its magnitude so that I’m left with only a unit vector direction that will become my new x-axis.
- Calculate the direction orthogonal to the collision direction. This is the direction along which the velocities will remain constant. I use a simple Gram-Schmidt process with the y-unit vector as my reference (i.e. y = [0 1]). Again, I normalize this vector and similarly use it as my new y-axis.
- Project the circles’ velocities onto these directions. All we have done so far is rotate our coordinate system so that the new x-axis is along the collision direction and the new y-axis is orthogonal to that. We then find what our velocity vectors look like using this new coordinate system by projecting them onto the unit vectors calculated in Steps 1 and 2.
- Update the velocities of each circle in the collision direction (i.e. the “new x”-component of the velocity vector) using elastic collision mechanics. The y-component of the velocity remains constant.
- Calculate a matrix of converting back to the original x and y basis (i.e. [1, 0] and [0, 1]). This is done by computing a 2×2 matrix where the elements are equal to the dot product of the various components. For instance, A_1,1 = dot(x, x’); A_1,2 = dot(x, y’). This projects your (x’, y’) coordinates back to the original (x,y).
- Finally, multiply this matrix by the updated velocity vectors from Step 4 to rotate the vectors back into the original (x,y) coordinates. This is your final answer.
What does this have to do with QM? When you find the eigen-values and eigen-vectors of a matrix operator, you’ve found the possible solutions since the eigen-values are the so-called observables (i.e. what outcomes you will get from measurement). Once you have the solutions in the eigen representation you can transform them to anything you want, so like we transformed back to our original x and y.
The particular representation of a matrix operator (i.e. the numbers in the matrix) are dependent on which basis you’re in, which in our case is equivalent to which coordinate system we’re using. Similarly, our velocity vectors represent something real, but the particular numbers depend on the coordinate system you’re using. Naturally, some representations may be easier to work with than others so it’s important to be able to freely transform the problem between different representations. In QM that usually means using the eigen-vectors as the “coordinate system”. In our case, we used the collision direction and those orthogonal to it as our coordinate system since it reduced the problem to a one dimension set of equations that were easy to solve.
An excellent example of applying similar machinery to solve the problem of normal mode vibrations in masses coupled to springs is in Shankar’s Principles of Quantum Mechanics, Second Edition, Example 1.8.6. In this case, you have differential equations for each block that depend on what the other block is doing (i.e. a coupled differential equation). By using the same techniques you find the “vibrational modes” that are uncoupled and only depend on one variable, similar to reducing the problem to 1D. Once you solve this much easier differential equation, you cast the solution back onto the original coordinate system to get the final answer.