Commit Graph

159 Commits

Author SHA1 Message Date
76a338f3d0 refactor(engine): remove dead import and add spacing comment in PatternTiler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 09:48:14 -04:00
f336af5d65 feat(engine): add PatternTiler for unit cell tiling across plates 2026-03-18 09:43:45 -04:00
3d6be3900e feat(engine): generalize Compactor.Push to support arbitrary angles and BB-only mode
Add Vector-based overloads to SpatialQuery (ray casting, edge distance,
directional gap, perpendicular overlap) and PartGeometry (directional
line filtering) to support pushing parts along any angle, not just
cardinal directions.

Add Compactor.PushBoundingBox for fast coarse positioning using only
bounding box gaps. ActionClone shift+click now uses a two-phase strategy:
BB push first to skip past irregular geometry snags, then geometry push
to settle against actual contours.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 09:41:09 -04:00
6229e5e49d fix(engine): fix FillExtents competition and vertical gap bugs
- FillExtents.Fill reported progress internally which overwrote the UI's
  temporary parts even when a better result (e.g. Pairs with 70 parts)
  won the competition. Added final ReportProgress call in FindBestFill
  and Fill(groupParts) to ensure the UI always shows the actual winner.

- FillExtents vertical copy distance clamp (Math.Max with pairHeight +
  spacing) prevented geometry-aware compaction from ever occurring,
  causing visible gaps between rows. Boundaries are already inflated by
  halfSpacing so the calculated distance is correct; only fall back to
  bounding-box distance on non-positive results.

- PairFiller now sets RemainderPatterns on FillLinear so remainder strips
  get pair-based filling instead of only individual parts (+1 part in
  tight layouts).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 07:59:28 -04:00
ccd230568e feat(engine): integrate FillExtents phase into DefaultNestEngine
Adds FillExtents as a fourth nesting phase in both FindBestFill and
Fill(groupParts, Box), running at bestRotation and bestRotation+90°.
Updates Description to reflect the new phase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:51:51 -04:00
7a19b78d31 feat(engine): implement FillExtents horizontal column repetition
Replace RepeatColumns stub with real implementation: compacts a test column
left against column 1 to derive the copy distance, tiles further columns at
that interval, and clips partial columns to the work area bounds. Adds 4 new
FillExtentsTests covering multi-column fill, rect shapes, non-zero-origin
work areas, and cancellation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:50:16 -04:00
31b293324d feat(engine): implement FillExtents iterative height adjustment
Replace AdjustColumn stub with a convergence loop that distributes the
remaining gap between the topmost part and the work area top edge across
all pairs. TryAdjustPair/TryShiftDirection try shifting part2 up (or down
as fallback) and compact left, rejecting moves that widen the pair.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:48:41 -04:00
7bc9f134f6 feat(engine): add FillExtents scaffold with pair construction and column tiling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:45:55 -04:00
6e30e24957 feat(engine): add NestPhase.Extents enum value 2026-03-18 00:42:48 -04:00
42f2475f3c fix: correct Size width/length axis mapping throughout codebase
The Size fix (d4222db) changed Size.Width to Y axis and Size.Length to
X axis but only updated DrawPlate/LayoutViewGL. BoundingBox, WorkArea,
rotations, DXF export, and engine code still used the old Width=X
convention, causing the fill engine to get a swapped work area (60x120
instead of 120x60) and parts to fill in the wrong direction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 16:20:24 -04:00
493f7f837a fix(engine): sort hull edge angles by longest edge first
Longest edges produce the flattest tiling rows and should be tried
first. Also deduplicates angles before sorting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:49:35 -04:00
c94beb51a4 feat(engine): try interlocking pair patterns in remainder strips
FillLinear now accepts optional RemainderPatterns that are tried in
leftover strips after the main grid fill, improving packing density
when pair patterns fit the narrow residual space.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:49:27 -04:00
c2c723f86f refactor(engine): clean up unused imports after extraction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:41:30 -04:00
5bb637f3e2 refactor(engine): use RemnantFiller in NestEngineBase.Nest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:38:53 -04:00
75cb6b2bac refactor(engine): rewire StripNestEngine to use extracted helpers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:37:59 -04:00
c077649734 refactor(engine): rewire DefaultNestEngine to use extracted helpers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:35:25 -04:00
319eace472 refactor(engine): extract RemnantFiller for iterative remnant filling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:33:00 -04:00
c8587929b5 refactor(engine): extract PairFiller from DefaultNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:31:51 -04:00
14048b0b7c refactor(engine): make BuildRotatedPattern and FillPattern internal static
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:30:37 -04:00
a7f27480e9 refactor(engine): extract AngleCandidateBuilder from DefaultNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:29:52 -04:00
094b1e9f00 refactor(engine): extract ShrinkFiller from StripNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:28:24 -04:00
31dbbbeedc refactor(engine): extract AccumulatingProgress from StripNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:26:53 -04:00
ba7ded14b5 build: add InternalsVisibleTo for OpenNest.Tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:25:46 -04:00
65bde123ed fix(engine): fix remnant finder missing L-shaped and split remnants
Two bugs caused the remnant finder to miss valid empty regions:

1. RemoveDominated used an 80% overlap-area threshold that incorrectly
   removed L-shaped remnants. A tall strip to one side would "dominate"
   wide strips above/below it even though they represent different usable
   space. Replaced with geometric containment check — only remove a box
   if it's fully inside a larger one.

2. FindTieredRemnants split remnants at the obstacle envelope boundary,
   and both pieces could fall below minDimension even though the original
   remnant passed the filter (e.g., 6.6" remnant split into 5.35" + 1.25"
   with minDim=5.38"). Added fallback to keep the original unsplit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:03:23 -04:00
66050c68f6 feat(engine): add CompactIndividual to Compactor (disabled in strip nester)
Add plate-free Push overload and CompactIndividual method that pushes
each part individually against all others as obstacles. Disabled in
StripNestEngine pending investigation — compaction opens irregular gaps
that the remnant finder scatters parts into.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 14:35:07 -04:00
0b9a42e84c fix(engine): use smallest remaining part as minimum remnant size
Skip remnants that are too small to fit any remaining part, avoiding
wasted fill attempts. Recalculated each iteration as quantities deplete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:51:30 -04:00
00ccf82196 fix(engine): apply shrink loop to remnant fills in StripNestEngine
Remainder items were being filled into the full remnant box without
compaction. Added ShrinkFill helper that fills then shrinks the box
horizontally and vertically while maintaining the same part count.
This matches the strip item's shrink behavior and produces tighter
layouts that leave more usable space for subsequent items.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:50:14 -04:00
a41a08c9af fix(engine): use local quantity tracking in StripNestEngine remnant loop
The iterative remnant fill was mutating shared NestItem.Quantity objects,
causing the second TryOrientation call (left) to see depleted quantities
from the first call (bottom). Use a local dictionary instead so both
orientations start with the full quantities.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:23:32 -04:00
3d23943b69 fix(engine): use RemnantFinder for iterative remnant filling in StripNestEngine
Replace the single-pass guillotine split approach with RemnantFinder-based
iteration. After each fill, re-discover all free rectangles and try all
remaining items again until no more progress is made. This fills gaps that
were previously left empty after the initial strip + remainder layout.

Also change ActiveWorkArea border color from orange to red.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 13:11:28 -04:00
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