Commit Graph

770 Commits

Author SHA1 Message Date
d7fa4bef43 feat: implement tab support in ContourCuttingStrategy
When TabsEnabled is set, trims the end of each contour using a circle
centered at the lead-in point with radius equal to the tab size. The
uncut gap between the trim point and the contour start keeps the part
connected to the sheet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:40:29 -04:00
7c58cfa749 fix: correct lead-in approach angle formula mirroring pierce point
The offset direction (start→pierce) is reversed from the approach
direction (pierce→start), so the old formula produced 180°−angle
instead of the requested angle. Invisible at the 90° default but
caused 45° to render as 135°.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:01:18 -04:00
525cbc6f12 fix: draw cut direction arrows as chevron lines instead of filled triangles
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 08:52:33 -04:00
134771aa23 feat: add Draw Cut Direction view option and extract PlateRenderer
Add a "Draw Cut Direction" toggle to the View menu that draws small
arrowheads along cutting paths to indicate the direction of travel.
Arrows are placed on both linear and arc moves, spaced ~60px apart,
and correctly follow CW/CCW arc tangents.

Extract all rendering methods (~660 lines) from PlateView into a new
PlateRenderer class, reducing PlateView from 1640 to 979 lines.
PlateView retains input handling, selection, zoom, and part management.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:22:05 -04:00
59a66173e1 fix: exempt scribe/etch contours from lead-ins and kerf
Scribe/etch lines were being treated as cut contours by
ContourCuttingStrategy, receiving lead-ins and kerf compensation.
Now they are separated before ShapeProfile construction and emitted
as plain moves with LayerType.Scribe preserved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:56:07 -04:00
a2b7be44f8 fix: draw approach rapid directly to first pierce point, not part origin
The approach rapid from sheet origin was drawing to part.Location (the
program coordinate origin) then a second rapid to the actual first
pierce point. This created a dog-leg through the part origin instead
of a single straight rapid to the lead-in. Also fixed PlateProcessor
using the original program's start point instead of the processed one
when the cutting strategy is applied on-the-fly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 20:38:53 -04:00
e94a556f23 feat: add Remove Lead-ins button to EditNestForm toolbar
Clears all manual lead-ins from every part on the active plate and
rebuilds the layout graphics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:36:01 -04:00
428dbdb03c feat: persist cutting parameters and add pierce clearance UI
Save/restore cutting parameters as JSON in user settings so values
survive between sessions. Add pierce clearance numeric input to the
CuttingParametersForm.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:35:51 -04:00
e860ca3f4a feat: add pierce clearance clamping for circle contour lead-ins
Scales down lead-ins that would place the pierce point too close to the
opposite wall of small holes. Uses quadratic solve to find the maximum
safe distance inside a clearance-reduced radius. Adds Scale() method to
all LeadIn types and applies clamping in both the strategy and the
interactive preview.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:35:41 -04:00
a399c89f58 fix: resolve rendering issues when applying lead-ins to parts
Three issues caused incorrect rendering after lead-in application:
- Rapid move entities from ToGeometry() were included in ShapeProfile
  contour detection, turning traversal paths into cutting moves
- Program created with Mode.Incremental default made the absolute-to-
  incremental conversion a no-op, leaving coordinates unconverted
- AddProgramSplit didn't call StartFigure() at rapid moves, causing
  GraphicsPath to draw implicit connecting lines between contours
- Part.Rotation returned 0 from the new program instead of the actual
  rotation, displacing the sequence label on rotated parts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:35:29 -04:00
