Commit Graph
63 Commits
Author SHA1 Message Date
ajandClaude Opus 5.5 13ab8e02f8 fix(cutting): plan with staged scrap cut-offs within budget
Staged cut-offs were appended after every part, so a kept order (the
"Keep the current part order" option, or the fallback after a free
search runs out of budget) always conflicted with any cut-off crossing
a part. PlateSequencing.PlaceCutOffs moves each new cut-off to just
before the first part it crosses, separators last, without moving
anything else; the panel applies it after staging.

The free search also learned "cut the cut-off first" only after a full
stall, re-planning the many-holed parts before it. A cut-off is a fixed
program that never gets harder to cut earlier, so a crossing approach
into a non-separating cut-off now teaches that rule at once. On the
reported 35-part plate this drops the plan from 23,930 expansions (over
the 20,000 budget) to 15,605.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:14:28 -04:00
ajandClaude Opus 5.5 fb505ef0ff fix(cutting): plan outlines with a seam gap before an arc, and memoize lead checks
A converted outline whose seam closes within the admitted 1e-6 gap could
only be entered at its seam: entered anywhere else, the arc after the
seam started off its own circle and every emission was refused as an
inconsistent radius. The search then spent its whole budget on that
part and the plate never planned. Emission now bridges the gap with a
straight move and cuts the arc as drawn; the verifier already admits
that slack. An entry on the seam vertex is left as before.

Each prefix of a part re-checked its earlier contours' leads against
every other part's material. One search now remembers each verdict by
the lead curve's exact bits and the material's reference, charging the
same native query budget; replay never uses it. On the reported plate
the memo alone gives a byte-identical result in 57 s instead of 12 min 47 s;
with the seam fix the plate plans Ready in about 17 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:21:20 -04:00
ajandClaude Opus 5.5 bbe0f17a64 feat(ui): allow clearing lead-ins and cut-offs while a cut plan runs
The Clear Lead-ins & Cut-offs button stays enabled during planning.
Confirming cancels the running plan, clears once the cancellation lands
so the plates never change under the planner, then replans.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 18:45:31 -04:00
ajandClaude Opus 5.5 ba39c3dc55 feat(cad): add tabbed cutouts with draggable tabs
A hole can now be declared a tabbed cutout in the CAD Converter: pick a
circle or any edge of a closed hole, set the tab count and width, and drag
the tabs around the hole. The definition persists on the drawing and in the
nest file, and stays editable from the source entities.

The builder replaces the hole with open cut pieces and uncut spans on a new
Tab layer. Tabs are material, so area, nesting and overlap checks still see
a closed hole, but they are never cut. Plan Cutting and Assign Lead-ins cut
each piece from the slug with the internal lead-in and no lead-out. A lead
that would reach back over a tab is mirrored, and an arc lead onto an arc
pierces straight in. Planning accounts for each span between tabs and runs
the open-cut proof, so its own tabbed cutouts certify; tabs followed by a
lead-out are still refused. Pre-post review flags programs that still
contain tab motions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 00:50:11 -04:00
ajandClaude Opus 5.5 6f555345e3 feat(cad): cut breakoff joining lines as tabbed open break cuts
Breakoffs are now picked by their joining line, default to the smaller side as scrap
(flippable), and cut that line between tabs on a new Break layer instead of slots.
Plan Cutting and Assign Lead-ins enter each cut from the scrap with the nest's internal
lead-in, or pierce on the line without one; checks treat break cuts as intentional open
cuts that are not material.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 17:46:35 -04:00
ajandClaude Opus 5.5 4a1587d6bd feat(engine): fill cutouts first in every whole-job run
NestPipeline.Run now bundles parts that fit other parts' enclosed cutouts
into their frames before the selected engine, for desktop, Console, MCP and
API alike. A valid complete bundled trial is kept; a refused trial falls back
to the ordinary solve (reason on RefusedCutoutTrial), and an incomplete trial
is compared with it, keeping whichever valid proposal places more. An
incomplete but valid trial is now keepable like any incomplete result.
Expanded sheets list each frame's inserts before the frame, so the committed
order cuts every insert before the cutout that releases its slug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:51:18 -04:00
ajandClaude Opus 5.5 9816326429 fix(engine): legacy lead assignment respects pins
Assign Lead-ins (LeadInAssigner) now leaves every unlocked part with active
drawing pins unchanged and returns those parts, so it never overwrites a pin
with the plate's settings; the desktop names them ("N parts kept their
drawing lead-ins (plate P: parts ...); use Plan Cutting to apply their
drawing pins."). Parts without pins, with pins switched off, or locked are
assigned or skipped exactly as before.

