0

I have a part in my code where I have two particles collide in an elastic collision. I know the masses and radii of both the particles. I know the center points of both the particles when they collide. I know the velocities (including direction) of both the particles. What I want to figure out is the velocities (including direction) of both the particles after the collision, and I want to calculate it in a efficient way. I know this is more of a physics question than a computer programming one, but programmers always seem to be better at finding the most efficient way of doing something. I'm programming in C++. I would appreciate any help I can get, even just pointing me in the right direction. Thanks for you help!

Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
user1216527
  • 145
  • 1
  • 1
  • 11
  • I read [this](http://www.gamasutra.com/view/feature/131424/pool_hall_lessons_fast_accurate_.php?page=1) Way Back when it first came out, IIRC it was accurate and useful. But closing as off-topic. – GManNickG Nov 29 '12 at 21:21

2 Answers2

1

The exact solution can be solved by mathematical softwares (Mathematica, sagemath..etc). Here I used the python package sympy. The algorithm uses Gröbner basis and Buchberger's algorithm, which can solve systems of polynomial equations.

The equations for elastic collision are 1) conservation of momentum, one dimension each 2) conservation of energy. 3) the velocity of the first particle after collision is in the direction of a specified unit vector

The equations look like so:

uij :j-th component of velocity of i-th particle before collision.
vij :j-th component of velocity of i-th particle after collision.
n :the unit-vector pointing in the direction of the first particle's velocity after collision
t :the magnitude of the first particle's velocity after collision
m :mass

from sympy import *

u11,u12,u13 = symbols('u11 u12 u13')
u21,u22,u23 = symbols('u21 u22 u23')
v11,v12,v13 = symbols('v11 v12 v13')
v21,v22,v23 = symbols('v21 v22 v23')
n1,n2,n3,t= symbols('n1 n2 n3 t')
m1,m2 = symbols('m1 m2')


p1 = m1*u11 +m2*u21 - m1*v11 -m2*v21
p2 = m1*u12 +m2*u22 - m1*v12 -m2*v22
p3 = m1*u13 +m2*u23 - m1*v13 -m2*v23

e = m1*(u11**2+ u12**2 +u13**2) + m2*(u21**2+ u22**2+ u23**2) \
-( m1*(v11**2+ v12**2 +v13**2) + m2*(v21**2+ v22**2+ v23**2 ))

d1 =v11 - t*n1
d2 =v12 - t*n2
d3 =v13 - t*n3


s = solve([p1,p2,p3,e,d1,d2,d3], v11,v12,v13,v21,v22,v23,t, set=True)

The solution is : [t, v11, v12, v13, v21, v22, v23]

2*sqrt(-m1**2*n1**2*u12**2 - m1**2*n1**2*u13**2 + 2*m1**2*n1*n2*u11*u12 + 2*m1**2*n1*n3*u11*u13 - m1**2*n2**2*u11**2 - m1**2*n2**2*u13**2 + 2*m1**2*n2*n3*u12*u13 - m1**2*n3**2*u11**2 - m1**2*n3**2*u12**2 - 2*m1*m2*n1**2*u12*u22 - 2*m1*m2*n1**2*u13*u23 + 2*m1*m2*n1*n2*u11*u22 + 2*m1*m2*n1*n2*u12*u21 + 2*m1*m2*n1*n3*u11*u23 + 2*m1*m2*n1*n3*u13*u21 - 2*m1*m2*n2**2*u11*u21 - 2*m1*m2*n2**2*u13*u23 + 2*m1*m2*n2*n3*u12*u23 + 2*m1*m2*n2*n3*u13*u22 - 2*m1*m2*n3**2*u11*u21 - 2*m1*m2*n3**2*u12*u22 + m2**2*n1**2*u11**2 - 2*m2**2*n1**2*u11*u21 + m2**2*n1**2*u12**2 - 2*m2**2*n1**2*u12*u22 + m2**2*n1**2*u13**2 - 2*m2**2*n1**2*u13*u23 + m2**2*n1**2*u21**2 + 2*m2**2*n1*n2*u21*u22 + 2*m2**2*n1*n3*u21*u23 + m2**2*n2**2*u11**2 - 2*m2**2*n2**2*u11*u21 + m2**2*n2**2*u12**2 - 2*m2**2*n2**2*u12*u22 + m2**2*n2**2*u13**2 - 2*m2**2*n2**2*u13*u23 + m2**2*n2**2*u22**2 + 2*m2**2*n2*n3*u22*u23 + m2**2*n3**2*u11**2 - 2*m2**2*n3**2*u11*u21 + m2**2*n3**2*u12**2 - 2*m2**2*n3**2*u12*u22 + m2**2*n3**2*u13**2 - 2*m2**2*n3**2*u13*u23 + m2**2*n3**2*u23**2)/(2*m1*n1**2 + 2*m1*n2**2 + 2*m1*n3**2 + 2*m2*n1**2 + 2*m2*n2**2 + 2*m2*n3**2) + (m1*n1*u11 + m1*n2*u12 + m1*n3*u13 + m2*n1*u21 + m2*n2*u22 + m2*n3*u23)/((m1 + m2)*(n1**2 + n2**2 + n3**2)) 


