2011-07-17 28 views
5

Estoy tratando de calcular la diferencia más pequeña entre dos ángulos.¿La diferencia más pequeña entre dos ángulos?

Este es mi código actual (una ligera variación de algo que encontré en línea):

float a1 = MathHelper.ToDegrees(Rot); 
float a2 = MathHelper.ToDegrees(m_fTargetRot); 

float dif = (float)(Math.Abs(a1 - a2); 

if (dif > 180) 
    dif = 360 - dif; 

dif = MathHelper.ToRadians(dif); 

Funciona bien, salvo en los casos en el borde de un círculo. Por ejemplo, si el ángulo actual es 355 y el ángulo objetivo es 5, calcula que la diferencia es -350 en lugar de 10, ya que 365 grados es igual a 5 grados.

¿Alguna idea sobre lo que puedo hacer para que esto funcione?

+0

esto parece correcto. también en realidad no necesitas convertir a grados y luego de vuelta a radianes - puedes calcular en radianes –

+4

No hay amor por 'MathHelper.WrapAngle' en las respuestas :( –

+0

Gran llamada, @Andrew. Llegué a esto sin ningún conocimiento de MathHelper, pero WrapAngle parece ser la solución de escritura. Ojalá hubieras publicado una solución, pero como no lo hiciste, actualizaré mi respuesta. – Prestaul

Respuesta

7

Usted básicamente lo tenía. Acaba de tomar el módulo de DIF 360 antes de comprobar para ver si es mayor que 180:

float a1 = MathHelper.ToDegrees(Rot); 
float a2 = MathHelper.ToDegrees(m_fTargetRot); 

float dif = (float)Math.Abs(a1 - a2) % 360; 

if (dif > 180) 
    dif = 360 - dif; 

dif = MathHelper.ToRadians(dif); 

Editar: @ Andrew Russell hizo un gran punto en los comentarios a su pregunta y la solución a continuación se aprovecha del método MathHelper.WrapAngle como sugirió:

diff = Math.Abs(MathHelper.WrapAngle(a2 - a1)); 
+0

¿Cómo sé si aumentar o disminuir la diferencia? – tweetypi

+0

Lo siento, no estoy muy seguro de lo que está preguntando ... El código debe estar completo tal como está y siempre devolverá un valor positivo entre 0 y 180 (inclusive). – Prestaul

+2

Solo tenga en cuenta que 'MathHelper.WrapAngle' funciona en radianes, por lo tanto, no realice la conversión de grados si lo usa. (Realmente nunca fue necesario de todos modos: 2π radianes = 360 grados. Y no te olvides de nuestro amigo 'MathHelper.TwoPi'!) –

1

Puede normalizar el resultado sea 0 < = theta < 360:

while(theta < 0) { theta += 360; } 

Si desea mantener la respuesta en radianes (recomendado):

const Double TwoPi = 2 * Math.Pi; 
while(theta < 0) { theta += TwoPi; } 
3

Se podría ampliar el cheque para ángulos fuera de límite:

if (dif < 0) dif = dif + 360; 
if (dif > 180) dif = 360 - dif; 
+1

¿Por qué la votación negativa? Si no exlabas lo que crees que está mal, puede 'mejorar la respuesta. – Guffa

1

Nunca me gusta manejar el cero-envoltura con declaraciones de casos. En su lugar, yo uso la definición del producto escalar para calcular el ángulo (sin firmar) entre dos ángulos:

vec(a) . vec(b) = ||a|| ||b|| cos(theta)

Sólo vamos a hacer unas unidades A y B vectores, por lo ||a|| == ||b|| == 1.

Desde vec(x) = [cos(x),sin(x)], obtenemos:

unsigned_angle_theta(a,b) = acos(cos(a)cos(b) + sin(a)sin(b)) 

(n.b. todos los ángulos en radianes)

Cuestiones relacionadas