diff --git a/OpenNest.Engine.Qwen/OpenNest.Engine.Qwen.csproj b/OpenNest.Engine.Qwen/OpenNest.Engine.Qwen.csproj new file mode 100644 index 0000000..bb15a22 --- /dev/null +++ b/OpenNest.Engine.Qwen/OpenNest.Engine.Qwen.csproj @@ -0,0 +1,13 @@ + + + net8.0 + OpenNest.Engine.Qwen + OpenNest.Engine.Qwen + enable + enable + + + + + + diff --git a/OpenNest.Engine.Qwen/QwenNestingEngine.cs b/OpenNest.Engine.Qwen/QwenNestingEngine.cs new file mode 100644 index 0000000..a3ed1b4 --- /dev/null +++ b/OpenNest.Engine.Qwen/QwenNestingEngine.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading; +using OpenNest.Engine.Jobs; + +namespace OpenNest.Engine.Qwen; + +/// +/// TODO: name and describe the actual placement strategy here (e.g. "skyline packer with +/// greedy shelf assignment", "NFP-based sliding placement with simulated-annealing order +/// search", etc). This must be an independently designed algorithm — see README.md. +/// +public sealed class QwenNestingEngine : INestingEngine +{ + public NestJobResult Solve( + NestJob job, + IProgress? progress = null, + CancellationToken token = default + ) + { + ArgumentNullException.ThrowIfNull(job); + + // TODO: implement independent placement logic here. + // + // Do NOT call NestingEngineRegistry.Create(...), PlateNesterFactory, or any + // FixedStrategyNestingEngine / StockLadderNestingEngine instance from inside this + // method. Decide placements yourself using OpenNest.Core / OpenNest.Geometry + // primitives (Polygon, NoFitPolygon, Collision, ConvexHull, RotatingCalipers, etc). + // + // job.Parts -> requested parts (PartGeometrySnapshot geometry, quantity, priority, rotation policy) + // job.Plates -> candidate stock sheets (size, spacing, quadrant, quantity) + // job.Options -> job-wide options + // + // Return a NestJobResult built from NestJobPlateResult (one per used sheet, holding + // ordered NestJobPlacement values), PartFulfillment (requested vs placed per part id), + // and StockUsage (sheets used per stock id). + + throw new NotImplementedException( + "Qwen nesting engine placement logic not yet implemented." + ); + } +} diff --git a/OpenNest.Engine.Qwen/README.md b/OpenNest.Engine.Qwen/README.md new file mode 100644 index 0000000..9c401d5 --- /dev/null +++ b/OpenNest.Engine.Qwen/README.md @@ -0,0 +1,57 @@ +# OpenNest.Engine.Qwen + +An independent `INestingEngine` implementation — **not** a wrapper, ensemble, or +selector over OpenNest's built-in engines (`StockLadderNestingEngine`, +`FixedStrategyNestingEngine` "Default"/"Strip"/"Vertical Remnant"/"Horizontal Remnant`, +or anything reachable through `PlateNesterFactory`/`NestingEngineRegistry`). +`Solve()` must never call, instantiate, or otherwise delegate a placement decision +to one of those. + +## Allowed building blocks + +Low-level geometry/data-structure primitives are fair game — they are not nesting +strategies: + +- `OpenNest.Core` geometry: `Polygon`, `Shape`, `BoundingBox`, `Vector`, `Box`, + `ConvexHull`, `ConvexDecomposition`, `RotatingCalipers`, `Collision` (overlap/spacing + checks), `NoFitPolygon`, `ShapeProfile`, `SpatialQuery`. +- `OpenNest.Engine` support types if useful: `PartBoundary`, `RotationAnalysis`, + `AngleCandidateBuilder` — the *decision logic* using them must be your own (don't just + call `BestFitFinder`/`PairEvaluator`/`RotationSlideStrategy`, which are the existing + best-fit engine's internals). + +## What to fill in + +`QwenNestingEngine.cs` — implement `Solve()`. Pick and document an actual +placement strategy (NFP-based sliding placement, skyline/shelf packer, +simulated-annealing/genetic layout search, guillotine-cut packer, +physics/gravity-settling, etc). It's fine to be simpler or worse than the built-in +engines to start; it must not be the same algorithm re-derived through indirection. + +## Build + +```bash +dotnet build OpenNest.Engine.Qwen/OpenNest.Engine.Qwen.csproj +``` + +This project is intentionally **outside** `OpenNest.sln` (same pattern as the +`OpenNest.Engine.Aurora` plugin) — it's discovered at runtime as a plugin, not built +as part of the main solution. + +## Try it out with the benchmark + +`OpenNest.Benchmark` auto-loads plugin engines from an `Engines/` folder next to its +own build output: + +```bash +dotnet build OpenNest.Engine.Qwen/OpenNest.Engine.Qwen.csproj -c Release +dotnet build OpenNest.Benchmark/OpenNest.Benchmark.csproj -c Release + +mkdir -p OpenNest.Benchmark/bin/Release/net8.0/Engines +cp OpenNest.Engine.Qwen/bin/Release/net8.0/OpenNest.Engine.Qwen.dll OpenNest.Benchmark/bin/Release/net8.0/Engines/ + +dotnet OpenNest.Benchmark/bin/Release/net8.0/OpenNest.Benchmark.dll +``` + +Your engine will show up in the report under its CLR type name (`QwenNestingEngine`), +competing on equal footing against the built-in engines. diff --git a/OpenNest.Engine.Qwen/tests/OpenNest.Engine.Qwen.Tests.csproj b/OpenNest.Engine.Qwen/tests/OpenNest.Engine.Qwen.Tests.csproj new file mode 100644 index 0000000..e3f0be9 --- /dev/null +++ b/OpenNest.Engine.Qwen/tests/OpenNest.Engine.Qwen.Tests.csproj @@ -0,0 +1,19 @@ + + + net8.0 + enable + enable + false + true + + + + + + + + + + + + diff --git a/OpenNest.Engine.Qwen/tests/QwenNestingEngineTests.cs b/OpenNest.Engine.Qwen/tests/QwenNestingEngineTests.cs new file mode 100644 index 0000000..4043aee --- /dev/null +++ b/OpenNest.Engine.Qwen/tests/QwenNestingEngineTests.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using OpenNest.Engine.Jobs; +using OpenNest.Geometry; + +namespace OpenNest.Engine.Qwen.Tests; + +public class QwenNestingEngineTests +{ + [Fact] + public void SolveReturnsAResultForASingleSimplePart() + { + // TODO: replace with a real fixture once Solve() is implemented — this only + // proves the plumbing (project reference, constructor, interface) is wired up. + var engine = new QwenNestingEngine(); + + Assert.NotNull(engine); + Assert.IsAssignableFrom(engine); + } +} diff --git a/OpenNest.Engine.Sonnet5/OpenNest.Engine.Sonnet5.csproj b/OpenNest.Engine.Sonnet5/OpenNest.Engine.Sonnet5.csproj new file mode 100644 index 0000000..0ffbe7b --- /dev/null +++ b/OpenNest.Engine.Sonnet5/OpenNest.Engine.Sonnet5.csproj @@ -0,0 +1,13 @@ + + + net8.0 + OpenNest.Engine.Sonnet5 + OpenNest.Engine.Sonnet5 + enable + enable + + + + + + diff --git a/OpenNest.Engine.Sonnet5/README.md b/OpenNest.Engine.Sonnet5/README.md new file mode 100644 index 0000000..ba2ffbb --- /dev/null +++ b/OpenNest.Engine.Sonnet5/README.md @@ -0,0 +1,57 @@ +# OpenNest.Engine.Sonnet5 + +An independent `INestingEngine` implementation — **not** a wrapper, ensemble, or +selector over OpenNest's built-in engines (`StockLadderNestingEngine`, +`FixedStrategyNestingEngine` "Default"/"Strip"/"Vertical Remnant"/"Horizontal Remnant`, +or anything reachable through `PlateNesterFactory`/`NestingEngineRegistry`). +`Solve()` must never call, instantiate, or otherwise delegate a placement decision +to one of those. + +## Allowed building blocks + +Low-level geometry/data-structure primitives are fair game — they are not nesting +strategies: + +- `OpenNest.Core` geometry: `Polygon`, `Shape`, `BoundingBox`, `Vector`, `Box`, + `ConvexHull`, `ConvexDecomposition`, `RotatingCalipers`, `Collision` (overlap/spacing + checks), `NoFitPolygon`, `ShapeProfile`, `SpatialQuery`. +- `OpenNest.Engine` support types if useful: `PartBoundary`, `RotationAnalysis`, + `AngleCandidateBuilder` — the *decision logic* using them must be your own (don't just + call `BestFitFinder`/`PairEvaluator`/`RotationSlideStrategy`, which are the existing + best-fit engine's internals). + +## What to fill in + +`Sonnet5NestingEngine.cs` — implement `Solve()`. Pick and document an actual +placement strategy (NFP-based sliding placement, skyline/shelf packer, +simulated-annealing/genetic layout search, guillotine-cut packer, +physics/gravity-settling, etc). It's fine to be simpler or worse than the built-in +engines to start; it must not be the same algorithm re-derived through indirection. + +## Build + +```bash +dotnet build OpenNest.Engine.Sonnet5/OpenNest.Engine.Sonnet5.csproj +``` + +This project is intentionally **outside** `OpenNest.sln` (same pattern as the +`OpenNest.Engine.Aurora` plugin) — it's discovered at runtime as a plugin, not built +as part of the main solution. + +## Try it out with the benchmark + +`OpenNest.Benchmark` auto-loads plugin engines from an `Engines/` folder next to its +own build output: + +```bash +dotnet build OpenNest.Engine.Sonnet5/OpenNest.Engine.Sonnet5.csproj -c Release +dotnet build OpenNest.Benchmark/OpenNest.Benchmark.csproj -c Release + +mkdir -p OpenNest.Benchmark/bin/Release/net8.0/Engines +cp OpenNest.Engine.Sonnet5/bin/Release/net8.0/OpenNest.Engine.Sonnet5.dll OpenNest.Benchmark/bin/Release/net8.0/Engines/ + +dotnet OpenNest.Benchmark/bin/Release/net8.0/OpenNest.Benchmark.dll +``` + +Your engine will show up in the report under its CLR type name (`Sonnet5NestingEngine`), +competing on equal footing against the built-in engines. diff --git a/OpenNest.Engine.Sonnet5/Sonnet5NestingEngine.cs b/OpenNest.Engine.Sonnet5/Sonnet5NestingEngine.cs new file mode 100644 index 0000000..c0958be --- /dev/null +++ b/OpenNest.Engine.Sonnet5/Sonnet5NestingEngine.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading; +using OpenNest.Engine.Jobs; + +namespace OpenNest.Engine.Sonnet5; + +/// +/// TODO: name and describe the actual placement strategy here (e.g. "skyline packer with +/// greedy shelf assignment", "NFP-based sliding placement with simulated-annealing order +/// search", etc). This must be an independently designed algorithm — see README.md. +/// +public sealed class Sonnet5NestingEngine : INestingEngine +{ + public NestJobResult Solve( + NestJob job, + IProgress? progress = null, + CancellationToken token = default + ) + { + ArgumentNullException.ThrowIfNull(job); + + // TODO: implement independent placement logic here. + // + // Do NOT call NestingEngineRegistry.Create(...), PlateNesterFactory, or any + // FixedStrategyNestingEngine / StockLadderNestingEngine instance from inside this + // method. Decide placements yourself using OpenNest.Core / OpenNest.Geometry + // primitives (Polygon, NoFitPolygon, Collision, ConvexHull, RotatingCalipers, etc). + // + // job.Parts -> requested parts (PartGeometrySnapshot geometry, quantity, priority, rotation policy) + // job.Plates -> candidate stock sheets (size, spacing, quadrant, quantity) + // job.Options -> job-wide options + // + // Return a NestJobResult built from NestJobPlateResult (one per used sheet, holding + // ordered NestJobPlacement values), PartFulfillment (requested vs placed per part id), + // and StockUsage (sheets used per stock id). + + throw new NotImplementedException( + "Sonnet5 nesting engine placement logic not yet implemented." + ); + } +} diff --git a/OpenNest.Engine.Sonnet5/tests/OpenNest.Engine.Sonnet5.Tests.csproj b/OpenNest.Engine.Sonnet5/tests/OpenNest.Engine.Sonnet5.Tests.csproj new file mode 100644 index 0000000..ee0d1ae --- /dev/null +++ b/OpenNest.Engine.Sonnet5/tests/OpenNest.Engine.Sonnet5.Tests.csproj @@ -0,0 +1,19 @@ + + + net8.0 + enable + enable + false + true + + + + + + + + + + + + diff --git a/OpenNest.Engine.Sonnet5/tests/Sonnet5NestingEngineTests.cs b/OpenNest.Engine.Sonnet5/tests/Sonnet5NestingEngineTests.cs new file mode 100644 index 0000000..158af80 --- /dev/null +++ b/OpenNest.Engine.Sonnet5/tests/Sonnet5NestingEngineTests.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using OpenNest.Engine.Jobs; +using OpenNest.Geometry; + +namespace OpenNest.Engine.Sonnet5.Tests; + +public class Sonnet5NestingEngineTests +{ + [Fact] + public void SolveReturnsAResultForASingleSimplePart() + { + // TODO: replace with a real fixture once Solve() is implemented — this only + // proves the plumbing (project reference, constructor, interface) is wired up. + var engine = new Sonnet5NestingEngine(); + + Assert.NotNull(engine); + Assert.IsAssignableFrom(engine); + } +} diff --git a/OpenNest.Engine.Terra/OpenNest.Engine.Terra.csproj b/OpenNest.Engine.Terra/OpenNest.Engine.Terra.csproj new file mode 100644 index 0000000..0f958a2 --- /dev/null +++ b/OpenNest.Engine.Terra/OpenNest.Engine.Terra.csproj @@ -0,0 +1,13 @@ + + + net8.0 + OpenNest.Engine.Terra + OpenNest.Engine.Terra + enable + enable + + + + + + diff --git a/OpenNest.Engine.Terra/README.md b/OpenNest.Engine.Terra/README.md new file mode 100644 index 0000000..b8551ab --- /dev/null +++ b/OpenNest.Engine.Terra/README.md @@ -0,0 +1,57 @@ +# OpenNest.Engine.Terra + +An independent `INestingEngine` implementation — **not** a wrapper, ensemble, or +selector over OpenNest's built-in engines (`StockLadderNestingEngine`, +`FixedStrategyNestingEngine` "Default"/"Strip"/"Vertical Remnant"/"Horizontal Remnant`, +or anything reachable through `PlateNesterFactory`/`NestingEngineRegistry`). +`Solve()` must never call, instantiate, or otherwise delegate a placement decision +to one of those. + +## Allowed building blocks + +Low-level geometry/data-structure primitives are fair game — they are not nesting +strategies: + +- `OpenNest.Core` geometry: `Polygon`, `Shape`, `BoundingBox`, `Vector`, `Box`, + `ConvexHull`, `ConvexDecomposition`, `RotatingCalipers`, `Collision` (overlap/spacing + checks), `NoFitPolygon`, `ShapeProfile`, `SpatialQuery`. +- `OpenNest.Engine` support types if useful: `PartBoundary`, `RotationAnalysis`, + `AngleCandidateBuilder` — the *decision logic* using them must be your own (don't just + call `BestFitFinder`/`PairEvaluator`/`RotationSlideStrategy`, which are the existing + best-fit engine's internals). + +## What to fill in + +`TerraNestingEngine.cs` — implement `Solve()`. Pick and document an actual +placement strategy (NFP-based sliding placement, skyline/shelf packer, +simulated-annealing/genetic layout search, guillotine-cut packer, +physics/gravity-settling, etc). It's fine to be simpler or worse than the built-in +engines to start; it must not be the same algorithm re-derived through indirection. + +## Build + +```bash +dotnet build OpenNest.Engine.Terra/OpenNest.Engine.Terra.csproj +``` + +This project is intentionally **outside** `OpenNest.sln` (same pattern as the +`OpenNest.Engine.Aurora` plugin) — it's discovered at runtime as a plugin, not built +as part of the main solution. + +## Try it out with the benchmark + +`OpenNest.Benchmark` auto-loads plugin engines from an `Engines/` folder next to its +own build output: + +```bash +dotnet build OpenNest.Engine.Terra/OpenNest.Engine.Terra.csproj -c Release +dotnet build OpenNest.Benchmark/OpenNest.Benchmark.csproj -c Release + +mkdir -p OpenNest.Benchmark/bin/Release/net8.0/Engines +cp OpenNest.Engine.Terra/bin/Release/net8.0/OpenNest.Engine.Terra.dll OpenNest.Benchmark/bin/Release/net8.0/Engines/ + +dotnet OpenNest.Benchmark/bin/Release/net8.0/OpenNest.Benchmark.dll +``` + +Your engine will show up in the report under its CLR type name (`TerraNestingEngine`), +competing on equal footing against the built-in engines. diff --git a/OpenNest.Engine.Terra/TerraNestingEngine.cs b/OpenNest.Engine.Terra/TerraNestingEngine.cs new file mode 100644 index 0000000..897f3e1 --- /dev/null +++ b/OpenNest.Engine.Terra/TerraNestingEngine.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading; +using OpenNest.Engine.Jobs; + +namespace OpenNest.Engine.Terra; + +/// +/// TODO: name and describe the actual placement strategy here (e.g. "skyline packer with +/// greedy shelf assignment", "NFP-based sliding placement with simulated-annealing order +/// search", etc). This must be an independently designed algorithm — see README.md. +/// +public sealed class TerraNestingEngine : INestingEngine +{ + public NestJobResult Solve( + NestJob job, + IProgress? progress = null, + CancellationToken token = default + ) + { + ArgumentNullException.ThrowIfNull(job); + + // TODO: implement independent placement logic here. + // + // Do NOT call NestingEngineRegistry.Create(...), PlateNesterFactory, or any + // FixedStrategyNestingEngine / StockLadderNestingEngine instance from inside this + // method. Decide placements yourself using OpenNest.Core / OpenNest.Geometry + // primitives (Polygon, NoFitPolygon, Collision, ConvexHull, RotatingCalipers, etc). + // + // job.Parts -> requested parts (PartGeometrySnapshot geometry, quantity, priority, rotation policy) + // job.Plates -> candidate stock sheets (size, spacing, quadrant, quantity) + // job.Options -> job-wide options + // + // Return a NestJobResult built from NestJobPlateResult (one per used sheet, holding + // ordered NestJobPlacement values), PartFulfillment (requested vs placed per part id), + // and StockUsage (sheets used per stock id). + + throw new NotImplementedException( + "Terra nesting engine placement logic not yet implemented." + ); + } +} diff --git a/OpenNest.Engine.Terra/tests/OpenNest.Engine.Terra.Tests.csproj b/OpenNest.Engine.Terra/tests/OpenNest.Engine.Terra.Tests.csproj new file mode 100644 index 0000000..6f9ab72 --- /dev/null +++ b/OpenNest.Engine.Terra/tests/OpenNest.Engine.Terra.Tests.csproj @@ -0,0 +1,19 @@ + + + net8.0 + enable + enable + false + true + + + + + + + + + + + + diff --git a/OpenNest.Engine.Terra/tests/TerraNestingEngineTests.cs b/OpenNest.Engine.Terra/tests/TerraNestingEngineTests.cs new file mode 100644 index 0000000..c917b9d --- /dev/null +++ b/OpenNest.Engine.Terra/tests/TerraNestingEngineTests.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using OpenNest.Engine.Jobs; +using OpenNest.Geometry; + +namespace OpenNest.Engine.Terra.Tests; + +public class TerraNestingEngineTests +{ + [Fact] + public void SolveReturnsAResultForASingleSimplePart() + { + // TODO: replace with a real fixture once Solve() is implemented — this only + // proves the plumbing (project reference, constructor, interface) is wired up. + var engine = new TerraNestingEngine(); + + Assert.NotNull(engine); + Assert.IsAssignableFrom(engine); + } +}