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

ce dont j'ai besoin est 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 sachant que:

  1. le plan contenant les deux vecteurs est un arbitraire et n'est pas parallèle à XY ou à tout autre plan cardinal
  2. Vn-est un plan normal
  3. les deux vecteurs avec 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 si le plan serait plan XY Va se présenterait pour l'axe X vecteur unitaire.

je suppose que je devrais effectuer une sorte de transformation de l'espace de coordonnées en utilisant la Va comme axe des X et le produit croisé de Vb et Vn comme axe des Y puis en utilisant juste une méthode 2d comme avec atan2() ou quelque chose. Des idées? Des formules?

41
demandé sur Peter O. 2011-03-04 04:07:32

9 réponses

Utiliser le produit vectoriel de deux vecteurs pour obtenir la normale au plan formé par les deux vecteurs. Ensuite, vérifiez le dotproduct entre celui-ci et le plan d'origine normal pour voir s'ils font face à la même direction.

angle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
  angle = -angle;
}
53
répondu msell 2011-03-04 06:14:14

la solution que j'utilise actuellement semble manquer ici. En supposant que le plan normal est normalisé (|Vn| == 1), l'angle signé est simplement:

atan2((Vb x Va) . Vn, Va . Vb)

qui renvoie un angle dans la plage [- PI, +PI] (ou ce que l'implémentation atan2 disponible renvoie).

. et x point et croix de produit respectivement.

pas de ramification explicite et pas de calcul de division/longueur de vecteur nécessaire. Utilisez Va x Vb pour la main droite rotation à la place de celui de gauche

explication de la raison pour laquelle cela fonctionne: que alpha soit l'angle direct entre les vecteurs (0 ° à 180°) et beta l'angle que nous recherchons (0 ° à 360°) avec beta == alpha ou beta == 360° - alpha

Va . Vb == |Va| * |Vb| * cos(alpha)    (by definition) 
        == |Va| * |Vb| * cos(beta)     (cos(alpha) == cos(-alpha) == cos(360° - alpha)


Va x Vb == |Va| * |Vb| * sin(alpha) * n1  
    (by definition; n1 is a unit vector perpendicular to Va and Vb with 
     orientation matching the right-hand rule)

Therefore (again assuming Vn is normalized):
   n1 . Vn == 1 when beta < 180
   n1 . Vn == -1 when beta > 180

==>  (Va x Vb) . Vn == |Va| * |Vb| * sin(beta)

Enfin

tan(beta) = sin(beta) / cos(beta) == ((Va x Vb) . Vn) / (Va . Vb)
25
répondu Adrian Leonhard 2016-10-12 23:35:07

vous pouvez le faire en deux étapes:

  1. Déterminer l'angle entre les deux vecteurs

    thêta = acos (dot produit de Va, Vb). En supposant Va, Vb sont normalisés. Cela donnera l'angle minimum entre les deux vecteurs

  2. Déterminer le signe de l'angle

    trouver vecteur V3 = produit croisé de Va, Vb. (l'ordre est important)

    si (Point produit de V3, Vn) est négatif, thêta est négatif. Autrement, theta est positif.

12
répondu Parag 2015-06-24 19:54:47

vous pouvez obtenir l'angle jusqu'à signer en utilisant le produit scalaire. Pour obtenir le signe de l'angle, prendre le signe de Vn * (Va x Vb). Dans le cas particulier du plan XY, cela se réduit à juste Va_x*Vb_y - Va_y*Vb_x.

7
répondu Stephen Canon 2011-03-04 04:16:34

croise un vecteur dans l'autre et normalise pour obtenir le vecteur unité.

le sinus de l'angle entre les deux vecteurs est égal à la grandeur du produit croisé divisé par les grandeurs des deux vecteurs:

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

2
répondu duffymo 2011-03-04 01:11:36

supposons que Vx est l'axe des x, étant donné la VN normale, vous pouvez obtenir l'axe des y par produit croisé, vous pouvez projeter le vecteur Vb vers Vx et Vy( par le produit point vous pouvez obtenir la longueur de la projection de Vb sur Vx et Vy), étant donné la(x, y) coordonnée sur le plan, vous pouvez utiliser atan2 (y, x) pour obtenir l'angle dans la gamme [-pi, +pi]

1
répondu LittleSweet 2012-11-17 16:04:01

Advanced Customer a fourni la solution suivante (à l'origine une édition 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
répondu Peter O. 2015-06-16 11:18:11

laisser thêta être l'angle entre les vecteurs. Soit C = Av de la croix du produit Vb. Puis

sin theta = longueur (C) / (longueur(Va) * longueur (Vb))

pour déterminer si theta est positif ou négatif, se rappeler que C est perpendiculaire à Va et VB pointant dans la direction déterminée par le bouton droit de la règle de la main. En particulier, C est parallèle à Vn. Dans votre cas, si C pointe dans la même direction que Vn, alors theta est négatif, puisque vous voulez gaucher de rotation. Probablement le moyen de calcul le plus facile pour vérifier rapidement si Vn et C pointent dans la même direction est de simplement prendre leur produit de point; s'il est positif, ils pointent dans la même direction.

tout cela découle des propriétés élémentaires de la croix.

0
répondu David Norman 2011-03-04 03:50:08

c'est le code Matlab pour calculer l'angle signé entre deux vecteurs u,v soit en 2D ou en 3D. Le code est explicite. La convention des signes est telle qu'un +90° positif est produit 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
répondu Massimo 2016-12-18 19:53:29