mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-15 03:15:34 -05:00
The repo mixed variants such as center/centre and color/colour, so a name could be spelled either way and searches missed half the hits. Standardize on the US spelling, matching .NET's own APIs (Color, Center). Wire values owned by other systems keep their spelling: the material ledger's "Cancelled" hold status and GitHub's "cancelled" job status. No behavior change beyond the spelling of a few status messages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
97 lines
4.1 KiB
C#
97 lines
4.1 KiB
C#
using OpenNest.Engine.Jobs;
|
|
using OpenNest.Engine.Jobs.Cutouts;
|
|
using OpenNest.Engine.Tests.NestingEngines;
|
|
using TestShapes = OpenNest.Engine.Tests.NestingEngines.Shapes;
|
|
|
|
namespace OpenNest.Engine.Tests.Jobs.Cutouts;
|
|
|
|
public class CutoutLatticeFillTests
|
|
{
|
|
private const double Spacing = 0.25;
|
|
|
|
// A 20" ring around a 10" round cutout. At 0.25" spacing the usable circle is 9.5" across;
|
|
// the largest square inside it is 6.72", which holds a 5 x 5 grid of 1" squares.
|
|
private const int InscribedRectangleCount = 25;
|
|
|
|
private static NestJobPart Ring() => JobBuilder.Part("ring", TestShapes.Ring(20, 10), 1);
|
|
|
|
private static NestJobPart Squares(double side, int quantity) =>
|
|
JobBuilder.Part("square", TestShapes.Rectangle(side, side), quantity);
|
|
|
|
[Fact]
|
|
public void ShiftedLatticeFillsMoreOfARoundCutoutThanItsInscribedRectangle()
|
|
{
|
|
var poses = CutoutLatticeFill.Fill(Ring(), 0, Squares(1, 100), 100, Spacing);
|
|
|
|
Assert.True(poses.Count > InscribedRectangleCount, $"placed {poses.Count}");
|
|
AssertValidLayout(Ring(), Squares(1, poses.Count), poses);
|
|
}
|
|
|
|
[Fact]
|
|
public void ShiftingTheLatticeKeepsMoreCopiesThanTheUnshiftedLattice()
|
|
{
|
|
var shifted = CutoutLatticeFill.Fill(Ring(), 0, Squares(1, 100), 100, Spacing);
|
|
var unshifted = CutoutLatticeFill.Fill(Ring(), 0, Squares(1, 100), 100, Spacing, 0, default);
|
|
|
|
Assert.True(shifted.Count > unshifted.Count, $"shifted {shifted.Count}, unshifted {unshifted.Count}");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(7.0)] // diagonal 9.90: wider than the cutout less its wall spacing
|
|
[InlineData(6.75)] // corners 4.773 from the center; the usable radius is 4.75
|
|
public void InsertThatCannotClearTheCutoutWallIsNeverPlaced(double side)
|
|
{
|
|
Assert.Empty(CutoutLatticeFill.Fill(Ring(), 0, Squares(side, 4), 4, Spacing));
|
|
}
|
|
|
|
[Fact]
|
|
public void QuantityCapsTheCopiesReturned()
|
|
{
|
|
var poses = CutoutLatticeFill.Fill(Ring(), 0, Squares(1, 5), 5, Spacing);
|
|
|
|
Assert.Equal(5, poses.Count);
|
|
AssertValidLayout(Ring(), Squares(1, 5), poses);
|
|
}
|
|
|
|
// Both cases fail intermittently; unskip when Project Memory opennest issue c98c21bd is fixed.
|
|
private const string FillNondeterminism = "Open defect (Project Memory opennest c98c21bd): Fill can "
|
|
+ "return different, equally scored lattices between identical calls.";
|
|
|
|
[Theory]
|
|
[InlineData(1.0, 1.0, Skip = FillNondeterminism)]
|
|
[InlineData(1.5, 0.75, Skip = FillNondeterminism)]
|
|
public void RepeatedCallsReturnIdenticalPoses(double length, double width)
|
|
{
|
|
var part = JobBuilder.Part("part", TestShapes.Rectangle(length, width), 100);
|
|
|
|
var first = CutoutLatticeFill.Fill(Ring(), 0, part, 100, Spacing);
|
|
var second = CutoutLatticeFill.Fill(Ring(), 0, part, 100, Spacing);
|
|
|
|
Assert.Equal(first, second);
|
|
}
|
|
|
|
/// <summary>Places the ring 1" in from the sheet corner, moves the copies with it and runs
|
|
/// the production layout check over the whole sheet.</summary>
|
|
private static void AssertValidLayout(NestJobPart frame, NestJobPart insert, IReadOnlyList<NestJobPlacement> poses)
|
|
{
|
|
var stock = JobBuilder.Stock("sheet", 22, 22, Spacing);
|
|
var job = JobBuilder.Job(new[] { frame, insert }, new[] { stock });
|
|
var bounds = JobPartGeometry.Read(frame.Geometry).Bounds;
|
|
var x = 1 - bounds.Left;
|
|
var y = 1 - bounds.Bottom;
|
|
var placements = new[] { new NestJobPlacement(frame.Id, 0, x, y, 0) }
|
|
.Concat(poses.Select((p, i) => new NestJobPlacement(insert.Id, i, p.X + x, p.Y + y, p.Rotation)))
|
|
.ToArray();
|
|
var result = new NestJobResult(NestJobStatus.Complete, NestJobStopReason.Completed,
|
|
new[] { new NestJobPlateResult(0, stock, placements) },
|
|
new[]
|
|
{
|
|
new PartFulfillment(frame.Id, 1, 1, 0),
|
|
new PartFulfillment(insert.Id, insert.Quantity, poses.Count, insert.Quantity - poses.Count),
|
|
},
|
|
new[] { new StockUsage(stock.Id, 1, null) });
|
|
|
|
LayoutAssert.Valid(job, result);
|
|
}
|
|
}
|