From f1b0d18674808b53e545c2d8a538ce149d1cc998 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 16 Oct 2021 11:50:24 +0100 Subject: [PATCH] Merge pull request #6747 from RomanSoloweow/master LineNode hit test optimization --- .../Rendering/SceneGraph/LineNode.cs | 18 +++++++- .../Rendering/SceneGraph/LineNodeTests.cs | 45 +++++++++---------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs index 19b751f66c6..3dc6d5f50e2 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs @@ -83,6 +83,20 @@ public override void Render(IDrawingContextImpl context) public override bool HitTest(Point p) { + if (!Transform.HasInverse) + return false; + + p *= Transform.Invert(); + + var halfThickness = Pen.Thickness / 2; + var minX = Math.Min(P1.X, P2.X) - halfThickness; + var maxX = Math.Max(P1.X, P2.X) + halfThickness; + var minY = Math.Min(P1.Y, P2.Y) - halfThickness; + var maxY = Math.Max(P1.Y, P2.Y) + halfThickness; + + if (p.X < minX || p.X > maxX || p.Y < minY || p.Y > maxY) + return false; + var a = P1; var b = P2; @@ -100,7 +114,7 @@ public override bool HitTest(Point p) var dot2 = Vector.Dot(a - b, bp); if (dot2 < 0) - return bp.Length <= Pen.Thickness / 2; + return bp.Length <= halfThickness; var bXaX = b.X - a.X; var bYaY = b.Y - a.Y; @@ -108,7 +122,7 @@ public override bool HitTest(Point p) var distance = (bXaX * (p.Y - a.Y) - bYaY * (p.X - a.X)) / (Math.Sqrt(bXaX * bXaX + bYaY * bYaY)); - return Math.Abs(distance) <= Pen.Thickness / 2; + return Math.Abs(distance) <= halfThickness; } } } diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/LineNodeTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/LineNodeTests.cs index d4d4a29dfd3..56f2b039320 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/LineNodeTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/LineNodeTests.cs @@ -11,50 +11,49 @@ public class LineNodeTests public void HitTest_Should_Be_True() { var lineNode = new LineNode( - Matrix.Identity, + Matrix.Identity, new Pen(Brushes.Black, 3), - new Point(15, 15), - new Point(150, 150)); - + new Point(15, 10), + new Point(150, 73)); var pointsInside = new List() { - new Point(14, 14), - new Point(15, 15), - new Point(32.1, 30), - new Point(30, 32.1), - new Point(150, 150), - new Point(151, 151), + new Point(14, 8.9), + new Point(15, 10), + new Point(30, 15.5), + new Point(30, 18.5), + new Point(150, 73), + new Point(151, 71.9), }; foreach (var point in pointsInside) { - Assert.True(lineNode.HitTest(point)); + Assert.True(lineNode.HitTest(point)); } } - + [Fact] public void HitTest_Should_Be_False() { var lineNode = new LineNode( - Matrix.Identity, + Matrix.Identity, new Pen(Brushes.Black, 3), - new Point(15, 15), - new Point(150, 150)); - + new Point(15, 10), + new Point(150, 73)); - var pointsOutside= new List() + var pointsOutside = new List() { - new Point(13.9, 13.9), - new Point(30, 32.2), - new Point(32.2, 30), - new Point(151.1, 151.1), - new Point(200, 200), + new Point(14, 8), + new Point(14, 8.8), + new Point(30, 15.3), + new Point(30, 18.7), + new Point(151, 71.8), + new Point(155, 75), }; foreach (var point in pointsOutside) { - Assert.False(lineNode.HitTest(point)); + Assert.False(lineNode.HitTest(point)); } } }