Рассчитать угол направления из двух векторов? - PullRequest
12 голосов
/ 03 апреля 2010

Скажем, у меня есть два 2D вектора, один для текущей позиции объектов и один для предыдущей позиции этих объектов. Как я могу определить угловое направление движения?

Это изображение может помочь понять, что я ищу:

(изображение) http://files.me.com/james.ingham/crcvmy

Ответы [ 4 ]

10 голосов
/ 03 апреля 2010

Вектор направления движения будет разностью двух векторов положения,

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

Теперь, когда вы запрашиваете угол направления, это зависит от того, в каком направлении вы хотите измерить угол. Это против оси х? Иди с ответом Раду. Против произвольного вектора? См. Ответ Justjeff.

Редактировать: Чтобы получить угол относительно оси Y:

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

тангенс угла - это отношение x-координаты вектора разности к y-координате вектора разности.

So

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

Где арктан означает обратную касательную. Не путать с обратной касательной, как это делают многие люди, поскольку их обоих часто обозначают как tan ^ -1. И убедитесь, что вы знаете, работаете ли вы в градусах или радианах.

9 голосов
/ 03 апреля 2010

Если вы находитесь на C (или другом языке, который использует тот же набор функций), то вы, вероятно, ищете функцию atan2(). Из вашей диаграммы:

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

Этот угол будет от вертикальной оси, как вы отметили, и будет измеряться в радианах (собственная угловая единица Бога).

5 голосов
/ 28 сентября 2010

Будьте осторожны, используя atan2 , чтобы избежать проблем с квадрантом и деления на ноль. Вот для чего это.

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

Однако, если вам все равно, будет ли это угол + ve или -ve, просто используйте правило точечного произведения (меньше загрузка процессора):

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

Обратите внимание, что в любом из приведенных выше разделов кода, если один (или оба) вектора близки к длине 0, произойдет сбой. Так что, возможно, вы захотите поймать это в ловушку.

2 голосов
/ 03 апреля 2010

Все еще не уверен, что вы подразумеваете под матрицами вращения, но это простой случай получения азимута от вектора направления.

Сложный ответ:

Обычно вы должны упаковать несколько функций преобразования / утилит с вашими 2D-векторами: одну для преобразования из X, Y (Carthesian) в Theta, R (полярные координаты). Вы также должны поддерживать основные векторные операции, такие как сложение, вычитание и скалярное произведение. Ваш ответ в этом случае будет:

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

Где ToPolarCoordinate () и ToCarhtesianCoordinate () - это две взаимные функции, переключающиеся с одного типа вектора на другой.

Простой:

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