fix(core): keep lead-in state and rotation through part copy and rotate

Part.Clone and CloneAtOffset copied the lead-in program but not
HasManualLeadIns, LeadInsLocked, CuttingParameters or the tracked
pre-lead-in rotation. A copy of a rotated lead-in part reported
rotation 0 (the rebuilt program's), so saving it wrote the wrong
rotation and Remove Lead-ins restored an unrotated part.

Part.Rotate on a lead-in part set the tracked rotation from the
lead-in program's own Rotation, which starts at zero when the cutting
strategy rebuilds it, so a further quarter turn left Rotation unchanged.
Lead-in parts now accumulate the applied angle instead.
This commit is contained in:
aj
2026-09-28 18:22:36 -04:00
parent a886735040
commit 20395eed9b
2 changed files with 214 additions and 2 deletions
+29 -2
View File
@@ -145,7 +145,7 @@ namespace OpenNest
EnsureOwnedProgram();
Program.Rotate(angle);
location = Location.Rotate(angle);
preLeadInRotation = Program.Rotation;
TrackRotation(angle);
UpdateBounds();
}
@@ -159,10 +159,22 @@ namespace OpenNest
EnsureOwnedProgram();
Program.Rotate(angle);
location = Location.Rotate(angle, origin);
preLeadInRotation = Program.Rotation;
TrackRotation(angle);
UpdateBounds();
}
/// <summary>
/// Records the part's rotation after it turned by <paramref name="angle"/>. A lead-in
/// program is rebuilt by the cutting strategy and starts over at zero program
/// rotation, so for those parts the rotation is accumulated rather than read back.
/// </summary>
private void TrackRotation(double angle)
{
preLeadInRotation = HasManualLeadIns
? Angle.NormalizeRad(preLeadInRotation + angle)
: Program.Rotation;
}
/// <summary>
/// Offsets the part.
/// </summary>
@@ -323,6 +335,7 @@ namespace OpenNest
new Box(BoundingBox.X, BoundingBox.Y, BoundingBox.Length, BoundingBox.Width)
);
part.ownsProgram = true;
part.CopyLeadInStateFrom(this);
return part;
}
@@ -347,10 +360,24 @@ namespace OpenNest
BoundingBox.Width
)
);
part.CopyLeadInStateFrom(this);
return part;
}
/// <summary>
/// Copies the lead-in state that goes with a copied program. Without it a copy of a
/// lead-in part reads its rotation from the rebuilt program (zero), and lead-in
/// assignment does not know to strip the copied lead-ins before adding new ones.
/// </summary>
private void CopyLeadInStateFrom(Part source)
{
HasManualLeadIns = source.HasManualLeadIns;
LeadInsLocked = source.LeadInsLocked;
CuttingParameters = source.CuttingParameters;
preLeadInRotation = source.preLeadInRotation;
}
private void EnsureOwnedProgram()
{
if (!ownsProgram)