diff --git a/OpenNest.Engine/CuttingPlanning/CuttingPlanBatch.cs b/OpenNest.Engine/CuttingPlanning/CuttingPlanBatch.cs index e76e7cd..a170297 100644 --- a/OpenNest.Engine/CuttingPlanning/CuttingPlanBatch.cs +++ b/OpenNest.Engine/CuttingPlanning/CuttingPlanBatch.cs @@ -343,10 +343,10 @@ public sealed class CuttingPlanProposal { yield return heading + $"best-effort, unverified. {Count(plate.PartCount, "part")}, " + $"{plate.RegeneratedCount} regenerated; review lead-ins and cutting order."; - foreach (var line in Limit(DescribeOverlap(plate.Overlap))) - yield return line; - foreach (var line in Limit(result.Findings.Select(DescribeFinding))) - yield return line; + // Unverified Apply requires the operator to see every finding, not just a + // bounded diagnostic summary that hides later parts behind "... and N more". + foreach (var line in DescribeOverlap(plate.Overlap).Concat(result.Findings.Select(DescribeFinding))) + yield return " - " + line; yield break; } diff --git a/OpenNest.Tests/CuttingPlanning/BestEffortCuttingPlanTests.cs b/OpenNest.Tests/CuttingPlanning/BestEffortCuttingPlanTests.cs index 1dbebf8..606ce12 100644 --- a/OpenNest.Tests/CuttingPlanning/BestEffortCuttingPlanTests.cs +++ b/OpenNest.Tests/CuttingPlanning/BestEffortCuttingPlanTests.cs @@ -25,6 +25,25 @@ public class BestEffortCuttingPlanTests Assert.True(ProgramContent.Equal(original, part.BaseDrawing.Program)); } + [Fact] + public void UnverifiedSummary_ShowsEveryWarningBeforeAcceptance() + { + var parts = Enumerable.Range(0, 6).Select(index => + { + var part = TouchingContours(); + part.Offset(index * 12, 0); + return part; + }).ToArray(); + var proposal = CuttingPlanBatch.Capture([Plate(parts)], ExplicitContourTests.Parameters(), false).Plan(); + Assert.True(proposal.RequiresWarningAcceptance); + var findings = Assert.Single(proposal.Plates).Result.Findings.ToArray(); + Assert.True(findings.Length > 5); + Assert.Contains(findings, finding => finding.SourceOrdinal == 5); + var summary = string.Join("\n", proposal.Describe("in")); + Assert.Contains("Part 6", summary); + Assert.DoesNotContain("... and", summary); + } + [Fact] public void AcceptWarnings_InstallsOwnedProgramsAndLeavesStrictApplyClosed() { diff --git a/OpenNest/Forms/CuttingPlanForm.cs b/OpenNest/Forms/CuttingPlanForm.cs index a5e8586..51220e2 100644 --- a/OpenNest/Forms/CuttingPlanForm.cs +++ b/OpenNest/Forms/CuttingPlanForm.cs @@ -57,6 +57,8 @@ public partial class CuttingPlanForm : Form this.isOperationBusy = isOperationBusy; unit = UnitsHelper.GetShortString(nest.Units); InitializeComponent(); + // Best-effort acceptance must be able to display every warning, even on large jobs. + summaryBox.MaxLength = int.MaxValue; // Captured once: when Application.DoEvents ends the outermost message loop, WinForms // uninstalls its ambient context, so progress and results must not depend on whichever // context is current when planning starts. diff --git a/docs/cutting-planner.md b/docs/cutting-planner.md index c262472..a7af77d 100644 --- a/docs/cutting-planner.md +++ b/docs/cutting-planner.md @@ -314,7 +314,9 @@ plans every plate that has parts. Both open one dialog built on says the order was kept. Both are allowed 400 expansions per part (at least the default 20000), because both still plan contour order and entries for every part. - The summary lists every plate: ready plates with part counts and rapid travel, others - with their status and findings. Finding part numbers are the plate's current order, as the + with their status and findings. Unverified proposals show every overlap and route + warning in the scrollable summary before the acceptance checkbox is used; they do + not truncate later parts' warnings. Finding part numbers are the plate's current order, as the editor numbers them. The preview shows the active plate detached from the nest (quantity zero, so drawing quantities do not change) in the proposed order with the proposed programs. Ready and best-effort proposals can be previewed only while the plate still