Files
OpenNest/OpenNest.Desktop/Rendering/PathFigure.cs
T
ajandClaude Opus 5.5 049b45b394 feat(desktop): share plate-view geometry, view transform and overlays
Port the WinForms GraphicsHelper program walker to a toolkit-neutral
figure list (move/line/arc) with its layer routing: cuts without tabs,
leads, etches, and a material fill without break cuts whose tab-gapped
pieces are bridged. Suppressed moves are skipped and marks never bound
the fill. PartDisplayGeometry picks the fill as LayoutPart does
(common-line members, break cuts, open cuts) and keeps display-only
entities; PartLabels ports the label points.

ViewTransform carries DrawControl's world/screen mapping and zoom rules.
PlateOverlays computes what the view draws around parts (sheet, edge
spacing, irregular usable area, clamps, cut-off strokes, rapids, pierce
points, cut direction, offset outline, support) through the existing
Core code. PlateViewOptions reads and writes the View toggles under the
WinForms PlateViewDrawRapid/PlateViewDrawBounds names.

WinForms still draws with GraphicsHelper; nothing there changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 22:18:14 -05:00

47 lines
1.7 KiB
C#

using System.Collections.Generic;
using OpenNest.Geometry;
using OpenNest.Math;
namespace OpenNest.Desktop.Rendering;
/// <summary>One drawn piece of a figure, ending at <see cref="End"/>.</summary>
public abstract record PathSegment(Vector End);
/// <summary>A straight line from the previous point to <see cref="PathSegment.End"/>.</summary>
public sealed record LineTo(Vector End) : PathSegment(End);
/// <summary>
/// A circular arc about <paramref name="Center"/>, 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.
/// </summary>
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;
}
/// <summary>
/// One continuous run of drawing moves: a move to <see cref="Start"/> followed by
/// <see cref="Segments"/>. Toolkit-neutral; each desktop app converts figures to its own path type.
/// </summary>
public sealed class PathFigure
{
public PathFigure(Vector start, IReadOnlyList<PathSegment> segments)
{
Start = start;
Segments = segments;
}
public Vector Start { get; }
public IReadOnlyList<PathSegment> Segments { get; }
public Vector End => Segments.Count == 0 ? Start : Segments[Segments.Count - 1].End;
/// <summary>Whether the figure ends where it starts, so a toolkit may close it.</summary>
public bool IsClosed => Start.DistanceTo(End) <= Tolerance.Epsilon;
public override string ToString() => $"{Start} +{Segments.Count} {(IsClosed ? "closed" : "open")}";
}