Browse Source
Merge pull request #6747 from RomanSoloweow/master
LineNode hit test optimization
pull/6755/head
Dan Walmsley
5 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with
38 additions and
25 deletions
-
src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
-
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/LineNodeTests.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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -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)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|