计算必须使用Math.acos
的两个向量之间的角度( EDIT :由于存在Math.acos
方式,因此不必使用Math.atan2
) ,仅接受[-1..1]
范围内的值。但是如果vector1.x==vector2.x
和vector1.y==vector2.y
且由于JS的性质而导致0.1+0.2>0.3
有时Math.acos
得到>1
的情况,并且返回{{ 1}}。
我在所有计算和NaN
之前只进行一次if-check来解决它
还有if (v1.x==v2.x&&v1.y==v2.y)
。
我是这样做的(接受的答案中的 EDIT 具有更好的版本):
return 0
它可以工作,但是,如果有动态图形处理,是否有比60 fps时的中等复杂逻辑检查更好,更有效的方法呢?
答案 0 :(得分:2)
请勿使用acos,而应使用atan2。为了使acos工作,必须对差异进行归一化,并以不同的角度处理pi> pi大小写。使用atan2,您只需提供y,x坐标的差,其余的就可以正确处理。
编辑
您想要矢量之间的角度,而不是差矢量的参数,我不好。我们只需要更改您处理计算错误的方式即可。带有一些伪代码:
function angle_between(ax, ay, bx, by) {
var al = ax*ax+ay*ay;
var bl = bx*bx+by*by;
var dot = (ax*bx+ay*by)/Math.sqrt(al2*bl2);
if (dot >= 1) return 0;
if (dot <= -1) return Math.PI;
return Math.acos(dot);
}
EDIT2
好的,让我们也看看atan2解决方案。正如@njuffa指出的那样,atan2仍然可以用于计算两个向量之间的角度。少一平方根,这很好。它还为我们提供了一个符号角,对于某些应用程序甚至更好。
function signed_angle_between(ax, ay, bx, by) {
var dot = ax*bx + ay*by;
var cross = ax*by - ay*bx;
return Math.atan2(cross, dot);
}
console.log(signed_angle_between(3, 4, 30, 40));
console.log(signed_angle_between(2, 5, -50, 20));
console.log(signed_angle_between(2, 5, 50, -20));
console.log(signed_angle_between(1, 1, -1, -1));
答案 1 :(得分:0)
基于acos
的计算不仅存在因舍入误差引起的伪NaN的问题,导致其自变量超过1,而且还存在数值问题,其结果接近0和π,导致结果不准确
一种避免这两个问题的高级方法是基于atan2
:角(a,b)= atan2(| a×b |,a·b)。我不知道Javascript,但是希望以下实现此功能的ISO-C代码能将一对一的翻译成Javascript:
double angle (double ax, double ay, double bx, double by)
{
double dot = ax * bx + ay * by;
double norm_cross = fabs (ax * by - ay * bx);
return atan2 (norm_cross, dot);
}
根据我的经验,使用atan2
进行的计算应该与通过acos
进行的计算具有大致相同的性能,但是当然是否取决于所用数学库的具体情况。