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:
+79
-4
@@ -47,6 +47,7 @@ namespace OpenNest
|
|||||||
Parts = new ObservableList<Part>();
|
Parts = new ObservableList<Part>();
|
||||||
Parts.ItemAdded += Parts_PartAdded;
|
Parts.ItemAdded += Parts_PartAdded;
|
||||||
Parts.ItemRemoved += Parts_PartRemoved;
|
Parts.ItemRemoved += Parts_PartRemoved;
|
||||||
|
CutOffs = new ObservableList<CutOff>();
|
||||||
Quadrant = 1;
|
Quadrant = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +93,38 @@ namespace OpenNest
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ObservableList<Part> Parts { get; set; }
|
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>
|
/// <summary>
|
||||||
/// The number of times to cut the plate.
|
/// The number of times to cut the plate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -242,11 +275,20 @@ namespace OpenNest
|
|||||||
/// <param name="angle"></param>
|
/// <param name="angle"></param>
|
||||||
public void Rotate(double angle)
|
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];
|
var part = Parts[i];
|
||||||
part.Rotate(angle);
|
part.Rotate(angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var cutoff in CutOffs)
|
||||||
|
cutoff.Position = cutoff.Position.Rotate(angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -256,11 +298,24 @@ namespace OpenNest
|
|||||||
/// <param name="origin"></param>
|
/// <param name="origin"></param>
|
||||||
public void Rotate(double angle, Vector origin)
|
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];
|
var part = Parts[i];
|
||||||
part.Rotate(angle, origin);
|
part.Rotate(angle, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var cutoff in CutOffs)
|
||||||
|
{
|
||||||
|
var pos = cutoff.Position - origin;
|
||||||
|
pos = pos.Rotate(angle);
|
||||||
|
cutoff.Position = pos + origin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -270,11 +325,22 @@ namespace OpenNest
|
|||||||
/// <param name="y"></param>
|
/// <param name="y"></param>
|
||||||
public void Offset(double x, double y)
|
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];
|
var part = Parts[i];
|
||||||
part.Offset(x, y);
|
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>
|
/// <summary>
|
||||||
@@ -283,11 +349,20 @@ namespace OpenNest
|
|||||||
/// <param name="voffset"></param>
|
/// <param name="voffset"></param>
|
||||||
public void Offset(Vector voffset)
|
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];
|
var part = Parts[i];
|
||||||
part.Offset(voffset);
|
part.Offset(voffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var cutoff in CutOffs)
|
||||||
|
cutoff.Position = new Vector(cutoff.Position.X + voffset.X, cutoff.Position.Y + voffset.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -215,4 +215,52 @@ public class CutOffTests
|
|||||||
Assert.True(hCut.Drawing.Program.Codes.Count > 0);
|
Assert.True(hCut.Drawing.Program.Codes.Count > 0);
|
||||||
Assert.True(vCut.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