0

4x4行列(行メジャー)クラスとクォータニオンクラスがあり、回転の2つの表現間で変換する変換メソッドを提供しようとしています。

これは、クォータニオンからマトリックスに変換するための変換関数です。ここで、_2はSystem.Math.Powです。

/// <summary>
/// Converts the quaternion to it's matrix representation.
/// </summary>
/// <returns>A matrix representing the quaternion.</returns>
public Matrix ToMatrix()
{
    return new Matrix(new double[,] {
        {
            _2(W) + _2(X) - _2(Y) - _2(Z),
            (2 * X * Y) - (2 * W * Z),
            (2 * X * Z) + (2 * W * Y),
            0
        },
        {
            (2 * X * Y) + (2 * W * Z),
            _2(W) - _2(X) + _2(Y) - _2(Z),
            (2 * Y * Z) + (2 * W * X),
            0
        },
        {
            (2 * X * Z) - (2 * W * Y),
            (2 * Y * Z) - (2 * W * X),
            _2(W) - _2(X) - _2(Y) + _2(Z),
            0
        },
        {
            0,
            0,
            0,
            1
        }
    });
}

これらは、行列からクォータニオンに変換するための2つの変換関数です。X回転を考慮すると、どちらも機能しないことに注意してください。

/// <summary>
/// Converts the matrix to a quaternion assuming the matrix purely
/// represents rotation (any translation or scaling information will
/// result in an invalid quaternion).
/// </summary>
/// <returns>A quaternion representing the rotation.</returns>
public Quaternion ToQuaternion()
{
    /* http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
        */
    double tr = this.m_Data[0, 0] + this.m_Data[1, 1] + this.m_Data[2, 2];
    if (tr > 0)
    {
        double s = _N2(tr + 1) * 2;
        return new Quaternion(
            (this.m_Data[2, 1] - this.m_Data[1, 2]) / s,
            (this.m_Data[0, 2] - this.m_Data[2, 0]) / s,
            (this.m_Data[1, 0] - this.m_Data[0, 1]) / s,
            0.25 * s
        );
    }
    else if ((this.m_Data[0, 0] > this.m_Data[1, 1]) && (this.m_Data[0, 0] > this.m_Data[2, 2]))
    {
        double s = _N2(1 + this.m_Data[0, 0] - this.m_Data[1, 1] - this.m_Data[2, 2]) * 2;
        return new Quaternion(
            0.25 * s,
            (this.m_Data[0, 1] + this.m_Data[1, 0]) / s,
            (this.m_Data[0, 2] + this.m_Data[2, 0]) / s,
            (this.m_Data[2, 1] - this.m_Data[1, 2]) / s
        );
    }
    else if (this.m_Data[1, 1] > this.m_Data[2, 2])
    {
        double s = _N2(1 + this.m_Data[1, 1] - this.m_Data[0, 0] - this.m_Data[2, 2]) * 2;
        return new Quaternion(
            (this.m_Data[0, 1] + this.m_Data[1, 0]) / s,
            0.25 * s,
            (this.m_Data[1, 2] + this.m_Data[2, 1]) / s,
            (this.m_Data[0, 2] - this.m_Data[2, 0]) / s
        );
    }
    else
    {
        double s = _N2(1 + this.m_Data[2, 2] - this.m_Data[0, 0] - this.m_Data[1, 1]) * 2;
        return new Quaternion(
            (this.m_Data[0, 2] + this.m_Data[2, 0]) / s,
            (this.m_Data[1, 2] + this.m_Data[2, 1]) / s,
            0.25 * s,
            (this.m_Data[1, 0] - this.m_Data[0, 1]) / s
        );
    }
}

/// <summary>
/// This is a simpler form than above, but doesn't work for all values.  It exhibits the
/// *same results* as ToQuaternion for X rotation however (i.e. both are invalid).
/// </summary>
public Quaternion ToQuaternionAlt()
{
    double w = System.Math.Sqrt(1 + this.m_Data[0, 0] + this.m_Data[1, 1] + this.m_Data[2, 2]) / 2;
    return new Quaternion(
        (this.m_Data[2, 1] - this.m_Data[1, 2]) / (4 * w),
        (this.m_Data[0, 2] - this.m_Data[2, 0]) / (4 * w),
        (this.m_Data[1, 0] - this.m_Data[0, 1]) / (4 * w),
        w
    );
}

これで、私のテストスイートには次のような簡単なテストがあります。

[TestMethod]
public void TestMatrixXA()
{
    Matrix m = Matrix.CreateRotationX(45 / (180 / System.Math.PI));
    Assert.AreEqual<Matrix>(m, m.ToQuaternion().ToMatrix(), "Quaternion conversion was not completed successfully.");
}

これは私がテストスイートから得た結果です:

Expected:
{ 1, 0, 0, 0 }
{ 0, 0.707106781186548, -0.707106781186547, 0 }
{ 0, 0.707106781186547, 0.707106781186548, 0 }
{ 0, 0, 0, 1 }

Actual:
{ 1, 0, 0, 0 }
{ 0, 0.707106781186547, 0.707106781186547, 0 }
{ 0, -0.707106781186547, 0.707106781186547, 0 }
{ 0, 0, 0, 1 }

マトリックスの2つの値が反転していることに注意してください。私はそれをテストしました、そして、前後に変換するたびに(つまり、.ToQuaternion()。ToMatrix())、これらのフィールドは反転されます。つまり、クォータニオン/マトリックス変換を2回実行すると、正しいマトリックスが得られます。

正しい値と結果の違いはとても単純なので、マイナス記号が間違った場所にあるような単純なものだと思いますが、私は行列と四元数の数学の専門家ではないので、問題があります問題がどこにあるかを見つける。

数学の何が悪いのか誰か知っていますか?

4

1 に答える 1

0

クォータニオンを行列に変換するための他のソリューションの1つは、機能しているようです。

/// <summary>
/// Converts the quaternion to it's matrix representation.
/// </summary>
/// <returns>A matrix representing the quaternion.</returns>
public Matrix ToMatrix()
{
    if (!this.Normalized)
        return this.Normalize().ToMatrix();

    double xx = X * X;
    double xy = X * Y;
    double xz = X * Z;
    double xw = X * W;

    double yy = Y * Y;
    double yz = Y * Z;
    double yw = Y * W;

    double zz = Z * Z;
    double zw = Z * W;

    return new Matrix(new double[,]
    {
        { 1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0 },
        { 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0 },
        { 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0 },
        { 0, 0, 0, 1 }
    });
}

それぞれの値を再配置して最初の形式にすると、おそらく数学的な違いが微妙にあると思いますが、私にとってはこれでうまくいき、満足しています。

于 2012-07-26T05:01:27.547 に答える