using System.Collections.Generic; using OpenNest.Geometry; using OpenNest.Math; namespace OpenNest.Desktop.Rendering; /// One drawn piece of a figure, ending at . public abstract record PathSegment(Vector End); /// A straight line from the previous point to . public sealed record LineTo(Vector End) : PathSegment(End); /// /// A circular arc about , in degrees measured from +X toward +Y (the /// y-up drawing frame); a positive sweep turns counterclockwise. A sweep of 360 degrees is a full /// circle. Toolkits join the previous point to the arc's start with a line, as GDI+ and Skia do. /// public sealed record ArcTo(Vector End, Vector Center, double Radius, double StartAngle, double SweepAngle) : PathSegment(End) { public bool IsFullCircle => System.Math.Abs(SweepAngle) >= 360.0; } /// /// One continuous run of drawing moves: a move to followed by /// . Toolkit-neutral; each desktop app converts figures to its own path type. /// public sealed class PathFigure { public PathFigure(Vector start, IReadOnlyList segments) { Start = start; Segments = segments; } public Vector Start { get; } public IReadOnlyList Segments { get; } public Vector End => Segments.Count == 0 ? Start : Segments[Segments.Count - 1].End; /// Whether the figure ends where it starts, so a toolkit may close it. public bool IsClosed => Start.DistanceTo(End) <= Tolerance.Epsilon; public override string ToString() => $"{Start} +{Segments.Count} {(IsClosed ? "closed" : "open")}"; }