Commit Graph
234 Commits
Author SHA1 Message Date
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 e897258a85 feat(cutouts): reconcile repeated frames and inserts through one solve 2026-10-09 20:36:43 -04:00
aj 138c86526a perf(cutting): reuse native curve wrappers for lead queries 2026-10-09 19:15:28 -04:00
aj 0b29c683b9 feat(cutouts): trial physical composite reconciliation in pipeline 2026-10-09 18:57:31 -04:00
aj 1d50c6ce60 feat(cutouts): compare measured ratio routes and certify leftovers 2026-10-09 17:47:12 -04:00
aj 962ae8c825 feat(cutouts): propose bounded mixed lattice and NFP inserts 2026-10-09 17:20:41 -04:00
aj d3e325f36c fix(ui): restore manual part sequencing and close control 2026-10-09 17:06:17 -04:00
aj 41737a4f4c feat(mcp): complete jobs with finite mixed sheet stock 2026-10-09 13:14:34 -04:00
aj f1d1df3f17 fix(mcp): preserve job constraints and compatible stock 2026-10-09 12:34:30 -04:00
aj 81404fc673 feat(mcp): complete whole jobs across matching plates 2026-10-09 12:22:40 -04:00
aj a5b6c8a00e fix(mcp): warn on unmet quantities rather than sheet ratio 2026-10-09 11:09:51 -04:00
aj 2a6e5504cd fix(mcp): report zero packing demand accurately 2026-10-09 10:52:41 -04:00
aj 3d5c73a353 fix(mcp): report requested and placed drawing mix 2026-10-09 10:48:59 -04:00
aj 8b94e49711 feat(mcp): delete unused session plates 2026-10-09 10:45:28 -04:00
aj 028adee046 ci(release): pin Poppler for Windows PDF verification 2026-10-08 19:42:13 -04:00
aj 3ddfff242d fix(test): read PDF text by visual rows across platforms 2026-10-08 19:36:33 -04:00
aj a73a85ebc0 ci(server): skip image publication for GitHub prereleases 2026-10-08 19:17:15 -04:00
aj 8628c69098 fix(ui): settle shift-click cloned parts with repeated directional pushes 2026-10-08 18:57:39 -04:00
aj c1c4b18f17 fix(ui): keep closed etch-only parts selectable 2026-10-08 13:50:12 -04:00
aj 7e887921ea fix(cutting): expose every unverified warning before consent 2026-10-08 13:50:12 -04:00
aj f50705c491 merge: integrate golden-angle Workshop colors 2026-10-08 13:34:23 -04:00
aj 81f3c006ab merge: integrate best-effort cutting on current master 2026-10-08 13:34:05 -04:00
aj b83518feac merge: integrate reviewed cutting-start planner fixes (#10)
Preserve reviewed cutting-start and plate-label commits; operator accepted A1-A4 and B1-B7. Excludes best-effort cutting and color trials.
2026-10-08 11:01:21 -04:00
aj 1826e6d5b5 feat(ui): add Workshop palette with distinct drawing colors
Keep cut outlines dark and etch strokes bright green. Assign drawing fills by a golden-angle hue walk with varied saturation/lightness tiers, preserving legacy schemes and rendering-only behavior. Include palette, visibility, persistence, and contrast regressions.
2026-10-08 10:24:11 -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 91aef95b1b fix(tests): acknowledge native BOM dialog without assuming button id
Fix DuplicateRows_CreateNestsButtonImportsOneDrawingWithCombinedQuantity timeout from Windows run 37526243901. Native trace on DesktopPC showed the sole OK button uses control ID 2, not IDOK 1. Preserve real dialog text and nest assertions; find the sole button and stop polling only after successful posting. All 392 WinForms and 49 FrontEnd tests pass in an interactive Windows session.
2026-10-06 16:52:52 -04:00
aj b591528aa2 ci(windows): retain fail-closed desktop acceptance evidence 2026-10-06 15:56:27 -04:00
aj 12206ed8fd feat(cutting): offer unverified best-effort plans for imperfect geometry 2026-10-06 14:44:53 -04:00
aj 89356371db feat(mcp): describe each engine in autonest_plate and default fill tools to Fill
The engine argument's description now names every built-in engine with what
it suits, so a model can choose one; omitting it still means Default. The fill
tools resolve an omitted strategy to Fill directly instead of through the
session's whole-job default. Front-end tests cover the MCP and console
defaults and keep the description in step with the registry's built-ins.
2026-10-06 12:26:19 -04:00
aj 5af44b251c feat(engine): make Default choose between Irregular and Rectangles per job
Default is the engine every front end uses when none is named. It now runs
Irregular, then Rectangles, checks both layouts with NestLayoutCheck and keeps
the best: valid first, then fewest unplaced parts, then lowest salvage-credited
cost; ties keep Irregular. A candidate that throws or returns nothing is
skipped, cancellation stops the search, and only the chosen layout's plate
commits are reported. Neither engine wins every job in the lane benchmarks,
and Rectangles adds little time while also covering Irregular's invalid
layouts.

The registry lists Default first and no longer maps the name to Fill; fill
strategy callers still read Default as Fill. A future circle/ring engine joins
as another candidate.
2026-10-06 12:26:10 -04:00
aj 0a1d021bf7 refactor(engine): rename the Default engine and fill strategy to Fill
The multi-phase lattice fill (linear, pairs, rectangle best-fit, remainder) is
no longer meant to be the engine used by default, so it gets a name for what
it does. The registry lists it as Fill and maps the old name Default to it;
PlateFillService, PlateNesterFactory and NestJobOptions use Fill, and every
fill-strategy caller still accepts Default. Console --autonest now validates
engine names through NestingEngineRegistry.ResolveName so renamed names work.

Layouts are unchanged: Default and Fill resolve to the same fillers and the
golden layouts pass under the new name.
2026-10-06 12:11:03 -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 bec4db21a8 merge: integrate ci/parallel-tests
Runs the four cross-platform suites as a matrix and the six synthetic
Irregular nests in their own job, with a fail-closed final "tests"
check.

Conflict in ci.yml: take the branch's Linux jobs and keep master's
windows-desktop job unchanged after them. actionlint and the aggregate
checker self-tests pass on the merged file.
2026-10-06 06:41:06 -04:00
aj bc061488ee merge: integrate refactor/menubar-reorg
Brings in the Plate menu reorganization, Database-mode drag-and-drop
open, the SavedNestsForm look fixes and the Irregular block-fill work
budget fix.

Conflicts:
- MainForm.Designer.cs: keep the branch's Plate menu order (Arrange
  submenu, View in CAD last) and add master's Plan Cutting item ahead
  of the lead-in commands.
