Commit Graph
31 Commits
Author SHA1 Message Date
ajandClaude Opus 5.5 36c8de825e fix(engine): route restricted-rotation Strip plates to the ordered nester
StripPlateNester sent every request to the strip fills, which try two
classification angles and ignore rotation bounds. With a fixed or bounded
rotation at quantity above one they proposed forbidden poses, the job
validator threw "Candidate rotation is not allowed for the requirement."
and the whole Strip job failed. Strip now uses the same guard as
DefaultPlateNester and hands such plates to OrderedPlateNester.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:13:39 -04:00
ajandClaude Opus 5.5 7ce5e73a82 refactor: share duplicated paging, HTTP and helper code
Roslyn duplicate scans found the same code copied across layers:
- Data: the three browse sessions share BrowseSession<TPage, TSort>;
  the remote clients share NestServerHttp (JSON options, If-Match,
  error text).
- WinForms: five paged lists share BrowsePager for loading text,
  navigation, sort glyphs and failure messages. The Add Drawings to
  Release, Drawing Library and set browser dialogs now dispose their
  browse sessions.
- Server: NestQueryRequest reuses DrawingLibraryRequest's helpers;
  revision history queries share count and paging binds.
- Engine: RemnantPlateNester delegates to DefaultPlateNester;
  CuttingPlanService reuses JointCuttingPlanSearch.Map.
- Core: LineArc and CleanHole lead-ins share LineArcApproach with
  unchanged arithmetic order, so output is bit-identical.
- IO: Dxf.GetGeometry overloads share one reader; .nest JSON test
  helpers move to NestArchiveJson.

Also fixes the production compiler warnings (CS8632, CS8603, CS0108)
and moves a test off an obsolete forwarding API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 08:45:36 -04:00
ajandClaude Opus 5.5 9f2e3d5291 feat(engine): compare clamp-hit dropping with filling past the clamp strip
Dropping the parts that land on a clamp suits small parts, which fill the
gaps between clamps. Large parts often do better if the fill area stops
short of the clamps. The rows still fit, and no part is lost on a clamp.

When every clamp in the fill area lies on one edge, interactive Fill now
also fills the area with that edge moved just past the clamp keep-outs,
as a larger edge spacing would. It keeps whichever layout the strategy's
comparer ranks better, and a tie keeps the dropped-parts layout. Clamps
on more than one edge skip the comparison. The second fill reuses the
cached best-fit pairs. While it runs, a preview counts as the new best
only when it beats the first layout, so the preview never gets worse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:49:48 -04:00
ajandClaude Opus 5.5 05aac952ba feat(engine): fill clamped plates ignoring clamps, then drop clamp hits
Interactive Fill on a plate with clamps used to split the plate into
clamp-free rectangles and fill each one separately. It showed no progress,
so Accept did nothing until the end, and Stop discarded the result. Packing
around the clamps also tends to give a worse layout than losing the few
parts that land on them.

FillItem and FillGroup now fill the area as if there were no clamps. They
then drop each part that enters a clamp keep-out or sits too close to an
existing part, using the same check as before. For a multi-part group, the
whole copy is dropped when any member fails. Progress previews are filtered
by the same check, so a layout accepted early is clamp-clear. A quantity
request that loses copies asks for that many more, up to two more times.
Pack and whole-plate Nest still pack only into the clamp-free areas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:49:48 -04:00
ajandClaude Opus 5.5 859d10b31d feat(engine): offer a box layout before best-fit pairs in Fill
Interactive Fill ran the best-fit pair phase first. The first pair
computation for a drawing can take about a minute, and until it finished
the progress dialog showed no layout, Accept stayed disabled and the
status text did not change.

