浏览代码

Merge pull request #6747 from RomanSoloweow/master

LineNode hit test optimization
Dan Walmsley 4 年之前
父节点
当前提交
48e26a2883

+ 16 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs

@@ -83,6 +83,20 @@ namespace Avalonia.Rendering.SceneGraph
 
         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 @@ namespace Avalonia.Rendering.SceneGraph
             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 @@ namespace Avalonia.Rendering.SceneGraph
             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;
         }
     }
 }

+ 22 - 23
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/LineNodeTests.cs

@@ -11,50 +11,49 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
         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<Point>()
             {
-                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<Point>()
+            var pointsOutside = new List<Point>()
             {
-                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));
             }
         }
     }