Problem with sin cosine
blargmob

Howdy,

I read the post about "how to make an object move in the direction its pointing" and clicked on the link the directed me to an article about this kind of stuff becuase I also had that problem. So I read the article and noticed that I could pass a radian to the "sin()" and "cos()" functions, than multiply the return by the length of the velocity vector. But in order to make this work for me, I had to first convert the allegro degrees (256) of my object into normal degrees (360), than find the radian of the result and pass the final result to the two functions. This worked, but as I read further on, I noticed that "fsin()" and "fcos()" accepted allegro degrees as their parameters, I tried this and it didn't work.....any suggestions?:-/

ImLeftFooted
Quote:

I tried this and it didn't work.....any suggestions?:-/

Yes actually, I suggest you post a small (ie <15 lines) bit of code that demonstrates your problem.

LennyLen
Quote:

but as I read further on, I noticed that "fsin()" and "fcos()" accepted allegro degrees as their parameters, I tried this and it didn't work.....any suggestions?

What do you mean by "didn't work?" And were you actually using the correct function names, which are fixsin() and fixcos()? Here's the manual entry for fixsin() so you can see how it should be used.

By the way, for modern computers with fast FPUs, using the fixed versions may actually be slower than their floating point counterparts.

blargmob

Well, the article said the "fsin()" and "fcos()" are the function names. I compile with no errors but when I run the program some super - duper - oober high number is produced. Also, when I try to declare the angle as "fixed" my compiler returns an error that says "fixed" is invalid and doesn't work.

kazzmir
#include <allegro.h>

fixed f = fsin( itofix( 192 ) ); // 192 is 270 degress

IIRC

blargmob

I tried to pass the angle variable in the "fcos()" and "fsin()" functions using itofix but that didn't work either....help please!.....

kazzmir

Show some friggin code!

blargmob
 int shipangle;
int laserxspeed;
int laseryspeed;
int laserx,lasery;

if(key[KEY_LEFT])
     shipangle++;
if(key[KEY_RIGHT])
     shipangle--;

laserxspeed = 8 * fcos(itofix(shipangle));
laseryspeed = 8 * fsin(itofix(shipangle));

laserx += laserxspeed;
lasery += laseryspeed;

kazzmir
laserxspeed = 8 * fixtof(itofix(shipangle));
laseryspeed = 8 * fixtof(itofix(shipangle));

you have to convert fix back to float/int.

alternatively you can just use cos/sin from the standard math library...

gnolam
Quote:

I had to first convert the allegro degrees (256) of my object into normal degrees (360), than find the radian of the result

... why not just convert directly between Allegro degrees and radians (* π / 128)? :P

Of course, the best course of action is to keep everything in radians and only convert when drawing (* 128 / π). It's by far the easiest, most convenient and readable way. And for Eris's sake, use floats!

1#include <math.h>
2#include <allegro.h>
3 
4float shipangle;
5float laserxspeed, laseryspeed;
6float laserx,lasery;
7 
8void your_function(void)
9{
10 if(key[KEY_LEFT])
11 shipangle += SOME_PROPER_AMOUNT;
12 if(key[KEY_RIGHT])
13 shipangle -= SOME_PROPER_AMOUNT;
14 
15 laserxspeed = 8 * cos(shipangle);
16 laseryspeed = 8 * sin(shipangle);
17 
18 laserx += laserxspeed;
19 lasery += laseryspeed;
20}

void and_then_draw_it(void)
{
 rotate_sprite(buffer, shipsprite, shipx, shipy, ftofix(shipangle*128.0/M_PI));
}

blargmob

But if I stick with float point math I have to do conversions everry time I call sin() and cos().

gnolam

No. Unless you mean the float->double conversion in sin() and cos() (they take and return doubles), but even the overly anal language of C++ does that automagically without complaining. :P
(And, of course, using doubles is always an option as well)

blargmob
gnolam said:

sin() and cos() (they take and return doubles)

No. Sin() and cos() both take radians, not doubles. (unless you meen the radian AS the double) And how come when I declare a variable with "fixed" my compiler returns an error saying that "fixed" isn't a class and doesn't exist?

kazzmir
Quote:

(unless you meen the radian AS the double)

Yes, he meant radians as doubles. radians are a unit of measure, doubles are an encoding of numeric quantity, they are independant of each other. It would be like saying "im going to measure this in meters, not integers".

Quote:

And how come when I declare a variable with "fixed" my compiler returns an error saying that "fixed" isn't a class and doesn't exist?

I forget exactly what causes this, are you including <allegro.h> before you use a fixed variable?

Michael Jensen

Dont use fixed numbers, they're slower than just using doubles and only have a precision from ~-32000 to ~32000 -- just use itofix and ftofix when you need to pass them into allegro functions...

Also as kazzmir said, radians, degrees, and allegro degrees are just units of measure. You can put radians into a double, a float or a fixed, just as well as you can put allegro degrees, or degrees, or meters, miles, or light years in.

A radian is a number between 0 and ~6.2831 (PI*2), a degree is between 0 and 360, and an allegro degree is between 0 and 255 -- they're all the same and you can use basic fractional math to convert between them.

For simplicity sake, you could do the following after including math.h (and make sure you include math.h or cos/sin won't work right):

#include <math.h>
#define DegToRad   PI/180.0f
#define RadToDeg   180.0f/PI

then when you have a variable:

double myvar = 180;  //180 degrees
double length = 10;  //10 pixels

and you need to pass it into cos or sin you can:

//the double "myvar" is in degrees, but cos and sin only take doubles as radians!
double dx = cos(myvar * DegToRad) * length;
double dy = sin(myvar * DegToRad) * length;

8-)

