diff --git a/OpenNest.Engine.Qwen38FlashNext/Engine/JobSolver.cs b/OpenNest.Engine.Qwen38FlashNext/Engine/JobSolver.cs index 77fa5a2..af24799 100644 --- a/OpenNest.Engine.Qwen38FlashNext/Engine/JobSolver.cs +++ b/OpenNest.Engine.Qwen38FlashNext/Engine/JobSolver.cs @@ -405,7 +405,7 @@ internal sealed class JobSolver ); } plates.Add( - new NestJobPlateResult(sheet.StockIndex, _job.Plates[sheet.StockIndex], placements) + new NestJobPlateResult(plates.Count, _job.Plates[sheet.StockIndex], placements) ); } diff --git a/OpenNest.Engine.Qwen38FlashNext/Engine/PartPreparation.cs b/OpenNest.Engine.Qwen38FlashNext/Engine/PartPreparation.cs index df544f0..50a049d 100644 --- a/OpenNest.Engine.Qwen38FlashNext/Engine/PartPreparation.cs +++ b/OpenNest.Engine.Qwen38FlashNext/Engine/PartPreparation.cs @@ -78,7 +78,7 @@ internal sealed class PartModel DrawingJobMapper.ToProgram(part.Geometry) ) ) - if (!ReferenceEquals(entity.Layer, SpecialLayers.Rapid)) + if (SpecialLayers.IsMaterial(entity.Layer)) entities.Add(entity); if (entities.Count == 0) return null; diff --git a/OpenNest.Engine.Qwen38FlashNext/tests/Qwen38FlashNextNestingEngineTests.cs b/OpenNest.Engine.Qwen38FlashNext/tests/Qwen38FlashNextNestingEngineTests.cs index 6d39936..9e45d04 100644 --- a/OpenNest.Engine.Qwen38FlashNext/tests/Qwen38FlashNextNestingEngineTests.cs +++ b/OpenNest.Engine.Qwen38FlashNext/tests/Qwen38FlashNextNestingEngineTests.cs @@ -107,6 +107,37 @@ public class Qwen38FlashNextNestingEngineTests Assert.Equal(1, huge.Unplaced); } + [Fact] + public void EtchMarksAreLeftOutOfNestingGeometry() + { + // A bend tick starts on material and ends 1.0 into a side notch, outside the part but + // inside its bounding box (the PEP case that crashed nesting before 1b5e1b1). As + // material it is open geometry leaving the part; as a mark it must be ignored. + var etched = Polyline((0, 0), (10, 0), (10, 4), (8, 4), (8, 6), (10, 6), (10, 10), (0, 10)); + etched.Codes.Add(new RapidMove(7.5, 5)); + etched.Codes.Add(new LinearMove(9, 5) { Layer = LayerType.Scribe }); + var job = Job(new[] { Part("part", etched, 2, RotationPolicy.Fixed(0)) }, new[] { Stock("sheet", 10.4, 20.6, spacing: 0.2) }); + + var result = new Qwen38FlashNextNestingEngine().Solve(job); + + AssertValid(job, result); + Assert.Equal(NestJobStatus.Complete, result.Status); + Assert.Equal(2, Assert.Single(result.Plates).Placements.Count); + } + + [Fact] + public void PlateIndicesRunInCommitOrder() + { + // Every sheet comes from the same stock (index 0), so the stock index must not leak + // into PlateIndex: the host and OpenNest.Api treat it as the sheet's position. + var job = Job(new[] { Part("square", Rectangle(10, 10), 30) }, new[] { Stock("sheet", 25, 45, spacing: 0.25) }); + + var result = new Qwen38FlashNextNestingEngine().Solve(job); + + Assert.True(result.Plates.Count > 1); + Assert.Equal(Enumerable.Range(0, result.Plates.Count), result.Plates.Select(p => p.PlateIndex)); + } + // ---- helpers ------------------------------------------------------------------------- private static void AssertValid(NestJob job, NestJobResult result)