【问题标题】:Rotating 2D Vector by unknown angle such that its direction vector is [1,0]以未知角度旋转二维向量,使其方向向量为 [1,0]
【发布时间】:2013-07-26 22:23:12
【问题描述】:

我正在尝试围绕原点旋转矢量[x,y],这样当旋转完成时,它位于 X 轴上。为此,我首先计算[x,y][1,0] 之间的角度,然后对其应用简单的二维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,隐式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

我做错了什么?

【问题讨论】:

    标签: javascript math geometry


    【解决方案1】:

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

    【讨论】:

    • 这比我的解决方案要好得多。谢谢!
    • 是的,他需要 R 来类似地旋转其他点,但不需要计算三角函数来计算 R。
    【解决方案2】:

    实际上,构建将已知二维向量与 [1, 0] 对齐的旋转矩阵的任务根本不需要任何三角函数。

    事实上,如果 [x y] 是你的向量,s 是它的长度(s = Sqrt(x*x + y*y)),那么映射 [x y] 到与 [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.
    

    【讨论】:

    • 非常好。您可能需要添加s=Sqrt(x*x+y*y),以便T=1/(x*x+y*y) * [[x y][-y x]]
    • 想了想,我意识到:如果你将[x,y] 映射到[1,0],那么你已经缩放了东西。所以我们应该有T=1/s*[[x y][-y x]]
    • @Teepeemm,这就是我在第一稿中的想法,然后我重新阅读了 OP 的问题,发现他想要的是相同的方向,而不是大小。至少我是这么解释的。你同意吗?
    • 我将 OP 读为想要[1,0] 方向和[x,y] 大小的向量。例如,我认为他给出的第二个例子就是他想要的。 (另一种看待它的方式:因为T 只作用于[x,y] 而不是任何其他点,所以问“我怎样才能做到[1,0]?”将是一个荒谬的问题。)但我承认,如果T 应该作用于其他点,然后将 [x,y] 变成 [1,0] 将是一个有效的问题。
    【解决方案3】:

    我的问题如此明显,以至于我不敢相信我没有看到它。当我检查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)。我几乎为自己解决了它而感到难过,但如果我不在这里发布,我认为我不会这么快就完成了。我在检查帖子是否有错别字时发现了问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-02
      相关资源
      最近更新 更多