feat: add ApplyLeadIns/RemoveLeadIns to Part with CuttingParameters storage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -102,7 +102,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return ordered;
|
||||
}
|
||||
|
||||
private ContourType DetectContourType(Shape cutout)
|
||||
internal static ContourType DetectContourType(Shape cutout)
|
||||
{
|
||||
if (cutout.Entities.Count == 1 && cutout.Entities[0] is Circle)
|
||||
return ContourType.ArcCircle;
|
||||
@@ -110,7 +110,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return ContourType.Internal;
|
||||
}
|
||||
|
||||
private double ComputeNormal(Vector point, Entity entity, ContourType contourType)
|
||||
internal static double ComputeNormal(Vector point, Entity entity, ContourType contourType)
|
||||
{
|
||||
double normal;
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return Math.Angle.NormalizeRad(normal);
|
||||
}
|
||||
|
||||
private RotationType DetermineWinding(Shape shape)
|
||||
internal static RotationType DetermineWinding(Shape shape)
|
||||
{
|
||||
// Use signed area: positive = CCW, negative = CW
|
||||
var area = shape.Area();
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace OpenNest
|
||||
{
|
||||
private Vector location;
|
||||
private bool ownsProgram;
|
||||
private double preLeadInRotation;
|
||||
|
||||
public readonly Drawing BaseDrawing;
|
||||
|
||||
@@ -56,6 +57,38 @@ namespace OpenNest
|
||||
|
||||
public bool HasManualLeadIns { get; set; }
|
||||
|
||||
public bool LeadInsLocked { get; set; }
|
||||
|
||||
public CNC.CuttingStrategy.CuttingParameters CuttingParameters { get; set; }
|
||||
|
||||
public void ApplyLeadIns(CNC.CuttingStrategy.CuttingParameters parameters, Vector approachPoint)
|
||||
{
|
||||
preLeadInRotation = Rotation;
|
||||
var strategy = new CNC.CuttingStrategy.ContourCuttingStrategy { Parameters = parameters };
|
||||
var result = strategy.Apply(Program, approachPoint);
|
||||
Program = result.Program;
|
||||
CuttingParameters = parameters;
|
||||
HasManualLeadIns = true;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
public void RemoveLeadIns()
|
||||
{
|
||||
var rotation = preLeadInRotation;
|
||||
var location = Location;
|
||||
Program = BaseDrawing.Program.Clone() as Program;
|
||||
ownsProgram = true;
|
||||
|
||||
if (!Math.Tolerance.IsEqualTo(rotation, 0))
|
||||
Program.Rotate(rotation);
|
||||
|
||||
Location = location;
|
||||
HasManualLeadIns = false;
|
||||
LeadInsLocked = false;
|
||||
CuttingParameters = null;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation of the part in radians.
|
||||
/// </summary>
|
||||
|
||||
127
OpenNest.Tests/PartLeadInTests.cs
Normal file
127
OpenNest.Tests/PartLeadInTests.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests;
|
||||
|
||||
public class PartLeadInTests
|
||||
{
|
||||
private static Part MakeSquarePart()
|
||||
{
|
||||
var pgm = new Program();
|
||||
pgm.Codes.Add(new RapidMove(new Vector(0, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, 10)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(10, 10)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(10, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, 0)));
|
||||
var drawing = new Drawing("test", pgm);
|
||||
return new Part(drawing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyLeadIns_SetsHasManualLeadIns()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
|
||||
InternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
|
||||
Assert.True(part.HasManualLeadIns);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyLeadIns_StoresCuttingParameters()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
|
||||
InternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
|
||||
Assert.Same(parameters, part.CuttingParameters);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyLeadIns_ProgramContainsLeadinCodes()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
|
||||
var hasLeadin = part.Program.Codes.OfType<LinearMove>().Any(m => m.Layer == LayerType.Leadin);
|
||||
Assert.True(hasLeadin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveLeadIns_RestoresOriginalProgram()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var originalCodeCount = part.Program.Codes.Count;
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
part.RemoveLeadIns();
|
||||
|
||||
Assert.False(part.HasManualLeadIns);
|
||||
Assert.Null(part.CuttingParameters);
|
||||
Assert.Equal(originalCodeCount, part.Program.Codes.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveLeadIns_PreservesRotation()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
part.Rotate(System.Math.PI / 4); // 45 degrees
|
||||
var rotation = part.Rotation;
|
||||
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
part.RemoveLeadIns();
|
||||
|
||||
Assert.Equal(rotation, part.Rotation, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveLeadIns_PreservesLocation()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
part.Offset(20, 30);
|
||||
var location = part.Location;
|
||||
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
part.RemoveLeadIns();
|
||||
|
||||
Assert.Equal(location.X, part.Location.X, 6);
|
||||
Assert.Equal(location.Y, part.Location.Y, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeadInsLocked_DefaultsFalse()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
Assert.False(part.LeadInsLocked);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user