Commit Graph

14 Commits

Author SHA1 Message Date
62d9dce0b1 refactor: simplify MultiPlateNester by converting to instance class
- Convert static class to instance with private constructor; shared
  parameters (template, plateOptions, salvageRate, minRemnantSize,
  progress, token) become fields, eliminating parameter threading
  across all private methods (10→3 params on Nest entry point stays
  unchanged; private methods drop from 7-9 params to 1-2)
- Extract FillAndPlace helper consolidating the repeated
  clone→fill→add-to-plate→deduct-quantity pattern (was duplicated
  in 4 call sites)
- Merge FindScrapZones/FindViableRemnants (98% duplicate) into single
  FindRemnants(plate, minRemnantSize, scrapOnly) method
- Extract ScoreZone helper and collapse duplicate normal/rotated
  orientation checks into single conditional
- Extract CreateNewPlateResult helper for repeated PlateResult
  construction + PlateOption lookup pattern

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:08:44 -04:00
1f88453d4c fix: recalculate remnants after each fill to prevent overlaps
The consolidation pass was iterating stale remnant lists after placing
parts, causing overlapping placements. Now recalculates remnants from
the plate after each fill operation. Also added plate options to the
real nest file integration test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:55:48 -04:00
0697bebbc2 fix: defer small parts to consolidation pass for shared plates
Small parts no longer create their own plates during the main pass.
Instead they're deferred to the consolidation pass which fills them
into remaining space on existing plates, packing multiple drawing
types together. Drops from 9 plates to 4 on the test nest file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:47:50 -04:00
f1fd211ba5 fix: small parts use FindScrapZones not FindAllRemnants
Small parts must only go into scrap zones (both dims < minRemnantSize)
to preserve viable remnants. The implementer had inverted this, giving
small parts access to all remnants. Also fixed the test to verify
remnant preservation behavior and removed unused FindAllRemnants helper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:11:10 -04:00
fd3c2462df feat: add MultiPlateNester.Nest orchestration method
Implements the main Nest() method that ties together sorting,
classification, and placement across multiple plates. The method
processes items largest-first, placing medium/small parts into
remnant zones on existing plates before creating new ones. Includes
private helpers: TryPlaceOnExistingPlates, PlaceOnNewPlates,
TryUpgradeOrNewPlate, FindAllRemnants, and CloneItem.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:07:24 -04:00
a4773748a1 feat: add plate creation and upgrade-vs-new evaluation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:56:08 -04:00
af57153269 feat: add scrap zone identification to MultiPlateNester
Adds IsScrapRemnant(), FindScrapZones(), and FindViableRemnants() to
MultiPlateNester. A remnant is scrap only when both dimensions fall
below the minimum remnant size threshold (AND logic, not OR).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:53:32 -04:00
35e89600d0 feat: add part classification (large/medium/small) to MultiPlateNester
Introduces PartClass enum and Classify() static method that categorizes
parts as Large (exceeds half work area in either dimension), Medium
(area > 1/9 work area), or Small.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:52:27 -04:00
89a4e6b981 feat: add MultiPlateNester with sorting logic
Implements static MultiPlateNester.SortItems with BoundingBoxArea and Size sort orders, covered by two passing xUnit tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:48:57 -04:00
250fdefaea refactor: merge DxfImporter and DxfExporter into single static Dxf class
Consolidated two stateless classes into one unified API: Dxf.Import(),
Dxf.GetGeometry(), Dxf.ExportPlate(), Dxf.ExportProgram(). Export
state moved into a private ExportContext. Removed bool+out pattern
from GetGeometry in favor of returning empty list on failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 08:17:49 -04:00
7380a43349 feat: add PlateOptimizer with cost-aware plate size selection
Tries each candidate plate size via the nesting engine, compares results
by part count then net cost (accounting for salvage credit on remnant
material), and returns the best option.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:31:36 -04:00
c5943e22eb fix: correct Width/Length axis mapping and add spiral center-fill
Box constructor and derived properties (Right, Top, Center, Translate, Offset)
had Width and Length swapped — Length is X axis, Width is Y axis. Corrected
across Core geometry, plate bounding box, rectangle packing, fill algorithms,
tests, and UI renderers.

Added FillSpiral with center remnant detection and recursive FillBest on
the gap between the 4 spiral quadrants. RectFill.FillBest now compares
spiral+center vs full best-fit fairly. BestCombination returns a
CombinationResult record instead of out params.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 21:22:55 -04:00
e50a7c82cf test: skip overlap tests gracefully when DXF fixture missing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:34:56 -04:00
3e340e67e0 refactor: organize test project into subdirectories by feature area
Move 43 root-level test files into feature-specific subdirectories
mirroring the main codebase structure: Geometry, Fill, BestFit, CutOffs,
CuttingStrategy, Engine, IO. Update namespaces to match folder paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:46:43 -04:00