Welcome, Guest. Please login or register.

Author Topic: C++ Trigonometry  (Read 5583 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline motorollinTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 8669
    • Show only replies by motorollin
C++ Trigonometry
« on: September 11, 2007, 08:25:39 PM »
I'm trying to calculate an angle given the distances between two objects:

int distx = playerx-x;
int disty = playery-y;
int angle = atan( disty/distx) * (180/3.14159265);
fprintf( stdout, "%d \n",angle );

Where x=100 y=100, playerx=0 and playery=0, the angle returned is 45 which sounds correct. But if the object is put on the opposite side (x=-100, y=-100) then the angle is still 45. What an I doing wrong?

--
moto
Code: [Select]
10  IT\'S THE FINAL COUNTDOWN
20  FOR C = 1 TO 2
30     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NAAAA
40     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NA-NA-NAAAAA
50  NEXT C
60  NA-NA-NAAAA
70  NA-NA NA-NA-NA-NA-NAAAA NAAA-NAAAAAAAAAAA
80  GOTO 10
 

Offline motorollinTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 8669
    • Show only replies by motorollin
Re: C++ Trigonometry
« Reply #1 on: September 11, 2007, 08:29:19 PM »
Also, moving the object to x=100,y=-100 makes the angle -45 degrees.

--
moto
Code: [Select]
10  IT\'S THE FINAL COUNTDOWN
20  FOR C = 1 TO 2
30     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NAAAA
40     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NA-NA-NAAAAA
50  NEXT C
60  NA-NA-NAAAA
70  NA-NA NA-NA-NA-NA-NAAAA NAAA-NAAAAAAAAAAA
80  GOTO 10
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: C++ Trigonometry
« Reply #2 on: September 11, 2007, 08:40:41 PM »
I think atan() has sign ambiguity problems with respect to your needs - it will always return the smallest angle subtended.

Try using atan2(y, x) instead.

-edit-

Also, don't forget: the sort of trig you are doing assumes cartesian coordinate axes. Pixel coordinates, of course, are the opposite way around with respect to the y axis.
int p; // A
 

Offline motorollinTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 8669
    • Show only replies by motorollin
Re: C++ Trigonometry
« Reply #3 on: September 11, 2007, 08:42:58 PM »
Thanks. In atan2(), are y and x the distances between the two points?

--
moto
Code: [Select]
10  IT\'S THE FINAL COUNTDOWN
20  FOR C = 1 TO 2
30     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NAAAA
40     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NA-NA-NAAAAA
50  NEXT C
60  NA-NA-NAAAA
70  NA-NA NA-NA-NA-NA-NAAAA NAAA-NAAAAAAAAAAA
80  GOTO 10
 

Offline motorollinTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 8669
    • Show only replies by motorollin
Re: C++ Trigonometry
« Reply #4 on: September 11, 2007, 08:45:37 PM »
Yeah! atan2( disty, distx ) works :-D

Cheers Karlos

--
moto
Code: [Select]
10  IT\'S THE FINAL COUNTDOWN
20  FOR C = 1 TO 2
30     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NAAAA
40     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NA-NA-NAAAAA
50  NEXT C
60  NA-NA-NAAAA
70  NA-NA NA-NA-NA-NA-NAAAA NAAA-NAAAAAAAAAAA
80  GOTO 10
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: C++ Trigonometry
« Reply #5 on: September 11, 2007, 08:48:01 PM »
Yes.
int p; // A
 

Offline Boot_WB

  • Hero Member
  • *****
  • Join Date: Feb 2005
  • Posts: 1326
    • Show only replies by Boot_WB
    • http://www.hullchimneyservices.co.uk
Re: C++ Trigonometry
« Reply #6 on: September 11, 2007, 11:03:28 PM »
Quote

motorollin wrote:
I'm trying to calculate an angle given the distances between two objects:

int distx = playerx-x;
int disty = playery-y;
int angle = atan( disty/distx) * (180/3.14159265);
fprintf( stdout, "%d \n",angle );

Where x=100 y=100, playerx=0 and playery=0, the angle returned is 45 which sounds correct. But if the object is put on the opposite side (x=-100, y=-100) then the angle is still 45. What an I doing wrong?

--
moto


This is due to the nature of tan, and the way it is generally handled.

Given that the convention of angles existing thus:
















And the graph of tan looks (roughly) like this:























The Tan of (for example) 45 degrees (tan(45)) = 1, but the tan of 180+45 degrees (Tan(225)) also = 1.
Consequently when doing an inverse tan of this value (arctan(1)) there are two possible angles which could be returned (45 and 225).
Conventionally, calculators will return values between -90 and 90 degrees for sin and tan, and 90 - 180 degrees for cos (both sin and cos have similar, albeit different, properties with regard to the full 360 degree range).
One way out would be to set up a series of "if" statements to compensate for this, adding the appropriate multiples of 90 degrees depending on which quadrant of the circle your object is located in.

I see you've already solved it with Karlos's help, but thought you might like the insight into why this occurs. :-)
Mac Mini G4 (1.5GHz, 64MB VRam, 1GB Ram): MorphOS 3.6
Powerbook 5.8 (15", 1.67GHz, 128MB VRam, 1GB Ram): MorphOS 3.8.

Windows-free since 2011-2014 (Damn you Netflix!)
 

Offline Boot_WB

  • Hero Member
  • *****
  • Join Date: Feb 2005
  • Posts: 1326
    • Show only replies by Boot_WB
    • http://www.hullchimneyservices.co.uk
Re: C++ Trigonometry
« Reply #7 on: September 11, 2007, 11:06:53 PM »
Just noticed - a topic on C++ Trigonometry, and only 14 people have viewed it!
Call yourselves geeks? :lol:
Mac Mini G4 (1.5GHz, 64MB VRam, 1GB Ram): MorphOS 3.6
Powerbook 5.8 (15", 1.67GHz, 128MB VRam, 1GB Ram): MorphOS 3.8.

Windows-free since 2011-2014 (Damn you Netflix!)
 

Offline motorollinTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 8669
    • Show only replies by motorollin
Re: C++ Trigonometry
« Reply #8 on: September 12, 2007, 08:00:47 AM »
Thanks Boot_WB, very interesting. I did consider calculating which quadrant the object is in and adding a multiple of 90 degrees to compensate, but fortunately atan2(x,y) does the hard work for me.

Now, here's another problem. The following code is supposed to move an object towards the player:

    //Find the angle required to move towards the player
    int distx = playerx-x;
    int disty = playery-y;
    int angle = atan2( disty, distx) * 57.29578;

    //Set the velocities
    dx = seekerspeed * cos(angle);
    dy = seekerspeed * sin(angle);

    //Move
    x+=dx;
    y+=dy;


As you can see in this Quicktime video, the effects aren't quite as desired. The enemy stops when it gets close to the player instead of attempting to collide with it, and if the player moves the enemy actually seems to move away from it!

--
moto
Code: [Select]
10  IT\'S THE FINAL COUNTDOWN
20  FOR C = 1 TO 2
30     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NAAAA
40     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NA-NA-NAAAAA
50  NEXT C
60  NA-NA-NAAAA
70  NA-NA NA-NA-NA-NA-NAAAA NAAA-NAAAAAAAAAAA
80  GOTO 10
 

Offline motorollinTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 8669
    • Show only replies by motorollin
Re: C++ Trigonometry
« Reply #9 on: September 12, 2007, 08:20:31 AM »
Someone on another forum has solved this for me. The  "* 57.29578" shouldn't be there because cos() and sin() take radians, not degrees.

--
moto
Code: [Select]
10  IT\'S THE FINAL COUNTDOWN
20  FOR C = 1 TO 2
30     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NAAAA
40     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NA-NA-NAAAAA
50  NEXT C
60  NA-NA-NAAAA
70  NA-NA NA-NA-NA-NA-NAAAA NAAA-NAAAAAAAAAAA
80  GOTO 10
 

Offline Cymric

  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 1031
    • Show only replies by Cymric
Re: C++ Trigonometry
« Reply #10 on: September 12, 2007, 08:29:36 AM »
I suggest you remove the '* 57.29578' bit for this part of the program. cos() and sin() require an argument in radians, not degrees. Oh, and please, do write 'double angle = ...'; angles are not integers :-). Then, to avoid those nasty type promotion rules of C++ noone---not even Karlos---can properly remember, I suggest you code as follows:

---------------------

double dx, dy, seekerspeed = SOME_DOUBLE_VAL;
double distx = playerx - x;
double disty = playery - y;
double angle = atan2(disty, distx);

dx = seekerspeed * cos(angle);
dy = seekerspeed * sin(angle);

x = x + (int)dx;
y = y + (int)dy;

----------------------

This has the advantage of keeping everything double which needs to be double right up to the point where it needs to become an integer. It's probably too C-like, but I like it this way anwyay. And I would code it in such a way that things were single rather than double, saves a lot of computational effort. Unfortunately, things are a bit iffy with the linker libraries, which sometime promote everything to double just the same.

You should also expect quite a lot of jittery behaviour when the seeker is near the target, as the number of possible directions the seeker can take is limited to a maximum of 8. A better and smoother result is obtained if you do all calculations of seeker and target movement in floating point (either free or fixed), and then translate those to screen coordinates only when you need to draw them. A little fudging is probably required to avoid exclamations of 'I WAS MILES AWAY FROM THAT BLASTED THING, ()&*)&U_&U_#Q!'
Some people say that cats are sneaky, evil and cruel. True, and they have many other fine qualities as well.
 

Offline motorollinTopic starter

  • Hero Member
  • *****
  • Join Date: Nov 2005
  • Posts: 8669
    • Show only replies by motorollin
Re: C++ Trigonometry
« Reply #11 on: September 12, 2007, 12:09:24 PM »
Actually I am now using this:

int distx = playerx-x;
int disty = playery-y;
int dist=sqrt(distx*distx+disty*disty);

dx=speed*distx/dist;
dy=speed*disty/dist;



This is much faster, since floating point maths and trig is very slow on the GP2X (no FPU so all float operations are done in software). Also this code seems to result in smoother and more accurate motion.

--
moto
Code: [Select]
10  IT\'S THE FINAL COUNTDOWN
20  FOR C = 1 TO 2
30     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NAAAA
40     DA-NA-NAAAA-NAAAA DA-NA-NA-NA-NA-NA-NAAAAA
50  NEXT C
60  NA-NA-NAAAA
70  NA-NA NA-NA-NA-NA-NAAAA NAAA-NAAAAAAAAAAA
80  GOTO 10
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show only replies by Karlos
Re: C++ Trigonometry
« Reply #12 on: September 12, 2007, 01:29:59 PM »
If you have no FPU, the sqrt() call is still a killer though. If you are using integer only, it might be worth looking to see if there are any approximation methods for "nearest integer root" that don't rely on sqrt() calls at all.

Also, as I've suggested before, if you want a balance of precision and performance, consider using fixed point maths. You can easily write a concrete FixedPoint class that wraps a single 32-bit integer and have it support, say 16.16 fixed point format. You could provide all the standard arithmetic operator methods for it.
int p; // A