The fill now packs the part boxes (RectBestFit) before the pair phase and
reports that layout, so Accept is available at once. The layout is only a
fallback: strategies still run in their usual order, and a completed fill
picks the same winner as before. While the pairs are computed, the detail
line reads "Computing best-fit pairs (may take a minute)...". Accept or
Stop now stops the wait. The computation keeps running in the background
and is cached for the next fill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:49:48 -04:00
aj 104b0aef99 fix(clamps): retain complete groups ahead of partial fill tails 2026-10-13 18:15:49 -04:00
aj 74544c689a fix(clamps): preserve interactive clearance and group integrity 2026-10-13 18:15:49 -04:00
aj 3e58a9e93f feat(engine): respect clamp zones in interactive placement and diagnostics 2026-10-13 18:15:49 -04:00
aj 0a1d021bf7 refactor(engine): rename the Default engine and fill strategy to Fill
The multi-phase lattice fill (linear, pairs, rectangle best-fit, remainder) is
no longer meant to be the engine used by default, so it gets a name for what
it does. The registry lists it as Fill and maps the old name Default to it;
PlateFillService, PlateNesterFactory and NestJobOptions use Fill, and every
fill-strategy caller still accepts Default. Console --autonest now validates
engine names through NestingEngineRegistry.ResolveName so renamed names work.

Layouts are unchanged: Default and Fill resolve to the same fillers and the
golden layouts pass under the new name.
2026-10-06 12:11:03 -04:00
aj 32db086384 perf(irregular): cap surplus rows in private stripe fills 2026-10-05 09:03:49 -04:00
aj 418f75916b refactor(engine): share the private-plate Fill run between blocks and future callers
Move BlockCatalog's private-drawing Fill invocation (BestFitCache stabilization plus
the Default FillItem call) into PrivatePlateFill so the cutout fill can reuse it
without duplicating the cache handling. Behavior unchanged; Irregular filter 96/96.
2026-10-04 19:40:49 -04:00
aj 6b6928213d fix(packing): apply work-area slack only at plate boundaries 2026-10-01 08:15:57 -04:00
aj 2e700df8ed feat(fill): pack leftover parts with maximal rectangles
DefaultPlateFiller.PackArea (Default, Strip and both Remnant strategies)
now packs leftover parts with the shared maximal-rectangles packer instead
of bottom-left corner points. Every fit rule and pick mode is tried; the
layout placing the most parts, then box area, per priority tier wins, and
the strategy's own fill comparer breaks ties so remnant strategies keep
their clear side. PackBottomLeft and PackEngine are removed.

Rectangle-lane benchmark (91 strict + 77 boxable jobs) against the old
packer: no strategy lost a valid layout; Default, Vertical Remnant,
Horizontal Remnant and Strip complete 2-3 more strict jobs, and Strip
gains a valid one. Cost on jobs complete in both runs falls for every
strategy (Default -0.6% strict, -2.7% boxable). Default is about 7-10%
slower on the changed jobs.

Golden layouts for Default and both Remnant strategies are re-captured;
each is complete, passes NestLayoutCheck and repeats exactly.
2026-09-30 22:19:25 -04:00
aj c55e375cf3 refactor(engine): remove legacy multi-plate auto-nest orchestration
Desktop Auto Nest, Console --autonest, MCP autonest_plate and the API
NestRunner all run through NestPipeline, so nothing calls the old
orchestration any more.

Delete MultiPlateNester (with MultiPlateNestOptions, MultiPlateResult,
PlateResult, PartClass and PartSortOrder), PlateOptimizer and
PlateOptimizerResult, plus their tests. The explicit-strategy contract
those tests checked now lives at PlateFillService.ResolveStrategy, which
keeps its null-means-Default, canonical-name and unknown-name tests.
CreateFiller loses its internal visibility, which only the deleted
orchestrators used.

This breaks source and binary compatibility for external callers of the
removed types; whole-job callers use NestPipeline.Run or INestingEngine.
2026-09-30 21:07:32 -04:00
aj 8e4735d25d [verified] add benchmark baseline and rotation fixes 2026-09-22 16:35:25 -04:00
aj e65f849c7a refactor(engine): remove legacy nesting engine surface 2026-09-22 14:25:46 -04:00
aj 56f39556d1 feat(engine): rebind live fill previews to the drawing's original frame
DefaultPlateFiller runs its search in a canonical (MBR-axis-aligned)
copy of the drawing. Intermediate progress reports — the Nesting
Progress dialog, PlateView's active-parts overlay — were showing that
transient canonical orientation instead of the drawing's real one.

