fix: resolve grid overlap bug and parallelize fill loops

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>
This commit is contained in:
2026-03-11 00:36:48 -04:00
parent 0e3bf3ccaa
commit 78ee65d946
6 changed files with 126 additions and 39 deletions

View File

@@ -247,7 +247,7 @@ namespace OpenNest.Geometry
/// Converts the shape to a polygon using a chord tolerance to determine
/// the number of segments per arc/circle.
/// </summary>
public Polygon ToPolygonWithTolerance(double tolerance)
public Polygon ToPolygonWithTolerance(double tolerance, bool circumscribe = false)
{
var polygon = new Polygon();
@@ -257,7 +257,7 @@ namespace OpenNest.Geometry
{
case EntityType.Arc:
var arc = (Arc)entity;
polygon.Vertices.AddRange(arc.ToPoints(arc.SegmentsForTolerance(tolerance)));
polygon.Vertices.AddRange(arc.ToPoints(arc.SegmentsForTolerance(tolerance), circumscribe));
break;
case EntityType.Line:
@@ -271,7 +271,7 @@ namespace OpenNest.Geometry
case EntityType.Circle:
var circle = (Circle)entity;
polygon.Vertices.AddRange(circle.ToPoints(circle.SegmentsForTolerance(tolerance)));
polygon.Vertices.AddRange(circle.ToPoints(circle.SegmentsForTolerance(tolerance), circumscribe));
break;
default: