From fe01544a4c53d8b1dd91a0d11fb91b00f155d73c Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 15 May 2020 12:07:16 -0300 Subject: [PATCH 1/3] Add a Rect.Normalize method with tests. --- src/Avalonia.Visuals/Rect.cs | 47 +++++++++++++++++-- tests/Avalonia.Visuals.UnitTests/RectTests.cs | 16 +++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index b0c4cb62eb..8dadaa3b0f 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -421,11 +421,48 @@ namespace Avalonia } /// - /// Gets the union of two rectangles. - /// - /// The other rectangle. - /// The union. - public Rect Union(Rect rect) + /// Normalizes the rectangle so both the and are positive, without changing the location of the rectangle + /// + /// Normalized Rect + /// + /// Empty rect will be return when Rect contains invalid values. Like NaN. + /// + public Rect Normalize() + { + Rect rect = this; + + if(double.IsNaN(rect.Right) || double.IsNaN(rect.Bottom) || double.IsNaN(rect.X) || double.IsNaN(rect.Y) || double.IsNaN(Height) || double.IsNaN(Width)) + { + return Rect.Empty; + } + + if (rect.Width < 0) + { + var old = X; + var x = X + Width; + var width = old - x; + + rect = rect.WithX(x).WithWidth(width); + } + if (rect.Height < 0) + { + var old = Y; + var y = Y + Height; + var height = old - y; + + rect = rect.WithY(y).WithHeight(height); + } + + return rect; + } + + + /// + /// Gets the union of two rectangles. + /// + /// The other rectangle. + /// The union. + public Rect Union(Rect rect) { if (IsEmpty) { diff --git a/tests/Avalonia.Visuals.UnitTests/RectTests.cs b/tests/Avalonia.Visuals.UnitTests/RectTests.cs index 34953e5fd7..89800e41bf 100644 --- a/tests/Avalonia.Visuals.UnitTests/RectTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/RectTests.cs @@ -35,5 +35,21 @@ namespace Avalonia.Visuals.UnitTests Assert.Equal(new Rect(0, 0, 100, 100), result); } + + [Fact] + public void Normalize_Should_Reverse_Negative_Size() + { + var result = new Rect(new Point(100, 100), new Point(0, 0)).Normalize(); + + Assert.Equal(new Rect(0, 0, 100, 100), result); + } + + [Fact] + public void Normalize_Should_Make_Invalid_Rects_Empty() + { + var result = new Rect(double.NegativeInfinity,double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity).Normalize(); + + Assert.Equal(Rect.Empty, result); + } } } From 29004117b6dae7b9cdee878a02b8c0e10a033184 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 15 May 2020 12:07:48 -0300 Subject: [PATCH 2/3] Draw operation bounds are Normalized. --- src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs index 0b04b97ff2..38df0cb289 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs @@ -11,7 +11,10 @@ namespace Avalonia.Rendering.SceneGraph { public DrawOperation(Rect bounds, Matrix transform) { + bounds = bounds.Normalize(); + bounds = bounds.TransformToAABB(transform); + Bounds = new Rect( new Point(Math.Floor(bounds.X), Math.Floor(bounds.Y)), new Point(Math.Ceiling(bounds.Right), Math.Ceiling(bounds.Bottom))); From cbda0e9d95e0c6434e8fc80fe5fdcf409f6744df Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 18 May 2020 12:46:25 -0300 Subject: [PATCH 3/3] fix nits. --- src/Avalonia.Visuals/Rect.cs | 14 ++++++++------ .../Rendering/SceneGraph/DrawOperation.cs | 4 +--- tests/Avalonia.Visuals.UnitTests/RectTests.cs | 5 ++++- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.Visuals/Rect.cs b/src/Avalonia.Visuals/Rect.cs index 8dadaa3b0f..d1110e0613 100644 --- a/src/Avalonia.Visuals/Rect.cs +++ b/src/Avalonia.Visuals/Rect.cs @@ -421,7 +421,8 @@ namespace Avalonia } /// - /// Normalizes the rectangle so both the and are positive, without changing the location of the rectangle + /// Normalizes the rectangle so both the and are positive, without changing the location of the rectangle /// /// Normalized Rect /// @@ -431,24 +432,25 @@ namespace Avalonia { Rect rect = this; - if(double.IsNaN(rect.Right) || double.IsNaN(rect.Bottom) || double.IsNaN(rect.X) || double.IsNaN(rect.Y) || double.IsNaN(Height) || double.IsNaN(Width)) + if(double.IsNaN(rect.Right) || double.IsNaN(rect.Bottom) || + double.IsNaN(rect.X) || double.IsNaN(rect.Y) || + double.IsNaN(Height) || double.IsNaN(Width)) { return Rect.Empty; } if (rect.Width < 0) { - var old = X; var x = X + Width; - var width = old - x; + var width = X - x; rect = rect.WithX(x).WithWidth(width); } + if (rect.Height < 0) { - var old = Y; var y = Y + Height; - var height = old - y; + var height = Y - y; rect = rect.WithY(y).WithHeight(height); } diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs index 38df0cb289..c49e7705e0 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DrawOperation.cs @@ -11,9 +11,7 @@ namespace Avalonia.Rendering.SceneGraph { public DrawOperation(Rect bounds, Matrix transform) { - bounds = bounds.Normalize(); - - bounds = bounds.TransformToAABB(transform); + bounds = bounds.Normalize().TransformToAABB(transform); Bounds = new Rect( new Point(Math.Floor(bounds.X), Math.Floor(bounds.Y)), diff --git a/tests/Avalonia.Visuals.UnitTests/RectTests.cs b/tests/Avalonia.Visuals.UnitTests/RectTests.cs index 89800e41bf..a2b0569949 100644 --- a/tests/Avalonia.Visuals.UnitTests/RectTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/RectTests.cs @@ -47,7 +47,10 @@ namespace Avalonia.Visuals.UnitTests [Fact] public void Normalize_Should_Make_Invalid_Rects_Empty() { - var result = new Rect(double.NegativeInfinity,double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity).Normalize(); + var result = new Rect( + double.NegativeInfinity, double.PositiveInfinity, + double.PositiveInfinity, double.PositiveInfinity) + .Normalize(); Assert.Equal(Rect.Empty, result); }