unitario trigonometricas trigonometria signos referencia punto plano los las lado funciones cuadrantes coterminales circulo cartesiano angulos angulo c++ math trigonometry

c++ - trigonometricas - Determine si el ángulo se encuentra entre otros 2 ángulos



signos de las funciones trigonometricas en los 4 cuadrantes (12)

Estoy tratando de averiguar si un ángulo se encuentra entre otros 2 ángulos. He estado tratando de crear una función simple para realizar esto, pero ninguna de mis técnicas funcionará para todos los valores posibles de los ángulos.

¿Puedes ayudarme a editar mi función para determinar correctamente si un ángulo se encuentra entre otros 2 ángulos?

En la imagen de arriba; Utilizo el punto verde como punto central, luego determino el ángulo de cada línea con respecto al punto verde. Entonces calculo el ángulo del punto negro al punto verde. Estoy tratando de verificar si el ángulo del punto negro está ENTRE los ángulos de las 2 líneas.

NOTA: En mi caso; se dice que un ángulo (targetAngle) se encuentra entre otros 2 ángulos SI la diferencia entre los 2 ángulos es <180 grados Y el angulo de destino se encuentra en la cavidad hecha por esos 2 ángulos.

El siguiente código debería funcionar pero falla para estos (que se encuentran entre el ángulo):
- is_angle_between (150, 190, 110)
- is_angle_between (3, 41, 345)

bool is_angle_between(int target, int angle1, int angle2) { int rAngle1 = ((iTarget - iAngle1) % 360 + 360) % 360; int rAngle2 = ((iAngle2 - iAngle1) % 360 + 360) % 360; return (0 <= rAngle1 && rAngle1 <= rAngle2); } // Example usage is_angle_between(3, 41, 345);

Otra técnica que intenté y que tampoco funciona:

int is_angle_between(int target, int angle1, int angle2) { int dif1 = angle1-angle2; int dif2 = angle2-angle1; int uDif1 = convert_to_positive_angle( dif1 ); // for eg; convert -15 to 345 int uDif2 = convert_to_positive_angle( dif2 ); if (uDif1 <= uDif2) { if (dif1 < 0) { return (target <= angle1 && target >= angle2); } else return (in_between_numbers(iTarget, iAngle1, iAngle2)); } else { if (dif2 < 0) { return (target <= angle1 && target >= angle2); } else return (in_between_numbers(iTarget, iAngle1, iAngle2)); } return -1; }


Es el ángulo T entre los ángulos A y B, siempre hay dos respuestas: verdadero y falso.

Necesitamos especificar qué queremos decir, y en este caso estamos buscando los ángulos de barrido pequeños normalizados y si nuestro ángulo está entre esos valores. Dado cualquiera de los dos ángulos, hay un ángulo reflejo entre ellos, ¿está el valor normalizado de T dentro de ese ángulo reflejo?

Si rotamos A y B y T de modo que T = 0 y normalizamos A y B dentro de + -hemicircumference (180 ° o 2PI). Entonces, nuestra respuesta es si A y B tienen signos diferentes, y están dentro de una hemicircunferencia entre sí.

Si restamos el ángulo de la prueba, entonces sumamos 180 ° (de modo que A es relativo a T + 180). Luego modificamos 360 dándonos un rango entre [-360 °, 360 °] agregamos 360 ° y mod nuevamente (nota, también puede verificar si es negativo y agregar 360 si es), dándonos un valor que es seguro de ser [0 °, 360 °]. Restamos 180 °, lo que nos da un valor entre [-180 °, 180 °] en relación con T + 180 ° -180 ° alias, T. Por lo tanto, T es el ángulo cero y todos los ángulos están dentro del rango normalizado. Ahora verificamos que los ángulos cambien de señal y que no estén separados más de 180 °, tenemos nuestra respuesta.

Porque la pregunta se hace en C ++:

bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) { int a_adjust = ((((a - test + 180)) % 360) + 360) % 360 - 180; int b_adjust = ((((b - test + 180)) % 360) + 360) % 360 - 180; return ((a_adjust ^ b_adjust) < 0) && ((a_adjust - b_adjust) < 180) && ((a_adjust - b_adjust) > -180); }

También podemos hacer algunos trucos para simplificar el código y evitar cualquier operación de módulo innecesaria (vea los comentarios a continuación). Normalizar moverá el ángulo a en el rango [-180 °, 180 °] con relación al ángulo t.

int normalized(int a, int test) { int n = a - test + 180; if ((n > 360) || (n < -360)) n %= 360; return (n > 0)? n - 180: n + 180; } bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) { int a_adjust = normalized(a,test); int b_adjust = normalized(b,test); return ((a_adjust ^ b_adjust) < 0) && ((a_adjust > b_adjust)? a_adjust-b_adjust: b_adjust-a_adjust) < 180; }

Además, si podemos estar seguros de que el rango es [0,360], podemos hacerlo con una instrucción if más simple