edit:
To convert from degrees to allegro degrees:

#define DegToADeg   256.0f/360.0f
#define ADegToDeg   360.0f/256.0f

And Similarly to convert allegro degrees to radians:

#define ADegToRad   PI/128.0f
#define RadToADeg   128.0f/PI

blargmob

Ah,ha! Thanks. That's what I was looking for. A simply and fast way to convert....thanks. (Can't believe I didn't think of that);)

Tobias Dammers

On the radians / double issue again:
Computers don't know about units (meters, degrees, liters, ampères, kelvins, radians and what have you) when doing calculations; all units are usually implicit, and the function takes something as an argument or returns something that is to be interpreted as a real-world number, the documentation usually specifies what unit is expected. For many things, especially in the computing world, there are conventions that pretty much everybody adheres to: for example, the size of a data chunk is given in bytes (not 12-bit binary words, or words of 57 base-7 digits). For other types of quantities though, such as angles, the matter isn't as clear, since there are several systems being used alongside each other; in this case, there are 3 systems involved, each of which has its advantages:
- Degrees; a full circle equals 360 degrees. This format is very human-friendly, since most commonly used angles are represented as whole numbers (0, 30, 45, 90, 180). It also allows for easy conversion to and from the "clock" system (the system used by sailors and aircraft pilots to indicate relative directions: "Enemy fighters at 3 o'clock!") - each hour equals 30 degrees. OpenGL uses this format.
- Radians; a full circle equals 2 * PI. From the mathematician's point of view, this is the "natural" way of measuring angles, because it defines the angle by the length of an arc on the unit circle. In other words, an angle in radians equals the length of its arc divided by a radius. (It makes more sense when you see it sketched on paper). Also, all the trig functions can be used unchanged for various circle calculations when using radians. Downside is that angles in this format look very un-intuitive, because PI is not a whole number. The C math library (libm) uses radians.
- Allegro degrees; a full circle equals 256. Big advantage is that it allows for a number of speed optimizations, especially on older computers. Wrapping an angle into a full-circle-range, which usually requires a modulo operation, can be optimized to a bitwise-and, because 256 is a power-of-2. It is still quite intuitive (half circle is 128, 1/4 is 64, etc.); downside, though, is that it is incompatible with pretty much all other libraries, including libm.

The unit chosen is independent from the numeric encoding format you use: int, allegro::fixed, float, double, etc.
The issue with allegro's math functions is that they expect fixed-point numbers, but since they are typedef'ed as long ints, C cannot tell the difference, nor convert them correctly for you.

My suggestion is to leave the fixed-point math alone altogether, and do everything using floats (or doubles) and radians. The only point where you really can't avoid 256-based fixed-point values is when you pass angles to allegro's drawing functions, in which case you should just take the float-point value and convert it on-the-fly, like this:

#include <allegro.h>
#include <math.h>
// assuming angle to be a float:
rotate_sprite(screen, sprite, 100, 100, ftofix(angle * 128.0f / M_PI));

X-G
Quote:

#define DegToADeg 256/360
#define ADegToDeg 360/256

Baaaaaaaad idea. 256/360 is an integer division, resulting in an integer. You want 256.0/360.0 or something similar.

Quote:

"Enemy fighters at 3 o'clock!") - each hour equals 15 degrees.

Don't you mean 30 degrees?

Tobias Dammers

'course. 30 degrees. I'll go edit, hehe.

Michael Jensen
Quote:

Baaaaaaaad idea. 256/360 is an integer division, resulting in an integer. You want 256.0/360.0 or something similar.

Thank you, I'll edit that post and put 256.0f/360.0f -- etc, I've been using VB.NET where constants have to be declared with data types and this would work fine, and I've forgotten about some the annoyances of C...

Public Const DegreesToADegrees As Double = 256 / 360

BAF

Even 256/360.0f would do. But, even that looks like horrible coding style to me (DegToADeg sounds like a function, not a constant, which should be const float blah = blah anyway ;)). I'd personally do #define DegToADeg(x) = (x) * 256/360.0f.

Tobias Dammers
Quote:

#define DegToADeg(x) = (x) * 256/360.0f.

What about:

const float DEG2ADEG_FAC = 256.0f / 360.0f;
inline float DegToADeg(float x) { return x * DEG2ADEG_FAC; }

?

BAF

That's even better.

[edit]
Nevermind

ImLeftFooted
Baf said:

I'd personally do #define DegToADeg(x) = (x) * 256/360.0f.

#define DegToADeg(x) = (x) * (256/360.0f)

Makes it easier for a compiler to optimize your code.

Matt Smith

Some versions of <math.h> define fcos() and fsin() as float versions (rather than double) of sin() and cos()

This is why Allegro's fsin() and fcos() have been renamed to fixsin() and fixcos(). It is better to use the new names to avoid confusion (both by you and by your compiler). The old compatability defines may be removed by Allegro 5.0.

ImLeftFooted

How evil... when was sinf / cosf finally decided upon?

Michael Jensen

ack, variable names in ALL CAPITALS! how ugly!

sorry, been sucked into the void of PascalCase, and am very used to it. -- I can tell if it's a variable, property or function by the icon that appears next to it in my autocomplete, and also get the neat little XML comments to the right of it...

God I love VB...

Thread #590290. Printed from Allegro.cc