mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-06 07:55:43 -05:00
Pinned-lead and locked-lead warnings named a Drawing Pins Off command and a Clear Lead-ins command that the desktop does not have; name Plate > Remove Lead-ins and spacing instead. Closing Plan Cutting no longer claims nothing changed after lead-ins or cut-offs were cleared, the no-stock reason no longer says the part is larger than every sheet when only the usable area at the checked rotations is too small, and the console says whole-job engines.
164 lines
8.0 KiB
C#
164 lines
8.0 KiB
C#
using System.Reflection;
|
|
using OpenNest.CNC;
|
|
using OpenNest.CNC.CuttingPlanning;
|
|
using OpenNest.CNC.CuttingStrategy;
|
|
using OpenNest.Diagnostics;
|
|
using OpenNest.Engine.CuttingPlanning;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Tests.CuttingPlanning;
|
|
|
|
/// <summary>
|
|
/// Capture reads a placement's active drawing pins (not when switched off), a locked or
|
|
/// unregenerated part keeps its program with a warning, and a proposal goes stale when the
|
|
/// drawing's pins or the part's pins-off flag change after capture.
|
|
/// </summary>
|
|
public class DrawingPinCaptureTests
|
|
{
|
|
[Fact]
|
|
public void PinsOff_PlansThePartWithTheNestSettingsAndNoWarning()
|
|
{
|
|
var (plate, part) = PinnedPlate();
|
|
part.DrawingPinsOff = true;
|
|
var plain = new Part(new Drawing("plain", ExplicitContourTests.Square(false)), part.Location);
|
|
|
|
var result = CuttingPlanService.Plan(CuttingPlanRequest.ForPlate(plate,
|
|
confirmedParameters: PinnedContourTests.NestSettings()));
|
|
var automatic = CuttingPlanService.Plan(new CuttingPlanRequest([plain],
|
|
confirmedParameters: PinnedContourTests.NestSettings()));
|
|
|
|
Assert.Equal(CuttingPlanStatus.Ready, result.Status);
|
|
Assert.Empty(result.Findings);
|
|
Assert.Equal(ExplicitContourTests.Fingerprint(automatic.ProposedOrder[0].CopyProgram()),
|
|
ExplicitContourTests.Fingerprint(result.ProposedOrder[0].CopyProgram()));
|
|
}
|
|
|
|
[Fact]
|
|
public void LockedPartWithActivePins_KeepsItsProgramWithAWarningNotARefusal()
|
|
{
|
|
var (plate, part) = PinnedPlate();
|
|
var prepared = PreparedContours.Capture(part.BaseDrawing.Program, ExplicitContourTests.Parameters());
|
|
var locked = prepared.Emit([prepared.ClosestEntry(0, new Vector(-1, 5))]);
|
|
Assert.True(part.RestoreLeadInProgram(locked, true));
|
|
var program = part.Program;
|
|
|
|
var proposal = CuttingPlanBatch.Capture([plate], PinnedContourTests.NestSettings(), false).Plan();
|
|
|
|
var planned = Assert.Single(proposal.Plates);
|
|
Assert.True(planned.HasOnlyFixedLeadWarnings);
|
|
var warning = Assert.Single(planned.Result.Findings);
|
|
Assert.Equal(PostVerificationKind.FixedLead, warning.Kind);
|
|
Assert.Equal("Locked lead-ins override drawing pins on part 1; use Plate > Remove Lead-ins, then Plan Cutting, to apply the pins.", warning.Message);
|
|
Assert.False(Assert.Single(planned.Result.ProposedOrder).IsRegenerated);
|
|
Assert.Equal(CuttingCommitStatus.Applied, proposal.Apply(acceptWarnings: true).Status);
|
|
Assert.Same(program, part.Program);
|
|
|
|
// Switching the pins off for this part leaves nothing to warn about.
|
|
part.DrawingPinsOff = true;
|
|
Assert.True(CuttingPlanBatch.Capture([plate], PinnedContourTests.NestSettings(), false).Plan().CanApply);
|
|
}
|
|
|
|
[Fact]
|
|
public void IneligiblePartWithActivePins_IsNotRegeneratedAndWarns()
|
|
{
|
|
var (plate, part) = PinnedPlate();
|
|
var other = new Part(new Drawing("other", ExplicitContourTests.Square(false)), new Vector(30, 0));
|
|
plate.Parts.Add(other);
|
|
|
|
var result = CuttingPlanService.Plan(CuttingPlanRequest.ForPlate(plate,
|
|
confirmedParameters: PinnedContourTests.NestSettings(), eligibleParts: [other]));
|
|
|
|
Assert.Equal(CuttingPlanStatus.BestEffort, result.Status);
|
|
Assert.Equal("Drawing pins on part 1 are not applied: the part is not regenerated.",
|
|
Assert.Single(result.Findings).Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void PinnedPartWithEarlierLeadInsFromOtherSettings_IsRegeneratedWithItsPins()
|
|
{
|
|
var (plate, part) = PinnedPlate();
|
|
var earlier = ExplicitContourTests.Parameters();
|
|
var prepared = PreparedContours.Capture(part.BaseDrawing.Program, earlier);
|
|
Assert.True(part.RestoreLeadInProgram(prepared.Emit([prepared.ClosestEntry(0, new Vector(11, 5))]), false));
|
|
part.CuttingParameters = earlier;
|
|
|
|
var proposal = CuttingPlanBatch.Capture([plate], PinnedContourTests.NestSettings(), false).Plan();
|
|
|
|
Assert.True(proposal.CanApply, string.Join("\n", proposal.Describe("in")));
|
|
var placement = Assert.Single(proposal.Plates[0].Result.ProposedOrder);
|
|
Assert.True(placement.IsRegenerated);
|
|
Assert.Equal(new Vector(0, 0), Assert.Single(placement.ContourChoices).Point);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("unchanged")]
|
|
[InlineData("pins-off")]
|
|
[InlineData("pin-added")]
|
|
[InlineData("pin-replaced")]
|
|
[InlineData("pin-removed")]
|
|
[InlineData("list-replaced")]
|
|
public void Apply_IsStaleWhenPinsOrPinsOffChangeAfterCapture(string change)
|
|
{
|
|
var (plate, part) = PinnedPlate();
|
|
var result = CuttingPlanService.Plan(CuttingPlanRequest.ForPlate(plate,
|
|
confirmedParameters: PinnedContourTests.NestSettings()));
|
|
Assert.Equal(CuttingPlanStatus.Ready, result.Status);
|
|
var pins = part.BaseDrawing.CutPins;
|
|
switch (change)
|
|
{
|
|
case "pins-off": part.DrawingPinsOff = true; break;
|
|
case "pin-added": pins.Add(PinnedContourTests.Corner(new Vector(10, 10))); break;
|
|
case "pin-replaced": pins[0] = PinnedContourTests.Corner(new Vector(10, 0)); break;
|
|
case "pin-removed": pins.Clear(); break;
|
|
case "list-replaced": part.BaseDrawing.CutPins = [.. pins]; break;
|
|
}
|
|
|
|
var commit = CuttingPlanService.Apply([result]);
|
|
|
|
Assert.Equal(change == "unchanged" ? CuttingCommitStatus.Applied : CuttingCommitStatus.Stale, commit.Status);
|
|
if (change != "unchanged")
|
|
Assert.Contains("drawing pins", result.Snapshot!.PlateState!.Difference(), StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void PinFingerprint_SeesEveryPublicPropertyOfAPin()
|
|
{
|
|
// ContourCutPin is immutable: every public property must come from a constructor
|
|
// argument the fingerprint writes. A new property means extending StateFingerprint.
|
|
var properties = typeof(ContourCutPin).GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
|
.Select(p => p.Name).Order().ToArray();
|
|
Assert.Equal(["HasTab", "LeadIn", "LeadOut", "Point", "Tab"], properties);
|
|
Assert.Empty(typeof(ContourCutPin).GetFields(BindingFlags.Public | BindingFlags.Instance));
|
|
|
|
var baseline = new ContourCutPin(new Vector(1, 2), new LineLeadIn { Length = 0.25 }, new NoLeadOut(),
|
|
new NormalTab { Size = 0.03 });
|
|
ContourCutPin[] variants =
|
|
[
|
|
new(new Vector(1.5, 2), baseline.LeadIn, baseline.LeadOut, baseline.Tab),
|
|
new(new Vector(1, 2.5), baseline.LeadIn, baseline.LeadOut, baseline.Tab),
|
|
new(baseline.Point, new LineLeadIn { Length = 0.3 }, baseline.LeadOut, baseline.Tab),
|
|
new(baseline.Point, new ArcLeadIn { Radius = 0.25 }, baseline.LeadOut, baseline.Tab),
|
|
new(baseline.Point, baseline.LeadIn, baseline.LeadOut, new NormalTab { Size = 0.04 }),
|
|
new(baseline.Point, baseline.LeadIn, baseline.LeadOut, new BreakerTab { Size = 0.03 }),
|
|
new(baseline.Point, baseline.LeadIn, baseline.LeadOut), // No tab.
|
|
new(baseline.Point, baseline.LeadIn, new LineLeadOut { Length = 0.1 }),
|
|
];
|
|
var fingerprints = variants.Select(v => StateFingerprint.Of([v]))
|
|
.Append(StateFingerprint.Of([baseline])).ToArray();
|
|
Assert.Equal(fingerprints.Length, fingerprints.Distinct().Count());
|
|
Assert.Equal(StateFingerprint.Of([baseline]), StateFingerprint.Of([new ContourCutPin(
|
|
new Vector(1, 2), new LineLeadIn { Length = 0.25 }, new NoLeadOut(), new NormalTab { Size = 0.03 })]));
|
|
Assert.NotEqual(StateFingerprint.Of((IReadOnlyList<ContourCutPin>)null!), StateFingerprint.Of([]));
|
|
Assert.NotEqual(StateFingerprint.Of([baseline, variants[0]]), StateFingerprint.Of([variants[0], baseline]));
|
|
}
|
|
|
|
private static (Plate Plate, Part Part) PinnedPlate()
|
|
{
|
|
var part = new Part(PinnedContourTests.SquareWithPin(new Vector(0, 0), PinnedContourTests.Corner()),
|
|
new Vector(5, 5));
|
|
var plate = new Nest().CreatePlate();
|
|
plate.Parts.Add(part);
|
|
return (plate, part);
|
|
}
|
|
}
|