Spline import now uses SplineConverter (arc-based) so the configurable
precision parameter is obsolete. Removed the setting from the options
dialog, DxfImporter property, Settings files, and all callsites.
Hardcoded 200 as the sampling density for the intermediate point
evaluation that feeds into SplineConverter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PlateListChanged handler was setting tabControl1.SelectedIndex = 0,
which forced the UI to the plates tab whenever a sentinel plate was
auto-created during part placement, disrupting the workflow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add LightGray separator lines between items to visually distinguish
adjacent quantity bars. Preserve scroll position and selection when
updating the drawing list by saving/restoring TopIndex and SelectedItem.
Use incremental item removal instead of full list rebuild when hiding
depleted drawings. Wrap list modifications in BeginUpdate/EndUpdate to
reduce flicker.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed add and remove plate buttons from the plate header panel.
The plate tab toolbar now has add/remove buttons with the remove
button state driven by PlateManager.CanRemoveCurrent. MainForm's
Plate > Remove menu item also syncs on plate change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without this, RemoveEmptyPlates would destroy the sentinel with no
recovery, and tail-plate subscriptions would go stale after plate list
mutations. Added tests for both scenarios.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
EditNestForm now holds a Document instead of a bare Nest field,
eliminating duplicated LastSavePath, LastSaveDate, and SaveAs logic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all backward-compat wrapper calls on EditNestForm (LoadFirstPlate,
LoadLastPlate, LoadNextPlate, LoadPreviousPlate, IsFirstPlate, IsLastPlate,
EnsureSentinelPlate, CurrentPlateIndex, PlateCount) with direct access to
activeForm.PlateManager. Remove the now-unused wrapper methods and properties
from EditNestForm.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace direct plate collection event handlers, navigation methods, and
sentinel logic in EditNestForm with PlateManager delegation. Navigation
buttons, list selection, export, and plate removal now route through
PlateManager. Backward-compatible delegating wrappers kept for MainForm
until Task 7.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OnPlateAdded now navigates to the new plate when suppressNavigation is
false, matching the original EditNestForm behavior. Fixed CanRemoveCurrent
test to account for this auto-navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- EnsureSentinel() maintains exactly one trailing empty plate, suppressing navigation events during mutation
- Reactive tail subscriptions (PartAdded/PartRemoved on last two plates) call EnsureSentinel automatically; re-subscribed after each plate list change
- BeginBatch()/EndBatch() defers sentinel enforcement during bulk operations
- GetOrCreateEmpty() returns or creates an empty plate; RemoveCurrent() removes the current plate with index clamping; CanRemoveCurrent guards deletion
- 13 new tests (30 total PlateManager tests), all passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drawings created by BomImportForm and MCP InputTools were missing color
assignments, causing them to render with default empty color instead of
the standard part color palette. Moved PartColors and GetNextColor() to
Drawing in Core so all consumers share one definition.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces PlateChangedEventArgs and PlateManager in OpenNest.Core to centralize plate navigation logic (CurrentIndex, LoadFirst/Last/Next/Previous/At, IsFirst/IsLast). Includes full xUnit test coverage (17 tests) verifying navigation, event firing, and disposal unsubscription.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FileListControl loses focus when interacting with other controls on the
form, making arrow key navigation stop working. Intercept Up/Down at
the form level via ProcessCmdKey and forward to the file list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Strategies now promote results to IsOverallBest when they beat the
pipeline best, so the UI updates immediately on improvement rather
than waiting for each phase to complete
- PlateView only updates the main view on overall-best results, fixing
intermediate angle-sweep layouts leaking to the plate display
- Skip Row/Column strategies for rectangle parts (redundant with Linear)
- Intercept Escape key at MainForm level via ProcessCmdKey so it always
reaches the active PlateView regardless of focus state
- Restore keyboard focus to PlateView after fill progress form closes
- Remnant engines use SelectBestFitPair for orientation-aware pair
selection; DefaultNestEngine tries both landscape and portrait pairs
- RemnantFiller preserves more parts during topmost-part removal
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Always keep a trailing empty plate so users can immediately place parts
without manually adding a plate. Auto-appends a new sentinel when parts
land on the last plate; trims excess trailing empties on removal.
Plate list now shows Parts count and Utilization % columns. Empty plates
are filtered from save and export. Sentinel updates are deferred via
BeginInvoke to avoid collection-modified exceptions and debounced to
prevent per-part overhead on bulk operations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a right-click "Delete" option on the drawings tab that removes the
selected drawing and all its placed parts from every plate.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rebuild the dialog from a flat layout into grouped sections: engine
selector at top, Parts group with rotation columns and summary label,
Options group, collapsible Plate Optimizer with single-field size
parsing, and a clean button bar. Adds engine sync between dialog and
toolbar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add LoadPlateOptions() method to AutoNestForm that restores saved plate
options and salvage rate from the Nest. Call this method in
RunAutoNest_Click when opening the dialog if saved options exist, and save
settings back to Nest after dialog completion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add PlateOptions and SalvageRate properties to the Nest class and
round-trip them through NestWriter/NestReader via a new PlateOptionDto.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When "Optimize plate size" is enabled in AutoNestForm, NestSinglePlateAsync
calls PlateOptimizer.Optimize instead of engine.Nest, trying multiple plate
sizes and resizing the plate to the winning option.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tries each candidate plate size via the nesting engine, compares results
by part count then net cost (accounting for salvage credit on remnant
material), and returns the best option.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add colored left-edge bars (green=met, orange=short) to indicate nesting
quantity status. Replace blue selection highlight with a border outline.
Add toolbar toggle to hide fully nested drawings, auto-updating as parts
are placed or removed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enables a "move" workflow: clone parts to a new position, then
press Delete to remove the originals. Previously Delete just
cancelled the clone action.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Strategies and fillers previously called NestEngineBase.ReportProgress
directly, each constructing ProgressReport structs with phase, plate
number, and work area manually. Some strategies (RectBestFit) reported
nothing at all. This made progress updates inconsistent and flakey.
Add FillContext.ReportProgress(parts, description) as the single
standard method for intermediate progress. RunPipeline sets ActivePhase
before each strategy, and the context handles common fields. Lower-level
fillers (PairFiller, FillExtents, StripeFiller) now accept an
Action<List<Part>, string> callback instead of raw IProgress, removing
their coupling to NestEngineBase and ProgressReport.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ActionLeadIn.DisconnectEvents() nulled selectedLayoutPart without first
setting IsSelected = false, leaving the part permanently rendered in the
selection color (transparent blue) after switching actions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BuildOffsets had Width and Length swapped after the Box axis correction
in c5943e2. Horizontal pushes used Length (X) for perpendicular sweep
and Width (Y) for push start — backwards. This caused part2 to start
inside part1's footprint, producing overlapping best-fit pairs.
Added regression test that verifies no kept best-fit pairs overlap.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ObservableList.Remove fired ItemRemoved even when the item wasn't in
the list, causing Plate to decrement Quantity.Nested for clone preview
parts that were never added — producing -1 counts. Delete in PlateView
now cancels ActionClone instead of trying to remove its preview parts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Box constructor and derived properties (Right, Top, Center, Translate, Offset)
had Width and Length swapped — Length is X axis, Width is Y axis. Corrected
across Core geometry, plate bounding box, rectangle packing, fill algorithms,
tests, and UI renderers.
Added FillSpiral with center remnant detection and recursive FillBest on
the gap between the 4 spiral quadrants. RectFill.FillBest now compares
spiral+center vs full best-fit fairly. BestCombination returns a
CombinationResult record instead of out params.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add general-purpose ShowSidePanel/HideSidePanel to EditNestForm
- CuttingPanel uses Dock.Top layout so collapsible panels reflow
- Add loop selection step: click contour to lock before placing lead-in
- Stay on selected part after placing a lead-in
- Delete unused LeadInToolWindow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove CuttingParametersForm modal dialog. PlaceLeadIn_Click,
AssignLeadIns_Click, and AssignLeadInsAllPlates now initialize
cutting parameters from saved settings or defaults instead of
showing a dialog. The CuttingPanel tool window (in LeadInToolWindow)
replaces the form for interactive parameter editing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds ApplySingle to ContourCuttingStrategy that applies lead-in/out to
only the contour containing the clicked entity, emitting other contours
as raw geometry. Also adds ApplySingleLeadIn wrapper to Part.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add AutoTabMinSize and AutoTabMaxSize properties to enable automatic tab
assignment based on part size. Update CuttingParametersSerializer for
round-trip serialization and add tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shape.Area() returns Math.Abs(signedArea), so DetermineWinding always
detected CCW regardless of actual winding. Use ToPolygon().RotationDirection()
which uses the signed area correctly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ComputeNormal assumed CW winding for all contours. For CCW-wound cutouts,
line normals pointed to the material side instead of scrap, placing lead-ins
on the wrong side. Now accepts a winding parameter: lines flip the normal
for CCW winding, and arcs flip when arc direction differs from contour
winding (concave feature detection).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of emitting separate M98 calls per identical sheet, use the L
(loop count) parameter so the operator can adjust quantity at the control.
M50 pallet exchange moves inside the sheet subprogram so each L iteration
gets its own exchange cycle. GOTO targets now correspond to layout groups.
Also fixes sheet name comment outputting dimensions in wrong order.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rapid traversing back to origin over a sheet of freshly cut parts risks
collisions with tipped or warped pieces. Removed from both the sheet
footer and part subprogram endings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cutoff features now substitute plate-edge coordinates with #SheetWidthVariable
and #SheetLengthVariable references. Vertical cutoffs at Y=plate_width emit
Y#110, horizontal cutoffs at X=plate_length emit X#111. Segmented cutoffs
only substitute the edge coordinate, interior segment endpoints stay literal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When programs have user-defined variables, the Cincinnati post now:
- Assigns numbered machine variables (#200, #201, etc.) to non-inline variables
- Emits declarations like #200=48.0 (SHEET WIDTH) in the variable declaration subprogram
- Emits X#200 instead of X48.0 in coordinates that have VariableRefs
- Handles global variables (shared number across drawings) vs local (per-drawing number)
- Inline variables emit the literal value as before
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Emit variable definitions before G-code in program text entries and use
\$varName syntax for coordinate fields that have VariableRefs, so programs
round-trip through NestWriter → NestReader without losing variable information.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ProgramReader now supports G-code user variables with a two-pass
approach: first pass collects variable definitions (name = expression
[inline] [global]) and evaluates them via topological sort and
ExpressionEvaluator; second pass parses G-code lines with $name
substitution and VariableRef tracking on motion and feedrate objects.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>