feat(plot): holding tabs for cutting mode - #76
Merged
Merged
Conversation
A closed contour is severed the moment its loop closes, and the overcut added in #58 exists to make sure of it. That is right for the last piece and wrong for every piece before it: a freed piece can shift or lift under the drag knife while later contours are still being cut, pieces come loose during the job rather than at weeding time, and there is no way to cut a part that should stay put. Overcut and tabs are opposite controls and both are wanted, per job. No new idea was needed downstream. The G-code writer already lifts the tool between strokes, so a tabbed contour is simply several strokes and the bridges come out for free — this is a polylines-in, polylines-out transform and nothing after it (ordering, framing, the time estimate) has to know tabs exist. Order is the whole design: compensate → overcut → tabs, with "was this closed?" decided once up front and carried through. Tabs have to come last because after them there is no closed contour left for the overcut to recognise, and it would silently do nothing. For the same reason tabs are kept out of the stretch the overcut re-traces — otherwise the overcut cuts through the first bridge and both features look broken at once. Bridges are nudged off sharp corners, where a bridge tears instead of snapping. The count is capped by what the contour can afford rather than honoured blindly, because each bridge needs cut on both sides of it and fifty tabs on a short contour is a dotted line. Slices that collapse are discarded explicitly: `orderPolylines` drops anything shorter than two points, so a degenerate fragment would vanish silently and leave an unexplained gap in the cut. Off by default — a piece that unexpectedly stays attached is as surprising as one that does not — and with tabs off `prepareForCut` produces exactly what it did before. The canvas now draws the prepared cutting path over faded artwork: grey is the drawing, red is what the knife does. Where a piece stays attached is exactly what has to be checked before committing a sheet of vinyl. Verified in the browser: 4 tabs of 2 mm on a rectangle produce 5 cut spans in the emitted G-code, with gaps measuring exactly 2.00 mm, evenly spread, each at least 130 mm from a corner. Closes #63 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
10 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #63.
Why
A closed contour is severed the moment its loop closes — and the overcut added in #58 exists to make sure of it. That's right for the last piece and wrong for every piece before it: a freed piece can shift or lift under the drag knife while later contours are still being cut, pieces come loose during the job rather than at weeding time, and there's no way to cut a part that should stay put. Overcut and tabs are opposite controls, and both are wanted, per job.
No new idea downstream
The G-code writer already lifts the tool between strokes, so a tabbed contour is simply several strokes and the bridges come out for free. This is a polylines-in, polylines-out transform, and nothing after it — ordering, framing, the time estimate — has to know tabs exist.
Order is the whole design
compensate → overcut → tabs, with "was this closed?" decided once up front and carried through. Tabs have to come last: after them there's no closed contour left for the overcut to recognise, and it would silently do nothing. For the same reason tabs are kept out of the stretch the overcut re-traces — otherwise the overcut cuts through the first bridge and both features look broken at once. (That's the interaction the issue flagged.)
The issue's other worry — that
orderPolylinesmay reverse a stroke and move evenly-distributed tabs — is already resolved: cutting disables reversal (#58).Details that matter
orderPolylinesdrops anything shorter than two points, so a collapsed slice would vanish silently and leave an unexplained gap in the cut — they're discarded explicitly instead.prepareForCutproduces exactly what it did before (pinned by a test). A piece that unexpectedly stays attached is as surprising as one that doesn't.Verification
mise run cigreen — 385 tests, coverage 66.5 → 67.4% statements. 13 new tests, including no-degenerate-fragments across many count/width combinations, bridges staying off corners, and bridges staying clear of the overcut.Driven in a browser: 4 tabs of 2 mm on a rectangle produce 5 cut spans in the emitted G-code, with gaps measuring exactly 2.00 mm, evenly spread, each ≥130 mm from a corner.
Not yet verified
⚙ Hardware — a real sticker has to confirm the piece stays attached during the job and snaps out cleanly by hand.
🤖 Generated with Claude Code