FillLinear now accepts optional RemainderPatterns that are tried in
leftover strips after the main grid fill, improving packing density
when pair patterns fit the narrow residual space.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The BestFitFilter's aspect ratio cap of 5.0 was rejecting valid pair
candidates needed for narrow plates (e.g. 60x6.5, aspect 9.2) and
remainder strips on normal plates. Three fixes:
- BestFitFinder: derive MaxAspectRatio from the plate's own aspect
ratio so narrow plates don't reject all elongated pairs
- SelectPairCandidates: search the full unfiltered candidate list
(not just Keep=true) in strip mode, so pairs rejected by aspect
ratio for the main plate can still be used for narrow remainder
strips
- BestFitCache.Populate: skip caching empty result lists so stale
pre-computed data from nest files doesn't prevent recomputation
Also fixes console --size parsing to use LxW format matching
Size.Parse convention, and includes prior engine refactoring
(sequential fill loops, parallel FillPattern, pre-sorted edge
arrays in RotationSlideStrategy).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace recursive FillRecursive with flat FillGrid that tiles along primary
axis, then perpendicular. Extract FindPlacedEdge, BuildRemainingStrip,
BuildRotationSet, FindBestFill helpers. Use array-based DirectionalDistance
to eliminate allocations in FindCopyDistance and FindPatternCopyDistance.
Simplify FindSinglePartPatternCopyDistance to delegate to FindCopyDistance.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
"Length" is more natural than "height" for flat plate materials.
Renames the field on OpenNest.Geometry.Size, Box.Height property,
and all references across 38 files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The push algorithm's copy distance formula (bboxDim - slideDistance)
produced distances smaller than the part width when inflated boundary
arc vertices interacted spuriously, causing ~0.05 unit overlaps between
all adjacent grid parts.
Two fixes applied:
- Clamp ComputeCopyDistance to bboxDim + PartSpacing minimum
- Use circumscribed polygons (R/cos(halfStep)) for PartBoundary arc
discretization so chord segments never cut inside the true arc,
eliminating the ChordTolerance offset workaround
Also parallelized three sequential fill loops using Parallel.ForEach:
- FindBestFill angle sweep (up to 38 angles x 2 directions)
- FillPattern angle sweep for group/pair fills
- FillRemainingStrip rotation loop
Added diagnostic logging to HasOverlaps, FindCopyDistance, and
FillRecursive for debugging fill issues.
Test result: 45 parts @ 79.6% -> 47 parts @ 83.1%, zero overlaps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the greedy maximum-row tiling leaves a thin remainder, tries removing
the last row and re-filling the larger strip. Picks whichever total is
higher. Fixes cases where e.g. 4 rows + 11 remainder = 47 beats 5 rows = 45.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-size TilePattern result list from estimated copy count to avoid
resizing. Remove redundant Program.BoundingBox() call and UpdateBounds()
in MakeSeedPattern — the Part's BoundingBox is already correct.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
max(aUpper_i - bLower_j) across all pairs simplifies to
max(aUpper) - min(bLower), computed in a single pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FindCopyDistance and FindPatternCopyDistance were cloning entire Parts
(including deep Program copies) just to get offset locations for
GetLines. Compute offset locations directly instead. Also skip the
Pattern wrapper in TilePattern — clone parts directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Part.Clone() re-clones from the drawing's unrotated program, re-rotates,
and walks all CNC codes twice for bounding box — 4 O(c) passes per clone.
CloneAtOffset clones from the already-rotated program and computes the
bounding box arithmetically, reducing to 1 O(c) pass per clone.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Narrow remnant strips now get more parts by:
- Sweeping rotations every 5° when the strip is narrower than the part
- Including all pairs that fit the strip width (not just top 50 by area)
- Placing individual parts from incomplete pattern copies that still fit
- Using finer polygon tolerance (0.01) for hull edge angle detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract MakeSeedPattern for shared part creation, and replace the
two-step primary/perpendicular tiling with a single FillRecursive
method that tiles along one axis then recurses perpendicular.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract offset polygon computation into PartBoundary, which builds
and caches inflated boundary polygons per unique part geometry.
FillLinear now uses symmetric half-spacing and reuses boundaries
across tiling passes, avoiding redundant offset calculations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FindPatternCopyDistance now checks every pair of parts across adjacent
patterns so that multi-part patterns (e.g. interlocking pairs) maintain
correct spacing between ALL parts, not just the bounding boxes. The
original single-part logic is preserved as a fast path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Offset the moving shape's geometry by PartSpacing instead of adding
spacing linearly to the copy distance. This guarantees minimum clearance
in all directions for curved/complex shapes, not just along the slide axis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge ActionAddPart into ActionClone by adding a Drawing constructor,
eliminating the redundant class. ActionClone now handles both adding
new parts from a drawing and cloning selected part groups. Added
Ctrl+F fill support for groups using FillLinear pattern tiling, and
adopted quadrant-aware push directions from ActionAddPart. Refactored
FillLinear to extract shared helpers and add a Fill(Pattern) overload
for tiling arbitrary part groups across the work area.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>