12

假设我有两个 2D 向量,一个用于对象当前位置,一个用于该对象先前位置。如何计算出行进的角度方向?

这张图片可能有助于理解我所追求的:

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

4

4 回答 4

10

行进的方向向量将是两个位置向量的差,

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

现在,当您询问方向角度时,这取决于您要测量角度的方向。是对着x轴吗?跟着拉杜的回答走。针对任意向量?请参阅justjeff的答案。

编辑:要获得相对于 y 轴的角度:

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

角度的正切是差向量的 x 坐标与差向量的 y 坐标的比值。

所以

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

其中 arctan 表示反正切。不要与许多人所做的切线的倒数混淆,因为它们都经常表示为 tan^-1。并确保您知道您是以度数还是弧度数工作。

于 2010-04-03T16:11:12.367 回答
9

如果您使用 C(或使用相同函数集的其他语言),那么您可能正在寻找该atan2()函数。从您的图表中:

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

正如您所标记的那样,该角度将来自垂直轴,并且将以弧度(上帝自己的角度单位)测量。

于 2010-04-03T16:15:17.970 回答
5

小心使用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 角度,只需使用点积规则(较少 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;
}

请注意,在上面的任一代码部分中,如果一个(或两个)向量的长度接近 0,这将失败。所以你可能想以某种方式捕获它。

于 2010-09-28T11:51:40.657 回答
2

仍然不确定旋转矩阵是什么意思,但这是从方向向量获取方位角的简单案例。

复杂的答案:

通常,您应该在 2D 向量中包含一些转换/实用函数:一个用于从 X、Y(笛卡尔坐标)转换为 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
 }
于 2010-04-03T16:09:11.257 回答