Détermine si l’angle est compris entre 2 autres angles

J’essaie de déterminer si un angle est compris entre 2 autres angles. J’ai essayé de créer une fonction simple pour effectuer cela, mais aucune de mes techniques ne fonctionnera pour toutes les valeurs possibles des angles.

Pouvez-vous m’aider à modifier ma fonction pour déterminer correctement si un angle se situe entre 2 autres angles?

entrez la description de l'image ici

Dans l’image ci-dessus; J’utilise le point vert comme point central, puis je détermine l’angle de chaque ligne par rapport au point vert. Je calcule ensuite l’angle du point noir au point vert. J’essaie de vérifier si l’angle du point noir est ENTRE les angles des 2 lignes.

NOTE: Dans mon cas; on dit qu’un angle (targetAngle) se situe entre 2 autres angles SI la différence entre les 2 angles est <180 degrés ET que targetAngle se situe dans la cavité formée par ces 2 angles.

Le code suivant devrait fonctionner mais il échoue pour ceux-ci (qui se situent entre l’angle):
– 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); 

Une autre technique que j’ai essayée et qui ne fonctionne pas non plus:

 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 = angle2); } else return (in_between_numbers(iTarget, iAngle1, iAngle2)); } else { if (dif2 < 0) { return (target = angle2); } else return (in_between_numbers(iTarget, iAngle1, iAngle2)); } return -1; } 

 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; } 

Inspiré d’un article sur les intervalles en arithmétique modulaire :

 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; } } 

où (en cas de contrôle des angles) modN() serait implémenté comme

 // 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; } 
 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; } 

Si angle2 était toujours égal à 0 et que angle1 était toujours compris entre 0 et 180, cela serait facile:

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

si je lis correctement les exigences.

Mais ce n'est pas si difficile d'y arriver.

 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; 

J’ai déjà fait cela en comparant les angles.

entrez la description de l'image ici

Dans l’esquisse ci-dessus, le vecteur AD sera entre AB et AC si et seulement si

 angle BAD + angle CAD == angle BAC 

En raison d’imprécisions sur les virgules flottantes, j’ai comparé les valeurs après les avoir arrondies, en commençant par 5 décimales.

Il s’agit donc d’avoir un algorithme d’angle entre deux vecteurs p et q qui est simplement exprimé comme ceci:

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

Je laisserai les calculs vectoriels DotProduct et Length comme exercice de recherche sur Google. Et vous obtenez des vecteurs simplement en soustrayant les coordonnées d’un terminal de l’autre.

Bien sûr, vous devez d’abord vérifier si AB et AC sont parallèles ou anti-parallèles.

Toutes les principales réponses ici sont fausses. En tant que tel, j’estime qu’il est nécessaire que je poste une réponse.

Je ne fais que republier une partie d’une réponse que j’ai postée ici: https://stackoverflow.com/a/42424631/2642059 Cette réponse traite également du cas où vous savez déjà quel angle sont le côté gauche et le côté droit du angle réflexif. Mais vous devez également déterminer quel côté de l’angle est lequel.


1 er pour trouver l’angle le plus à gauche si l’une ou l’autre de ces affirmations est vraie, angle1 est votre angle le plus à gauche:

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

Par souci de simplicité, disons que votre angle le plus à gauche est l et votre angle le plus à droite est r et que vous essayez de trouver si g est entre eux.

Le problème ici est le paraître. Nous recherchons essentiellement 3 cas positifs:

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

Puisque vous calculez les côtés gauche et droit de l'angle, vous remarquerez qu'il existe une opportunité d'optimisation dans le fait de faire les deux processus en même temps. Votre fonction ressemblera à:

 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; } } 

Ou si vous en avez besoin, vous pourriez développer cette situation cauchemardesque:

 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)) 

Notez que tout cela suppose que votre entrée est en radians et dans la plage [0: 2π].

Exemple en direct

Est l’angle T entre les angles A et B, il y a toujours deux réponses: vrai et faux.