bool isAngleBetweenNormalizedSmallSweepRange(int test, int a, int b) { int dA = a - test + 180; if (dA > 360) { dA -= 360; } int a_adjust = (dA > 0) ? dA - 180 : dA + 180; int dB = b - test + 180; if (dB > 360) { dB -= 360; } int b_adjust = (dB > 0) ? dB - 180 : dB + 180; return ((a_adjust ^ b_adjust) < 0) && ((a_adjust > b_adjust) ? a_adjust - b_adjust : b_adjust - a_adjust) < 180; }

JS Fiddle prueba del código.


He encontrado esta cita de this hilo:

si un punto P está dentro del triángulo ABC, entonces

Área PAB + Área PBC + Área PAC = Área ABC

observe que si P está en el borde de AB, BC o CA, la retención anterior. Pero efectivamente, una de las áreas PAB, PBC, PAC es 0 (así que asegúrese de verificarlo).

si P está fuera, la igualdad anterior NO se cumple ...

¿Cómo determinar el área? tiene dos opciones: 1) El teorema de Heron, involucra sqrt, más lento 2) la forma más preferida es los productos cruzados (o, efectivamente, la mitad del valor absoluto de (suma de los productos inactivos menos la suma de los productos ascendentes))

por ejemplo, si A = (x1, y1) B = (x2, y2), C = (x3, y3) Área = abs (x1 * y2 + x2 * y3 + x3 * y1-x1 * y3-x3 * y2- x2 * y1) / 2

También es posible que desee tener cuidado con los errores de punto flotante ... en lugar de verificar la desigualdad estricta, verifique los abdominales

Esperemos que eso ayude


He hecho esto antes comparando ángulos.

En el croquis anterior, el vector AD estará entre AB y AC si y solo si

angle BAD + angle CAD == angle BAC

Debido a imprecisiones de punto flotante, comparé los valores después de redondearlos primero para decir 5 decimales.

Así que todo se reduce a tener un algoritmo de ángulo entre dos vectores p y q que simplemente se pone como:

double a = p.DotProduct(q); double b = p.Length() * q.Length(); return acos(a / b); // radians

Dejaré el vector DotProduct y los cálculos de longitud como un ejercicio de búsqueda de Google. Y obtienes vectores simplemente restando las coordenadas de un terminal de la otra.

Por supuesto, primero debe comprobar si AB y AC son paralelos o antiparalelos.


Inspirado en un post sobre Intervalos en aritmética modular :

static bool is_angle_between(int x, int a, int b) { b = modN(b - a); x = modN(x - a); if (b < 180) { return x < b; } else { return b < x; } }

donde (en caso de verificar ángulos) modN() se implementaría como

// modN(x) is assumed to calculate Euclidean (=non-negative) x % N. static int modN(int x) { const int N = 360; int m = x % N; if (m < 0) { m += N; } return m; }


Sé que esta publicación es antigua, pero no parece haber una respuesta aceptada y he encontrado que el siguiente enfoque es bastante confiable. Aunque podría ser más de lo que necesitas. Admite rangos de ángulos superiores a 180 grados (así como mayores de 360 ​​grados y ángulos negativos). También soporta precisión decimal.

El método utiliza esta función auxiliar normalize() para convertir ángulos en el espacio correcto:

