web-dev-qa-db-fra.com

Angle signé entre deux vecteurs 3D de même origine dans le même plan

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:

  1. Le plan contenant les deux vecteurs est arbitraire et n'est pas parallèle à XY ni à aucun autre des plans cardinaux
  2. Vn - est un avion normal
  3. Les deux vecteurs ainsi que la normale ont la même origine. O = {0, 0, 0}
  4. Va - est une référence pour mesurer la rotation de la main gauche à Vn

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?

43

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

Vous pouvez le faire en deux étapes:

  1. 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

  2. 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.

12
Parag

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.

7
Stephen Canon

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:

http://mathworld.wolfram.com/CrossProduct.html

2
duffymo

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 .

1
David Norman

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
}
1
Peter O.

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]

1
LittleSweet

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
0
Massimo