The pre-post review now covers drawing pins. A part with active pins whose
placed program does not cut each pinned contour exactly as the pin's own
emission (re-emitted with the part's cutting settings and matched motion for
motion) warns "Drawing pins not applied", as do locked lead-ins overriding
pins and a pin that no longer matches the geometry; pins switched off are
not reported. The contours that are cut as pinned join locked programs in
the fixed-lead re-check against every part's clean material, and fixed
leads are now also checked against active clamps (Plan Cutting itself does
not model clamps).

AGENTS.md records the fixed-emission safeguard and the characterization
digests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:26 -04:00
ajandClaude Opus 5.5 a18f8c9b56 feat(engine): pinned contours use the fixed-lead warning path
A drawing-pinned contour is now a fixed emission like a locked program. A
regenerated placement maps its execution motions onto the emitted contour
choices (one group per choice after the program's scribes, opened by its
rapids) and owns as fixed the lead-in, cut, lead-out and tab of every pinned
contour; the rapids between contours, including the one into a pinned
contour, stay the planner's and strictly checked. If the motions do not
split cleanly into one group per choice, nothing is treated as fixed.

So a pinned lead that meets another part's material or its own part's no
longer rejects the candidate: the feasibility precheck accepts a pinned
entry as given, the search keeps it in place, and replay reports a FixedLead
warning naming the part, cutting contour, pin and the part hit, with the
advice to increase spacing or switch off drawing pins for the part. The
plate is UNVERIFIED and needs acceptance; the lead is never shortened and
the entry never moved. The unpinned control and the same plate with pins
off are Ready.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:25 -04:00
ajandClaude Opus 5.5 8d17cf8c59 feat(engine): capture and freshness for pins
Capture now honours a placement's pins only while they are active: a part
with DrawingPinsOff plans from the plate settings with no warning (D1's
per-part escape hatch), and Part.HasActiveDrawingPins is the shared test.
A pinned part is regenerated like any unlocked part whatever lead-ins or
settings it carried. A locked part with active pins keeps its exact program
and warns "Locked lead-ins override drawing pins on part N; Clear Lead-ins
to apply the pins." instead of being refused; an unlocked part a caller left
ineligible warns that its pins are not applied.

Apply's freshness record now holds each drawing's pin list (reference and an
explicit StateFingerprint of every pin's point, leads and tab) and each
part's pins-off flag, so editing either after capture returns Stale. The
fingerprint writer is shared between settings and pins; a reflection test
pins ContourCutPin's public surface to what the fingerprint covers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:25 -04:00
ajandClaude Opus 5.5 7949d41b6d feat(core): pinned contour preparation
PreparedContours.Capture(program, parameters, pins) takes CutPinResolver
results for the same contours and fixes every resolved pin's contour: its
one and only entry is the pin's point, and it is emitted through the
existing emitter with the pin's own lead-in, lead-out and tab (angle
rounding off, so the entry never moves). Every catalogue returns the pinned
entry alone and emission refuses any other entry for that contour, so no
search path can relocate it. The certified tab size is the pinned outside's
own, so a pinned tab gap is genuine and replay certifies it. Unpinned
contours keep the shared settings and automatic selection; without pins the
existing preparation is untouched (5.1 digests unchanged).

Capture now resolves a regenerated part's drawing pins. A pin that does not
resolve (not on a contour, on several, sharing one, or unplaceable) is never
guessed: its contour stays automatic and the plate gets a FixedLead warning
naming the pin, making the proposal UNVERIFIED. A tab pinned on an internal
contour cannot be cut as pinned (only the outside is tabbed) and warns the
same way. Pins-off, locked parts with pins and freshness follow in 5.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:24 -04:00
ajandClaude Opus 5.5 d56f67a99a feat(engine): fixed-lead violations warn instead of refusing
D1a (user, 2026-10-14): one locked cutout must not refuse the whole layout.
With confirmed parameters a locked program is now a fixed emission, accepted
as given. The replay checker and the lead validator take a per-motion owner:
a violation inside the fixed emission (a lead meeting another part's or its
own material, a rapid inside the locked program crossing a cut contour, an
uncertifiable tab gap or a partial/reversed/retraced cut) is recorded apart
instead of failing the candidate. The search never rejects or learns an order
rule from them, so fixed emissions never steer it; the planner's rapid into
the locked program and every regenerated lead keep every strict check.

