From 267254dcaed3f3a525c27fe9d3ef23e3cad64202 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Wed, 18 Mar 2026 13:02:16 -0400 Subject: [PATCH] feat(engine): add LinearFillStrategy adapter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wraps FillLinear in an IFillStrategy, sweeping all AngleCandidates from SharedState (falling back to 0° and 90°) in both directions and recording AngleResults for UI inspection. Co-Authored-By: Claude Sonnet 4.6 --- .../Strategies/LinearFillStrategy.cs | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 OpenNest.Engine/Strategies/LinearFillStrategy.cs diff --git a/OpenNest.Engine/Strategies/LinearFillStrategy.cs b/OpenNest.Engine/Strategies/LinearFillStrategy.cs new file mode 100644 index 0000000..dfe84ef --- /dev/null +++ b/OpenNest.Engine/Strategies/LinearFillStrategy.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using OpenNest.Math; + +namespace OpenNest +{ + public class LinearFillStrategy : IFillStrategy + { + public string Name => "Linear"; + public NestPhase Phase => NestPhase.Linear; + public int Order => 400; + + public List Fill(FillContext context) + { + var angles = context.SharedState.TryGetValue("AngleCandidates", out var cached) + ? (List)cached + : new List { 0, Angle.HalfPI }; + + var workArea = context.WorkArea; + List best = null; + var bestScore = default(FillScore); + + for (var ai = 0; ai < angles.Count; ai++) + { + context.Token.ThrowIfCancellationRequested(); + + var angle = angles[ai]; + var engine = new FillLinear(workArea, context.Plate.PartSpacing); + var h = engine.Fill(context.Item.Drawing, angle, NestDirection.Horizontal); + var v = engine.Fill(context.Item.Drawing, angle, NestDirection.Vertical); + + var angleDeg = Angle.ToDegrees(angle); + + if (h != null && h.Count > 0) + { + var scoreH = FillScore.Compute(h, workArea); + context.AngleResults.Add(new AngleResult + { + AngleDeg = angleDeg, + Direction = NestDirection.Horizontal, + PartCount = h.Count + }); + + if (best == null || scoreH > bestScore) + { + best = h; + bestScore = scoreH; + } + } + + if (v != null && v.Count > 0) + { + var scoreV = FillScore.Compute(v, workArea); + context.AngleResults.Add(new AngleResult + { + AngleDeg = angleDeg, + Direction = NestDirection.Vertical, + PartCount = v.Count + }); + + if (best == null || scoreV > bestScore) + { + best = v; + bestScore = scoreV; + } + } + + NestEngineBase.ReportProgress(context.Progress, NestPhase.Linear, + context.PlateNumber, best, workArea, + $"Linear: {ai + 1}/{angles.Count} angles, {angleDeg:F0}° best = {bestScore.Count} parts"); + } + + return best ?? new List(); + } + } +}