FillContext.OriginalDrawing carries the pre-canonicalization drawing
through the pipeline; ReportProgress rebinds reported parts to it via
CanonicalFrame.RebindToOriginal before they reach the UI. Uses a
shallow list copy rather than per-part Part.Clone() — Clone() re-derives
its target rotation from BaseDrawing.Program.Rotation + Rotation, which
would double-count the canonical drawing's baked source angle.
2026-09-22 09:51:11 -04:00
aj 88966d118c refactor(engine): route console and MCP nesting through named job engines
Console --engine now names a jobs engine for --autonest (solved once
through NestingEngineRegistry.Create and committed onto the plate) or a
built-in fill strategy for single-plate fill through the public
PlateFillService; unknown names exit with the valid choices instead of
consulting the process-global legacy registry. MCP nesting tools take an
explicit engine argument per call with the session default, never read
process-global active-engine state, and reject whole-job engine names on
single-plate fill tools. NestingEngineRegistry gains an explicit Create
(name) resolution; PlateFillService gains a public ResolveStrategy and a
plate-number Nest overload used by interactive callers.
2026-09-22 00:30:03 -04:00
aj f36e124039 refactor(engine): thread explicit placement strategy through multi-plate orchestrators 2026-09-21 20:22:45 -04:00
aj 856dbfd8af refactor(engine): add public plate fill service 2026-09-21 19:51:35 -04:00
aj eb8fbec1aa refactor(engine): make jobs plate nesters filler-backed 2026-09-21 18:08:25 -04:00
aj 073ead9b79 refactor(engine): share jobs placement identity and progress mechanics 2026-09-21 16:36:24 -04:00
aj ed908b9706 refactor(engine): extract strip plate filler 2026-09-21 15:40:13 -04:00
aj e69ec07830 refactor(engine): extract default and remnant plate fillers 2026-09-21 15:27:03 -04:00
aj eafa0fab01 refactor(engine): extract plate fill orchestration 2026-09-21 15:01:00 -04:00
aj 9b9e510510 refactor(engine): extract progress reporting seam 2026-09-21 14:43:46 -04:00
aj 451841401a refactor(engine): align namespaces with directory layout under OpenNest.Engine
All 132 OpenNest.Engine source files now declare namespaces matching
their nested directories: Jobs/, Jobs/Placement/, Jobs/Adapters/,
Fill/, RectanglePacking/, CirclePacking/, and engine-root types moved
from 'OpenNest' to 'OpenNest.Engine'. RootNamespace updated accordingly.
Consumers (Api, Console, Mcp, Benchmark, Training, desktop app, tests)
gained the explicit usings the move requires; CLAUDE.md updated.
2026-09-21 13:18:34 -04:00
ajandClaude Sonnet 5 64d38c452c fix(engine): route restricted-rotation requirements to OrderedPlateNester
The legacy engine reads RotationStart == RotationEnd == 0 as
unconstrained and its Pairs/RectBestFit strategies rotate freely, so it
returned poses a Fixed/BoundedSweep RotationPolicy forbids and the job
validator threw. DefaultPlateNester now delegates such requests to the
policy-aware OrderedPlateNester.

Fixes RunAsync_FiniteStockExhaustion_PreservesUnplacedRequirementAndLockedRotation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 11:07:45 -04:00
aj aec0523062 style: apply CSharpier formatting to all C# sources
Repo-wide sweep with the pinned CSharpier 1.3.0 tool. Whitespace and
line-wrapping only; OpenNest.Engine.Tests (109) and OpenNest.IO.Tests
pass after reformat, full solution builds 0 errors.

Added .csharpierignore so csproj/config XML keeps its existing layout
(CSharpier's XML wrapping churns attributes with zero benefit).

Formatting is now enforceable: dotnet csharpier check . passes.
2026-09-20 16:41:50 -04:00
aj ea4bd836cd Add tested caller-stock StockLadder baseline with strict geometry validation 2026-09-19 11:24:36 -04:00
aj 02141f6ca5 refactor(engine): separate plate placement from job allocation 2026-09-18 08:38:23 -04:00