Commit Graph

130 Commits

Author SHA1 Message Date
6419f6b8a2 feat: report ActiveWorkArea in NestProgress from ReportProgress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:58:17 -04:00
2c62f601ca feat: add ActiveWorkArea property to NestProgress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:55:54 -04:00
2bda7c9f0f refactor: remove StripNestResult.RemnantBox
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:54:19 -04:00
4d30178752 refactor: replace ComputeRemainderWithin with RemnantFinder in Nest()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:51:25 -04:00
2b578fa006 refactor: remove NestPhase.Remainder enum value and switch cases
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:50:48 -04:00
78c625361e refactor: remove remainder phase from DefaultNestEngine
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:50:26 -04:00
dd3a2b0e9a refactor: remove UsableRemnantArea from NestProgress and UI 2026-03-16 12:47:57 -04:00
9b21a0c6d7 fix: update FillWithPairs debug logging after FillScore simplification 2026-03-16 12:47:11 -04:00
5b9e6c28e4 refactor: simplify FillScore to count + density, remove remnant tracking 2026-03-16 12:46:53 -04:00
ecdf571c71 feat: add RemnantFinder with edge projection algorithm 2026-03-16 12:45:35 -04:00
1b62f7af04 docs: revise lead-in UI spec with external/internal split and LayerType tagging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:04:42 -04:00
ff496e4efe fix(engine): track multiple free rectangles in strip remnant filling
ComputeRemainderWithin only returned the larger of two possible free
rectangles, permanently losing usable area on the other axis after each
remainder item was placed. Replace the single shrinking box with a list
of free rectangles using guillotine cuts so both sub-areas remain
available for subsequent items.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 01:28:25 -04:00
7d198f837c feat: add PlateProcessor orchestrator 2026-03-16 00:44:25 -04:00
5948dc9cae feat: add PlateResult and ProcessedPart 2026-03-16 00:43:17 -04:00
6dffd8f5ad feat: add DirectRapidPlanner with line-shape intersection check 2026-03-16 00:43:06 -04:00
29b2572f9a feat: add IRapidPlanner, RapidPath, and SafeHeightRapidPlanner 2026-03-16 00:39:34 -04:00
c1e21abd45 feat: add PartSequencerFactory
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:36:41 -04:00
edc81ae45e feat: add AdvancedSequencer with row grouping and serpentine
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:36:07 -04:00
7edf6ee843 feat: add LeastCodeSequencer with nearest-neighbor and 2-opt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:35:19 -04:00
f568308d1a feat: add EdgeStartSequencer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:32:35 -04:00
d0351ab765 feat: add directional part sequencers (RightSide, LeftSide, BottomSide)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:27:57 -04:00
4f8febde23 feat: add IPartSequencer interface and SequencedPart
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 00:27:02 -04:00
5e346270c6 fix: delegate Fill(groupParts) and PackArea to DefaultNestEngine
StripNestEngine only overrode Fill(NestItem), so ActionClone.Fill
and Pack operations fell through to the empty base class defaults.
Now all virtual methods delegate to DefaultNestEngine.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 22:43:42 -04:00
4e747a8e6c fix: show strip + remnant parts together during progress updates
Wrap IProgress with AccumulatingProgress so remnant fills prepend
previously placed strip parts to each report. The UI now shows the
full picture (red + purple) instead of replacing strip parts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 22:31:11 -04:00
310165db02 fix: add quantity deduction and progress reporting to StripNestEngine
Nest() now deducts placed counts from input NestItem.Quantity so the
UI loop doesn't create extra plates. All inner DefaultNestEngine.Fill
calls forward the IProgress parameter for live progress updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 22:26:29 -04:00
48be4d5d46 feat: add virtual Nest method to NestEngineBase for polymorphic auto-nest
The auto-nest code paths (MainForm, MCP, Console) now call
engine.Nest(items, progress, token) instead of manually orchestrating
sequential fill+pack. The default implementation in NestEngineBase
does sequential FillExact+PackArea. StripNestEngine overrides with
its strip strategy. This makes the engine dropdown actually work.

Also consolidates ComputeRemainderWithin into NestEngineBase,
removing duplicates from MainForm and StripNestEngine.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 22:16:08 -04:00
4d80710b48 feat: register StripNestEngine in NestEngineRegistry
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 21:39:25 -04:00
42d404577b feat: add StripNestEngine with strip-based multi-drawing nesting
New NestEngineBase subclass that dedicates a tight strip to the
largest-area drawing and fills the remnant with remaining drawings.
Tries both bottom and left orientations, uses a shrink loop to find
the tightest strip, and picks the denser result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 21:39:01 -04:00
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