Replay turns those violations into typed FixedLead findings that name the
part, contour and the part hit. A plate whose only findings are these is
BestEffort with IndependentlyReplayed set: never Ready, applicable only with
the per-proposal acceptance, and CuttingPlanService.Apply still rejects it.
Overlap, unreadable programs, stale input and cancellation still block, and
unlocked programs a caller left ineligible and the no-parameter route keep
refusing as before.

Pre-post review now re-checks locked leads against every part's clean
material, so the same violations reappear before posting.

Existing tests that encoded the old locked refusal now assert the warning;
two batch tests that used a locked crossing as their hard block use an
overlap instead. The 5.1 digests are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:23 -04:00
ajandClaude Opus 5.5 405a867a77 fix(desktop): draw planned cut-offs and issue markers on the plan preview
The proposal preview skipped the cut-off overlay: it carries cut-off parts but no
cut-off definitions, so planner cut-offs looked like thin black part outlines
instead of the orange-red dashes used everywhere else. The preview now draws each
cut-off part's own cutting moves in that style.

The same paint guard hid the validation overlay over a preview, so issue markers
for unverified plans were set but never drawn. The overlay now draws on proposals
too, with the marker's part numbers mapped to the preview's proposed order so the
right parts stay highlighted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:18:48 -04:00
ajandClaude Opus 5.5 c3fa8e79e0 feat(desktop): mark cut-plan issues on the plate and trim the inspection panel
Plan Cutting findings dropped the checker's geometry, so selecting one could only
zoom to part extents, and overlap-blocked plates (no preview) did nothing at all.
Findings now keep the check's world-coordinate witness (overlap regions, rapid,
contacts); selecting a row draws it with the Validate Nest overlay, on the proposal
or a blocked plate's live sheet. The witness is excluded from finding equality so
repeated search rejections still collapse to one finding.

The side panel's scrolling report was a wall of text operators skipped. It is now
a colored outcome line, one line for the shown plate, and one remedy or marker
hint above the issue grid, with secondary detail moved to tooltips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:11:13 -04:00
aj ddd1e422be feat(cutoffs): cut sheet-separating cut-offs after every part 2026-10-13 21:09:35 -04:00
aj b9a387b517 feat(desktop): choose cutting-planner cut-off settings in the automatic cut-off dialog 2026-10-13 20:55:24 -04:00
aj 9f2ece37ed feat(desktop): add automatic cut-offs, existing-work banner and clear button to the cutting planner 2026-10-13 20:39:43 -04:00
ajandClaude Opus 5.5 311178c15a fix(cutting): trim baked-in seam overcuts and route parts nested in cutouts
Nests converted from another CAM system carry its seam overcut inside the
clean contour: the last cut runs on past the contour's own start along its
first cut, then a straight jog returns to the start. The ring then touches
itself at its seam, so neither the cutting planner nor the overlap analyzer
could certify it and the whole plate refused.

SeamOvercut recognizes exactly that shape (same line, or same circle and
direction) and trims it from an owned copy; the retraced tail encloses no
area, so material is unchanged and the drawing is never edited. Any other
self-contact still refuses. Arcs of one circle whose centers were each derived
from their own endpoints agree only within Epsilon, so their spans are now
compared at the seam tolerance: shared spans still refuse as overlap, while
arcs that only meet at a joint or lie apart no longer do.

Plates with parts nested in other parts' cutouts then failed to route, since
the host is cut last and every straight approach from the middle of a crowded
cutout crosses a finished neighbour. CuttingNestedOrder tours each host's
inner parts as one run ending beside the host's own contours, hosts follow
the parts beside them, and learned rules still win. Outside entries are
ordered by clear sight lines to the next cut, the look-ahead toward a host is
its nearest contour point rather than its centre, a cutout containing the
arrival point is routed from that point, and a pass that teaches an order
rule ends the round instead of repeating the blocked approach.

