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:
@@ -203,20 +203,24 @@ namespace OpenNest.Geometry
|
||||
/// </summary>
|
||||
/// <param name="segments">Number of parts to divide the arc into.</param>
|
||||
/// <returns></returns>
|
||||
public List<Vector> ToPoints(int segments = 1000)
|
||||
public List<Vector> ToPoints(int segments = 1000, bool circumscribe = false)
|
||||
{
|
||||
var points = new List<Vector>();
|
||||
var stepAngle = reversed
|
||||
? -SweepAngle() / segments
|
||||
: SweepAngle() / segments;
|
||||
|
||||
var r = circumscribe && segments > 0
|
||||
? Radius / System.Math.Cos(System.Math.Abs(stepAngle) / 2.0)
|
||||
: Radius;
|
||||
|
||||
for (int i = 0; i <= segments; ++i)
|
||||
{
|
||||
var angle = stepAngle * i + StartAngle;
|
||||
|
||||
points.Add(new Vector(
|
||||
System.Math.Cos(angle) * Radius + Center.X,
|
||||
System.Math.Sin(angle) * Radius + Center.Y));
|
||||
System.Math.Cos(angle) * r + Center.X,
|
||||
System.Math.Sin(angle) * r + Center.Y));
|
||||
}
|
||||
|
||||
return points;
|
||||
|
||||
@@ -135,18 +135,22 @@ namespace OpenNest.Geometry
|
||||
return System.Math.Max(3, (int)System.Math.Ceiling(Angle.TwoPI / maxAngle));
|
||||
}
|
||||
|
||||
public List<Vector> ToPoints(int segments = 1000)
|
||||
public List<Vector> ToPoints(int segments = 1000, bool circumscribe = false)
|
||||
{
|
||||
var points = new List<Vector>();
|
||||
var stepAngle = Angle.TwoPI / segments;
|
||||
|
||||
var r = circumscribe && segments > 0
|
||||
? Radius / System.Math.Cos(stepAngle / 2.0)
|
||||
: Radius;
|
||||
|
||||
for (int i = 0; i <= segments; ++i)
|
||||
{
|
||||
var angle = stepAngle * i;
|
||||
|
||||
points.Add(new Vector(
|
||||
System.Math.Cos(angle) * Radius + Center.X,
|
||||
System.Math.Sin(angle) * Radius + Center.Y));
|
||||
System.Math.Cos(angle) * r + Center.X,
|
||||
System.Math.Sin(angle) * r + Center.Y));
|
||||
}
|
||||
|
||||
return points;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user