fix: correct Width/Length axis mapping and add spiral center-fill

Box constructor and derived properties (Right, Top, Center, Translate, Offset)
had Width and Length swapped — Length is X axis, Width is Y axis. Corrected
across Core geometry, plate bounding box, rectangle packing, fill algorithms,
tests, and UI renderers.

Added FillSpiral with center remnant detection and recursive FillBest on
the gap between the 4 spiral quadrants. RectFill.FillBest now compares
spiral+center vs full best-fit fairly. BestCombination returns a
CombinationResult record instead of out params.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 21:22:55 -04:00
parent e50a7c82cf
commit c5943e22eb
55 changed files with 433 additions and 257 deletions
+9 -9
View File
@@ -201,8 +201,8 @@ public class StripeFiller
private static Box MakeStripeBox(Box workArea, double perpDim, NestDirection primaryAxis)
{
return primaryAxis == NestDirection.Horizontal
? new Box(workArea.X, workArea.Y, workArea.Width, perpDim)
: new Box(workArea.X, workArea.Y, perpDim, workArea.Length);
? new Box(workArea.X, workArea.Y, workArea.Length, perpDim)
: new Box(workArea.X, workArea.Y, perpDim, workArea.Width);
}
private List<Part> FillRemnant(List<Part> gridParts, NestDirection primaryAxis)
@@ -224,7 +224,7 @@ public class StripeFiller
var remnantLength = workArea.Top - remnantY;
if (remnantLength < minDim)
return null;
remnantBox = new Box(workArea.X, remnantY, workArea.Width, remnantLength);
remnantBox = new Box(workArea.X, remnantY, workArea.Length, remnantLength);
}
else
{
@@ -232,7 +232,7 @@ public class StripeFiller
var remnantWidth = workArea.Right - remnantX;
if (remnantWidth < minDim)
return null;
remnantBox = new Box(remnantX, workArea.Y, remnantWidth, workArea.Length);
remnantBox = new Box(remnantX, workArea.Y, remnantWidth, workArea.Width);
}
Debug.WriteLine($"[StripeFiller] Remnant box: {remnantBox.Width:F2}x{remnantBox.Length:F2}");
@@ -324,7 +324,7 @@ public class StripeFiller
{
var box = FillHelpers.BuildRotatedPattern(patternParts, 0).BoundingBox;
var span0 = GetDimension(box, axis);
var perpSpan0 = axis == NestDirection.Horizontal ? box.Length : box.Width;
var perpSpan0 = axis == NestDirection.Horizontal ? box.Width : box.Length;
if (span0 <= perpSpan0)
return 0;
@@ -388,7 +388,7 @@ public class StripeFiller
var rotated = FillHelpers.BuildRotatedPattern(patternParts, currentAngle);
var pairSpan = GetDimension(rotated.BoundingBox, axis);
var perpDim = axis == NestDirection.Horizontal
? rotated.BoundingBox.Length : rotated.BoundingBox.Width;
? rotated.BoundingBox.Width : rotated.BoundingBox.Length;
if (pairSpan + spacing <= 0)
break;
@@ -472,13 +472,13 @@ public class StripeFiller
{
var rotated = FillHelpers.BuildRotatedPattern(patternParts, angle);
return axis == NestDirection.Horizontal
? rotated.BoundingBox.Width
: rotated.BoundingBox.Length;
? rotated.BoundingBox.Length
: rotated.BoundingBox.Width;
}
private static double GetDimension(Box box, NestDirection axis)
{
return axis == NestDirection.Horizontal ? box.Width : box.Length;
return axis == NestDirection.Horizontal ? box.Length : box.Width;
}
private static bool HasOverlappingParts(List<Part> parts) =>