Tests: SeamOvercutTests and CuttingNestedOrderTests; the cutting-planning,
diagnostics and overlap tests in OpenNest.Tests pass (1023 passed, 6 skipped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:40:32 -04:00
aj 565dc90762 refactor(ui): rephrase negative-tone disclaimers as affirmative guidance
Report, dialog and diagnostic text across post verification, cutoff
planning, alignment and cutting-plan review repeatedly told the user
what checks weren't (safety certifications, proof, guarantees) instead
of what to do. Reworded these to state the same caveats affirmatively
(inspect X, confirm Y, review Z) without changing the underlying
safety guidance, and updated the tests/docs that pinned the old wording.
2026-10-12 07:45:23 -04:00
aj 9bd5d0dfa7 fix(cutting-ui): navigate selected source plate in planner 2026-10-11 22:45:54 -04:00
aj d6ae706098 refactor(cutting-ui): retire redundant planning and validation forms 2026-10-11 22:15:35 -04:00
aj f9b2e1282a feat(cutting-ui): inspect live nest validation in docked panel 2026-10-11 21:55:59 -04:00
aj 943b63937d feat(cutting-ui): plan and apply all plates from docked panel 2026-10-11 21:40:26 -04:00
aj 4738a0390e feat(cutting-ui): inspect one proposal on the main canvas 2026-10-11 21:21:07 -04:00
aj ddc4710dfd perf(cutting): defer alternate hole entries in preferred pass 2026-10-11 20:26:47 -04:00
aj 97a468ee2c fix(cutting): recover checked routes through interlocking holed parts 2026-10-11 19:51:29 -04:00
aj 08acb092a7 fix(cutting): anchor near-corner entries to their native edge 2026-10-11 01:14:50 -04:00
aj ca6966906f Support direct contour piercing and correct planner geometry checks 2026-10-10 16:44:03 -04:00
aj 90ae3b6a84 Fix false self-intersection warnings at rounded contour joints 2026-10-10 15:57:16 -04:00
aj 17e504fb70 feat(cutting): navigate diagnostic rows in enlarged planner 2026-10-10 11:37:57 -04:00
aj 1c6d02c480 perf(cutting): try a bounded entry catalogue before full search 2026-10-09 21:26:40 -04:00
aj d328c5f691 perf(cutting): generate ranked alternatives only when visited 2026-10-09 20:40:10 -04:00
aj 7e887921ea fix(cutting): expose every unverified warning before consent 2026-10-08 13:50:12 -04:00
aj 81f3c006ab merge: integrate best-effort cutting on current master 2026-10-08 13:34:05 -04:00
aj fc300705a8 fix(cutting): aim round cutouts toward the next cut 2026-10-07 20:55:40 -04:00
aj 1c923976a8 fix(cutting): explain missing leads and suggest clearance remedies 2026-10-07 17:50:31 -04:00
aj f4d5cfe98e fix(ui): translate absolute-coordinate part paths by placement
Build paths in the drawing-local frame and translate both ordinary and split cut/lead paths once, without changing CNC programs. Add native Windows regressions using the operator's synthetic G90 fixture and incremental controls. Four absolute-mode cases fail before the fix; all seven pass after.
2026-10-07 17:22:06 -04:00
aj 9196d9157f fix(cutting): reuse clear candidates across side coverage scans 2026-10-07 16:05:25 -04:00
aj 64459f7bc8 fix(cutting): try endpoint alternatives before hole combinations 2026-10-07 15:21:09 -04:00
aj 414e9b4e75 fix(cutting): prefer hole entries facing the next contour 2026-10-07 14:58:23 -04:00
aj d4544ea358 fix(cutting): aim perimeter entries toward the next part
No-hole parts now choose the outside entry through the S03-S08 pipeline
at the part boundary: rank the native catalogue toward the NEXT cut's
placed-material centre, lazily certify each emitted lead with the shared
validator, cap at maxEntries with side coverage. The next cut is the
next unfinished part on the supplied order (re-read after every
learned-order replan) or, in sequence-free fallback, the nearest
dependency-ready remaining part with stable ordinal ties; the last part
has no target and ranks by tier then arrival distance — never the plate
origin. Target and arrival are converted to prepared LOCAL coordinates
exactly once; geometry is already rotated.

The look-ahead rank survives Follow's ordering: children sort by
nearest source first (the sequence-free tour stays nearest-first), then
contour, then the selection rank — plain OrderBy(Distance) can no longer
undo the facing. Measured fixture (three squares, 0.15 leads, origin
start): legacy cut every sheet at its arrival-nearest lower-left corner
with 10.5-unit cross-sheet rapids totalling 21.0; look-ahead cuts the
+X-facing corner with the same 21.0 total but each inter-part rapid now
starts at the facing edge instead of trailing across the whole sheet.

Uncertain validator answers are never precheck-refused: they skip the
selected slots but flow to the emitted-prefix Check and complete replay,
which stay the authority — a refused-looking incomplete is reported,
not hidden. A fully evaluated catalogue with no fitting lead surfaces
'No tested lead-in fits on part N, contour M'; budget exhaustion stays a
budget finding. Lead prechecks count separately from DFS expansions; the
pipeline itself is one counted expansion per contour. Full backtracking,
dependencies, locked/fixed programs, cutoff handling, emitted-prefix
Check and complete replay are unchanged; budgets and CuttingPartOrder
untouched. Hole parts keep the legacy path until S12.
2026-10-07 11:01:08 -04:00
aj 12206ed8fd feat(cutting): offer unverified best-effort plans for imperfect geometry 2026-10-06 14:44:53 -04:00
aj 18a61717fe fix(cutting): accept tangent line-arc joints in material capture
Plan Cutting refused ordinary filleted parts with "Native contact query is
numerically uncertain." Material capture checks every curve pair of a ring,
adjacent ones included. Where a line meets a tangent arc at their shared
vertex, rounding can drop the tangent root of the native line/circle
quadratic; the exact ray cast from the line's far end then reached the
vertex, which is already recorded as an endpoint contact, and was read as a
contact the native query missed. Rounded rectangles rotated off-axis were
refused 1037 times in 1080 before this change and 0 times after.

The exactness rays now stop short of a line endpoint the other curve already
contains (half-way from each end when both are contained), so together they
still cover every other point of the line and any unrecorded contact still
refuses. The native kernel and tolerances are unchanged.

Regressions: four tangent-fillet rings and a rotated filleted part planned
through CuttingPlanBatch (red before, green after); a line ending inside a
small circle's contact band stays uncertain in both directions. Mutations that
treat either endpoint as always contained, drop the start ray, or count
recorded endpoints as native contacts all fail.

Project Memory: 41880037
2026-10-06 10:37:07 -04:00
aj ea1270e1e7 fix(cutting): check every lead against all other material again
The second delta review compared the filtered checks with the previous
implementation on 5,400 generated cases. Rapid checks matched in every
case, but 114 lead checks differed: a long lead passing a small circle
or arc well over 0.001 away was reported clear, while the native
line/circle query, through rounding in its squared terms, reports a
contact there. A coordinate limit and a fixed margin cannot bound that
cancellation.

Lead checks therefore examine every other part's material again,
exactly as before the filter; LeadMaterialSnapshot no longer keeps an
extent. Rapid checks, including the pre-post review's, keep skipping
completed contours more than 0.001 clear of the rapid. The 900000-long
lead beside a radius-0.0001 circle is a regression test.

Planning a dense 144-part grid now takes about 19 s again (lead checks
dominate); a new part order is still found where the old search gave
up.
2026-10-06 00:47:46 -04:00
aj 8c21c62ec3 fix(cutting): skip checks only for well-clear, well-conditioned extents
The delta review found two more ways the extent filter could skip a
check a native query would have flagged:

- Native line intersections accept points 0.00001 outside each line's
  bounding box, so a lead 0.000003 from another part touched it while
  their extents were 0.000003 apart, beyond the 1e-6 margin.
- Around a circle of radius 5e11, rounding let the native query count
  a rapid at x = -0.00001 as touching although the circle's extent
  started at x = 0; the margin scaled only with the rapid's own size.

Rather than chase each tolerance, the filter now has one narrow rule:
Extent.IsClearOf skips only when both extents are finite, lie within
1e6 and are more than 0.001 apart on some axis. 0.001 is ten times the
widest absolute band of any native contact query (the 0.00001 box
allowance and the 0.0001 contact reach of tiny arcs), and within 1e6
rounding stays far below it. Larger geometry is always checked in
full, as before the filter. Planning speed is unchanged (144-part grid
about 0.5-0.8 s).

All three reproductions are regression tests, with a test of the rule
itself.
2026-10-06 00:20:41 -04:00
aj 1c0320d17e docs(cutting): describe the arc contact band in the extent filter
Follows c1c8d5f and c21f687: an arc's extent is its supporting circle widened to the native contact reach, and an extent with a nonfinite bound is never skipped.
2026-10-06 00:07:39 -04:00
aj 4e6419fd2c fix(cutting): fall back to a full order search when learning stops
Review found a plate the previous search planned that the tour now
refused. Left leads in on its left and right on its right, so right
straight after left crosses left and left straight after right crosses
right. Learning "right before left" then contradicted "left before
right" and the search returned ConstraintConflict, although cutting a
third part above them in between is safe.

A blocked approach only proves that one part cannot follow the parts
cut so far from that position, not a global order, so learned rules
stay a heuristic. Once nothing new can be learned, the remaining budget
now goes to a full search over every ready part, nearest first (the
search used before the tour). A rule contradicting an order already
required is still skipped rather than ending learning early.
2026-10-06 00:04:05 -04:00
aj 2419a9e2e3 fix(cutting): give a new part order the plate's expansion budget
The desktop batch searched for a new part order with the flat 20000
default and kept the current order with 400 expansions per part. A new
order now also plans contour order and entries for every part (about
260 expansions per part on a dense grid), so a 100-part plate ran out
of budget and fell back to the current order. Both attempts now get
PlateBudget: 400 per part, at least 20000. The constants are renamed
MinimumExpansionBudget and ExpansionsPerPart to match.
2026-10-05 23:41:16 -04:00
aj b8f3d3bf0a fix(cutting): order parts as a short tour and learn blocked approaches
Free-order planning was one depth-first search over parts, contours and
entries. A dead end at one part backtracked through every entry
combination of the part before it (about 1,450 for a square with two
holes) before trying another part order, so a 4 x 4 grid of such parts
ran out of its 20000 expansions (and 200000) although cutting it row by
row is safe.

The whole-part order is now an open travelling-salesman path over part
centres from the start point: nearest neighbour, then 2-opt reversals
and Or-opt moves of one to three parts, never placing a part before a
cutoff or nested-part prerequisite. The existing search then plans
contour order and entries along that order. If a part cannot be
reached without crossing parts already cut, the search learns "cut it
before those", backs up to just before the earliest of them, keeps the
parts cut before that point and re-plans the rest from the tool
position there. An attempt stops backtracking after 8 x entries x
contours expansions without getting further, so it learns instead of
retrying the entries of every earlier part. When nothing new can be
learned the result is a refusal, as before. A preserved order is
planned exactly as before.

16- and 36-part grids, in row order and shuffled, are now ready within
the default budget (they were NoSolutionWithinBudget); a 144-part grid
plans in about half a second.
2026-10-05 23:41:11 -04:00
aj bfe2e518e6 perf(cutting): skip lead and rapid checks against distant material
Every lead was checked against every placed part's material and every
rapid against every completed contour, so each check cost O(parts) and
planning a plate cost O(parts^2). Lead checks were 88% of planning time
on a 144-part grid.

LeadMaterialSnapshot and each completed contour now keep a conservative
extent (an arc counts as its whole supporting circle). A lead or rapid
skips material or a contour only when the extents are farther apart
than 1e-6 x (1 + coordinate size), far above the contact tolerance, so
results are unchanged: anything touching or closer still gets the full
native check. The rapid filter also applies to pre-post verification,
which shares ReleasedContourState.

New tests cover the cases just inside the skip: an arc lead and a
completed arc whose bulge reaches past their endpoints, and a lead and
a rapid that only touch another part's extent.
2026-10-05 23:41:02 -04:00
aj 48367da820 fix(diagnostics): refuse absolute subprograms instead of normalizing
1b422ef read absolute-mode hole subprograms by converting an
incremental-mode copy of every clean program. Rebuilding absolute
endpoints from incremental deltas is not exact: after a rapid at
1e12 a 1x10 rectangle moved by about 2.4e-5 and a real 2e-5 overlap
was reported clear, in the overlap overlay and pre-post verification
as well as Plan Cutting.

Convert programs directly again, which reads absolute coordinates
exactly, and refuse an absolute-mode subprogram as an incomplete
check instead: the converter adds a call's frame offset to
incremental moves only, so it would read such a hole at its frame
origin. OpenNest writes hole subprograms in incremental mode. The
null-list and unknown-instruction refusals from 1b422ef stay, and
CopyForGeometry is private to the planner again.
2026-10-05 22:04:47 -04:00