angles between two vectors

Started by
11 comments, last by apanjocko 20 years, 5 months ago
if you have two vectors (in world space), how do you calculate the x, y (you could skip the z angle) between them? i have done like this, but it seems to sometimes give slightly bad results (looks right most of the time though!):


// first vector, the surface vector of the terrain

_terrainNormal = _terrain.GetTerrainNormal( _x, _y );
	
// second vector

Vector3 tankNormal = new Vector3( 0, 0, -1 );

// calculate angles


_angleX = (float) Math.Asin( ( _terrainNormal.X - tankNormal.X ) / ( Math.Sqrt( _terrainNormal.X * _terrainNormal.X + _terrainNormal.Z * _terrainNormal.Z )) );

_angleY = (float) Math.Asin( ( _terrainNormal.Y - tankNormal.Y ) / ( Math.Sqrt( _terrainNormal.Y * _terrainNormal.Y + _terrainNormal.Z * _terrainNormal.Z )) );



that is, im doing the regular sin(angle) = a/b thingy here, and sort of "projecting" the vectors on a 2d picture. like, when calculating angleX i totally forgett about the difference between the vectors in Y. can you do it like this?

if you can do like that, maybe there is something wrong with the code that get the terrain normal?  this code takes three points and makes it a normal:

   

		public Vector3 GetTerrainNormal( float x, float y )
		{
			Vector3 p1 = Vector3.Empty;
			Vector3 p2 = Vector3.Empty;
			Vector3 p3 = Vector3.Empty;

			float fPosX = (x / _spacing);
			float fPosY = (_terrainHeight-y)/_spacing;

			int posX = (int) fPosX;
			int posY = (int) fPosY;

			float percentX = fPosX - (int) posX;
			float percentY = fPosY - (int) posY;

			float balance = percentX + percentY;

			int triangle;

			if( balance < 1 ) triangle = 0;
			else triangle = 1;

			if( triangle == 0 ) // top left triangle

			{
				p1.X = GridXToTerrainX( posX );
				p1.Y = GridYToTerrainY( posY );
				p1.Z = GridZToTerrainZ( GetGridHeight( posX, posY ) );

				p2.X = GridXToTerrainX( posX + 1 );
				p2.Y = GridYToTerrainY( posY );
				p2.Z = GridZToTerrainZ( GetGridHeight( posX + 1, posY ) );

				p3.X = GridXToTerrainX( posX );
				p3.Y = GridYToTerrainY( posY + 1 );
				p3.Z = GridZToTerrainZ( GetGridHeight( posX, posY + 1 ) );
			}
			else // bottom right triangle

			{
				p1.X = GridXToTerrainX( posX );
				p1.Y = GridYToTerrainY( posY + 1 );
				p1.Z = GridZToTerrainZ( GetGridHeight( posX, posY + 1 ) );

				p2.X = GridXToTerrainX( posX + 1 );
				p2.Y = GridYToTerrainY( posY );
				p2.Z = GridZToTerrainZ( GetGridHeight( posX + 1, posY ) );

				p3.X = GridXToTerrainX( posX + 1 );
				p3.Y = GridYToTerrainY( posY + 1 );
				p3.Z = GridZToTerrainZ( GetGridHeight( posX + 1, posY + 1 ) );
			}

			// TextWriter.AddText( "   triangle: " + triangle );


			// calculate the x and y angles to the terrain plane normal from the tank normal


			Vector3 v12 = p1 - p2;
			Vector3 v13 = p1 - p3;

			Vector3 normalTerrain = Vector3.Cross( v12, v13 );

			// TextWriter.AddText( "   normal: (" + normalTerrain.X + ", " + normalTerrain.Y + ", " + normalTerrain.Z + ")" );


			normalTerrain.Normalize();

			return normalTerrain;
		}


thanks for any help! [edited by - apanjocko on October 23, 2003 9:21:32 PM]
Advertisement
i belive you want to user Arc Tangent instead

angle=convertToDegrees(atan2(deltax,deltay));

where deltax and y are the origin based distances of the vectors
somthing along those lines =)



Raymond Jacobs,

www.EDIGames.com

