diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml
index 9f369dae98..bf63b6d1c6 100644
--- a/samples/RenderDemo/Pages/Transform3DPage.axaml
+++ b/samples/RenderDemo/Pages/Transform3DPage.axaml
@@ -2,12 +2,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="400"
+ mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="700"
x:Class="RenderDemo.Pages.Transform3DPage">
-
+
I'm a text
@@ -21,11 +21,9 @@
@@ -41,23 +39,23 @@
-
+
-
+
-
+
-
+
-
+
@@ -69,23 +67,23 @@
-
+
-
+
-
+
-
+
-
+
@@ -97,23 +95,23 @@
-
+
-
+
-
+
-
+
-
+
@@ -125,67 +123,119 @@
-
+
-
+
-
+
-
+
-
+
+
+
+
-
-
+
-
-
-
- Depth:
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs
index 0c1caac8ea..2a6bdcb434 100644
--- a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs
+++ b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs
@@ -8,10 +8,54 @@ namespace RenderDemo.ViewModels
{
private double _depth = 200;
+ private double _depth2 = 200;
+ private double _centerX = 0;
+ private double _centerY = 0;
+ private double _centerZ = 0;
+ private double _angleX = 0;
+ private double _angleY = 0;
+ private double _angleZ = 0;
+
public double Depth
{
get => _depth;
set => RaiseAndSetIfChanged(ref _depth, value);
}
+
+ public double Depth2
+ {
+ get => _depth2;
+ set => RaiseAndSetIfChanged(ref _depth2, value);
+ }
+ public double CenterX
+ {
+ get => _centerX;
+ set => RaiseAndSetIfChanged(ref _centerX, value);
+ }
+ public double CenterY
+ {
+ get => _centerY;
+ set => RaiseAndSetIfChanged(ref _centerY, value);
+ }
+ public double CenterZ
+ {
+ get => _centerZ;
+ set => RaiseAndSetIfChanged(ref _centerZ, value);
+ }
+ public double AngleX
+ {
+ get => _angleX;
+ set => RaiseAndSetIfChanged(ref _angleX, value);
+ }
+ public double AngleY
+ {
+ get => _angleY;
+ set => RaiseAndSetIfChanged(ref _angleY, value);
+ }
+ public double AngleZ
+ {
+ get => _angleZ;
+ set => RaiseAndSetIfChanged(ref _angleZ, value);
+ }
}
}
diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs
index 38d0508ffb..5c7d42676a 100644
--- a/src/Avalonia.Visuals/Matrix.cs
+++ b/src/Avalonia.Visuals/Matrix.cs
@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Linq;
+using System.Numerics;
using Avalonia.Utilities;
namespace Avalonia
@@ -277,7 +278,7 @@ namespace Avalonia
{
return angle * 0.0174532925;
}
-
+
///
/// Appends another matrix as post-multiplication operation.
/// Equivalent to this * value;
@@ -310,14 +311,57 @@ namespace Avalonia
///
public double GetDeterminant()
{
- //return (_m11 * _m22) - (_m12 * _m21); //TODO: ensure new implementation yields the same result as before, when pers is 0,0,1
-
// implemented using "Laplace expansion":
return _m11 * (_m22 * _m33 - _m23 * _m32)
- _m12 * (_m21 * _m33 - _m23 * _m31)
+ _m13 * (_m21 * _m32 - _m22 * _m31);
}
+ ///
+ /// Transforms the point with the matrix
+ ///
+ /// The point to be transformed
+ /// The transformed point
+ public Point Transform(Point p)
+ {
+ Point transformedResult;
+
+ // If this matrix contains a non-affine transform with need to extend
+ // the point to a 3D vector and flatten it back for 2d display
+ // by multiplying X and Y with the inverse of the Z axis.
+ // The code below also works with affine transformations, but for performance (and compatibility)
+ // reasons we will use the more complex calculation only if necessary
+ if (ContainsPerspective())
+ {
+ var m44 = new Matrix4x4(
+ (float)M11, (float)M12, (float)M13, 0,
+ (float)M21, (float)M22, (float)M23, 0,
+ (float)M31, (float)M32, (float)M33, 0,
+ 0, 0, 0, 1
+ );
+
+ var vector = new Vector3((float)p.X, (float)p.Y, 1);
+ var transformedVector = Vector3.Transform(vector, m44);
+ var z = 1 / transformedVector.Z;
+
+ transformedResult = new Point(transformedVector.X * z, transformedVector.Y * z);
+ }
+ else
+ {
+ var x = p.X;
+ var y = p.Y;
+ var xAdd = y * M21 + M31;
+ var yAdd = x * M12 + M32;
+ x *= M11;
+ x += xAdd;
+ y *= M22;
+ y += yAdd;
+ transformedResult = new Point(x, y);
+ }
+
+ return transformedResult;
+ }
+
///
/// Returns a boolean indicating whether the matrix is equal to the other given matrix.
///
diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs
index a3af6b8c66..45cd9f803b 100644
--- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs
+++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs
@@ -1,5 +1,6 @@
using System;
using System.Numerics;
+using Avalonia.Animation.Animators;
namespace Avalonia.Media;
@@ -9,22 +10,22 @@ namespace Avalonia.Media;
public class Rotate3DTransform : Transform
{
///
- /// Defines the property.
+ /// Defines the property.
///
- public static readonly StyledProperty RotationXProperty =
- AvaloniaProperty.Register(nameof(RotationX));
+ public static readonly StyledProperty AngleXProperty =
+ AvaloniaProperty.Register(nameof(AngleX));
///
- /// Defines the property.
+ /// Defines the property.
///
- public static readonly StyledProperty RotationYProperty =
- AvaloniaProperty.Register(nameof(RotationY));
+ public static readonly StyledProperty AngleYProperty =
+ AvaloniaProperty.Register(nameof(AngleY));
///
- /// Defines the property.
+ /// Defines the property.
///
- public static readonly StyledProperty RotationZProperty =
- AvaloniaProperty.Register(nameof(RotationZ));
+ public static readonly StyledProperty AngleZProperty =
+ AvaloniaProperty.Register(nameof(AngleZ));
///
@@ -58,9 +59,9 @@ public class Rotate3DTransform : Transform
///
public Rotate3DTransform()
{
- this.GetObservable(RotationXProperty).Subscribe(_ => RaiseChanged());
- this.GetObservable(RotationYProperty).Subscribe(_ => RaiseChanged());
- this.GetObservable(RotationZProperty).Subscribe(_ => RaiseChanged());
+ this.GetObservable(AngleXProperty).Subscribe(_ => RaiseChanged());
+ this.GetObservable(AngleYProperty).Subscribe(_ => RaiseChanged());
+ this.GetObservable(AngleZProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(CenterZProperty).Subscribe(_ => RaiseChanged());
@@ -70,23 +71,23 @@ public class Rotate3DTransform : Transform
///
/// Initializes a new instance of the class.
///
- /// The rotation around the X-Axis
- /// The rotation around the Y-Axis
- /// The rotation around the Z-Axis
+ /// The rotation around the X-Axis
+ /// The rotation around the Y-Axis
+ /// The rotation around the Z-Axis
/// The origin of the X-Axis
/// The origin of the Y-Axis
/// The origin of the Z-Axis
public Rotate3DTransform(
- double rotationX,
- double rotationY,
- double rotationZ,
+ double angleX,
+ double angleY,
+ double angleZ,
double centerX,
double centerY,
double centerZ) : this()
{
- RotationX = rotationX;
- RotationY = rotationY;
- RotationZ = rotationZ;
+ AngleX = angleX;
+ AngleY = angleY;
+ AngleZ = angleZ;
CenterX = centerX;
CenterY = centerY;
CenterZ = centerZ;
@@ -95,32 +96,32 @@ public class Rotate3DTransform : Transform
///
/// Sets the rotation around the X-Axis
///
- public double RotationX
+ public double AngleX
{
- get => GetValue(RotationXProperty);
- set => SetValue(RotationXProperty, value);
+ get => GetValue(AngleXProperty);
+ set => SetValue(AngleXProperty, value);
}
///
/// Sets the rotation around the Y-Axis
///
- public double RotationY
+ public double AngleY
{
- get => GetValue(RotationYProperty);
- set => SetValue(RotationYProperty, value);
+ get => GetValue(AngleYProperty);
+ set => SetValue(AngleYProperty, value);
}
///
/// Sets the rotation around the Z-Axis
///
- public double RotationZ
+ public double AngleZ
{
- get => GetValue(RotationZProperty);
- set => SetValue(RotationZProperty, value);
+ get => GetValue(AngleZProperty);
+ set => SetValue(AngleZProperty, value);
}
///
- /// Moves the origin of the X-Axis
+ /// Moves the origin the X-Axis rotates around
///
public double CenterX
{
@@ -129,7 +130,7 @@ public class Rotate3DTransform : Transform
}
///
- /// Moves the origin of the Y-Axis
+ /// Moves the origin the Y-Axis rotates around
///
public double CenterY
{
@@ -138,7 +139,7 @@ public class Rotate3DTransform : Transform
}
///
- /// Moves the origin of the Z-Axis
+ /// Moves the origin the Z-Axis rotates around
///
public double CenterZ
{
@@ -166,9 +167,9 @@ public class Rotate3DTransform : Transform
matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ);
- matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(RotationX));
- matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(RotationY));
- matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(RotationZ));
+ matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(AngleX));
+ matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(AngleY));
+ matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(AngleZ));
matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ);
diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs
index 473de8e501..8e01ea47c5 100644
--- a/src/Avalonia.Visuals/Point.cs
+++ b/src/Avalonia.Visuals/Point.cs
@@ -243,34 +243,7 @@ namespace Avalonia
///
/// The transform.
/// The transformed point.
- public Point Transform(Matrix transform)
- {
- if (transform.ContainsPerspective())
- {
- var m44 = new Matrix4x4(
- (float)transform.M11, (float)transform.M12, (float)transform.M13, 0,
- (float)transform.M21, (float)transform.M22, (float)transform.M23, 0,
- (float)transform.M31, (float)transform.M32, (float)transform.M33, 0,
- 0, 0, 0, 1
- );
-
- var vector = new Vector3((float)X, (float)Y, 1);
- var transformedVector = Vector3.Transform(vector, m44);
- var z = 1 / transformedVector.Z;
-
- return new Point(transformedVector.X * z, transformedVector.Y * z);
- }
-
- var x = X;
- var y = Y;
- var xadd = y * transform.M21 + transform.M31;
- var yadd = x * transform.M12 + transform.M32;
- x *= transform.M11;
- x += xadd;
- y *= transform.M22;
- y += yadd;
- return new Point(x, y);
- }
+ public Point Transform(Matrix transform) => transform.Transform(this);
///
/// Returns a new point with the specified X coordinate.