math - triangulo - hallar el valor de los angulos desconocidos
Calculando si un ángulo está entre dos ángulos (6)
Así que estoy haciendo un pequeño juego en el que estoy comprobando si un personaje puede "ver" otro donde el personaje A puede ver al personaje B si A está a una cierta distancia de B, y la dirección en grados de A es +/- 45 grados de El ángulo B está orientado.
Actualmente, hago un pequeño cálculo donde estoy comprobando si
(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45)
Esto funciona bien, excepto cuando cruzamos la línea de 360 grados.
Digamos, facingAngle = 359, angleOfTarget = 5
. En esta situación, el objetivo está solo a 6 grados fuera del centro, por lo que quiero que mi función vuelva a ser verdadera. Desafortunadamente, 5 no está entre 314 y 404.
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 está hecha para trabajar en c, trabaja en Xcode).
Recuerde, comprueba COUNTER-CLOCKWISE desde el ángulo A al ángulo B. Devuelve YES (verdadero) si el ángulo está entre :)
Primero, una función de conversión simple para 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;
}
Compruebe si el ángulo está 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;
}
P.ej. Para comprobar si el ángulo 300 está entre 180 y 10 grados:
BOOL isBetween=angle_is_between_angles( 300, 180,10);
// DEVOLUCIONES SI
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 ha especificado que conoce la distancia entre los dos que presumiblemente calculó utilizando el teorema de Pitágoras.
Puedes usar el producto de puntos de dos vectores para calcular el ángulo entre ellos:
A . B = |A| . |B| . cos(theta).
Si toma A
como el vector de facingAngle
, será [cos(fA), sin(fA)]
, y tendrá magnitud |A|
de 1.
Si toma B
como el vector entre los dos caracteres, y su distancia por encima de usted obtiene:
cos(theta) = (cos(fA) * (P2x - P1x) + sin(fA) * (P2y - P1y)) / |B|
donde |B|
es la distancia que ya has calculado.
No es necesario que tome el coseno inverso para encontrar theta
, ya que para un rango de -45 a +45 solo necesita verificar cos(theta) >= 0.70710678
(es decir, 1 / sqrt(2)
).
Esto puede parecer un poco complicado, pero es probable que ya tenga todas las variables necesarias en su programa de todos modos.
Otra forma utilizando siempre la diferencia positiva mínima y comparando con el umbral:
anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection));
if (anglediff <= 45)
Replanteando la respuesta de Alnitak de una manera diferente, una solución que evita el ajuste de ángulo en 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 utilizando la proyección vectorial. Suponiendo que los vectores | enfrentando> = [cos (enfrentando) sin (enfrentando)] y | objetivo> = [cos (objetivo) sin (objetivo)], al proyectar el objetivo en el vector enfrentado, el ángulo oscilará desde cero, cuando el objetivo se encuentra exactamente en el vector de frente o aumentará a cada 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 de punto entre los vectores | enfrentando> y | destino> dividió sus módulos, que es 1 en este caso, que se convierte en:
angle = acos(<facing|target>)
Referencia: https://en.wikipedia.org/wiki/Vector_projection
Sólo inténtalo
anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180
if (anglediff <= 45 && anglediff>=-45) ....
La razón es que la diferencia en los ángulos se facingAngle - angleOfTarget
aunque debido a los efectos de envoltura, puede estar desactivada en 360 grados.
El sumar 180 + 360 luego el módulo 360 luego restar 180, efectivamente convierte todo en el rango de -180 a 180 grados (al sumar o restar 360 grados).
Luego puede verificar la diferencia de ángulo fácilmente, ya sea entre -45 y 45 grados.
Una solución simple para manejar el ajuste en el extremo inferior (en valores negativos), es simplemente agregar 360 a todos sus valores:
(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405)
De esa manera, la resta de 45 nunca puede ser negativa, porque ya no sucede.
Para manejar el ajuste en el extremo superior, debe volver a verificar, agregando otro 360 al valor de angleOfTarget
:
canSee = (facingAngle + 315 <= angleOfTarget + 360) &&
(angleOfTarget + 360 <= facingAngle + 405);
canSee |= (facingAngle + 315 <= angleOfTarget + 720) &&
(angleOfTarget + 720 <= facingAngle + 405);