- Online Community Forums » Programming Questions » Angles, how i hate them...

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Angles, how i hate them...
Member #1,365
June 2001

NEVER MIND! but let it remain, i do hate angles and trigs

[Insert signature here]

Member #1,509
September 2001

Remeber your friend
Soh Cah Toa
Then you'll never see the end
Dont yah knowa
Sin() is not a sin
cos shows the spirt within
and when you want to know the hypontose
take the square and hand a noose
Pathagragram was a cool guy
too bad he had to die
so next a triangle has you all up in a bunch
open up a bag of chips and take a munch
--I'm a poet :P (and i dident know it)

And they say goldfish have no memory, I guess their lives are much like mine.
And their little plastic castle, its a surprise everytime.

Member #1,134
March 2001


Some     Old     Hippie
Caught   Another Hippie
Tripping On      Acid

There's another with "Old Hags" but I forget it ....

Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Steve Terry
Member #1,989
March 2002


[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. -
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Marty Dill
Member #277
April 2000

That brings back memories ...

Member #119
April 2000

People always mention sohcahtoa or whatever it is but I never learned that one. I guess I learned a different one, which I haven't heard from other people:

Oscar Had A Heap Of Apples:


sin = O/H
cos = A/H
tan = O/A

O = opposite edge
H = hypotenuse
A = adjacent edge

Gillius's Programming --

Thomas Harte
Member #33
April 2000

I hate to put a dampener on things, but the number of times even a program with 'perfect' physics actually calculates the angle between anything is zero. And certainly the number of times any of that stuff they taught you during the first few years of school about soh cah toa isn't very useful in either the real or programming worlds . . .

Member #1,666
April 2001

I found that when I first started programming.. 'soh cah toa' actually made things worse! :P I was trying to do the stuff that was already done for me, then add it here.. subtract it here... and voila! A big mess! ;D

"He who controls the stuffing controls the Universe"

Shawn Hargreaves
The Progenitor
April 2000

I think angles are very rarely a good idea. They are the obvious way to store orientation because they are what you get taught in school, but vectors are almost always easier and more efficient and more flexible. Especially in 3D (it wasn't until I'd been doing commercial games for several months that I figured out how much a pain it was to use angles for everything!) but even in 2D vectors are nice.

If you store all your orientations and positions and speeds as vectors, it becomes incredibly easy to convert between any of them (just a few adds and subtracts). And you can do much more interesting physics type stuff without too much hassle, for instance bouncing off walls is just a dot product to reverse the momentum, plus maybe a multiply if you want to absorb some energy during the collision response. That kind of thing would be a total nightmare to do with an angle+speed type respresentation.

And learn how dot products work: that is the most useful basic operation you can possibly have, as almost anything can be done in terms of it.

A good C++ vector class is highly recommended, so you can add/subtract/scale vectors as simple data types. And overload operators for some of the more useful operations (I use ^ for cross product, | for dot product, and unary ~ for normalize). There's one in my Speedhack entry that you could use as a starting point...

Member #1,365
June 2001

i guess i should learn vectors? point me in a good direction and ill go learn about em

closest i come is an angle and a velocity...

[Insert signature here]

Thomas Harte
Member #33
April 2000

There isn't much to learn about vectors, they are very simple. A vector is an ordered n-tuple. In geometric space, when people say 'vectors' they usually mean something of the form :

(x, y [, z])

Where the components are quantities to move parrallel to the predefined set of axis :

(1, 0 [, 0])
(0, 1 [, 0])
[(0, 0, 1)]

The most interesting thing one can do between two vectors in the general case is the dot, or scalar, product. Which maps two vectors to a scalar, like this :

(a, b [, c]).(d, e [, f]) = a*d + b*e [+ c*f]

The scalar has the property that it is :

|(a, b [, c])||(d, e [, f])|cos(angle between)

Where || are used to mean 'length of'. Which also means that it is a way of finding out how far either vector travels in the direction of the other, the result being in multiples of the length of the other.

There is also the 'cross' product, but this isn't so interesting since it is defined only in 3 and 8 dimensions. It takes two vectors and gives one that is perpendicular to both, by :

(a, b, c)x(d, e, f) = ( (b*f - e*c), (c*d - f*a), (a*e - d*b) )

Finally, commonly people like to make vectors unit length, principly because it makes like easier in the dot product. This is easy, you just get the total vector length (using Pythagoras) and divide each component by it.

And that is nearly all most programmers know about vectors. The only extra bit of information is that it is very useful to store planes (or lines in 2d) in the form 'normal vector & distance from the origin along normal vector', since then you can dot product away without any adaption.

Shawn Hargreaves
The Progenitor
April 2000

2d vector: a pair of values, eg. (x, y)
3d vector: a trio of values, eg. (x, y, z)

So all positions are vectors. Also all directions can be stored as vectors.

Given the points A and B, the direction from A to B is the vector B-A. Call this direction vector D. Then you can start doing basic algebra with them, eg. B = A+D (this is where the C++ vector class comes in handy as it lets you write such things directly).

The direction vector D contains both direction and distance information. You can extract the distance using Pythagoras:

dist = d.magnitude() = sqrt(d.x*d.x + d.y*d.y)

Once you have that, you can normalize d:

d.x /= dist;
d.y /= dist;

Or if you have good C++ classes:

d /= dist; or
d.normalize(); or
d = ~d;

This will give you a unit vector, which holds only direction information. It points in the same direction as the original D, but has length=1. Unit vectors are especially handy for using with dot products...

The dot product, a | b = a.x*b.x + a.y*b.y. If a and b are both unit vectors, this gives the cosine of the angle between them. If only a is a unit vector, this tells you how much of vector b lies along the direction of a. Which is a lot more useful than it might seem! It will be zero if the lines are at right angles, positive if they are in the same direction, negative if they are in opposite directions.

An example of a simple vector based physics system:

Vector pos(0, 0);
Vector vel(0, 0);
Vector dir(0, 0);

// add velocity
pos += vel;

// apply air resistance
vel *= 0.9;

// apply gravity
const Vector gravity(0, 0.1);
vel += gravity;

// apply thrust
if (firing thruster)
vel += dir;

// turn by angle
dir = Vector(dir.x*cos(ang) - dir.y*sin(ang),
dir.y*cos(ang) + dir.x*sin(ang));

Which is probably very similar to stuff you are already doing, as a lot of vector math is just common sense!

Let's add a bit of collision. Assume we have a wall defined by an infinitely long line (if the line has fixed ends the same principle applies but needs a few extra checks). You can store this line as a vector holding any arbitrary point on the line, and another unit vector holding the normal of the line (the normal is just a vector at 90 degrees to the direction of the line).

Say L is a point on the line, N is the normal, and you want to check for collision of a point P. Work out:

// direction from point to line
Vector d = L - P;

// dot the direction with the line normal
float dot = d | N;

// which side of the line are we on?
if (dot > 0)
// collision!

Ok, let's try bouncing off the line, rather than just stopping dead after we hit it. For that, we want to reverse the amount of our velocity that was heading towards the surface, but leave the amount of velocity that was sideways on to the surface alone. Really easy to do with dot products:

// how much velocity was towards the surface?
float dot = vel | N;

// recoil away from the surface by that amount
Vector recoil = dot * N;

// apply recoil. One of it will cancel out
// the movement towards the surface, and two
// of it makes us bounce back away from it.
vel -= recoil*2;

You can really easily extend this to support non-elastic collisions, where the surface absorbs some amount of your energy. Either change the last line above to:

vel -= recoil*1.5;

to absorb half the energy, or for a surface that also absorbs sideways motion:

vel = (vel-recoil*2) * 0.5;

The really great thing about vectors is that they work pretty much the same in 2d and 3d. Working with angles is ok but sometimes a bit complicated in 2d, but becomes a million times worse if you try to extend it into 3d, while vectors are equally simple in either.

Member #1,365
June 2001

wow :o thats a lot of stuff... yo uthink id be able to pick that crap up easily being in calculus 2, but it seems strange to me...
so tell me this:
i have a character object , and i dont want to use angles any more
do i need to store several vectors for him?
ie. direction, velocity, point?

[Insert signature here]

Damyan Pepper
Member #2,181
April 2002

Yup - I normally store the velocity, the position and the front vector. If you're in 3D then also a right vector. You can then work out an up vector by crossing the front and right.

Be sure that you keep your direction vectors normalised!

Cross products only really make sense in 3D:

vc is the cross product of v1 and v2:

vc.x = v1.y * v2.z - v1.z * v2.y
vc.y = v1.z * v2.x - v1.x * v2.z
vc.z = v1.x * v2.y - v1.y * v2.x

I think it is quite standard to use the ^ operator in C++ for this.

So, (v1 ^ v2) gives you the vector perpendicular to v1 and v2. This only works if v1 and v2 are both normalised.

Shawn Hargreaves
The Progenitor
April 2000

Ignore Damyan. In 3D, sensible people always store the front vector and up vector, and generate the right vector with a cross product. Only a crazy man would suggest storing front and right and regenerating up!

Actually it makes no difference: you could store all three if you wanted. But there is no need as given any two of front, up, and right, you can recalculate the other one whenever needed with a cross product.

The problem with storing all three is that it only makes sense for them to be at right angles to each other (otherwise your object would be in some weird squashed universe with dimensions at funny angles :-) but even if they start out at right angles, over time as you rotate the object, rounding errors are likely to end up with them getting misaligned. So at the end of each frame, it is worth renormalising everything to make sure all your vectors are perpendicular, eg, if you store front and up:

front = ~front;
Vector right = front ^ up;
up = ~(right ^ front);

(assuming ~ = normalize and ^ = cross product)

This will give you a new up vector that has been corrected to make sure it is exactly 90 degrees from the front vector.

Incidentally, Damyan is also wrong in saying that vectors have to be normalised for cross products to work: it's just that if they aren't normalized, or if the input vectors aren't 90 from each other, the result won't be a unit vector (so you have to re-normalize it).

Don't you feel stupid now Damyan? :-)

In 2D you don't need any of that: just a single front vector is enough to encode a complete orientation. Plus position, obviously, and maybe velocity.

Thomas Harte
Member #33
April 2000


In 2D you don't need any of that: just a single front vector is enough to encode a complete orientation. Plus position, obviously, and maybe velocity.

A whole post of pettiness for you:

It depends what you want to do. Even in general case engines, you will usually [numerically] integrate acceleration to get velocity, and integrate that to get position. Note to those scared of maths - this :

vel += acc;
pos += vel;

is actually an approximate integration using the same simple observation as Euler made many centuries ago about graphs, but taking the 'step size', often called h, to be 1.

However, my childishness makes me point out - there is no point storing velocity if you don't intend to make your objects move, and if they are moving you are probably storing a list of the forces acting upon the body also. So thats something else you want to store.

Damyan Pepper
Member #2,181
April 2002

:-[ I guess I've had one of those days, Shawn.

BTW, are you sure that cupid is frame rate compensated?

Also, on the subject of euler integration, some of you may be interested to have a look at the string code in cupid, and grabbing hold of the paper that is linked at the top of heart_trails.cpp that describes a really neat and simple way of doing physics without all the tedious mucking around with forces, inertia tensors and other nastiness.

Member #1,365
June 2001

wow, im really confused... id probably get it if you showe dme an example of these few things( all i do is 2-D im not concerned with 3d yet, all it does is confuse me :) :

if i have position vector A and velocity vector B, to move him would be A+B, the result of which is my new position?

how would i go about rotating a vector? say i have a sprite pointing straight up and i want him to rotate 128 (fixed numbers :) ) degress ?

how would i clip a vector agaisnt a vector? like tell where, and when a collsion occured?

what does normalizing do, why would i want to do it, and how is it done, and how does it effect the numbers stored in the vectors?

tehre wre more quations .. confusions i mean? that i may need answers for :) thanks for he hwelp though

