Простой способ держать углы от -179 до 180 градусов - PullRequest
33 голосов
/ 23 февраля 2010

Есть ли простой способ преобразовать угол (в градусах) между -179 и 180? Я уверен, что мог бы использовать mod (%) и некоторые операторы if, но это выглядит ужасно:


//Make angle between 0 and 360
angle%=360;

//Make angle between -179 and 180
if (angle>180) angle-=360;

Просто кажется, что должна быть простая математическая операция, которая будет выполнять оба оператора одновременно. Возможно, мне просто нужно создать статический метод для конвертации.

Ответы [ 15 ]

80 голосов
/ 24 февраля 2010
// reduce the angle  
angle =  angle % 360; 

// force it to be the positive remainder, so that 0 <= angle < 360  
angle = (angle + 360) % 360;  

// force into the minimum absolute value residue class, so that -180 < angle <= 180  
if (angle > 180)  
    angle -= 360;  
16 голосов
/ 23 февраля 2010

Попробуйте вместо этого!

atan2(sin(angle), cos(angle))

atan2 имеет диапазон [- & pi ;, & pi;) . Это использует тот факт, что tan & theta; = грех и тета; / cos & theta; , и что atan2 достаточно умен, чтобы знать, в каком квадранте & theta; находится.

Поскольку вам нужны градусы, вам нужно преобразовать угол в радианы:

atan2(sin(angle * PI/180.0), cos(angle * PI/180.0)) * 180.0/PI

Обновление Мой предыдущий пример был совершенно законным, но ограничил диапазон до & plusmn; 90 & deg ;. Диапазон atan2 - это желаемое значение -179 & deg; до 180 °. Сохранено ниже.


Попробуйте это:

asin(sin(angle)))

Домен sin является реальной линией, диапазон равен [-1, 1]. Домен asin равен [-1, 1], а диапазон [-PI/2, PI/2]. Поскольку asin является инверсией sin, ваш ввод не изменяется (в значительной степени, есть некоторый сдвиг, потому что вы используете числа с плавающей запятой). Таким образом, вы вернете свое входное значение и получите желаемый диапазон как побочный эффект ограниченного диапазона арксинуса.

Поскольку вам нужны градусы, вам нужно преобразовать угол в радианы:

asin(sin(angle * PI/180.0)) * 180.0/PI

(Предостережение: триггерные функции в миллиарды раз медленнее, чем простые операции деления и вычитания, даже если они выполняются в FPU!)

14 голосов
/ 23 февраля 2010

Я немного опаздываю на вечеринку, я знаю, но ...

Большинство этих ответов бесполезны, потому что они стараются быть умными и лаконичными, а потом не заботятся окрайние случаи.

Это немного более многословно, но если вы хотите, чтобы это работало, просто включите логику, чтобы это работало.Не пытайтесь быть умным.

int normalizeAngle(int angle)
{
    int newAngle = angle;
    while (newAngle <= -180) newAngle += 360;
    while (newAngle > 180) newAngle -= 360;
    return newAngle;
}

Это работает и достаточно чисто и просто, не пытаясь быть изощренным.Обратите внимание, что можно запускать только ноль или один из циклов while.

9 голосов
/ 23 февраля 2010

Не слишком умный, но нет, если.

угол = (угол + 179)% 360 - 179;

Но я не уверен, как Java обрабатывает по модулю для отрицательных чисел. Это работает, только если -1 по модулю 360 равно 359.

UPDATE

Только что проверил документы и a % b выдает значение от -(|b| - 1) до +(|b| - 1), следовательно код не работает . Для учета отрицательных значений, возвращаемых оператором по модулю, необходимо использовать следующее.

angle = ((angle + 179) % 360 + 360) % 360 - 179;

Но ... нет ... никогда ... Используйте что-то похожее на исходное решение, но фиксированное для значений меньше -179.

8 голосов
/ 09 апреля 2014

Работает как с отрицательными, так и с десятичными числами и не требует ни циклов, ни тригонометрических функций:

угол - = Math.floor (угол / 360 + 0,5) * 360

Результат находится в интервале [-180, 180). Для интервала (-180, 180] вы можете использовать это вместо:

угол - = Math.ceil (угол / 360 - 0,5) * 360

3 голосов
/ 25 июня 2014

Вот целочисленное решение:

int normalize(int angle)
{
    angle %= 360;
    int fix = angle / 180; // Integer division!!
    return (fix) ? angle - (360 * (fix)) : angle;
}

Иногда быть умным - это еще веселее, Platinum Azure.

3 голосов
/ 09 апреля 2014

Я знаю, что прошли годы, но все же.

Это решение не содержит ни петель, ни вычитаний, ни по модулю (позволяет нормализовать интервал радиан). Работает для любого ввода, включая отрицательные значения, большие значения, крайние случаи.

double normalizedAngle = angle - (ceil((angle + M_PI)/(2*M_PI))-1)*2*M_PI;  // (-Pi;Pi]:
double normalizedAngle = angle - (ceil((angle + 180)/360)-1)*360;           // (-180;180]:

double normalizedAngle = angle - (floor((angle + M_PI)/(2*M_PI)))*2*M_PI;  // [-Pi;Pi):
double normalizedAngle = angle - (floor((angle + 180)/360))*360;           // [-180;180):
3 голосов
/ 24 февраля 2010

Короткий способ обработки отрицательных чисел:

double mod = x - Math.floor((x + 179.0) / 360) * 360;

В ролях по вкусу.

Кстати: кажется, что углы между (180.0, 181.0) не определены. Не должно быть диапазона (-180, 180] (эксклюзив, включительно)

3 голосов
/ 23 февраля 2010

Может быть, не полезно, но мне всегда нравилось использовать углы без градусов.

Диапазон углов от 0 до 255 может поддерживаться в границах с помощью побитовых операций или для одной байтовой переменной, которую можно просто переполнить.

Диапазон углов от -128 до 127 не так просто с побитовыми операциями, но, опять же, для однобайтовой переменной вы можете позволить ей переполниться.

Я думал, что это была отличная идея много лет назад для игр, где вы, вероятно, используете справочную таблицу для углов. В наши дни не все так хорошо - углы используются по-разному, и все равно плавают.

Тем не менее - возможно, стоит упомянуть.

2 голосов
/ 04 февраля 2015

Я сделал формулу для ориентации круговых значений

чтобы угол между 0 и 359 был:

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

, но сохранить от -179 до 180 формула может быть:

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

это даст смещение ориентации примерно на -179, сохраняя фактический угол без изменений

Обобщенная формула для сдвига угла ориентации может быть:

angle + Math.ceil( (-angle+shift) / 360 ) * 360
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...