mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-26 22:01:06 -04:00
fix(leads): keep manual lead-ins off a display perimeter
Place Lead-in built its contours from cut-layer entities only, so on a blank the largest cutout looked like the outside and took an external lead pierced on the blank; committing then regenerated the part with the outline as a cut perimeter. The legacy whole-part strategy did the same. Both strategies now refuse a program with a display perimeter and leave the part unchanged, and Place Lead-in explains that such a part's cutouts get their leads from Plan Cutting instead of selecting it.
This commit is contained in:
1 parent
8f568482bc
commit
684207039a
4 files changed
+43
No files matched your search
@@ -20,6 +20,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
public CuttingResult Apply(Program partProgram, Vector approachPoint, Vector nextPartStart)
|
||||
{
|
||||
var entities = partProgram.ToGeometry();
|
||||
RefuseDisplayPerimeter(entities);
|
||||
var breakCuts = TakeBreakCuts(entities);
|
||||
entities.RemoveAll(e => e.Layer == SpecialLayers.Rapid);
|
||||
|
||||
@@ -107,6 +108,14 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return new CuttingResult { Program = result, LastCutPoint = perimeterPt };
|
||||
}
|
||||
|
||||
// These tools would lead the outline or mistake the largest cutout for it (an External lead
|
||||
// pierced on the blank). Only the cutting planner knows every contour of such a part is a hole.
|
||||
private static void RefuseDisplayPerimeter(List<Entity> entities)
|
||||
{
|
||||
if (entities.Exists(e => e.Layer == SpecialLayers.DisplayPerimeter))
|
||||
throw new InvalidOperationException(DisplayPerimeterTail.LeadInRefusal);
|
||||
}
|
||||
|
||||
public CuttingResult ApplySingle(
|
||||
Program partProgram,
|
||||
Vector point,
|
||||
@@ -115,6 +124,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
)
|
||||
{
|
||||
var entities = partProgram.ToGeometry();
|
||||
RefuseDisplayPerimeter(entities);
|
||||
var breakCuts = TakeBreakCuts(entities);
|
||||
entities.RemoveAll(e => e.Layer == SpecialLayers.Rapid);
|
||||
|
||||
|
||||
@@ -17,6 +17,11 @@ namespace OpenNest.CNC
|
||||
/// <summary>The comment that starts the tail; every code after it is display only.</summary>
|
||||
public const string Marker = "DISPLAY PERIMETER NEVER CUT";
|
||||
|
||||
/// <summary>Why the manual and legacy lead-in tools leave a display-perimeter part alone.</summary>
|
||||
public const string LeadInRefusal =
|
||||
"This part's outline is a display perimeter: a supplied blank that is never cut. "
|
||||
+ "Lead-ins for its cutouts come from Plan Cutting, which keeps every pierce inside a cutout.";
|
||||
|
||||
/// <summary>The index of the tail's marker in <paramref name="program"/>'s codes, or -1.</summary>
|
||||
public static int IndexOf(Program program)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.CNC.CuttingPlanning;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Engine.CuttingPlanning;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
@@ -144,6 +145,25 @@ public class DisplayPerimeterTests
|
||||
Assert.DoesNotContain(simulation.Steps, step => step.Layer == LayerType.DisplayPerimeter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ManualAndLegacyLeadIns_RefuseADisplayPerimeterAndLeaveThePartAlone()
|
||||
{
|
||||
var part = new Part(new Drawing("door", Door()), Vector.Zero);
|
||||
var before = ExplicitContourTests.Fingerprint(part.Program);
|
||||
var edge = ConvertProgram.ToGeometry(part.Program).First(e => e.Layer == SpecialLayers.DisplayPerimeter);
|
||||
var hole = ConvertProgram.ToGeometry(part.Program).First(e => e.Layer == SpecialLayers.Cut);
|
||||
|
||||
var onEdge = Assert.Throws<InvalidOperationException>(() => part.ApplySingleLeadIn(
|
||||
ExplicitContourTests.Parameters(), new Vector(0, 10), edge, OpenNest.CNC.CuttingStrategy.ContourType.External));
|
||||
Assert.Throws<InvalidOperationException>(() => part.ApplySingleLeadIn(
|
||||
ExplicitContourTests.Parameters(), new Vector(5, 7), hole, OpenNest.CNC.CuttingStrategy.ContourType.Internal));
|
||||
Assert.Throws<InvalidOperationException>(() => part.ApplyLeadIns(ExplicitContourTests.Parameters(), Vector.Zero));
|
||||
|
||||
Assert.Contains("Plan Cutting", onEdge.Message);
|
||||
Assert.False(part.HasManualLeadIns);
|
||||
Assert.Equal(before, ExplicitContourTests.Fingerprint(part.Program));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Posting_RefusesAnUnplannedDisplayPerimeter()
|
||||
{
|
||||
|
||||
@@ -423,6 +423,14 @@ namespace OpenNest.Actions
|
||||
if (part.BaseDrawing.IsCutOff)
|
||||
return;
|
||||
|
||||
// A supplied blank's cutouts get their leads from Plan Cutting only.
|
||||
if (CNC.DisplayPerimeterTail.HasDisplayPerimeterMotion(part.BaseDrawing.Program))
|
||||
{
|
||||
MessageBox.Show(plateView.FindForm(), CNC.DisplayPerimeterTail.LeadInRefusal, "Place Lead-in",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedLayoutPart = layoutPart;
|
||||
selectedPart = part;
|
||||
|
||||
|
||||
Reference in new issue
Block a user