public void BasicTests()
        {
            base.TestElementAccessAndDispose(new FbxMatrix());

            FbxMatrix mx;

            // make sure the constructors compile and don't crash
            mx = new FbxMatrix();
            mx = new FbxMatrix(new FbxMatrix());
            mx = new FbxMatrix(new FbxAMatrix());
            mx = new FbxMatrix(new FbxVector4(), new FbxVector4(), new FbxVector4(1, 1, 1));
            mx = new FbxMatrix(new FbxVector4(), new FbxQuaternion(), new FbxVector4(1, 1, 1));
            mx = new FbxMatrix(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);

            /* Check the values we typed in match up. */
            for (int y = 0; y < 4; ++y)
            {
                for (int x = 0; x < 4; ++x)
                {
                    Assert.AreEqual(x + 4 * y, mx.Get(y, x));
                }
            }
            Assert.AreEqual(new FbxVector4(4, 5, 6, 7), mx.GetRow(1));
            Assert.AreEqual(new FbxVector4(1, 5, 9, 13), mx.GetColumn(1));

            /* Check that set and get work (silly transpose operation). */
            FbxMatrix mx2 = new FbxMatrix();

            for (int y = 0; y < 4; ++y)
            {
                for (int x = 0; x < 4; ++x)
                {
                    mx2.Set(y, x, y + 4 * x);
                    Assert.AreEqual(mx.Get(x, y), mx2.Get(y, x));
                }
            }

            /* normal transpose operation */
            Assert.AreEqual(mx, mx2.Transpose());

            // Test SetIdentity
            Assert.IsFalse(AssertIsIdentity(mx, nothrow: true));
            AssertIsIdentity(mx, 15); // squint very, very, very hard
            mx.SetIdentity();
            AssertIsIdentity(mx);

            // Test getting the elements from a matrix built by TRS
            var translate = new FbxVector4(1, 2, 3);
            var rotate    = new FbxVector4(0, 90, 0);
            var scale     = new FbxVector4(1, 2, .5);

            mx = new FbxMatrix(translate, rotate, scale);
            FbxVector4 t, r, s, shear;
            double     sign;

            mx.GetElements(out t, out r, out shear, out s, out sign);
            Assert.AreEqual(1, sign);
            FbxVector4Test.AssertSimilarXYZ(translate, t);
            FbxVector4Test.AssertSimilarEuler(rotate, r);
            FbxVector4Test.AssertSimilarXYZ(new FbxVector4(), shear);
            FbxVector4Test.AssertSimilarXYZ(scale, s);

            FbxQuaternion q = new FbxQuaternion();

            mx.GetElements(out r, q, out shear, out s, out sign);
            Assert.AreEqual(1, sign);
            FbxVector4Test.AssertSimilarXYZ(translate, t);
            FbxQuaternionTest.AssertSimilar(rotate, q);
            FbxVector4Test.AssertSimilarXYZ(new FbxVector4(), shear);
            FbxVector4Test.AssertSimilarXYZ(scale, s);

            // Try SetTRS and SetTQS with the same arguments.
            using (var X = new FbxMatrix()) {
                X.SetTRS(translate, rotate, scale);
                X.GetElements(out r, q, out shear, out s, out sign);
                Assert.AreEqual(1, sign);
                FbxVector4Test.AssertSimilarXYZ(translate, t);
                FbxQuaternionTest.AssertSimilar(rotate, q);
                FbxVector4Test.AssertSimilarXYZ(new FbxVector4(), shear);
                FbxVector4Test.AssertSimilarXYZ(scale, s);
            }

            using (var X = new FbxMatrix()) {
                FbxQuaternion qRotate = new FbxQuaternion();
                qRotate.ComposeSphericalXYZ(rotate);
                X.SetTQS(translate, q, scale);
                X.GetElements(out r, q, out shear, out s, out sign);
                Assert.AreEqual(1, sign);
                FbxVector4Test.AssertSimilarXYZ(translate, t);
                FbxQuaternionTest.AssertSimilar(rotate, q);
                FbxVector4Test.AssertSimilarXYZ(new FbxVector4(), shear);
                FbxVector4Test.AssertSimilarXYZ(scale, s);

                // While we're at it, transform a vertex.
                // Verify also that w turns out normalized.
                var v  = new FbxVector4(1, 2, 3, 4);
                var v2 = X.MultNormalize(v);
                FbxVector4Test.AssertSimilarXYZW(new FbxVector4(2.5, 6, 2, 1), v2);

                // While we're at it, test that we can invert the matrix.
                // This matrix is invertible (since it's an affine transformation),
                // and the inversion turns out to be exact.
                AssertIsIdentity(X.Inverse() * X);
                using (var inv = new FbxMatrix(
                           0, 0, 2, 0,
                           0, 0.5, 0, 0,
                           -1, 0, 0, 0,
                           3, -1, -2, 1)) {
                    Assert.AreEqual(inv, X.Inverse());
                }
            }

            // Test set column + set row
            mx = new FbxMatrix();
            mx.SetColumn(1, new FbxVector4(1, 2, 3, 4));
            mx.SetRow(2, new FbxVector4(5, 6, 7, 8));
            //check that the column is what we expect
            Assert.AreEqual(1, mx.Get(0, 1));
            Assert.AreEqual(2, mx.Get(1, 1));
            Assert.AreEqual(6, mx.Get(2, 1));   // this value got changed by SetRow
            Assert.AreEqual(4, mx.Get(3, 1));
            // check that the row is what we expect
            Assert.AreEqual(new FbxDouble4(5, 6, 7, 8), mx [2]);

            // Test operators on two matrices.
            using (var a = new FbxMatrix(
                       0, 1, 2, 3,
                       4, 5, 6, 7,
                       8, 9, 10, 11,
                       12, 13, 14, 15)) {
                using (var b = new FbxMatrix(
                           15, 14, 13, 12,
                           11, 10, 9, 8,
                           7, 6, 5, 4,
                           3, 2, 1, 0)) {
                    using (var sum = new FbxMatrix(
                               15, 15, 15, 15,
                               15, 15, 15, 15,
                               15, 15, 15, 15,
                               15, 15, 15, 15)) {
                        Assert.AreEqual(sum, a + b);
                    }
                    using (var diff = new FbxMatrix(
                               -15, -13, -11, -9,
                               -7, -5, -3, -1,
                               1, 3, 5, 7,
                               9, 11, 13, 15)) {
                        Assert.AreEqual(diff, a - b);
                    }
                    using (var prod = new FbxMatrix(
                               304, 358, 412, 466,
                               208, 246, 284, 322,
                               112, 134, 156, 178,
                               16, 22, 28, 34)) {
                        Assert.AreEqual(prod, a * b);
                    }
                    using (var neg = new FbxMatrix(
                               0, -1, -2, -3,
                               -4, -5, -6, -7,
                               -8, -9, -10, -11,
                               -12, -13, -14, -15)) {
                        Assert.AreEqual(neg, -a);
                    }
                }
            }

            var eyePosition  = new FbxVector4(1, 2, 3);
            var eyeDirection = new FbxVector4(-1, -1, -1);
            var eyeUp        = new FbxVector4(0, 1, 0);

            using (mx = new FbxMatrix()) {
                mx.SetLookToRH(eyePosition, eyeDirection, eyeUp);
                AssertSimilar(new FbxMatrix(
                                  0.707, -0.408, 0.577, 0,
                                  0, 0.816, 0.577, 0,
                                  -0.707, -0.408, 0.577, 0,
                                  1.414, 0, -3.464, 1), mx, 1e-2);

                mx.SetLookToLH(eyePosition, eyeDirection, eyeUp);
                AssertSimilar(new FbxMatrix(
                                  -0.707, -0.408, -0.577, 0,
                                  0, 0.816, -0.577, 0,
                                  0.707, -0.408, -0.577, 0,
                                  -1.414, 0, 3.464, 1), mx, 1e-2);

                mx.SetLookAtRH(eyePosition, eyeDirection, eyeUp);
                AssertSimilar(new FbxMatrix(
                                  0.894, -0.249, 0.371, 0,
                                  0, 0.834, 0.557, 0,
                                  -0.447, -0.498, 0.742, 0,
                                  0.447, 0.083, -3.713, 1), mx, 1e-2);

                mx.SetLookAtLH(eyePosition, eyeDirection, eyeUp);
                AssertSimilar(new FbxMatrix(
                                  -0.894, -0.249, -0.371, 0,
                                  0, 0.834, -0.557, 0,
                                  0.447, -0.498, -0.742, 0,
                                  -0.447, 0.083, 3.713, 1), mx, 1e-2);
            }
        }
        public void BasicTests()
        {
            base.TestElementAccessAndDispose(new FbxAMatrix());

            // make sure the constructors compile and don't crash
            new FbxAMatrix();
            new FbxAMatrix(new FbxAMatrix());
            var mx = new FbxAMatrix(new FbxVector4(), new FbxVector4(), new FbxVector4(1, 1, 1));

            // check that the matrix is the id matrix
            Assert.IsTrue(mx.IsIdentity());
            for (int y = 0; y < 4; ++y)
            {
                for (int x = 0; x < 4; ++x)
                {
                    Assert.AreEqual(x == y ? 1 : 0, mx.Get(y, x));
                }
            }

            // Test that all the operations work.
            // In particular, test that they don't return the default element
            // when they aren't supposed to.

            var translate = new FbxVector4(5, 3, 1);
            var euler     = new FbxVector4(-135, -90, 0);
            var scale     = new FbxVector4(1, 2, .5);
            var quat      = new FbxQuaternion();

            quat.ComposeSphericalXYZ(euler);

            mx = new FbxAMatrix(translate, euler, scale);
            Assert.IsFalse(mx.IsIdentity());
            Assert.IsTrue(mx.IsIdentity(10)); // squint very, very, very hard

            FbxVector4Test.AssertSimilarXYZ(translate, mx.GetT());
            FbxVector4Test.AssertSimilarEuler(euler, mx.GetR());
            FbxQuaternionTest.AssertSimilar(quat, mx.GetQ());
            FbxVector4Test.AssertSimilarXYZ(scale, mx.GetS());
            FbxVector4Test.AssertSimilarXYZ(new FbxVector4(0.354, 0.354, 0), mx.GetRow(2), 1e-2);
            FbxVector4Test.AssertSimilarXYZ(new FbxVector4(1, 0, 0), mx.GetColumn(2));

            mx.SetT(translate * 2);
            FbxVector4Test.AssertSimilarXYZ(2 * translate, mx.GetT());

            mx.SetR(euler * 2);
            FbxVector4Test.AssertSimilarEuler(2 * euler, mx.GetR());

            mx.SetQ(quat * 2);
            FbxQuaternionTest.AssertSimilar(2 * quat, mx.GetQ());

            mx.SetS(scale * 2);
            FbxVector4Test.AssertSimilarXYZ(2 * scale, mx.GetS());

            mx.SetTRS(translate, euler, scale);
            FbxVector4Test.AssertSimilarXYZ(translate, mx.GetT());

            mx.SetTQS(2 * translate, 2 * quat, 2 * scale);
            FbxVector4Test.AssertSimilarXYZ(2 * translate, mx.GetT());

            // Test Inverse.
            var mxInv = mx.Inverse();

            Assert.AreNotEqual(mx.GetT(), mxInv.GetT());
            Assert.IsTrue((mx * mxInv).IsIdentity());

            // Test multiplying by a translation. Really we just want to make sure we got a result
            // different than doing nothing.
            FbxVector4Test.AssertSimilarXYZ(new FbxVector4(17.778175, 2.464466, 4), mx.MultT(new FbxVector4(1, 2, 3)), 1e-5);

            // Test multiplying by a rotation.
            FbxVector4Test.AssertSimilarEuler(new FbxVector4(-180, 0, 45), mx.MultR(new FbxVector4(0, -90, 0)));
            quat.ComposeSphericalXYZ(new FbxVector4(0, -90, 0));
            quat = mx.MultQ(quat);
            var quatExpected = new FbxQuaternion();

            quatExpected.ComposeSphericalXYZ(new FbxVector4(-180, 0, 45));
            FbxQuaternionTest.AssertSimilar(quatExpected, quat);

            // Test multiplying a scale.
            FbxVector4Test.AssertSimilarXYZ(new FbxVector4(4, 6, .5), mx.MultS(new FbxVector4(2, 1.5, .5)));

            // Test scaling. Multiply/divide by powers of two so there's no roundoff.
            // The scale/rotate is scaled, the translation is cleared to (0,0,0,1).
            AssertScaled(mx, mx * 2, 2);
            AssertScaled(mx, 2 * mx, 2);
            AssertScaled(mx, mx / 2, 0.5);

            // Test negating. This is different from scaling by -1.
            using (var mxNegated = -mx) {
                for (int y = 0; y < 4; ++y)
                {
                    for (int x = 0; x < 4; ++x)
                    {
                        Assert.AreEqual(-mx.Get(x, y), mxNegated.Get(x, y),
                                        string.Format("Index {0} {1}", x, y));
                    }
                }
            }

            // Test transpose.
            using (var mxTranspose = mx.Transpose()) {
                for (int y = 0; y < 4; ++y)
                {
                    for (int x = 0; x < 4; ++x)
                    {
                        Assert.AreEqual(mx.Get(y, x), mxTranspose.Get(x, y),
                                        string.Format("Index {0} {1}", x, y));
                    }
                }
            }

            // Test setting to identity.
            mx.SetIdentity();
            Assert.IsTrue(mx.IsIdentity());

            // Slerp between two rotation matrices.
            var q1 = new FbxQuaternion(); q1.ComposeSphericalXYZ(new FbxVector4(0, -90, 0));
            var q2 = new FbxQuaternion(); q2.ComposeSphericalXYZ(new FbxVector4(0, 90, 0));

            var m1 = new FbxAMatrix(); m1.SetQ(q1);
            var m2 = new FbxAMatrix(); m2.SetQ(q2);


            var m12 = m1.Slerp(m2, 0.25);
            var q12 = new FbxQuaternion(); q12.ComposeSphericalXYZ(new FbxVector4(0, -45, 0));

            FbxQuaternionTest.AssertSimilar(q12, m12.GetQ());
        }