0

Am I wrong on assuming that by arbitrary converting from Quaternion to Matrix of Vecmath classes should remain the same transformation to a vector/point?

Here is my test script. It just loops around printing the rotated vector, testing the result and converting quaternion to matrix and vice versa.

public class Test {

    public static Vector3d rotateVector( Quat4d q, Vector3d v )
    {
        Quat4d w = new Quat4d();
        w.x = v.x;
        w.y = v.y;
        w.z = v.z;
        w.w = 0;

        Quat4d qTmp = new Quat4d();

        // q * w * q^-1

        qTmp.mul( q, w );
        qTmp.mulInverse( q );

        return new Vector3d( qTmp.x, qTmp.y, qTmp.z );
    }

    public static Vector3d rotateVector( Matrix4d m, Vector3d v )
    {
        Point3d vp = new Point3d( v );

        m.transform( vp );

        return new Vector3d( vp );
    }

    public static final double EPS = 0.00000001;

    public static void main( String[] args )
    {
        Quat4d q = new Quat4d();
        q.set( new AxisAngle4d( new Vector3d( 1, 0, -1 ), Math.PI ) ); // same as rotation x 90°, y 90°, z -90° in static frame

        Matrix4d m = new Matrix4d();

        Vector3d v = new Vector3d( 1, 2, 3 );

        Vector3d vResult = new Vector3d( -3, -2, -1 );

        String rotMethod = "";

        for( int i = 0; i < 4; i++ )
        {
            rotMethod += "q";
            Vector3d vq = rotateVector( q, v );
            System.out.println( rotMethod + ": " + vq + " ==> " + vResult.epsilonEquals( vq, EPS ) );

            m.set( q );

            rotMethod += "m";
            Vector3d vm = rotateVector( m, v );
            System.out.println( rotMethod + ": " + vm + " ==> " + vResult.epsilonEquals( vm, EPS ) );

            q.set( m );
        }
    }
}

Here is the output. First quaternionen and first matrix are doing ok. But then they drift off and converge to a somewhat mirrowed point.

q: (-3.0, -2.0000000000000004, -1.0) ==> true
qm: (-2.9999999999999987, -1.9999999999999993, -0.9999999999999989) ==> true
qmq: (1.4421707565920456, 0.2675892211829013, 3.4421707565920463) ==> false
qmqm: (1.0000000000000002, 1.9999999999999998, 3.0) ==> false
qmqmq: (1.0, 1.9999999999999996, 3.0) ==> false
qmqmqm: (1.0000000000000002, 1.9999999999999998, 3.0) ==> false
qmqmqmq: (1.0, 1.9999999999999996, 3.0) ==> false
qmqmqmqm: (1.0000000000000002, 1.9999999999999998, 3.0) ==> false

Thanks in advance for your help and time.


Edit: Workaround

Every Matrix to Quaternion conversion which I could find in the web were unstable with my test script like the vecmath library.

Following implementation were tested:

A workaround with Matrix -> Euler -> Quaternion provides the expected results. I fused the implementation of both conversion from Christoph Gohlke.

public static void setQuatFromMatrix( Quat4d quat, Matrix4d mat )
{
    double az, ay, ax;
    double ai, aj, ak;
    double si, sj, sk;
    double ci, cj, ck;
    double cy, cc, cs, sc, ss;

    cy = Math.sqrt( mat.m00 * mat.m00 + mat.m10 * mat.m10 );

    if( cy > MathUtil.EPS )
    {
        ax = Math.atan2( mat.m21, mat.m22 );
        ay = Math.atan2( -mat.m20, cy );
        az = Math.atan2( mat.m10, mat.m00 );
    }
    else
    {
        ax = Math.atan2( -mat.m12, mat.m11 );
        ay = Math.atan2( -mat.m20, cy );
        az = 0.0;
    }

    ai = ax / 2.0;
    aj = ay / 2.0;
    ak = az / 2.0;

    ci = Math.cos( ai );
    si = Math.sin( ai );
    cj = Math.cos( aj );
    sj = Math.sin( aj );
    ck = Math.cos( ak );
    sk = Math.sin( ak );
    cc = ci * ck;
    cs = ci * sk;
    sc = si * ck;
    ss = si * sk;

    quat.x = cj * sc - sj * cs;
    quat.y = cj * ss + sj * cc;
    quat.z = cj * cs - sj * sc;
    quat.w = cj * cc + sj * ss;
}

I didn't optimize it because I can't figure how but it works for me. Here is the output:

q: (-3.0, -2.0000000000000004, -1.0) ==> true
qm: (-2.9999999999999987, -1.9999999999999993, -0.9999999999999989) ==> true
qmq: (-2.9999999999999996, -2.0000000000000004, -1.0000000000000009) ==> true
qmqm: (-2.9999999999999996, -2.0000000000000004, -1.0000000000000007) ==> true
qmqmq: (-2.9999999999999996, -2.0000000000000004, -1.0000000000000009) ==> true
qmqmqm: (-2.9999999999999996, -2.0000000000000004, -1.0000000000000007) ==> true
qmqmqmq: (-2.9999999999999996, -2.0000000000000004, -1.0000000000000009) ==> true
qmqmqmqm: (-2.9999999999999996, -2.0000000000000004, -1.0000000000000007) ==> true
Jay
  • 21
  • 4
  • @Ali But any conversion, even the ambiguous ones, should rotate any point to the same coordinate? I'm testing for the result vector not for the quaternions or matrices. – Jay Aug 09 '13 at 14:09
  • Exactly. Hmm, if it is not like that then you have a bug somewhere... :( – Ali Aug 09 '13 at 18:07
  • OK, it was my mistake, I apologize. – Ali Aug 09 '13 at 18:09
  • No problem @Ali. But you agree on my assumption. I'm wondering where to report this bug. Do you have an alternative library or implementation recommendation? – Jay Aug 09 '13 at 19:20
  • No, unfortunately not. In any case, I would double-check my code to make sure that the bug is not in my code and I would prepare a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org/). Sorry I couldn't help more... – Ali Aug 09 '13 at 19:49

0 Answers0