refactor(ui): extract compaction helper, fix auto-arrange UX in PatternTileForm

- Extract CompactTowardCentroid static helper to DRY compaction logic
- Disable Auto-Arrange button when fewer than 2 drawings selected
- Widen mouse-up compaction guard from == 2 to >= 2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 09:56:21 -04:00
parent f0b9b51229
commit d8373ab135

View File

@@ -97,6 +97,7 @@ namespace OpenNest.Forms
{ {
RebuildCell(); RebuildCell();
RebuildPreview(); RebuildPreview();
btnAutoArrange.Enabled = SelectedDrawingA != null && SelectedDrawingB != null;
} }
private void OnPlateSettingsChanged(object sender, EventArgs e) private void OnPlateSettingsChanged(object sender, EventArgs e)
@@ -107,7 +108,7 @@ namespace OpenNest.Forms
private void OnCellMouseUp(object sender, MouseEventArgs e) private void OnCellMouseUp(object sender, MouseEventArgs e)
{ {
if (e.Button == MouseButtons.Left && cellView.Plate.Parts.Count == 2) if (e.Button == MouseButtons.Left && cellView.Plate.Parts.Count >= 2)
{ {
CompactCellParts(); CompactCellParts();
} }
@@ -154,8 +155,15 @@ namespace OpenNest.Forms
if (parts.Count < 2) if (parts.Count < 2)
return; return;
var combinedBox = parts.GetBoundingBox(); CompactTowardCentroid(parts, PartSpacing);
var centroid = combinedBox.Center; cellView.Refresh();
}
private static void CompactTowardCentroid(List<Part> parts, double spacing)
{
// Use a fixed centroid as the attractor — close enough for 2-part cells
// and avoids oscillation from recomputing each iteration.
var centroid = parts.GetBoundingBox().Center;
var syntheticWorkArea = new Box(-10000, -10000, 20000, 20000); var syntheticWorkArea = new Box(-10000, -10000, 20000, 20000);
for (var iteration = 0; iteration < 10; iteration++) for (var iteration = 0; iteration < 10; iteration++)
@@ -167,9 +175,8 @@ namespace OpenNest.Forms
var partCenter = part.BoundingBox.Center; var partCenter = part.BoundingBox.Center;
var dx = centroid.X - partCenter.X; var dx = centroid.X - partCenter.X;
var dy = centroid.Y - partCenter.Y; var dy = centroid.Y - partCenter.Y;
var dist = System.Math.Sqrt(dx * dx + dy * dy);
if (dist < 0.01) if (System.Math.Sqrt(dx * dx + dy * dy) < 0.01)
continue; continue;
var angle = System.Math.Atan2(dy, dx); var angle = System.Math.Atan2(dy, dx);
@@ -177,14 +184,12 @@ namespace OpenNest.Forms
var obstacles = parts.Where(p => p != part).ToList(); var obstacles = parts.Where(p => p != part).ToList();
totalMoved += Compactor.Push(single, obstacles, totalMoved += Compactor.Push(single, obstacles,
syntheticWorkArea, PartSpacing, angle); syntheticWorkArea, spacing, angle);
} }
if (totalMoved < 0.01) if (totalMoved < 0.01)
break; break;
} }
cellView.Refresh();
} }
private void UpdatePreviewPlateSize() private void UpdatePreviewPlateSize()
@@ -242,30 +247,7 @@ namespace OpenNest.Forms
partB.Offset(partA.BoundingBox.Right + PartSpacing, 0); partB.Offset(partA.BoundingBox.Right + PartSpacing, 0);
var cell = new List<Part> { partA, partB }; var cell = new List<Part> { partA, partB };
CompactTowardCentroid(cell, PartSpacing);
// Compact toward center
var box = cell.GetBoundingBox();
var centroid = box.Center;
var syntheticWorkArea = new Box(-10000, -10000, 20000, 20000);
for (var i = 0; i < 10; i++)
{
var moved = 0.0;
foreach (var part in cell)
{
var pc = part.BoundingBox.Center;
var dx = centroid.X - pc.X;
var dy = centroid.Y - pc.Y;
if (System.Math.Sqrt(dx * dx + dy * dy) < 0.01)
continue;
var angle = System.Math.Atan2(dy, dx);
var single = new List<Part> { part };
var obstacles = cell.Where(p => p != part).ToList();
moved += Compactor.Push(single, obstacles, syntheticWorkArea, PartSpacing, angle);
}
if (moved < 0.01) break;
}
var finalBox = cell.GetBoundingBox(); var finalBox = cell.GetBoundingBox();
var area = finalBox.Width * finalBox.Length; var area = finalBox.Width * finalBox.Length;