Add argument validation to EllipseConverter.Convert for tolerance and
semi-axis parameters. Narrow bare catch in Extensions.cs spline method
to log via Debug.WriteLine. Remove unused lineCount variable from
SolidWorksBendDetectorTests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add EllipseConverter static class with foundational methods for converting
ellipse parameters to circular arcs: EvaluatePoint, EvaluateTangent,
EvaluateNormal, and IntersectNormals. All 8 unit tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a file is loaded, a background task analyzes the entities for
simplification candidates and highlights the Simplify button with a
count when candidates are found. Button resets after simplification
is applied.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OptionsForm now shows checkboxes for each fill strategy, persisted via
the new DisabledStrategies user setting. FillStrategyRegistry exposes
AllStrategies and DisabledNames for the UI. MainForm applies disabled
strategies on startup via OptionsForm.ApplyDisabledStrategies().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New EngineOverlapTests verifies all engine types produce overlap-free
results. New StrategyOverlapTests checks each fill strategy individually.
StripeFillerTests updated to verify returned parts are overlap-free
rather than just asserting non-empty results. Remove obsolete FitCircle
tests from GeometrySimplifierTests (method was removed).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FillExtents falls back to the unadjusted column when iterative pair
adjustment shifts parts enough to cause genuine overlap. StripeFiller
rejects grid results where bounding boxes overlap, which can occur when
angle convergence produces slightly off-axis rotations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Part.Intersects now filters out intersection points that coincide with
vertices of both perimeters (shared corners/endpoints), which are touch
points rather than actual crossings. Plate.HasOverlappingParts adds a
bounding box pre-filter requiring overlap region to exceed Epsilon in
both dimensions before performing expensive shape intersection checks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Convert SimplifierViewerForm to partial class with standard WinForms
designer pattern. UI controls are now defined in the .Designer.cs file
with InitializeComponent(), enabling visual designer support.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three bugs prevented the simplifier from working on ellipse geometry:
1. Sweep angle check blocked initial fit — the 5-degree minimum sweep
was inside TryFit(), killing candidates before the extension loop
could accumulate enough segments. Moved to TryFitArcAt() after
extension.
2. Layer reference equality split runs — entities from separate DXF
ellipses had different Layer object instances for the same layer "0",
splitting them into independent runs. Changed to compare Layer.Name.
3. Symmetrize replaced arcs with mirrored copies whose endpoints didn't
match the target's original geometry, creating ~0.014 gaps. Now only
applies mirrored arcs when endpoints are within tolerance of the
target's boundary points.
Also: default tolerance 0.02 -> 0.004, Export DXF button in
CadConverterForm for debugging simplified geometry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Geometry Simplifier:
- Replace least-squares circle fitting with mirror axis algorithm
that constrains center to perpendicular bisector of chord, guaranteeing
zero-gap endpoint connectivity by construction
- Golden section search optimizes center position along the axis
- Increase default tolerance from 0.005 to 0.5 for practical CNC use
- Support existing arcs in simplification runs (sample arc points to
find larger replacement arcs spanning lines + arcs together)
- Add tolerance zone visualization (offset original geometry ±tolerance)
- Show original geometry overlay with orange dashed lines in preview
- Add "Original" checkbox to CadConverter for comparing old vs new
- Store OriginalEntities on FileListItem to prevent tolerance creep
when re-running simplifier with different settings
Bend Detection:
- Propagate bend notes to collinear bend lines split by cutouts
using infinite-line perpendicular distance check
- Add bend note text rendering in EntityView at bend line midpoints
DXF Import:
- Fix trimmed ellipse closing chord: only close when sweep ≈ 2π,
preventing phantom lines through slot cutouts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use chars.Length instead of hardcoded 36 for modulus/division since
the character set excludes 0 and O. Pad with '2' (first valid char)
instead of '0' to avoid ambiguity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without this, simplified geometry was lost on file switch and
not included in the final GetDrawings output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add "Simplify..." button to the detail bar and wire up SimplifierViewerForm
as a tool window with lazy creation, positioning, and entity replacement on apply.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Foundation for the geometry simplifier that will replace consecutive line
segments with fitted arcs. Adds ArcCandidate data class, GeometrySimplifier
with stub Analyze/Apply methods, and FitCircle using the Kasa algebraic
least-squares method. Also adds InternalsVisibleTo for OpenNest.Tests on
OpenNest.Core.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DxfImporter now filters ETCH entities (like BEND) since etch marks are
generated from bends during export, not cut geometry. GeometryOptimizer
no longer merges lines/arcs across different layers and preserves layer
and color on merged entities. EntityView draws etch marks directly from
the Bends list so they remain visible without relying on imported ETCH
entities.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidate duplicated static methods (SplitFeatures, ComputeCutDistance,
IsFeatureEtch, feature ordering) from CincinnatiSheetWriter and
CincinnatiPartSubprogramWriter into a shared FeatureUtils class. Move
inline sub-program registry building from Post() into
CincinnatiPartSubprogramWriter.BuildRegistry().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wrap the left sidebar and right entity view in a SplitContainer so the
boundary can be dragged to resize. Fixed panel on the left with a 200px
minimum width.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The remnant viewer previously always filtered by smallest part dimension,
hiding large remnants that were narrower than the smallest part. Added a
"Filter by part size" checkbox (on by default) so users can toggle this
off to see all remnants regardless of size.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add toggleable pierce point drawing to PlateView that shows small red
filled circles at each rapid move endpoint (where cutting begins). Wire
through View menu, EditNestForm toggle, and MainForm handler.
Also rename RectangleShape/RoundedRectangleShape Width/Height to
Length/Width for consistency with CNC conventions, update MCP tools and
tests accordingly. Fix SplitDrawingForm designer layout ordering and
EntityView bend line selection styling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After splitting a drawing with a circular hole, CadConverterForm writes
the split piece to DXF and re-imports it. The circle (decomposed into
two semicircular arcs by DrawingSplitter) was being incorrectly merged
back into a single zero-sweep arc by GeometryOptimizer.TryJoinArcs
during reimport.
Root cause: TryJoinArcs mutated input arc angles in-place and didn't
guard against merging two arcs that together form a full circle. When
arc2 had startAngle=π, endAngle=0 (DXF wrap-around from 360°→0°), the
mutation produced startAngle=-π, and the merge created an arc with
startAngle=π, endAngle=π (zero sweep), losing half the hole.
Fix: use local variables instead of mutating inputs, require arcs to be
adjacent (endpoints touching) rather than just overlapping, and refuse
to merge when the combined sweep would be a full circle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FitToPlate now places split lines at usable-width intervals so each
piece (except the last) fills the entire plate work area. Also adds a
live yellow preview line that follows the cursor during manual split
line placement, and piece dimension labels in the preview regions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DrawingSplitter now clips bend lines to each piece's region using
Liang-Barsky line clipping and offsets them to the new origin. Bend
properties (direction, angle, radius, note text) are preserved through
the entire split pipeline instead of being lost during re-import.
CadConverterForm applies the same origin offset to bends before passing
them to the splitter, and creates FileListItems directly from split
results to avoid re-detection overwriting the bend metadata.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change split file suffix from _split# to -# (e.g., PartName-1.dxf)
- Add numbered labels at the center of each split region in the preview
- Fix fit-to-plate axis calculation to use correct plate dimension
instead of min(width, height) for single-axis splits
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace sidebar Panel+Splitter with SplitContainer for resizable file
list / filter panel. Sort file list alphabetically on insert. Widen bend
line dash spacing and draw ETCH layer entities on top of bend lines so
etch marks are visible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BEND layer lines were being imported as cut geometry alongside the
separate Bend object detection, causing duplicate dark lines in nests.
Skip BEND layer entities in DxfImporter since bend detection reads
directly from the raw CadDocument.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PushBoundingBox left exactly partSpacing between bounding boxes, but the
geometry push inflates offset lines by halfSpacing + chordTolerance per
side (totaling partSpacing + 2*chordTolerance). The 0.002 overlap caused
RayEdgeDistance to return MaxValue for negative t, making the nearest
obstacle invisible and allowing the part to push through it.
Subtract 2*ChordTolerance from the BB push distance so the gap is wide
enough for the offset geometry lines to remain non-overlapping.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fire SelectedIndexChanged when the first item is added so the preview
loads automatically. Invalidate the file list after quantity changes so
the badge repaints immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ConvertProgram.ToGeometry() created entities without setting Color,
defaulting to Color.Empty (alpha=0). After ededc7b switched from
Pens.White to per-entity colors, these rendered fully transparent.
- Add explicit colors to all SpecialLayers (Cut=White, Rapid=Gray, etc.)
- Set entity Color from layer in ConvertProgram for lines, arcs, circles
- Add GetEntityPen fallback: treat Empty/alpha-0 as White
- Add bend line rendering and selection in EntityView/CadConverterForm
- Fix SolidWorksBendDetector MText formatting strip for bend notes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SplitContainer wasn't sizing children correctly. Switched to the same
Panel(Dock.Left) + Splitter + Fill pattern used by SplitDrawingForm,
with explicit Size on all controls.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the old DataGridView+TabControl layout with a sidebar containing
FileListControl and FilterPanel on the left, and EntityView with a detail
bar on the right. Adds drag-and-drop support, thread-safe parallel file
import, bend detection integration, and split-to-DXF workflow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces a pluggable bend detection system in OpenNest.IO.Bending:
- IBendDetector takes CadDocument directly to preserve MText/layer/linetype info
- SolidWorksBendDetector finds lines on BEND layer with CENTER linetype and matches nearby MText notes
- BendDetectorRegistry auto-registers SolidWorks detector and supports AutoDetect
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces OpenNest.Core/Bending/ with Bend and BendDirection types as
the foundation for bend line detection. Includes 6 passing unit tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace polygon boolean clipping with direct entity splitting using
bounding box filtering and exact intersection math. Eliminates Clipper2
precision drift that caused contour gaps (0.0035") breaking area
calculation and ShapeBuilder chaining.
Also fixes SpikeGrooveSplit: spike depth is now grooveDepth + weldGap
(spike protrudes past groove), both V-shapes use same angle formula,
and weldGap no longer double-subtracted from tip depth.
SplitDrawingForm: fix parameter mapping (GrooveDepth direct from nud,
not inflated), remove redundant Spike Depth display, add feature
contour preview and trimmed split lines at feature positions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ToLine() to SplitLine and create SplitLineIntersect static class with
FindIntersection, CrossesSplitLine, and SideOf methods for testing entity
intersections against split lines. These helpers support the upcoming
Clipper2-free DrawingSplitter rewrite.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace raw Panel with EntityView (via SplitPreview subclass) for proper
zoom-to-point, middle-button pan, and double-buffered rendering
- Add draggable handles for tab/spike positions along split lines; positions
flow through to WeldGapTabSplit and SpikeGrooveSplit via SplitLine.FeaturePositions
- Fix OK/Cancel buttons hidden off-screen by putting them in a bottom-docked panel
- Fix DrawControl not invalidating on resize
- Swap plate Width/Length label order, default edge spacing to 0.5
- Rename tab labels: Tab Width→Tab Length, Tab Height→Weld Gap, default count 2
- Spike depth now calculated (read-only), groove depth means positioning depth
beyond spike tip (default 0.125), converted to total depth internally
- Set entity layers visible so EntityView renders them
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SpikeParameters: added GrooveDepth (how deep groove cuts into
receiving part) and SpikeWeldGap (gap between spike tip and groove)
- SpikeGrooveSplit: groove uses its own depth (wider/deeper than spike),
spike tip stops short by weld gap amount
- UI: added Groove Depth and Weld Gap fields to spike parameters panel
- Changed default pair count to 2 (one near each end)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When user selects Vertical Only or Horizontal Only, use the smaller
plate dimension as the constraint for that axis. Previously it filtered
results from FitToPlate which produced no lines when the part already
fit in the plate width but not height.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a "Split Axis" dropdown (Auto / Vertical Only / Horizontal Only)
to the Fit to Plate options so users can control which direction the
part is split when weld direction matters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rapid-layer entities (connecting lines between cutouts and perimeter)
were being rendered in the split preview. Filter them out, matching
the same pattern used in DrawingSplitter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a Split button column to the DXF converter grid. Clicking it
builds a temporary Drawing from the item's visible entities and opens
SplitDrawingForm; if the user confirms, the split results replace the
original item in GetDrawings().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements the main drawing splitting algorithm that orchestrates splitting
a Drawing into multiple pieces along split lines using Clipper2 polygon
clipping. After clipping, recovers original arcs by matching clipped edges
back to perimeter entities, stitches in feature edges from ISplitFeature
where polygon edges lie on split lines, and normalizes each piece's origin.
Key fix from plan: filters rapid-layer entities before ShapeProfile
construction so cutouts are properly separated from perimeters.
Includes 7 integration tests covering vertical/horizontal splits, three-way
splits, property copying, origin normalization, cutout assignment, and
grid (cross) splits.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add MaterialLibraryResolver for Cincinnati post processor to resolve
G89 library files from material/thickness/gas configuration
- Add Nest.AssistGas property with serialization support in nest format
- Add etch library support with separate gas configuration
- Fix CutOff tests to match AwayFromOrigin default cut direction
- Fix plate info label not updating after ResizePlateToFitParts
- Add cutoff and remnants toolbar button icons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PolygonHelper.ExtractPerimeterPolygon always used OffsetSide.Right
assuming CCW winding, but DXF imports can produce CW winding. This
caused the spacing polygon to shrink inward instead of expanding
outward, making parts overlap during nesting.
Now detects winding direction via polygon signed area and selects
the correct OffsetSide accordingly.
Also adds save_nest MCP tool and a BOM-to-nest builder utility
(tools/NestBuilder) for batch-creating nest files from Excel BOMs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cut-off parts use absolute coordinates in their programs, causing
Program.BoundingBox() to span from the origin to the cut-off position.
This made cut-offs invisible to GetLargestBoxVertically/Horizontally
since the oversized box straddled the cursor instead of acting as a
boundary. Derive thin obstacle boxes directly from CutOff definitions
and apply PartSpacing offset so fills respect spacing from cut lines.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
G-code output was concatenated without spaces (e.g. N1005G0X1.4375Y-0.6562).
Now emits standard spacing (N1005 G0 X1.4375 Y-0.6562) across all motion
commands, line numbers, kerf comp, feedrates, M-codes, and comments.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Load IPostProcessor plugin DLLs from Posts/ directory (same convention
as the WinForms app) and run them after nesting via --post <name>.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous default of 0.125 was too large for typical use, causing
cut-off lines to be pushed unnecessarily far from parts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds project dependency in .sln and project reference in OpenNest.csproj
so the Cincinnati post processor DLL builds before the main app, ensuring
it's always available in the Posts/ directory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each unique part geometry (drawing + rotation) is written once as a
reusable sub-program called via M98, reducing output size for nests
with repeated parts. G92 coordinate repositioning handles per-instance
plate placement with restore after each call. Cut-offs remain inline.
Controlled by UsePartSubprograms (default false) and PartSubprogramStart
config properties.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The WinForms app's LoadPosts() scans Posts/ for IPostProcessor DLLs.
A build target copies the Cincinnati DLL there so it appears in the
Nest > Post menu automatically.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move ProgramVariable and ProgramVariableManager from
OpenNest.Posts.Cincinnati to OpenNest.Core/CNC (namespace OpenNest.CNC)
so they can be used internally in nest programs
- Add parameterless constructor to CincinnatiPostProcessor that loads
config from a .json file next to the DLL (creates defaults on first run)
- Enums serialize as readable strings (e.g., "Inches", "ControllerSide")
- Config file: OpenNest.Posts.Cincinnati.json in the Posts/ directory
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Select cut-offs by clicking their lines instead of a grip point.
Drag is axis-constrained with live regeneration during movement.
Selected cut-off highlighted with bright blue 3.5px line.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Polygon.OffsetEntity now computes proper miter-join offsets using edge
normals and winding direction, with self-intersection cleanup. CutOff
exclusion zones use geometric perimeter offset instead of scalar padding,
giving uniform clearance around parts regardless of cut angle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use CultureInfo.InvariantCulture in CoordinateFormatter, SpeedClassifier,
and CincinnatiPreambleWriter to prevent locale-dependent G-code output
- Make CincinnatiPostConfig sealed per spec
- Fix SpeedClassifier.Classify threshold to >= (matching spec)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Orchestrates CincinnatiPreambleWriter and CincinnatiSheetWriter to produce
a complete Cincinnati CNC output file from a Nest; includes 4 integration tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>