# Vector2.SignedAngle backwards?

Discussion in 'Scripting' started by andyz, Sep 4, 2019.

1. ### andyz

Joined:
Jan 5, 2010
Posts:
2,236
I have a hard time understanding why Vector2.SignedAngle(new Vector2(0, 1f), new Vector2(1, 0f)) returns -90;
This seems to assume +y is down but in the x/y plane of Unity y is up. So why is this?

Even worse if you write it as Vector2.SignedAngle(Vector2.up, Vector2.right) - how does that make sense?

Last edited: Sep 4, 2019
2. ### andyz

Joined:
Jan 5, 2010
Posts:
2,236
No comment on this?

3. ### Baste

Joined:
Jan 24, 2013
Posts:
6,274
I've pointed it out before.

The "solution" is to use Vector3.SignedAngle, and provide the correct "up" axis for your vectors (ie. Vector3.back).

ledshok likes this.
4. ### andyz

Joined:
Jan 5, 2010
Posts:
2,236
OK, good. But I would say the solution is just -Vector2.SignedAngle, but why unity?!

5. ### palex-nx

Joined:
Jul 23, 2018
Posts:
1,745
Because this way positive rotation angle becomes counterclockwise. It should not be a surprise to unity users because rotating object using inspector gives the same result. Positive angle is counterclockwise for any axis.

6. ### andyz

Joined:
Jan 5, 2010
Posts:
2,236
It is not a surprise for 3d but for 2d x/y maths it is, however given sprites and RectTransforms do not even pretend to be 2d for rotation perhaps it is to be expected

7. ### palex-nx

Joined:
Jul 23, 2018
Posts:
1,745
They just ignore Z coordinate and use canvas hierarchy for rendering order. RectTrasform is based on Transform and they using same matrices and coordinate system.

8. ### Baste

Joined:
Jan 24, 2013
Posts:
6,274
It is surprising to Unity users that read the docs for signed angle that very specificly states that it uses a clockwise angle:

I've delivered a bug report, but I'm pretty sure that it's the docs that are wrong here. Also note that it states that the angle is acute, and between -180 and 180, which is also just plain wrong.

Both implementations are valid, but the docs shouldn't state the opposite of what the implementation is! It should also probably know what the maths terms it uses mean!

If starting from scratch, I would've implemented this as a clockwise angle - it makes very little sense to look at a clock sprite from the front, and say that the angle from 12 o' clock to 3 o' clock is -90. I don't think it's worth the breakage that would ensue if the function got "fixed", though, so the docs should just be fixed instead.

andyz and palex-nx like this.
9. ### Double-V

Joined:
Aug 13, 2016
Posts:
21
The docs still say it's clockwise. I ran into this thread exactly because I read them first and then discovered that it's not doing the expected thing and went searching for answers.

10. ### Bunny83

Joined:
Oct 18, 2010
Posts:
3,854
Well, it's true that the docs are wrong. However the normal mathematical definition is counter clockwise. All trig functions are based on counter clockwise rotation and 0° are usually the positive x axis. In the case of SignedAngle we specify the reference ourselfs. So doing "Vector2.SignedAngle(Vector2.up, Vector2.right)" it should return -90 since that's a clockwise rotation.

You get the same behaviour from Atan2 which can be used to get the angle between the positive x axis and your given vector. So
``Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg``
is comparable to
``SignedAngle(Vector2.right, v);``
for a given vector v.

See also Clockwise (wikipedia). or Euler's formula(wikipedia). Literally everything related to rotations in math is based on a counter clockwise rotation.

11. ### andyz

Joined:
Jan 5, 2010
Posts:
2,236
This is an interesting point and some libraries use 0 as right but I feel like that is more the hard-maths community and most developers use a compass-style angle system. But I wonder on the stats...

12. ### Wambosa

Joined:
Jun 2, 2013
Posts:
12
This method burned me + lost me two dev days. I spent a long time troubleshooting around it thinking that something was off with my algorithm, well it was this function in there.

I swapped to using a
Code (CSharp):
1. Quaternion.Inverse(transform.rotation) * vec2Direction
and it was more clear to me how to use that output.

There is a high probability that I was using the wrong method in the first place.