2009-12-10 13 views
96

Dados 2 ángulos en el rango -PI -> PI alrededor de una coordenada, ¿cuál es el valor del más pequeño de los 2 ángulos entre ellos?La diferencia más pequeña entre 2 ángulos

Teniendo en cuenta que la diferencia entre PI y -PI no es 2 PI sino cero.

Ejemplo:

imaginar un círculo, con 2 líneas que salen del centro, hay 2 ángulos entre esas líneas, el ángulo que hacen en la interior también conocido como el ángulo más pequeño, y el ángulo hacen en el exterior, también conocido como el ángulo más grande. Ambos ángulos cuando se suman forman un círculo completo. Dado que cada ángulo puede caber dentro de un cierto rango, cuál es el valor de ángulos más pequeños, teniendo en cuenta el vuelco

+2

He leído 3 veces antes de entender lo que quería decir. Por favor, agregue un ejemplo, o explique mejor ... – Kobi

+0

Imagínese un círculo, con 2 líneas que salen desde el centro, hay 2 ángulos entre esas líneas, el ángulo que hacen en el interior también conocido como el ángulo más pequeño, y el ángulo que forman en el exterior, también conocido como el ángulo más grande. Ambos ángulos cuando se suman forman un círculo completo. Dado que cada ángulo puede caber dentro de un cierto rango, ¿cuál es el valor de ángulos más pequeños, teniendo en cuenta el vuelco –

+0

Posible duplicado de [Cómo calcular el ángulo entre una línea y el eje horizontal?] (Https://stackoverflow.com/questions/7586063/cómo calcular el ángulo entre una línea y el eje horizontal) –

Respuesta

135

Esto da un ángulo firmado para cualquier ángulo:

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

Cuidado en muchos idiomas la operación modulo devuelve un valor con el el mismo signo que el dividendo (como C, C++, C#, JavaScript, full list here).Esto requiere una costumbre mod función de este modo:

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

O así:

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

Si los ángulos están dentro de [-180, 180] Esto también funciona:

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

De una manera más forma detallada:

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

Más simple y tiene más sentido leer en voz alta, aunque efectivamente es lo mismo, primero bti calcula el ángulo, la segunda parte asegura que siempre es el más pequeño de los 2 ángulos posibles –

+1

aunque se podría querer hacer un% 360, p. si tuviera el ángulo 0 y el ángulo objetivo 721, la respuesta correcta sería 1, la respuesta dada por el anterior sería 361 –

+0

Sí, eso es cierto y deliberado, pero definitivamente vale la pena señalarlo. En mi ejemplo, anteriormente obtuve 'targetA' y' sourceA' de 'atan2', por lo tanto, sus ángulos absolutos nunca son superiores a 360. – bennedich

30

Si sus dos ángulos son xey, entonces uno de los ángulos entre ellos es abs (x - y) El otro ángulo es (2 * PI) - abs (x - y). Así que el valor de la más pequeña de los ángulos 2 es:

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

Esto le da el valor absoluto del ángulo, y asume las entradas están normalizados (es decir: en el intervalo [0, 2π)).

Si desea conservar el signo (es decir, la dirección) del ángulo y también aceptar ángulos fuera del rango [0, 2π), puede generalizar lo anterior. Aquí está el código Python para la versión generalizada:

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 

Tenga en cuenta que el operador % no se comporta de la misma en todos los idiomas, sobre todo cuando se trata de valores negativos, por lo que si portar algunos ajustes de signos puede ser necesario.

+0

. Falla el banco de pruebas https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing

+1

@bradgonesurfing Eso es/era cierto, pero para ser justos, sus pruebas buscaron cosas que no fueron especificados en la pregunta original, específicamente entradas no normalizadas y preservación de la señal. La segunda versión en la respuesta editada debería pasar sus pruebas. –

105

x es el ángulo de destino. y es la fuente o el ángulo inicial:

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

Devuelve el ángulo delta firmado. Tenga en cuenta que, dependiendo de su API, el orden de los parámetros para la función atan2() podría ser diferente.

+3

esto funciona. ¿por qué? – ericsoco

+8

'x-y' le da la diferencia de ángulo, pero puede estar fuera de los límites deseados. Piensa en este ángulo que define un punto en el círculo unitario. Las coordenadas de ese punto son '(cos (x-y), sin (x-y))'. 'atan2' devuelve el ángulo para ese punto (que es equivalente a' x-y'') excepto que su rango es [-PI, PI]. – Max

+1

Esto pasa el banco de pruebas https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing

7

que hacer frente al reto de proporcionar la respuesta firmada:

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

Ah ... la respuesta es una función de Python por cierto. Lo siento, estuve en modo Python por un momento. Espero que esté bien. –

+0

¡Voy a conectar la nueva fórmula en mi código de arriba y ver qué pasa!(gracias^_ ^) –

+1

Estoy bastante seguro de que la respuesta de PeterB también es correcta. Y malvadamente hackish. :) –

5

Ari Solución thmetical (en lugar de algorítmica):

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

Esto falla en el banco de pruebas https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8 – bradgonesurfing

2

No es necesario calcular funciones trigonométricas. El simple código en lenguaje C es:

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

vamos DIF = a - b, en radianes

dif = difangrad(a,b); 

dejó DIF = a - b, en grados

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 

Ningún pecado, no cos, no tan, .... solo geometría !!!!

+4

Error! Ya que #define PIV2 como" M_PI + M_PI " , no "(M_PI + M_PI) ", la línea' arg = arg - PIV2; 'se expande a' arg = arg - M_PI + M_PI', y por lo tanto no hace nada. – canton7

4

Para los usuarios de Unity Engine, la manera más fácil es simplemente usar Mathf.DeltaAngle.

Cuestiones relacionadas