Skip to content

feat(plot): holding tabs for cutting mode - #76

Merged
BernardJen merged 1 commit into
mainfrom
feat/holding-tabs
Sep 12, 2026
Merged

BernardJen merged 1 commit into
mainfrom
feat/holding-tabs

Conversation

@BernardJen

Copy link
Copy Markdown
Contributor

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 orderPolylines may reverse a stroke and move evenly-distributed tabs — is already resolved: cutting disables reversal (#58).

Details that matter

  • 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; fifty tabs on a short contour is a dotted line.
  • No degenerate fragments. orderPolylines drops 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.
  • Off by default, and with tabs off prepareForCut produces exactly what it did before (pinned by a test). A piece that unexpectedly stays attached is as surprising as one that doesn't.
  • The canvas 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.

Verification

mise run ci green — 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

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>
@BernardJen
BernardJen merged commit 5cac139 into main Sep 12, 2026
2 checks passed
@BernardJen
BernardJen deleted the feat/holding-tabs branch September 12, 2026 10:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cutting mode: holding tabs — leave uncut bridges so the cut piece stays attached

1 participant