2012-09-02 14 views
16

Así que estoy haciendo un pequeño juego donde estoy comprobando si un personaje puede "ver" otro donde el personaje A puede ver el personaje B si A está dentro de una cierta distancia de B, y la dirección en grados de A es +/- 45 grados del ángulo B que está mirando.Cálculo si un ángulo está entre dos ángulos

Actualmente, hago un poco de cálculo donde yo estoy comprobando si

(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45) 

Esto funciona bien, salvo cuando cruzamos la línea de 360 ​​grados.

Digamos facingAngle = 359, angleOfTarget = 5. En esta situación, el objetivo está a solo 6 grados del centro, por lo que quiero que mi función sea verdadera. Por desgracia, no es entre 5 314 y 404.

+0

duplicado Posible de [Determinar si el ángulo se encuentra entre otros ángulos 2] (http://stackoverflow.com/questions/11406189/determine-if-angle-lies- entre-2-otros-ángulos) – sschuberth

Respuesta

14

sólo trato

anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180 

if (anglediff <= 45 && anglediff>=-45) .... 

La razón es que la diferencia en ángulos es facingAngle - angleOfTarget aunque debido a los efectos de envoltura, puede estar fuera de 360 ​​grados.

Agregue 180 + 360 luego módulo 360 y reste 180, con eficacia simplemente convierte todo al rango -180 a 180 grados (sumando o restando 360 grados).

Luego puede verificar la diferencia de ángulo fácilmente, ya sea dentro de -45 a 45 grados.

+1

En abetos Creí que no funcionaba en el caso del tema, pero luego lo probé en Python ... ¡¡Trabajando !! Así que volví a Pascal para descubrir por qué no funcionaba allí, resulta que 'mod' en Pascal no funciona con números negativos ... – JHolta

+1

Esto falla en el caso en que la orientación del ángulo es 0 y angleOfTarget es 359, por ejemplo. A menos que me falta algo, obtienes (0 - 359 + 180)% 360 - 180 = -359. Se requiere un valor absoluto alrededor de la sustracción de ángulo opuesto - ánguloDefunción. –

+0

Totalmente probado en Java (Android). Funciona. – pascalbros

0

Una solución sencilla para manejar envolver en el extremo inferior (en valores negativos), es sólo para agregar 360 a todos sus valores:

(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405) 

De esta manera, la resta de 45 nunca puede ir negativa, porque ya no sucede.

Manejar envoltura en el extremo superior, es necesario comprobar de nuevo, añadiendo otra 360 al valor angleOfTarget:

canSee = (facingAngle + 315 <= angleOfTarget + 360) && 
      (angleOfTarget + 360 <= facingAngle + 405); 
canSee |= (facingAngle + 315 <= angleOfTarget + 720) && 
      (angleOfTarget + 720 <= facingAngle + 405); 
8

Hay una solución trigonométrica que evita el problema de envoltura.

Supongo que tiene coordenadas (x, y) para los caracteres P1 y P2. Ya has especificado que conoces la distancia entre los dos que supuestamente calculabas usando el teorema de Pitágoras.

Usted puede utilizar el producto punto de dos vectores para calcular el ángulo entre ellos:

A . B = |A| . |B| . cos(theta). 

Si se toma A como el vector facingAngle será [cos(fA), sin(fA)], y tendrá magnitud |A| de 1.

Si se toma B como el vector entre los dos personajes, y su distancia por encima que se obtiene:

cos(theta) = (cos(fA) * (P2x - P1x) + sin(fA) * (P2y - P1y))/|B| 

donde |B| es la distancia que ya ha calculado.

No es necesario tomar realmente el coseno inverso para encontrar theta, ya que para el rango de -45 a +45 sólo tiene que comprobar si hay cos(theta) >= 0.70710678 (es decir 1/sqrt(2)).

Esto podría parecer ligeramente complicado, pero lo más probable es que ya tenga todas las variables requeridas en su programa de todos modos.

6

Aquí hay una función simple que encontré en línea y modifiqué. Funciona correctamente para cualquier ángulo (puede estar fuera de 0-360). (Esta función se hace para trabajar en c, trabaja en Xcode.)

Recuerde, comprueba las agujas del reloj ángulo A con el ángulo B. Se devuelve (true) si el ángulo es entre :)

en primer lugar, una función de conversión simple de hacer todos los ángulos 1-360

//function to convert angle to 1-360 degrees 
static inline double angle_1to360(double angle){ 
angle=((int)angle % 360) + (angle-trunc(angle)); //converts angle to range -360 + 360 
if(angle>0.0) 
return angle; 
else 
return angle + 360.0; 
} 

Comprobar si el ángulo es de entre :)

//check if angle is between angles 
static inline BOOL angle_is_between_angles(float N,float a,float b) { 
N = angle_1to360(N); //normalize angles to be 1-360 degrees 
a = angle_1to360(a); 
b = angle_1to360(b); 

if (a < b) 
return a <= N && N <= b; 
return a <= N || N <= b; 
} 

enter image description here

Por ejemplo. Para comprobar si el ángulo 300 es de entre 180 y 10 grados:

BOOL isBetween=angle_is_between_angles(300, 180,10); 

// devuelve SÍ

+1

Parece que funciona para Java si trunc() se reemplaza con Math.floor(). – mindoverflow

0

Otra forma usando siempre diferencia positiva mínimo y comparando con umbral:

anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection)); 
if (anglediff <= 45) 
0

Repetir la respuesta de Alnitak de una manera diferente, una solución que evita la envoltura de ángulo a 360 grados es replantear el problema en un sistema de coordenadas diferente donde los ángulos son siempre pequeños. Aquí está el código:

def inside_angle(facing, target): 
    dot = cos(facing)*cos(target) + sin(facing)*sin(target) 
    angle = acos(dot) 

    return angle <= pi/4 

Esto se hace mediante proyección vectorial. Suponiendo que los vectores | se enfrentan> = [cos (frente a) sin (frente)] y | destino> = [cos (objetivo) sin (destino)], al proyectar el objetivo en el vector de frente, el ángulo será de cero, cuando el objetivo está exactamente en el vector de frente o aumentará a cualquier lado. De esta manera, podemos compararlo con pi/4 (45 grados). La fórmula para el ángulo es la siguiente:

cos(angle) = <facing|target>/<target|target> <facing|facing> 

es decir, el coseno del ángulo es el producto escalar entre los vectores | frente> y | target> dividido sus módulos, que es de 1 en este caso, que se convierte en:

angle = acos(<facing|target>) 

Referencia: https://en.wikipedia.org/wiki/Vector_projection

Cuestiones relacionadas