feat(ui): two-bucket preview parts in PlateView

Replace single temporaryParts list with stationaryParts (overall best,
full opacity) and activeParts (current strategy, reduced opacity).
Update SetPlate, Refresh, UpdateMatrix, DrawParts, and FillWithProgress
accordingly. Replace SetTemporaryParts/ClearTemporaryParts/AcceptTemporaryParts
with SetStationaryParts/SetActiveParts/ClearPreviewParts/AcceptPreviewParts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 22:14:59 -04:00
parent 231f97fafc
commit 4fc8f1f6cf

View File

@@ -31,7 +31,8 @@ namespace OpenNest.Controls
private Action currentAction; private Action currentAction;
private Action previousAction; private Action previousAction;
private List<LayoutPart> parts; private List<LayoutPart> parts;
private List<LayoutPart> temporaryParts = new List<LayoutPart>(); private List<LayoutPart> stationaryParts = new List<LayoutPart>();
private List<LayoutPart> activeParts = new List<LayoutPart>();
private Point middleMouseDownPoint; private Point middleMouseDownPoint;
private Box activeWorkArea; private Box activeWorkArea;
private List<Box> debugRemnants; private List<Box> debugRemnants;
@@ -149,7 +150,8 @@ namespace OpenNest.Controls
plate.PartAdded -= plate_PartAdded; plate.PartAdded -= plate_PartAdded;
plate.PartRemoved -= plate_PartRemoved; plate.PartRemoved -= plate_PartRemoved;
parts.Clear(); parts.Clear();
temporaryParts.Clear(); stationaryParts.Clear();
activeParts.Clear();
SelectedParts.Clear(); SelectedParts.Clear();
} }
@@ -408,7 +410,8 @@ namespace OpenNest.Controls
public override void Refresh() public override void Refresh()
{ {
parts.ForEach(p => p.Update(this)); parts.ForEach(p => p.Update(this));
temporaryParts.ForEach(p => p.Update(this)); stationaryParts.ForEach(p => p.Update(this));
activeParts.ForEach(p => p.Update(this));
Invalidate(); Invalidate();
} }
@@ -503,24 +506,38 @@ namespace OpenNest.Controls
part.Draw(g, (i + 1).ToString()); part.Draw(g, (i + 1).ToString());
} }
// Draw temporary (preview) parts // Draw stationary preview parts (overall best — full opacity)
for (var i = 0; i < temporaryParts.Count; i++) for (var i = 0; i < stationaryParts.Count; i++)
{ {
var temp = temporaryParts[i]; var part = stationaryParts[i];
if (temp.IsDirty) if (part.IsDirty)
temp.Update(this); part.Update(this);
var path = temp.Path; var path = part.Path;
var pathBounds = path.GetBounds(); if (!path.GetBounds().IntersectsWith(viewBounds))
if (!pathBounds.IntersectsWith(viewBounds))
continue; continue;
g.FillPath(ColorScheme.PreviewPartBrush, path); g.FillPath(ColorScheme.PreviewPartBrush, path);
g.DrawPath(ColorScheme.PreviewPartPen, path); g.DrawPath(ColorScheme.PreviewPartPen, path);
} }
// Draw active preview parts (current strategy — reduced opacity)
for (var i = 0; i < activeParts.Count; i++)
{
var part = activeParts[i];
if (part.IsDirty)
part.Update(this);
var path = part.Path;
if (!path.GetBounds().IntersectsWith(viewBounds))
continue;
g.FillPath(ColorScheme.ActivePreviewPartBrush, path);
g.DrawPath(ColorScheme.ActivePreviewPartPen, path);
}
if (DrawOffset && Plate.PartSpacing > 0) if (DrawOffset && Plate.PartSpacing > 0)
DrawOffsetGeometry(g); DrawOffsetGeometry(g);
@@ -879,34 +896,49 @@ namespace OpenNest.Controls
Plate.Parts.Add(part); Plate.Parts.Add(part);
} }
public void SetTemporaryParts(List<Part> parts) public void SetStationaryParts(List<Part> parts)
{ {
temporaryParts.Clear(); stationaryParts.Clear();
if (parts != null) if (parts != null)
{ {
foreach (var part in parts) foreach (var part in parts)
temporaryParts.Add(LayoutPart.Create(part, this)); stationaryParts.Add(LayoutPart.Create(part, this));
} }
Invalidate(); Invalidate();
} }
public void ClearTemporaryParts() public void SetActiveParts(List<Part> parts)
{ {
temporaryParts.Clear(); activeParts.Clear();
if (parts != null)
{
foreach (var part in parts)
activeParts.Add(LayoutPart.Create(part, this));
}
Invalidate(); Invalidate();
} }
public int AcceptTemporaryParts() public void ClearPreviewParts()
{ {
var count = temporaryParts.Count; stationaryParts.Clear();
activeParts.Clear();
Invalidate();
}
foreach (var layoutPart in temporaryParts) public void AcceptPreviewParts(List<Part> parts)
Plate.Parts.Add(layoutPart.BasePart); {
if (parts != null)
{
foreach (var part in parts)
Plate.Parts.Add(part);
}
temporaryParts.Clear(); stationaryParts.Clear();
return count; activeParts.Clear();
} }
public async void FillWithProgress(List<Part> groupParts, Box workArea) public async void FillWithProgress(List<Part> groupParts, Box workArea)
@@ -918,7 +950,12 @@ namespace OpenNest.Controls
var progress = new Progress<NestProgress>(p => var progress = new Progress<NestProgress>(p =>
{ {
progressForm.UpdateProgress(p); progressForm.UpdateProgress(p);
SetTemporaryParts(p.BestParts);
if (p.IsOverallBest)
SetStationaryParts(p.BestParts);
else
SetActiveParts(p.BestParts);
ActiveWorkArea = p.ActiveWorkArea; ActiveWorkArea = p.ActiveWorkArea;
}); });
@@ -932,20 +969,20 @@ namespace OpenNest.Controls
if (parts.Count > 0 && (!cts.IsCancellationRequested || progressForm.Accepted)) if (parts.Count > 0 && (!cts.IsCancellationRequested || progressForm.Accepted))
{ {
AcceptTemporaryParts(); AcceptPreviewParts(parts);
sw.Stop(); sw.Stop();
Status = $"Fill: {parts.Count} parts in {sw.ElapsedMilliseconds} ms"; Status = $"Fill: {parts.Count} parts in {sw.ElapsedMilliseconds} ms";
} }
else else
{ {
ClearTemporaryParts(); ClearPreviewParts();
} }
progressForm.ShowCompleted(); progressForm.ShowCompleted();
} }
catch (Exception) catch (Exception)
{ {
ClearTemporaryParts(); ClearPreviewParts();
} }
finally finally
{ {
@@ -1082,7 +1119,8 @@ namespace OpenNest.Controls
{ {
base.UpdateMatrix(); base.UpdateMatrix();
parts.ForEach(p => p.Update(this)); parts.ForEach(p => p.Update(this));
temporaryParts.ForEach(p => p.Update(this)); stationaryParts.ForEach(p => p.Update(this));
activeParts.ForEach(p => p.Update(this));
} }
} }
} }