#1
  1. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2005
    Location
    Internet
    Posts
    7,625
    Rep Power
    6089

    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.
    Chat Server Project & Tutorial | WiFi-remote-control sailboat (building) | Joke Thread
    “Rational thinkers deplore the excesses of democracy; it abuses the individual and elevates the mob. The death of Socrates was its finest fruit.”
    Use XXX in a comment to flag something that is bogus but works. Use FIXME to flag something that is bogus and broken. Use TODO to leave yourself reminders. Calling a program finished before all these points are checked off is lazy.
    -Partial Credit: Sun

    If I ask you to redescribe your problem, it's because when you describe issues in detail, you often get a *click* and you suddenly know the solutions.
    Ches Koblents
  2. #2
  3. 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.

    Comments on this post

    • gimp agrees
    Last edited by M.Hirsch; May 8th, 2007 at 11:33 AM. Reason: disable smillies
  4. #3
  5. Trapped on the forums...help
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2003
    Location
    /Users/edman007
    Posts
    4,602
    Rep Power
    910
    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

    Comments on this post

    • gimp agrees
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2005
    Location
    Internet
    Posts
    7,625
    Rep Power
    6089
    @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).
    Chat Server Project & Tutorial | WiFi-remote-control sailboat (building) | Joke Thread
    “Rational thinkers deplore the excesses of democracy; it abuses the individual and elevates the mob. The death of Socrates was its finest fruit.”
    Use XXX in a comment to flag something that is bogus but works. Use FIXME to flag something that is bogus and broken. Use TODO to leave yourself reminders. Calling a program finished before all these points are checked off is lazy.
    -Partial Credit: Sun

    If I ask you to redescribe your problem, it's because when you describe issues in detail, you often get a *click* and you suddenly know the solutions.
    Ches Koblents
  8. #5
  9. Devshed God 1st Plane (5500 - 5999 posts)

    Join Date
    Jun 2005
    Posts
    5,929
    Rep Power
    4857
    It is a problem comparing a computed double to zero, despite the fact that zero can be represented precisely.
  10. #6
  11. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2005
    Location
    Internet
    Posts
    7,625
    Rep Power
    6089
    How so?
    Chat Server Project & Tutorial | WiFi-remote-control sailboat (building) | Joke Thread
    “Rational thinkers deplore the excesses of democracy; it abuses the individual and elevates the mob. The death of Socrates was its finest fruit.”
    Use XXX in a comment to flag something that is bogus but works. Use FIXME to flag something that is bogus and broken. Use TODO to leave yourself reminders. Calling a program finished before all these points are checked off is lazy.
    -Partial Credit: Sun

    If I ask you to redescribe your problem, it's because when you describe issues in detail, you often get a *click* and you suddenly know the solutions.
    Ches Koblents

IMN logo majestic logo threadwatch logo seochat tools logo