A part with lead-ins applied could not be pushed away once another part
touched it. PartGeometry kept LEADIN/LEADOUT entities as material, so the
leads chained onto the perimeter as open spurs and the spacing offset no
longer closed. The slide-contact classifier cannot tell the material side
of an unclosed boundary and blocks every contact, so parts resting against
it could not move up or right off it. Leads are cut into scrap, and the
spacing review, overlap analyzer and support checks already drop them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thirteen test classes built the same origin-anchored rectangle drawing in
their own private helper (MakeRectDrawing, MakeRect or Rect). They now
call TestHelpers.MakeRectDrawing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PEP-rounded drawings can leave a contour 1e-6 short of closing. ShapeBuilder
chains it as a loop at Tolerance.ChainTolerance, but the slide classifier
re-recovered loops at 1e-7, so the whole part became unresolved and every
contact with it blocked. Parts placed in its cutout at exactly the part
spacing could not be pushed (Y/X keys) in any direction, even away from the
wall. Recover loops with the same tolerance ShapeBuilder uses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Repo-wide sweep with the pinned CSharpier 1.3.0 tool. Whitespace and
line-wrapping only; OpenNest.Engine.Tests (109) and OpenNest.IO.Tests
pass after reformat, full solution builds 0 errors.
Added .csharpierignore so csproj/config XML keeps its existing layout
(CSharpier's XML wrapping churns attributes with zero benefit).
Formatting is now enforceable: dotnet csharpier check . passes.
Parts that already overlap the moving group are now excluded from the
obstacle list so they don't block the push direction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ArcToLineClosestDistance used geometric closest-point as a proxy for
directional push distance, which are fundamentally different queries.
The heuristic could overestimate the safe push distance when an arc
faces an inclined line, causing the Compactor to over-push parts into
overlapping positions.
Replace with analytical computation: for each arc/line pair, solve
dt/dθ = 0 to find the two critical angles where the directional
distance is stationary, evaluate both (if within the arc's angular
span), and fire a ray to verify the hit is within the line segment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 43 root-level test files into feature-specific subdirectories
mirroring the main codebase structure: Geometry, Fill, BestFit, CutOffs,
CuttingStrategy, Engine, IO. Update namespaces to match folder paths.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>