0

[x,y]回転が完了すると X 軸上にあるように、原点を中心にベクトルを回転させようとしています。これを行うために、まず と の間の角度を計算し[x,y][1,0]次に単純な 2D回転行列をそれに適用します。ベクトルを操作するために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

実際には、既知の 2 次元ベクトルを [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 に答える