Soit 2 angles dans l'intervalle -PI -> PI autour d'une coordonnée, quelle est la valeur du plus petit des 2 angles entre eux?
En prenant en compte que la différence entre PI et -PI n'est pas 2 PI mais zéro.
Exemple:
Imaginez un cercle, avec 2 lignes sortant du centre, il y a 2 angles entre ces lignes, l’angle qu’ils forment à l’intérieur, aka le plus petit angle, et l’angle qu’ils forment à l’extérieur, aka le plus grand angle. Les deux angles ajoutés forment un cercle complet. Étant donné que chaque angle peut tenir dans une certaine plage, quelle est la valeur des plus petits angles, compte tenu du basculement
Cela donne un angle signé pour tous les angles:
a = targetA - sourceA
a = (a + 180) % 360 - 180
Attention, dans de nombreux langages, l'opération modulo
renvoie une valeur avec le même signe que le dividende (comme C, C++, C #, JavaScript, liste complète ici ). Cela nécessite une fonction personnalisée mod
comme ceci:
mod = (a, n) -> a - floor(a/n) * n
Ou alors:
mod = (a, n) -> (a % n + n) % n
Si les angles sont compris entre [-180 et 180], cela fonctionne également:
a = targetA - sourceA
a += (a>180) ? -360 : (a<-180) ? 360 : 0
De manière plus verbeuse:
a = targetA - sourceA
a -= 360 if a > 180
a += 360 if a < -180
x est l'angle cible. y est la source ou l'angle de départ:
atan2(sin(x-y), cos(x-y))
Il retourne l'angle delta signé. Notez qu'en fonction de votre API l'ordre des paramètres de la fonction atan2 () peut être différent.
Si vos deux angles sont x et y, l’un des angles qui les sépare est abs (x - y). L'autre angle est (2 * PI) - abs (x - y). Donc, la valeur du plus petit des 2 angles est:
min((2 * PI) - abs(x - y), abs(x - y))
Cela vous donne la valeur absolue de l'angle et suppose que les entrées sont normalisées (c'est-à-dire: dans la plage [0, 2π)
).
Si vous souhaitez conserver le signe (c.-à-d. La direction) de l'angle et également accepter des angles en dehors de la plage [0, 2π)
, Vous pouvez généraliser ce qui précède. Voici le code Python pour la version généralisée:
PI = math.pi
TAU = 2*PI
def smallestSignedAngleBetween(x, y):
a = (x - y) % TAU
b = (y - x) % TAU
return -a if a < b else b
Notez que l'opérateur %
Ne se comporte pas de la même manière dans toutes les langues, en particulier lorsque des valeurs négatives sont impliquées. Par conséquent, le portage de certains ajustements de signe peut être nécessaire.
Je relève le défi de fournir la réponse signée:
def f(x,y):
import math
return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs)
Pour les utilisateurs de UnityEngine, le moyen le plus simple consiste simplement à utiliser Mathf.DeltaAngle .
Solution arithmétique (par opposition à algorithmique):
angle = Pi - abs(abs(a1 - a2) - Pi);
Un code efficace en C++ est:
inline double getAbsoluteDiff2Angles(const double x, const double y, const double c)
{
// c can be PI or 180;
return c - fabs(fmod(fabs(x - y), 2*c) - c);
}
Il n’est pas nécessaire de calculer des fonctions trigonométriques. Le code simple en langage C est:
#include <math.h>
#define PIV2 M_PI+M_PI
#define C360 360.0000000000000000000
double difangrad(double x, double y)
{
double arg;
arg = fmod(y-x, PIV2);
if (arg < 0 ) arg = arg + PIV2;
if (arg > M_PI) arg = arg - PIV2;
return (-arg);
}
double difangdeg(double x, double y)
{
double arg;
arg = fmod(y-x, C360);
if (arg < 0 ) arg = arg + C360;
if (arg > 180) arg = arg - C360;
return (-arg);
}
soit dif = a - b, en radians
dif = difangrad(a,b);
laisser dif = a - b, en degrés
dif = difangdeg(a,b);
difangdeg(180.000000 , -180.000000) = 0.000000
difangdeg(-180.000000 , 180.000000) = -0.000000
difangdeg(359.000000 , 1.000000) = -2.000000
difangdeg(1.000000 , 359.000000) = 2.000000
Pas de péché, pas de cos, pas de bronzage, .... seulement de la géométrie !!!!