Как отобразить atan2 () в градусы 0-360


108

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()подойдет любой поддерживаемый язык .


Примечание. Опубликованный метод обновления возвращает не ноль градусов, а значения от чуть выше 0 до 360,0.
chux - Восстановить Монику

2
> [Как получить угол с 2 позиций] [1] [1]: stackoverflow.com/questions/9457988/…
Маной Сарнаик 08

Эта функция отлично работает, однако угол вычисления «BearDegrees» меняется. например, угол 45 градусов обычно соответствует 1-му квадранту, но это 4-й квадрант. 135 градусов обычно будет во 2-м квадранте, но эта функция возвращает его в 3-м квадранте. Я могу просто взять возвращаемое функцией значение x и отрицать это из 360, чтобы получить правильное значение угла, однако мне любопытно узнать, почему это вообще происходит?
goelv

Ответы:


66
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)

6
Вероятно, также хотите, чтобы x> = 0 для случая x = 0.
bpw1621

13
Для тех, кто не знаком с этой нотацией и без встроенного преобразования в градусы: if (x> 0) {radians = x;} else {radians = 2 * PI + x;}, поэтому мы просто добавляем 2PI к результату, если он меньше 0.
Дэвид Дориа

1
Или (x >= 0 ? x : (2*PI + x)) * 180/PIкак в(x < 0 ? 2*PI + x : x) * 180/PI
user3342816 09

97

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

Простое решение, подходящее для всех случаев.

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

Объяснение

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

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

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

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

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

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


3
потрясающие решения :)
Кадир Хуссейн

5
Я не считаю, что нужно добавлять 360. -1% 360 все еще 359 :)
pleasemorebacon

11
Я не думаю, что это правильно для всех языков. На Javascript-1 % 360 = -1
Startec

Также не жизнеспособный подход в Java
Халк

1
@pleasemorebacon Неверно. В некоторых языках -1% 360 равно -1.
Pharap

40

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


6
Это то же самое, что «просто добавить 2 * PI», если у вас один из таких дней.
Chris O

33

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

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


2
Спасибо, это именно то, что я искал.
Джереми Херрман

2
Я бы предпочел изменить свой код, чтобы использовать денормализованные углы (<0,> = 360), но всегда, кажется, есть кто-то, стремящийся к этому фальшивому «оптимизированному» ощущению; вот почему я хотел добавить это. (Или это потому, что это был более быстрый способ обойти какой-то временный отладочный код, который я использовал? Хмм)
aib

1
Определенно не так просто грок, как я могу согласиться через 2+ лет. Итак: добавление 180 ° к возвращаемому значению хорошо помещает его в диапазон 0–360, но меняет угол. Отрицание обоих входных параметров переворачивает его обратно.
aib

Это может иметь некоторые проблемы, если $ x = 0 $ и $ y> 0 $ iirc
Тринидад

22

@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 градусов.


если я вас правильно понял, в Фортране это atan2 (-y, -x) * 180 / PI + 180. Это правильно?
gansub

извините, я не знаю FORTRAN. Но ваша математика выглядит верной.
Jason S

11

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

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;
}

Вы, сэр, спаситель жизни. Просто использовал этот подход в Unity и работает как шарм.
porfiriopartida

7

@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

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


5

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

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

2
angle = Math.atan2(x,y)*180/Math.PI;

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

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

2

Альтернативным решением является использование функции 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

Геосфера пакетов R вычислит пеленг Rhumb, который является постоянной линией пеленга с учетом исходной точки и направления на восток / север. Ориентация на восток и север должны быть в матрице или векторе. Начальная точка розы ветров - 0,0. Следующий код, кажется, легко решает проблему:

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)

1
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 градус становится (-1 + 360) = 359 градусов
-179 градусов становится (-179 + 360) = 181 градус


Что Math.PI? Это то же самое, что и M_PI?
Pang

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

Это вернет градус от 0 ° -360 ° против часовой стрелки, 0 ° соответствует 3 часам.


1

Формула, имеющая диапазон значений от 0 до 360 градусов.

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

     -(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))

Не могли бы вы объяснить, как это связано с вопросом?
Клаус Гюттер

1

Вот какой-нибудь javascript. Просто введите значения x и y.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.