Hi!
I'm writing a pool simulation and have an awful problem with my ball collisions (elastic collisions).
The theory (in terms of vectors) is that when two balls collide you take the line between their centers and the velocity components which are perpendicular to this line are unaffected, while the parallel ones are calculated from the formula:
v1' = [2*m2v2-v1(m2-m1)]/[m1+m2]
v2' = [2*m1v1-v2(m1-m2)]/[m1+m2]
What I do is when I find that the balls are in touch I find a vector which is the line joining the centers. I then use atan2(y,x) to get the polar angle (in radians).
I then premultiply the velocity vectors by the (counter-clockwise) rotation matrix:
1st row(cos(angle) sin(angle))
2nd row(-sin(angle) cos(angle))
Then I take the x components (which are now the components parallel to the line joining centers) And apply the formulas given above. Now I have new x components in the new basis and the old y components in the new basis.
So I rotate everything back and I should get the right velocity components?
The simulation looks ok, it even works fine for a head-on collision. But When I print out the balls velocities I find that the momentum wasn't conserved. Eg. balls of same mass, one ball is initially stationary, other going at 80pix/s:
After collision I find that the velocity magnitudes are 77 and 19 :(
That's way too much :( I initially thought it might be the problem that the balls penetrate each other slightly as it changes "angle" slightly, but that is surely not the case, as I checked for balls exactly touching). I'm also sure that the equations for parallel velocity components given are correct, and that the error appears right after calling my collision method. This means that it is a conceptual mistake with the rotation matrix or sth.
if anyone can find the mistake I'd be really grateful as I'm really stuck at this point.
Here is my collision method code:
/// Method for collision of two balls- sets their' new velocities
public static void Collide(Ball A, Ball B){
Vector2d joining = LineBetweenCentres(A, B);
System.out.println(joining.GetX() + " " +joining.GetY() + " "+ joining.magnitude());
/// angle is the angle of line joining centres in terms of polar coordinates
double angle = Math.atan2(joining.GetY(), joining.GetX());
/// rotate the velocity vectors of ball A and B in terms of the new basis (so that joining is "not tilted")
double AvelXrotated = A.GetVel().GetX()*Math.cos(angle) + A.GetVel().GetY()*Math.sin(angle);
double AvelYrotated = -1.0*A.GetVel().GetX()*Math.sin(angle) + A.GetVel().GetY()*Math.cos(angle);
double BvelXrotated = B.GetVel().GetX()*Math.cos(angle) + B.GetVel().GetY()*Math.sin(angle);
double BvelYrotated = -1.0*B.GetVel().GetX()*Math.sin(angle) + B.GetVel().GetY()*Math.cos(angle);
/// perpendicular (y) velocity components are not affected, the new (x) components (in terms of new basis) are calculated:
double AvelXnew = (2.0*B.GetMass()*BvelXrotated - AvelXrotated*(B.GetMass() - A.GetMass()))/(A.GetMass() + B.GetMass());
double BvelXnew = (2.0*A.GetMass()*AvelXrotated - BvelXrotated*(A.GetMass() - B.GetMass()))/(A.GetMass() + B.GetMass());
/// now the vectors need to be rotated back to the standard basis:
double AvelXrerotated = AvelXnew*Math.cos(-1.0*angle) + AvelYrotated*Math.sin(-1.0*angle);
double AvelYrerotated = -1.0*AvelXnew*Math.sin(-1.0*angle) + AvelYrotated*Math.cos(-1.0*angle);
double BvelXrerotated = BvelXnew*Math.cos(-1.0*angle) + BvelYrotated*Math.sin(-1.0*angle);
double BvelYrerotated = -1.0*BvelXnew*Math.sin(-1.0*angle) + BvelYrotated*Math.cos(-1.0*angle);
/// set the new velocity components to the balls
A.SetVelocity(AvelXrerotated, AvelYrerotated);
B.SetVelocity(BvelXrerotated, BvelYrerotated);
/// This part is responsible for making the balls go away from each other after collision so that they don't collide again straight away
do{
line = Ball.LineBetweenCentres(A, B);
A.UpdatePosition();
B.UpdatePosition();
}
while(line.magnitude() < A.GetRadius()+B.GetRadius());
}
If you want I can send you the whole program code on the mail, just give me your mail or write to trelek2@gmail.com