[Insert signature here]

Free Market Evangelist
September 2000

Damyan: That link 404s on me :(
You wouldn't happen to have the paper on hand (or at least another link to it)?

- Bob
[ -- All my signature links are 404 -- ]

Peter Wang
Member #23
April 2000

I'll answer the easy one :-) Normalising is turning a vector into a unit vector, i.e. a vector of length 1. (divide each component of vector v with the magnitude of v) If that's wrong, I'll look like a fool.

This thread has been really useful. If I had read this last year maybe I would have paid attention in class.

Member #2,049
March 2002

Member #1,365
June 2001

wow, that stuff seems to be over my head :(

[Insert signature here]

Damyan Pepper
Member #2,181
April 2002

It would be worth reading through it - it does end up giving some source code that pretty much works.

If you have position A and velocity B, then yes, A+B gives you the new position. This is basically Euler integration - so if you read anything that goes on about Euler integration then don't be scared. (I was so pleased when I realised that!)

To rotate an arbitrary vector, F by ang degrees:

newF.x = F.x * cos(ang) - F.y * sin(ang)
newF.y = F.y * cos(ang) + F.x * sin(ang)

I'd also normalise it after that, just to be sure...although Shawn'll probably complain that I normalise too much!

Shawn has also just pointed out that another neat way to deal with rotations is to just add some amount of the right vector and normalise again:

newF = ~(F + right*0.2);

This is harder to control though!

I'm not sure what you mean by clipping a vector against a vector. There's a whole bunch of collision detection stuff in cupid, colliding circles against lines etc. that might be useful.

Shawn Hargreaves
The Progenitor
April 2000

Thomas Harte writes:
> It depends what you want to do. Even in
> general case engines, you will usually
> [numerically] integrate acceleration to
> get velocity, and integrate that to get
> position.

But acceleration is often a constant, so it's not part of the data you'd bother storing. Even when it is variable, acceleration rarely has state that needs to persist from frame to frame, eg. in MotoGP the acceleration force is a function of the engine revs, torque, current gear, current speed, and so on.

> Note to those scared of maths - this :
> vel += acc;
> pos += vel;
> is actually an approximate integration

I hate the term 'integration' because it makes the issue seem far more complicated than it really is! It's pretty rare for you to need anything more than the simple Euler integration you give above, and although this is of course just a linear approximation of a proper calculus integration, it's a lot easier to visualise if you just think of it as adding a load of forces together!

> However, my childishness makes me point
> out - there is no point storing velocity
> if you don't intend to make your objects
> move

Very true :-)


Damyan Pepper writes:
> BTW, are you sure that cupid is frame rate
> compensated?


(to explain: about halfway through Saturday George complained that the ship turned more slowly if you were near the bottom of the level. After trying to blame Damyan for it, it turned out that I had very carefully adjusted the render function to run at a fixed framerate, while the update just ran as fast as possible in whatever time was left. Oops!)


Peter Wang writes:
> This thread has been really useful. If
> I had read this last year maybe I would
> have paid attention in class.

Nobody seems to teach vectors properly. Or at least not in ways that make them seem useful for solving real world problems.

When someone says "a dot b gives the cosine of the angle between the two vectors, as long as they are unit vectors", that doesn't seem especially handy. When I first heard this I just filed it away as "I'll remember that in case I ever need to know the cosine of the angle between two unit vectors". And I never needed to know that.

It is only when you realise that dot product tells you how much of one vector lies in the direction of another that it starts to be useful. It turns out that about 90% of what you do in games and graphics can be expressed in terms of dot products, which is why things like the NVidia vertex shader processor or PS2 vector units are basically just really fast dot product evaluators!

When I first started working at Probe, I was doing some flags in the crowd for an N64 football game, and spent about three days working out loads of trig calls to rotate a polygon so it would always face towards the camera. I got it working in the end, but it required about 10 sin/cos calls, two tangents, one inverse tangent, multiple square roots, and a huge amount of head scratching. I couldn't decide whether to be pissed off or incredibly relieved when I started on ExtremeG, and Ash (the lead coder) explained how you can do the same thing using just a couple of dot products and one cross product!

Matt Smith
Member #783
November 2000

Ash Hogg? say Hi from me :)

 1   2 

Go to: