using OpenNest.Clamps;
using OpenNest.Converters;
using OpenNest.Engine.Jobs;
using OpenNest.Engine.Jobs.Adapters;
using OpenNest.Engine.NestingEngines.Rectangles;
using OpenNest.Geometry;
using static OpenNest.Engine.Tests.NestingEngines.JobBuilder;
using static OpenNest.Engine.Tests.NestingEngines.Shapes;
namespace OpenNest.Engine.Tests.NestingEngines;
///
/// The sheet that finishes a job is re-packed into a shorter or narrower bin, so the drop it
/// leaves is as large as the packer can make it.
///
public class RectanglesSqueezeTests
{
///
/// N26-2A5: 14 door stops (4.168 x 1.5) and 14 lock plates (2 x 2) on a 26 x 26 sheet with a
/// front clamp. Every fit rule on the whole sheet stopped at 8.0 high; the shop's hand layout
/// holds all 28 under 7.5 (three rows of four stops, two stops on end over the clamp, a 2 x 2
/// block of plates, then a row of plates across the top), leaving an 18" drop.
///
[Fact]
public void FinishingSheetPacksIntoTheShortestStripItFinds()
{
var clamp = new ClampZone("clamp-1", new Box(19.25, 0, 1.5, 0.625));
var job = Job(
[
Part("door stop", Rectangle(4.168108, 1.5), 14),
Part("lock plate", Rectangle(2, 2), 14),
],
[Stock("sheet", 26, 26, spacing: 0.25, edge: new Spacing(0.25, 0.25, 0.25, 0.25), clampZones: [clamp])]);
var result = new RectanglesNestingEngine().Solve(job);
LayoutAssert.Valid(job, result);
Assert.Equal(NestJobStatus.Complete, result.Status);
Assert.Single(result.Plates);
Assert.True(Top(job, result.Plates[0]) <= 7.5 + 1e-9, $"layout top {Top(job, result.Plates[0])}");
}
[Fact]
public void SheetsThatDoNotFinishTheJobAreNotSqueezed()
{
// Four 9 x 9 squares fill each 20 x 20 sheet; only the last sheet could be squeezed, and
// it repeats the full layout, so every sheet keeps one pass of the twelve rule/mode packs.
var job = Job([Rectangle("a", 9, 9, 40)], [Stock("s", 20, 20, spacing: 0.2)]);
var calls = 0;
var result = new RectanglesNestingEngine { SheetPacked = _ => calls++ }.Solve(job);
LayoutAssert.Valid(job, result);
Assert.Equal(12, calls);
}
private static double Top(NestJob job, NestJobPlateResult sheet) =>
sheet.Placements.Max(pose =>
{
var part = job.Parts.Single(p => p.Id == pose.PartId);
var geometry = ConvertProgram.ToGeometry(DrawingJobMapper.ToProgram(part.Geometry))
.Where(e => SpecialLayers.IsMaterial(e.Layer)).ToArray();
foreach (var entity in geometry)
{
entity.Rotate(pose.Rotation);
entity.Offset(pose.X, pose.Y);
}
return geometry.Max(e => e.Top);
});
}