Как отобразить atan2 () в градусах 0-360 - PullRequest
87 голосов
/ 21 августа 2009

atan2 (y, x) имеет этот разрыв при 180 °, где он переключается на -180 ° ..0 ° по часовой стрелке.

Как отобразить диапазон значений на 0 ° ..360 °?

вот мой код:

CGSize deltaPoint = CGSizeMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
float swipeBearing = atan2f(deltaPoint.height, deltaPoint.width);

Я вычисляю направление события касания пальцем, учитывая startPoint и endPoint, обе структуры XY. Код для iPhone, но подойдет любой язык, который поддерживает atan2f ().

Спасибо за вашу помощь, ребята, с общим решением и кодом.

Обновление : Я превратил ответ Эриккалена в функцию с хорошими длинными именами переменных, поэтому я пойму его через 6 месяцев. Возможно, это поможет другому iPhone.

float PointPairToBearingDegrees(CGPoint startingPoint, CGPoint endingPoint)
{
    CGPoint originPoint = CGPointMake(endingPoint.x - startingPoint.x, endingPoint.y - startingPoint.y); // get origin point to origin by subtracting end from start
    float bearingRadians = atan2f(originPoint.y, originPoint.x); // get bearing in radians
    float bearingDegrees = bearingRadians * (180.0 / M_PI); // convert to degrees
    bearingDegrees = (bearingDegrees > 0.0 ? bearingDegrees : (360.0 + bearingDegrees)); // correct discontinuity
    return bearingDegrees;
}

Ответы [ 14 ]

81 голосов
/ 08 сентября 2014

Решение с использованием Modulo

Простое решение, которое ловит все случаи.

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

Объяснение

Положительный: от 1 до 180

Если вы измените любое положительное число от 1 до 180 на 360, вы получите точно такое же число, которое вы указали. Мод здесь просто гарантирует, что эти положительные числа будут возвращены в одно и то же значение.

Отрицательно: от -180 до -1

Использование здесь мода вернет значения в диапазоне 180 и 359 градусов.

Особые случаи: 0 и 360

Использование мода означает, что возвращается 0, что делает это безопасным решением 0-359 градусов.

53 голосов
/ 21 августа 2009
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)
34 голосов
/ 21 августа 2009

Просто добавьте 360 °, если ответ от atan2 меньше 0 °.

30 голосов
/ 21 августа 2009

Или, если вам не нравится ветвление, просто отмените два параметра и добавьте 180 ° к ответу.

(При добавлении 180 ° к возвращаемому значению оно красиво переводится в диапазон 0-360, но изменяется на угол. Отрицание обоих входных параметров возвращает его назад.)

20 голосов
/ 21 августа 2009

@ erikkallen близок, но не совсем прав.

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

Это должно работать в C ++: (в зависимости от того, как реализован fmod, оно может быть быстрее или медленнее, чем условное выражение)

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

В качестве альтернативы вы можете сделать это:

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

, поскольку (x, y) и (-x, -y) отличаются углами на 180 градусов.

7 голосов
/ 20 августа 2014

У меня есть 2 решения, которые, кажется, работают для всех комбинаций положительных и отрицательных х и у.

1) Злоупотребление atan2 ()

Согласно документам atan2 принимает параметры y и x в указанном порядке. Однако, если вы измените их, вы можете сделать следующее:

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

2) Используйте atan2 () правильно и затем преобразуйте

double degrees = std::atan2(y, x) * 180 / M_PI;
if (degrees > 90)
{
    degrees = 450 - degrees;
}
else
{
    degrees = 90 - degrees;
}
6 голосов
/ 22 августа 2009

@ Jason S: ваш вариант "fmod" не будет работать в соответствии со стандартами. Стандарт C является явным и понятным (7.12.10.1, «функции fmod»):

если y не равен нулю, результат будет иметь тот же знак, что и x

Таким образом,

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

на самом деле это просто подробное переписывание:

atan2(y,x)/M_PI*180

Ваше третье предложение, однако, верно.

2 голосов
/ 06 февраля 2017

Это то, что я обычно делаю:

float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;
1 голос
/ 04 февраля 2016

Альтернативным решением является использование функции mod (), определенной как:

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

Затем с помощью следующей функции получается угол между ini (x, y) и end (x, y) точек. Угол выражается в градусах, нормированных на [0, 360] град. и север, ссылаясь на 360 градусов.

    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);
    }
1 голос
/ 04 февраля 2015
angle = Math.atan2(x,y)*180/Math.PI;

Я сделал формулу для ориентации угла от 0 до 360

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