Commit Graph

401 Commits

Author SHA1 Message Date
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
289a2044a6 fix(ui): mark LayoutParts dirty after PushSelected so paths rebuild
Moving BasePart locations via Compactor.Push bypassed LayoutPart.Offset
which sets IsDirty. Without it, graphics paths were stale until a zoom
triggered a full rebuild.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 14:20:18 -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
4525be302c fix(engine): compute remainder from just-placed parts within current work area
ComputeRemainderStrip used the bounding box of ALL plate parts against
the full plate, missing large interior gaps between drawing groups.
Now computes remainder within the current work area based on only the
parts that were just placed. This lets subsequent drawings fill the
gap between previous drawing groups instead of being forced into a
tiny strip at the plate edge.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 13:43:33 -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
56592f909a feat(mcp): use FillExact + Compactor in autonest_plate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:43:41 -04:00
521ada17cc feat(console): use FillExact + Compactor in --autonest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:43:38 -04:00
2bde2545f4 feat(ui): use FillExact + Compactor in AutoNest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 12:43:32 -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
cab603c50d docs: fix spec issues from review — non-sequential stepper, font caching, sizing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 01:54:07 -04:00
40d99b402f docs: add NestProgressForm redesign spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 01:51:20 -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
8e0c082876 refactor(ui): optimize PushSelected with directional filtering and lazy line computation
Extract direction helpers to Helper class (EdgeDistance, DirectionalGap,
DirectionToOffset, IsHorizontalDirection) and use them to skip parts not
ahead in the push direction or further than the current best distance.
Defer line computation until parts survive bounding box checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 01:30:50 -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
eddcc7602d feat(console): refactor Program.cs and add DXF file import support
Refactor flat top-level statements into NestConsole class with Options
and focused methods. Add support for passing .dxf files directly as
input — auto-imports geometry via DxfImporter and creates a fresh nest
with a plate when --size is specified. Supports three modes: nest-only,
DXF-only (requires --size), and mixed nest+DXF.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 21:50:01 -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
2a58a8e123 feat(ui): add description row to nest progress form
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:26:47 -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
a145fd3c60 feat(training): add AngleResults table migration and batch insert
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:24:40 -04:00
dddd81fd90 feat(training): add TrainingAngleResult entity and DbSet
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 20:23:38 -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
954831664a docs: add ML angle pruning design spec
Design for training an XGBoost model to predict which rotation
angles are worth trying during FillLinear, reducing the 36-angle
sweep to 4-8 predicted angles in narrow-work-area cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 20:05:03 -04:00
acc75868c0 refactor: extract training data collection into OpenNest.Training
Move brute-force data collection, TrainingDatabase, and GPU init from
OpenNest.Console into a dedicated OpenNest.Training project. Replaces
raw Microsoft.Data.Sqlite with EF Core. Console is now a pure nesting
CLI with template support and cleaned-up usage output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:41: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
bf104309b4 chore: ignore SQLite database files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 13:15:00 -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
1db51b1cce feat(ui): add elapsed timer to nest progress form
Show a live elapsed-time counter that updates every second during
nesting. Rename "Remnant" label to "Unused" for clarity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:41:14 -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
65ded42120 feat(core): add Program.ToString() and fix sub-program rotation origin
Add G-code serialization via ToString() for debugging/ML workflows.
Fix Rotate(angle, origin) to propagate origin to sub-programs instead
of calling the single-argument overload.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:40:57 -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
3133228fc9 feat(console): use GPU for best-fit when available
Wire up GpuEvaluatorFactory in the Console app the same way the GUI app
does, so BestFitCache uses GPU-accelerated slide computation when a
CUDA/OpenCL device is detected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 23:40:14 -04:00