0

我正在尝试[x,y]围绕原点旋转一个矢量,以便在旋转完成后它位于 X 轴上。为了做到这一点,我首先计算 和 之间的角度[x,y][1,0]然后对其应用一个简单的二维旋转矩阵。我正在使用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隐式z坐标 0,但结果是一样的。不会抛出错误。一些示例结果:

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

我究竟做错了什么?

4

3 回答 3

2

如果您要旋转矢量以外的其他东西,那么您需要使用R矩阵。但是,如果您只需要旋转矢量,结果将是[Math.sqrt(x*x+y*y),0].

于 2013-07-26T00:20:18.103 回答
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.
于 2013-07-26T04:43:43.757 回答
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)。我几乎为自己解决了它而感到难过,但我认为如果我不在这里发布的话,我不会这么快就完成了。当我检查我的帖子是否有错别字时,我发现了这个问题。

于 2013-07-25T18:53:05.367 回答