Commit Graph

94 Commits

Author SHA1 Message Date
4baeb57e84 feat: add NestEngineInfo and NestEngineRegistry with plugin loading
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 21:07:59 -04:00
1bcfe5d031 feat: add NestEngineBase abstract class, rename NestEngine to DefaultNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 21:06:28 -04:00
13b01240b1 refactor: extract SpatialQuery from Helper
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:46:14 -04:00
2881815c7a refactor: extract PartGeometry from Helper
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:44:17 -04:00
7c4eac5460 refactor: extract ShapeBuilder from Helper
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:41:40 -04:00
823320e982 fix(engine): use reverse-gap check in Compactor to handle irregular shapes
The forward bounding-box gap check (gap < 0) incorrectly skipped obstacles
for irregular shapes like SULLYS-003 whose narrow handle extends past an
adjacent part's BB edge while the wide body still needs contact detection.
Replaced with a reverse-direction gap check that only skips obstacles the
moving part has entirely cleared. Also fixed edge distance check to prevent
overshooting the work area boundary when already at the limit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:29:29 -04:00
7508fbf715 refactor(engine): delegate PlateView.PushSelected to Compactor and add iterative compaction
PushSelected now calls Compactor.Push instead of duplicating the push
logic. Compactor.Push moves parts as a group (single min distance) to
preserve grid layouts. Compact tries both left-first and down-first
orderings, iterating up to 20 times until movement drops below
threshold, and keeps whichever ordering traveled further.

Also includes a cancellation check in FillWithProgress to avoid
accepting parts after the user stops a nest.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 14:16:35 -04:00
2042c7d3f2 perf(engine): cap strip-mode pair candidates at 100 (sorted by utilization)
Strip mode was adding thousands of candidates (7600+) when the work area
was narrow. Now caps at 100 total, sorted by utilization descending so
the best candidates are tried first.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 13:35:30 -04:00
2af02096e0 fix(engine): pass progress through FillExact binary search iterations
The binary search was passing null for progress, so the NestProgressForm
showed all dashes during the entire search (potentially minutes). Now
each iteration reports progress — the user sees phases, part counts, and
density updating as the search runs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 13:30:39 -04:00
744062152e feat(engine): optimize FillExact with angle pruning and tight search range
- Track productive angles across Fill calls; subsequent fills skip
  angles that never produced results (knownGoodAngles)
- Binary search uses utilization-based range estimates (70%-25%)
  instead of starting from the full work area dimension
- Quick bounding-box capacity check skips binary search entirely
  when the plate can't fit more than the requested quantity
- Use full Fill (not rect-only) for binary search iterations so
  the search benefits from pairs/linear strategies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 13:21:28 -04:00
ef12cf2966 fix(engine): Compactor treats pushed parts as obstacles for subsequent pushes
Previously each moving part only checked against the original stationary
set. Parts pushed earlier in the loop were invisible to later parts,
causing overlaps (utilization > 100%). Now each pushed part is added to
the obstacle set so subsequent parts collide correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:54:25 -04:00
00ee205b44 feat(engine): add Compactor for post-fill gravity compaction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:41:29 -04:00
28fb1a1a67 feat(engine): add FillExact method for exact-quantity nesting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:41:21 -04:00
9a17fe97d3 feat(engine): add BinarySearchFill helper for exact-quantity search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:40:56 -04:00
45509cfd3f feat(ui): add nested dimensions and area to progress window
Show width x length and total part area on the "Nested:" row
in the nesting progress dialog, using the existing GetBoundingBox
extension to compute the extents.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 01:42:34 -04:00
3c59da17c2 fix(engine): fix pair candidate filtering for narrow plates and strips
The BestFitFilter's aspect ratio cap of 5.0 was rejecting valid pair
candidates needed for narrow plates (e.g. 60x6.5, aspect 9.2) and
remainder strips on normal plates. Three fixes:

- BestFitFinder: derive MaxAspectRatio from the plate's own aspect
  ratio so narrow plates don't reject all elongated pairs
- SelectPairCandidates: search the full unfiltered candidate list
  (not just Keep=true) in strip mode, so pairs rejected by aspect
  ratio for the main plate can still be used for narrow remainder
  strips
- BestFitCache.Populate: skip caching empty result lists so stale
  pre-computed data from nest files doesn't prevent recomputation