float normalize( float degrees ) { //-- Converts the specified angle to an angle between 0 and 360 degrees float circleCount = (degrees / 360.0f); degrees -= (int)circleCount * 360; if( 0.0f > degrees ) { degrees += 360.0f; } return degrees; }

Aquí está la solución:

bool isWithinRange( float start, float end, float angle ) { if( fabsf( end - start ) >= 360.0f ) { //-- Ranges greater or equal to 360 degrees cover everything return true; } //-- Put our angle between 0 and 360 degrees float degrees = normalize( angle ); //-- Resolve degree value for the start angle; make sure it''s // smaller than our angle. float startDegrees = normalize( start ); if( startDegrees > degrees ) { startDegrees -= 360.0f; } //-- Resolve degree value for the end angle to be within the // same 360 degree range as the start angle and make sure it // comes after the start angle. float endDegrees = normalize( end ); if( endDegrees < startDegrees ) { endDegrees += 360.0f; } else if( (endDegrees - startDegrees) >= 360.0f ) { endDegrees -= 360.0f; } //-- All that remains is to validate that our angle is between // the start and the end. if( (degrees < startDegrees) || (degrees > endDegrees) ) { return false; } return true; }

Espero que esto ayude a alguien.


Si angle2 siempre fue 0, y angle1 siempre estuvo entre 0 y 180, esto sería fácil:

return angle1 < 180 && 0 < target && target < angle1;

si estoy leyendo los requerimientos correctamente

Pero no es tan difícil llegar allí.

int reduced1 = (angle1 - angle2 + 360) % 360; // and imagine reduced2 = 0 if (180 < reduced1) { angle2 = angle1; reduced1 = 360 - reduced1; } // swap if backwards int reducedTarget = (target - angle2 + 360) % 360; return reduced1 < 180 && 0 < reducedTarget && reducedTarget < reduced1;


Si tienes ángulos $$ a $ y $ b $, y no quieres ver si el ángulo x está entre estos ángulos.

Puedes calcular el ángulo entre a->x y a->b . Si ∠a->x es menor que ∠a->b , x debe estar entre b .

La distancia entre los ángulos, a y b

function distanceBetweenAngles(a, b) { distance = b - a; if (a > b) { distance += 2*pi; } return distance; }

Entonces puedes hacer

// Checks if angle ''x'' is between angle ''a'' and ''b'' function isAngleBetween(x, a, b) { return distanceBetweenAngles(a, b) >= distanceBetweenAngles(a, x); }

Esto supone que estás usando radianes, y no grados, como se debería. Se elimina una gran cantidad de código innecesario.


Si ustedes tienen tiempo, miren esto:

bool AngleIsBetween(int firstAngle, int secondAngle, int targetAngle) { while (firstAngle >= 360) firstAngle -= 360; while (secondAngle >= 360) secondAngle -= 360; while (targetAngle >= 360) targetAngle -=360; while (firstAngle < 0) firstAngle += 360; while (secondAngle < 0) secondAngle += 360; while (targetAngle < 0) targetAngle +=360; int temp = secondAngle; if (firstAngle > secondAngle) { secondAngle = firstAngle; firstAngle = temp; } if ((secondAngle - firstAngle) > 180) { temp = secondAngle - 360; secondAngle = firstAngle; firstAngle = temp; } return ((targetAngle >= firstAngle) && (targetAngle <= secondAngle)); }

Cambie los parámetros para flotar si es necesario.


Todas las respuestas principales aquí están mal. Como tal, creo que es necesario que publique una respuesta.

Acabo de volver a publicar una parte de una respuesta que publiqué aquí: https://.com/a/42424631/2642059 Esa respuesta también trata el caso en el que ya sabe qué ángulo es el lado izquierdo y el lado derecho del ángulo reflexivo. Pero también necesitas determinar qué lado del ángulo es cuál.

1 st para encontrar el ángulo más a la izquierda si alguna de estas afirmaciones son verdaderas angle1 es su ángulo más a la izquierda:

  1. angle1 <= angle2 && angle2 - angle1 <= PI
  2. angle1 > angle2 && angle1 - angle2 >= PI

Para simplificar, digamos que su ángulo más a la izquierda es l y su ángulo más a la derecha es r y usted está tratando de encontrar si g está entre ellos.

El problema aquí es lo que parece. Hay esencialmente 3 casos positivos que estamos buscando:

  1. l ≤ g ≤ r
  2. l ≤ g ∧ r <l
  3. g ≤ r ∧ r <l

Ya que está calculando los lados izquierdo y derecho del ángulo, notará que hay una oportunidad de optimización aquí al hacer ambos procesos a la vez. Su función se verá como:

if(angle1 <= angle2) { if(angle2 - angle1 <= PI) { return angle1 <= target && target <= angle2; } else { return angle2 <= target || target <= angle1; } } else { if(angle1 - angle2 <= PI) { return angle2 <= target && target <= angle1; } else { return angle1 <= target || target <= angle2; } }

O si lo necesitas, puedes expandirte a esta condición de pesadilla:

angle1 <= angle2 ? (angle2 - angle1 <= PI && angle1 <= target && target <= angle2) || (angle2 - angle1 > PI && (angle2 <= target || target <= angle1)) : (angle1 - angle2 <= PI && angle2 <= target && target <= angle1) || (angle1 - angle2 > PI && (angle1 <= target || target <= angle2))

Tenga en cuenta que todas estas matemáticas suponen que su entrada está en radianes y en el rango [0: 2π].

Ejemplo vivo


Usando un estilo de función similar al de su pregunta, he tenido buena suerte con los siguientes métodos:

public static bool IsInsideRange(double testAngle, double startAngle, double endAngle) { var a1 = System.Math.Abs(AngleBetween(startAngle, testAngle)); var a2 = System.Math.Abs(AngleBetween(testAngle, endAngle)); var a3 = System.Math.Abs(AngleBetween(startAngle, endAngle)); return a1 + a2 == a3; } public static double AngleBetween(double start, double end) { return (end - start) % 360; }


bool is_angle_between(int target, int angle1, int angle2) { // make the angle from angle1 to angle2 to be <= 180 degrees int rAngle = ((angle2 - angle1) % 360 + 360) % 360; if (rAngle >= 180) std::swap(angle1, angle2); // check if it passes through zero if (angle1 <= angle2) return target >= angle1 && target <= angle2; else return target >= angle1 || target <= angle2; }


void normalize( float& angle ) { while ( angle < -180 ) angle += 360; while ( angle > 180 ) angle -= 360; } bool isWithinRange( float testAngle, float a, float b ) { a -= testAngle; b -= testAngle; normalize( a ); normalize( b ); if ( a * b >= 0 ) return false; return fabs( a - b ) < 180; }