// *********************************************************************** // Copyright (c) 2017 Unity Technologies. All rights reserved. // // Licensed under the ##LICENSENAME##. // See LICENSE.md file in the project root for full license information. // *********************************************************************** using NUnit.Framework; using Autodesk.Fbx; namespace Autodesk.Fbx.UnitTests { public class FbxQuaternionTest { #if ENABLE_COVERAGE_TEST [Test] public void TestCoverage() { CoverageTester.TestCoverage(typeof(FbxQuaternion), this.GetType()); } #endif /// /// Check that two quaternions represent a similar rotation. /// /// Either they're equal (within tolerance) or they're exactly opposite. /// Note that a slerp will go opposite directions if they're opposite. /// /// If you want to use the boolean result, pass in 'nothrow' as true. /// Otherwise a failed comparision will throw an exception. /// public static bool AssertSimilar(FbxQuaternion expected, FbxQuaternion actual, double tolerance = 1e-10, bool nothrow = false) { // Are they bitwise equal? if (expected == actual) { return true; } // Compute the dot product. It'll be +1 or -1 if they're the same rotation. if (System.Math.Abs(expected.DotProduct(actual)) >= 1 - tolerance) { return true; } // Fail. Print it out nicely. if (!nothrow) { Assert.AreEqual(expected, actual); } return false; } public static bool AssertSimilar(FbxVector4 euler, FbxQuaternion actual, double tolerance = 1e-10, bool nothrow = false) { var expected = new FbxQuaternion(); expected.ComposeSphericalXYZ(euler); return AssertSimilar(expected, actual, tolerance, nothrow); } [Test] public void TestEquality() { EqualityTester.TestEquality( new FbxQuaternion(0.0, 0.1, 0.2, 0.3), new FbxQuaternion(0.3, 0.2, 0.1, 0.0), new FbxQuaternion(0.0, 0.1, 0.2, 0.3)); } [Test] public void BasicTests () { FbxQuaternion u, v; // make sure the no-arg constructor doesn't crash new FbxQuaternion(); // test dispose using (new FbxQuaternion()) { } DisposeTester.TestDispose(new FbxQuaternion()); // Test other constructors v = new FbxQuaternion(0.1, 0.2, 0.3, 0.4); u = new FbxQuaternion(v); Assert.AreEqual(v, u); u[0] = 0.5; Assert.AreEqual(0.5, u[0]); Assert.AreEqual(0.1, v[0]); // check that setting u doesn't set v // axis-angle constructor and setter v = new FbxQuaternion(new FbxVector4(1,2,3), 90); u = new FbxQuaternion(); u.SetAxisAngle(new FbxVector4(1,2,3), 90); Assert.AreEqual(u, v); // euler v = new FbxQuaternion(); v.ComposeSphericalXYZ(new FbxVector4(20, 30, 40)); var euler = v.DecomposeSphericalXYZ(); Assert.That(euler.X, Is.InRange(19.99, 20.01)); Assert.That(euler.Y, Is.InRange(29.99, 30.01)); Assert.That(euler.Z, Is.InRange(39.99, 40.01)); Assert.AreEqual(0, euler.W); v = new FbxQuaternion(0.1, 0.2, 0.3); Assert.AreEqual(0.1, v[0]); Assert.AreEqual(0.2, v[1]); Assert.AreEqual(0.3, v[2]); Assert.AreEqual(1, v[3]); // w is assumed to be a homogenous coordinate v.Set(0.9, 0.8, 0.7, 0.6); Assert.AreEqual(0.9, v[0]); Assert.AreEqual(0.8, v[1]); Assert.AreEqual(0.7, v[2]); Assert.AreEqual(0.6, v[3]); v.Set(0.9, 0.8, 0.7); Assert.AreEqual(0.9, v[0]); Assert.AreEqual(0.8, v[1]); Assert.AreEqual(0.7, v[2]); v.SetAt(1, 2); Assert.AreEqual(2, v.GetAt(1)); // Test operator[] v = new FbxQuaternion(); v[0] = 0.1; Assert.AreEqual(0.1, v[0]); v[1] = 0.2; Assert.AreEqual(0.2, v[1]); v[2] = 0.3; Assert.AreEqual(0.3, v[2]); v[3] = 0.4; Assert.AreEqual(0.4, v[3]); v.SetAt(3, 0.5); Assert.AreEqual(0.5, v.GetAt(3)); Assert.That(() => v[-1], Throws.Exception.TypeOf()); Assert.That(() => v[ 4], Throws.Exception.TypeOf()); Assert.That(() => v.GetAt(-1), Throws.Exception.TypeOf()); Assert.That(() => v.GetAt( 4), Throws.Exception.TypeOf()); Assert.That(() => v[-1] = 0.5, Throws.Exception.TypeOf()); Assert.That(() => v[ 4] = 0.5, Throws.Exception.TypeOf()); Assert.That(() => v.SetAt(-1, 0.5), Throws.Exception.TypeOf()); Assert.That(() => v.SetAt( 4, 0.5), Throws.Exception.TypeOf()); // Test W/X/Y/Z v.X = 0.1; Assert.AreEqual(0.1, v.X); v.Y = 0.2; Assert.AreEqual(0.2, v.Y); v.Z = 0.3; Assert.AreEqual(0.3, v.Z); v.W = 0.4; Assert.AreEqual(0.4, v.W); // call the multiply/divide/add/sub operators, make sure they're vaguely sane u = new FbxQuaternion(v); v = v * v; Assert.AreNotEqual(0, u.Compare(v, 1e-15)); // test compare can return false v = v * 9; v = 9 * v; v = v + 5; v = v - 5; // undo v + 5 v = v + u; v = v - u; // undo v + u v = v / 81; // undo 9 * (v * 9) v = v / u; // undo v*v Assert.AreEqual(0, u.Compare(v)); // u and v are the same up to rounding Assert.AreEqual(u * u, u.Product(u)); // unary negate and dot product Assert.AreEqual(0, (-u).Compare(-v)); Assert.AreEqual(-0.3, v.DotProduct(-v), 1e-6); Assert.AreEqual(System.Math.Sqrt(0.3), v.Length(), 1e-6); v.Normalize(); Assert.AreEqual(1, v.DotProduct(v), 1e-6); // various others where we assume that FBX works, just test that they don't crash v.Conjugate(); v.Inverse(); v.Slerp(u, 0.5); } } }