Also fixes console --size parsing to use LxW format matching
Size.Parse convention, and includes prior engine refactoring
(sequential fill loops, parallel FillPattern, pre-sorted edge
arrays in RotationSlideStrategy).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 01:14:07 -04:00
ae010212ac refactor(engine): extract AutoNester and reorganize NestEngine
Move NFP-based AutoNest logic (polygon extraction, rotation computation,
simulated annealing) into dedicated AutoNester class. Consolidate duplicate
FillWithPairs overloads, extract BuildCandidateAngles and BuildProgressSummary,
reorganize NestEngine into logical sections. Update callers in Console,
MCP tools, and MainForm to use AutoNester.Nest.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 22:51:57 -04:00
ce6b25c12a refactor(engine): simplify FillLinear with iterative grid fill
Replace recursive FillRecursive with flat FillGrid that tiles along primary
axis, then perpendicular. Extract FindPlacedEdge, BuildRemainingStrip,
BuildRotationSet, FindBestFill helpers. Use array-based DirectionalDistance
to eliminate allocations in FindCopyDistance and FindPatternCopyDistance.
Simplify FindSinglePartPatternCopyDistance to delegate to FindCopyDistance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 22:51:50 -04:00
6993d169e4 perf(core): optimize geometry with edge pruning and vertex dedup
Vector implements IEquatable<Vector> with proper GetHashCode for HashSet usage.
Polygon.FindCrossing uses bounding-box pruning to skip non-overlapping edge pairs.
Helper.DirectionalDistance deduplicates vertices via HashSet, sorts edges for
early-exit pruning, and adds a new array-based overload that avoids allocations.
PartBoundary sorts directional edges and exposes GetEdges for zero-alloc access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 22:51:44 -04:00
9783d417bd feat(engine): show running ledger in progress descriptions
Linear phase shows "Linear: 12/36 angles, 45° = 48 parts" with a
running count. Pairs phase shows "Pairs: 8/50 candidates, best = 252
parts" tracking the best result seen so far. Reports on every
completion so the UI always reflects current state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:57:01 -04:00
91281c8813 fix(engine): throttle progress reports to 150ms intervals
Parallel loops were flooding the UI with per-angle/per-candidate reports
faster than WinForms could render them. Use Interlocked timestamp checks
to report at most every 150ms, keeping descriptions readable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:51:29 -04:00
c2f775258d fix(ui): show live per-angle/per-candidate detail during nesting
Don't overwrite the Detail label with phase-level reports — let the
per-angle and per-candidate descriptions from the parallel loops remain
visible. Only clear the label on completion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:48:58 -04:00
930dd59213 fix(ui): set Description in phase-level progress reports
ReportProgress was not setting Description, so the Detail row always
showed the default em-dash. Now each phase report includes a meaningful
description, and UpdateProgress always updates the label (resetting to
em-dash when null).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:40:25 -04:00
9cc6cfa1b1 fix(engine): add volatile to AnglePredictor lock field and Models content copy
- Mark _loadAttempted as volatile for correct double-checked locking
- Add Content item to copy Models/ directory to output for ONNX inference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:33:07 -04:00
e33b5ba063 feat(engine): integrate AnglePredictor into FindBestFill angle selection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:28:50 -04:00
8cc14997af feat(engine): add AnglePredictor ONNX inference class
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:27:44 -04:00
eee2d0e3fe feat(training): add training notebook skeleton and requirements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:27:41 -04:00
c466a24486 chore(engine): add Microsoft.ML.OnnxRuntime package
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:26:26 -04:00
71fc1e61ef feat(training): enable forced full angle sweep and store per-angle results
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:25:33 -04:00
8e46ed1175 feat(engine): pass per-angle results through BruteForceResult
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:22:38 -04:00
09ed9c228f feat(engine): add ForceFullAngleSweep flag and per-angle result collection
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:21:14 -04:00
eb21f76ef4 feat(engine): add AngleResult class and Description to NestProgress 2026-03-14 20:18:38 -04:00
74272bea80 feat(engine): add perimeter-to-area ratio to part features
Adds PerimeterToAreaRatio (perimeter / area) as a spacing sensitivity
indicator for ML feature extraction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:41:30 -04:00
321c476b8b feat(engine): add ML feature extraction and brute-force runner
Add FeatureExtractor for computing geometric part features (convexity,
aspect ratio, circularity, bitmask) and BruteForceRunner for generating
training data by running the fill engine and recording results.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:41:20 -04:00
10f9b5357c fix(engine): compute unused area from actual part areas
Calculate unused plate area by subtracting total part area from the
work area instead of relying on FillScore.UsableRemnantArea, which
could over-report available space.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:41:08 -04:00
a9aaab8337 refactor: use ShapeProfile perimeter for boundary and intersection
Replace shape-list iteration with ShapeProfile.Perimeter in both
Part.Intersects and PartBoundary, simplifying the logic and ensuring
only the outermost contour is used for collision detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:41:03 -04:00
d6ffa77f35 feat(console): improve training data collection and best-fit persistence
- Add verbose per-file and per-sheet-size console output during collection
- Skip already-processed parts at the sheet-size level instead of all-or-nothing
- Precompute best-fits once per part and reuse across all sheet sizes
- Clear best-fit cache after each part to prevent memory growth
- Save best-fits in separate bestfits/ zip entries instead of embedding in nest.json
- Filter to Keep=true results only and scope to plate sizes in the nest
- Set nest name to match filename (includes sheet size and part count)
- Add TrainingDatabase with per-run skip logic and SQLite schema

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:39:24 -04:00
1440d2a16a refactor(engine): reorder phases and simplify fill pipeline
Run pairs phase first to establish a baseline before linear and
rect-best-fit phases. Replace IsBetterFill with direct FillScore
comparison. Simplify FillPattern to sequential iteration, reusing a
single FillLinear engine instance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 21:14:32 -04:00
152e057a46 perf(engine): inline bounding box computation in FillScore
Compute min/max bounds in a single pass alongside part area
accumulation, avoiding the separate GetBoundingBox() call and
redundant iteration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 21:14:28 -04:00
de70999975 refactor(engine): precompute hull angles during pair evaluation
Store hull edge angles in BestFitResult at evaluation time so they
don't need to be recomputed during the fill phase. Extract
GetHullEdgeAngles(Polygon) overload from FindHullEdgeAngles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 21:14:25 -04:00
183d169cc1 feat: integrate GPU slide computation into best-fit pipeline
Thread ISlideComputer through BestFitCache → BestFitFinder →
RotationSlideStrategy. RotationSlideStrategy now collects all offsets
across 4 push directions and dispatches them in a single batch (GPU or
CPU fallback). Also improves rotation angle extraction: uses raw geometry
(line endpoints + arc cardinal extremes) instead of tessellation to avoid
flooding the hull with near-duplicate edge angles, and adds a 5-degree
deduplication threshold.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 20:29:51 -04:00
97dfe27953 feat: add ISlideComputer interface and GPU implementation
ISlideComputer abstracts batched directional-distance computation so GPU
implementations can process all slide offsets in a single kernel launch.
GpuSlideComputer uses ILGPU with prepared edge data (precomputed inverse
deltas and min/max bounds) and caches stationary/moving buffers across
calls. GpuEvaluatorFactory exposes a singleton factory method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 20:29:43 -04:00
6b0bafc9de merge: integrate NFP-based autonesting from feature/nfp-autonest
Brings in the full NFP implementation: ConvexDecomposition, NoFitPolygon,
InnerFitPolygon, NfpCache, BottomLeftFill, SimulatedAnnealing optimizer,
and INestOptimizer interface. Resolves conflicts by keeping master's
progress reporting infrastructure alongside the new AutoNest methods,
and adapting RunAutoNest_Click to use NFP AutoNest with async/cancellation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:40:38 -04:00
ca685ac8ba feat(engine): add public Fill overloads returning List<Part> with progress/cancellation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 08:27:31 -04:00
93fbe1a9f8 feat(engine): add FindBestFill and FillWithPairs overloads with progress and cancellation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 08:26:32 -04:00
a97477fcdf feat(engine): add NestPhase enum and NestProgress data model
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 08:24:55 -04:00
c68139e15e merge: resolve .gitignore conflict, keep both entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 07:22:45 -04:00
612b540d9d refactor: rename Size.Height to Size.Length across codebase
"Length" is more natural than "height" for flat plate materials.
Renames the field on OpenNest.Geometry.Size, Box.Height property,
and all references across 38 files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:01:40 -04:00
a084819889 perf: comment out Debug.WriteLine calls in FillLinear
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:44:14 -04:00
2632b3dbf7 fix: resolve infinite loop in multi-plate autonest and wire into console
- Change while(true) to bounded for-loop (max 100 plates) in MainForm
- Use Drawing.Name comparison instead of reference equality for quantity deduction
- Add Math.Max(0, ...) guard to prevent negative quantities
- Tune SA parameters for faster convergence (cooling=0.995, minTemp=0.1, maxNoImprove=500)
- Add --autonest flag to OpenNest.Console for CLI-based NFP autonesting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 08:29:02 -04:00