n1*(m1*n1*u11 + m1*n2*u12 + m1*n3*u13 + m2*n1*u21 + m2*n2*u22 + m2*n3*u23 + sqrt(-m1**2*n1**2*u12**2 - m1**2*n1**2*u13**2 + 2*m1**2*n1*n2*u11*u12 + 2*m1**2*n1*n3*u11*u13 - m1**2*n2**2*u11**2 - m1**2*n2**2*u13**2 + 2*m1**2*n2*n3*u12*u13 - m1**2*n3**2*u11**2 - m1**2*n3**2*u12**2 - 2*m1*m2*n1**2*u12*u22 - 2*m1*m2*n1**2*u13*u23 + 2*m1*m2*n1*n2*u11*u22 + 2*m1*m2*n1*n2*u12*u21 + 2*m1*m2*n1*n3*u11*u23 + 2*m1*m2*n1*n3*u13*u21 - 2*m1*m2*n2**2*u11*u21 - 2*m1*m2*n2**2*u13*u23 + 2*m1*m2*n2*n3*u12*u23 + 2*m1*m2*n2*n3*u13*u22 - 2*m1*m2*n3**2*u11*u21 - 2*m1*m2*n3**2*u12*u22 + m2**2*n1**2*u11**2 - 2*m2**2*n1**2*u11*u21 + m2**2*n1**2*u12**2 - 2*m2**2*n1**2*u12*u22 + m2**2*n1**2*u13**2 - 2*m2**2*n1**2*u13*u23 + m2**2*n1**2*u21**2 + 2*m2**2*n1*n2*u21*u22 + 2*m2**2*n1*n3*u21*u23 + m2**2*n2**2*u11**2 - 2*m2**2*n2**2*u11*u21 + m2**2*n2**2*u12**2 - 2*m2**2*n2**2*u12*u22 + m2**2*n2**2*u13**2 - 2*m2**2*n2**2*u13*u23 + m2**2*n2**2*u22**2 + 2*m2**2*n2*n3*u22*u23 + m2**2*n3**2*u11**2 - 2*m2**2*n3**2*u11*u21 + m2**2*n3**2*u12**2 - 2*m2**2*n3**2*u12*u22 + m2**2*n3**2*u13**2 - 2*m2**2*n3**2*u13*u23 + m2**2*n3**2*u23**2))/(m1*n1**2 + m1*n2**2 + m1*n3**2 + m2*n1**2 + m2*n2**2 + m2*n3**2)


