A 5 x 5 right triangle fits both its legs' square and its hypotenuse's
7.07 x 3.54 box, each of area 25, and rotating calipers kept whichever
rounding found first, so the same gusset measured 5 long at one rotation
and 7.07 at another. Of rectangles tied for least area, measure the one
with the shorter long side, so length, width and the tab tie-break no
longer depend on placement.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plans every occupied plate of every .nest file in a local folder the way
Plan Cutting does after clearing lead-ins and cut-offs, and writes one
JSON line per plate with its outcome, warnings, fallbacks, expansions,
time and spacing pairs. It is how the reliability sweep found its
failure classes over 1,260 production plates; the nests and the report
stay outside the repository, and the test skips without the folder.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contour recovery tries each outside entry's hole-tour search first for a
part with at most 16 holes, and the reading-order sweeps after them; once
the searched entries had spent the recovery allowance it jumped straight
to the widened tries and never swept. A frame cut from inside its own
cutout, after the strips nested there, is often routed only by a sweep,
which leaves the cutout on its far side toward the outside entry beyond
it, so such plates fell back to the safest route with head raises or to
no plan at all. The sweeps now still get their few expansions per hole,
bounded by the whole budget. On the production corpus six plates went
from a safest-route or head-raise fallback to a strict plan, five kept
fewer raises, one blocked plate gained a safest route, and none got
worse; the problem-nest corpus is unchanged in every outcome and share.
No synthetic plate reproduced the exhausted allowance yet, so the corpus
guards this change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
With a pierce diameter set, every internal contour whose configured
pierce is inside the zone is resolved by flattening the cutout, finding
its pole and eroding it, and the search emits a part's whole chain again
on every expansion, so on parts with dozens of such holes almost all of
the planning time went there: three 1,600-motion parts took 41 minutes
and timed out in production. The resolution is a pure function of the
hole, the entry, the configured lead-in, the zone and the turn, so each
preparation now keeps it by contour ordinal and reuses it, unchanged,
across its emissions and copies. The same plate plans in 148 s.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A fillet whose circle is tangent inside the arc it continues, as a
keyhole's slot ends are, gives the supporting-circle query of the pair
no real root: the circles' distance is the radii's difference up to
rounding, so the intersection comes back NaN, and the unfiltered check
that runs before any adjacency handling refused the whole part as
"nonfinite program coordinates". On the production corpus 17 plates
failed this way. Adjacent curves are now resolved from their shared
vertex before the native query would run, so no query runs for them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two curves that meet end to end share that vertex, but every contact
check asked the native intersection query about them, and it is
ill-conditioned there: two circles meeting at a shallow angle (a fillet
continuing into a larger arc) or a line meeting its fillet put their root
up to 1e-5 off the joint when the DXF arcs were rounded apart from their
neighbors by 1e-9. Material validation then refused the part as
self-touching, and the open-cut proof read a tabbed perimeter's fillet
joint as a loop, so with support tabs on every such part lost its
retention proof and its plate came back blocked. On a corpus of 1260
production plates this was the largest planner failure class: 61 of 67
NoSolutionWithinBudget plates, all planning once the joint is exact.
Contacts now report an adjacent pair's shared vertex itself and derive
the pair's other intersection from it analytically (two circles meet
again at the vertex's mirror image across the line through their
centers; a line meets a circle again at the far end of its chord),
keeping it only on both finite spans. No tolerance grows: a genuine
second crossing beside the joint is still reported, and overlapping
spans still refuse.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A server Auto Nest result could only be reviewed in the session that sent it,
and nothing stopped two desktops from keeping the same result. Phase 3 adds
My Server Jobs, so results that finished while OpenNest was closed are easy
to find, and records each review on the server.
- Server: GET /api/nest-jobs lists jobs newest first with state, engine,
submitter, times, queue position, review and the worker's summary (parts,
sheets, utilization, unplaced). It filters to active, finished or
unreviewed jobs and to a submitter (a bare user name matches that user on
any workstation). An ETag turns unchanged polls into 304s. Schema v17 adds
nestId, review and summary columns, only where missing.
- Keep once: POST .../keep and .../discard take If-Match on the job revision
and change an unreviewed result only once. A second desktop gets 409 with
who kept it. DELETE removes finished jobs. A succeeded job keeps its
package until it is reviewed, so a later session can rebuild the job.
- Retention: OPENNEST_JOB_RETENTION_DAYS (default 7) deletes finished jobs
with their results. It runs on claims and list reads. A malformed value
fails startup instead of deleting results early.
- Worker: reports the result's summary with the transcript. A job cancelled
while its result arrived keeps no summary (found in the Docker smoke run).
- Desktop: Nest > My Server Jobs polls the list every 3 s; polling rather
than per-job SSE because the list must show other desktops' jobs and
removals. Open rebuilds the job from job.json against the open nest's own
drawings. New per-drawing geometry fingerprints make the freshness check
work across sessions. Cancel Job and Remove act on the selected job. A
status-bar item counts this user's results waiting for review; there is
no popup. Auto Nest's review now records Keep on the server before it
commits, and records Discard too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A server Auto Nest showed only "Nesting on the nest server" for however long
the job took, and Stop could take a whole 20-second heartbeat to reach the
worker. Now the desktop shows the same Best plan so far strip a local run
does, and a job that ends while OpenNest is in the background says so.
- Worker: RecordingNestingEngine taps each solve's progress. NestJobReporter
stores only the latest stage and plan, at most once every two seconds, so a
chatty engine cannot flood SQLite. Each round also reads the cancel flag,
so Stop reaches the worker within one interval (about 2 s in the Docker
smoke test).
- Server: schema v16 adds per-job revision, progress, plan and planRevision
columns, which the upgrade adds only where missing. PUT .../progress and
.../plan renew the lease like a heartbeat. GET .../events is Server-Sent
Events, woken by an in-process change signal: plan and job events with
revision ids, keep-alives, Last-Event-ID resume, and the final state always
sent before the stream ends. GET .../plan serves the polling fallback.
Progress goes over HTTP because the worker never opens the database
(another host, NFS).
- Desktop: NestJobWatch follows the stream. When the stream drops it polls
once and reconnects, and it polls throughout when the server has no stream.
RemoteNestPlanPreview draws worker plans from the client's own request,
including cutout-trial frame proxies. ServerNestNotice shows a tray balloon
(a toast on Windows 10/11) when the job ends while OpenNest is not in
front. A real toast would need an AUMID shortcut that Velopack does not
promise. Clicking the balloon brings the review forward; nothing is kept
without Keep.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Large nests tie up the workstation that runs them. In Database mode, Auto Nest
can now queue the job on the nest server, where a worker container solves one
job at a time under its own CPU and memory limits. The job has no time limit,
so a throttled worker finds the same nest a fast one does, only later.
- Server: /api/nest-jobs queue (schema v15). The worker holds a job on a
heartbeat lease. When the lease lapses, the job goes back to the queue,
or fails after three attempts. Only one job runs at a time. Packages and
results are opaque to the HTTP server, which stays off Engine and IO.
- Worker: OpenNest.Server.Worker in the same image (OPENNEST_ROLE=worker),
reaching the server over HTTP only. It records each engine answer with
RecordingNestingEngine and gives its job back on shutdown.
- Desktop: "Nest on the server" in the Auto Nest dialog, for built-in
engines only. The client replays the recorded answers with
RemoteNestSubmission, so validation, the review and Keep run locally
against the client's own drawings, exactly as after a local run. A
drawing edited after sending refuses the result. If the server cannot
take the job, the user may nest locally instead.
- compose.server.yaml adds the throttled worker service. The Dockerfile,
.dockerignore, CI paths and the deploy script now include the worker's
projects.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reopening a nest regenerated its cut-offs with built-in defaults (no
overtravel, a different minimum segment) rather than the machine's
settings it was made with, so a nest saved, reopened and posted could
cut scrap that never separates. Plates now record the settings their
cut-offs were last generated with, and files carry them; older files
still load with the defaults.
Saving over a nest file truncated it before writing, so any failure
part way lost the only good copy, and the error reached the user as an
unhandled exception after the save path had already changed. Nest and
settings files are now written beside the target and swapped in, and a
failed save is reported with the old file left intact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ahead of the new laser schedule, three ways a post could silently cut
with the wrong process, and one way its settings silently reset:
- Cincinnati CL wrote no G89 when no cut library matched the nest's
material, thickness and gas (or no etch library for etch features),
so the controller cut with whatever library it loaded last. It now
refuses, unless the new "Require libraries" setting is turned off.
- Cincinnati CL declared G20/G21 from its own setting without comparing
the nest's units, so a metric nest posted 25.4x too large. It now
refuses a mismatch.
- CI Fiber posted any material missing from its table as the default
code (MSN), so stainless or aluminum ran with mild-steel technology.
A named, unmapped material is now refused; the default code covers
only nests with no material.
- Posts saved their settings beside their DLL, inside the install
folder a Velopack update replaces, so every update reset them to the
shipped defaults. Saves now go to %APPDATA%\OpenNest\Posts and the
shipped JSON only seeds them; constructing a post no longer writes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PartSupport findings counted toward the headline and the Post Anyway
checkbox but had no tile or list group, so an operator saw "1 warning"
with nothing to read and was likely to tick through a part that may tip
once cut free. A test now fails if any finding kind is left unlisted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A support-tabbed part that no single tab can hold level was limited to its
one steadiest entry. Two strips stacked in a frame's cutout then blocked
the plate: from the upper strip's only entry, every route to the lower one
crossed holes already cut. Its other entries clear of inside corners now
follow the steadiest, in the search and in contour recovery; the part is
still tabbed and still warned about. Parts a tab can hold keep their
steadying entries.
The unverified headline also named fixed lead-ins when the only warning
was a part that may tip; it now says what needs review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every part the support grid could not hold level got a tabbed perimeter
with the outside lead-out after its tab, and planning refused any lead-out
after its own open cut, so with a lead-out configured no such part could
be planned. Pre-post review already proves such cuts release nothing (the
lead-out stays out of the tab gap); planning now runs the same proof, so
planning and review agree and a lead-out that reaches into the tab is
still refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The grid was added to check the whole library for drawings that freeze
a preview; it is a testing tool, not an operator feature. The form and
its test stay for future library checks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The best-fit filter rejected pairs over a 5:1 aspect (or the plate's)
unless 75% utilized. A long part such as U251-DET3 (27.4 x 3.5, aspect
7.7) is past that alone, so its tightest interlocked pairs (5.1:1) were
all dropped even though they are less elongated than the part itself.
On the 60 x 120 sheet that cost 12 parts: 66 placed instead of 78.
The limit now widens to the part's own bounding-box aspect, so
side-by-side pairs survive while end-to-end pairs of compact parts are
still rejected.
The learned-angle characterization nests re-captured: their 46 x 3 bar
now nests as an interlocked pair, which left the Fill nest identical to
a full sweep, so the notched quantity drops from 6 to 4 to keep the
fixture sensitive to learned angles.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Drawing Library Grid check found seven drawings with 1,000-1,700
holes (90-6138-26/27, Reeves bakery vent pans, 4938 A15) that took
0.5-3.6 s to preview, all of it in the part label point.
- PolyLabel skips a hole's containment test outside its bounds and its
edge distances when its bounds are farther than the nearest edge so
far. Both skips leave the result exactly as before; label points on
all seven drawings are unchanged and the search is 4-35x faster.
- ShapeBuilder.GetShapes rescanned every remaining entity at each
chaining step. An endpoint grid now finds the candidates, tested in
list order with the same checks, so chosen entities, reversals and
shapes are identical (compared against the old loop on the library
drawings and 300 random entity soups). 90-6138: 700 ms -> 40 ms.
- The label builds its shapes once: ShapeProfile.FromShapes reuses the
ones it already chained instead of chaining them again.
Previews of all seven now take 57-166 ms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
File > Drawing Library Grid shows a page of library drawings side by
side. Check All Pages walks every page, downloading each drawing, timing
its label search without the paint's cell budget on a worker with a
10 s limit, then timing its paint, and lists drawings that fail, run
slow or would freeze a preview. It was added to confirm no other library
drawing hangs on load the way the twin-outline drawing did: a run over
all 40,757 drawings on the work server found no hangs or failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A drawing of two equal, separate outlines (RC-204441A23 PT13) froze the
drawing library preview. ShapeProfile takes one outline as the perimeter
and the other as a cutout, so the net area is rounding noise and
ThicknessPrecision fell to 1e-9. A rectangle's pole is a whole ridge, so
the label search refined it into billions of cells on the UI thread.
Net area negligible next to the outline now falls back to the outline's
own width, and the paint-time label search has a cell budget so no shape
can stall painting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The drawing list only showed nest-wide totals, so seeing how many of a
drawing a layout holds meant counting parts by eye. Prefix the nested
line with the current plate's count, e.g. "[78] 144 of 1 nested".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--autonest without --quantity nested one copy of each drawing, so a
118-part job of 67 drawings solved as 67 parts and reported success.
Default to the required quantity less copies on other plates, which the
run keeps; drawings without one are left out, as on the desktop, unless
no drawing has one. --quantity still overrides.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Search insert selections as boxes with a counted beam search over maximal
free rectangles, pair low-density parts with their half turn, then gap-fill
with the frontier packer. The router takes it on seated outline area.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compare cutout proposals, frame angles and bundles by insert outline area,
and add bounded largest-first packer candidates so big parts get the first
move in an empty hole. On the real job the four frames go from 54-70% to
77-81% filled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The spiral used only the least-waste rows and columns. Those often make
one pair of blocks the larger on both axes, so it overlapped itself and
placed nothing, leaving Fill at two blocks. It now also tries every
four-block combination and takes one that holds more parts than both the
least-waste spiral and the two-block layout, so ties keep today's layout.
A 9 x 6.5 part on a 60 x 120 sheet goes from 109 to 112.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Long fills read as thousands of milliseconds. Keep milliseconds under
a second, then show seconds and minutes so the time stays readable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An empty canvas corner gave no sign of whether a check was still running,
which matters on large nests. A Layout section beside utilization now
follows the automatic check: checking, OK, or findings in red, with the
full wording in its tooltip. It has its own label so rechecks never
replace the last command's status text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the check mark: a clear result, and an automatic recheck after one,
now draw nothing. Findings and failed, canceled or incomplete checks keep
their text, and views without automatic rechecks keep their pending text.
The status bar still reports a manual check's result.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pending or running recheck no longer swaps the green check for status
text. A clear result stays as a gray check, and earlier findings stay as
dimmed text, neither of which claims anything about the edited layout.
Views without automatic rechecks still ask for a manual check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The overlap check now runs the pre-post part spacing scan on its snapshot,
so the canvas label and posting agree. Too-close pairs are counted in the
label and marked with an orange ring showing the gap, with hover details.
A fully checked plate with no findings draws a green check instead of
text; the status bar keeps the wording. Changing the plate's part spacing
now stales the report, and repeated parts share one offset outline so
automatic rechecks stay fast.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Fill engine rename changed McpFillToolsWithoutAnEngineUseFill to
...UseLattice, so the acceptance check failed on a missing test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Fill" said nothing about what the engine does, since every engine fills.
It is now Lattice, and Fill stays an alias, so saved selections, scripts
and API requests keep working. Engine descriptions are rewritten in plain
language and shown beside each name in the desktop engine lists; the main
toolbar's tooltip also says when Fill Area falls back to Lattice.
Docs also cover the leftover placement from the previous commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A quantity-limited fill trimmed the parts farthest along the trim axis,
which could take one half from each of two pairs. TrimToCount now finds
interlocked pairs and keeps or drops them whole (from d1d68a91), so the
spare space stays one usable cell.
After a fill, leftovers now run in two orders, pack-first and pairs-first,
and the strategy's comparer keeps the better whole layout, so its ranking
of this step cannot get worse. Even quantities go in as best-fit pairs,
may turn a quarter when unrestricted, are tried in every remnant and are
ranked with the layout around them. Each placed pair slides left and down
against true outlines to take the space its bounding box could not.
On compare.nest Vertical Remnant goes from 6665.1 to 5862.6 and Lattice
from 7200 to 5915.8. Nine characterization pins change from the trim with
counts unchanged; the fill pins now also check layout validity. Vertical
Remnant's golden layout shortens from 28 to 26.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
F1 opening help kept taking over from placing a part. Help stays on
the Help menu and F1 belongs to the Clone tool alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whole-job fills treated clamps as occupied space, so a clamped edge cost
a row: 8.25in circles stopped at 96 on a sheet the plate fill packs with
102. When one drawing still has unmet demand, also fill the sheet as if
the clamps were absent, drop the parts on them and keep the better
layout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A cut-off always runs away from its fixed edge: the origin side, the only
edge guaranteed to be a real sheet edge. The part order is proposed as a
traveling-salesman path over one point per placement, and a cut-off's
point was the middle of its line. The route did not know the tool must
arrive at the line's start and leaves at its far end, so the parts
before a sheet-splitting line finished level with its middle, and the
rapid down to its start crossed parts already cut.
Each placement now has an entry and an exit point; they differ only for
cut-offs (start and departure). Nearest neighbor and Or-opt go on from
each part's exit, and 2-opt costs a reversed run along its own directed
legs; with no cut-off on the plate the exits are not passed and the
symmetric route is unchanged. The part cut before a cut-off faces its
start.
Cut-off direction is not chosen here: the order reads each cut-off's start
and end from its program as given, and the joint search may still reverse a
head-locked far-edge segment.
When a blocked approach teaches an order rule, the search backs up to the
earliest part that approach crossed, keeps the parts before it and
re-plans the rest. The last kept part was planned facing the part that
followed it in the old order. If the new order puts another part after
it, its entry and exit still face the old one, so the plan ends with a
stale exit that a kept-order re-plan of the same order would fix.
Now that part is planned again, in the same place, facing its new
successor; when its successor is unchanged nothing is re-planned.
The locked-among-regenerated fixture's plan changes: rapid 67.60 ->
60.22, expansions 528 -> 268 (digest updated). Learning "cut the
cutoff first" now takes 40 expansions rather than 22, because B is
planned again to face the cutoff; retrying every entry of B took 60.
Plate commands need an open nest and no running job; Trim/Extend Cut-Off
needs a cut-off on the plate and Sequence by Path needs two parts. The
Plate menu's Trim/Extend item follows the same rule.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Irregular's block catalog fills a private plate per part type, and that
fill searched best-fit pairs through the overload that ignores the
token. On one CPU the search can take minutes, so a time limit waited
for it: the converted Nestbolt m-public-gear-1 job under a 60 s limit
ran past 180 s. PrivatePlateFill now passes its token, as PairCatalog
does since 9431006e; the search still finishes in the background and
fills the shared cache.
gear-1, Irregular, one CPU, 60 s limit: killed after 180 s -> stops at
60.0 s (no layout yet; its no-fit polygons are the next bottleneck).
CreatePlate copied a rail-backed stock's zones but not its rail, so the
materialized plate fell back to the bottom edge spacing as its clamp
clearance while every engine packed to the rail's own. With a rail
clearance below the edge spacing, valid layouts from all engines were
rejected as clamp violations. Carry the rail and any removed clamps
across, sharing the rule the commit path already used.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A visual review of the toolbar set found the magnifiers heavier than the
cut icons' outlines, Zoom To Fit's small square ambiguous and Zoom To
Area crowded at 24 px. Thin the ring and handle, let Fit's sheet fill the
glass edge to edge, and give Area longer dashes and a smaller corner lens.
The header gets a fourth zoom button that starts the existing Zoom Window
action, with a matching dashed-window icon also shown on View > Zoom To >
Area. It stays out of the inspection's live zoom controls: inspection owns
Escape, so a zoom window could not be cancelled there.
Redraw Zoom In, Zoom Out and Zoom To Fit in the cut planner and cut-off
palette: slate magnifier, pale glass, the card's 1px shadow, orange +/-
and a part-blue sheet for Fit.
Clone's Delete only removed its source parts, so parts picked with
Select All stayed on the plate until Escape ended the action.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FillEndOdd and FillEndEven had no production callers, so round parts
only got stripe layouts. A Circle strategy now runs them in the fill
pipeline: 8in circles on a 60x120 go from 98 to 112.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FillEndOdd and FillEndEven read Box.Width as the X span, though it is
the Y span, so non-square sheets got the wrong pitch. They also started
centers at the bin corner, leaving circles a radius outside it.
FillEndEven now tries both stripe directions, as FillEndOdd does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows reposts a mouse move when a dialog opens or closes, so Set
Offset Increment threw away arrow-key nudges by snapping the previews
back to the cursor. Only a real cursor move now moves them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Show Original drew nothing until Simplify ran, and then showed entities that
had already been through import cleanup. The importers now capture the
entities before any optimization and the overlay draws those from load, while
Simplify keeps starting from the cleaned entities.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CAM exports often draw a hole as two arcs that overshoot the seam, plus a
short chord back to the start. The Hole Table rejected these contours for
sweeping more than 360 degrees, so drawings like the HT EX flange listed no
round holes.
CadImporter now replaces coradial arcs on one material layer that cover the
whole circle with a Circle, and drops a chord lying wholly on the overlap.
Arcs that leave a gap or overlap by more than MaxSeamOverlap stay as they are.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>