From e9c4c238f1cbb01217340a738a18584c7a2fa824 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Fri, 16 Mar 2018 23:53:32 +0800 Subject: [PATCH 1/3] Added SkewTransform and the corresponding skew function in Matrix class. --- src/Avalonia.Visuals/Matrix.cs | 14 ++++- src/Avalonia.Visuals/Media/SkewTransform.cs | 69 +++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/Avalonia.Visuals/Media/SkewTransform.cs diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 10549b967d..89eb7b4928 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -150,6 +150,19 @@ namespace Avalonia return new Matrix(cos, sin, -sin, cos, 0, 0); } + /// + /// Creates a skew matrix from the given axis skew angles in radians. + /// + /// The amount of skew along the X-axis, in radians. + /// The amount of skew along the Y-axis, in radians. + /// A rotation matrix. + public static Matrix CreateSkew(double xAngle, double yAngle) + { + double tanX = Math.Tan(xAngle); + double tanY = Math.Tan(yAngle); + return new Matrix(1.0, tanX, tanY, 1.0, 0.0, 0.0); + } + /// /// Creates a scale matrix from the given X and Y components. /// @@ -215,7 +228,6 @@ namespace Avalonia return (_m11 * _m22) - (_m12 * _m21); } - /// /// Returns a boolean indicating whether the matrix is equal to the other given matrix. /// diff --git a/src/Avalonia.Visuals/Media/SkewTransform.cs b/src/Avalonia.Visuals/Media/SkewTransform.cs new file mode 100644 index 0000000000..880b73750b --- /dev/null +++ b/src/Avalonia.Visuals/Media/SkewTransform.cs @@ -0,0 +1,69 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.VisualTree; + +namespace Avalonia.Media +{ + /// + /// Skews an . + /// + public class SkewTransform : Transform + { + /// + /// Defines the property. + /// + public static readonly StyledProperty AngleXProperty = + AvaloniaProperty.Register(nameof(AngleX)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty AngleYProperty = + AvaloniaProperty.Register(nameof(AngleY)); + + /// + /// Initializes a new instance of the class. + /// + public SkewTransform() + { + this.GetObservable(AngleXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(AngleYProperty).Subscribe(_ => RaiseChanged()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The skew angle of X-axis, in degrees. + /// The skew angle of Y-axis, in degrees. + public SkewTransform(double angleX, double angleY) : this() + { + AngleX = angleX; + AngleY = angleY; + } + + /// + /// Gets or sets the AngleX property. + /// + public double AngleX + { + get { return GetValue(AngleXProperty); } + set { SetValue(AngleXProperty, value); } + } + + /// + /// Gets or sets the AngleY property. + /// + public double AngleY + { + get { return GetValue(AngleYProperty); } + set { SetValue(AngleYProperty, value); } + } + + /// + /// Gets the tranform's . + /// + public override Matrix Value => Matrix.CreateSkew(Matrix.ToRadians(AngleX), Matrix.ToRadians(AngleY)); + } +} \ No newline at end of file From 0306d9475d9e55f264d5e192966f02333d116cd2 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sat, 17 Mar 2018 01:05:52 +0800 Subject: [PATCH 2/3] Added LayoutTransformControl skew tests --- .../LayoutTransformControlTests.cs | 97 ++++++++++++++++++- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs index b6ef550da6..45154b9dad 100644 --- a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs @@ -30,6 +30,51 @@ namespace Avalonia.Controls.UnitTests new Size(50, 25)); } + [Fact] + public void Measure_On_Skew_X_axis_45_degrees_Is_Correct() + { + TransformMeasureSizeTest( + new Size(100, 100), + new SkewTransform() { AngleX = 45 }, + new Size(100, 200)); + } + + [Fact] + public void Measure_On_Skew_Y_axis_45_degrees_Is_Correct() + { + TransformMeasureSizeTest( + new Size(100, 100), + new SkewTransform() { AngleY = 45 }, + new Size(200, 100)); + } + + [Fact] + public void Measure_On_Skew_X_axis_minus_45_degrees_Is_Correct() + { + TransformMeasureSizeTest( + new Size(100, 100), + new SkewTransform() { AngleX = -45 }, + new Size(100, 200)); + } + + [Fact] + public void Measure_On_Skew_Y_axis_minus_45_degrees_Is_Correct() + { + TransformMeasureSizeTest( + new Size(100, 100), + new SkewTransform() { AngleY = -45 }, + new Size(200, 100)); + } + + [Fact] + public void Measure_On_Skew_0_degrees_Is_Correct() + { + TransformMeasureSizeTest( + new Size(100, 100), + new SkewTransform() { AngleX = 0, AngleY = 0 }, + new Size(100, 100)); + } + [Fact] public void Measure_On_Rotate_90_degrees_Is_Correct() { @@ -123,9 +168,9 @@ namespace Avalonia.Controls.UnitTests new RotateTransform() { Angle = -90 }, new Rect(0, 100, 100, 25)); } - + [Fact] - public void Should_Generate_RenderTransform_90_degrees() + public void Should_Generate_RotateTransform_90_degrees() { LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( 100, @@ -147,7 +192,7 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Should_Generate_RenderTransform_minus_90_degrees() + public void Should_Generate_RotateTransform_minus_90_degrees() { LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( 100, @@ -189,6 +234,52 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(m.M32, res.M32, 3); } + [Fact] + public void Should_Generate_SkewTransform_45_degrees() + { + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( + 100, + 100, + new SkewTransform() { AngleX = 45, AngleY = 45 }); + + Assert.NotNull(lt.TransformRoot.RenderTransform); + + Matrix m = lt.TransformRoot.RenderTransform.Value; + + Matrix res = Matrix.CreateSkew(Matrix.ToRadians(45), Matrix.ToRadians(45)); + + Assert.Equal(m.M11, res.M11, 3); + Assert.Equal(m.M12, res.M12, 3); + Assert.Equal(m.M21, res.M21, 3); + Assert.Equal(m.M22, res.M22, 3); + Assert.Equal(m.M31, res.M31, 3); + Assert.Equal(m.M32, res.M32, 3); + } + + [Fact] + public void Should_Generate_SkewTransform_minus_45_degrees() + { + LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( + 100, + 100, + new SkewTransform() { AngleX = -45, AngleY = -45 }); + + Assert.NotNull(lt.TransformRoot.RenderTransform); + + Matrix m = lt.TransformRoot.RenderTransform.Value; + + Matrix res = Matrix.CreateSkew(Matrix.ToRadians(-45), Matrix.ToRadians(-45)); + + Assert.Equal(m.M11, res.M11, 3); + Assert.Equal(m.M12, res.M12, 3); + Assert.Equal(m.M21, res.M21, 3); + Assert.Equal(m.M22, res.M22, 3); + Assert.Equal(m.M31, res.M31, 3); + Assert.Equal(m.M32, res.M32, 3); + } + + + private static void TransformMeasureSizeTest(Size size, Transform transform, Size expectedSize) { LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform( From fc06fa1e35ed7ed1dea968692568e8bc203a4376 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Sun, 18 Mar 2018 00:27:03 +0800 Subject: [PATCH 3/3] Fix skew matrix function's flipped axes + update tests. --- src/Avalonia.Visuals/Matrix.cs | 2 +- .../LayoutTransformControlTests.cs | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 89eb7b4928..4e5cd61994 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -160,7 +160,7 @@ namespace Avalonia { double tanX = Math.Tan(xAngle); double tanY = Math.Tan(yAngle); - return new Matrix(1.0, tanX, tanY, 1.0, 0.0, 0.0); + return new Matrix(1.0, tanY, tanX, 1.0, 0.0, 0.0); } /// diff --git a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs index 45154b9dad..d5f9818f89 100644 --- a/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs @@ -36,7 +36,8 @@ namespace Avalonia.Controls.UnitTests TransformMeasureSizeTest( new Size(100, 100), new SkewTransform() { AngleX = 45 }, - new Size(100, 200)); + new Size(200, 100)); + } [Fact] @@ -45,7 +46,7 @@ namespace Avalonia.Controls.UnitTests TransformMeasureSizeTest( new Size(100, 100), new SkewTransform() { AngleY = 45 }, - new Size(200, 100)); + new Size(100, 200)); } [Fact] @@ -54,7 +55,7 @@ namespace Avalonia.Controls.UnitTests TransformMeasureSizeTest( new Size(100, 100), new SkewTransform() { AngleX = -45 }, - new Size(100, 200)); + new Size(200, 100)); } [Fact] @@ -63,7 +64,7 @@ namespace Avalonia.Controls.UnitTests TransformMeasureSizeTest( new Size(100, 100), new SkewTransform() { AngleY = -45 }, - new Size(200, 100)); + new Size(100, 200)); } [Fact] @@ -168,7 +169,7 @@ namespace Avalonia.Controls.UnitTests new RotateTransform() { Angle = -90 }, new Rect(0, 100, 100, 25)); } - + [Fact] public void Should_Generate_RotateTransform_90_degrees() { @@ -278,8 +279,6 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(m.M32, res.M32, 3); } - - private static void TransformMeasureSizeTest(Size size, Transform transform, Size expectedSize) { LayoutTransformControl lt = CreateWithChildAndMeasureAndTransform(