refactor(cutting): merge circle lead settings into internal leads

Full circles now take InternalLeadIn/InternalLeadOut like every other
cutout; the ArcCircle lead settings and the cutting panel's Arc / Circle
tab are removed. Circle-specific geometry handling (radius clamp, angle
rounding, pierce zone) is unchanged.

Older nest files and desktop settings still load: their arcCircleLeadIn/
arcCircleLeadOut keys are ignored and no longer written, so re-planned
circles take the internal leads. Saved part programs are untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-10-24 21:20:09 -04:00
1 parent 8cd9b2cbe3
commit d4269c1f06
49 files changed
+66 -127

No files matched your search

@@ -33,10 +33,8 @@ internal static class OwnedCuttingParameters
PierceDiameter = Dimension(source.PierceDiameter),
ExternalLeadIn = CopyLeadIn(source.ExternalLeadIn),
InternalLeadIn = CopyLeadIn(source.InternalLeadIn),
ArcCircleLeadIn = CopyLeadIn(source.ArcCircleLeadIn),
ExternalLeadOut = CopyLeadOut(source.ExternalLeadOut),
InternalLeadOut = CopyLeadOut(source.InternalLeadOut),
ArcCircleLeadOut = CopyLeadOut(source.ArcCircleLeadOut),
RoundLeadInAngles = source.RoundLeadInAngles,
LeadInAngleIncrement = source.LeadInAngleIncrement,
TabConfig = source.TabConfig == null
@@ -208,17 +208,15 @@ public sealed class PreparedContours
return pins.Any(p => p?.IsResolved != false) ? new PreparedContours(unpinned, pins, token) : unpinned;
}
// The pin's leads replace every contour type's leads, since the type the emitter detects is
// The pin's leads replace both lead sets, since the type the emitter detects is
// not the caller's concern; angle rounding is off because a pinned entry never moves.
private static CuttingParameters PinParameters(CuttingParameters shared, ContourCutPin pin)
{
var owned = OwnedCuttingParameters.Copy(shared);
owned.ExternalLeadIn = pin.LeadIn;
owned.InternalLeadIn = pin.LeadIn;
owned.ArcCircleLeadIn = pin.LeadIn;
owned.ExternalLeadOut = pin.LeadOut;
owned.InternalLeadOut = pin.LeadOut;
owned.ArcCircleLeadOut = pin.LeadOut;
owned.RoundLeadInAngles = false;
owned.TabsEnabled = pin.HasTab;
if (pin.HasTab)
@@ -83,8 +83,6 @@ internal static class StateFingerprint
Out(p.ExternalLeadOut);
Lead(p.InternalLeadIn);
Out(p.InternalLeadOut);
Lead(p.ArcCircleLeadIn);
Out(p.ArcCircleLeadOut);
Number(p.PierceClearance);
Number(p.PierceDiameter);
Flag(p.RoundLeadInAngles);
@@ -1103,8 +1103,7 @@ namespace OpenNest.CNC.CuttingStrategy
{
return contourType switch
{
ContourType.ArcCircle => Parameters.ArcCircleLeadIn ?? Parameters.InternalLeadIn,
ContourType.Internal => Parameters.InternalLeadIn,
ContourType.Internal or ContourType.ArcCircle => Parameters.InternalLeadIn,
_ => Parameters.ExternalLeadIn,
};
}
@@ -1113,8 +1112,7 @@ namespace OpenNest.CNC.CuttingStrategy
{
return contourType switch
{
ContourType.ArcCircle => Parameters.ArcCircleLeadOut ?? Parameters.InternalLeadOut,
ContourType.Internal => Parameters.InternalLeadOut,
ContourType.Internal or ContourType.ArcCircle => Parameters.InternalLeadOut,
_ => Parameters.ExternalLeadOut,
};
}
@@ -15,13 +15,14 @@ namespace OpenNest.CNC.CuttingStrategy
public LeadIn ExternalLeadIn { get; set; } = new NoLeadIn();
public LeadOut ExternalLeadOut { get; set; } = new NoLeadOut();
/// <summary>
/// The lead-in of every cutout, full circles included; circles still get their own
/// geometry handling (radius clamp, angle rounding) when the lead is emitted.
/// </summary>
public LeadIn InternalLeadIn { get; set; } =
new LineLeadIn { Length = 0.125, ApproachAngle = 90 };
public LeadOut InternalLeadOut { get; set; } = new NoLeadOut();
public LeadIn ArcCircleLeadIn { get; set; } = new NoLeadIn();
public LeadOut ArcCircleLeadOut { get; set; } = new NoLeadOut();
public double PierceClearance { get; set; } = 0.0625;
/// <summary>
+1 -3
View File
@@ -55,17 +55,15 @@ public static class MachineCuttingDefaults
var scale = Scale(machine!.Units, nest.Units);
var kerf = settings.Kerf * scale;
// Each contour type gets its own instance, as the cutting panel builds them.
// Each lead set gets its own instance, as the cutting panel builds them.
if (ToLeadIn(settings.LeadIn, scale, kerf) is { } leadIn)
{
if (leadIn is not CleanHoleLeadIn)
parameters.ExternalLeadIn = leadIn;
parameters.InternalLeadIn = ToLeadIn(settings.LeadIn, scale, kerf);
parameters.ArcCircleLeadIn = ToLeadIn(settings.LeadIn, scale, kerf);
}
parameters.ExternalLeadOut = ToLeadOut(settings.LeadOut, scale);
parameters.InternalLeadOut = ToLeadOut(settings.LeadOut, scale);
parameters.ArcCircleLeadOut = ToLeadOut(settings.LeadOut, scale);
parameters.Kerf = kerf;
parameters.MachineName = machine.Name;
parameters.MaterialName = nest.Material.Name;
@@ -216,7 +216,6 @@ public class CuttingPlanFrontEndTests : IDisposable
{
ExternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 45 },
InternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 45 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 45 },
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
PierceClearance = 0.05,
@@ -20,7 +20,6 @@ public class CuttingParametersSerializerTests
{
ExternalLeadIn = leadIn,
InternalLeadIn = leadIn,
ArcCircleLeadIn = leadIn,
TabConfig = new NormalTab { Size = 0.42, TabLeadIn = leadIn },
};
@@ -28,7 +27,6 @@ public class CuttingParametersSerializerTests
AssertEquivalent(leadIn, restored.ExternalLeadIn);
AssertEquivalent(leadIn, restored.InternalLeadIn);
AssertEquivalent(leadIn, restored.ArcCircleLeadIn);
AssertEquivalent(leadIn, restored.TabConfig.TabLeadIn);
}
@@ -43,7 +41,6 @@ public class CuttingParametersSerializerTests
{
ExternalLeadOut = leadOut,
InternalLeadOut = leadOut,
ArcCircleLeadOut = leadOut,
TabConfig = new NormalTab { Size = 0.42, TabLeadOut = leadOut },
};
@@ -51,7 +48,6 @@ public class CuttingParametersSerializerTests
AssertEquivalent(leadOut, restored.ExternalLeadOut);
AssertEquivalent(leadOut, restored.InternalLeadOut);
AssertEquivalent(leadOut, restored.ArcCircleLeadOut);
AssertEquivalent(leadOut, restored.TabConfig.TabLeadOut);
}
@@ -118,11 +114,6 @@ public class CuttingParametersSerializerTests
Assert.Equal(43, lineOut.ApproachAngle);
Assert.Equal(0.12, Assert.IsType<ArcLeadIn>(restored.InternalLeadIn).Radius);
Assert.Equal(0.09, Assert.IsType<ArcLeadOut>(restored.InternalLeadOut).Radius);
var cleanHole = Assert.IsType<CleanHoleLeadIn>(restored.ArcCircleLeadIn);
Assert.Equal(0.8, cleanHole.LineLength);
Assert.Equal(0.3, cleanHole.ArcRadius);
Assert.Equal(0.04, cleanHole.Kerf);
Assert.IsType<NoLeadOut>(restored.ArcCircleLeadOut);
Assert.True(restored.TabsEnabled);
Assert.Equal(0.375, Assert.IsType<NormalTab>(restored.TabConfig).Size);
Assert.Equal(0.0625, restored.PierceClearance);
@@ -133,6 +124,26 @@ public class CuttingParametersSerializerTests
AssertEquivalent(new SequenceParameters(), restored.Sequencing);
}
[Fact]
public void Deserialize_LegacyArcCircleLeads_AreDroppedInFavorOfTheInternalLeads()
{
const string json = """
{
"internalLeadIn": { "type": "Line", "length": 0.125, "approachAngle": 90 },
"internalLeadOut": { "type": "None" },
"arcCircleLeadIn": { "type": "CleanHole", "lineLength": 0.8,
"arcRadius": 0.3, "kerf": 0.04 },
"arcCircleLeadOut": { "type": "Arc", "radius": 0.09 }
}
""";
var restored = CuttingParametersSerializer.Deserialize(json);
Assert.Equal(0.125, Assert.IsType<LineLeadIn>(restored.InternalLeadIn).Length);
Assert.IsType<NoLeadOut>(restored.InternalLeadOut);
Assert.DoesNotContain("arcCircle", CuttingParametersSerializer.Serialize(restored));
}
[Theory]
[InlineData(0)]
[InlineData(-1)]
@@ -150,10 +161,8 @@ public class CuttingParametersSerializerTests
Assert.IsType<NoLeadIn>(restored.ExternalLeadIn);
Assert.IsType<NoLeadIn>(restored.InternalLeadIn);
Assert.IsType<NoLeadIn>(restored.ArcCircleLeadIn);
Assert.IsType<NoLeadOut>(restored.ExternalLeadOut);
Assert.IsType<NoLeadOut>(restored.InternalLeadOut);
Assert.IsType<NoLeadOut>(restored.ArcCircleLeadOut);
Assert.Equal(0, Assert.IsType<NormalTab>(restored.TabConfig).Size);
Assert.Equal(0, restored.PierceClearance);
Assert.Equal(0, restored.PierceDiameter);
@@ -297,8 +306,6 @@ public class CuttingParametersSerializerTests
ExternalLeadOut = CreateLeadOut("Line"),
InternalLeadIn = CreateLeadIn("CleanHole"),
InternalLeadOut = CreateLeadOut("Arc"),
ArcCircleLeadIn = CreateLeadIn("LineArc"),
ArcCircleLeadOut = CreateLeadOut("None"),
PierceClearance = 0.17,
PierceDiameter = 0.41,
RoundLeadInAngles = true,
+3 -2
View File
@@ -19,8 +19,9 @@ public class CuttingParametersDto
public LeadOutDto ExternalLeadOut { get; set; }
public LeadInDto InternalLeadIn { get; set; }
public LeadOutDto InternalLeadOut { get; set; }
public LeadInDto ArcCircleLeadIn { get; set; }
public LeadOutDto ArcCircleLeadOut { get; set; }
// Older files also stored arcCircleLeadIn/arcCircleLeadOut. Circles now use the internal
// leads, so those keys are ignored on read and no longer written.
public bool TabsEnabled { get; set; }
// Legacy settings only stored tabWidth. A missing TabConfig uses that width;
@@ -63,8 +63,6 @@ public static class CuttingParametersSerializer
ExternalLeadOut = ToLeadOutDto(parameters.ExternalLeadOut),
InternalLeadIn = ToLeadInDto(parameters.InternalLeadIn),
InternalLeadOut = ToLeadOutDto(parameters.InternalLeadOut),
ArcCircleLeadIn = ToLeadInDto(parameters.ArcCircleLeadIn),
ArcCircleLeadOut = ToLeadOutDto(parameters.ArcCircleLeadOut),
TabsEnabled = parameters.TabsEnabled,
TabWidth = parameters.TabConfig?.Size ?? 0.25,
TabConfig = ToTabDto(parameters.TabConfig),
@@ -97,8 +95,6 @@ public static class CuttingParametersSerializer
ExternalLeadOut = FromLeadOutDto(dto.ExternalLeadOut),
InternalLeadIn = FromLeadInDto(dto.InternalLeadIn),
InternalLeadOut = FromLeadOutDto(dto.InternalLeadOut),
ArcCircleLeadIn = FromLeadInDto(dto.ArcCircleLeadIn),
ArcCircleLeadOut = FromLeadOutDto(dto.ArcCircleLeadOut),
TabsEnabled = dto.TabsEnabled,
TabConfig = dto.TabConfig == null
? new NormalTab { Size = dto.TabWidth }
@@ -301,8 +301,6 @@ public class CincinnatiPostRegressionTests
part.ApplyLeadIns(
new CuttingParameters
{
ArcCircleLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ArcCircleLeadOut = new NoLeadOut(),
ExternalLeadIn = new LineLeadIn { Length = leadIn, ApproachAngle = 90 },
ExternalLeadOut = new NoLeadOut(),
},
@@ -169,8 +169,6 @@ public class HolePlacementRegressionTests
part.ApplyLeadIns(
new CuttingParameters
{
ArcCircleLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ArcCircleLeadOut = new NoLeadOut(),
ExternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 },
ExternalLeadOut = new NoLeadOut(),
},
@@ -184,7 +184,6 @@ public class CIFiberPostProcessorTests
{
InternalLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ExternalLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
};
TestLeadIns.Apply(plate);
@@ -54,14 +54,13 @@ public class CIFiberSampleRegressionTests
var plate = nest.Plates[0];
plate.CuttingParameters = new CuttingParameters
{
// OpenNest's own short perpendicular linear leads, including the
// circles (ArcCircleLeadIn). TF5200 13.2.4.1 requires a LINEAR
// OpenNest's own short perpendicular linear leads; circles take the
// internal lead. TF5200 13.2.4.1 requires a LINEAR
// first motion block after G41/G42, so holes must have linear
// leads. (The sample itself pierces holes at their centre and
// uses 0.125 in perimeter leads; see the saved-lead-in test.)
InternalLeadIn = new LineLeadIn { Length = 0.075, ApproachAngle = 90 },
ExternalLeadIn = new LineLeadIn { Length = 0.075, ApproachAngle = 90 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.075, ApproachAngle = 90 },
PierceClearance = 0.02,
};
@@ -116,7 +116,6 @@ public class ContinuedContourCheckTests
{
ExternalLeadIn = new LineLeadIn { Length = 0.2, ApproachAngle = 90 },
InternalLeadIn = new LineLeadIn { Length = 0.1, ApproachAngle = 90 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.1, ApproachAngle = 90 },
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
};
@@ -175,7 +175,7 @@ public class ContourCandidateEmissionTests
var parameters = ExplicitContourTests.Parameters();
parameters.RoundLeadInAngles = true;
parameters.LeadInAngleIncrement = 90;
parameters.ArcCircleLeadIn = new LineLeadIn { Length = 2 };
parameters.InternalLeadIn = new LineLeadIn { Length = 2 };
var p = ExplicitContourTests.Square(false);
foreach (var center in new[] { new Vector(3, 3), new Vector(7, 7) })
{
@@ -116,7 +116,6 @@ public class ContourEntryFeasibilityTests
var parameters = ExplicitContourTests.Parameters();
parameters.ExternalLeadIn = new NoLeadIn();
parameters.InternalLeadIn = new NoLeadIn();
parameters.ArcCircleLeadIn = new NoLeadIn();
var clean = ExplicitContourTests.Square(false);
var prepared = PreparedContours.Capture(clean, parameters);
var choice = prepared.Entry(0, 0, new Vector(0, 5));
@@ -106,7 +106,6 @@ public class ContourRecoveryFileTests
{
parameters.ExternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
parameters.InternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
parameters.ArcCircleLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
}
return parameters;
}
@@ -90,7 +90,6 @@ public class CuttingGridOrderTests
{
ExternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 },
InternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 },
};
var result = CuttingPlanService.Plan(CuttingPlanRequest.ForPlate(plate,
@@ -171,7 +171,6 @@ public class CuttingReplayContractTests
var settings = ExplicitContourTests.Parameters();
settings.RoundLeadInAngles = true;
settings.LeadInAngleIncrement = 90;
settings.ArcCircleLeadIn = new LineLeadIn { Length = 10 };
var clean = PreparedContourTests.Holes();
if (shape == "mixed-circles") clean.Codes.OfType<ArcMove>().Last().Rotation = RotationType.CW;
if (shape == "arcs")
@@ -181,6 +180,11 @@ public class CuttingReplayContractTests
clean.ArcTo(4, 3, 5, 3, RotationType.CCW);
clean.LineTo(6, 3);
}
else
{
// Circles clamp an over-long lead to their radius; the arc slot has no clamp.
settings.InternalLeadIn = new LineLeadIn { Length = 10 };
}
var part = new Part(new Drawing("native", clean));
var snapshot = CuttingPlanService.Capture(new CuttingPlanRequest([part], Start, confirmedParameters: settings));
var ready = CuttingPlanService.Plan(snapshot);
@@ -71,7 +71,7 @@ public class ExplicitContourTests
var parameters = Parameters("line");
parameters.RoundLeadInAngles = true;
parameters.LeadInAngleIncrement = 90;
parameters.ArcCircleLeadIn = new LineLeadIn { Length = 2 };
parameters.InternalLeadIn = new LineLeadIn { Length = 2 };
var result = new ContourCuttingStrategy { Parameters = parameters }.Apply(program, new Vector(20, 20));
var calls = result.Program.Codes.OfType<SubProgramCall>().ToArray();
Assert.Equal(2, calls.Length);
@@ -124,7 +124,6 @@ public class ExplicitContourTests
{
ExternalLeadIn = lead,
InternalLeadIn = lead,
ArcCircleLeadIn = lead,
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
PierceClearance = 0.05
@@ -44,10 +44,8 @@ public class HoleDepartureTests
{
ExternalLeadIn = lead,
InternalLeadIn = lead,
ArcCircleLeadIn = lead,
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
ArcCircleLeadOut = new NoLeadOut(),
PierceClearance = 0
};
}
@@ -25,7 +25,6 @@ public class HoleLookAheadTests
{
var p = ExplicitContourTests.Parameters();
p.InternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
p.ArcCircleLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
p.PierceClearance = 0;
return p;
}
@@ -25,10 +25,8 @@ public class ImportedArcHoleTests
{
ExternalLeadIn = lead,
InternalLeadIn = lead,
ArcCircleLeadIn = lead,
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
ArcCircleLeadOut = new NoLeadOut(),
PierceClearance = 0.0625
};
}
@@ -28,7 +28,6 @@ public class InterlockingHoleRouteTests
{
parameters.ExternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
parameters.InternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
parameters.ArcCircleLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
}
var before = parts.Select(p => ExplicitContourTests.Fingerprint(p.Program)).ToArray();
var snapshot = CuttingPlanService.Capture(new CuttingPlanRequest(parts,
@@ -16,7 +16,6 @@ public class JointCuttingPlanTests
var (part, parameters) = Crossing();
parameters.ExternalLeadIn = new NoLeadIn();
parameters.InternalLeadIn = new NoLeadIn();
parameters.ArcCircleLeadIn = new NoLeadIn();
var unchanged = Unchanged(part, parameters);
var source = Read(part.Program, part.Location);
Assert.Contains(new ReleasedContourState(reportMissingLeadIns: false).Check(source, Vector.Zero, 1),
@@ -36,10 +36,8 @@ public class OwnedCuttingParameterTests
PierceDiameter = 0.3,
ExternalLeadIn = leadIn,
InternalLeadIn = leadIn,
ArcCircleLeadIn = leadIn,
ExternalLeadOut = leadOut,
InternalLeadOut = leadOut,
ArcCircleLeadOut = leadOut,
TabConfig = tab,
TabsEnabled = true,
SupportTabs = true,
@@ -122,7 +120,7 @@ public class OwnedCuttingParameterTests
case "null-settings": source = null; break;
case "null-sequence": source.Sequencing = null; break;
case "null-assignment": source.Assignment = null; break;
case "null-lead": source.ArcCircleLeadIn = null; break;
case "null-lead": source.InternalLeadIn = null; break;
case "null-leadout": source.InternalLeadOut = null; break;
case "null-tab": source.TabsEnabled = true; break;
case "dimension": source.PartSpacing = -1; break;
@@ -131,7 +129,7 @@ public class OwnedCuttingParameterTests
case "enum": source.Assignment.Method = (SequenceMethod)6; break;
case "tab-lead": source.TabConfig = new NormalTab { TabLeadIn = new ArcLeadIn { Radius = double.PositiveInfinity } }; break;
case "custom-in": source.InternalLeadIn = new CustomLeadIn(); break;
case "custom-out": source.ArcCircleLeadOut = new CustomLeadOut(); break;
case "custom-out": source.InternalLeadOut = new CustomLeadOut(); break;
case "custom-tab": source.TabConfig = new CustomTab(); break;
case "custom-settings": source = new CustomParameters(); break;
case "custom-sequence": source.Sequencing = new CustomSequence(); break;
@@ -165,7 +165,7 @@ public class PerimeterLookAheadTests
var parameters = Parameters();
parameters.RoundLeadInAngles = false;
parameters.PierceClearance = 0;
parameters.ArcCircleLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
parameters.InternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
var arrival = location + new Vector(20, 8);
var before = ExplicitContourTests.Fingerprint(part.Program);
var snapshot = CuttingPlanService.Capture(new CuttingPlanRequest([part], arrival,
@@ -322,10 +322,8 @@ public class PierceZoneTests
{
ExternalLeadIn = new LineLeadIn { Length = 1, ApproachAngle = 90 },
InternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 },
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
ArcCircleLeadOut = new NoLeadOut(),
PierceClearance = 0,
PierceDiameter = pierceDiameter,
};
@@ -168,7 +168,6 @@ public class PinnedContourTests
{
ExternalLeadIn = new ArcLeadIn { Radius = 0.15 },
InternalLeadIn = new ArcLeadIn { Radius = 0.15 },
ArcCircleLeadIn = new ArcLeadIn { Radius = 0.15 },
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
PierceClearance = 0.05
@@ -188,7 +188,7 @@ public class PreparedContourTests
{
var source = Holes();
var parameters = ExplicitContourTests.Parameters();
parameters.ArcCircleLeadIn = new LineLeadIn { Length = 10 };
parameters.InternalLeadIn = new LineLeadIn { Length = 10 };
parameters.RoundLeadInAngles = true;
parameters.LeadInAngleIncrement = 90;
var prepared = PreparedContours.Capture(source, parameters);
@@ -129,7 +129,6 @@ public partial class ProblemNestRegressionTests(ITestOutputHelper output)
var parameters = new CuttingParameters();
parameters.ExternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
parameters.InternalLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
parameters.ArcCircleLeadIn = new LineLeadIn { Length = 0.15, ApproachAngle = 90 };
return parameters;
}
@@ -71,7 +71,7 @@ public class SettingsFreshnessTests
switch (slot)
{
case "lead-in": settings.InternalLeadIn = new CustomLeadIn(); break;
case "lead-out": settings.ArcCircleLeadOut = new CustomLeadOut(); break;
case "lead-out": settings.InternalLeadOut = new CustomLeadOut(); break;
case "tab": settings.TabConfig = new CustomTab(); break;
case "tab-lead-in": settings.TabConfig = new NormalTab { TabLeadIn = new CustomLeadIn() }; break;
case "sequence": settings.Sequencing = new CustomSequence(); break;
@@ -172,10 +172,8 @@ public class SettingsFreshnessTests
{
ExternalLeadIn = lead,
InternalLeadIn = lead,
ArcCircleLeadIn = lead,
ExternalLeadOut = leadOut,
InternalLeadOut = leadOut,
ArcCircleLeadOut = leadOut,
TabConfig = tab,
TabsEnabled = true
};
@@ -238,7 +238,6 @@ public class SideCoverageRegressionTests
{
ExternalLeadIn = new LineLeadIn { Length = length, ApproachAngle = angle },
InternalLeadIn = new LineLeadIn { Length = length, ApproachAngle = angle },
ArcCircleLeadIn = new LineLeadIn { Length = length },
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
TabsEnabled = false,
@@ -123,8 +123,6 @@ public class HoleSubProgramTests
{
Parameters = new CuttingParameters
{
ArcCircleLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ArcCircleLeadOut = new NoLeadOut(),
},
};
@@ -167,8 +165,6 @@ public class HoleSubProgramTests
{
RoundLeadInAngles = true,
LeadInAngleIncrement = 5.0,
ArcCircleLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ArcCircleLeadOut = new NoLeadOut(),
},
};
@@ -222,8 +218,6 @@ public class HoleSubProgramTests
{
Parameters = new CuttingParameters
{
ArcCircleLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ArcCircleLeadOut = new NoLeadOut(),
},
};
@@ -283,8 +277,6 @@ public class HoleSubProgramTests
{
RoundLeadInAngles = true,
LeadInAngleIncrement = 5.0,
ArcCircleLeadIn = new LineLeadIn { Length = 0.125, ApproachAngle = 90 },
ArcCircleLeadOut = new NoLeadOut(),
ExternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 },
ExternalLeadOut = new NoLeadOut(),
};
@@ -32,7 +32,7 @@ public class PartLeadInTransformTests
new()
{
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
InternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
};
private static Part MakeLeadInPart(Drawing drawing, double rotation)
@@ -48,14 +48,14 @@ public class MachineCuttingDefaultsTests
Assert.True(MachineCuttingDefaults.ApplyTo(parameters, Machine(LineArc), NestOf(0.25)));
foreach (var leadIn in new[] { parameters.ExternalLeadIn, parameters.InternalLeadIn, parameters.ArcCircleLeadIn })
foreach (var leadIn in new[] { parameters.ExternalLeadIn, parameters.InternalLeadIn })
{
var lineArc = Assert.IsType<LineArcLeadIn>(leadIn);
Assert.Equal(0.125, lineArc.LineLength);
Assert.Equal(0.0625, lineArc.ArcRadius);
Assert.Equal(90, lineArc.ApproachAngle);
}
foreach (var leadOut in new[] { parameters.ExternalLeadOut, parameters.InternalLeadOut, parameters.ArcCircleLeadOut })
foreach (var leadOut in new[] { parameters.ExternalLeadOut, parameters.InternalLeadOut })
{
var line = Assert.IsType<LineLeadOut>(leadOut);
Assert.Equal(0.0625, line.Length);
@@ -118,7 +118,6 @@ public class MachineCuttingDefaultsTests
Assert.Equal(0.3, Assert.IsType<LineLeadIn>(parameters.ExternalLeadIn).Length);
Assert.Equal(0.012, Assert.IsType<CleanHoleLeadIn>(parameters.InternalLeadIn).Kerf);
Assert.IsType<CleanHoleLeadIn>(parameters.ArcCircleLeadIn);
}
[Fact]
@@ -607,6 +607,5 @@ public class PostVerificationAnalyzerTests
{
ExternalLeadIn = new LineLeadIn { Length = 0.5 },
InternalLeadIn = new LineLeadIn { Length = 0.5 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.5 }
};
}
@@ -205,7 +205,7 @@ public class DrawingProgramSnapshotTests
part.ApplyLeadIns(new CuttingParameters
{
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
InternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
}, new Vector(-5, -5));
part.LeadInsLocked = true;
Assert.Contains(part.Program.Codes.OfType<LinearMove>(), move => move.Layer == LayerType.Leadin);
@@ -310,7 +310,7 @@ public class PartLeadInSerializationTests
{
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
ExternalLeadOut = new LineLeadOut { Length = 0.25 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
InternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
TabsEnabled = true,
TabConfig = new NormalTab { Size = 0.15 },
};
@@ -103,7 +103,7 @@ public static class NestReportTestData
{
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
ExternalLeadOut = new LineLeadOut { Length = 0.25 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
InternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 90 },
TabsEnabled = true,
TabConfig = new NormalTab { Size = 0.15 },
}, new Vector(-5, -5));
@@ -240,7 +240,6 @@ public class TabbedCutoutBuilderTests
{
ExternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 },
InternalLeadIn = new ArcLeadIn { Radius = 0.1 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.1, ApproachAngle = 90 },
});
Assert.True(planned.IsReady, planned.Describe);
Assert.True(part.RestoreLeadInProgram(planned.Program, false));
@@ -957,10 +957,8 @@ public class CuttingInspectionPanelTests
{
ExternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 45 },
InternalLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 45 },
ArcCircleLeadIn = new LineLeadIn { Length = 0.3, ApproachAngle = 45 },
ExternalLeadOut = new NoLeadOut(),
InternalLeadOut = new NoLeadOut(),
ArcCircleLeadOut = new NoLeadOut(),
};
private static void PumpUntil(Func<bool> condition)
+1 -2
View File
@@ -576,8 +576,7 @@ namespace OpenNest.Actions
{
return contourType switch
{
ContourType.ArcCircle => parameters.ArcCircleLeadIn ?? parameters.InternalLeadIn,
ContourType.Internal => parameters.InternalLeadIn,
ContourType.Internal or ContourType.ArcCircle => parameters.InternalLeadIn,
_ => parameters.ExternalLeadIn,
};
}
+4 -28
View File
@@ -24,15 +24,11 @@ namespace OpenNest.Controls
cboExternalLeadOut;
private readonly ComboBox cboInternalLeadIn,
cboInternalLeadOut;
private readonly ComboBox cboArcCircleLeadIn,
cboArcCircleLeadOut;
private readonly Panel pnlExternalLeadIn,
pnlExternalLeadOut;
private readonly Panel pnlInternalLeadIn,
pnlInternalLeadOut;
private readonly Panel pnlArcCircleLeadIn,
pnlArcCircleLeadOut;
private readonly CheckBox chkTabsEnabled;
private readonly NumericUpDown nudTabWidth;
@@ -56,7 +52,6 @@ namespace OpenNest.Controls
{
0 => ContourType.External,
1 => ContourType.Internal,
2 => ContourType.ArcCircle,
_ => null,
};
}
@@ -68,8 +63,8 @@ namespace OpenNest.Controls
var index = value.Value switch
{
ContourType.External => 0,
ContourType.Internal => 1,
ContourType.ArcCircle => 2,
// Circles share the internal leads.
ContourType.Internal or ContourType.ArcCircle => 1,
_ => -1,
};
@@ -88,7 +83,6 @@ namespace OpenNest.Controls
var tabExternal = new TabPage("External") { Padding = new Padding(4) };
var tabInternal = new TabPage("Internal") { Padding = new Padding(4) };
var tabArcCircle = new TabPage("Arc / Circle") { Padding = new Padding(4) };
SetupTab(
tabExternal,
@@ -104,17 +98,9 @@ namespace OpenNest.Controls
out cboInternalLeadOut,
out pnlInternalLeadOut
);
SetupTab(
tabArcCircle,
out cboArcCircleLeadIn,
out pnlArcCircleLeadIn,
out cboArcCircleLeadOut,
out pnlArcCircleLeadOut
);
tabControl.Controls.Add(tabExternal);
tabControl.Controls.Add(tabInternal);
tabControl.Controls.Add(tabArcCircle);
var tabWrapper = new Panel { Dock = DockStyle.Top, Height = 340 };
tabWrapper.Controls.Add(tabControl);
@@ -264,8 +250,6 @@ namespace OpenNest.Controls
ExternalLeadOut = BuildLeadOut(cboExternalLeadOut, pnlExternalLeadOut),
InternalLeadIn = BuildLeadIn(cboInternalLeadIn, pnlInternalLeadIn),
InternalLeadOut = BuildLeadOut(cboInternalLeadOut, pnlInternalLeadOut),
ArcCircleLeadIn = BuildLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn),
ArcCircleLeadOut = BuildLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut),
TabsEnabled = chkTabsEnabled.Checked && rbTabAll.Checked,
TabConfig = new NormalTab { Size = (double)nudTabWidth.Value },
PierceClearance = (double)nudPierceClearance.Value,
@@ -284,8 +268,6 @@ namespace OpenNest.Controls
LoadLeadOut(cboExternalLeadOut, pnlExternalLeadOut, p.ExternalLeadOut);
LoadLeadIn(cboInternalLeadIn, pnlInternalLeadIn, p.InternalLeadIn);
LoadLeadOut(cboInternalLeadOut, pnlInternalLeadOut, p.InternalLeadOut);
LoadLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn, p.ArcCircleLeadIn);
LoadLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut, p.ArcCircleLeadOut);
chkTabsEnabled.Checked = p.TabsEnabled || p.SupportTabs;
rbSupportTab.Checked = p.SupportTabs;
@@ -385,7 +367,7 @@ namespace OpenNest.Controls
private void PopulateDropdowns()
{
foreach (
var combo in new[] { cboExternalLeadIn, cboInternalLeadIn, cboArcCircleLeadIn }
var combo in new[] { cboExternalLeadIn, cboInternalLeadIn }
)
{
combo.Items.AddRange(LeadInTypes);
@@ -393,7 +375,7 @@ namespace OpenNest.Controls
}
foreach (
var combo in new[] { cboExternalLeadOut, cboInternalLeadOut, cboArcCircleLeadOut }
var combo in new[] { cboExternalLeadOut, cboInternalLeadOut }
)
{
combo.Items.AddRange(LeadOutTypes);
@@ -405,11 +387,9 @@ namespace OpenNest.Controls
{
cboExternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
cboInternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
cboArcCircleLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
cboExternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
cboInternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
cboArcCircleLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
}
private void OnLeadInTypeChanged(object sender, EventArgs e)
@@ -436,8 +416,6 @@ namespace OpenNest.Controls
return pnlExternalLeadIn;
if (combo == cboInternalLeadIn)
return pnlInternalLeadIn;
if (combo == cboArcCircleLeadIn)
return pnlArcCircleLeadIn;
return null;
}
@@ -447,8 +425,6 @@ namespace OpenNest.Controls
return pnlExternalLeadOut;
if (combo == cboInternalLeadOut)
return pnlInternalLeadOut;
if (combo == cboArcCircleLeadOut)
return pnlArcCircleLeadOut;
return null;
}
+1 -1
View File
@@ -1154,7 +1154,7 @@ internal sealed class CuttingInspectionPanel : UserControl
private void ShowSettings()
{
settingsLabel.Text = $"Outside: {Describe(parameters.ExternalLeadIn)} · Holes: {Describe(parameters.InternalLeadIn)} · "
+ $"Arcs: {Describe(parameters.ArcCircleLeadIn)} · Tabs: {(parameters.TabsEnabled ? "on" : "off")}";
+ $"Tabs: {(parameters.TabsEnabled ? "on" : "off")}";
}
private static string Describe(LeadIn leadIn)
+2 -2
View File
@@ -21,8 +21,8 @@ machine, material, grade and thickness recorded on the parameters. A plate that
parameters keeps them: changing the machine, material or thickness does not rewrite leads
the plate was planned with.
The machine holds one lead-in and one lead-out per thickness; both go to external, internal
and arc/circle contours. Types map as follows:
The machine holds one lead-in and one lead-out per thickness; both go to external and internal
contours (internal covers full circles). Types map as follows:
| Machine type | Lead-in |
|---|---|
+6
View File
@@ -97,6 +97,12 @@ cross-platform DTO mapping; the desktop settings serializer delegates to it so
existing saved settings keep their JSON contract. Settings are independent of
the saved part programs: restoring settings never regenerates those programs.
Lead settings are external (the perimeter) and internal (every cutout, full
circles included). Older files and desktop settings also stored
`arcCircleLeadIn`/`arcCircleLeadOut`; these are ignored on read and no longer
written, so circles in a re-planned older nest take its internal leads. Saved
part programs keep the leads they were cut with.
## Clamp zones
Each plate may carry an optional `clamps` array of fixed rectangular keep-out
+1 -1
View File
@@ -30,7 +30,7 @@ nest's. A different outcome at the same or a better rank is only reported. When
intended, update the baseline.
Plates use their own cutting parameters. A plate without them uses line lead-ins of 0.15 at
90 degrees (external, internal and arc/circle) and no lead-outs.
90 degrees (external and internal) and no lead-outs.
## Adding a nest