Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » [Math] Elasticity/Deflection

This thread is locked; no one can reply to it. rss feed Print
[Math] Elasticity/Deflection
ngiacomelli
Member #5,114
October 2004

Quite a few questions here. I'm looking for a very simple way to demonstrate elasticity! Basically, I have a line with two points. I have a spherical object. I want to check the line for a collision with this spherical object. After that, I need a way to find the angle of deflection... and update the spherical objects speed/direction accordingly.

{"name":"590377","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/7\/f7433584382862f02fff33c41ec27b86.png","w":339,"h":235,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/f\/7\/f7433584382862f02fff33c41ec27b86"}590377

DanielH
Member #934
January 2001
avatar

You can use these 3d equations with 2D with some minor adjustments;

Point1 = ( x1, y1, 0 );
Point2 = ( x2, y2, 0 );
Point3 = ( x2, y2, -5 );
Dir = direction Vector
spherePos = center sphere
sphereRadius = As it says
ArbitraryPointOnLine = As it says

Normal to Line:

normal = ( Point2 - Point3 ).crossProduct( Point2 - Point1 );
normal = normal / normal.length; // normalize

Distance to Line: (distance is signed, neg means other side )

distance = normal.dotProduct( spherePos - ArbitraryPointOnLine );

To be a hit then distance is less than sphereRadius.

if ( distance < sphereRadius )
{
    spherePos = spherePos + Dir + this->normal * 2.0 * ( sphereRadius - distance );
}

Zaphos
Member #1,468
August 2001

Quote:

normal = ( Point2 - Point3 ).crossProduct( Point2 - Point1 );

For reference (since a cross product for 2D seems a bit silly), you can find the normal direction of a 2D line like this: Say your line is p1 to p2, and it's direction is d = (p2 - p1) = (dx, dy). Then the normal direction is just (-dy, dx). And the normalized normal, as in the 3D case, may be found by dividing the normal direction by its magnitude.

Quote:

Point3 = ( x2, y2, -5 );

There should be no need to keep around that Point3 variable, or use 3D math functions -- functions that only operate on 2D vectors will work just fine.

Quote:

distance = normal.dotProduct( spherePos - ArbitraryPointOnLine );

Note that to detect a hit on a line segment, which is what it looks like you might be talking about, you also would want to do another dot product to find how far along the line segment the circle lies, and you'd want to do two distance tests against the line segment's endpoints.

Quote:

After that, I need a way to find the angle of deflection... and update the spherical objects speed/direction accordingly.

You probably don't want to use an angle of deflection, or a direction vector, or a speed value. Just track velocity. To adjust the velocity in response to a collision, do something like this:
velocity += (1 + elasticity) * dotProduct(velocity, normal);
Where elasticity is a value between 0 and 1 (inclusive).

I'll note that I really have no idea what math you do or don't understand, so ... if anything doesn't make sense: sorry! Ask for clarifications as needed.
Do you understand the dot product, and why it's useful here?

ngiacomelli
Member #5,114
October 2004

Quote:

I'll note that I really have no idea what math you do or don't understand, so ... if anything doesn't make sense: sorry! Ask for clarifications as needed.
Do you understand the dot product, and why it's useful here?

I'm not so hot when it comes to number work. I understand that the dot product is the result of adding two vectors together. I'm not entirely sure why DanielH is using 3d equations, but I assume I can just remove the references to point3.

I'm definately going to need my hand held for a little. I'm not even sure how I would go about writing the routines to calculate the dot product or cross product.

I don't like to just copy and paste code. So if anyone's willing to (try) and explain this to me, that'd be wonderful.

DanielH
Member #934
January 2001
avatar

Quote:

I'm not entirely sure why DanielH is using 3d equations

That's all I've been working with for the past few weeks.

Zaphos
Member #1,468
August 2001

Quote:

I understand that the dot product is the result of adding two vectors together.

Okay, so for notation I'll refer to a vector as if it had this structure: struct vector { float x; float y; };

The dot product is an operation that takes two vectors and returns a scalar (single number). It takes the components of the vectors, multiplies them together, then sums the results.
In code, that's:

float dot_product(vector a, vector b) {
   return a.x * b.x + a.y * b.y;
}

Abstractly, the dot product is useful because of one interesting identity: dot_product(v, n) = length(v) * length(n) * cos(theta), where theta is the angle between vectors v and n.
(wikipedia has a picture, to help visualize.)
Computing the angle between two vectors, and their lengths, is relatively slow. The dot product is fast and easy. When we use the dot product, we're really using it as a short-cut to get at the length * cos(theta) value.

In our case what we want is really the length(velocity) * cos(theta). We get this out of dot_product(velocity, normal) by ensuring the normal vector is 'normalized' -- has length(n) == 1.
If you'll recall from trigonometry, the length(velocity) * cos(theta) gives the magnitude of velocity in the normal direction, ignoring magnitude of the velocity parallel to the wall.

Now, think back to your collision example. Let's look at a picture:
{"name":"590378","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/1\/717f363fba88a8270ff65394cac2c3a3.png","w":368,"h":187,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/1\/717f363fba88a8270ff65394cac2c3a3"}590378
In this case, the black arrow represents our ball's velocity. This arrow can be broken down into the red arrow (velocity in to the wall) and the green arrow (velocity parallel to the wall).
When you hit a wall, your motion parallel to the wall is unchanged. Your motion 'in to' the wall is either stopped (inelastic collision) or reversed (elastic collision). So we first want to isolate: how much of the motion is 'in to' the wall? As noted above, that's: dot_product(normal, velocity). Now, that's just a length, but we can make that a vector along the correct direction by simply scaling the normal: normal * dot_product(normal, velocity). This should give us a vector equivalent to the red vector*. Now, to change the black vector so it no longer has any motion 'in to' the wall, we can simply subtract the red vector from the black vector. To change the black vector so the ball bounces away from the wall, simply subtract the red vector an additional time.
In code, that's:
velocity += (1 + elasticity) * dot_product(velocity, normal) * normal;

  • you may be concerned that the dot_product(normal, velocity) will be negative, if the normal and velocity are in opposite directions. This is true, but okay, because in this case the normal, when scaled by a negative, will reverse directions and again match the red vector as expected.

Is this making sense?

ngiacomelli
Member #5,114
October 2004

I wrote the following code:

1typedef struct Point2d {
2
3 float x, y;
4
5} Point2d;
6 
7float dotProduct( Point2d p1, Point2d p2 )
8{
9 return sqrt( p1.x * p2.x + p1.y * p2.y );
10}
11 
12 
13int main(void) {
14
15 float len1, len2, mag;
16 Point2d p1, p2, delta, normal;
17
18 p1.x = 100; p1.y = 100;
19 p2.x = 200; p2.y = 200;
20
21 len1 = dotProduct( p1, p1 );
22 len2 = dotProduct( p1, p2 );
23 
24 delta.x = p2.x - p1.x;
25 delta.y = p2.y - p1.y;
26 
27 mag = dotProduct( delta, delta );
28
29 printf("l1: %f | l2: %f | l3: %f", len1, len2, mag);
30
31 return 0;
32
33}

And got these results:

l1: 141.421356 | l2: 200.000000 | l3: 141.421356

Am I on the right track, here?

EDIT: Just saw the new post, reading!

Zaphos
Member #1,468
August 2001

Quote:

return sqrt( p1.x * p2.x + p1.y * p2.y );

That's not a dot product. That's the square root of a dot product.

Quote:

len2 = dotProduct( p1, p2 );

I'm not sure why you think that's len2. Did you mean dotProduct( p2, p2 )?

Quote:

Am I on the right track, here?

Well, I have no idea what you're trying to do, here. The dot product can give the squared magnitude of a vector, if you take the dot product of a vector and itself, because then the cos is equal to 1. But that's not really how you're going to be using the dot product for collision detection and response.

edit: Oh ... was that code in response to DanielH's now-mysteriously-absent post?

ngiacomelli
Member #5,114
October 2004

I was just converting DanielH's equations to code, initially. I'll have to read through your post. I'm terrible when it comes to math. This will take me a while.

DanielH
Member #934
January 2001
avatar

I goofed and erased my goof. I was hoping it wasn't viewed before I erased it.

Go to: