2025-03-11 15:30:07 +08:00

165 lines
6.7 KiB
C#

// ***********************************************************************
// 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
{
internal class FbxAMatrixTest : FbxDouble4x4TestBase<FbxAMatrix>
{
[Test]
public void TestEquality()
{
var zero = new FbxVector4();
var one = new FbxVector4(1,1,1);
var mx1 = new FbxAMatrix(zero, zero, one);
var mx2 = new FbxAMatrix(one, zero, one);
var mx1copy = new FbxAMatrix(zero, zero, one);
EqualityTester<FbxAMatrix>.TestEquality(mx1, mx2, mx1copy);
}
// Helper for the scaling operators.
//
// If scale is a power of two, tolerance can be zero.
//
// Scaling an FbxAMatrix scales the 3x3 matrix for scale and rotation,
// and zeroes out the translation.
static void AssertScaled(FbxAMatrix expected, FbxAMatrix scaled,
double scale, double tolerance = 0)
{
for(int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
Assert.AreEqual(scale * expected.Get(x, y), scaled.Get(x, y),
tolerance, string.Format("Index ({0} {1})", x, y));
}
}
Assert.AreEqual(new FbxVector4(0,0,0,1), scaled.GetRow(3));
Assert.AreEqual(new FbxVector4(0,0,0,1), scaled.GetColumn(3));
}
[Test]
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());
}
}
}