Ce dont j'ai besoin, c'est d'un angle de rotation signé entre deux vecteurs Va et Vb situés dans le même plan 3D et ayant la même origine, en sachant que:
L'angle doit être mesuré de manière à ce que si le plan est le plan XY, le Va en représente le vecteur unitaire de l'axe X.
Je suppose que je devrais effectuer une sorte de transformation d’espace de coordonnées en utilisant Va comme axe des X et le produit croisé de Vb et Vn comme axe des Y, puis en utilisant simplement une méthode 2D comme avec atan2 () ou quelque chose du genre. Des idées? Des formules?
Utilisez le produit croisé des deux vecteurs pour obtenir la normale du plan formé par les deux vecteurs. Ensuite, vérifiez le pointproduct entre ce plan et le plan d'origine normal pour voir si elles sont dans la même direction.
angle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
angle = -angle;
}
Vous pouvez le faire en deux étapes:
Déterminer l'angle entre les deux vecteurs
thêta = acos (produit scalaire de Va, Vb). En supposant que Va, Vb sont normalisés. Cela donnera l'angle minimal entre les deux vecteurs
Déterminer le signe de l'angle
Trouver le vecteur V3 = produit croisé de Va, Vb. (la commande est importante)
Si (produit scalaire de V3, Vn) est négatif, thêta est négatif. Sinon, le thêta est positif.
Vous pouvez obtenir l’angle de signature en utilisant le produit dot . Pour obtenir le signe de l'angle, prenez le signe de Vn * (Va x Vb)
. Dans le cas particulier du plan XY, cela se réduit à Va_x*Vb_y - Va_y*Vb_x
.
Traverser un vecteur dans l’autre et normaliser pour obtenir le vecteur unitaire.
Le sinus de l'angle entre les deux vecteurs est égal à la magnitude du produit croisé divisée par la magnitude des deux vecteurs:
Soit thêta l'angle entre les vecteurs. Soit C = Va le produit croisé Vb. ensuite
sin thêta = longueur (C)/(longueur (Va) * longueur (Vb))
Pour déterminer si thêta est positif ou négatif, rappelez-vous que C est perpendiculaire à Va et Vb dans la direction déterminée par la règle main droite . Donc, en particulier, C est parallèle à Vn. Dans votre cas, si C pointe dans la même direction que Vn, alors thêta est négatif, car vous voulez une rotation à gauche. Le moyen de calcul le plus simple pour vérifier rapidement si Vn et C vont dans la même direction consiste simplement à prendre leur produit scalaire; si c'est positif, ils vont dans la même direction.
Tout cela découle des propriétés élémentaires du produit cross .
Le client avancé a fourni la solution suivante (à l’origine, une modification de la question):
SOLUTION:
sina = |Va x Vb| / ( |Va| * |Vb| )
cosa = (Va . Vb) / ( |Va| * |Vb| )
angle = atan2( sina, cosa )
sign = Vn . ( Va x Vb )
if(sign<0)
{
angle=-angle
}
Supposons que Vx soit l’axe des x; étant donné le Vn normal, vous pouvez obtenir l’axe des y par produit croisé, vous pouvez projeter le vecteur Vb sur Vx et Vy Vx et Vy), étant donné la coordonnée (x, y) sur le plan, vous pouvez utiliser atan2 (y, x) pour obtenir l'angle dans la plage [-pi, + pi]
C'est le code Matlab pour calculer l'angle signé entre deux vecteurs u, v soit en 2D, soit en 3D. Le code est explicite. La convention de signe est telle qu’un positif + 90 ° est émis entre ix et iy ([1,0,0], [0,1,0]) ou iy et iz ([0,1,0], [0, 0,1])
function thetaDEG = angDist2Vecs(u,v)
if length(u)==3
%3D, can use cross to resolve sign
uMod = sqrt(sum(u.^2));
vMod = sqrt(sum(v.^2));
uvPr = sum(u.*v);
costheta = min(uvPr/uMod/vMod,1);
thetaDEG = acos(costheta)*180/pi;
%resolve sign
cp=(cross(u,v));
idxM=find(abs(cp)==max(abs(cp)));
s=sign(cp(idxM(1)));
if s < 0
thetaDEG = -thetaDEG;
end
elseif length(u)==2
%2D use atan2
thetaDEG = (atan2(v(2),v(1))-atan2(u(2),u(1)))*180/pi;
else
error('u,v must be 2D or 3D vectors');
end