BuildPartPerimeter swallowed every exception. It now guards a missing
program and an outline that forms no shape, and catches only geometry
failures; a null perimeter still makes a cut-off exclude the part's whole
bounding-box span.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Part.CloneAtOffset hands the copy the source's Program instance. The copy
cloned before rotating, but the source still owned the program, so rotating
the source turned the program under every tiled copy while their location
and bounds stayed put.
Program now carries a sticky SharedByParts flag that CloneAtOffset sets, and
a part copies its program before rotating when it does not own it or the
program is shared. The flag lives on the program rather than the part so a
restored cutting state, which reinstates ownership field for field, cannot
re-alias a shared program. Unrotated copies keep sharing one instance, which
the fill and overlap caches key on.
Update, ApplyLeadIns and ApplySingleLeadIn install a fresh program and now
own it, saving a needless copy on the next rotate.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Nothing called MoveTo on a geometry entity or the OffsetEntity(distance,
point) overload. Shape and Arc threw NotImplementedException for them, and
the Line and Polygon versions were wrong and untested. Remove the abstract
declarations and every override; the OffsetSide overload stays.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Nest Info filled a blank Made By with the current user every time it
opened, so pressing OK on an existing nest's info (from a tab or Saved
Nests) signed someone else's nest. The author is now stamped once when a
nest is made (File > New, drawing set Make Nests, BOM import), and Nest
Info shows the stored value as is, leaving a blank one blank.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.8.0 documents the drawing library's Filter dialog and its Size and Holes
columns (b9fc618a), with recaptured library screenshots and a new
library-filter topic. The zip's SHA-256 was checked against the release's
published hash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On an enclosed machine a cutout slug that tips once cut free can stand up
above the sheet and catch the enclosure door when the pallet changes. The
head already keeps off cut cutouts, so this is about clearing the door, not
the head.
Cutting Settings > Cutouts > "Slice slugs the support grid can't hold
level" (CuttingParameters.SliceTippingSlugs, off by default, saved per
machine thickness and written only when on) makes Plan Cutting cut each
such slug along the bed's contact lines (grid rows and columns, slat center
lines) before the cutout, so no piece keeps a contact and the pieces drop
between the supports. Each slice stops a kerf short of the cutout, so the
pieces stay attached until the cutout's own kerf frees them together. A
slug the bed holds level, or one on no contact, is left whole; a cutout
holding another part or another of its part's cuts is never sliced.
Slices are break cuts emitted right after the drawing's own break cuts,
pierced on themselves and led straight back to their start. The
released-contour proof now leaves out straight break cuts lying wholly
inside one of the part's closed holes, since the grid cells they free are
scrap; break cuts in material still take part. The plan fingerprint only
changes when the setting is on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Finding a part on the nest server meant scrolling 40k drawings: the library
could only match an exact thickness or customer and knew nothing about a
drawing's size or holes. The library browser gets a Filter dialog with
inclusive ranges, and the query API takes them.
The server never parses packages and stays off IO, so the server worker now
measures each package beside its nest jobs (bounding sides, net area, closed
cutouts inside the outline) and stores the summary keyed by package hash
(schema v19). Identical geometry is measured once, an unreadable package is
recorded once instead of retried forever, and size or hole limits match only
measured drawings. Thickness ranges compare in inches across units and keep
the library's rule that a drawing saved without a thickness suits any.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guides now use the regrouped File menu labels from ecd0bba4 and show a
recaptured File menu. The release also carries the earlier unreleased guide
updates for part printouts, plate list delete/duplicate and clone push
placement, all of which are on master.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ecd0bba4 removed File > Export Nest Report..., so its cancel test went
away and three report tests were renamed for the viewer path. The Windows
acceptance manifest still required the old names and failed with "expected
at least 1 cases, found 0" although every test passed. List the current
names, and add the two viewer tests now that the viewer is the only way to
get the PDF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The File menu ran six output commands together with no separators, and
"Export" / "Export All" didn't say what they exported. Group them by what
they produce:
- Save Copy as .nest File... (was Export .nest...) moves next to Save As,
since it writes the nest file rather than exporting a plate.
- Export Plate... / Export All Plates... (were Export / Export All) get their
own group and the "..." their save dialogs call for.
- Nest Report... / Part Printouts... (were View ...) form a reports group.
- Storage Mode... gets its own separator above Exit.
Export Nest Report... is removed: the report viewer already has Save As
(available even without WebView2), so it was a second path to the same PDF.
Its guard and failure tests now drive the viewer path, and the atomic-write
test calls WriteNestReport directly. The Avalonia prototype's matching
command is renamed too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A part printout showed the part but not its size on the drawing, so the
operator had to read the table to know which way was which. Each page now
draws the overall X extent below the part and the Y extent to its right,
as the Shape Library does: arrows, a boxed label and extension lines that
stop 6 pt short of the outline itself rather than its bounding box.
Each dimension line moves out far enough to keep its label 14 pt clear of
the part (a wide label centered on an 18 pt line nearly touched it), and
the part and its dimensions sit 28 pt inside the drawing border, double
the old padding.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nest report already leads its thickness with the machine config's
Name / Gauge; the part printout's THICKNESS cell now does the same
(16 ga - 0.0598"), from the same lookup in the desktop.
Thickness names are typed into the machine config, so both writers now check
them against the bundled font's Latin-1 limit like other free text, instead
of failing partway through rendering.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thicknesses saved before the auto-fill kept a blank Name / Gauge until someone
edited their value, so their nest reports showed only the decimal. Opening
Machine Configuration now names every blank thickness that matches a standard
gauge or plate fraction and marks the form changed, so closing offers to save
them. Thicknesses matching none stay blank, and once saved a reopen finds
nothing to fill and does not ask again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reports now take a thickness's name from the machine config, so a blank
Name / Gauge leaves the report with just the decimal. Machine Configuration
now fills a blank name from the standard steel gauge or plate fraction table
when the thickness value changes, and keeps following the value while the
name is still the old value's standard one; a typed name is never replaced.
A new thickness starts named for its default 0.25 (1/4").
Existing blank names are not filled on open, so viewing a machine never marks
it dirty; editing the value fills them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each machine thickness already has a Name / Gauge field the shop fills in, so
the report now shows that name instead of guessing one from the standard
gauge table. It is matched the way the machine cutting defaults match the
nest's material, grade and thickness; a thickness without a name shows just
the decimal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every size, thickness and weight on the report already carries its own unit,
so the summary's Units row only repeated them and took a header line from the
part cards. The plate pages' ruler note still names the units, since ruler
numbers are bare.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generated date sat among the summary's report details and printed a UTC
offset nobody on the shop floor reads. It now goes in every page's footer,
left of "Page X of Y", in the computer's own time zone without the offset.
The thickness now leads with its gauge or plate fraction ("16 ga - 0.0598 in")
when it matches one, as the thickness box lists it. Reporting references Core
only, so the desktop looks the name up in StandardThicknesses and passes it on
the snapshot.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shops used CutSend to get a part printout (the part drawn to fit a Letter
page over a details table) because OpenNest had no way to make one. File >
View Part Printouts prints every part drawing of the nest, and the drawing
list's View Part Printout prints one; both open the report viewer to save
or print.
Cut length and pierce count walk the program as it is cut, so etch marks,
tab spans and display-only moves add neither, a tabbed cutout counts one
pierce per piece, and breakoff and common-line cuts count. The drawing list
item reaches the main window directly so nests made by BOM import get it
too. Rendering shares the nest report's lock, fonts and Latin-1 limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write PlateViewDrawRapid/PlateViewDrawBounds only when changed from the default
or already saved, as the WinForms settings provider does, so a later default
change still applies. Give the render thread a copy of a broken common-line
part's box, and prune the label-point cache with the part paths.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plate canvas now draws from the shared OpenNest.Desktop geometry
(ProgramPaths.cs is gone) and maps through ViewTransform: tabbed cutouts
fill as holes, break cuts stay out of the fill, display-only geometry is
dashed, and etch-only parts select by their marks. It adds the origin
axes, irregular sheets with hatched obstacles and their usable outline,
part numbers at the label point, cut-off lines with their segment
numbers, active and removed clamps, common lines, and the selection box.
View gets Draw Rapids, Pierce Points, Bounds, Offset, Cut Direction and
Support, per nest as in WinForms. Rapids and bounds are read from the
shared user settings (PlateViewDrawRapid/PlateViewDrawBounds) when a
nest opens and written when it closes; --snapshot ignores them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the WinForms GraphicsHelper program walker to a toolkit-neutral
figure list (move/line/arc) with its layer routing: cuts without tabs,
leads, etches, and a material fill without break cuts whose tab-gapped
pieces are bridged. Suppressed moves are skipped and marks never bound
the fill. PartDisplayGeometry picks the fill as LayoutPart does
(common-line members, break cuts, open cuts) and keeps display-only
entities; PartLabels ports the label points.
ViewTransform carries DrawControl's world/screen mapping and zoom rules.
PlateOverlays computes what the view draws around parts (sheet, edge
spacing, irregular usable area, clamps, cut-off strokes, rapids, pierce
points, cut direction, offset outline, support) through the existing
Core code. PlateViewOptions reads and writes the View toggles under the
WinForms PlateViewDrawRapid/PlateViewDrawBounds names.
WinForms still draws with GraphicsHelper; nothing there changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The main window loads the post processors in Posts/ beside the app (their
materials registered) as it loads engine plug-ins, and reports any that
fail in the status line. It then reads the machines off the UI thread
through the shared MachineSettingsSource, following storage.json's mode
(the nest server's copy in Database mode), copies legacy clamps onto the
defaults' or only machine as WinForms does, and shows the offline-copy or
clamp warning in the status line. The machines and posts are kept in
DesktopSettings for later screens; nothing uses them yet.
The two posts the WinForms app ships now build with the Avalonia app and
copy to its Posts/ directory, with their settings JSON unless an edited
copy is already deployed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rules behind the WinForms MachineSettings and SharedSettings move into
OpenNest.Desktop as MachineSettingsSource and SharedSettingsSource, so the
Avalonia app reads machines, clamps and nest defaults the same way: in
Database mode the nest server's copy once it holds one (machines as a
whole, nest defaults and clamps as single documents), otherwise this PC's
files; the copy is re-read after two minutes (one while offline), and while
the server is unreachable the last copy read is used, read-only. Legacy
clamps still move onto the defaults' or the only machine once, asking at
most once per session, and cutting settings edited for a nest still save
onto the machine's thickness, or this PC (stamped for that job when the
machine cannot be saved).
Nothing in the shared code shows UI: it returns the warning texts, takes
the clamp-machine question as a delegate and reads the DefaultUnit and
CuttingParametersJson settings through IMachineUserSettings (with a
user-settings.json implementation under the WinForms names). Cut-off
defaults take CutOffSettings instead of a PlateView. MachineSettings and
SharedSettings stay in the WinForms project as thin wrappers with the same
members, showing the same dialogs and reading Properties.Settings and
NestStorage as before, so their callers are unchanged.
Tests cover File vs Database mode precedence, the offline read-only copy
and its once-per-session warning, staleness and retry timing, uploads,
post settings, legacy clamp migration, the cutting-settings save and the
user-settings file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PostProcessorLoader and PostProcessorMaterials move unchanged (namespace
OpenNest kept) into the toolkit-neutral library, so the Avalonia app can
load the posts in Posts/ and register their materials as the WinForms app
does. Each DLL still loads on its own and a failing one is reported in the
result instead of stopping the others; the WinForms MainForm shows the
failures as before.
New tests load a copy of the test assembly as a post plug-in beside a
broken DLL: the broken one is reported, the good one's posts load and its
materials are registered once each, ignoring case and blanks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pinning a model in shared agent files forces that tier on anyone who
runs them; each user picks their own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Track .claude/agents/ so every worktree gets the shared agent
definitions; the rest of .claude/ stays ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Avalonia app applies the colour scheme saved as ActiveColorScheme in
the shared user-settings file when the main window opens, and recolours a
nest's drawings from it when opening the nest, as WinForms does.
The plate canvas draws the background, sheet, edge spacing, etch, part
outlines and selection from the active scheme through SkiaSchemePalette,
a cache of Skia colours rebuilt when the scheme's colours change, instead
of hard-coded colours. Part outlines follow the scheme's outline colour
or the fill darkened as WinForms darkens it. There is no Options screen
to change the scheme yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ColorScheme, ColorSchemeRegistry, ColorSchemeSerializer and the Schemes
folder move into the toolkit-neutral library, keeping the OpenNest
namespace, so the Avalonia app can share the built-in palettes, the
scheme files and the recolour-on-open rule.
ColorScheme is now pure colour data with a Version that changes with
any colour. Its GDI+ pens and brushes move to GdiSchemeTools in the
WinForms project (still one set per thread, rebuilt after a colour
change), reached through scheme.Gdi(). The legacy part outline uses
ColorShade.Dark, a port of ControlPaint.Dark's HLS arithmetic; a
WinForms test compares the two across a colour sweep on Windows.
The registry no longer walks Application.OpenForms: Apply raises
Applied, and EditNestForm subscribes once to recolour every open nest
window as before. The saved scheme is read under the same
ActiveColorScheme setting (SavedSchemeName/ApplySaved for the shared
user-settings file); WinForms still reads it through Settings.Default.
Schemes/*.json now copies beside both desktop apps from OpenNest.Desktop.
Pure scheme tests move to OpenNest.Desktop.Tests, with new ones for
built-in round trips, scheme files, bad files, the saved name and the
recolour rule.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LargeDialogBounds computes the bounds the large browse dialogs open at:
nine tenths of the owner screen's working area, centered, never below the
dialog's minimum size. WinForms' DialogBounds now calls it with the
screen's working area, with unchanged behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NestTemplateMigration converts the legacy NestTemplatePath template into
the nest defaults file when the template exists and no defaults file does,
and says whether to clear the setting (converted or nothing to convert)
or the warning to show when the conversion failed, which keeps the
setting. A settings-map overload clears it to the empty text WinForms
stores, so it runs once. WinForms' MainWindowSettings now calls it and
still shows the same warning.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SavedCutOffHeadLock reads and writes CutOffLockHeadHeight and
CutOffHeadLockOvercutInches in the WinForms format and converts the
overcut, always stored in inches, to and from each nest's units, using
1.5 in when the saved overcut is not a positive number. The WinForms
CutOffHeadLockDefaults now calls it, with unchanged behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SavedCutTimeSettings reads and writes the cut-time values last used in
Calculate Cut Time or the simulator under the names and text the WinForms
app already stores (LastFeedrate, LastHoleFeedrate, LastRapidFeedrate,
LastPierceTime as invariant decimals, CutTimeSkipEtch "True"/"False",
CutTimeMachine as a machine id or "none"), with each unreadable value
falling back to its WinForms default. It also holds the rules: never-saved
values use the cut-parameter defaults, no hole feed uses the feed, and the
saved machine falls back to the first by name. The WinForms app's
SavedCutParameters and machine box now call it; their behaviour is
unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Files dropped anywhere on the main window, over the nest view too, are
taken (as a copy) only when one is a .nest file; each opens in its own
tab, or shows its tab if already open, and other files are ignored, as
in the WinForms app. Load warnings follow as for File > Open, and as
File > Open, a drop works while Auto Nest runs.
File > Exit shows and answers Ctrl+Q, asking about unsaved nests as
closing the window does; the window placement is still saved on exit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DroppedNestFiles.Select keeps the dropped paths with the .nest extension
in any case, as the WinForms main window does, ignoring everything else.
It returns full paths in the order dropped, each once however its path is
written, compared as NestTabs compares open files. Any says whether the
drop holds a nest file, so a window accepts it only then.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Master added head-raise markers, common-line shared cuts and remainders to
the CI Fiber's own contour extractor, which this branch replaced with Core's
shared PostContours. Those now live in the shared model: PostContour carries
Raised, IsCommonLine and RemainderWinding, and Classify gives remainders the
perimeter macro on their perimeter's side and shared cuts no kerf side.
ContourWinding uses PortableMath for trig, as master's Core guard requires.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
File > Save (Ctrl+S), Save As and Export .nest, with Save and Save As on
the toolbar. Save writes to the file saved to this session, else asks
for one in the nest's folder; a failed save says why, keeps the nest
unsaved and points to Save As. One save or export runs at a time, a
nest cannot be closed while one is under way, and the nest Auto Nest
is working on is not written, checked again after the file picker.
Closing a nest with unsaved changes asks Save / Don't Save / Cancel, as
the WinForms nest window does; Exit asks about each unsaved nest in
turn, showing it, and reads the list again after each answer, since
Auto Nest can finish while a question is open. Cancel, or a save that
does not happen, keeps the app open; an unsaved nest still being
nested stops Exit with how to stop Auto Nest.
Nest load warnings are shown after opening, one dialog at a time and
scrolling when long; for nests opened from the command line they appear
once the window opens, and --snapshot only notes them in the status.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NestTabs.SaveAs writes the tab's nest, makes the file its file and name,
and clears its unsaved mark; a write that fails throws and changes
nothing. ExportCopy writes the nest without touching its file, name or
unsaved mark.
Both refuse, before writing anything, a file another open tab shows (so
one file never has two tabs) and a tab that has been closed; Export
also refuses the tab's own file, which only Save may write. Refusals
are a SaveTargetRefusedException whose message says what to do.
SavePath is the file Save writes without asking: only one saved to this
session, as in the WinForms app, so a nest that was only opened asks
for a file on its first Save.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CL post wrote the configured default side (G41) on every contour,
so a contour wound against OpenNest's convention was compensated into
the part. It now takes each feature's side from Core's shared
PostContours winding rule, as the CI Fiber post does: the perimeter is
picked across the part's cut features and hole sub-program contours
are always holes. Correctly wound drawings post unchanged.
Remove the "Default kerf side" post setting; saved configs that still
carry it load as before. Expose PostContours.Flatten and Classify so a
post can classify one part's features itself.
Add CL tests for a square with a hole: the exact inline program, cuts
that match the shared contours on the sheet, G41/G42 keeping the part
out of the kerf inline and through part sub-programs, and identical
output from absolute and incremental part and hole programs. The
replay now records the compensation in force on each cut.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the CI Fiber post's contour extraction and winding into Core as
OpenNest.CNC.Posting.PostContours and ContourWinding, so every post can
take sheet- or part-frame contours with the perimeter and kerf side
already chosen instead of re-deriving them. CI Fiber now writes from
the shared model; its golden output is unchanged.
Scribe marks are never picked as the perimeter and get no kerf. A cut
that resumes after suppressed moves starts a new contour where they
end, so it is no longer cut as a chord across the gap.
Add tests for a square with a hole in sheet coordinates, identical
contours from absolute and incremental part/hole programs, rotation,
and the kerf side for both windings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The labels said left and down, but every push follows the plate quadrant:
on quadrant 4 "Push left, then down" pushed left, then up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shift+click in Clone Parts always kept whichever axis order landed the
copy nearest the origin, which can park it in a pocket the user didn't
want. Options > Clone push placement now picks Closest to origin (the old
behavior, still the default), Push left then down, or Push down then left.
Ctrl+click settles the copy on bounding boxes alone, so it stops square
to its neighbors' boxes instead of nesting into their shapes. Shift+click
keeps its box pass then geometry settle; both follow the chosen order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One Irregular decode of a small job took seconds because each block in the
catalog is built by the full Fill pipeline (PrivatePlateFill), and inside it
StripeFiller's estimate rows spent about 85% of the CPU in FillLinear's
perpendicular TilePattern. A stripe estimate is exactly one pattern tall, so
the pattern's copy distance, an all-pairs slide search, always exceeded the
room left and the copies were discarded after the search had run in full.
TilePattern now passes FindPatternCopyDistance the largest distance that
could still place a copy: for a whole copy, the room past the pattern; for a
pattern that may tile partially, the most room past any one of its parts. The distance
is the maximum over every pair, so the search stops as soon as it passes that
bound and the tile returns empty, which is what the full search led to. The
public CopyDistance is unchanged. StripeFiller's angle searches also reuse
each rotated pattern's bounding box per angle instead of cloning and
rotating the parts again on every probe.
Output is identical: the layouts of every benchmark job that finishes match
the previous build. Measured A/B on this machine, alternating builds per job
(Benchmark --engines Irregular --parallel 1, benchmark ms):
- N26-2A5: 15.5 s -> 8.8 s (12.6 s -> ~7.2 s in quieter runs)
- 73 of the 80 bench jobs (the other 7 time out at 5 minutes in both
builds): 1,990 s -> 1,578 s total (-21%), process CPU 6,486 s -> 3,842 s
(-41%), median job 0.91x. N26-295 now finishes in 242 s with the same
layout where it hit the 5-minute limit before.
- Problem-nest corpus auto-nest and fill areas: all at baseline.
A parallel herringbone pair build was tried and dropped: it saved 1.2 s on
N26-2A5 but cost 10 s and 45 s more CPU on P241017-01.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a plate packed edge to edge, an overlap left by hand-placing extra
parts could not be fixed: straight push chains ran into the edge and
the relaxation gave up on pairs that share material, which have no
contact normal. The relaxation now pushes such a pair along its
shortest straight way out and lets the rest settle, which cleared a
0.92 sq in overlap on a 38-part plate with every part kept square.
When moves alone still cannot settle, the relaxation runs again as a
rigid one: an off-center push also turns a part, up to 3 degrees, if
its drawing is free to rotate. Moves stay first because a tilt turns
every part the push reaches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expand Spacing opens up a whole selection; nests that are a hair short
of fitting need the opposite: move only the parts the overlap check
flags, by the shortfall, and leave everything else where it is.
Fix Spacing pushes one part of each flagged pair straight away from the
other and ripples the push into neighbors it crowds, so rows already
locked in at the spacing can make room. When a plate is packed edge to
edge and no straight push fits, a constraint relaxation shares each
shortfall between both parts along the closest-point normal. Every
result is confirmed by the overlap check before any part moves, and is
applied only when it has fewer findings and nothing new.
NativeContours gains a coarse-flattening overload, Translated, Nested
and a closest-points GapTo for the search.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows erases a resized window before WinForms updates its cached
ClientSize, so the erase handler filled the blank area below the rows only
out to the old width. Windows then treated the new strip as erased, and it
kept whatever was on screen before. The handler now reads the client rect
from Windows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Auto Nest left N26-2A5 (14 door stops, 14 lock plates on a clamped 26x26
sheet) 8.0 high, while the shop's hand layout holds all 28 under 7.5 and
leaves a half-inch-deeper drop. Every MaxRects fit rule packs into the
whole sheet, so with room to spare it spreads the parts out and never
looks for the shortest strip.
When a rule places all the remaining demand, Rectangles now repacks it
into shorter and narrower bins, every rule and mode per probe, and offers
the tightest complete layout per axis to the stock loop, which still
picks by cost and offcut. Fit is not monotonic in bin size (7.5 packs,
7.62 and 7.74 do not), so probes walk down through stack heights (sums of
spaced part sides from the bin edge or a reached clamp) instead of
bisecting. A placement budget skips sheets finishing ~2000+ parts.
Benchmark, Rectangles on 80 recent production nests with salvage credit:
11 cheaper, 0 worse, all valid, total time 14.7 s -> 13.2 s.
The zero-clamp hash is re-captured (the squeezed layout is narrower);
the far-clamp test now compares poses, since the clamp can reorder an
identical layout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Strip whole-job engine laid its strips, settled them and picked its pack
remnant from the bare work area, never adding the plate's clamp keep-outs the
Lattice orchestration uses. On a clamped sheet it put parts over the clamp, the
runner's layout check rejected the candidate, and Strip produced nothing (N26-2A5
rev 5: door stop at (21.09,1.50) over clamp-1).
NestStrips now treats InteractiveClamps.ClearanceRectangles as occupied space for
the iterative shrink strips (through RemnantFiller), settles with the clamp
obstacles when there are zones, and finds the pack remnant around them even
before any strip is placed. Unclamped plates take the old path unchanged.
A FixedStrategyNestingEngine theory runs all four fixed strategies on a clamped
26 x 26 sheet; only Strip failed it before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fill/cutoff legend, the part-ID note and the "verify geometry and CNC
output" reminder repeated on every plate page and added clutter without
telling the operator anything plate-specific. Only the clamp legend (on
plates with clamps) and the ruler-units line remain.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>