using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Media; namespace Kniip.Editor.Annotations; /// Markeerstift: half-transparant, als rechte horizontale streep of uit de vrije hand. public sealed class HighlightAnnotation : Annotation { private const byte HighlightAlpha = 110; public List Points { get; set; } = new(); public bool Straight { get; set; } public override ToolKind Kind => ToolKind.Highlight; public override Rect Bounds { get { if (Points.Count == 0) { return Rect.Empty; } double minX = Points.Min(p => p.X), maxX = Points.Max(p => p.X); double minY = Points.Min(p => p.Y), maxY = Points.Max(p => p.Y); var r = new Rect(new Point(minX, minY), new Point(maxX, maxY)); r.Inflate(Style.Thickness / 2, Style.Thickness / 2); return r; } } public override bool IsDegenerate { get { if (Points.Count < 2) { return true; } Rect r = Bounds; return r.Width - Style.Thickness < 3 && r.Height - Style.Thickness < 3; } } public override void Render(DrawingContext dc, EditorDocument document) { if (Points.Count < 2) { return; } Color c = Style.Stroke; var color = Color.FromArgb(HighlightAlpha, c.R, c.G, c.B); Pen? pen = RenderHelpers.CreatePen(color, Style.Thickness, LineDash.Solid, Straight ? PenLineCap.Square : PenLineCap.Round); if (pen == null) { return; } // Eén geometrie, zodat overlappende delen niet dubbel zo donker worden. var geometry = new StreamGeometry(); using (StreamGeometryContext ctx = geometry.Open()) { ctx.BeginFigure(Points[0], false, false); ctx.PolyLineTo(Points.Skip(1).ToList(), true, true); } geometry.Freeze(); dc.DrawGeometry(null, pen, geometry); } public override bool HitTest(Point point, double tolerance) { double limit = tolerance + Style.Thickness / 2; for (int i = 1; i < Points.Count; i++) { if (RenderHelpers.DistanceToSegment(point, Points[i - 1], Points[i]) <= limit) { return true; } } return false; } public override void Move(Vector delta) { for (int i = 0; i < Points.Count; i++) { Points[i] += delta; } } public override IReadOnlyList GetHandles() => Straight && Points.Count == 2 ? new[] { Points[0], Points[1] } : Array.Empty(); public override void MoveHandle(int index, Point point, bool constrain) { if (!Straight || Points.Count != 2) { return; } Points[index] = new Point(point.X, Points[1 - index].Y); } public override bool CanFlip => !Straight; public override void Flip(bool horizontal) { for (int i = 0; i < Points.Count; i++) { Points[i] = Mirror(Points[i], horizontal); } } public override Annotation Clone() { var clone = (HighlightAnnotation)base.Clone(); clone.Points = new List(Points); return clone; } }