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

View File

@@ -420,8 +420,8 @@ namespace OpenNest.Geometry
boundingBox.X = minX;
boundingBox.Y = minY;
boundingBox.Width = maxX - minX;
boundingBox.Length = maxY - minY;
boundingBox.Length = maxX - minX;
boundingBox.Width = maxY - minY;
}
public override Entity OffsetEntity(double distance, OffsetSide side)

View File

@@ -12,8 +12,8 @@ namespace OpenNest.Geometry
double minX = boxes[0].X;
double minY = boxes[0].Y;
double maxX = boxes[0].X + boxes[0].Width;
double maxY = boxes[0].Y + boxes[0].Length;
double maxX = boxes[0].Right;
double maxY = boxes[0].Top;
foreach (var box in boxes)
{

View File

@@ -14,15 +14,15 @@ namespace OpenNest.Geometry
public Box(double x, double y, double w, double h)
{
Location = new Vector(x, y);
Width = w;
Length = h;
Length = w;
Width = h;
}
public Vector Location;
public Vector Center
{
get { return new Vector(X + Width * 0.5, Y + Length * 0.5); }
get { return new Vector(X + Length * 0.5, Y + Width * 0.5); }
}
public Size Size;
@@ -76,12 +76,12 @@ namespace OpenNest.Geometry
public Box Translate(double x, double y)
{
return new Box(X + x, Y + y, Width, Length);
return new Box(X + x, Y + y, Length, Width);
}
public Box Translate(Vector offset)
{
return new Box(X + offset.X, Y + offset.Y, Width, Length);
return new Box(X + offset.X, Y + offset.Y, Length, Width);
}
public double Left
@@ -91,12 +91,12 @@ namespace OpenNest.Geometry
public double Right
{
get { return X + Width; }
get { return X + Length; }
}
public double Top
{
get { return Y + Length; }
get { return Y + Width; }
}
public double Bottom
@@ -207,7 +207,7 @@ namespace OpenNest.Geometry
public Box Offset(double d)
{
return new Box(X - d, Y - d, Width + d * 2, Length + d * 2);
return new Box(X - d, Y - d, Length + d * 2, Width + d * 2);
}
public override string ToString()

View File

@@ -9,7 +9,7 @@
var x = large.Left;
var y = small.Top;
var w = large.Width;
var w = large.Length;
var h = large.Top - y;
return new Box(x, y, w, h);
@@ -23,7 +23,7 @@
var x = large.Left;
var y = large.Bottom;
var w = small.Left - x;
var h = large.Length;
var h = large.Width;
return new Box(x, y, w, h);
}
@@ -35,7 +35,7 @@
var x = large.Left;
var y = large.Bottom;
var w = large.Width;
var w = large.Length;
var h = small.Top - y;
return new Box(x, y, w, h);
@@ -49,7 +49,7 @@
var x = small.Right;
var y = large.Bottom;
var w = large.Right - x;
var h = large.Length;
var h = large.Width;
return new Box(x, y, w, h);
}

View File

@@ -370,23 +370,23 @@ namespace OpenNest.Geometry
if (StartPoint.X < EndPoint.X)
{
boundingBox.X = StartPoint.X;
boundingBox.Width = EndPoint.X - StartPoint.X;
boundingBox.Length = EndPoint.X - StartPoint.X;
}
else
{
boundingBox.X = EndPoint.X;
boundingBox.Width = StartPoint.X - EndPoint.X;
boundingBox.Length = StartPoint.X - EndPoint.X;
}
if (StartPoint.Y < EndPoint.Y)
{
boundingBox.Y = StartPoint.Y;
boundingBox.Length = EndPoint.Y - StartPoint.Y;
boundingBox.Width = EndPoint.Y - StartPoint.Y;
}
else
{
boundingBox.Y = EndPoint.Y;
boundingBox.Length = StartPoint.Y - EndPoint.Y;
boundingBox.Width = StartPoint.Y - EndPoint.Y;
}
}

View File

@@ -311,8 +311,8 @@ namespace OpenNest.Geometry
boundingBox.X = minX;
boundingBox.Y = minY;
boundingBox.Width = maxX - minX;
boundingBox.Length = maxY - minY;
boundingBox.Length = maxX - minX;
boundingBox.Width = maxY - minY;
}
public override Entity OffsetEntity(double distance, OffsetSide side)