refactor(engines): move plugin engines into an Engines/ subfolder
Plugin engines (Opus55, Qwen, Terra) each add two projects at the repo root, and more are coming; at a dozen they would outnumber the core projects. They are also a different kind of thing: out-of-solution, runtime-loaded plugins. Grouping them under Engines/ keeps the root readable. Engines/Directory.Build.props now holds the shared TFM, nullable and implicit-usings settings and the OpenNest.Engine reference, so a new engine's csproj is nearly empty. The tests/ compile exclusion lives in Directory.Build.targets because a removal in .props runs before the SDK adds its default Compile glob and has no effect. Build-Engines.ps1 replaces the per-README manual build-and-copy steps for deploying engines into the benchmark's runtime Engines/ folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Shared settings and the OpenNest.Engine reference come from Engines/Directory.Build.props. -->
|
||||
</Project>
|
||||
@@ -0,0 +1,59 @@
|
||||
# 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 Engines/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 Engines/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 Engines/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 <path-to-.nest-or-folder>
|
||||
```
|
||||
|
||||
Or build and deploy in one step with `./Engines/Build-Engines.ps1 -Engines Terra`.
|
||||
|
||||
Your engine will show up in the report under its CLR type name (`TerraNestingEngine`),
|
||||
competing on equal footing against the built-in engines.
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using OpenNest.Engine.Jobs;
|
||||
|
||||
namespace OpenNest.Engine.Terra;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public sealed class TerraNestingEngine : INestingEngine
|
||||
{
|
||||
public NestJobResult Solve(
|
||||
NestJob job,
|
||||
IProgress<NestJobProgress>? 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."
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.5.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="../OpenNest.Engine.Terra.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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<INestingEngine>(engine);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user