SFML community forums

Help => Graphics => Topic started by: lazerblade on October 21, 2011, 09:09:14 pm

Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 21, 2011, 09:09:14 pm
Yes, it's this question again. The reason I'm asking, despite the fact that there are 100 answers to be found on Google, is that they all revolve around atan2(). While atan2() is an awesome function, it's also apparently ineffective under certain circumstances.

All of this will be explained. This is my current code:

Code: [Select]
float angleBetweenVectors(sf::Vector2f a, sf::Vector2f b)
{
return 57.2957795f * atan2(b.y - a.y, b.x - a.x);
}


I take this, use it to rotate a missile sprite toward the mouse cursor, and then give it forward velocity. The problem is that the rotation is bit off for any angle not divisible by 45. In order to further prove my point, I've constructed a console program which should return a rotation of 22.5 degrees, because the ratio of x:y is 1:2. This gives me incorrect output. The code:


Code: [Select]
#include <iostream>
#include <math.h>
using namespace std;

int main(void)
{
  // the parameters to atan2() are precalculated distances,
  // so it should work
  cout << "The rotation is: " << (57.2957795f * atan2(5,10)) << \
   ", but it shouldn't be.\n";

  return 0;
}


And the output is: "The rotation is: 26.5651, but it shouldn't be." So either I'm misinterpreting how to use of atan2(), or it's just wrong. The assumption I'm making is that I'm misinterpreting/misusing it. Anybody know how to do this properly?
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: OniLinkPlus on October 21, 2011, 09:25:10 pm
You... don't understand angles very well, do you? If the ratio of x:y is 1:2, that's an angle of 26.6 degrees, like your program says.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: Nexus on October 21, 2011, 09:30:38 pm
Quote from: "lazerblade"
I've constructed a console program which should return a rotation of 22.5 degrees, because the ratio of x:y is 1:2.
Here is your mistake, the angle is not 22.5°. Otherwise, tan(22.5°) would have to be 5/10 = 0.5.