www.EtherealDarkness.com




Voice your discontent! help stop the flames!

Raymond Jacobs, Owner - Ethereal Darkness Interactive
www.EDIGames.com - EDIGamesCompany - @EDIGames

can you tell me _why_, more exactly? i'm actually really interested thanks...

i mean why use tan, not sin...

[edited by - apanjocko on October 24, 2003 12:14:21 PM]
You can use the dot-product to get the angle


A.B = |A||B|cos(theta)
where theta is the angle between the 2 vectors

also
A.B = (A.x * B.x) + (A.y * B.y)

you know what A and B are so you can solve for theta


cos(theta) = A.B / |A||B|

theta = acos((A.xB.x + A.yB.y) / (sqr(A.x^2 + A.y^2) * sqr(B.x^2 + B.y^2)))
double post

[edited by - apanjocko on October 23, 2003 4:42:20 PM]
well, that''s not what i want,
you see,
you only get one,
i want two angles, x and y - how much to rotate in the world X axis and how much to rotate in the world Y axis... that angle is not helping me in this case
the reason why you use the arctangent2 instead of atan, acos or asin is beacuse of their precision at their limits. atan2 doesn''t have anyh precision limits to it. Read the help files and documentation for a full explaination.

Also, check out this post http://www.gamedev.net/community/forums/topic.asp?topic_id=185968 (recent) in the maths forum. one by minorlogic. It will save me ALOT of explaining hopefully


me off - taking gf out to the hair stylists.
Beer - the love catalystgood ol' homepage
in the post by ob, the code he uses is quite bad (mathematically it is completely correct, but for computational maths and physics (as one of my university subjects was called) it''s not accurate) as
(original)
theta = acos((A.xB.x + A.yB.y) / (sqr(A.x^2 + A.y^2) * sqr(B.x^2 + B.y^2)))

is loosing precision twice NOT including the floating point precision.

calling sqrt twice isn''t good. on really small vectors, it buggers up basically. instead of being accurate to about 12 sig figures (1.xxxx numbers) it will drop to about 10. I can post an example if you wish.
original
theta = acos((Ai*Bi+Aj*Bj+Ak*Bk)/(sqrt(Ai*Ai+Aj*Aj+Ak*Ak)*sqrt(Bi*Bi+Bj*Bj+Bk*Bk)))
rearrange to
theta = acos((Ai*Bi+Aj*Bj+Ak*Bk)/sqrt((Ai*Ai+Aj*Aj+Ak*Ak)*(Bi*Bi+Bj*Bj+Bk*Bk)))

That is one part that will help. The other is that acos (as I said before) looses precision in at different angles.

Bascially, use atan2 like EDI said to get around that

try
atan2l(cross(&v1,&v2).length(),dot(&v1,&v2));

(v1 and v2 are vectors)
(cross is the cross product)
(dot is the dot product)
(length is the length of a vector - in this case the cross product)


Hope I didn''t confuse you too much.

Also - not sure how old you are, but atleast at my university I took up some electives (I''m an engineer) in the physics and maths strands (which may be part of a double latter) called computational maths and physics. there is alot of image manipulation, and alot of maths stuff that you learn, like the one above (quite simple) in it. if your at uni, see if you are able to do some similar electives. my advice anyway.
Beer - the love catalystgood ol' homepage
thank you very much for your time,
i mangaged to solve it with tan, and will as soon as i've read the thread you linked to try it with atan2.

this however does the work with fewer operations:

_angleX = (float) Math.Atan( ( -_terrainNormal.X + tankNormal.X ) / tankNormal.Z );

_angleY = (float) Math.Atan( ( -_terrainNormal.Y + tankNormal.Y ) / tankNormal.Z );

why does everyone have to make it so complicated?

[edited by - apanjocko on October 24, 2003 7:37:49 AM]

[edited by - apanjocko on October 24, 2003 7:39:59 AM]
and another thing
that still only gives me the "absolute" angle between the vectors. i needed two angles projected on the XZ plane and the YZ plane... which my version solves...

[edited by - apanjocko on October 24, 2003 7:41:42 AM]

This topic is closed to new replies.

Advertisement