feat: fill open area and optimize pattern rotation via convex hull

ActionClone.Fill() now computes the largest open rectangle from the
cursor position (trying both vertical and horizontal) and passes it
to the engine, so fills no longer overlap existing parts.

Pattern fills try all convex hull edge angles to find the rotation
that maximizes part count.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-07 10:51:21 -05:00
parent 0b2100a661
commit 0573cb2f6d
2 changed files with 166 additions and 14 deletions
+38 -2
View File
@@ -106,6 +106,17 @@ namespace OpenNest.Actions
plateView.SelectedParts.AddRange(parts);
}
public override void ConnectEvents()
{
plateView.KeyDown += plateView_KeyDown;
plateView.MouseMove += plateView_MouseMove;
plateView.MouseDown += plateView_MouseDown;
plateView.Paint += plateView_Paint;
plateView.SelectedParts.Clear();
plateView.SelectedParts.AddRange(parts);
}
public override void DisconnectEvents()
{
plateView.KeyDown -= plateView_KeyDown;
@@ -159,9 +170,34 @@ namespace OpenNest.Actions
private void Fill()
{
var engine = new NestEngine(plateView.Plate);
var plate = plateView.Plate;
var engine = new NestEngine(plate);
var groupParts = parts.Select(p => p.BasePart).ToList();
engine.Fill(groupParts);
var bounds = plate.WorkArea();
if (plate.Parts.Count == 0)
{
engine.Fill(groupParts);
return;
}
var boxes = new List<Box>();
foreach (var part in plate.Parts)
boxes.Add(part.BoundingBox.Offset(plate.PartSpacing));
var pt = plateView.CurrentPoint;
var vertical = Helper.GetLargestBoxVertically(pt, bounds, boxes);
var horizontal = Helper.GetLargestBoxHorizontally(pt, bounds, boxes);
var bestArea = vertical;
if (horizontal.Area() > vertical.Area())
bestArea = horizontal;
if (bestArea == Box.Empty)
return;
engine.Fill(groupParts, bestArea);
}
}
}