using System; using System.Collections.Generic; using System.Numerics; using System.Text; using NUnit.Framework; namespace SharpGLTF { // [System.Diagnostics.DebuggerStepThrough] public static class NumericsAssert { public static double UnitError(this Vector3 v) { return v.LengthError(1); } public static double LengthError(this Vector3 v, double expectedLength) { return Math.Abs(Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z) - expectedLength); } public static void IsFinite(Single value, string message = null) { // Assert.IsTrue(float.IsFinite(value), message); Assert.That(!float.IsNaN(value) && !float.IsInfinity(value), Is.True, message); } public static void IsFinite(Double value, string message = null) { // Assert.IsTrue(double.IsFinite(value), message); Assert.That(!Double.IsNaN(value) && !Double.IsInfinity(value), Is.True, message); } public static void IsFinite(Vector2 vector) { IsFinite(vector.X, "X"); IsFinite(vector.Y, "Y"); } public static void IsFinite(Vector3 vector) { IsFinite(vector.X, "X"); IsFinite(vector.Y, "Y"); IsFinite(vector.Z, "Z"); } public static void IsFinite(Vector4 vector) { IsFinite(vector.X, "X"); IsFinite(vector.Y, "Y"); IsFinite(vector.Z, "Z"); IsFinite(vector.W, "W"); } public static void IsFinite(Quaternion quaternion) { IsFinite(quaternion.X, "X"); IsFinite(quaternion.Y, "Y"); IsFinite(quaternion.Z, "Z"); IsFinite(quaternion.W, "W"); } public static void IsFinite(Plane plane) { IsFinite(plane.Normal.X, "Normal.X"); IsFinite(plane.Normal.Y, "Normal.Y"); IsFinite(plane.Normal.Z, "Normal.Z"); IsFinite(plane.D, "D"); } public static void IsFinite(Matrix3x2 matrix) { IsFinite(matrix.M11, "M11"); IsFinite(matrix.M12, "M12"); IsFinite(matrix.M21, "M21"); IsFinite(matrix.M22, "M22"); IsFinite(matrix.M31, "M31"); IsFinite(matrix.M32, "M32"); } public static void IsFinite(Matrix4x4 matrix) { IsFinite(matrix.M11, "M11"); IsFinite(matrix.M12, "M12"); IsFinite(matrix.M13, "M13"); IsFinite(matrix.M14, "M14"); IsFinite(matrix.M21, "M21"); IsFinite(matrix.M22, "M22"); IsFinite(matrix.M23, "M23"); IsFinite(matrix.M24, "M24"); IsFinite(matrix.M31, "M31"); IsFinite(matrix.M32, "M32"); IsFinite(matrix.M33, "M33"); IsFinite(matrix.M34, "M34"); IsFinite(matrix.M41, "M41"); IsFinite(matrix.M42, "M42"); IsFinite(matrix.M43, "M43"); IsFinite(matrix.M44, "M44"); } public static void AreEqual(BigInteger expected, BigInteger actual, double tolerance = 0) { Assert.That((double)BigInteger.Abs(actual - expected), Is.EqualTo(0).Within(tolerance)); } public static void AreEqual(Vector2 expected, Vector2 actual, double tolerance = 0) { Assert.Multiple(() => { Assert.That(actual.X, Is.EqualTo(expected.X).Within(tolerance), "X"); Assert.That(actual.Y, Is.EqualTo(expected.Y).Within(tolerance), "Y"); }); } public static float AreEqual(Vector3 expected, Vector3 actual, double tolerance = 0) { Assert.Multiple(() => { Assert.That(actual.X, Is.EqualTo(expected.X).Within(tolerance), "X"); Assert.That(actual.Y, Is.EqualTo(expected.Y).Within(tolerance), "Y"); Assert.That(actual.Z, Is.EqualTo(expected.Z).Within(tolerance), "Z"); }); // get tolerance var tx = Math.Abs(expected.X - actual.X); var ty = Math.Abs(expected.Y - actual.Y); var tz = Math.Abs(expected.Z - actual.Z); return Math.Max(tx, Math.Max(ty, tz)); } public static void AreEqual(Vector4 expected, Vector4 actual, double tolerance = 0) { Assert.Multiple(() => { Assert.That(actual.X, Is.EqualTo(expected.X).Within(tolerance), "X"); Assert.That(actual.Y, Is.EqualTo(expected.Y).Within(tolerance), "Y"); Assert.That(actual.Z, Is.EqualTo(expected.Z).Within(tolerance), "Z"); Assert.That(actual.W, Is.EqualTo(expected.W).Within(tolerance), "W"); }); } public static void AreEqual(Quaternion expected, Quaternion actual, double tolerance = 0) { Assert.Multiple(() => { Assert.That(actual.X, Is.EqualTo(expected.X).Within(tolerance), "X"); Assert.That(actual.Y, Is.EqualTo(expected.Y).Within(tolerance), "Y"); Assert.That(actual.Z, Is.EqualTo(expected.Z).Within(tolerance), "Z"); Assert.That(actual.W, Is.EqualTo(expected.W).Within(tolerance), "W"); }); } public static void AreEqual(Matrix4x4 expected, Matrix4x4 actual, double tolerance = 0) { Assert.Multiple(() => { Assert.That(actual.M11, Is.EqualTo(expected.M11).Within(tolerance), "M11"); Assert.That(actual.M12, Is.EqualTo(expected.M12).Within(tolerance), "M12"); Assert.That(actual.M13, Is.EqualTo(expected.M13).Within(tolerance), "M13"); Assert.That(actual.M14, Is.EqualTo(expected.M14).Within(tolerance), "M14"); Assert.That(actual.M21, Is.EqualTo(expected.M21).Within(tolerance), "M21"); Assert.That(actual.M22, Is.EqualTo(expected.M22).Within(tolerance), "M22"); Assert.That(actual.M23, Is.EqualTo(expected.M23).Within(tolerance), "M23"); Assert.That(actual.M24, Is.EqualTo(expected.M24).Within(tolerance), "M24"); Assert.That(actual.M31, Is.EqualTo(expected.M31).Within(tolerance), "M31"); Assert.That(actual.M32, Is.EqualTo(expected.M32).Within(tolerance), "M32"); Assert.That(actual.M33, Is.EqualTo(expected.M33).Within(tolerance), "M33"); Assert.That(actual.M34, Is.EqualTo(expected.M34).Within(tolerance), "M34"); Assert.That(actual.M41, Is.EqualTo(expected.M41).Within(tolerance), "M41"); Assert.That(actual.M42, Is.EqualTo(expected.M42).Within(tolerance), "M42"); Assert.That(actual.M43, Is.EqualTo(expected.M43).Within(tolerance), "M43"); Assert.That(actual.M44, Is.EqualTo(expected.M44).Within(tolerance), "M44"); }); } public static float AreGeometryicallyEquivalent(Matrix4x4 expected, Matrix4x4 actual, double tolerance = 0) { var expectedX = Vector3.Transform(Vector3.UnitX, expected); var expectedY = Vector3.Transform(Vector3.UnitY, expected); var expectedZ = Vector3.Transform(Vector3.UnitZ, expected); var actualX = Vector3.Transform(Vector3.UnitX, actual); var actualY = Vector3.Transform(Vector3.UnitY, actual); var actualZ = Vector3.Transform(Vector3.UnitZ, actual); var tx = AreEqual(expectedX, actualX, tolerance); var ty = AreEqual(expectedY, actualY, tolerance); var tz = AreEqual(expectedZ, actualZ, tolerance); return Math.Max(tx, Math.Max(ty, tz)); } public static void IsInvertible(Matrix3x2 matrix) { IsFinite(matrix); Assert.That(Matrix3x2.Invert(matrix, out Matrix3x2 inverted), Is.True); } public static void IsInvertible(Matrix4x4 matrix) { IsFinite(matrix); Assert.That(Matrix4x4.Invert(matrix, out Matrix4x4 inverted), Is.True); } public static void IsOrthogonal3x3(Matrix4x4 matrix, double tolerance = 0) { IsFinite(matrix); Assert.Multiple(() => { Assert.That(matrix.M41, Is.EqualTo(0)); Assert.That(matrix.M42, Is.EqualTo(0)); Assert.That(matrix.M43, Is.EqualTo(0)); Assert.That(matrix.M44, Is.EqualTo(1)); }); var cx = new Vector3(matrix.M11, matrix.M21, matrix.M31); var cy = new Vector3(matrix.M12, matrix.M22, matrix.M32); var cz = new Vector3(matrix.M13, matrix.M23, matrix.M33); Assert.Multiple(() => { Assert.That(Vector3.Dot(cx, cy), Is.EqualTo(0).Within(tolerance)); Assert.That(Vector3.Dot(cx, cz), Is.EqualTo(0).Within(tolerance)); Assert.That(Vector3.Dot(cy, cz), Is.EqualTo(0).Within(tolerance)); }); } public static void Length(Vector2 actual, double length, double tolerance = 0) { IsFinite(actual); length = Math.Abs(actual.Length() - length); Assert.That(length, Is.EqualTo(0).Within(tolerance)); } public static void Length(Vector3 actual, double length, double tolerance = 0) { IsFinite(actual); length = Math.Abs(actual.Length() - length); Assert.That(length, Is.EqualTo(0).Within(tolerance)); } public static void Length(Vector4 actual, double length, double tolerance = 0) { IsFinite(actual); length = Math.Abs(actual.Length() - length); Assert.That(length, Is.EqualTo(0).Within(tolerance)); } public static void Length(Quaternion actual, double length, double tolerance = 0) { IsFinite(actual); length = Math.Abs(actual.Length() - length); Assert.That(length, Is.EqualTo(0).Within(tolerance)); } public static void IsNormalized(Vector2 actual, double tolerance = 0) { Length(actual, 1, tolerance); } public static void IsNormalized(Vector3 actual, double tolerance = 0) { Length(actual, 1, tolerance); } public static void IsNormalized(Vector4 actual, double tolerance = 0) { Length(actual, 1, tolerance); } public static void IsNormalized(Quaternion actual, double tolerance = 0) { Length(actual, 1, tolerance); } public static void InRange(BigInteger value, BigInteger min, BigInteger max) { GreaterOrEqual(value, min); LessOrEqual(value, max); } public static void InRange(Vector2 value, Vector2 min, Vector2 max) { GreaterOrEqual(value, min); LessOrEqual(value, max); } public static void InRange(Vector3 value, Vector3 min, Vector3 max) { GreaterOrEqual(value, min); LessOrEqual(value, max); } public static void InRange(Vector4 value, Vector4 min, Vector4 max) { GreaterOrEqual(value, min); LessOrEqual(value, max); } public static void Less(BigInteger arg1, BigInteger arg2) { Assert.That(arg1.CompareTo(arg2), Is.LessThan(0)); } public static void Less(Vector2 arg1, Vector2 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.LessThan(arg2.X), "X"); Assert.That(arg1.Y, Is.LessThan(arg2.Y), "Y"); }); } public static void Less(Vector3 arg1, Vector3 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.LessThan(arg2.X), "X"); Assert.That(arg1.Y, Is.LessThan(arg2.Y), "Y"); Assert.That(arg1.Z, Is.LessThan(arg2.Z), "Z"); }); } public static void Less(Vector4 arg1, Vector4 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.LessThan(arg2.X), "X"); Assert.That(arg1.Y, Is.LessThan(arg2.Y), "Y"); Assert.That(arg1.Z, Is.LessThan(arg2.Z), "Z"); Assert.That(arg1.W, Is.LessThan(arg2.W), "W"); }); } public static void LessOrEqual(BigInteger arg1, BigInteger arg2) { Assert.That(arg1.CompareTo(arg2), Is.LessThanOrEqualTo(0)); } public static void LessOrEqual(Vector2 arg1, Vector2 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.LessThanOrEqualTo(arg2.X), "X"); Assert.That(arg1.Y, Is.LessThanOrEqualTo(arg2.Y), "Y"); }); } public static void LessOrEqual(Vector3 arg1, Vector3 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.LessThanOrEqualTo(arg2.X), "X"); Assert.That(arg1.Y, Is.LessThanOrEqualTo(arg2.Y), "Y"); Assert.That(arg1.Z, Is.LessThanOrEqualTo(arg2.Z), "Z"); }); } public static void LessOrEqual(Vector4 arg1, Vector4 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.LessThanOrEqualTo(arg2.X), "X"); Assert.That(arg1.Y, Is.LessThanOrEqualTo(arg2.Y), "Y"); Assert.That(arg1.Z, Is.LessThanOrEqualTo(arg2.Z), "Z"); Assert.That(arg1.W, Is.LessThanOrEqualTo(arg2.W), "W"); }); } public static void Greater(BigInteger arg1, BigInteger arg2) { Assert.That(arg1.CompareTo(arg2), Is.GreaterThan(0)); } public static void Greater(Vector2 arg1, Vector2 arg2) { Assert.That(arg1.X, Is.GreaterThan(arg2.X), "X"); Assert.That(arg1.Y, Is.GreaterThan(arg2.Y), "Y"); } public static void Greater(Vector3 arg1, Vector3 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.GreaterThan(arg2.X), "X"); Assert.That(arg1.Y, Is.GreaterThan(arg2.Y), "Y"); Assert.That(arg1.Z, Is.GreaterThan(arg2.Z), "Z"); }); } public static void Greater(Vector4 arg1, Vector4 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.GreaterThan(arg2.X), "X"); Assert.That(arg1.Y, Is.GreaterThan(arg2.Y), "Y"); Assert.That(arg1.Z, Is.GreaterThan(arg2.Z), "Z"); Assert.That(arg1.W, Is.GreaterThan(arg2.W), "W"); }); } public static void GreaterOrEqual(BigInteger arg1, BigInteger arg2) { Assert.That(arg1.CompareTo(arg2), Is.GreaterThanOrEqualTo(0)); } public static void GreaterOrEqual(Vector2 arg1, Vector2 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.GreaterThanOrEqualTo(arg2.X), "X"); Assert.That(arg1.Y, Is.GreaterThanOrEqualTo(arg2.Y), "Y"); }); } public static void GreaterOrEqual(Vector3 arg1, Vector3 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.GreaterThanOrEqualTo(arg2.X), "X"); Assert.That(arg1.Y, Is.GreaterThanOrEqualTo(arg2.Y), "Y"); Assert.That(arg1.Z, Is.GreaterThanOrEqualTo(arg2.Z), "Z"); }); } public static void GreaterOrEqual(Vector4 arg1, Vector4 arg2) { Assert.Multiple(() => { Assert.That(arg1.X, Is.GreaterThanOrEqualTo(arg2.X), "X"); Assert.That(arg1.Y, Is.GreaterThanOrEqualTo(arg2.Y), "Y"); Assert.That(arg1.Z, Is.GreaterThanOrEqualTo(arg2.Z), "Z"); Assert.That(arg1.W, Is.GreaterThanOrEqualTo(arg2.W), "W"); }); } public static void AngleLessOrEqual(Vector2 a, Vector2 b, double radians) { var angle = (a, b).GetAngle(); Assert.That(angle, Is.LessThanOrEqualTo(radians), "Angle"); } public static void AngleLessOrEqual(Vector3 a, Vector3 b, double radians) { var angle = (a, b).GetAngle(); Assert.That(angle, Is.LessThanOrEqualTo(radians), "Angle"); } public static void AngleLessOrEqual(Quaternion a, Quaternion b, double radians) { var angle = (a, b).GetAngle(); Assert.That(angle, Is.LessThanOrEqualTo(radians), "Angle"); } } }