n2*(m1*n1*u11 + m1*n2*u12 + m1*n3*u13 + m2*n1*u21 + m2*n2*u22 + m2*n3*u23 + sqrt(-m1**2*n1**2*u12**2 - m1**2*n1**2*u13**2 + 2*m1**2*n1*n2*u11*u12 + 2*m1**2*n1*n3*u11*u13 - m1**2*n2**2*u11**2 - m1**2*n2**2*u13**2 + 2*m1**2*n2*n3*u12*u13 - m1**2*n3**2*u11**2 - m1**2*n3**2*u12**2 - 2*m1*m2*n1**2*u12*u22 - 2*m1*m2*n1**2*u13*u23 + 2*m1*m2*n1*n2*u11*u22 + 2*m1*m2*n1*n2*u12*u21 + 2*m1*m2*n1*n3*u11*u23 + 2*m1*m2*n1*n3*u13*u21 - 2*m1*m2*n2**2*u11*u21 - 2*m1*m2*n2**2*u13*u23 + 2*m1*m2*n2*n3*u12*u23 + 2*m1*m2*n2*n3*u13*u22 - 2*m1*m2*n3**2*u11*u21 - 2*m1*m2*n3**2*u12*u22 + m2**2*n1**2*u11**2 - 2*m2**2*n1**2*u11*u21 + m2**2*n1**2*u12**2 - 2*m2**2*n1**2*u12*u22 + m2**2*n1**2*u13**2 - 2*m2**2*n1**2*u13*u23 + m2**2*n1**2*u21**2 + 2*m2**2*n1*n2*u21*u22 + 2*m2**2*n1*n3*u21*u23 + m2**2*n2**2*u11**2 - 2*m2**2*n2**2*u11*u21 + m2**2*n2**2*u12**2 - 2*m2**2*n2**2*u12*u22 + m2**2*n2**2*u13**2 - 2*m2**2*n2**2*u13*u23 + m2**2*n2**2*u22**2 + 2*m2**2*n2*n3*u22*u23 + m2**2*n3**2*u11**2 - 2*m2**2*n3**2*u11*u21 + m2**2*n3**2*u12**2 - 2*m2**2*n3**2*u12*u22 + m2**2*n3**2*u13**2 - 2*m2**2*n3**2*u13*u23 + m2**2*n3**2*u23**2))/(m1*n1**2 + m1*n2**2 + m1*n3**2 + m2*n1**2 + m2*n2**2 + m2*n3**2)


n3*(m1*n1*u11 + m1*n2*u12 + m1*n3*u13 + m2*n1*u21 + m2*n2*u22 + m2*n3*u23 + sqrt(-m1**2*n1**2*u12**2 - m1**2*n1**2*u13**2 + 2*m1**2*n1*n2*u11*u12 + 2*m1**2*n1*n3*u11*u13 - m1**2*n2**2*u11**2 - m1**2*n2**2*u13**2 + 2*m1**2*n2*n3*u12*u13 - m1**2*n3**2*u11**2 - m1**2*n3**2*u12**2 - 2*m1*m2*n1**2*u12*u22 - 2*m1*m2*n1**2*u13*u23 + 2*m1*m2*n1*n2*u11*u22 + 2*m1*m2*n1*n2*u12*u21 + 2*m1*m2*n1*n3*u11*u23 + 2*m1*m2*n1*n3*u13*u21 - 2*m1*m2*n2**2*u11*u21 - 2*m1*m2*n2**2*u13*u23 + 2*m1*m2*n2*n3*u12*u23 + 2*m1*m2*n2*n3*u13*u22 - 2*m1*m2*n3**2*u11*u21 - 2*m1*m2*n3**2*u12*u22 + m2**2*n1**2*u11**2 - 2*m2**2*n1**2*u11*u21 + m2**2*n1**2*u12**2 - 2*m2**2*n1**2*u12*u22 + m2**2*n1**2*u13**2 - 2*m2**2*n1**2*u13*u23 + m2**2*n1**2*u21**2 + 2*m2**2*n1*n2*u21*u22 + 2*m2**2*n1*n3*u21*u23 + m2**2*n2**2*u11**2 - 2*m2**2*n2**2*u11*u21 + m2**2*n2**2*u12**2 - 2*m2**2*n2**2*u12*u22 + m2**2*n2**2*u13**2 - 2*m2**2*n2**2*u13*u23 + m2**2*n2**2*u22**2 + 2*m2**2*n2*n3*u22*u23 + m2**2*n3**2*u11**2 - 2*m2**2*n3**2*u11*u21 + m2**2*n3**2*u12**2 - 2*m2**2*n3**2*u12*u22 + m2**2*n3**2*u13**2 - 2*m2**2*n3**2*u13*u23 + m2**2*n3**2*u23**2))/(m1*n1**2 + m1*n2**2 + m1*n3**2 + m2*n1**2 + m2*n2**2 + m2*n3**2)


