2009-12-10 7 views
96

Учитывая 2 угла в диапазоне -PI -> PI вокруг координаты, каково значение наименьшего из двух углов между ними?Наименьшая разница между двумя углами

Принимая во внимание, что разница между PI и -PI не равна 2 PI, но равна нулю.

Пример:

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

+2

Я читал 3 раза, прежде чем понял, что вы имели в виду. Пожалуйста, добавьте пример или объясните лучше ... – Kobi

+0

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

+0

Возможный дубликат [Как рассчитать угол между линией и горизонтальной осью?] (Https://stackoverflow.com/questions/7586063/how-to-calculate-the-angle-a-line-and-the-horizontal-axis) –

ответ

135

Это дает подписанный угол для любых углов:

a = targetA - sourceA 
a = (a + 180) % 360 - 180 

Берегитесь на многих языках modulo операции возвращает значение с тот же знак, что и дивиденд (например, C, C++, C#, JavaScript, full list here).Это требует обычай mod функции следующим образом:

mod = (a, n) -> a - floor(a/n) * n 

Или так:

mod = (a, n) -> (a % n + n) % n 

Если углы в [-180, 180] это также работает:

a = targetA - sourceA 
a += (a>180) ? -360 : (a<-180) ? 360 : 0 

В более подробный способ:

a = targetA - sourceA 
a -= 360 if a > 180 
a += 360 if a < -180 
+0

Проще и имеет смысл читать вслух, хотя фактически то же самое, сначала bti определяет угол, вторая часть гарантирует, что он всегда будет меньшим из двух возможных углов –

+1

, хотя можно захотеть сделать% 360, например. если бы у меня был угол 0 и целевой угол 721, правильный ответ был бы равен 1, ответ, указанный выше, был бы 361 –

+0

Да, это правда и преднамеренно, но определенно стоит указать. В моем примере я ранее получил 'targetA' и' sourceA' от 'atan2', поэтому их абсолютные углы никогда не превышали 360. – bennedich

30

Если ваши два угла равны x и y, то один из углов между ними - abs (x - у). Другой угол равен (2 * PI) - abs (x - y). Таким образом, значение наименьшей из 2-х углов:

min((2 * PI) - abs(x - y), abs(x - y)) 

Это дает абсолютное значение угла, и она принимает входные данные нормированы (т.е. в пределах диапазона [0, 2π)).

Если вы хотите сохранить знак (то есть: направление) угла, а также принять углы вне диапазона [0, 2π), вы можете обобщить приведенное выше. Вот Python код для обобщенной версии:

PI = math.pi 
TAU = 2*PI 
def smallestSignedAngleBetween(x, y): 
    a = (x - y) % TAU 
    b = (y - x) % TAU 
    return -a if a < b else b 

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

+0

Не удается установить тестовый пакет https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing

+1

@bradgonesurfing То есть/было правдой, но чтобы быть справедливым, ваши тесты проверены на предмет вещей которые не были указаны в исходном вопросе, в частности ненормированные входные данные и сохранение знака. Вторая версия в отредактированном ответе должна пройти ваши тесты. –

105

x - целевой угол. y является исходным или начальным углом:

atan2(sin(x-y), cos(x-y)) 

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

+3

это работает. Зачем? – ericsoco

+8

'x-y' дает вам разницу в углу, но может быть и не в нужных границах. Подумайте об этом угле, определяющем точку на единичном круге. Координаты этой точки: '(cos (x-y), sin (x-y))'. 'atan2' возвращает угол для этой точки (что эквивалентно' x-y'), за исключением диапазона [-PI, PI]. – Max

+1

Это проходит тестовый набор https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing

7

встает на проблему обеспечения подписанного ответа:

def f(x,y): 
    import math 
    return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs) 
+1

А ... Ответ, кстати, есть функция Python. К сожалению, я был в режиме Python на мгновение. Надеюсь, все в порядке. –

+0

Я подключу новую формулу в свой код наверх и посмотрю, что с ней будет!(thankyou^_ ^) –

+1

Я уверен, что ответ PeterB тоже верен. И злой хакер. :) –

5

Ari (в отличие от алгоритмического) решения:

angle = Pi - abs(abs(a1 - a2) - Pi); 
+0

Это не соответствует тестовому набору https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing

2

Нет необходимости вычислять тригонометрические функции. Простой код на языке C является:

#include <math.h> 
#define PIV2 M_PI+M_PI 
#define C360 360.0000000000000000000 
double difangrad(double x, double y) 
{ 
double arg; 

arg = fmod(y-x, PIV2); 
if (arg < 0) arg = arg + PIV2; 
if (arg > M_PI) arg = arg - PIV2; 

return (-arg); 
} 
double difangdeg(double x, double y) 
{ 
double arg; 
arg = fmod(y-x, C360); 
if (arg < 0) arg = arg + C360; 
if (arg > 180) arg = arg - C360; 
return (-arg); 
} 

пусть диф = а - Ь, в радианах

dif = difangrad(a,b); 

пусть диф = а - Ь, в градусах

dif = difangdeg(a,b); 

difangdeg(180.000000 , -180.000000) = 0.000000 
difangdeg(-180.000000 , 180.000000) = -0.000000 
difangdeg(359.000000 , 1.000000) = -2.000000 
difangdeg(1.000000 , 359.000000) = 2.000000 

Нет греха, нет cos, no загар, .... только геометрия !!!!

+4

Ошибка: поскольку вы #define PIV2 как« M_PI + M_PI », , а не "(M_PI + M_PI) ", строка' arg = arg - PIV2; 'расширяется до' arg = arg - M_PI + M_PI' и не делает ничего. – canton7

4

Для пользователей UnityEngine простым способом является использование только Mathf.DeltaAngle.