using System.Collections.Generic; using NUnit.Framework; using Robust.Shared.Maths; namespace Robust.UnitTesting.Shared.Maths { [TestFixture] [Parallelizable(ParallelScope.All | ParallelScope.Fixtures)] [TestOf(typeof(Matrix3))] public class Matrix3_Test { [Test] public void TranslationTest() { var control = new Vector2(1, 1); var matrix = Matrix3.CreateTranslation(control); var origin = new Vector3(0, 0, 1); Matrix3.Transform(matrix, ref origin); var result = origin.Xy; Assert.That(control == result, Is.True, result.ToString); } private static readonly IEnumerable<(Vector2, double)> _rotationTests = new[] { (new Vector2( 1, 0).Normalized, 0.0), (new Vector2( 1, 1).Normalized, 1 * System.Math.PI / 4.0), (new Vector2( 0, 1).Normalized, 1 * System.Math.PI / 2.0), (new Vector2(-1, 1).Normalized, 3 * System.Math.PI / 4.0), (new Vector2(-1, 0).Normalized, 1 * System.Math.PI / 1.0), (new Vector2(-1,-1).Normalized, 5 * System.Math.PI / 4.0), (new Vector2( 0,-1).Normalized, 3 * System.Math.PI / 2.0), (new Vector2( 1,-1).Normalized, 7 * System.Math.PI / 4.0), }; [Test] [Sequential] public void RotationTest([ValueSource(nameof(_rotationTests))] (Vector2, double) testCase) { var angle = testCase.Item2; var matrix = Matrix3.CreateRotation((float)angle); var test = new Vector3(1, 0, 1); Matrix3.Transform(matrix, ref test); var control = testCase.Item1; var result = test.Xy; Assert.That(MathHelper.CloseTo(control.X, result.X), Is.True, result.ToString); Assert.That(MathHelper.CloseTo(control.Y, result.Y), Is.True, result.ToString); } [Test] public void MultiplyTransformOrder() { var startPoint = new Vector3(1, 0, 1); var scaleMatrix = Matrix3.CreateScale(new Vector2(2, 2)); var rotateMatrix = Matrix3.CreateRotation((float)(System.Math.PI / 2.0)); var translateMatrix = Matrix3.CreateTranslation(new Vector2(-5, -3)); // 1. Take the start point -> ( 1, 0) // 2. Scale it by 2 -> ( 2, 0) // 3. Rotate by +90 degrees -> ( 0, 2) // 4. Translate by (-5, -3) -> (-5,-1) var result = (scaleMatrix * rotateMatrix * translateMatrix) * startPoint; Assert.That(result.X, Is.Approximately(-5f)); Assert.That(result.Y, Is.Approximately(-1f)); } [Test] public void InvertTest() { const float epsilon = 1.0E-7f; var control = Matrix3.Identity; // take our matrix var normalMatrix = new Matrix3( 3, 7, 2, 1, 8, 4, 2, 1, 9 ); // invert it (1/matrix) var invMatrix = Matrix3.Invert(normalMatrix); // multiply it back together Matrix3.Multiply(ref normalMatrix, ref invMatrix, out var leftVerifyMatrix); Matrix3.Multiply(ref invMatrix, ref normalMatrix, out var rightVerifyMatrix); // these should be the same (A × A-1 = A-1 × A = I) Assert.That(leftVerifyMatrix, new ApproxEqualityConstraint(rightVerifyMatrix, epsilon)); // verify matrix == identity matrix (or very close to because float precision) Assert.That(leftVerifyMatrix, new ApproxEqualityConstraint(control, epsilon)); } [Test] public void TranslateMultiplyTest() { // Arrange var mat1 = Matrix3.CreateTranslation(new Vector2(1, 1)); var mat2 = Matrix3.CreateTranslation(new Vector2(-2, -2)); var mat3 = Matrix3.CreateTranslation(new Vector2(3, 3)); mat1.Multiply(ref mat2, out var res2); res2.Multiply(ref mat3, out var res3); // Act Vector3 test = new Vector3(0, 0, 1); Matrix3.Transform(res3, ref test); var result = test.Xy; // Assert Assert.That(MathHelper.CloseTo(result.X, 2), result.ToString); Assert.That(MathHelper.CloseTo(result.Y, 2), result.ToString); } [Test] public void SpaceSwitchTest() { // Arrange var startPoint = new Vector3(2, 0, 1); var rotateMatrix = Matrix3.CreateRotation((float)(System.Math.PI / 6.3967)); var translateMatrix = Matrix3.CreateTranslation(new Vector2(5.357f, -37.53854f)); // NOTE: Matrix Product is NOT commutative. OpenTK (and this) uses pre-multiplication, OpenGL and all the tutorials // you will read about it use post-multiplication. So in OpenTK MVP = M*V*P; in OpenGL it is MVP = P*V*M. Matrix3.Multiply(ref rotateMatrix, ref translateMatrix, out var transformMatrix); // Act Matrix3.Transform(in transformMatrix, in startPoint, out var localPoint); var invMatrix = Matrix3.Invert(transformMatrix); Matrix3.Transform(in invMatrix, in localPoint, out var result); // Assert Assert.That(MathHelper.CloseTo(startPoint.X, result.X), Is.True, result.ToString); Assert.That(MathHelper.CloseTo(startPoint.Y, result.Y), Is.True, result.ToString); } } }