using System; using System.Collections.Generic; using Avalonia.Media; using Avalonia.Media.Immutable; using Avalonia.Platform; using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { /// /// A node in the scene graph which represents a line draw. /// internal class LineNode : BrushDrawOperation { /// /// Initializes a new instance of the class. /// /// The transform. /// The stroke pen. /// The start point of the line. /// The end point of the line. /// Child scenes for drawing visual brushes. public LineNode( Matrix transform, IPen pen, Point p1, Point p2, IDictionary childScenes = null) : base(LineBoundsHelper.CalculateBounds(p1, p2, pen), transform) { Transform = transform; Pen = pen?.ToImmutable(); P1 = p1; P2 = p2; ChildScenes = childScenes; } /// /// Gets the transform with which the node will be drawn. /// public Matrix Transform { get; } /// /// Gets the stroke pen. /// public ImmutablePen Pen { get; } /// /// Gets the start point of the line. /// public Point P1 { get; } /// /// Gets the end point of the line. /// public Point P2 { get; } /// public override IDictionary ChildScenes { get; } /// /// Determines if this draw operation equals another. /// /// The transform of the other draw operation. /// The stroke of the other draw operation. /// The start point of the other draw operation. /// The end point of the other draw operation. /// True if the draw operations are the same, otherwise false. /// /// The properties of the other draw operation are passed in as arguments to prevent /// allocation of a not-yet-constructed draw operation object. /// public bool Equals(Matrix transform, IPen pen, Point p1, Point p2) { return transform == Transform && Equals(Pen, pen) && p1 == P1 && p2 == P2; } public override void Render(IDrawingContextImpl context) { context.Transform = Transform; context.DrawLine(Pen, P1, P2); } public override bool HitTest(Point p) { var a = P1; var b = P2; //If dot1 or dot2 is negative, then the angle between the perpendicular and the segment is obtuse. //The distance from a point to a straight line is defined as the //length of the vector formed by the point and the closest point of the segment Vector ap = p - a; var dot1 = Vector.Dot(b - a, ap); if (dot1 < 0) return ap.Length <= Pen.Thickness / 2; Vector bp = p - b; var dot2 = Vector.Dot(a - b, bp); if (dot2 < 0) return bp.Length <= Pen.Thickness / 2; var bXaX = b.X - a.X; var bYaY = b.Y - a.Y; 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; } } }