mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-07 06:25:44 -05:00
Slice 3 of common-line cutting. On costly plate (N26-295: 3/16 RA310S at about $2,500 a sheet) pairing parts one kerf apart fits the part the spacing cannot: the last plate's 38 parts fit on one 48x120 with Auto Nest only with pairs. - Drawing Properties gains "Allow common line" (Drawing.AllowCommonLine, off by default because customer edge-quality needs vary). The nest's CommonLineUsage (Off / When it adds parts / Whenever available) is set in Auto Nest and seeded from Tools > Nest Defaults; both persist (nest.json, defaults.json). - NestPipeline runs the ordinary solve, then, with a level on, trials where eligible parts are offered as kerf-gap pair compounds. Placed pairs expand into parts plus explicit NestJobCommonLine groups, are validated again, and CommonLineRanking keeps a trial only by the level: count first, then sheets; "when it adds parts" keeps the plain layout on a tie, "whenever" also takes a shorter cut or less material, never at the cost of a part. Engines, FillScore and their comparers are unchanged; Off asks the engine exactly what it did. - NestLayoutCheck exempts members only through a sheet's explicit group list and only when the job allows common lines; materializing and committing create Plate.CommonLines. - Server nesting writes common-line jobs as version 3 and replays the recorded trial answers, so the desktop binds the same groups. - Fill Area honors the level through a PlateFillService overload. - The benchmark gains --common-lines <level> --kerf <k>. Benchmark (synthetic nests + N26-295, --parallel 1): with no flag and with --common-lines off every engine matches the base commit; with a level on no layout becomes invalid and three runs save a sheet at equal nested area. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
2.5 KiB
C#
60 lines
2.5 KiB
C#
using OpenNest.Engine;
|
|
using OpenNest.Engine.Jobs;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.IO;
|
|
|
|
namespace OpenNest.Tests.CommonLines;
|
|
|
|
/// <summary>
|
|
/// N26-295's last plate (3/16 stainless, 48 x 120): 1 PT03, 3 PT14 and 34 PT42 at the nest's
|
|
/// 0.25 spacing. Without common lines Auto Nest fits 37 and leaves a PT42 for another sheet;
|
|
/// pairing PT42s one kerf apart fits all 38. The customer nest stays out of the repository:
|
|
/// set <c>CommonLineLastPlateNestPath</c> in test-config.json to run it.
|
|
/// </summary>
|
|
public class CommonLineAutoPlacementTests
|
|
{
|
|
private const double Kerf = 0.012;
|
|
|
|
private static NestPipelineRequest LastPlate(string path, CommonLineUsage usage)
|
|
{
|
|
var nest = new NestReader(path).Read();
|
|
var plate = nest.Plates[4];
|
|
var drawings = plate.Parts.Select(p => p.BaseDrawing).Distinct().ToList();
|
|
var pt42 = drawings.Single(d => d.Name.EndsWith("PT42"));
|
|
pt42.AllowCommonLine = true;
|
|
var items = drawings.Select(d => new NestItem
|
|
{
|
|
Drawing = d,
|
|
Quantity = d == pt42 ? 34 : plate.Parts.Count(p => p.BaseDrawing == d),
|
|
}).ToList();
|
|
var stock = new NestPlateStock("48x120", new Size(48, 120), 1, 0.25, new Spacing(0.25, 0.25, 0.25, 0.25), 1);
|
|
return new NestPipelineRequest("Default", items, [stock],
|
|
new NestJobOptions { CommonLineUsage = usage, CommonLineKerf = Kerf });
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void LastPlate_FitsTheLastPt42OnlyWithCommonLines()
|
|
{
|
|
var path = TestConfig.GetExistingPath("CommonLineLastPlateNestPath");
|
|
Skip.If(path == null, "N26-295 nest not configured in test-config.json");
|
|
|
|
var off = NestPipeline.Run(LastPlate(path!, CommonLineUsage.Off));
|
|
var on = NestPipeline.Run(LastPlate(path!, CommonLineUsage.WhenItAddsParts));
|
|
|
|
Assert.True(off.IsValid, string.Join("; ", off.Violations));
|
|
Assert.Equal(37, off.Raw.Plates.Sum(p => p.Placements.Count));
|
|
Assert.All(off.Plates, plate => Assert.Empty(plate.CommonLines));
|
|
|
|
Assert.True(on.IsValid, string.Join("; ", on.Violations));
|
|
Assert.Equal(NestJobStatus.Complete, on.Status);
|
|
var plate = Assert.Single(on.Plates);
|
|
Assert.Equal(38, plate.Parts.Count);
|
|
Assert.NotEmpty(plate.CommonLines);
|
|
Assert.All(plate.CommonLines, group =>
|
|
{
|
|
Assert.True(CommonLineGeometry.Check(group).IsIntact);
|
|
Assert.All(group.Members, member => Assert.EndsWith("PT42", member.BaseDrawing.Name));
|
|
});
|
|
}
|
|
}
|