How to map atan2() to degrees 0-360

人盡茶涼 提交于 2019-11-27 03:05:43
erikkallen
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)

Solution using Modulo

A simple solution that catches all cases.

degrees = (degrees + 360) % 360;  // +360 for implementations where mod returns negative numbers

Explanation

Positive: 1 to 180

If you mod any positive number between 1 and 180 by 360, you will get the exact same number you put in. Mod here just ensures these positive numbers are returned as the same value.

Negative: -180 to -1

Using mod here will return values in the range of 180 and 359 degrees.

Special cases: 0 and 360

Using mod means that 0 is returned, making this a safe 0-359 degrees solution.

Just add 360° if the answer from atan2 is less than 0°.

Or if you don't like branching, just negate the two parameters and add 180° to the answer.

(Adding 180° to the return value puts it nicely in the 0-360 range, but flips the angle. Negating both input parameters flips it back.)

@erikkallen is close but not quite right.

theta_rad = atan2(y,x);
theta_deg = (theta_rad/M_PI*180) + (theta_rad > 0 ? 0 : 360);

This should work in C++: (depending on how fmod is implemented, it may be faster or slower than the conditional expression)

theta_deg = fmod(atan2(y,x)/M_PI*180,360);

Alternatively you could do this:

theta_deg = atan2(-y,-x)/M_PI*180 + 180;

since (x,y) and (-x,-y) differ in angles by 180 degrees.

I have 2 solutions that seem to work for all combinations of positive and negative x and y.

1) Abuse atan2()

According to the docs atan2 takes parameters y and x in that order. However if you reverse them you can do the following:

double radians = std::atan2(x, y);
double degrees = radians * 180 / M_PI;
if (radians < 0)
{
    degrees += 360; 
}

2) Use atan2() correctly and convert afterwards

double degrees = std::atan2(y, x) * 180 / M_PI;
if (degrees > 90)
{
    degrees = 450 - degrees;
}
else
{
    degrees = 90 - degrees;
}

@Jason S: your "fmod" variant will not work on a standards-compliant implementation. The C standard is explicit and clear (7.12.10.1, "the fmod functions"):

if y is nonzero, the result has the same sign as x

thus,

fmod(atan2(y,x)/M_PI*180,360)

is actually just a verbose rewriting of:

atan2(y,x)/M_PI*180

Your third suggestion, however, is spot on.

This is what I normally do:

float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;
angle = Math.atan2(x,y)*180/Math.PI;

I have made a Formula for orienting angle into 0 to 360

angle + Math.ceil( -angle / 360 ) * 360;

An alternative solution is to use the mod () function defined as:

function mod(a, b) {return a - Math.floor (a / b) * b;}

Then, with the following function, the angle between ini(x,y) and end(x,y) points is obtained. The angle is expressed in degrees normalized to [0, 360] deg. and North referencing 360 deg.

    function angleInDegrees(ini, end) {
        var radian = Math.atan2((end.y - ini.y), (end.x - ini.x));//radian [-PI,PI]
        return mod(radian * 180 / Math.PI + 90, 360);
    }

The R packages geosphere will calculate bearingRhumb, which is a constant bearing line given an origin point and easting/northing. The easting and northing must be in a matrix or vector. The origin point for a wind rose is 0,0. The following code seems to readily resolve the issue:

windE<-wind$uasE
windN<-wind$vasN
wind_matrix<-cbind(windE, windN)
wind$wind_dir<-bearingRhumb(c(0,0), wind_matrix)
wind$wind_dir<-round(wind$wind_dir, 0)
theta_rad = Math.Atan2(y,x);
if(theta_rad < 0)
  theta_rad = theta_rad + 2 * Math.PI;    //if neg., add 2 PI to it
theta_deg = (theta_rad/M_PI*180) ;        //convert from radian to degree

//or
theta_rad = Math.Atan2(y,x);
theta_rad = (theta_rad < 0) ? theta_rad + 2 * Math.PI : theta_rad;
theta_deg = (theta_rad/M_PI*180) ;

-1 deg becomes (-1 + 360) = 359 deg
-179 deg becomes (-179 + 360) = 181 deg

Finallz
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);

This will return degree from 0°-360° counter-clockwise, 0° is at 3 o'clock.

A formula to have the range of values from 0 to 360 degrees.

f(x,y)=180-90*(1+sign(x))* (1-sign(y^2))-45*(2+sign(x))*sign(y)

     -(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!