feat(engine): add built-in Rectangles and Irregular nesting engines

Moves the two production plug-in engines into OpenNest.Engine under names
that describe the jobs they suit:

- Rectangles: plain and near-rectangular plates, maximal-rectangles box
  packing (was the RectanglesNestingEngine plug-in)
- Irregular: irregular profiles, no-fit-polygon frontier packing (was the
  Opus55NestingEngine plug-in)

Their tests and the shared engine contract/layout test kit move into
OpenNest.Engine.Tests/NestingEngines.

The registry maps the old plug-in names to the new engines, so saved desktop
selections, scripts and API requests keep working, and a leftover plug-in DLL
under an old name cannot shadow its replacement. Desktop startup passes the
registry's lookup when restoring the saved Auto Nest engine.
This commit is contained in:
aj
2026-09-29 21:18:37 -04:00
parent 1eb509740e
commit b688ce896f
21 changed files with 2399 additions and 12 deletions
@@ -167,6 +167,31 @@ public class EngineSelectionSettingsTests : IDisposable
Assert.Null(message);
}
[Fact]
public void Resolve_RenamedEngineMapsToItsReplacementWithoutRewritingSavedChoice()
{
new EngineSelectionSettings { EngineName = "Opus55NestingEngine" }.Save(_path);
var settings = EngineSelectionSettings.Load(_path);
var resolved = settings.Resolve(new[] { "Default", "Irregular" }, out var message,
name => name == "Opus55NestingEngine" ? "irregular" : null);
Assert.Equal("Irregular", resolved);
Assert.Null(message);
Assert.Equal("Opus55NestingEngine", EngineSelectionSettings.Load(_path).EngineName);
}
[Fact]
public void Resolve_RenameToAnUnselectableEngineStillFallsBackWithMessage()
{
var settings = new EngineSelectionSettings { EngineName = "Opus55NestingEngine" };
var resolved = settings.Resolve(new[] { "Default", "Strip" }, out var message, _ => "Irregular");
Assert.Equal("Default", resolved);
Assert.Equal("Saved Auto Nest engine 'Opus55NestingEngine' is unavailable. Using Default.", message);
}
[Fact]
public void Save_UnwritablePathReportsFailureToCaller()
{