Thread: Bah. Need math/programming help. Collision handling.

1. Bah. Need math/programming help. Collision handling.

This is java syntax, but anybody can read it, so I'm posting it here. More of a math question.

Basically, I'm handling ball (molecule) collisions.

java Code:
```// other is the other molecule we're colliding with

// x and y distances between molecules
double xDist = this.getX() - other.getX();
double yDist = this.getY() - other.getY();

// get the distance between circle centers
double hypotenuse = Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2));

// create the line tangent to the two circles (through the collision point) and get its direction
double tangentAngle = Math.toDegrees(Math.atan(Math.abs(yDist / xDist))) + 90;
if (yDist < 0 && xDist != 0) { tangentAngle += 90; tangentAngle %= 360; }

// rounds to nearest decimal if it's very, very close to it
hypotenuse = MyMath.roundIfClose(hypotenuse);
tangentAngle = MyMath.roundIfClose(tangentAngle);

// rotate the two molecules until the line tangent to the circles is vertical
double toAdd = 90 - tangentAngle;
double thisNewTheta = (this.getVel().getTheta() + toAdd + 360) % 360;
double otherNewTheta = (other.getVel().getTheta() + toAdd + 360) % 360;

// get the speed of the molecule in the x direction (toward the tangent line is x direction)
double v1 = this.getVel().getSpeed() * Math.cos(Math.toRadians(thisNewTheta));
double v2 = other.getVel().getSpeed() * Math.cos(Math.toRadians(otherNewTheta));

// masses
double m1 = this.getMass();
double m2 = other.getMass();

// new velocities based on mass
double newv1 = ((v1*(m1 - m2)) + 2 * m2 * v2) / (m1 + m2);
double newv2 = ((v2*(m2 - m1)) + 2 * m1 * v1) / (m1 + m2);

// get the speed of the molecule in the y direction (up and down the tangent line, not toward it)
double thisY = MyMath.roundIfClose(this.getVel().getSpeed() * Math.sin(Math.toRadians(thisNewTheta)));
double otherY = MyMath.roundIfClose(other.getVel().getSpeed() * Math.sin(Math.toRadians(otherNewTheta)));

// gets the new direction of the molecules - shown later
double newt1 = getThetaAfterCollision(newv1, thisY, toAdd, true);
double newt2 = getThetaAfterCollision(newv2, otherY, toAdd, false);

// sets directions
this.getVel().setTheta(newt1);
other.getVel().setTheta(newt2);

// gets the new speeds
double thisNewSpeed = MyMath.roundIfClose(Math.sqrt(Math.pow(newv1, 2) + Math.pow(thisY, 2)));
double otherNewSpeed = MyMath.roundIfClose(Math.sqrt(Math.pow(newv2, 2) + Math.pow(otherY, 2)));

// and sets them
this.getVel().setSpeed(thisNewSpeed);
other.getVel().setSpeed(otherNewSpeed);```

And here is the collision angle returning method
java Code:
```double getThetaAfterCollision(double xChange, double yChange, double toAdd, boolean thisMolecule) {
double theta = 0;

if (yChange == 0) { // the molecule is traveling perpendicularly to the tangent line
if (xChange > 0) {
theta = -toAdd; // bounce perpendicularly off the tangent line
} else if (xChange < 0) {
theta = 180 - toAdd; // bounce perpendicularly off the tangent line
} else {
theta = 0;
}
} else {
theta = (Math.toDegrees(Math.atan(xChange / yChange)) - toAdd + 360) % 360;
if (xChange < 0 && yChange != 0) { theta += 180; theta %= 360; }
}

System.out.println("New theta for " + (thisMolecule == true ? "this" : "other") + " molecule: " + theta);
return theta;
}```

My math doesn't look too right. Can anyone help out a bit?
It works a lot of the time (~80%) but sometimes it just does completely wrong things.
Last edited by gimp; May 6th, 2007 at 01:34 PM.
2. No Profile Picture
Contributing User
Devshed God 1st Plane (5500 - 5999 posts)

Join Date
Oct 2000
Location
Back in the real world.
Posts
5,960
Rep Power
195
Originally Posted by gimp
java Code:
```double getThetaAfterCollision(double xChange, double yChange, double toAdd, boolean thisMolecule) {
double theta = 0;

if (yChange == 0) { // the molecule is traveling```
Hi gimp!

I assume yChange is a computed value?

You can't compare floats with "equals" because when computed, they are only nearly equal. This is due to the way computers handle floating point numbers.

You need to use some threshold, usually called epsilon. That is (yChange < ε && yChange >-ε ) with a very small ε (like 0.001).

Not sure if this is the only problem, didn't check any further.

HTH,
M.

• gimp agrees
Last edited by M.Hirsch; May 8th, 2007 at 11:33 AM. Reason: disable smillies
3. java Code:
`double thisNewTheta = (this.getVel().getTheta() + toAdd + 360) % 360;`

what is the +360 for? if getTheta() returns positive numbers then adding 360 will not affect the answer

also why are you rounding so much (roundIfClose()), rounding reduces accuracy, you should deal with the full worked out answers for everything, if you want to round anything then do it in the display portion of the program, i'm especially thinking about how you get the x portions of the vector and use them, for the y portion you decide to round it, and i'm guess your rounding will throw a lot of error into it for large angles

looking at your getThetaAfterCollision() method i would say you problems are that you found about the problems with comparing floats and introduced your rounding function if its close to zero, but close to zero is a valid value, and rounding that will introduce a large error, i would probably check for zero as M.Hirsch suggested, as that looks like what you want

• gimp agrees
4. @Hirsch: Yes, it's computed, and called in the first part. I really don't think it's a problem comparing a double to 0 - I'm only doing it so that atan doesn't freak out (atan cannot have npi as the argument).

@edman: 360 is just to make it look nicer. If it returns the angle as -45, I'd prefer it to be 315.

roundIfClose() is because of slight inaccuracies in the traveling sequence. In other words, collisions don't happen when the distance between them is EXACTLY 2r - it happens when it's right after it, very very close after. I'm not entirely sure how to create a continuous update - instead, it updates in increments (after 10 milliseconds, or so). I'm also not sure if I care enough to do it. So, when I get an answer like 1.0E-15 I want that to be 0, as it damn well should be.

I will try with epsilon though. I don't think that's the problem, though - I've set up certain collisions where it just goes the wrong way, and yChange (delta y) is never 0 or close in those cases (not that I've noticed, yet).
5. It is a problem comparing a computed double to zero, despite the fact that zero can be represented precisely.
6. How so?