diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs
index 4feca7acd8..dbcf749789 100644
--- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs
+++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs
@@ -70,13 +70,15 @@ public class Rotate3DTransform : Transform
/// The origin of the X-Axis
/// The origin of the Y-Axis
/// The origin of the Z-Axis
+ /// The depth of the 3D effect
public Rotate3DTransform(
double angleX,
double angleY,
double angleZ,
double centerX,
double centerY,
- double centerZ) : this()
+ double centerZ,
+ double depth) : this()
{
_isInitializing = true;
AngleX = angleX;
@@ -85,6 +87,7 @@ public class Rotate3DTransform : Transform
CenterX = centerX;
CenterY = centerY;
CenterZ = centerZ;
+ Depth = depth;
_isInitializing = false;
}
diff --git a/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs b/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs
new file mode 100644
index 0000000000..cb5e2390c7
--- /dev/null
+++ b/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Numerics;
+using System.Runtime.InteropServices;
+using Avalonia.Media;
+using Xunit;
+
+namespace Avalonia.Visuals.UnitTests;
+
+///
+/// These tests use the "official" Matrix4x4 and Matrix3x2 from the System.Numerics namespace, to validate
+/// that Avalonias own implementation of a 3x3 Matrix works correctly.
+///
+public class MatrixTests
+{
+ private double ReducePrecision(double input)
+ {
+ return Math.Truncate(input * 10000);
+ }
+
+ ///
+ /// Because Avalonia is working internally with doubles, but System.Numerics Vector and Matrix implementations
+ /// only make use of floats, we need to reduce precision, comparing them. It should be sufficient to compare
+ /// 5 fractional digits to ensure, that the result is correct.
+ ///
+ /// The expected vector
+ /// The actual transformed point
+ private void AssertCoordinatesEqualWithReducedPrecision(Vector2 expected, Point actual)
+ {
+ var expectedX = ReducePrecision(expected.X);
+ var expectedY = ReducePrecision(expected.Y);
+
+ var actualX = ReducePrecision(actual.X);
+ var actualY = ReducePrecision(actual.Y);
+
+ Assert.Equal(expectedX, actualX);
+ Assert.Equal(expectedY, actualY);
+ }
+
+ [Fact]
+ public void Transform_Point_Should_Return_Correct_Value_For_Translated_Matrix()
+ {
+ var vector2 = Vector2.Transform(
+ new Vector2(1, 1),
+ Matrix3x2.CreateTranslation(2, 2));
+ var expected = new Point(vector2.X, vector2.Y);
+
+ var matrix = Matrix.CreateTranslation(2, 2);
+ var point = new Point(1, 1);
+ var transformedPoint = matrix.Transform(point);
+
+ Assert.Equal(expected, transformedPoint);
+ }
+
+ [Fact]
+ public void Transform_Point_Should_Return_Correct_Value_For_Rotated_Matrix()
+ {
+ var expected = Vector2.Transform(
+ new Vector2(0, 10),
+ Matrix3x2.CreateRotation((float)Matrix.ToRadians(45)));
+
+ var matrix = Matrix.CreateRotation(Matrix.ToRadians(45));
+ var point = new Point(0, 10);
+ var actual = matrix.Transform(point);
+
+ AssertCoordinatesEqualWithReducedPrecision(expected, actual);
+ }
+
+ [Fact]
+ public void Transform_Point_Should_Return_Correct_Value_For_Scaled_Matrix()
+ {
+ var vector2 = Vector2.Transform(
+ new Vector2(1, 1),
+ Matrix3x2.CreateScale(2, 2));
+ var expected = new Point(vector2.X, vector2.Y);
+ var matrix = Matrix.CreateScale(2, 2);
+ var point = new Point(1, 1);
+ var actual = matrix.Transform(point);
+
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void Transform_Point_Should_Return_Correct_Value_For_Skewed_Matrix()
+ {
+ var expected = Vector2.Transform(
+ new Vector2(1, 1),
+ Matrix3x2.CreateSkew(30, 20));
+
+ var matrix = Matrix.CreateSkew(30, 20);
+ var point = new Point(1, 1);
+ var actual = matrix.Transform(point);
+
+ AssertCoordinatesEqualWithReducedPrecision(expected, actual);
+ }
+}