language agnostic - La diferencia más pequeña entre 2 ángulos
language-agnostic geometry (7)
Dado 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?
Teniendo en cuenta que la diferencia entre PI y -PI no es 2 PI sino cero.
Ejemplo:
Imagine un círculo, con 2 líneas que salen del 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 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?
Esto le da un ángulo firmado para cualquier ángulo:
a = targetA - sourceA
a = (a + 180) % 360 - 180
Tenga en cuenta que en muchos idiomas la operación de modulo
devuelve un valor con el mismo signo que el dividendo (como C, C ++, C #, JavaScript, lista completa aquí ). Esto requiere una función mod
personalizada así:
mod = (a, n) -> a - floor(a/n) * n
Más o menos:
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 detallada:
a = targetA - sourceA
a -= 360 if a > 180
a += 360 if a < -180
Me levanto al desafío 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)
No es necesario calcular funciones trigonométricas. El código simple 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);
}
dejar dif = a - b, en radianes
dif = difangrad(a,b);
dejar 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
Sin pecado, sin cos, sin bronceado, ... ¡solo geometría!
Para los usuarios de UnityEngine, la manera más sencilla es usar Mathf.DeltaAngle .
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). Entonces el valor del más pequeño de los 2 ángulos es:
min((2 * PI) - abs(x - y), abs(x - y))
Esto le da el valor absoluto del ángulo, y supone que las entradas están normalizadas (es decir: dentro del rango [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 de 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 forma en todos los idiomas, especialmente cuando se trata de valores negativos, por lo que puede ser necesario cambiar algunos ajustes de signo.
Solución aritmética (en lugar de algorítmica):
angle = Pi - abs(abs(a1 - a2) - Pi);
x es el ángulo objetivo. y es la fuente o el ángulo de inicio:
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.