using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Globalization; using UnitTestSharp; namespace Azimuth.UnitTests { public class AffineMatrixTests : TestFixture { public void CTor_ScalarScale() { AffineMatrix matrix = new AffineMatrix(Math.PI / 4, new Vector(2, -3), 10); Scalar sqrt = Math.Sqrt(2) * 10; CheckEqual(new Vector(2 + sqrt, -3), matrix.TransformPoint(new Vector(1, -1))); } public void CTor_VectorScale() { AffineMatrix matrix = new AffineMatrix(Math.PI / 4, new Vector(2, -3), new Vector(3, 5)); var expected = new Matrix2x2(Math.Sqrt(2) / 2.0 * 3.0, -Math.Sqrt(2) / 2.0 * 3.0, Math.Sqrt(2) / 2.0 * 5.0, Math.Sqrt(2) / 2.0 * 5.0); CheckEqual(expected, matrix.RotationMatrix); CheckEqual(new Vector(2, -3), matrix.Translation); } public void CTor() { AffineMatrix matrix = new AffineMatrix(Math.PI / 2, new Vector(10, 20)); CheckEqual(0, matrix.M00); CheckEqual(-1, matrix.M01); CheckEqual(10, matrix.M02); CheckEqual(1, matrix.M10); CheckEqual(0, matrix.M11); CheckEqual(20, matrix.M12); } public void CTor_From2DArray() { var array = new Scalar[,] { { 1, 2, 3 }, { 4, 5, 6} }; var matrix = new AffineMatrix(array); CheckEqual(array[0,0], matrix.M00); CheckEqual(array[0,1], matrix.M01); CheckEqual(array[0,2], matrix.M02); CheckEqual(array[1,0], matrix.M10); CheckEqual(array[1,1], matrix.M11); CheckEqual(array[1,2], matrix.M12); } public void Ctor_GivenCols() { var v1 = new Vector(1, 0); var v2 = new Vector(3, 1); var v3 = new Vector(-1, 2); var mat = new AffineMatrix(v1, v2, v3); var expected = new AffineMatrix( 1, 3, -1, 0, 1, 2 ); CheckEqual(expected, mat); } public void TransformDirection() { Vector vec = new Vector(10, 0); AffineMatrix matrix = new AffineMatrix(Math.PI / 2, new Vector(10, 20)); CheckEqual(new Vector(0, 10), matrix.TransformDirection(vec)); } public void TransformPoint() { Vector vec = new Vector(10, 0); AffineMatrix matrix = new AffineMatrix(Math.PI / 2, new Vector(10, 20)); //Should rotate then translate CheckEqual(new Vector(10, 30), matrix.TransformPoint(vec)); } public void Translation() { Vector point = new Vector(100, -100); AffineMatrix matrix = new AffineMatrix(0, point); CheckEqual(point, matrix.Translation); } public void Determinant() { var array = new Scalar[,] { { 1, 2, 3, }, { 4, 5, 6 } }; AffineMatrix matrix = new AffineMatrix(array); CheckEqual(-3, matrix.Determinant()); } public void Inverse_NotInvertible() { var array = new Scalar[,] { { 1, 2, 4, }, { 16, 32, 64 } }; AffineMatrix forward = new AffineMatrix(array); AffineMatrix backward; bool successfulInversion = forward.Inverse(out backward); CheckFalse(successfulInversion); } public void Inverse() { var array = new Scalar[,] { { 1, 2, 4, }, { 16, 2, 64 } }; AffineMatrix forward = new AffineMatrix(array); AffineMatrix backward; bool success = forward.Inverse(out backward); CheckEqual(AffineMatrix.Identity, forward * backward); CheckEqual(AffineMatrix.Identity, backward * forward); Check(success); } public void Inverse_TransformPoint() { var array = new Scalar[,] { { 1, 2, 4, }, { 16, 2, 64 } }; AffineMatrix forward = new AffineMatrix(array); AffineMatrix backward; bool success = forward.Inverse(out backward); Vector vec = new Vector(8, 2); CheckEqual(vec, forward.TransformPoint(backward.TransformPoint(vec))); CheckEqual(vec, backward.TransformPoint(forward.TransformPoint(vec))); Check(success); } public void Scalar_Multiplication() { var array = new Scalar[,] { { 1, 2, 3, }, { 4, 5, 6 } }; var doubleArray = new Scalar[,] { { 2, 4, 6, }, { 8, 10, 12 } }; AffineMatrix matrix = new AffineMatrix(array); CheckEqual(new AffineMatrix(doubleArray), matrix * 2); CheckEqual(new AffineMatrix(doubleArray), 2 * matrix); } public void MatrixMultiplication() { var array1 = new Scalar[,] { { 1, 2, 3, }, { 5, 7, 11 }, }; var array2 = new Scalar[,] { {11, 5, 7, }, {3, 1, 2 }, }; var expected1 = new Scalar[,] { { 17, 7, 14, }, { 76, 32, 60 }, }; var expected2 = new Scalar[,] { { 36, 57, 95, }, { 8, 13, 22 }, }; AffineMatrix a = new AffineMatrix(array1); AffineMatrix b = new AffineMatrix(array2); AffineMatrix expectedMatrix1 = new AffineMatrix(expected1); AffineMatrix expectedMatrix2 = new AffineMatrix(expected2); CheckEqual(expectedMatrix1, a * b); CheckEqual(expectedMatrix2, b * a); } public void Negation() { var origin = new Scalar[,] { { 1, 2, 3, }, { 5, 7, 11 }, }; var expectedArray = new Scalar[,] { { -1, -2, -3, }, { -5, -7, -11 }, }; AffineMatrix actual = new AffineMatrix(origin); actual = -actual; AffineMatrix expected = new AffineMatrix(expectedArray); CheckEqual(expected, actual); } public void ArrayAccess() { var actualArray = new Scalar[,] { { 1, 2, 3, }, { 5, 7, 11 }, }; AffineMatrix actualMatrix = new AffineMatrix(actualArray); CheckEqual(actualArray[0, 0], actualMatrix.M00); CheckEqual(actualArray[0, 1], actualMatrix.M01); CheckEqual(actualArray[0, 2], actualMatrix.M02); CheckEqual(actualArray[1, 0], actualMatrix.M10); CheckEqual(actualArray[1, 1], actualMatrix.M11); CheckEqual(actualArray[1, 2], actualMatrix.M12); } public void MatrixMultiplicationOrder() { AffineMatrix orient = new AffineMatrix(Math.PI / 4, Vector.Zero); AffineMatrix translate = new AffineMatrix(0, new Vector(10, -20)); AffineMatrix scale = new AffineMatrix(5, 0, 0, 0, 5, 0); AffineMatrix concat = (translate * orient * scale); Scalar sqrt = Math.Sqrt(2) / 2 * 5; CheckEqual(new Vector(sqrt + 10, sqrt - 20), concat.TransformPoint(Vector.UnitX)); } public void StaticBuildRotation() { CheckEqual(new AffineMatrix(Math.PI / 2, Vector.Zero), AffineMatrix.BuildFromRotation(Math.PI / 2)); } public void StaticBuildTranslation() { CheckEqual(new AffineMatrix(0, Vector.UnitX), AffineMatrix.BuildFromTranslation(Vector.UnitX)); } public void StaticBuildScaleScalar() { CheckEqual(new AffineMatrix(0, Vector.Zero, 10), AffineMatrix.BuildFromScale(10)); } public void StaticBuildScaleVector() { CheckEqual( new AffineMatrix(0, Vector.Zero, new Vector(1, 2)), AffineMatrix.BuildFromScale(new Vector(1, 2))); } public class IsNaN : TestFixture { public void None() { var array = new Scalar[,] { {1, 2, 3}, {4, 5, 6} }; CheckFalse(AffineMatrix.IsNaN(new AffineMatrix(array))); } public void M00() { var array = new Scalar[,] { { Scalar.NaN, 2, 3, }, { 4, 5, 6 }, }; Check(AffineMatrix.IsNaN(new AffineMatrix(array))); } public void M01() { var array = new Scalar[,] { { 1, Scalar.NaN, 3, }, { 4, 5, 6 }, }; Check(AffineMatrix.IsNaN(new AffineMatrix(array))); } public void M02() { var array = new Scalar[,] { { 1, 2, Scalar.NaN, }, { 4, 5, 6 }, }; Check(AffineMatrix.IsNaN(new AffineMatrix(array))); } public void M10() { var array = new Scalar[,] { { 1, 2, 3, }, { Scalar.NaN, 5, 6 }, }; Check(AffineMatrix.IsNaN(new AffineMatrix(array))); } public void M11() { var array = new Scalar[,] { { 1, 2, 3, }, { 4, Scalar.NaN, 6 }, }; Check(AffineMatrix.IsNaN(new AffineMatrix(array))); } public void M12() { var array = new Scalar[,] { { 1, 2, 3, }, { 4, 5, Scalar.NaN }, }; Check(AffineMatrix.IsNaN(new AffineMatrix(array))); } public void All() { var array = new Scalar[,] { { Scalar.NaN, Scalar.NaN, Scalar.NaN, }, { Scalar.NaN, Scalar.NaN, Scalar.NaN }, }; Check(AffineMatrix.IsNaN(new AffineMatrix(array))); } } public class Equality : TestFixture { AffineMatrix a, b; public override void TestSetup() { a = b = new AffineMatrix(0.1, new Vector(0.2, 0.3), 0.7); } public void DifferentTypes() { Scalar c = 0.0; Check(!a.Equals(c)); } public void Equal() { Check(a.Equals(b)); Check(a == b); CheckFalse(a != b); } public void NotEqual_M00() { a.M00 -= 0.001; Check(!a.Equals(b)); Check(a != b); CheckFalse(a == b); } public void NotEqual_M01() { a.M01 -= 0.001; Check(!a.Equals(b)); Check(a != b); CheckFalse(a == b); } public void NotEqual_M02() { a.M02 -= 0.001; Check(!a.Equals(b)); Check(a != b); CheckFalse(a == b); } public void NotEqual_M10() { a.M10 -= 0.001; Check(!a.Equals(b)); Check(a != b); CheckFalse(a == b); } public void NotEqual_M11() { a.M11 -= 0.001; Check(!a.Equals(b)); Check(a != b); CheckFalse(a == b); } public void NotEqual_M12() { a.M12 -= 0.001; Check(a != b); CheckFalse(a == b); Check(!a.Equals(b)); } } public class RotationMatrixTests : TestFixture { public void Basic() { var mat = new AffineMatrix(Math.PI / 8, new Vector(10, 20)); var expected = Matrix2x2.FromRotation(Math.PI / 8); CheckEqual(expected, mat.RotationMatrix); } } public class FullMatrixTests : TestFixture { public void Basic() { var mat = new AffineMatrix(Math.PI / 8, new Vector(10, 20)); var c = Math.Cos(Math.PI / 8); var s = Math.Sin(Math.PI / 8); var expected = new Matrix3x3(new Scalar[,] { { c, -s, 10, }, { s, c, 20, }, { 0, 0, 1} }); CheckEqual(expected, mat.FullMatrix); } } public class ToFromHexCodes : TestFixture { public void RoundTrips() { var matrix = new AffineMatrix(new Scalar[,] { { 1.0 / 3.0, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); var returnTrip = AffineMatrix.HexCodeToBits(bits); CheckEqual(matrix, returnTrip); CheckEqual(matrix.M00.Value, returnTrip.M00.Value); CheckEqual(matrix.M01.Value, returnTrip.M01.Value); CheckEqual(matrix.M02.Value, returnTrip.M02.Value); CheckEqual(matrix.M10.Value, returnTrip.M10.Value); CheckEqual(matrix.M11.Value, returnTrip.M11.Value); CheckEqual(matrix.M12.Value, returnTrip.M12.Value); } public void TryRoundTrips() { var matrix = new AffineMatrix(new Scalar[,] { { 1.0 / 3.0, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); AffineMatrix returnTrip; bool success = AffineMatrix.TryHexCodeToBits(bits, out returnTrip); Check(success); CheckEqual(matrix, returnTrip); CheckEqual(matrix.M00.Value, returnTrip.M00.Value); CheckEqual(matrix.M01.Value, returnTrip.M01.Value); CheckEqual(matrix.M02.Value, returnTrip.M02.Value); CheckEqual(matrix.M10.Value, returnTrip.M10.Value); CheckEqual(matrix.M11.Value, returnTrip.M11.Value); CheckEqual(matrix.M12.Value, returnTrip.M12.Value); } public void NaNs() { var matrix = new AffineMatrix(new Scalar[,] { { Scalar.NaN, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); var returnTrip = AffineMatrix.HexCodeToBits(bits); Check(Scalar.IsNaN(returnTrip.M00)); } public void TryNaNs() { var matrix = new AffineMatrix(new Scalar[,] { { Scalar.NaN, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); AffineMatrix returnTrip; bool success = AffineMatrix.TryHexCodeToBits(bits, out returnTrip); Check(success); Check(Scalar.IsNaN(returnTrip.M00)); } public void _0() { var matrix = new AffineMatrix(new Scalar[,] { { 0.0, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); var returnTrip = AffineMatrix.HexCodeToBits(bits); CheckEqual(matrix, returnTrip); CheckEqual(matrix.M00.Value, returnTrip.M00.Value); CheckEqual(matrix.M01.Value, returnTrip.M01.Value); CheckEqual(matrix.M02.Value, returnTrip.M02.Value); CheckEqual(matrix.M10.Value, returnTrip.M10.Value); CheckEqual(matrix.M11.Value, returnTrip.M11.Value); CheckEqual(matrix.M12.Value, returnTrip.M12.Value); } public void Try0() { var matrix = new AffineMatrix(new Scalar[,] { { 0.0, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); AffineMatrix returnTrip; bool success = AffineMatrix.TryHexCodeToBits(bits, out returnTrip); CheckEqual(matrix, returnTrip); CheckEqual(matrix.M00.Value, returnTrip.M00.Value); CheckEqual(matrix.M01.Value, returnTrip.M01.Value); CheckEqual(matrix.M02.Value, returnTrip.M02.Value); CheckEqual(matrix.M10.Value, returnTrip.M10.Value); CheckEqual(matrix.M11.Value, returnTrip.M11.Value); CheckEqual(matrix.M12.Value, returnTrip.M12.Value); } public void Inf() { var matrix = new AffineMatrix(new Scalar[,] { { Scalar.PositiveInfinity, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); var returnTrip = AffineMatrix.HexCodeToBits(bits); Check(Scalar.IsPositiveInfinity(returnTrip.M00)); } public void TryInf() { var matrix = new AffineMatrix(new Scalar[,] { { Scalar.PositiveInfinity, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); AffineMatrix returnTrip; bool success = AffineMatrix.TryHexCodeToBits(bits, out returnTrip); Check(success); Check(Scalar.IsPositiveInfinity(returnTrip.M00)); } public void StartsWith0x() { var matrix = new AffineMatrix(new Scalar[,] { { 1.0 / 3.0, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); Check(bits.StartsWith("[ [0x")); } public void FailsWhenNotStartingWith0x() { var text = "[ [4000000000000000 : 2 : 3] [4: 5: 6] ]"; CheckThrow(typeof(Exception)); Scalar.HexCodeToBits(text); } public void TryFailsWhenNotStartingWith0x() { var text = "[ [4000000000000000 : 0x4000000000000000 : 0x4008000000000000] " + "[0x4010000000000000: 0x4014000000000000: 0x4018000000000000] ]"; AffineMatrix value; bool success = AffineMatrix.TryHexCodeToBits(text, out value); Check(Scalar.IsNaN(value.M00)); CheckEqual(2, value.M01); CheckEqual(3, value.M02); CheckEqual(4, value.M10); CheckEqual(5, value.M11); CheckEqual(6, value.M12); CheckFalse(success); } } public class FromUnknownFormat : TestFixture { public void TryRoundtripHex() { var matrix = new AffineMatrix(new Scalar[,] { { 1.0 / 3.0, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); AffineMatrix valOut; bool success = AffineMatrix.TryParseFromUnknownFormat(bits, out valOut); Check(success); CheckEqual(matrix, valOut); CheckEqual(matrix.M00.Value, valOut.M00.Value); CheckEqual(matrix.M01.Value, valOut.M01.Value); CheckEqual(matrix.M02.Value, valOut.M02.Value); CheckEqual(matrix.M10.Value, valOut.M10.Value); CheckEqual(matrix.M11.Value, valOut.M11.Value); CheckEqual(matrix.M12.Value, valOut.M12.Value); } public void RoundtripHex() { var matrix = new AffineMatrix(new Scalar[,] { { 1.0 / 3.0, 2, 3 }, { 4, 5, 6 }, }); var bits = AffineMatrix.BitsToHexCode(matrix); AffineMatrix valOut = AffineMatrix.ParseFromUnknownFormat(bits); CheckEqual(matrix, valOut); CheckEqual(matrix.M00.Value, valOut.M00.Value); CheckEqual(matrix.M01.Value, valOut.M01.Value); CheckEqual(matrix.M02.Value, valOut.M02.Value); CheckEqual(matrix.M10.Value, valOut.M10.Value); CheckEqual(matrix.M11.Value, valOut.M11.Value); CheckEqual(matrix.M12.Value, valOut.M12.Value); } public void TryRoundtripNumbers() { var matrix = new AffineMatrix(new Scalar[,] { { 1.0 / 3.0, 2, 3 }, { 4, 5, 6 }, }); var str = matrix.ToString(); AffineMatrix valOut; bool success = AffineMatrix.TryParseFromUnknownFormat(str, out valOut); Check(success); CheckEqual(matrix, valOut); } public void RoundtripNumbers() { var matrix = new AffineMatrix(new Scalar[,] { { 1.0 / 3.0, 2, 3 }, { 4, 5, 6 }, }); string str = matrix.ToString(); AffineMatrix valOut = AffineMatrix.ParseFromUnknownFormat(str); CheckEqual(matrix, valOut); } public void TryRoundTripWord() { string str = "[ [poop: poop: 1] [poop: 0x4000000000000000: poop] ]"; AffineMatrix valOut; bool success = AffineMatrix.TryParseFromUnknownFormat(str, out valOut); CheckFalse(success); Check(Scalar.IsNaN(valOut.M00)); Check(Scalar.IsNaN(valOut.M01)); CheckEqual(1, valOut.M02); Check(Scalar.IsNaN(valOut.M10)); CheckEqual(2, valOut.M11); Check(Scalar.IsNaN(valOut.M12)); } public void RoundTripWord() { string str = "[ [poop: poop: poop] [poop: poop: poop] ]"; AffineMatrix valOut; CheckThrow(typeof(Exception)); valOut = AffineMatrix.ParseFromUnknownFormat(str); } // Partial success TryParseFromUnknownFormat } public class ToStringTests : TestFixture { // Note: we have to force the culture for these tests so that the unit tests run the same for // other developers. public class American : TestFixture { CultureInfo culture; public override void FixtureSetup() { culture = CultureInfo.CreateSpecificCulture("en-US"); } public void Basic() { var array = new Scalar[,] { { 1.25, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [1.25 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void Thousands() { var array = new Scalar[,] { { 1000.25, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [1000.25 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void TooManyDigits() { var array = new Scalar[,] { { 1.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [0.3333333333 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void GenericFormat() { var array = new Scalar[,] { { 1.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [0.3333333333 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString("G", culture)); } public void Rounding() { var array = new Scalar[,] { { 2.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [0.6666666667 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void HugeNumber() { Scalar value = 1.0 / Scalar.FuzzyEqualityEpsilon + 0.1; var array = new Scalar[,] { { value, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [10000000000 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void DropsTrailingZeros() { var array = new Scalar[,] { { 1.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [1 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void CustomFormater() { var array = new Scalar[,] { { 1.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [0.3 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString("0.#", culture)); } public void Infinity() { var array = new Scalar[,] { { Scalar.PositiveInfinity, 2, 3, }, { 4, 5, 6 } }; CheckEqual( $"[ [{culture.NumberFormat.PositiveInfinitySymbol} : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void NegativeInfinity() { var array = new Scalar[,] { { Scalar.NegativeInfinity, 2, 3, }, { 4, 5, 6 } }; CheckEqual( $"[ [{culture.NumberFormat.NegativeInfinitySymbol} : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void NaN() { var array = new Scalar[,] { { Scalar.NaN, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [NaN : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } } public class European : TestFixture { CultureInfo culture; public override void FixtureSetup() { culture = CultureInfo.CreateSpecificCulture("de-DE"); } public void Basic() { var array = new Scalar[,] { { 1.5, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [1,5 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void Thousands() { var array = new Scalar[,] { { 1001.5, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [1001,5 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void TooManyDigits() { var array = new Scalar[,] { { 1.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [0,3333333333 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void GenericFormat() { var array = new Scalar[,] { { 1.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [0,3333333333 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString("G", culture)); } public void Rounding() { var array = new Scalar[,] { { 2.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [0,6666666667 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void HugeNumber() { Scalar value = 1.0 / Scalar.FuzzyEqualityEpsilon + 0.1; var array = new Scalar[,] { { value, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [10000000000 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void DropsTrailingZeros() { Scalar value = 1.0 / Scalar.FuzzyEqualityEpsilon + 0.1; var array = new Scalar[,] { { 1.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual("[ [1 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void CustomFormater() { Scalar value = 1.0 / Scalar.FuzzyEqualityEpsilon + 0.1; var array = new Scalar[,] { { 1.0 / 3.0, 2, 3, }, { 4, 5, 6 } }; CheckEqual( "[ [0,3 : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString("0.#", culture)); } public void Infinity() { Scalar value = Scalar.PositiveInfinity; var array = new Scalar[,] { { value, 2, 3, }, { 4, 5, 6 } }; CheckEqual( $"[ [{culture.NumberFormat.PositiveInfinitySymbol} : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void NegativeInfinity() { Scalar value = Scalar.NegativeInfinity; var array = new Scalar[,] { { value, 2, 3, }, { 4, 5, 6 } }; CheckEqual( $"[ [{culture.NumberFormat.NegativeInfinitySymbol} : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } public void NaN() { Scalar value = Scalar.NaN; var array = new Scalar[,] { { value, 2, 3, }, { 4, 5, 6 } }; CheckEqual( $"[ [{culture.NumberFormat.NaNSymbol} : 2 : 3] : [4 : 5 : 6] ]", new AffineMatrix(array).ToString(culture)); } } } } }