(-m1**2*n1*n2*u12 - m1**2*n1*n3*u13 + m1**2*n2**2*u11 + m1**2*n3**2*u11 + m1*m2*n1**2*u11 - m1*m2*n1*n2*u22 - m1*m2*n1*n3*u23 + m1*m2*n2**2*u11 + m1*m2*n2**2*u21 + m1*m2*n3**2*u11 + m1*m2*n3**2*u21 - m1*n1*sqrt(-m1**2*n1**2*u12**2 - m1**2*n1**2*u13**2 + 2*m1**2*n1*n2*u11*u12 + 2*m1**2*n1*n3*u11*u13 - m1**2*n2**2*u11**2 - m1**2*n2**2*u13**2 + 2*m1**2*n2*n3*u12*u13 - m1**2*n3**2*u11**2 - m1**2*n3**2*u12**2 - 2*m1*m2*n1**2*u12*u22 - 2*m1*m2*n1**2*u13*u23 + 2*m1*m2*n1*n2*u11*u22 + 2*m1*m2*n1*n2*u12*u21 + 2*m1*m2*n1*n3*u11*u23 + 2*m1*m2*n1*n3*u13*u21 - 2*m1*m2*n2**2*u11*u21 - 2*m1*m2*n2**2*u13*u23 + 2*m1*m2*n2*n3*u12*u23 + 2*m1*m2*n2*n3*u13*u22 - 2*m1*m2*n3**2*u11*u21 - 2*m1*m2*n3**2*u12*u22 + m2**2*n1**2*u11**2 - 2*m2**2*n1**2*u11*u21 + m2**2*n1**2*u12**2 - 2*m2**2*n1**2*u12*u22 + m2**2*n1**2*u13**2 - 2*m2**2*n1**2*u13*u23 + m2**2*n1**2*u21**2 + 2*m2**2*n1*n2*u21*u22 + 2*m2**2*n1*n3*u21*u23 + m2**2*n2**2*u11**2 - 2*m2**2*n2**2*u11*u21 + m2**2*n2**2*u12**2 - 2*m2**2*n2**2*u12*u22 + m2**2*n2**2*u13**2 - 2*m2**2*n2**2*u13*u23 + m2**2*n2**2*u22**2 + 2*m2**2*n2*n3*u22*u23 + m2**2*n3**2*u11**2 - 2*m2**2*n3**2*u11*u21 + m2**2*n3**2*u12**2 - 2*m2**2*n3**2*u12*u22 + m2**2*n3**2*u13**2 - 2*m2**2*n3**2*u13*u23 + m2**2*n3**2*u23**2) + m2**2*n1**2*u21 + m2**2*n2**2*u21 + m2**2*n3**2*u21)/(m2*(m1*n1**2 + m1*n2**2 + m1*n3**2 + m2*n1**2 + m2*n2**2 + m2*n3**2))


(m1**2*n1**2*u12 - m1**2*n1*n2*u11 - m1**2*n2*n3*u13 + m1**2*n3**2*u12 + m1*m2*n1**2*u12 + m1*m2*n1**2*u22 - m1*m2*n1*n2*u21 + m1*m2*n2**2*u12 - m1*m2*n2*n3*u23 + m1*m2*n3**2*u12 + m1*m2*n3**2*u22 - m1*n2*sqrt(-m1**2*n1**2*u12**2 - m1**2*n1**2*u13**2 + 2*m1**2*n1*n2*u11*u12 + 2*m1**2*n1*n3*u11*u13 - m1**2*n2**2*u11**2 - m1**2*n2**2*u13**2 + 2*m1**2*n2*n3*u12*u13 - m1**2*n3**2*u11**2 - m1**2*n3**2*u12**2 - 2*m1*m2*n1**2*u12*u22 - 2*m1*m2*n1**2*u13*u23 + 2*m1*m2*n1*n2*u11*u22 + 2*m1*m2*n1*n2*u12*u21 + 2*m1*m2*n1*n3*u11*u23 + 2*m1*m2*n1*n3*u13*u21 - 2*m1*m2*n2**2*u11*u21 - 2*m1*m2*n2**2*u13*u23 + 2*m1*m2*n2*n3*u12*u23 + 2*m1*m2*n2*n3*u13*u22 - 2*m1*m2*n3**2*u11*u21 - 2*m1*m2*n3**2*u12*u22 + m2**2*n1**2*u11**2 - 2*m2**2*n1**2*u11*u21 + m2**2*n1**2*u12**2 - 2*m2**2*n1**2*u12*u22 + m2**2*n1**2*u13**2 - 2*m2**2*n1**2*u13*u23 + m2**2*n1**2*u21**2 + 2*m2**2*n1*n2*u21*u22 + 2*m2**2*n1*n3*u21*u23 + m2**2*n2**2*u11**2 - 2*m2**2*n2**2*u11*u21 + m2**2*n2**2*u12**2 - 2*m2**2*n2**2*u12*u22 + m2**2*n2**2*u13**2 - 2*m2**2*n2**2*u13*u23 + m2**2*n2**2*u22**2 + 2*m2**2*n2*n3*u22*u23 + m2**2*n3**2*u11**2 - 2*m2**2*n3**2*u11*u21 + m2**2*n3**2*u12**2 - 2*m2**2*n3**2*u12*u22 + m2**2*n3**2*u13**2 - 2*m2**2*n3**2*u13*u23 + m2**2*n3**2*u23**2) + m2**2*n1**2*u22 + m2**2*n2**2*u22 + m2**2*n3**2*u22)/(m2*(m1*n1**2 + m1*n2**2 + m1*n3**2 + m2*n1**2 + m2*n2**2 + m2*n3**2))


