The sequencer returns parts ordered from exit point inward. Reverse
so part 1 is nearest the origin and cutting works outward.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Advanced sequencer with default 0.25 MinDistanceBetweenRowsColumns
puts every part in its own row, degenerating to a Y-sort. Switch to
LeastCode (nearest-neighbor + 2-opt) for visible results.
Also replace AddRange(linq) with foreach+Add to avoid ObservableList
AddRange re-enumerating a deferred LINQ query for event firing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace old SequenceByNearest with PartSequencerFactory using default
SequenceParameters (Advanced method with serpentine row grouping).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Visual Studio re-serialized the designer — removes `this.` prefixes,
modernizes event handler syntax, trims trailing whitespace in resx.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
When Strip is selected in the engine dropdown, RunAutoNest_Click
calls StripNestEngine.Nest() instead of sequential FillExact+Pack.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Replace single scrollable grid with fixed 5x2 pages (10 items per page).
Add prev/next buttons and page label. Support Left/Right and PageUp/
PageDown keyboard navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>
Cache offset polygon geometry on LayoutPart so DrawOffset no longer
recomputes the expensive offset pipeline every paint cycle. The costly
OffsetEntity/ToPolygonWithTolerance/RemoveSelfIntersections chain now
runs only when rotation, spacing, or tolerance actually changes.
Also update temporary parts in UpdateMatrix() so preview parts during
nesting scale correctly with zoom.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Avoids visual confusion with reserved UI colors (orange preview parts,
green/blue selection windows) by using a fixed 12-color palette that
skips those hue zones. Removes unused HSLColor and RandomColorGenerator.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Moves async fill+progress orchestration into PlateView so ActionClone's
Ctrl+F fill shows the NestProgressForm dialog.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shape.OffsetEntity computed joins between consecutive offset segments
but never joined the last segment back to the first, leaving the
closing corner with a straight line instead of a proper miter/arc.
Track the first entity and apply the same join logic after the loop.
Also wrap nest template loading in try-catch so a corrupt template
file doesn't crash the app on startup — falls back to default nest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace engine.Pack(items) with individual engine.Fill(item) calls so each
drawing is filled independently. Quantity decrements now count parts actually
placed per plate (grouped by drawing) instead of relying on the drawing's
internal remaining counter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
"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>
- 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>
Implement geometry-aware nesting using No-Fit Polygons and simulated
annealing optimization. Parts interlock based on true shape rather than
bounding boxes, producing tighter layouts for mixed-part scenarios.
New types in Core/Geometry:
- ConvexDecomposition: ear-clipping triangulation for concave polygons
- NoFitPolygon: Minkowski sum via convex decomposition + Clipper2 union
- InnerFitPolygon: feasible region computation for plate placement
New types in Engine:
- NfpCache: caches NFPs keyed by (drawingId, rotation) pairs
- BottomLeftFill: places parts using feasible regions from IFP - NFP union
- INestOptimizer: abstraction for future GA/parallel upgrades
- SimulatedAnnealing: optimizes part ordering and rotation
Integration:
- NestEngine.AutoNest(): new public entry point for mixed-part nesting
- MainForm.RunAutoNest_Click: uses AutoNest instead of Pack
- NestingTools.autonest_plate: new MCP tool for Claude Code integration
- Drawing.Id: auto-incrementing identifier for NFP cache keys
- Clipper2 NuGet added to OpenNest.Core for polygon boolean operations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The GPU pair evaluator reported false-positive overlaps for all
candidates because the bitmap coordinate system didn't account for
Part.CreateAtOrigin's Location offset. When rotation produced negative
coordinates, CreateAtOrigin sets Location = -bbox.Location (non-zero),
but the offset formula assumed Location was always (0,0).
Two fixes:
- Rasterize bitmaps from Part.CreateAtOrigin directly (new FromPart
method) instead of separately rotating polygons and computing bbox,
eliminating any Polygon.Rotate vs Program.Rotate mismatch
- Correct offset formula to include the Location shift:
(Part2Offset - partB.Location) instead of raw Part2Offset
Also optimized post-kernel bounding computation: pre-compute vertices
once per rotation group and process results with Parallel.For, matching
the CPU evaluator's concurrency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add bounding box rejection in HasOverlaps to skip expensive
Part.Intersects (CNC→geometry conversion) for non-adjacent parts.
Eliminates ~35% CPU in IsBetterValidFill for grid layouts.
- Optimize RayEdgeDistance: access Line fields directly instead of
property getters (avoids Vector struct copies), inline IsEqualTo
with direct range comparison (avoids Math.Abs), and precompute
deltas for reuse in interpolation.
- Cache line endpoints in DirectionalDistance outer loop to avoid
repeated struct copies in the inner loop.
- Add fill timer to ActionClone.Fill, displayed in PlateView status
bar as "Fill: N parts in M ms".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- F key triggers ZoomToFit; Ctrl+F passes through for ActionClone fill
- Middle-button double-click ZoomToFit skipped when parts are selected
to avoid conflicting with middle-click 90° rotation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded PushChordTolerance constant with a configurable
OffsetTolerance property on PlateView (default 0.001), giving smoother
arc profiles in offset drawing and push-to-part collision detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move DxfImporter, DxfExporter, NestReader, NestWriter, ProgramReader,
and Extensions into a new OpenNest.IO class library. The WinForms project
now references OpenNest.IO instead of ACadSharp directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The GPU bitmap evaluator produces false overlap detections due to
discretization errors at cell boundaries. Use the CPU PairEvaluator
(exact geometric intersection) for now. Also remove the double-counted
spacing dilation from GpuPairEvaluator for when GPU is revisited.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add PushDirection.Right and PushDirection.Up to RotationSlideStrategy so
parts can approach from all four directions. This discovers concave
interlocking arrangements (e.g. L-shaped parts nesting into each other's
cavities) that the original Left/Down-only slides could never reach.
Introduce BestFitCache so best-fit results are computed once at step size
0.25 and shared between the viewer and nesting engine. The GPU evaluator
factory is configured once at startup instead of being wired per call
site, and NestEngine.CreateEvaluator is removed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>