我正在尝试围绕原点旋转矢量[x,y]
,以便在旋转完成时它位于X轴上。为了做到这一点,我首先计算[x,y]
和[1,0]
之间的角度,然后对其应用简单的2D rotation matrix。我正在使用numericjs来处理向量。
math.angleBetween = function(A, B) {
var x = numeric.dot(A, B) / (numeric.norm2(A) * numeric.norm2(B));
if(Math.abs(x) <= 1) {
return Math.acos(x);
} else {
throw "Bad input to angleBetween";
}
};
math.alignToX = function(V) {
var theta = -math.angleBetween([1,0], V);
var R = [[Math.cos(theta), -Math.sin(theta)],
[Math.sin(theta), Math.cos(theta)]];
return numeric.dot(R, V);
};
(注意:math
是我项目中的命名空间对象。Math
是数学对象。)
此代码有时 ,但有时无论我运行多少次math.alignToX
,向量都不会接近与X轴对齐。我通过检查y
坐标是否小于1e-10
来测试这个。
我也尝试使用隐式Math.atan2
坐标为0的z
,但结果是一样的。错误不会被抛出。一些示例结果:
math.alignToX([152.44444444444434, -55.1111111111111])
// result: [124.62691466033475, -103.65652585400568]
// expected: [?, 0]
math.alignToX([372, 40])
// result: [374.14435716712336, -2.0605739337042905e-13]
// expected: [?, 0]
// this value has abs(y coordinate) < 1e-10, so its considered aligned
我做错了什么?
答案 0 :(得分:2)
如果您正在旋转除矢量之外的其他内容,则需要使用R
矩阵。但是,如果您只需要旋转矢量,结果将为[Math.sqrt(x*x+y*y),0]
。
答案 1 :(得分:1)
实际上,构建将已知的2d向量与[1,0]对齐的旋转矩阵的任务根本不需要任何三角函数。
事实上,如果[xy]是你的向量而s是它的长度(s = Sqrt(x * x + y * y)),那么映射[xy]以与[1 0]对齐的变换(纯旋转,没有缩放)只是:
[ x y]
T = 1/s^2 [-y x]
例如,假设您的向量是[Sqrt(3)/ 2,1 / 2]。这是一个单位向量,因为你可以很容易地检查s = 1.
[Sqrt(3)/2 1/2 ]
T = [ -1/2 Sqrt(3)/2]
通过我们的向量乘以T得到:
[Sqrt(3)/2 1/2 ][Sqrt(3)/2] [1]
T = [ -1/2 Sqrt(3)/2][ 1/2 ] = [0]
因此,在找到旋转角度(在本例中为Pi / 6)然后创建旋转矩阵时,您只需完整地回到您的开始。 [Sqrt(3)/ 2,1 / 2]的旋转角度为Pi / 2,cos(Pi / 2)为Sqrt(3)/ 2 = x,sin(pi / 2)为1/2 = y
换句话说,如果你知道向量,你就已经知道它与正弦和余弦定义的x轴的正弦和余弦的正弦和余弦:
cos a = x/s
sin a = y/s where s = || [x, y] ||, is the length of the vector.
答案 2 :(得分:0)
我的问题非常明显,以至于我无法相信我没有看到它。在我查看Math.acos
的域时,我根本没有检查范围!当向量位于范围之外时([0,PI]
),会出现问题。以下是我要解决的问题:
math.alignToX = function(V) {
var theta = -math.angleBetween([1,0], V);
var R = [[Math.cos(theta), -Math.sin(theta)],
[Math.sin(theta), Math.cos(theta)]];
var result = numeric.dot(R, V);
if(Math.abs(result[1]) < ZERO_THRESHOLD) {
return result;
} else {
V = numeric.dot([[-1, 0], [0, -1]], V); // rotate by PI
theta = -math.angleBetween([1,0], V);
R = [[Math.cos(theta), -Math.sin(theta)],
[Math.sin(theta), Math.cos(theta)]];
result = numeric.dot(R, V);
if(Math.abs(result[1]) < ZERO_THRESHOLD) {
return result;
} else {
throw "Unable to align " + V; // still don't trust it 100%
}
}
};
对于我上面给出的破碎的例子,这产生了:
[162.10041088743887, 2.842170943040401e-14]
此结果的Y坐标显着小于我的ZERO_THRESHOLD(1e-10)。我几乎感觉很糟糕,我自己解决了这个问题,但如果我没有在这里发布,我认为我不会那么快就这么做。当我查看错别字的帖子时,我看到了问题。