Подтвердить что ты не робот

Легкий способ удерживания углов между -179 и 180 градусов

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


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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

Попробуй это!

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

atan2 имеет диапазон [- & pi;, & pi;). Это использует тот факт, что tan & theta; = sin & 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 & deg;. Сохраняется ниже.


Попробуйте следующее:

asin(sin(angle)))

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

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

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

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

Ответ 4

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

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

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

UPDATE

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

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

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

Ответ 5

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

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

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

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

Ответ 6

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

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

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

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

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

Ответ 7

Короткий путь, который обрабатывает отрицательные числа,

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

Наслаждайтесь вкусом.

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

Ответ 8

Ну, еще одно решение, одно с одним делением и без петель.

static double normalizeAngle(double angle)
{
    angle %= 360.0; // [0..360) if angle is positive, (-360..0] if negative
    if (angle > 180.0) // was positive
        return angle - 360.0; // was (180..360) => returning (-180..0)
    if (angle <= -180.0) // was negative
        return angle + 360.0; // was (-360..180] => returning (0..180]
    return angle; // (-180..180]
}

Ответ 9

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

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

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):

Ответ 10

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

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

Иногда умнее просто веселее, Platinum Azure.

Ответ 11

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

для сохранения угла между 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

Ответ 12

int angle = -394;

// shortest
angle %= 360;
angle = angle < -170 ? angle + 360 : (angle > 180 ? angle - 380 : angle);

// cleanest
angle %= 360;
if (angle < -179) angle += 360;
else if (angle > 180) angle -= 360;

Ответ 13

Как насчет

(angle % 360) - 179

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

Ответ 14

Вот мой вклад. Кажется, он работает для всех углов без проблем с краем. Это быстро. Он может сделать n180 [360000359] = -1 почти мгновенно. Обратите внимание, как функция Sign помогает выбрать правильный логический путь и позволяет использовать тот же код для разных углов.

храповик

n180[a_] := 
 If[Abs[Mod[a, If[Sign[a] == 0, 360, Sign[a] 360]]] <= 180, 
  Mod[a, If[Sign[a] == 0, 360, Sign[a] 360]], 
  Mod[a, If[Sign[a] == 0, 360, -Sign[a] 360]]]

Ответ 15

Лучше использовать библиотечные функции. Они обрабатывают особые случаи, такие как NaN и бесконечности.

public static double normalizeAngleDegrees(double angle) {
    return Math.toDegrees(Math.atan2(Math.sin(Math.toRadians(angle)), Math.cos(Math.toRadians(angle))));
}