2010-04-03 7 views
12

Dites que j'ai deux vecteurs 2D, un pour la position actuelle d'un objet et un pour la position précédente de cet objet. Comment puis-je travailler dans la direction angulaire du voyage?Calculer l'angle de direction à partir de deux vecteurs?

Cette image peut aider à comprendre ce que je suis après:

(image) http://files.me.com/james.ingham/crcvmy

+0

Pouvez-vous expliquer un peu plus? Est-ce que c'est dans un espace 2D ou 3D, pouvez-vous donner un exemple de code et à quoi ressemblent vos matrices? Ces matrices stockent-elles des données de rotation (il devrait probablement s'agir alors d'un quaternion) ou décrivent-elles des transformations? –

+0

http://en.wikipedia.org/wiki/Slope_formula? – Ross

+0

Merci ross, j'essaie actuellement de mettre les réponses en pratique. Je vais vous faire savoir comment je m'entends en une seconde ... –

Répondre

10

Le vecteur de direction de Voyage sera la différence des deux vecteurs de position,

d = (x1, y1) - (x, y) = (x1 - x, y1 - y) 

Maintenant, lorsque vous demandez l'angle de direction, cela dépend dans quelle direction vous voulez mesurer l'angle contre. Est-ce contre l'axe des x? Aller avec la réponse de Radu. Contre un vecteur arbitraire? Voir la réponse de justjeff.

Edit: Pour obtenir l'angle contre l'axe des y:

tan (theta) = (x1 -x)/(y1 - y)   

la tangente de l'angle est le rapport de la coordonnée x du vecteur de différence à la coordonnée y du vecteur de différence.

Alors

theta = arctan[(x1 - x)/(y1 - y)] 

Où arctan signifie tangente inverse. Ne pas confondre avec la réciproque de la tangente, ce que font beaucoup de gens, puisqu'ils sont tous les deux souvent dénotés tan^-1. Et assurez-vous de savoir si vous travaillez en degrés ou en radians.

+0

En fait, c'est contre l'axe Y je cherche –

+0

@ james.ingham: J'espère que ça aide –

+0

Merci C'était arctan que je cherchais! :) –

2

Toujours pas sûr ce que vous entendez par des matrices de rotation, mais c'est un cas simple d'obtenir un azimut à partir d'un vecteur de direction.

La réponse compliquée:

Normalement, vous devez emballer quelques fonctions de conversion/utilitaires avec vos vecteurs 2D: un pour convertir X, Y (cartésienne) à Theta, R (coordonnées polaires). Vous devez également prendre en charge les opérations vectorielles de base telles que l'ajout, la soustraction et le produit scalaire. Votre réponse dans ce cas serait:

double azimuth = (P2 - P1).ToPolarCoordinate().Azimuth; 

Où ToPolarCoordinate() et ToCarhtesianCoordinate() sont deux fonctions réciproques de commutation d'un type de vecteur à l'autre.

Le simple:

double azimuth = acos ((x2-x1)/sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1)); 
//then do a quadrant resolution based on the +/- sign of (y2-y1) and (x2-x1) 
if (x2-x1)>0 { 
    if (y2-y1)<0 { azimuth = Pi-azimuth; } //quadrant 2 
} else 
{ if (y2-y1)> 0 { azimuth = 2*Pi-azimuth;} //quadrant 4 
    else { azimuth = Pi + azimuth;} //quadrant 3 
} 
+0

Désolé, j'ai mis à jour la question mais pas le titre concernant les choses de la matrice ... –

9

Si vous êtes en C (ou une autre langue qui utilise le même jeu de fonctions), alors vous êtes probablement à la recherche de la fonction atan2(). A partir de votre diagramme:

double theta = atan2(x1-x, y1-y); 

Cet angle sera de l'axe vertical, comme vous avez marqué, et sera mesurée en radians (propre unité d'angle de Dieu).

5

Veillez à utiliser atan2 pour éviter les problèmes de quadrant et la division par zéro. C'est ce qu'il y a là-bas.

float getAngle(CGPoint ptA, CGPoint ptOrigin, CGPoint ptB) 
{ 
    CGPoint A = makeVec(ptOrigin, ptA); 
    CGPoint B = makeVec(ptOrigin, ptB); 

    // angle with +ve x-axis, in the range (−π, π] 
    float thetaA = atan2(A.x, A.y); 
    float thetaB = atan2(B.x, B.y); 

    float thetaAB = thetaB - thetaA; 

    // get in range (−π, π] 
    while (thetaAB <= - M_PI) 
     thetaAB += 2 * M_PI; 

    while (thetaAB > M_PI) 
     thetaAB -= 2 * M_PI; 

    return thetaAB; 
} 

Cependant, si vous ne se soucient pas que ce soit un + ve ou angle -ve, il suffit d'utiliser la règle de produit scalaire (moins de charge CPU):

float dotProduct(CGPoint p1, CGPoint p2) { return p1.x * p2.x + p1.y * p2.y; } 

float getAngle(CGPoint A, CGPoint O, CGPoint B) 
{ 
    CGPoint U = makeVec(O, A); 
    CGPoint V = makeVec(O, B); 

    float magU = vecGetMag(U); 
    float magV = vecGetMag(V); 
    float magUmagV = magU * magV; assert (ABS(magUmagV) > 0.00001); 

    // U.V = |U| |V| cos t 
    float cosT = dotProduct(U, V)/magUmagV; 
    float theta = acos(cosT); 
    return theta; 
} 

Notez que dans les deux codes section ci-dessus, si un (ou les deux) vecteurs sont proches de 0, cela va échouer. Donc, vous pourriez vouloir piéger cela en quelque sorte.

Questions connexes