In a closed system where moving 2-dimensional circular bodies (they have mass and velocity attributes) collide with one another with perfect elasticity, is total velocity speed (magnitude of velocity) of all the bodies within the system conserved?
I'm implementing a simple 2-D physics engine in Python based on the collision resolution method outlined in this Stack Overflow question. My expectation is that total speed (the sum of the length of the velocity vectors associated with each body) should remain constant between 2 bodies when they collide and I designed a unit test for my resolution method based on this expectation. But I find my test failing. So I want to make sure first that my assumption is correct.
If it is correct, I invite you to review my code and explain why the test is failing:
class Physics:
@staticmethod
def reflect_colliding_circles(
(c1_x, c1_y, c1_vx, c1_vy, c1_r, c1_m, c1_e),
(c2_x, c2_y, c2_vx, c2_vy, c2_r, c2_m, c2_e)):
# inverse masses, mtd, restitution
im1 = 1.0 / c1_m
im2 = 1.0 / c2_m
mtd = Physics.calculate_mtd((c1_x, c1_y, c1_r), (c2_x, c2_y, c2_r))
normal_mtd = mtd.normalized()
restitution = c1_e * c2_e
# impact speed
v = vec2d(c1_vx, c1_vy) - vec2d(c2_vx, c2_vy)
vn = v.dot(normal_mtd)
# circle moving away from each other already -- return
# original velocities
if vn > 0.0:
return vec2d(c1_vx, c1_vy), vec2d(c2_vx, c2_vy)
# collision impulse
i = (-1.0 * (1.0 + restitution) * vn) / (im1 + im2)
impulse = normal_mtd * i
# change in momentun
new_c1_v = vec2d(c1_vx, c1_vy) + (impulse * im1)
new_c2_v = vec2d(c2_vx, c2_vy) - (impulse * im2)
return new_c1_v, new_c2_v
@staticmethod
def calculate_mtd((c1_x, c1_y, c1_r), (c2_x, c2_y, c2_r)):
"""source: https://stackoverflow.com/q/345838/1093087"""
delta = vec2d(c1_x, c1_y) - vec2d(c2_x, c2_y)
d = delta.length
mtd = delta * (c1_r + c2_r - d) / d
return mtd
def test_conservation_of_velocity_in_elastic_collisions(self):
for n in range(10):
r = 2
m = 10
e = 1.0
c1_pos = vec2d(0, 0)
c1_v = vec2d(random.randint(-100,100), random.randint(-100,100))
c2_delta = vec2d(random.randint(-100,100), random.randint(-100,100))
c2_delta.length = random.randint(50, 99) * r / 100.0
c2_pos = c1_pos + c2_delta
c2_v = vec2d(random.randint(-100,100), random.randint(-100,100))
c1_np, c2_np = Physics.translate_colliding_circles(
(c1_pos.x, c1_pos.y, r, m),
(c2_pos.x, c2_pos.y, r, m))
c1_nv, c2_nv = Physics.reflect_colliding_circles(
(c1_np.x, c1_np.y, c1_v.x, c1_v.y, r, m, e),
(c2_np.x, c2_np.y, c2_v.x, c2_v.y, r, m, e))
old_v = c1_v.length + c2_v.length
new_v = c1_nv.length + c2_nv.length
self.assertTrue(Physics.circles_overlap(
(c1_pos.x, c1_pos.y, r), (c2_pos.x, c2_pos.y, r)))
self.assertTrue(old_v - new_v < old_v * .01)
I'm using this pygame vector class: http://www.pygame.org/wiki/2DVectorClass
Total momentum is conserved, regardless of how elastic the collision is. Total velocity is obviously not. Strictly speaking, velocity is a vector quantity, and it is rather easy to see that it will change, as a vector quantity: for example, a ball that elastically bounces off an immovable perpendicular wall changes its velocity to its opposite.