feat: add Plate.CutOffs collection with materialization and transform support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@ namespace OpenNest
|
||||
Parts = new ObservableList<Part>();
|
||||
Parts.ItemAdded += Parts_PartAdded;
|
||||
Parts.ItemRemoved += Parts_PartRemoved;
|
||||
CutOffs = new ObservableList<CutOff>();
|
||||
Quadrant = 1;
|
||||
}
|
||||
|
||||
@@ -92,6 +93,38 @@ namespace OpenNest
|
||||
/// </summary>
|
||||
public ObservableList<Part> Parts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cut-off lines defined on this plate.
|
||||
/// </summary>
|
||||
public ObservableList<CutOff> CutOffs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Regenerates all cut-off drawings and materializes them as parts.
|
||||
/// Existing cut-off parts are removed first, then each cut-off is
|
||||
/// regenerated and added back if it produces any geometry.
|
||||
/// </summary>
|
||||
public void RegenerateCutOffs(CutOffSettings settings)
|
||||
{
|
||||
// Remove existing cut-off parts
|
||||
for (var i = Parts.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (Parts[i].BaseDrawing.IsCutOff)
|
||||
Parts.RemoveAt(i);
|
||||
}
|
||||
|
||||
// Regenerate and materialize each cut-off
|
||||
foreach (var cutoff in CutOffs)
|
||||
{
|
||||
cutoff.Regenerate(this, settings);
|
||||
|
||||
if (cutoff.Drawing.Program.Codes.Count == 0)
|
||||
continue;
|
||||
|
||||
var part = new Part(cutoff.Drawing);
|
||||
Parts.Add(part);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of times to cut the plate.
|
||||
/// </summary>
|
||||
@@ -242,11 +275,20 @@ namespace OpenNest
|
||||
/// <param name="angle"></param>
|
||||
public void Rotate(double angle)
|
||||
{
|
||||
for (int i = 0; i < Parts.Count; ++i)
|
||||
for (var i = Parts.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (Parts[i].BaseDrawing.IsCutOff)
|
||||
Parts.RemoveAt(i);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Parts.Count; ++i)
|
||||
{
|
||||
var part = Parts[i];
|
||||
part.Rotate(angle);
|
||||
}
|
||||
|
||||
foreach (var cutoff in CutOffs)
|
||||
cutoff.Position = cutoff.Position.Rotate(angle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -256,11 +298,24 @@ namespace OpenNest
|
||||
/// <param name="origin"></param>
|
||||
public void Rotate(double angle, Vector origin)
|
||||
{
|
||||
for (int i = 0; i < Parts.Count; ++i)
|
||||
for (var i = Parts.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (Parts[i].BaseDrawing.IsCutOff)
|
||||
Parts.RemoveAt(i);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Parts.Count; ++i)
|
||||
{
|
||||
var part = Parts[i];
|
||||
part.Rotate(angle, origin);
|
||||
}
|
||||
|
||||
foreach (var cutoff in CutOffs)
|
||||
{
|
||||
var pos = cutoff.Position - origin;
|
||||
pos = pos.Rotate(angle);
|
||||
cutoff.Position = pos + origin;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -270,11 +325,22 @@ namespace OpenNest
|
||||
/// <param name="y"></param>
|
||||
public void Offset(double x, double y)
|
||||
{
|
||||
for (int i = 0; i < Parts.Count; ++i)
|
||||
// Remove cut-off parts before transforming
|
||||
for (var i = Parts.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (Parts[i].BaseDrawing.IsCutOff)
|
||||
Parts.RemoveAt(i);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Parts.Count; ++i)
|
||||
{
|
||||
var part = Parts[i];
|
||||
part.Offset(x, y);
|
||||
}
|
||||
|
||||
// Transform cut-off positions
|
||||
foreach (var cutoff in CutOffs)
|
||||
cutoff.Position = new Vector(cutoff.Position.X + x, cutoff.Position.Y + y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -283,11 +349,20 @@ namespace OpenNest
|
||||
/// <param name="voffset"></param>
|
||||
public void Offset(Vector voffset)
|
||||
{
|
||||
for (int i = 0; i < Parts.Count; ++i)
|
||||
for (var i = Parts.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (Parts[i].BaseDrawing.IsCutOff)
|
||||
Parts.RemoveAt(i);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Parts.Count; ++i)
|
||||
{
|
||||
var part = Parts[i];
|
||||
part.Offset(voffset);
|
||||
}
|
||||
|
||||
foreach (var cutoff in CutOffs)
|
||||
cutoff.Position = new Vector(cutoff.Position.X + voffset.X, cutoff.Position.Y + voffset.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -215,4 +215,52 @@ public class CutOffTests
|
||||
Assert.True(hCut.Drawing.Program.Codes.Count > 0);
|
||||
Assert.True(vCut.Drawing.Program.Codes.Count > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Plate_RegenerateCutOffs_MaterializesParts()
|
||||
{
|
||||
var plate = new Plate(100, 50);
|
||||
var cutoff = new CutOff(new Geometry.Vector(25, 10), CutOffAxis.Vertical);
|
||||
plate.CutOffs.Add(cutoff);
|
||||
|
||||
plate.RegenerateCutOffs(new CutOffSettings());
|
||||
|
||||
Assert.Single(plate.Parts);
|
||||
Assert.True(plate.Parts[0].BaseDrawing.IsCutOff);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Plate_RegenerateCutOffs_ReplacesOldParts()
|
||||
{
|
||||
var plate = new Plate(100, 50);
|
||||
var cutoff = new CutOff(new Geometry.Vector(25, 10), CutOffAxis.Vertical);
|
||||
plate.CutOffs.Add(cutoff);
|
||||
|
||||
var settings = new CutOffSettings();
|
||||
plate.RegenerateCutOffs(settings);
|
||||
plate.RegenerateCutOffs(settings);
|
||||
|
||||
Assert.Single(plate.Parts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Plate_RegenerateCutOffs_DoesNotAffectRegularParts()
|
||||
{
|
||||
var pgm = new OpenNest.CNC.Program();
|
||||
pgm.Codes.Add(new OpenNest.CNC.RapidMove(new Geometry.Vector(0, 0)));
|
||||
pgm.Codes.Add(new OpenNest.CNC.LinearMove(new Geometry.Vector(5, 5)));
|
||||
var drawing = new Drawing("real", pgm);
|
||||
|
||||
var plate = new Plate(100, 50);
|
||||
plate.Parts.Add(new Part(drawing));
|
||||
|
||||
var cutoff = new CutOff(new Geometry.Vector(25, 10), CutOffAxis.Vertical);
|
||||
plate.CutOffs.Add(cutoff);
|
||||
|
||||
plate.RegenerateCutOffs(new CutOffSettings());
|
||||
|
||||
Assert.Equal(2, plate.Parts.Count);
|
||||
Assert.False(plate.Parts[0].BaseDrawing.IsCutOff);
|
||||
Assert.True(plate.Parts[1].BaseDrawing.IsCutOff);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user