I have implemented a function to get the signed angle between two vectors in my library, namely thor::Angle() (http://www.bromeon.ch/thor/v1.1/doc/_vector_algebra2_d_8hpp.html), you could use it directly if you wanted. Even without linking the library ;)
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 21, 2011, 09:31:17 pm
Quote from: "OniLink10"
You... don't understand angles very well, do you? Is the ratio of x:y is 1:2, that's an angle of 26.6 degrees, like your program says.


I was afraid I was doing something stupid like that. I'm having trouble coming up with a good way to show the problem from a simple console application. Examples aside, shouldn't my angleBetweenVectors() function return a proper value? If not, I need to figure out why. If so, that means I should look elsewhere in my program for the bug. That's why being sure about whether or not this function works is important.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: Nexus on October 21, 2011, 09:39:45 pm
You are calculating the polar angle of the difference vector b - a. Expressed with my functions this would be PolarAngle(b - a).

But I think you rather want to know how much a has to be rotated to cover b, that would be PolarAngle(b) - PolarAngle(a) with handling of correct wraparound or just Angle(a, b).

Have you seen my upper post?
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 21, 2011, 09:46:20 pm
Quote from: "Nexus"
You are calculating the polar angle of the difference vector b - a. Expressed with my functions this would be PolarAngle(b - a).

But I think you rather want to know how much a has to be rotated to cover b, that would be PolarAngle(b) - PolarAngle(a) with handling of correct wraparound or just Angle(a, b).

Have you seen my upper post?


Yes, but I'm having a little trouble finding the implementation. I only see the declaration in the .hpp file.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 21, 2011, 10:31:39 pm
Found implementation and tried it out. Now it's even more erradic. I'm probably using it wrong. New code:

Code: [Select]
//  (180 / PI = 57.2957795)
float angleBetweenVectors(sf::Vector2f lhs, sf::Vector2f rhs)
{
    return 57.2957795f * atan2((lhs.x * rhs.y) - (lhs.y * rhs.x), (lhs.x * rhs.x) + (lhs.y * rhs.y));
}
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: sbroadfoot90 on October 21, 2011, 11:31:29 pm
Dude, it's not the programming you have wrong. It's the maths. You're trying to do the wrong thing... You need something like this

Code: [Select]

float angleBetweenVectors(sf::Vector2f lhs, sf::Vector2f rhs)
{
    return 57.2957795f * (atan2(lhs.x, lhs.y) - atan2(rhs.x, rhs.y));
}


Next time draw a diagram and work out the formula properly instead of trying to copy and paste things from tutorials. Nexus even told you what to do and instead of listening, you randomly multiplied the x and y components of the vectors together and shoved them into a function. Just take a step back and think about what you are doing.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 22, 2011, 12:05:11 am
Quote from: "sbroadfoot90"
Dude, it's not the programming you have wrong. It's the maths. You're trying to do the wrong thing... You need something like this

Code: [Select]

float angleBetweenVectors(sf::Vector2f lhs, sf::Vector2f rhs)
{
    return 57.2957795f * (atan2(lhs.x, lhs.y) - atan2(rhs.x, rhs.y));
}


Next time draw a diagram and work out the formula properly instead of trying to copy and paste things from tutorials. Nexus even told you what to do and instead of listening, you randomly multiplied the x and y components of the vectors together and shoved them into a function. Just take a step back and think about what you are doing.


Actually, those multiplications are an adaption of the code Nexus pointed me to. His code required cross/dot products, which is where that came from. That, and the code you recommend is something I came up with myself and already tried, based on Nexus's instructions. Both what you recommend and what I created from Nexus's code result in the same illogical rotation.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: Nexus on October 22, 2011, 12:13:08 am
Quote from: "sbroadfoot90"
Nexus even told you what to do and instead of listening, you randomly multiplied the x and y components of the vectors together and shoved them into a function.
It's not random, my implementation is as follows. Strange, but I find it quite elegant. And don't ask me how I came to it :D
Code: [Select]
template <typename T>
T Angle(const sf::Vector2<T>& lhs, const sf::Vector2<T>& rhs)
{
assert(lhs != sf::Vector2<T>() && rhs != sf::Vector2<T>());
return TrigonometricTraits<T>::ArcTan2(CrossProduct(lhs, rhs).z, DotProduct(lhs, rhs));
}


Quote from: "lazerblade"
Both what you recommend and what I created from Nexus's code result in the same illogical rotation.
What do you mean with "illogical" rotation? It looks like you don't expect the same behavior as sbroadfoot90 and I do, so you should probably explain what you exactly want to calculate, ideally with an obvious example. To find out what I expect, read the thor::Angle() doc ;)
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 22, 2011, 12:24:32 am
Quote from: "Nexus"
Quote from: "lazerblade"
Both what you recommend and what I created from Nexus's code result in the same illogical rotation.
What do you mean with "illogical" rotation? It looks like you don't expect the same behavior as sbroadfoot90 and I do, so you should probably explain what you exactly want to calculate ;)


Good point. I expect to get back how much rotation an object at vector lhs would need in order to face an object at vector rhs, where both of these objects have the center set as half their size. What I'm getting back is... hard to explain. Screenshot thumbnails anyone?

(http://picturestack.com/235/721/MRYscreenshotkUS.th.jpg) (http://picturestack.com/235/721/MRYscreenshotkUS.png)

(http://picturestack.com/235/721/bX2screenshotyIl.th.jpg) (http://picturestack.com/235/721/bX2screenshotyIl.png)

(http://picturestack.com/235/721/olQscreenshotboC.th.jpg) (http://picturestack.com/235/721/olQscreenshotboC.png)

I tried to take screenshots that would give a good idea of how the rotation is turning out, but these don't exactly describe it perfectly.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: Nexus on October 22, 2011, 12:35:25 am
What do you mean with "at vector rhs/lhs"? You cannot describe position and orientation with a single vector, maybe this is your problem.

But given a spaceship at position p with velocity v and the mouse cursor at position q, you can find out the rotation needed for the spaceship to face the cursor like this:
Code: [Select]
thor::Angle(v, q - p)
q - p is the direction vector from the spaceship towards the cursor. Draw it on paper to imagine it better :)
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 22, 2011, 01:31:32 am
Quote from: "Nexus"
What do you mean with "at vector rhs/lhs"? You cannot describe position and orientation with a single vector, maybe this is your problem.

That's just it. I don't care what the ship's orientation is.

Quote from: "Nexus"

But given a spaceship at position p with velocity v and the mouse cursor at position q, you can find out the rotation needed for the spaceship to face the cursor like this:
Code: [Select]
thor::Angle(v, q - p)
q - p is the direction vector from the spaceship towards the cursor. Draw it on paper to imagine it better :)


Ah yes, I understand. From when I first encountered this bug, I've filled about five pages with my fundamental understanding of trig now, and I think I'm starting to get the idea. This almost worked, but then I was quite irked to find that it has the same problem as my original function.

To explain more perfectly what is happening, I will use more screenshots.

(http://picturestack.com/239/729/EY6screenshottUn.th.jpg) (http://picturestack.com/239/729/EY6screenshottUn.png)

As you can see, any angle divisible by 45 degrees (or almost,) is good (enough). However...

(http://picturestack.com/239/701/yYkscreenshotmlA.th.jpg) (http://picturestack.com/239/701/yYkscreenshotmlA.png)

As I leave that rotation area, the rotation starts to get messed up.

If the rotation should 100% be working, that means the only place left for the problem is my local motion code. I can provide and explain it if need be.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 22, 2011, 01:55:23 am
P.S:

It's probably also quite important to note that I have to negate the angle I get from the function and then subtract 180 degrees from it in order to make it behave as it does. Otherwise the rotation is 180 degrees of and backwards.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: sbroadfoot90 on October 23, 2011, 07:11:49 am
Reading through all your posts, you kinda never really explain what sort of behaviour you want. Everything you say is really confusing. Perhaps you should just start over, draw a simple diagram and let us know what you want to do.

This is not a programming problem, it's a maths problem.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 23, 2011, 09:48:33 pm
Quote from: "sbroadfoot90"
Reading through all your posts, you kinda never really explain what sort of behaviour you want. Everything you say is really confusing. Perhaps you should just start over, draw a simple diagram and let us know what you want to do.

This is not a programming problem, it's a maths problem.


Well, I believe I already stated quite clearly that I have drawn this out many times over. If you need a diagram, I can provide one. I took the time to draw this up in GIMP:

(http://picturestack.com/398/321/OhwthetaNpx.th.jpg) (http://picturestack.com/398/321/OhwthetaNpx.png)

Given an object centered at point A, and given a point B, determine Theta, or what rotation an object centered at A would need in order to face B.

My solution was the arctangent of D over C, plus compensation for quadrant and special cases. However, I learned about atan2() which does quadrants, division, and special cases for you, which is why I'm using it. I then multiply my solution by 180 over PI in order to convert to degrees.

I expect to get back theta in degrees. I then expect this rotation be set for an object centered at A, causing it to face B.

If the following function should be doing this, that means the bug is elsewhere in my code. An explanation of why I'm doing it wrong, or a clarification that it should be working are both useful to me.


Code: [Select]
float angleBetweenVectors(sf::Vector2f a, sf::Vector2f b)
{
   return 57.2957795f * atan2(b.y - a.y, b.x - a.x);
}



If you need me to clarify anything, or if you have any additional questions, just say so.
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: OniLinkPlus on October 24, 2011, 12:19:13 am
That should be exactly correct... if you expect the rotations to go counterclockwise. However, I think SFML2 was recently changed to make angles go clockwise, so you'll have to compensate with theta_final = 360-theta
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 24, 2011, 12:25:41 am
Quote from: "OniLink10"
That should be exactly correct... if you expect the rotations to go counterclockwise. However, I think SFML2 was recently changed to make angles go clockwise, so you'll have to compensate with theta_final = 360-theta


Thank you very much. I shall hunt for the bug elsewhere. You probably understand that knowing where a bug isn't, is almost as useful as knowing where a bug is. You have all been quite helpful, so I extend my gratitude. :D
Title: [SOLVED] atan2 ineffective when Rotating x to face y?
Post by: lazerblade on October 26, 2011, 10:07:44 pm
I finally managed to fix the bug. Because you confirmed that the my rotation function, I was able to look for it in the one other place I thought it might be, which was the local translation function.

It was really a relief to fix this bug after musing over it for about a month.