d16ef36d34 feat: add lead-out parameters and tab toggle to CuttingParametersForm
Restructure the cutting parameters dialog with separate Lead-In and
Lead-Out GroupBoxes per tab, exposing editable length/angle/radius
fields for lead-outs (previously hardcoded). Add Tabs section with
enable checkbox and width control. Also fix lead-in/lead-out angle
calculations and convert cutting strategy output to incremental mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:08:18 -04:00
5307c5c85a feat: add ActionLeadIn for manual lead-in placement on part contours
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:47:22 -04:00
21321740d6 feat: add Assign Lead-ins button to EditNestForm toolbar
Adds a text-only toolbar button to the Plates tab that opens the
CuttingParametersForm, saves the chosen parameters on the plate, and
runs LeadInAssigner with LeftSideSequencer to auto-assign lead-ins.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:39:40 -04:00
7f8c708d3f feat: add CuttingParametersForm dialog for lead-in/lead-out configuration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:36:41 -04:00
ab4f806820 feat: render lead-in/lead-out codes in yellow, skip suppressed codes
Add GetGraphicsPaths/AddProgramSplit to GraphicsHelper that builds separate
GraphicsPath objects for cut vs lead-in/lead-out codes, skipping suppressed
codes. Update LayoutPart to use split paths when HasManualLeadIns is set,
drawing lead-in geometry in yellow regardless of selection state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:32:43 -04:00
c9b5ee1918 feat: serialize HasManualLeadIns, LeadInsLocked, and :SUPPRESSED in nest files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:29:49 -04:00
f34dce95da feat: add LeadInAssigner for auto-assigning lead-ins to plate parts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:26:43 -04:00
a2a19938d3 feat: add CuttingParameters property to Plate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:22:28 -04:00
c064c7647a feat: add ApplyLeadIns/RemoveLeadIns to Part with CuttingParameters storage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:21:09 -04:00
8a712b9755 feat: set Layer = Leadout on all LeadOut subclass generated codes
Adds LayerType.Leadout to all LinearMove and ArcMove instances produced
by LineLeadOut and ArcLeadOut Generate() methods.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 13:16:11 -04:00
82de512f44 feat: set Layer = Leadin on all LeadIn subclass generated codes
Adds LayerType.Leadin to all LinearMove and ArcMove instances produced
by LineLeadIn, ArcLeadIn, LineArcLeadIn, CleanHoleLeadIn, and
LineLineLeadIn Generate() methods, plus tests covering all subclasses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 13:16:06 -04:00
f903cbe18a feat: add Motion.Suppressed property to mark tab-gap codes
Adds Suppressed bool to the Motion base class so LinearMove, ArcMove,
and RapidMove can be flagged for skip during rendering and post-processing
when they fall within a tab gap. Clone() updated on all three subclasses
to preserve the flag. Covered by new MotionSuppressedTests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:13:00 -04:00
3d4204db7b fix: Cincinnati post processor arc feedrate, G89 spacing, pallet exchange, and preamble
- Add radius-based arc feedrate calculation (Variables/Percentages modes)
  with configurable radius ranges (#123/#124/#125 or inline expressions)
- Fix arc distance in SpeedClassifier using actual arc length instead of
  chord length (full circles previously computed as zero)
- Fix G89 P spacing: P now adjacent to filename per CL-707 manual syntax
- Add lead-out feedrate support (#129) and arc lead-in feedrate (#127)
- Fix pallet exchange: StartAndEnd emits M50 in preamble + last sheet only
- Add G121 Smart Rapids emission when UseSmartRapids is enabled
- Add G90 absolute mode to main program preamble alongside G20/G21

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 09:33:50 -04:00
722f758e94 feat: dual-tangent arc fitting and DXF version export
Add ArcFit.FitWithDualTangent to constrain replacement arcs to match
tangent directions at both endpoints, preventing kinks without
introducing gaps. Add DXF year selection to CAD converter export.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 09:16:09 -04:00
9b2322abe9 refactor: simplify GeometrySimplifier by removing wrappers and extracting shared helpers
Remove pass-through wrappers (FitWithStartTangent, MaxRadialDeviation), extract
PerpendicularDistance and NormalizeAngle helpers to deduplicate mirror axis math,
convert GetExitDirection to switch expression, and simplify ComputeEndTangent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:05:28 -04:00
b15375cca5 feat: capacity-based fill/pack split with best-fit pair placement
Change Nest() to decide fill vs pack based on total area coverage
instead of qty != 1. Items covering < 10% of the plate are packed,
so large parts get prime position and small low-qty parts fill gaps.

Qty=2 items are placed as interlocking best-fit pairs in remnant
spaces after the main pack phase, rather than as separate rectangles.

- Add ShouldFill() capacity-based heuristic
- Split pack phase: regular items pack first, then pairs
- Add PlaceBestFitPairs() for Phase 3 remnant pair placement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 00:38:57 -04:00
e3b388464d feat: fast-path fill and dual-axis shrink for low quantities
For qty 1-2, skip the full 6-strategy pipeline: place a single part
or a best-fit pair directly. For larger low quantities, shrink the
work area in both dimensions (sqrt scaling with 2x margin) before
running strategies, with fallback to full area if insufficient.

- Add TryFillSmallQuantity fast path (qty=1 single, qty=2 best-fit pair)
- Add ShrinkWorkArea with proportional dual-axis reduction
- Extract RunFillPipeline helper from Fill()
- Make ShrinkFiller.EstimateStartBox internal with margin parameter
- Add MaxQuantity to FillContext for strategy-level access

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 00:38:44 -04:00
ab09f835d3 refactor: extract RunAutoNest_Click into focused helper methods
Break the 113-line click handler into single-responsibility methods:
RunAutoNestAsync, GetOrCreatePlate, NestSinglePlateAsync, and
CreatePreviewPlate (eliminates duplicated plate-cloning code).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 23:52:07 -04:00
f8b0fb573b fix: fill preview now matches accepted layout
Refresh PlateView preview with settled parts after Compactor.Settle
so the accepted layout matches what was shown, not the pre-settle
positions from the last progress report.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 23:39:43 -04:00
6ce501da11 feat: smart strategy skipping, pack rotation, and dual-sort packing
- Skip ExtentsFillStrategy for rectangle/circle parts
- Skip PairsFillStrategy for circle parts
- PackBottomLeft now tries rotated orientation when items don't fit
- PackBottomLeft tries both area-descending and length-descending sort
  orders, keeping whichever places more parts (tighter bbox on tie)
- Add user constraint override tests for AngleCandidateBuilder

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 23:25:40 -04:00
05037bc928 feat: wire PartClassifier into engine and update angle selection
Replace RotationAnalysis.FindBestRotation with PartClassifier.Classify in
RunPipeline, propagate ClassificationResult through BuildAngles signatures and
FillContext.PartType, and rewrite AngleCandidateBuilder to dispatch on part type
(Circle=1 angle, Rectangle=2, Irregular=full sweep).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 22:19:20 -04:00
f83df3a55a test: add PartClassifier unit tests for all shape types
Covers all 9 cases: pure rectangle, rounded rectangle, rect with notch,
circle, L-shape, triangle, serrated edge (perimeter ratio), tilted rect
(primary angle), and empty drawing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 22:12:40 -04:00
84ad39414a feat: add PartClassifier with rectangle/circle/irregular detection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 22:09:33 -04:00
fdb4a2373a fix: simplify Shape.OffsetOutward winding normalization and sync designer
OffsetOutward now normalizes to CW winding before offsetting instead of
trial-and-error with bounding box comparison. CadConverterForm designer
regenerated with new entityView1 properties.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 21:01:46 -04:00
3a0267c041 chore: add docs/ to gitignore and remove tracked superpowers docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 21:01:20 -04:00
036f723876 fix: update PlateView fill path and sync stats with preview
- Route best-result updates to progress form preview in
  PlateView.FillWithProgress (Ctrl+F path) — was still using
  the old SetStationaryParts approach
- Only update results stats (parts, density, area) when
  IsOverallBest so they match the preview display

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:56:41 -04:00
21a5d3b026 feat: route best-result updates to progress form preview
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 19:59:51 -04:00
0607c6c7c5 feat: add UpdatePreview method and PreviewPlate property
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 19:58:47 -04:00
c8cfeb3c6b feat: add SplitContainer and PlateView to NestProgressForm layout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 19:57:12 -04:00
d4f424f274 refactor: simplify FillExtents with PartPair record and FillLinear delegation
Replace verbose value tuple with named PartPair record struct, extract
AnchorToWorkArea/PairBbox helpers to eliminate duplication, and delegate
RepeatColumns to FillLinear.Fill which already handles geometry-aware
column tiling with overlap fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 19:16:16 -04:00
028b1fabfc fix: move bend line action links above list for more vertical space
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 18:32:53 -04:00
a7c2fcffe6 test: add edge case tests for Collision; update CLAUDE.md 2026-03-29 09:43:31 -04:00
b834813889 refactor: delegate Part.Intersects to Collision.Check 2026-03-29 09:41:40 -04:00
4fa6100722 test: add hole subtraction and batch collision tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 09:40:28 -04:00
8f2fbee02c feat: add Collision static class with Sutherland-Hodgman clipping and tests
Polygon-polygon collision detection using convex decomposition (ear-clipping
triangulation) followed by Sutherland-Hodgman clipping on each triangle pair.
Handles overlapping, non-overlapping, edge-touching, containment, and concave
polygons. Includes hole subtraction support for future use.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 09:35:41 -04:00
230a11d32e feat: add CollisionResult data class for polygon collision detection
Immutable result type that holds overlap flag, overlap regions (as polygons),
intersection points, and computed overlap area.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 09:32:51 -04:00
953429dae9 fix: add overlap safety check and diagnostics to FillGrid Step 2
FillGrid had no overlap check after perpendicular tiling of the row
pattern (Step 2), unlike Step 1 which had one. When geometry-aware
FindPatternCopyDistance underestimated row spacing, overlapping parts
were returned unchecked.

Changes:
- Make FillLinear.HasOverlappingParts shape-aware (bbox pre-filter +
  Part.Intersects) instead of bbox-only, preventing false positives on
  interlocking pairs while catching real overlaps
- Add missing overlap safety check after Step 2 perpendicular tiling
  with bbox fallback
- Add diagnostic Debug.WriteLine logging when overlap fallback triggers,
  including engine label, step, direction, work area, spacing, pattern
  details, and overlapping part locations/rotations for reproduction
- Add FillLinear.Label property set at all callsites for log traceability
- Refactor LinearFillStrategy and ExtentsFillStrategy to use shared
  FillHelpers.BestOverAngles helper for angle-sweep logic

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:08:38 -04:00
1c2b569ff4 fix: eliminate endpoint gaps in EllipseConverter arc output
EllipseConverter computed arc radius from start point only, causing
~0.0009 unit gaps between consecutive arcs. Use circumcircle of
(start, mid, end) points so both endpoints lie exactly on the arc.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:37:01 -04:00
048b10a1e9 refactor: deduplicate BestFitHorizontal and BestFitVertical
Extract shared BestFitAxis helper parameterized by orientation,
eliminating 23-line duplicate in rectangle packing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:23:08 -04:00
3022982f6d refactor: consolidate HasOverlappingParts into FillHelpers
StripeFiller and FillExtents had identical 24-line overlap detection
methods; move to FillHelpers and delegate from both callers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:22:00 -04:00