Angle entre 3 points?
Points ABC, comment pourrais-je trouver de l'angle ABC? Je suis en train de faire un feehand outil pour une application de dessin vectoriel et de minimiser le nombre de points qu'il génère, je ne vais pas ajouter un points de moins que l'angle de la position de la souris et les 2 derniers points est supérieure à un certain seuil.
Grâce
ce que j'avais:
int CGlEngineFunctions::GetAngleABC( POINTFLOAT a, POINTFLOAT b, POINTFLOAT c )
{
POINTFLOAT ab;
POINTFLOAT ac;
ab.x = b.x - a.x;
ab.y = b.y - a.y;
ac.x = b.x - c.x;
ac.y = b.y - c.y;
float dotabac = (ab.x * ab.y + ac.x * ac.y);
float lenab = sqrt(ab.x * ab.x + ab.y * ab.y);
float lenac = sqrt(ac.x * ac.x + ac.y * ac.y);
float dacos = dotabac / lenab / lenac;
float rslt = acos(dacos);
float rs = (rslt * 180) / 3.141592;
RoundNumber(rs);
return (int)rs;
}
source d'informationauteur jmasterx
Vous devez vous connecter pour publier un commentaire.
Premières suggestions concernant votre méthode:
Ce que vous appelez
ac
est en faitcb
. Mais c'est ok, c'est ce qui est vraiment nécessaire.Ensuite,
C'est votre première erreur. Le réel produit scalaire de deux vecteurs est:
Maintenant,
Ici vous devriez noter qu'en raison de la précision de la perte au cours du calcul, il est théoriquement possible que
dacos
va devenir plus grand que 1 (ou inférieur à -1). Par conséquent, vous devriez vérifier cela de manière explicite.En Plus d'une performance remarque: vous appelez un lourd
sqrt
fonction deux fois pour le calcul de la longueur de deux vecteurs. Ensuite, vous divisez le produit scalaire par ces longueurs.Au lieu de cela, vous pourriez l'appeler
sqrt
sur la multiplication des places de la longueur de deux vecteurs.Et enfin, vous devez noter que votre résultat est précis jusqu'à la
sign
. Voilà, votre méthode de ne pas distinguer les 20° et -20°, depuis le cosinus de deux sont les mêmes.Votre méthode donnera le même angle ABC et ABC.
Une bonne méthode pour le calcul de l'angle est "oslvbo" suggère:
(J'ai juste remplacé
atan
paratan2
).C'est la méthode la plus simple, qui donne toujours le bon résultat. L'inconvénient de cette méthode est que l'on fait appel à une lourde trigonométrie fonction
atan2
deux fois.Je propose la méthode suivante. C'est un peu plus complexe (nécessite une certaine trigonométrie les compétences nécessaires pour comprendre), mais il est supérieur du point de vue des performances.
Il se contente d'appeler une fois par trigonométrie fonction
atan2
. Et pas de racine carrée calculs.EDIT:
Récemment, j'ai travaillé sur un sujet connexe. Et puis j'ai réalisé il y a une meilleure façon. C'est en fait plus ou moins la même (en coulisses). Cependant, il est plus simple à mon humble avis.
L'idée est de faire tourner les deux vecteurs de sorte que le premier est aligné à (positif) X-sens. De toute évidence la rotation de deux vecteurs n'affecte pas l'angle entre eux. Otoh, que, après une telle rotation, il suffit de trouver l'angle de la 2ème vecteur par rapport à l'axe des abscisses. Et c'est exactement ce que
atan2
est pour.De Rotation est obtenue par la multiplication d'un vecteur par la matrice suivante:
Une fois peut voir que le vecteur
a
multiplié par une matrice en effet se tourne vers l'axe X positif.Remarque: Strictement parlant, la matrice n'est pas juste en tournant, c'est aussi mise à l'échelle. Mais c'est ok dans notre cas, puisque la seule chose qui compte, c'est le vecteur de direction, et non pas sa longueur.
Rotation du vecteur
b
devient:Enfin, la réponse peut être exprimé comme:
β = arccos((a^2 + c^2 - b^2) /2ac)
où a est le côté opposé à l'angle α, b est situé en face de l'angle β, et c est à l'opposé de l'angle γ. Si β est ce que vous avez appelé angle ABC.
Approche avec
arccos
est dangereux, car on risque d'avoir c'est l'argument égal à, disons, 1.0000001 et jusqu'à la fin avecEDOMAIN
erreur. Mêmeatan
approche est dangereuse, parce qu'elle implique des divisions, ce qui peut conduire à une division par zéro. Mieux utiliseratan2
en passantdx
etdy
valeurs.Voici un rapide et correcte du calcul de la valeur de l'angle droit:
Hors sujet? Mais vous pouvez le faire avec la loi du cosinus:
Trouver la distance entre A et B (appelons le x), et la distance entre B et C (appelons cela y), et la distance entre A et C (appelons z).
Alors vous savez que z^2=x^2+y^2-2*xycos(ANGLE que VOUS VOULEZ)
par conséquent, l'angle est cos^-1((z^2-x^2-y^2)/(2 x y))=ANGLE
Voici un OpenCV manière à obtenir l'angle entre les 3 points A, B, C) avec B comme le sommet:
Basé sur l'excellente solution par @valdo