(m1**2*n1**2*u13 - m1**2*n1*n3*u11 + m1**2*n2**2*u13 - m1**2*n2*n3*u12 + m1*m2*n1**2*u13 + m1*m2*n1**2*u23 - m1*m2*n1*n3*u21 + m1*m2*n2**2*u13 + m1*m2*n2**2*u23 - m1*m2*n2*n3*u22 + m1*m2*n3**2*u13 - m1*n3*sqrt(-m1**2*n1**2*u12**2 - m1**2*n1**2*u13**2 + 2*m1**2*n1*n2*u11*u12 + 2*m1**2*n1*n3*u11*u13 - m1**2*n2**2*u11**2 - m1**2*n2**2*u13**2 + 2*m1**2*n2*n3*u12*u13 - m1**2*n3**2*u11**2 - m1**2*n3**2*u12**2 - 2*m1*m2*n1**2*u12*u22 - 2*m1*m2*n1**2*u13*u23 + 2*m1*m2*n1*n2*u11*u22 + 2*m1*m2*n1*n2*u12*u21 + 2*m1*m2*n1*n3*u11*u23 + 2*m1*m2*n1*n3*u13*u21 - 2*m1*m2*n2**2*u11*u21 - 2*m1*m2*n2**2*u13*u23 + 2*m1*m2*n2*n3*u12*u23 + 2*m1*m2*n2*n3*u13*u22 - 2*m1*m2*n3**2*u11*u21 - 2*m1*m2*n3**2*u12*u22 + m2**2*n1**2*u11**2 - 2*m2**2*n1**2*u11*u21 + m2**2*n1**2*u12**2 - 2*m2**2*n1**2*u12*u22 + m2**2*n1**2*u13**2 - 2*m2**2*n1**2*u13*u23 + m2**2*n1**2*u21**2 + 2*m2**2*n1*n2*u21*u22 + 2*m2**2*n1*n3*u21*u23 + m2**2*n2**2*u11**2 - 2*m2**2*n2**2*u11*u21 + m2**2*n2**2*u12**2 - 2*m2**2*n2**2*u12*u22 + m2**2*n2**2*u13**2 - 2*m2**2*n2**2*u13*u23 + m2**2*n2**2*u22**2 + 2*m2**2*n2*n3*u22*u23 + m2**2*n3**2*u11**2 - 2*m2**2*n3**2*u11*u21 + m2**2*n3**2*u12**2 - 2*m2**2*n3**2*u12*u22 + m2**2*n3**2*u13**2 - 2*m2**2*n3**2*u13*u23 + m2**2*n3**2*u23**2) + m2**2*n1**2*u23 + m2**2*n2**2*u23 + m2**2*n3**2*u23)/(m2*(m1*n1**2 + m1*n2**2 + m1*n3**2 + m2*n1**2 + m2*n2**2 + m2*n3**2))
golopot
  • 10,726
  • 6
  • 37
  • 51
0

I recomend you this paper published by Pixar. It is about simulation of rigid body and contains some code, so that you can give it a shot! :-)

Here you can also download some C++-Code dealing with motion in 3D.

Tengis
  • 2,721
  • 10
  • 36
  • 58