mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-15 18:01:37 -04:00
When a commit installed solved explicit zones on a plate that followed a different nest clamp rail (an extra sheet created from the defaults), the plate kept the rail, so a later Size or Quadrant assignment (Edit Plate assigns Size even when unchanged) or a stock-option build swapped the validated zones for the rail's clamps. Install solved zones as explicit zones and keep the rail only when it recreates them. Review finding 1, Project Memory 4e5f566d-626e-4db5-9352-14ddd9051181.
171 lines
6.7 KiB
C#
171 lines
6.7 KiB
C#
using OpenNest.Engine.Jobs;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Engine.Tests.Jobs;
|
|
|
|
/// <summary>
|
|
/// A committed live plate must carry exactly the clamp keep-outs its layout was solved and
|
|
/// validated against, in plate coordinates, including sheets the commit had to create.
|
|
/// </summary>
|
|
public class ClampZoneCommitTests
|
|
{
|
|
// A 1.5 x 0.625 clamp on the front edge of a 48 x 96 sheet (Length 96 runs along X).
|
|
private const double ZoneX = 5.25;
|
|
|
|
private static ClampZone Zone() => new("clamp-1", new Box(ZoneX, 0, 1.5, 0.625));
|
|
|
|
/// <summary>Two different one-part sheets so repeat grouping cannot merge them.</summary>
|
|
private sealed class TwoSheetStub : INestingEngine
|
|
{
|
|
public NestJobResult Solve(NestJob job, IProgress<NestJobProgress>? progress = null,
|
|
CancellationToken token = default)
|
|
{
|
|
var stock = job.Plates[0];
|
|
var work = stock.WorkArea;
|
|
var builder = new NestJobResultBuilder(job);
|
|
builder.AddSheet(stock, new[] { (job.Parts[0].Id, work.Left + 20, work.Bottom + 10, 0.0) });
|
|
builder.AddSheet(stock, new[] { (job.Parts[0].Id, work.Left + 40, work.Bottom + 20, 0.0) });
|
|
return builder.Build(NestJobStopReason.Completed);
|
|
}
|
|
}
|
|
|
|
private static NestPipelineResult Result(Drawing drawing, int quadrant, params ClampZone[] zones)
|
|
{
|
|
var result = NestPipeline.Run(new TwoSheetStub(), "stub", new NestPipelineRequest("stub",
|
|
new[] { new NestItem { Drawing = drawing, Quantity = 2 } },
|
|
new[]
|
|
{
|
|
new NestPlateStock("sheet", new Size(48, 96), null, 0.25, new Spacing(1, 1, 1, 1),
|
|
quadrant, cost: null, clampZones: zones),
|
|
}));
|
|
Assert.True(result.IsValid, string.Join("; ", result.Violations));
|
|
Assert.Equal(2, result.Plates.Count);
|
|
return result;
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(1)]
|
|
[InlineData(2)]
|
|
[InlineData(3)]
|
|
[InlineData(4)]
|
|
public void EveryCommittedPlateCarriesTheSolvedZonesInPlateCoordinates(int quadrant)
|
|
{
|
|
var drawing = new Drawing("part", TestDrawingFactory.Rectangle());
|
|
var nest = new Nest();
|
|
nest.Drawings.Add(drawing);
|
|
nest.CreatePlate(); // empty template without zones; the second sheet is created by commit
|
|
using var manager = new PlateManager(nest);
|
|
|
|
var applied = NestPipelineCommit.ApplyToEmptyPlates(Result(drawing, quadrant, Zone()), manager);
|
|
|
|
Assert.Equal(2, applied.Count);
|
|
Assert.All(applied, plate =>
|
|
{
|
|
var zone = Assert.Single(plate.ClampZones);
|
|
Assert.Equal("clamp-1", zone.Id);
|
|
// Exact bits: the inverse of the stock's placement-frame translation.
|
|
Assert.Equal(ZoneX, zone.Bounds.X);
|
|
Assert.Equal(0, zone.Bounds.Y);
|
|
Assert.Equal(1.5, zone.Bounds.Length);
|
|
Assert.Equal(0.625, zone.Bounds.Width);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void MatchingPlateZonesAreKeptWithoutChangeEvents()
|
|
{
|
|
var drawing = new Drawing("part", TestDrawingFactory.Rectangle());
|
|
var nest = new Nest();
|
|
nest.Drawings.Add(drawing);
|
|
var template = nest.CreatePlate();
|
|
template.Quadrant = 3;
|
|
template.Size = new Size(48, 96);
|
|
var original = Zone();
|
|
template.ClampZones.Add(original);
|
|
var changes = 0;
|
|
template.ClampZonesChanged += (_, _) => changes++;
|
|
using var manager = new PlateManager(nest);
|
|
|
|
var applied = NestPipelineCommit.ApplyToEmptyPlates(Result(drawing, 3, Zone()), manager);
|
|
|
|
Assert.Same(template, applied[0]);
|
|
Assert.Same(original, Assert.Single(template.ClampZones));
|
|
Assert.Equal(0, changes);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(1)]
|
|
[InlineData(2)]
|
|
[InlineData(3)]
|
|
[InlineData(4)]
|
|
public void SolvedZonesARailCannotRecreateStopFollowingThatRail(int quadrant)
|
|
{
|
|
// The nest rail puts a clamp at 6"; the template carries a different explicit zone,
|
|
// so the extra sheet the commit creates must not keep following the nest rail.
|
|
var drawing = new Drawing("part", TestDrawingFactory.Rectangle());
|
|
var nest = new Nest();
|
|
nest.Drawings.Add(drawing);
|
|
nest.PlateDefaults.Size = new Size(48, 96);
|
|
nest.PlateDefaults.Quadrant = quadrant;
|
|
nest.SetClampRail(new ClampRail(1.5, 0.625, new[] { 6.0 }));
|
|
var template = nest.CreatePlate();
|
|
template.SetClampRail(null!);
|
|
var manual = new ClampZone("manual", new Box(10, 0, 2, 0.5));
|
|
template.ClampZones.Add(manual);
|
|
using var manager = new PlateManager(nest);
|
|
|
|
var applied = NestPipelineCommit.ApplyToEmptyPlates(
|
|
Result(drawing, quadrant, template.ClampZones.ToArray()), manager);
|
|
|
|
Assert.Equal(2, applied.Count);
|
|
Assert.All(applied, plate =>
|
|
{
|
|
Assert.Null(plate.ClampRail);
|
|
plate.Size = plate.Size; // the Edit Plate dialog assigns Size even when unchanged
|
|
plate.Quadrant = plate.Quadrant;
|
|
Assert.Equal("manual", Assert.Single(plate.ClampZones).Id);
|
|
Assert.Equal("manual", Assert.Single(Assert.Single(
|
|
NestStockBuilder.FromTemplate(plate, [new PlateOption { Width = 48, Length = 96 }])).ClampZones).Id);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void SolvedZonesTheRailRecreatesKeepFollowingIt()
|
|
{
|
|
var drawing = new Drawing("part", TestDrawingFactory.Rectangle());
|
|
var nest = new Nest();
|
|
nest.Drawings.Add(drawing);
|
|
nest.PlateDefaults.Size = new Size(48, 96);
|
|
var rail = new ClampRail(1.5, 0.625, new[] { 6.0 });
|
|
nest.SetClampRail(rail);
|
|
var template = nest.CreatePlate();
|
|
using var manager = new PlateManager(nest);
|
|
|
|
var applied = NestPipelineCommit.ApplyToEmptyPlates(
|
|
Result(drawing, 1, template.ClampZones.ToArray()), manager);
|
|
|
|
Assert.Equal(2, applied.Count);
|
|
Assert.All(applied, plate =>
|
|
{
|
|
Assert.Same(rail, plate.ClampRail);
|
|
plate.Size = new Size(48, 4);
|
|
Assert.Empty(plate.ClampZones); // still re-resolves: no clamp reaches a 4" sheet
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void ZonesTheLayoutWasNotSolvedWithAreRemoved()
|
|
{
|
|
var drawing = new Drawing("part", TestDrawingFactory.Rectangle());
|
|
var nest = new Nest();
|
|
nest.Drawings.Add(drawing);
|
|
var template = nest.CreatePlate();
|
|
template.ClampZones.Add(Zone());
|
|
using var manager = new PlateManager(nest);
|
|
|
|
var applied = NestPipelineCommit.ApplyToEmptyPlates(Result(drawing, 1), manager);
|
|
|
|
Assert.All(applied, plate => Assert.Empty(plate.ClampZones));
|
|
}
|
|
}
|