- SavedNestsForm.cs: keep master's browser rewrite (details, preview,
  columns) and apply the branch's intent to it: open maximized with
  MaximizedBounds clear of the taskbar, the lighter grid palette on all
  three grids, and B/KB/MB/GB file sizes.
2026-10-06 06:39:41 -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
aj 8590f21c9c fix(cutting): block overlapping plates and preview only fresh plans
Review fixes for the Plan Cutting batch and dialog:

- A plate whose clean part material overlaps, or cannot be checked
  for overlap, is no longer ready, whatever its route. The batch
  captures each plate's material with PlateOverlapAnalyzer on the
  owner thread, analyzes it on the worker, and names both parts.
  Before, two overlapping squares were Ready and Apply regenerated
  them (plan section 4.2: overlap warnings are not waived).
- BuildPreview returns null for a refused plate, whose program graphs
  may be unsafe to copy (an unsupported instruction's Clone ran, and a
  cyclic subprogram overflowed the stack), and for a plate that
  changed after planning, which drew the replayed program at the live
  pose. The dialog then shows no preview and says why.
- The dialog plans with its own copy of the caller's settings, shows
  a failure message if a plan cannot be presented, and has a worker
  seam so the close-while-planning test holds the worker instead of
  racing a slow search. Form tests now observe the planning task.
2026-10-05 21:39:58 -04:00