Nous devons spécifier ce que nous voulons dire et, dans ce cas, nous recherchons les petits angles normalisés de balayage et si notre angle est compris entre ces valeurs. Si deux angles sont présents, il y a un angle de reflection entre eux. La valeur normalisée de T est-elle comprise dans cet angle de reflection?

Si nous faisons pivoter A et B et T tels que T = 0 et normalisons A et B à + -hémicirconférence (180 ° ou 2PI). Ensuite, notre réponse est de savoir si A et B ont des signes différents et se situent dans un hémicirconférence l’un de l’autre.

Si nous soustrayons l’angle du test, ajoutez 180 ° (donc A est relatif à T + 180). Ensuite, nous modifions par 360 en nous donnant une plage entre [-360 °, 360 °], nous ajoutons à nouveau 360 ° et mod (remarque, vous pouvez aussi vérifier si c’est négatif et append 360 si c’est le cas), en nous donnant une valeur qui est certain d’être [0 °, 360 °]. Nous soustrayons 180 °, ce qui nous donne une valeur comprise entre [-180 ° et 180 °] par rapport à T + 180 ° -180 °, autrement dit, T. So T est maintenant l’angle zéro et tous les angles se situent dans la plage normalisée. Maintenant, nous vérifions que les angles ont un signe de changement et qu’ils ne sont pas séparés de plus de 180 °. Nous avons notre réponse.

Parce que la question demande 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); } 

Nous pouvons également faire quelques astuces pour simplifier le code et éviter les opérations modulo inutiles (voir commentaires ci-dessous). Normaliser déplacera l’angle a dans la plage [-180 °, 180 °] par rapport à l’angle 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; } 

Aussi, si nous pouvons être sûrs que la plage est [0,360], nous pouvons nous contenter d'une instruction if plus 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 test du code

J’ai trouvé cette citation de ce fil:

si un point P est à l’intérieur du sortingangle ABC, alors

Zone PAB + Zone PBC + Zone PAC = Zone ABC

Notez que si P est sur le bord de AB, BC ou CA, ce qui est indiqué ci-dessus est valable. Mais effectivement, un des secteurs PAB, PBC, PAC est 0 (assurez-vous simplement de vérifier cela).

si P est en dehors de l’égalité, l’égalité ci-dessus ne tient pas …

Comment déterminer la zone? vous avez deux options: 1) le théorème de Heron, implique sqrt, slow 2) plus le produit est croisé (ou effectivement, la moitié de la valeur absolue de (sum des produits vers le bas moins la sum des produits vers le haut))

par exemple, si A = (x1, y1) B = (x2, y2), C = (x3, y3) Superficie = abs (x1 * y2 + x2 * y3 + x3 * y1-x1 * y3-x3 * y2- x2 * y1) / 2

vous voudrez peut-être aussi faire attention aux erreurs en virgule flottante … au lieu de vérifier les inégalités ssortingctes, vérifiez les abs (ba)

Espérons que cela aidera

En utilisant un style de fonction similaire à celui de votre question, j’ai eu de la chance avec les méthodes suivantes:

  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; } 

Je sais que ce message est ancien, mais il ne semble pas y avoir de réponse acceptée et j’ai trouvé l’approche suivante assez fiable. Bien que cela puisse être plus que ce dont vous avez besoin. Il prend en charge des plages d’angle supérieures à 180 degrés (ainsi que des angles supérieurs à 360 degrés et des angles négatifs). Il prend également en charge la précision décimale.

La méthode utilise cette fonction d’assistance normalize() pour convertir les angles en un espace approprié:

 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; } 

Voici la solution:

 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; } 

J’espère que ça aide quelqu’un.

Vous avez l’angle a et c , et vous ne pouvez pas voir si l’angle b est entre ces angles.

Vous pouvez calculer l’angle entre a->b et a->c . Si ∠a->c est inférieur à ∠a->b , b doit être compris entre a et c .

La distance entre les angles, a et b

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

Alors tu peux faire

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

Cela suppose que vous utilisez des radians et non des degrés, comme il se doit. Cela supprime beaucoup de code inutile.

Si vous avez le temps, consultez celui-ci:

 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)); } 

Modifiez les parameters pour qu'ils flottent si vous en avez besoin.