fix(ui): rotate grouped parts around shared center with dedup

Parts created by fill operations share a Program instance via
CloneAtOffset. RotateSelectedParts called Part.Rotate on each,
compounding Program.Rotate on the shared object (1x, 2x, 3x…)
and producing inconsistent bounding boxes. Fix tracks rotated
programs with a HashSet, rotates locations around the group center,
and anchors the bounding box corner to prevent drift.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-16 14:11:07 -04:00
parent 0b9a42e84c
commit 195e29da52

View File

@@ -625,9 +625,9 @@ namespace OpenNest.Controls
};
rect.Y -= rect.Height;
using var pen = new Pen(Color.Red, 1f)
using var pen = new Pen(Color.Red, 1.5f)
{
DashStyle = DashStyle.Dot
DashStyle = DashStyle.Dash
};
g.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
}
@@ -994,22 +994,28 @@ namespace OpenNest.Controls
public void RotateSelectedParts(double angle)
{
var pt1 = SelectedParts.Select(p => p.BasePart).ToList().GetBoundingBox().Location;
var parts = SelectedParts.Select(p => p.BasePart).ToList();
var bounds = parts.GetBoundingBox();
var center = bounds.Center;
var anchor = bounds.Location;
var rotatedPrograms = new HashSet<Program>();
for (int i = 0; i < SelectedParts.Count; ++i)
{
var part = SelectedParts[i];
part.Rotate(angle);
var basePart = part.BasePart;
if (rotatedPrograms.Add(basePart.Program))
basePart.Program.Rotate(angle);
part.Location = part.Location.Rotate(angle, center);
basePart.UpdateBounds();
}
var pt2 = SelectedParts.Select(p => p.BasePart).ToList().GetBoundingBox().Location;
var diff = pt1 - pt2;
var diff = anchor - parts.GetBoundingBox().Location;
for (int i = 0; i < SelectedParts.Count; ++i)
{
var part = SelectedParts[i];
part.Offset(diff);
}
SelectedParts[i].Offset(diff);
}
protected override void UpdateMatrix()