2009-10-17 10 views
8

Necesito un algoritmo para averiguar si un ángulo está dentro de una cierta cantidad de grados desde otro ángulo.Encuentra si un ángulo está dentro de X grados de otro

Mi primer pensamiento fue (a-x < b) && (a+x > b), pero falla cuando se tiene que trabajar con ángulos que se envuelven alrededor de -179 a 180.

En el diagrama anterior, la región (verde) que la el ángulo debe estar entre vueltas entre los lados negativo y positivo. ¿Cómo puedo determinar si el ángulo (la línea roja) cae dentro de esta región?

+0

probar la versión actualizada. – cletus

Respuesta

7

tratar esta fórmula:

360-(|a-b|)%360<x || (|a-b|)%360<x 

O in PHP:

<?php 

$b = 10; 
$angle1 = -179; 
$angle2 = 180; 

$diff = $angle1 - $angle2; 
if(abs($diff % 360) <= $b || (360-abs($diff % 360))<=$b) { 
    echo "yes"; 
} else { 
    echo "no"; 
} 

?> 
+0

¡Parece que funciona! Gracias Ngu. –

3

Como Marcel señala con razón, módulo de números negativos es potencialmente problemática. Además, ¿cuál es la diferencia entre 355 y 5 grados? Podría ser calculado en 350 grados, pero 10 grados es probablemente lo que la gente está esperando. Hacemos los siguientes supuestos:

  1. queremos que el ángulo positivo más pequeño entre los otros dos ángulos para 0 <= diff <= 180;
  2. estamos trabajando en grados. Si radianes, sustituye 360 ​​por 2*PI;
  3. ángulos pueden ser positivos o negativos pueden estar fuera del rango -360 < x < 360 donde x es un ángulo de entrada y
  4. orden de los ángulos de entrada o la dirección de la diferencia es irrelevante.

Entradas: ángulos a y b. Entonces el algoritmo es simple:

  1. Normaliza ayb a 0 <= x < 360;
  2. Calcule el ángulo más corto entre los dos ángulos normales.

Para el primer paso, para convertir el ángulo con respecto a la gama deseada, hay dos posibilidades:

  • x >= 0: normal = x% 360
  • x < 0: normal = (-x/360 + 1) * 360 + x

El segundo está diseñado para eliminar cualquier ambigüedad en la diferencia en la interpretación de las operaciones de módulo negativo. Así que para dar un ejemplo trabajado para x = -400:

-x/360 + 1 
= -(-400)/360 + 1 
= 400/360 + 1 
= 1 + 1 
= 2 

continuación

normal = 2 * 360 + (-400) 
     = 320 

por lo que para las entradas 10 y -400 los ángulos normales son 10 y 320.

Ahora se calcula la el ángulo más corto entre ellos. Como un control de cordura, la suma de esos dos ángulos debe ser 360. En este caso, las posibilidades son 50 y 310 (dibuja y verás esto).Para trabajar estos fuera:

normal1 = min(normal(a), normal(b)) 
normal2 = max(normal(a), normal(b)) 
angle1 = normal2 - normal1 
angle2 = 360 + normal1 - normal2 

Así que para nuestro ejemplo:

normal1 = min(320, 10) = 10 
normal2 = max(320, 10) = 320 
angle1 = normal2 - normal1 = 320 - 10 = 310 
angle2 = 360 + normal1 - normal2 = 360 + 10 - 320 = 50 

Se habrá dado cuenta normal1 + normal2 = 360 (e incluso se puede demostrar que este será el caso si se quiere).

Por último:

diff = min(normal1, normal2) 

o 50 en nuestro caso.

+0

¿Tiene un error tipográfico allí entre angle1 y angle2? –

+1

El módulo en un número potencialmente negativo (diff) puede ser peligroso en algunos idiomas. –

+1

¿Confía en que el ángulo sea 0 - 360 o puedo usarlo con ángulos entre -180 y 180? –

1

También se puede utilizar un producto de punto:

cos(a)*cos(b) + sin(a)*sin(b) >= cos(x) 
1

para un radio de 1, la distancia entre los puntos finales de la línea son 2sin ((ab/2). Así que tira los 2 ya que solo estás interesado en una comparación, y compa re sin (x/2) con sin ((a-b)/2). Las funciones trigonométricas se encargan de todo el envoltorio.

0

implementación en C++:

float diff = fabsf(angle1 - angle2); 
bool isInRange = fmodf(diff, 360.0f) <= ANGLE_RANGE || 
       360.0f - fmodf(diff, 360.0f) <= ANGLE_RANGE; 
Cuestiones relacionadas