如何获取两个二维向量之间的“逆时针”角度?

3

我有两个向量,想要得到它们之间的夹角,目前我是用以下公式计算的:

acos(dot(v1.unitVector, v2.unitVector))

这是我得到的结果: enter image description here
我想要的是绿色角度而不是红色角度,但我不知道应该使用什么公式...
谢谢。
编辑:当向量仍处于某个位置时(例如前两对向量),它没问题,但每当它处于像第三对中那样的配置时,它就不能再给我正确的角度了。

这可能取决于您使用的语言/平台。 “红色”答案是否为负?如果是,您可以执行(360 + angle) MOD 360(或2 * PI,如果您的答案以弧度表示)。 - D Stanley
我知道,但如果red_angle为负数,则green_angle = 360 + red_angle = (360 + red_angle) MOD 360。如果你的答案是正数(比如purple_angle),那么(360+purple_angle) MOD 360仍将给出purple_angle。因此,它适用于所有情况(正数或负数)。 - D Stanley
@DStanley 很不幸,它也不起作用! - Pop Flamingo
1
这个问题更适合在math.stackexchange.com上询问。 - sid-m
我投票关闭此问题,因为它与编程或软件开发无关,而是与[math.se]有关。 - Pang
显示剩余2条评论
4个回答

9
使用点积计算时,得到的角度与向量顺序无关,并且取两种可能中较小的一个。
对于您所需的内容,您需要使用复数的参数函数,该函数由atan2函数实现。从a = ax + i * ayb = bx + i * by的角度是a共轭乘以b的参数(将ba的角度向后旋转,不考虑比例),在坐标系中为:
(ax-i*ay) * (bx+i*by) = ax*bx+ay*by + i*(ax*by-ay*bx)

所以这个角度是:
atan2( ax*by-ay*bx, ax*bx+ay*by ).

非常感谢! - Pop Flamingo
这段代码仅适用于2D环境...在3D环境中,您必须投影到公共平面或使用acos +点积,然后构造旋转向量进行CW / CCW检查并根据需要纠正结果角度。 - Spektre
在搜寻了许多资料后,这是唯一一个解释得非常清楚的答案。 - palapapa
如果逆时针角度大于180度,则会返回负角度。为了得到0~360度的结果,如果结果为负数,则将结果加上360度。 - palapapa
这在其他答案中已经广泛讨论过了,我们在此处添加信息也不会有任何收获。 - Lutz Lehmann

2
除了接受的答案之外,atan2 的问题在于,如果你想象向量 a 是静态的,而向量 b 逆时针旋转,你会看到返回值从 0 到 π 变化,但突然变为负数并从 -π 到 0 进行,如果你对一个从 0 到 2π 增加的角度感兴趣,这不是很好。

为了解决这个问题,下面的函数方便地将结果从 atan2 映射,并返回一个值,该值在 0 到 2π 之间,正如人们所期望的那样:

const TAU = Math.PI * 2;

/**
 * Gives the angle in radians from vector a to vector b in anticlockwise direction, 
 * ranging from 0 to 2π.
 * 
 * @param {Vector} a
 * @param {Vector} b
 * @returns {Number}
 */
static angle(a, b) {
    let angle = Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);
    if (angle < 0) {
        angle += TAU;
    }
    return angle;
}

这个项目使用JavaScript编写,但是可以轻松移植到其他编程语言中。


1
Lutz已经正确回答了这个问题,但是我强烈建议基于几何代数来编写现代向量数学代码,这将极大地提高抽象级别。
使用GA,您只需将两个向量U和V相乘即可获得一个旋转子。旋转子在内部看起来像A + Bxy,其中A = U点乘V = |U|V|cos(angle),Bxy = U楔积V = |U||V|sin(angle)xy(这等同于复数)。然后,您可以返回旋转子的有符号逆时针角度,即atan2(B,A)。
因此,通过运算符重载,您只需键入(u * v).Angle。最终计算结果相同,但您所思考和工作的抽象级别要高得多。

1
也许这个更加适合:
atan2( ax*by-ay*bx, ax*bx+ay*by ) % (PI*2)

计算可以得到完整逆时针弧度的值。


1
当值为负数时,%(欧几里得模)无法正常工作,您需要执行以下操作:((angle % tau) + tau) % tau,其中tau为2 * pi。 - Tim Rutter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接