2010-02-23 1 views
27

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


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

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

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

+5

ИМХО Это не безобразно. Это довольно чисто и понятно. –

+6

Что делать, если начальный угол меньше -179? –

+0

После консультаций с документами я с Matthew Whited - угол% 360 дает значение от -359 до +359, а не 0 и +359. Следовательно, ваше решение не может нормализовать начальные значения, меньшие, чем -179. –

ответ

13

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

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

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

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

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

+0

+1, лучший ответ до сих пор! –

+1

И он обрабатывает углы с нецелыми степенями! – Aniko

+1

Вы могли бы начать с newAngle = angle% 360 в начале, так что вам не нужно беспокоиться о normalizeAngle (Integer.MAX_VALUE)? который, вероятно, попадет в категорию «не заботясь о краевых случаях». – Jimmy

8

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

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

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

UPDATE

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

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

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

+0

слишком загадочный ИМО. – missingfaktor

+0

Он должен быть «angle = (angle + 179)% 360 - 179». В противном случае 180 преобразуется в -180. –

+0

Уже исправлено это. –

0

Как насчет

(angle % 360) - 179 

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

+2

Я думаю, вы имеете в виду '((угол + 180)% 360) - 180' – Cascabel

+0

И есть вопрос« один за другим »(исправлено в ответе Даниэля). – Cascabel

3

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

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

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

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

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

+0

+1 Это очень интересная идея, и если требуется более подробная гранулярность, можно использовать больше бит - два байта, например, дают 65536 различных углов. –

14

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

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

atan2 имеет диапазон [- π, π).Это имеет преимущество в том, что загар θ = грех θ/соз θ, и что atan2 достаточно умен, чтобы знать, какой квадрант θ в.

Так как вы хотите градусов, вы хотите, чтобы преобразовать угол и из радиана:

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

Update Моего предыдущий пример был вполне законным, но ограничил диапазон & plusmn; 90 °. atan2 - это желаемое значение -179 ° до 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 

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

+2

+1 для использования функций ограниченного диапазона для нормализации. Немного накладных расходов, но это, безусловно, самый краткий ответ, который на самом деле правильный. –

+3

+1 чистый, но медленный. Я соблазн выбрать этот ответ. – User1

+0

Еще лучше, так как значение находится в правильном диапазоне. Однако теперь вы делаете три триггерных функции вместо двух! – Seth

1
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; 
+0

Ваш «самый короткий» ответ должен иметь «угол <-179' вместо' angle <-170'. –

3

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

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

Cast по вкусу.

BTW: Похоже, что углы между (180,0, 181,0) не определены. Если не диапазон быть (-180, 180] (без учета включительно]

+0

не совсем корректен. Если угол равен 270 градусов, I получить неожиданный результат -90 градусов –

+1

@ letdev-cwack -90 - это то, что я ожидал бы получить. Что бы вы ожидали и почему? –

60
// 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; 
+1

Это правильный ответ с наименьшими вычислениями. – tzot

+0

Кажется, это лучшее решение здесь для меня – Steve

+3

@PlatinumAzure: Нет, это не избыточно. Предположим, что угол равен -5000? –

2

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

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] 
} 
6

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

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

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

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

+1

Просто обратите внимание, что 'angle' должен быть' float' для этой или целочисленной математики. Используйте ' angle - = Math.ceil ((двойной) угол/360 - 0,5) * 360' или что-то для лучшей безопасности. Мне нравится ответ. Должно быть # 1 –

2

Я знаю, что прошло лет, но до сих пор

.

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

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

Вот целое только раствор:

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

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

2

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

, чтобы сохранить угол между 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 
-2

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

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

С -180 не работает – pascalbros

0

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

храповик

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]]] 
Смежные вопросы