views:

107

answers:

3

I'm working on a (rather) simple 2D project in OpenGL. It's some sort of asteroids clone.

The ship is basically an isosceles triangle of height H, with the base have a length of H/2.

The way I've been doing it so far is simply storing the center point (CP) of the triangle and then calculating the final vertex positions on the fly. The 'point' of the ship is (vectors are x,y) the (CP.x, CP.y + H/2). The other two points are (CP.X - H/4, CP.Y - H/2) and (CP.X + H/4, CP.Y - H/2).

To get the ship facing the right direction, I first call glRotate on the current rotation angle.

This part is working fine however I'm running into issues with collision detection. Currently I'm trying to implement triangle-plane collision detection however to do that, I first need to figure out the actual points of the ship vertices after rotation. I've tried using trigonometry to calculate these points, however I've failed.

The way I've attempted is was to use the cosine rule to find the distance between the unrotated triangle and the triangle after rotation. To give an example, the following is how I've tried to calculate the 'pointy' vertex position after rotation:

//pA is a vector struct holding the position of the pointy vertex of the ship (centerPoint.x, centerPoint.y + height / 2)

//Distance between pA and the rotated pointy vertex - using the cosine rule
float distance = sqrt((2 * pow(size / 2, 2)) * (1 - cosf(rotAngle)));

//The angle to the calculated point
float newPointAngle = (M_PI / 2) - rotAngle;
float xDif = distance * cosf(newPointAngle);
float yDif = distance * sinf(newPointAngle);

//Actually drawing the new point
glVertex2f(pA.x - xDif, pA.y - yDif);

Any idea what I could be doing wrong?

+2  A: 

Rotation calculations need to be centered at the origin, so you may need to first translate the coordinates so the center of rotation is aligned with the origin.

Then use the new points to get the rotated coordinates:

x1 = x cos f - y sin f
y1 = y cos f + x sin f

where f is the angle of rotation.

Then you translate the new coordinates back to where you started (the reverse of the first translation.

Check out this article for some diagrams and clarification.

JoshD
+1  A: 

Calculating the new points is relatively simple. Assume the x and y are the coordinates of a certain point on the triangle (i.e. the vertices) relative to the point of rotation (or center).

You must convert the coords to a square distance and angle component:

float dist, angle;
dist = (x*x) + (y*y);
angle = atan(abs(x)/abs(y));
// a little more code is required for the different quadrants that the angle could be in.

Then rotate:

angle+=rotation_angle;

Then convert back:

new_x = sqrt(dist)*sin(angle*pi/180);
new_y = sqrt(dist)*cos(angle*pi/180);
Alexander Rafferty
Using atan like that will cause problems with angles greater than 90 degrees or less than -90 degrees.
JoshD
That's the purpose of the extra little bit of code I said would be needed to make it work.
Alexander Rafferty
A: 

Thanks for the help guys but I think those explanations were a bit too technical for me. Nonetheless you made it clear to me that there's no special case for a triangle (which, in hindsight, I should've known) so I tried my hand at searching and after trying a few methods, found one which worked for me.

The post from estain at the GameDev forums did the trick. To quote his post (sorry for the c&p but may be useful for someone else who runs into a similar issue):

Without getting to heavily into general solutions and maths (as the above posters and lots of articles have covered this already), I could give you an example on how to solve the problem "rotating a point A around point B by C degrees".

Now. First of all, as I described in the previous post, a point that is on the X axis, L distance from origo, is rotated C degrees around origo by

x = L * cos(C)

y = L * sin(C)

Similarly, the formula for a perpendicular vector is x = -y | y = x, which means that a point that is on the Y axis (again, L from origo) would be rotated by C using the formula

x = - L * sin(C)

y = L * cos(C)

As shown in the above image, the final solution is the sum of the rotations of the projected vectors, so we can derive the formula

x' = x * cos(C) - y * sin(C)

y' = y * cos(C) + x * sin(C)

... but you knew that already, right? problem is, this formula only rotates around origo. So what we need to do is move the coordinate system we're rotating around to origo, rotate and then move back. This can be done quickly with complex numbers or in general solutions with matrices, but we're gonna stick to vector math on this one to keep it simple.

first step; move the origin point.

x' = A.x - B.x

y' = A.y - B.y

second step, perform rotation

x'' = x' * cos(C) - y' * sin(C) = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C)

y'' = y' * cos(C) + x' * sin(C) = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C)

third and final step, move back the coordinate frame

x''' = x'' + B.x = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C) + B.x

y''' = y'' + B.y = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C) + B.y

And presto! we have our rotation formula. I'll give it to you without all those >calculations:

Rotating a point A around point B by angle C

A.x' = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C) + B.x

A.y' = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C) + B.y

If you've been following me here (and I'm a pretty lousy teacher, so sorry if you haven't), you can se that the ordering in which you perform these operations is very important. Try to mix step 3 and 1 and see the difference in the formulae you get.

Good luck and all!

NRaf
I guess you didn't look at the link in my answer. It's mostly the same thing. :)
JoshD