Compare commits
9 Commits
5bcad9667b
...
e50a7c82cf
| Author | SHA1 | Date | |
|---|---|---|---|
| e50a7c82cf | |||
| 7a893ef50f | |||
| 925a1c7751 | |||
| 036b48e273 | |||
| bd9b0369cf | |||
| 93391c4b8f | |||
| ebab795f86 | |||
| 9f9111975d | |||
| 25ee193ae6 |
@@ -50,6 +50,126 @@ namespace OpenNest.CNC.CuttingStrategy
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CuttingResult ApplySingle(Program partProgram, Vector point, Entity entity, ContourType contourType)
|
||||||
|
{
|
||||||
|
var entities = partProgram.ToGeometry();
|
||||||
|
entities.RemoveAll(e => e.Layer == SpecialLayers.Rapid);
|
||||||
|
|
||||||
|
var scribeEntities = entities.FindAll(e => e.Layer == SpecialLayers.Scribe);
|
||||||
|
entities.RemoveAll(e => e.Layer == SpecialLayers.Scribe);
|
||||||
|
|
||||||
|
var profile = new ShapeProfile(entities);
|
||||||
|
|
||||||
|
var result = new Program(Mode.Absolute);
|
||||||
|
|
||||||
|
EmitScribeContours(result, scribeEntities);
|
||||||
|
|
||||||
|
// Find the target shape that contains the clicked entity
|
||||||
|
var (targetShape, matchedEntity) = FindTargetShape(profile, point, entity);
|
||||||
|
|
||||||
|
// Emit cutouts — only the target gets lead-in/out
|
||||||
|
foreach (var cutout in profile.Cutouts)
|
||||||
|
{
|
||||||
|
if (cutout == targetShape)
|
||||||
|
{
|
||||||
|
var ct = DetectContourType(cutout);
|
||||||
|
EmitContour(result, cutout, point, matchedEntity, ct);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitRawContour(result, cutout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit perimeter
|
||||||
|
if (profile.Perimeter == targetShape)
|
||||||
|
{
|
||||||
|
EmitContour(result, profile.Perimeter, point, matchedEntity, ContourType.External);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitRawContour(result, profile.Perimeter);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Mode = Mode.Incremental;
|
||||||
|
|
||||||
|
return new CuttingResult
|
||||||
|
{
|
||||||
|
Program = result,
|
||||||
|
LastCutPoint = point
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (Shape Shape, Entity Entity) FindTargetShape(ShapeProfile profile, Vector point, Entity clickedEntity)
|
||||||
|
{
|
||||||
|
var matched = FindMatchingEntity(profile.Perimeter, clickedEntity);
|
||||||
|
if (matched != null)
|
||||||
|
return (profile.Perimeter, matched);
|
||||||
|
|
||||||
|
foreach (var cutout in profile.Cutouts)
|
||||||
|
{
|
||||||
|
matched = FindMatchingEntity(cutout, clickedEntity);
|
||||||
|
if (matched != null)
|
||||||
|
return (cutout, matched);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: closest shape, use closest point to find entity
|
||||||
|
var best = profile.Perimeter;
|
||||||
|
var bestPt = profile.Perimeter.ClosestPointTo(point, out var bestEntity);
|
||||||
|
var bestDist = bestPt.DistanceTo(point);
|
||||||
|
|
||||||
|
foreach (var cutout in profile.Cutouts)
|
||||||
|
{
|
||||||
|
var pt = cutout.ClosestPointTo(point, out var cutoutEntity);
|
||||||
|
var dist = pt.DistanceTo(point);
|
||||||
|
if (dist < bestDist)
|
||||||
|
{
|
||||||
|
best = cutout;
|
||||||
|
bestEntity = cutoutEntity;
|
||||||
|
bestDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (best, bestEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Entity FindMatchingEntity(Shape shape, Entity clickedEntity)
|
||||||
|
{
|
||||||
|
foreach (var shapeEntity in shape.Entities)
|
||||||
|
{
|
||||||
|
if (shapeEntity.GetType() != clickedEntity.GetType())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (shapeEntity is Line sLine && clickedEntity is Line cLine)
|
||||||
|
{
|
||||||
|
if (sLine.StartPoint.DistanceTo(cLine.StartPoint) < Math.Tolerance.Epsilon
|
||||||
|
&& sLine.EndPoint.DistanceTo(cLine.EndPoint) < Math.Tolerance.Epsilon)
|
||||||
|
return shapeEntity;
|
||||||
|
}
|
||||||
|
else if (shapeEntity is Arc sArc && clickedEntity is Arc cArc)
|
||||||
|
{
|
||||||
|
if (System.Math.Abs(sArc.Radius - cArc.Radius) < Math.Tolerance.Epsilon
|
||||||
|
&& sArc.Center.DistanceTo(cArc.Center) < Math.Tolerance.Epsilon)
|
||||||
|
return shapeEntity;
|
||||||
|
}
|
||||||
|
else if (shapeEntity is Circle sCircle && clickedEntity is Circle cCircle)
|
||||||
|
{
|
||||||
|
if (System.Math.Abs(sCircle.Radius - cCircle.Radius) < Math.Tolerance.Epsilon
|
||||||
|
&& sCircle.Center.DistanceTo(cCircle.Center) < Math.Tolerance.Epsilon)
|
||||||
|
return shapeEntity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitRawContour(Program program, Shape shape)
|
||||||
|
{
|
||||||
|
var startPoint = GetShapeStartPoint(shape);
|
||||||
|
program.Codes.Add(new RapidMove(startPoint));
|
||||||
|
program.Codes.AddRange(ConvertShapeToMoves(shape, startPoint));
|
||||||
|
}
|
||||||
|
|
||||||
private static List<ContourEntry> ResolveLeadInPoints(List<Shape> cutouts, Vector startPoint)
|
private static List<ContourEntry> ResolveLeadInPoints(List<Shape> cutouts, Vector startPoint)
|
||||||
{
|
{
|
||||||
var entries = new ContourEntry[cutouts.Count];
|
var entries = new ContourEntry[cutouts.Count];
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ namespace OpenNest.CNC.CuttingStrategy
|
|||||||
|
|
||||||
public double PierceClearance { get; set; } = 0.0625;
|
public double PierceClearance { get; set; } = 0.0625;
|
||||||
|
|
||||||
|
public double AutoTabMinSize { get; set; }
|
||||||
|
public double AutoTabMaxSize { get; set; }
|
||||||
|
|
||||||
public Tab TabConfig { get; set; }
|
public Tab TabConfig { get; set; }
|
||||||
public bool TabsEnabled { get; set; }
|
public bool TabsEnabled { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,18 @@ namespace OpenNest
|
|||||||
UpdateBounds();
|
UpdateBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ApplySingleLeadIn(CNC.CuttingStrategy.CuttingParameters parameters,
|
||||||
|
Geometry.Vector point, Geometry.Entity entity, CNC.CuttingStrategy.ContourType contourType)
|
||||||
|
{
|
||||||
|
preLeadInRotation = Rotation;
|
||||||
|
var strategy = new CNC.CuttingStrategy.ContourCuttingStrategy { Parameters = parameters };
|
||||||
|
var result = strategy.ApplySingle(Program, point, entity, contourType);
|
||||||
|
Program = result.Program;
|
||||||
|
CuttingParameters = parameters;
|
||||||
|
HasManualLeadIns = true;
|
||||||
|
UpdateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
public void RemoveLeadIns()
|
public void RemoveLeadIns()
|
||||||
{
|
{
|
||||||
var rotation = preLeadInRotation;
|
var rotation = preLeadInRotation;
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
using OpenNest.CNC;
|
||||||
|
using OpenNest.CNC.CuttingStrategy;
|
||||||
|
using OpenNest.Geometry;
|
||||||
|
|
||||||
|
namespace OpenNest.Tests.CuttingStrategy;
|
||||||
|
|
||||||
|
public class ApplySingleTests
|
||||||
|
{
|
||||||
|
private static Program MakeSquareProgram()
|
||||||
|
{
|
||||||
|
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)));
|
||||||
|
return pgm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Program MakeSquareWithHoleProgram()
|
||||||
|
{
|
||||||
|
var pgm = new Program();
|
||||||
|
pgm.Codes.Add(new RapidMove(new Vector(0, 0)));
|
||||||
|
pgm.Codes.Add(new LinearMove(new Vector(0, 20)));
|
||||||
|
pgm.Codes.Add(new LinearMove(new Vector(20, 20)));
|
||||||
|
pgm.Codes.Add(new LinearMove(new Vector(20, 0)));
|
||||||
|
pgm.Codes.Add(new LinearMove(new Vector(0, 0)));
|
||||||
|
pgm.Codes.Add(new RapidMove(new Vector(12, 10)));
|
||||||
|
pgm.Codes.Add(new ArcMove(new Vector(12, 10), new Vector(10, 10), RotationType.CW));
|
||||||
|
return pgm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ICode> GetLeadInCodes(Program program)
|
||||||
|
{
|
||||||
|
var result = new List<ICode>();
|
||||||
|
foreach (var code in program.Codes)
|
||||||
|
{
|
||||||
|
if (code is LinearMove lm && lm.Layer == LayerType.Leadin)
|
||||||
|
result.Add(lm);
|
||||||
|
else if (code is ArcMove am && am.Layer == LayerType.Leadin)
|
||||||
|
result.Add(am);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingle_ExternalContour_PlacesLeadInAtExactPoint()
|
||||||
|
{
|
||||||
|
var pgm = MakeSquareProgram();
|
||||||
|
var strategy = new ContourCuttingStrategy
|
||||||
|
{
|
||||||
|
Parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var clickPoint = new Vector(5, 0);
|
||||||
|
var entity = new Line(new Vector(10, 0), new Vector(0, 0));
|
||||||
|
var result = strategy.ApplySingle(pgm, clickPoint, entity, ContourType.External);
|
||||||
|
|
||||||
|
var hasLeadin = result.Program.Codes.OfType<LinearMove>().Any(m => m.Layer == LayerType.Leadin);
|
||||||
|
Assert.True(hasLeadin);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingle_ContourStartsAtClickPoint()
|
||||||
|
{
|
||||||
|
var pgm = MakeSquareProgram();
|
||||||
|
var strategy = new ContourCuttingStrategy
|
||||||
|
{
|
||||||
|
Parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var clickPoint = new Vector(5, 0);
|
||||||
|
var entity = new Line(new Vector(10, 0), new Vector(0, 0));
|
||||||
|
var result = strategy.ApplySingle(pgm, clickPoint, entity, ContourType.External);
|
||||||
|
|
||||||
|
// Convert back to absolute to check positions
|
||||||
|
result.Program.Mode = Mode.Absolute;
|
||||||
|
|
||||||
|
var firstLinear = result.Program.Codes.OfType<LinearMove>()
|
||||||
|
.First(m => m.Layer == LayerType.Leadin);
|
||||||
|
Assert.Equal(clickPoint.X, firstLinear.EndPoint.X, 4);
|
||||||
|
Assert.Equal(clickPoint.Y, firstLinear.EndPoint.Y, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingle_ProgramModeIsIncremental()
|
||||||
|
{
|
||||||
|
var pgm = MakeSquareProgram();
|
||||||
|
var strategy = new ContourCuttingStrategy
|
||||||
|
{
|
||||||
|
Parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var clickPoint = new Vector(5, 0);
|
||||||
|
var entity = new Line(new Vector(10, 0), new Vector(0, 0));
|
||||||
|
var result = strategy.ApplySingle(pgm, clickPoint, entity, ContourType.External);
|
||||||
|
|
||||||
|
Assert.Equal(Mode.Incremental, result.Program.Mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingle_OnlyTargetContourGetsLeadIn()
|
||||||
|
{
|
||||||
|
var pgm = MakeSquareWithHoleProgram();
|
||||||
|
var strategy = new ContourCuttingStrategy
|
||||||
|
{
|
||||||
|
Parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
|
||||||
|
InternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var clickPoint = new Vector(10, 0);
|
||||||
|
var entity = new Line(new Vector(20, 0), new Vector(0, 0));
|
||||||
|
var result = strategy.ApplySingle(pgm, clickPoint, entity, ContourType.External);
|
||||||
|
|
||||||
|
var leadinMoves = GetLeadInCodes(result.Program);
|
||||||
|
Assert.Single(leadinMoves);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using OpenNest.CNC.CuttingStrategy;
|
||||||
|
using OpenNest.Forms;
|
||||||
|
|
||||||
|
namespace OpenNest.Tests.CuttingStrategy;
|
||||||
|
|
||||||
|
public class CuttingParametersSerializerTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void RoundTrip_PreservesAutoTabFields()
|
||||||
|
{
|
||||||
|
var original = new CuttingParameters
|
||||||
|
{
|
||||||
|
AutoTabMinSize = 0.5,
|
||||||
|
AutoTabMaxSize = 3.0,
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 }
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = CuttingParametersSerializer.Serialize(original);
|
||||||
|
var restored = CuttingParametersSerializer.Deserialize(json);
|
||||||
|
|
||||||
|
Assert.Equal(0.5, restored.AutoTabMinSize);
|
||||||
|
Assert.Equal(3.0, restored.AutoTabMaxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Deserialize_MissingAutoTabFields_DefaultsToZero()
|
||||||
|
{
|
||||||
|
var json = "{\"externalLeadIn\":{\"type\":\"None\"},\"externalLeadOut\":{\"type\":\"None\"},\"internalLeadIn\":{\"type\":\"None\"},\"internalLeadOut\":{\"type\":\"None\"},\"arcCircleLeadIn\":{\"type\":\"None\"},\"arcCircleLeadOut\":{\"type\":\"None\"},\"tabsEnabled\":false,\"tabWidth\":0.25,\"pierceClearance\":0.0625}";
|
||||||
|
|
||||||
|
var restored = CuttingParametersSerializer.Deserialize(json);
|
||||||
|
|
||||||
|
Assert.Equal(0.0, restored.AutoTabMinSize);
|
||||||
|
Assert.Equal(0.0, restored.AutoTabMaxSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -124,4 +124,74 @@ public class PartLeadInTests
|
|||||||
var part = MakeSquarePart();
|
var part = MakeSquarePart();
|
||||||
Assert.False(part.LeadInsLocked);
|
Assert.False(part.LeadInsLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingleLeadIn_SetsHasManualLeadIns()
|
||||||
|
{
|
||||||
|
var part = MakeSquarePart();
|
||||||
|
var parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||||
|
};
|
||||||
|
|
||||||
|
var entity = new Line(new Vector(10, 0), new Vector(0, 0));
|
||||||
|
part.ApplySingleLeadIn(parameters, new Vector(5, 0), entity, ContourType.External);
|
||||||
|
|
||||||
|
Assert.True(part.HasManualLeadIns);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingleLeadIn_ProgramContainsLeadinCodes()
|
||||||
|
{
|
||||||
|
var part = MakeSquarePart();
|
||||||
|
var parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||||
|
};
|
||||||
|
|
||||||
|
var entity = new Line(new Vector(10, 0), new Vector(0, 0));
|
||||||
|
part.ApplySingleLeadIn(parameters, new Vector(5, 0), entity, ContourType.External);
|
||||||
|
|
||||||
|
var hasLeadin = part.Program.Codes.OfType<LinearMove>().Any(m => m.Layer == LayerType.Leadin);
|
||||||
|
Assert.True(hasLeadin);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingleLeadIn_ThenRemove_RestoresOriginal()
|
||||||
|
{
|
||||||
|
var part = MakeSquarePart();
|
||||||
|
var originalCodeCount = part.Program.Codes.Count;
|
||||||
|
var parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||||
|
};
|
||||||
|
|
||||||
|
var entity = new Line(new Vector(10, 0), new Vector(0, 0));
|
||||||
|
part.ApplySingleLeadIn(parameters, new Vector(5, 0), entity, ContourType.External);
|
||||||
|
part.RemoveLeadIns();
|
||||||
|
|
||||||
|
Assert.False(part.HasManualLeadIns);
|
||||||
|
Assert.Equal(originalCodeCount, part.Program.Codes.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplySingleLeadIn_PreservesRotation()
|
||||||
|
{
|
||||||
|
var part = MakeSquarePart();
|
||||||
|
part.Rotate(System.Math.PI / 4);
|
||||||
|
var rotation = part.Rotation;
|
||||||
|
|
||||||
|
var parameters = new CuttingParameters
|
||||||
|
{
|
||||||
|
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// After rotation, the edges change. Use a point on the rotated bottom edge.
|
||||||
|
// The rotated square has vertices roughly at rotated positions.
|
||||||
|
// We'll use a generic entity that will be matched via fallback.
|
||||||
|
var entity = new Line(new Vector(10, 0), new Vector(0, 0));
|
||||||
|
part.ApplySingleLeadIn(parameters, new Vector(5, 0), entity, ContourType.External);
|
||||||
|
|
||||||
|
Assert.Equal(rotation, part.Rotation, 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ public class EngineOverlapTests
|
|||||||
_output = output;
|
_output = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Drawing ImportDxf()
|
private static Drawing? ImportDxf()
|
||||||
{
|
{
|
||||||
|
if (!System.IO.File.Exists(DxfPath))
|
||||||
|
return null;
|
||||||
|
|
||||||
var importer = new DxfImporter();
|
var importer = new DxfImporter();
|
||||||
importer.GetGeometry(DxfPath, out var geometry);
|
importer.GetGeometry(DxfPath, out var geometry);
|
||||||
var pgm = ConvertGeometry.ToProgram(geometry);
|
var pgm = ConvertGeometry.ToProgram(geometry);
|
||||||
@@ -31,6 +34,9 @@ public class EngineOverlapTests
|
|||||||
public void FillPlate_NoOverlaps(string engineName)
|
public void FillPlate_NoOverlaps(string engineName)
|
||||||
{
|
{
|
||||||
var drawing = ImportDxf();
|
var drawing = ImportDxf();
|
||||||
|
if (drawing is null)
|
||||||
|
return; // Skip if test DXF not available
|
||||||
|
|
||||||
var plate = new Plate(60, 120);
|
var plate = new Plate(60, 120);
|
||||||
|
|
||||||
NestEngineRegistry.ActiveEngineName = engineName;
|
NestEngineRegistry.ActiveEngineName = engineName;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
<ProjectReference Include="..\OpenNest.Engine\OpenNest.Engine.csproj" />
|
<ProjectReference Include="..\OpenNest.Engine\OpenNest.Engine.csproj" />
|
||||||
<ProjectReference Include="..\OpenNest.IO\OpenNest.IO.csproj" />
|
<ProjectReference Include="..\OpenNest.IO\OpenNest.IO.csproj" />
|
||||||
<ProjectReference Include="..\OpenNest.Posts.Cincinnati\OpenNest.Posts.Cincinnati.csproj" />
|
<ProjectReference Include="..\OpenNest.Posts.Cincinnati\OpenNest.Posts.Cincinnati.csproj" />
|
||||||
|
<ProjectReference Include="..\OpenNest\OpenNest.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -18,8 +18,11 @@ public class StrategyOverlapTests
|
|||||||
_output = output;
|
_output = output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Drawing ImportDxf()
|
private static Drawing? ImportDxf()
|
||||||
{
|
{
|
||||||
|
if (!System.IO.File.Exists(DxfPath))
|
||||||
|
return null;
|
||||||
|
|
||||||
var importer = new DxfImporter();
|
var importer = new DxfImporter();
|
||||||
importer.GetGeometry(DxfPath, out var geometry);
|
importer.GetGeometry(DxfPath, out var geometry);
|
||||||
var pgm = ConvertGeometry.ToProgram(geometry);
|
var pgm = ConvertGeometry.ToProgram(geometry);
|
||||||
@@ -30,6 +33,9 @@ public class StrategyOverlapTests
|
|||||||
public void EachStrategy_CheckOverlaps()
|
public void EachStrategy_CheckOverlaps()
|
||||||
{
|
{
|
||||||
var drawing = ImportDxf();
|
var drawing = ImportDxf();
|
||||||
|
if (drawing is null)
|
||||||
|
return; // Skip if test DXF not available
|
||||||
|
|
||||||
_output.WriteLine($"Drawing bbox: {drawing.Program.BoundingBox().Width:F2} x {drawing.Program.BoundingBox().Length:F2}");
|
_output.WriteLine($"Drawing bbox: {drawing.Program.BoundingBox().Width:F2} x {drawing.Program.BoundingBox().Length:F2}");
|
||||||
|
|
||||||
var strategies = FillStrategyRegistry.Strategies.ToList();
|
var strategies = FillStrategyRegistry.Strategies.ToList();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using OpenNest.CNC.CuttingStrategy;
|
using OpenNest.CNC.CuttingStrategy;
|
||||||
using OpenNest.Controls;
|
using OpenNest.Controls;
|
||||||
using OpenNest.Converters;
|
using OpenNest.Converters;
|
||||||
|
using OpenNest.Forms;
|
||||||
using OpenNest.Geometry;
|
using OpenNest.Geometry;
|
||||||
using OpenNest.Math;
|
using OpenNest.Math;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -30,9 +31,12 @@ namespace OpenNest.Actions
|
|||||||
private bool hasSnap;
|
private bool hasSnap;
|
||||||
private SnapType activeSnapType;
|
private SnapType activeSnapType;
|
||||||
private ShapeInfo hoveredContour;
|
private ShapeInfo hoveredContour;
|
||||||
|
private ShapeInfo lockedContour;
|
||||||
private ContextMenuStrip contextMenu;
|
private ContextMenuStrip contextMenu;
|
||||||
|
private CuttingPanel cuttingPanel;
|
||||||
private static readonly Brush grayOverlay = new SolidBrush(Color.FromArgb(160, 180, 180, 180));
|
private static readonly Brush grayOverlay = new SolidBrush(Color.FromArgb(160, 180, 180, 180));
|
||||||
private static readonly Pen highlightPen = new Pen(Color.Cyan, 2.5f);
|
private static readonly Pen highlightPen = new Pen(Color.Cyan, 2.5f);
|
||||||
|
private static readonly Pen lockedPen = new Pen(Color.Yellow, 3.0f);
|
||||||
|
|
||||||
public ActionLeadIn(PlateView plateView)
|
public ActionLeadIn(PlateView plateView)
|
||||||
: base(plateView)
|
: base(plateView)
|
||||||
@@ -46,6 +50,7 @@ namespace OpenNest.Actions
|
|||||||
plateView.MouseDown += OnMouseDown;
|
plateView.MouseDown += OnMouseDown;
|
||||||
plateView.KeyDown += OnKeyDown;
|
plateView.KeyDown += OnKeyDown;
|
||||||
plateView.Paint += OnPaint;
|
plateView.Paint += OnPaint;
|
||||||
|
ShowSidePanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DisconnectEvents()
|
public override void DisconnectEvents()
|
||||||
@@ -55,6 +60,8 @@ namespace OpenNest.Actions
|
|||||||
plateView.KeyDown -= OnKeyDown;
|
plateView.KeyDown -= OnKeyDown;
|
||||||
plateView.Paint -= OnPaint;
|
plateView.Paint -= OnPaint;
|
||||||
|
|
||||||
|
HideSidePanel();
|
||||||
|
|
||||||
contextMenu?.Dispose();
|
contextMenu?.Dispose();
|
||||||
contextMenu = null;
|
contextMenu = null;
|
||||||
|
|
||||||
@@ -72,6 +79,77 @@ namespace OpenNest.Actions
|
|||||||
|
|
||||||
public override bool IsBusy() => selectedPart != null;
|
public override bool IsBusy() => selectedPart != null;
|
||||||
|
|
||||||
|
private void ShowSidePanel()
|
||||||
|
{
|
||||||
|
var form = plateView.FindForm() as EditNestForm;
|
||||||
|
if (form == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cuttingPanel = new CuttingPanel { ShowAutoAssign = true };
|
||||||
|
cuttingPanel.AutoAssignClicked += OnAutoAssignClicked;
|
||||||
|
cuttingPanel.ParametersChanged += OnToolParametersChanged;
|
||||||
|
|
||||||
|
// Load current parameters or defaults
|
||||||
|
var plate = plateView.Plate;
|
||||||
|
if (plate?.CuttingParameters != null)
|
||||||
|
cuttingPanel.LoadFromParameters(plate.CuttingParameters);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||||
|
if (!string.IsNullOrEmpty(json))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var saved = CuttingParametersSerializer.Deserialize(json);
|
||||||
|
cuttingPanel.LoadFromParameters(saved);
|
||||||
|
}
|
||||||
|
catch { /* use defaults */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.ShowSidePanel(cuttingPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideSidePanel()
|
||||||
|
{
|
||||||
|
if (cuttingPanel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SaveParameters();
|
||||||
|
|
||||||
|
cuttingPanel.ParametersChanged -= OnToolParametersChanged;
|
||||||
|
cuttingPanel.AutoAssignClicked -= OnAutoAssignClicked;
|
||||||
|
|
||||||
|
var form = plateView.FindForm() as EditNestForm;
|
||||||
|
form?.HideSidePanel();
|
||||||
|
|
||||||
|
cuttingPanel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CuttingParameters GetCurrentParameters()
|
||||||
|
{
|
||||||
|
return cuttingPanel?.BuildParameters() ?? plateView.Plate?.CuttingParameters ?? new CuttingParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveParameters()
|
||||||
|
{
|
||||||
|
if (cuttingPanel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var parameters = cuttingPanel.BuildParameters();
|
||||||
|
var json = CuttingParametersSerializer.Serialize(parameters);
|
||||||
|
Properties.Settings.Default.CuttingParametersJson = json;
|
||||||
|
Properties.Settings.Default.Save();
|
||||||
|
|
||||||
|
if (plateView.Plate != null)
|
||||||
|
plateView.Plate.CuttingParameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnToolParametersChanged(object sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
plateView.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnMouseMove(object sender, MouseEventArgs e)
|
private void OnMouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
if (selectedPart == null || contours == null)
|
if (selectedPart == null || contours == null)
|
||||||
@@ -91,7 +169,12 @@ namespace OpenNest.Actions
|
|||||||
activeSnapType = SnapType.None;
|
activeSnapType = SnapType.None;
|
||||||
hoveredContour = null;
|
hoveredContour = null;
|
||||||
|
|
||||||
foreach (var info in contours)
|
// When a contour is locked, only snap within that contour
|
||||||
|
var searchContours = lockedContour != null
|
||||||
|
? new List<ShapeInfo> { lockedContour }
|
||||||
|
: contours;
|
||||||
|
|
||||||
|
foreach (var info in searchContours)
|
||||||
{
|
{
|
||||||
var closest = info.Shape.ClosestPointTo(localPt, out var entity);
|
var closest = info.Shape.ClosestPointTo(localPt, out var entity);
|
||||||
var dist = closest.DistanceTo(localPt);
|
var dist = closest.DistanceTo(localPt);
|
||||||
@@ -110,8 +193,14 @@ namespace OpenNest.Actions
|
|||||||
|
|
||||||
// Check endpoint/midpoint snaps on the hovered contour
|
// Check endpoint/midpoint snaps on the hovered contour
|
||||||
if (hoveredContour != null)
|
if (hoveredContour != null)
|
||||||
|
{
|
||||||
TrySnapToEntityPoints(localPt);
|
TrySnapToEntityPoints(localPt);
|
||||||
|
|
||||||
|
// Auto-switch tool window tab only when no contour is locked
|
||||||
|
if (cuttingPanel != null && lockedContour == null)
|
||||||
|
cuttingPanel.ActiveContourType = snapContourType;
|
||||||
|
}
|
||||||
|
|
||||||
plateView.Invalidate();
|
plateView.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,15 +213,22 @@ namespace OpenNest.Actions
|
|||||||
// First click: select a part
|
// First click: select a part
|
||||||
SelectPartAtCursor();
|
SelectPartAtCursor();
|
||||||
}
|
}
|
||||||
else if (hasSnap)
|
else if (lockedContour == null && hasSnap)
|
||||||
{
|
{
|
||||||
// Second click: commit lead-in at snap point
|
// Second click: lock the hovered contour
|
||||||
|
LockContour(hoveredContour);
|
||||||
|
}
|
||||||
|
else if (lockedContour != null && hasSnap)
|
||||||
|
{
|
||||||
|
// Third click: commit lead-in at snap point on locked contour
|
||||||
CommitLeadIn();
|
CommitLeadIn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (e.Button == MouseButtons.Right)
|
else if (e.Button == MouseButtons.Right)
|
||||||
{
|
{
|
||||||
if (selectedPart != null && selectedPart.HasManualLeadIns)
|
if (lockedContour != null)
|
||||||
|
UnlockContour();
|
||||||
|
else if (selectedPart != null && selectedPart.HasManualLeadIns)
|
||||||
ShowContextMenu(e.Location);
|
ShowContextMenu(e.Location);
|
||||||
else
|
else
|
||||||
DeselectPart();
|
DeselectPart();
|
||||||
@@ -143,7 +239,9 @@ namespace OpenNest.Actions
|
|||||||
{
|
{
|
||||||
if (e.KeyCode == Keys.Escape)
|
if (e.KeyCode == Keys.Escape)
|
||||||
{
|
{
|
||||||
if (selectedPart != null)
|
if (lockedContour != null)
|
||||||
|
UnlockContour();
|
||||||
|
else if (selectedPart != null)
|
||||||
DeselectPart();
|
DeselectPart();
|
||||||
else
|
else
|
||||||
plateView.SetAction(typeof(ActionSelect));
|
plateView.SetAction(typeof(ActionSelect));
|
||||||
@@ -159,6 +257,23 @@ namespace OpenNest.Actions
|
|||||||
DrawLeadInPreview(g);
|
DrawLeadInPreview(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LockContour(ShapeInfo contour)
|
||||||
|
{
|
||||||
|
lockedContour = contour;
|
||||||
|
|
||||||
|
// Lock the tab to this contour type
|
||||||
|
if (cuttingPanel != null)
|
||||||
|
cuttingPanel.ActiveContourType = contour.ContourType;
|
||||||
|
|
||||||
|
plateView.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnlockContour()
|
||||||
|
{
|
||||||
|
lockedContour = null;
|
||||||
|
plateView.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawOverlay(Graphics g)
|
private void DrawOverlay(Graphics g)
|
||||||
{
|
{
|
||||||
foreach (var lp in plateView.LayoutParts)
|
foreach (var lp in plateView.LayoutParts)
|
||||||
@@ -170,10 +285,24 @@ namespace OpenNest.Actions
|
|||||||
|
|
||||||
private void DrawHoveredContour(Graphics g)
|
private void DrawHoveredContour(Graphics g)
|
||||||
{
|
{
|
||||||
if (hoveredContour == null || selectedPart == null)
|
if (selectedPart == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using var contourPath = hoveredContour.Shape.GetGraphicsPath();
|
// Draw locked contour with distinct pen
|
||||||
|
if (lockedContour != null)
|
||||||
|
{
|
||||||
|
DrawContourHighlight(g, lockedContour.Shape, lockedPen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw hovered contour
|
||||||
|
if (hoveredContour != null)
|
||||||
|
DrawContourHighlight(g, hoveredContour.Shape, highlightPen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawContourHighlight(Graphics g, Shape shape, Pen pen)
|
||||||
|
{
|
||||||
|
using var contourPath = shape.GetGraphicsPath();
|
||||||
using var contourMatrix = new Matrix();
|
using var contourMatrix = new Matrix();
|
||||||
contourMatrix.Translate((float)selectedPart.Location.X, (float)selectedPart.Location.Y);
|
contourMatrix.Translate((float)selectedPart.Location.X, (float)selectedPart.Location.Y);
|
||||||
contourMatrix.Multiply(plateView.Matrix, MatrixOrder.Append);
|
contourMatrix.Multiply(plateView.Matrix, MatrixOrder.Append);
|
||||||
@@ -181,7 +310,7 @@ namespace OpenNest.Actions
|
|||||||
|
|
||||||
var prevSmooth = g.SmoothingMode;
|
var prevSmooth = g.SmoothingMode;
|
||||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
g.DrawPath(highlightPen, contourPath);
|
g.DrawPath(pen, contourPath);
|
||||||
g.SmoothingMode = prevSmooth;
|
g.SmoothingMode = prevSmooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,9 +319,7 @@ namespace OpenNest.Actions
|
|||||||
if (!hasSnap || selectedPart == null)
|
if (!hasSnap || selectedPart == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var parameters = plateView.Plate?.CuttingParameters;
|
var parameters = GetCurrentParameters();
|
||||||
if (parameters == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var leadIn = SelectLeadIn(parameters, snapContourType);
|
var leadIn = SelectLeadIn(parameters, snapContourType);
|
||||||
if (leadIn == null)
|
if (leadIn == null)
|
||||||
@@ -375,29 +502,53 @@ namespace OpenNest.Actions
|
|||||||
|
|
||||||
private void CommitLeadIn()
|
private void CommitLeadIn()
|
||||||
{
|
{
|
||||||
var parameters = plateView.Plate?.CuttingParameters;
|
var parameters = GetCurrentParameters();
|
||||||
if (parameters == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Remove any existing lead-ins first
|
|
||||||
if (selectedPart.HasManualLeadIns)
|
if (selectedPart.HasManualLeadIns)
|
||||||
selectedPart.RemoveLeadIns();
|
selectedPart.RemoveLeadIns();
|
||||||
|
|
||||||
// Apply lead-ins using the snap point as the approach point.
|
ApplyAutoTab(parameters);
|
||||||
// snapPoint is in the program's local coordinate space (rotated, not offset),
|
|
||||||
// which is what Part.ApplyLeadIns expects.
|
selectedPart.ApplySingleLeadIn(parameters, snapPoint, snapEntity, snapContourType);
|
||||||
selectedPart.ApplyLeadIns(parameters, snapPoint);
|
|
||||||
selectedPart.LeadInsLocked = true;
|
selectedPart.LeadInsLocked = true;
|
||||||
|
|
||||||
// Rebuild the layout part's graphics
|
|
||||||
selectedLayoutPart.IsDirty = true;
|
selectedLayoutPart.IsDirty = true;
|
||||||
selectedLayoutPart.Update();
|
UnlockContour();
|
||||||
|
|
||||||
// Deselect and reset
|
|
||||||
DeselectPart();
|
|
||||||
plateView.Invalidate();
|
plateView.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAutoAssignClicked(object sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
if (selectedPart == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var parameters = GetCurrentParameters();
|
||||||
|
|
||||||
|
if (selectedPart.HasManualLeadIns)
|
||||||
|
selectedPart.RemoveLeadIns();
|
||||||
|
|
||||||
|
ApplyAutoTab(parameters);
|
||||||
|
|
||||||
|
selectedPart.ApplyLeadIns(parameters, Vector.Zero);
|
||||||
|
selectedPart.LeadInsLocked = true;
|
||||||
|
|
||||||
|
selectedLayoutPart.IsDirty = true;
|
||||||
|
UnlockContour();
|
||||||
|
plateView.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyAutoTab(CuttingParameters parameters)
|
||||||
|
{
|
||||||
|
if (parameters.AutoTabMinSize <= 0 && parameters.AutoTabMaxSize <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bbox = selectedPart.Program.BoundingBox();
|
||||||
|
var minDim = System.Math.Min(bbox.Width, bbox.Length);
|
||||||
|
|
||||||
|
if (minDim >= parameters.AutoTabMinSize && minDim <= parameters.AutoTabMaxSize)
|
||||||
|
parameters.TabsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void DeselectPart()
|
private void DeselectPart()
|
||||||
{
|
{
|
||||||
if (selectedLayoutPart != null)
|
if (selectedLayoutPart != null)
|
||||||
@@ -409,6 +560,7 @@ namespace OpenNest.Actions
|
|||||||
selectedPart = null;
|
selectedPart = null;
|
||||||
profile = null;
|
profile = null;
|
||||||
contours = null;
|
contours = null;
|
||||||
|
lockedContour = null;
|
||||||
hasSnap = false;
|
hasSnap = false;
|
||||||
activeSnapType = SnapType.None;
|
activeSnapType = SnapType.None;
|
||||||
hoveredContour = null;
|
hoveredContour = null;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using OpenNest.CNC.CuttingStrategy;
|
using OpenNest.CNC.CuttingStrategy;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace OpenNest.Forms
|
namespace OpenNest.Controls
|
||||||
{
|
{
|
||||||
public partial class CuttingParametersForm : Form
|
public class CuttingPanel : Panel
|
||||||
{
|
{
|
||||||
private static readonly string[] LeadInTypes =
|
private static readonly string[] LeadInTypes =
|
||||||
{ "None", "Line", "Arc", "Line + Arc", "Clean Hole", "Line + Line" };
|
{ "None", "Line", "Arc", "Line + Arc", "Clean Hole", "Line + Line" };
|
||||||
@@ -12,85 +13,241 @@ namespace OpenNest.Forms
|
|||||||
private static readonly string[] LeadOutTypes =
|
private static readonly string[] LeadOutTypes =
|
||||||
{ "None", "Line", "Arc", "Microtab" };
|
{ "None", "Line", "Arc", "Microtab" };
|
||||||
|
|
||||||
private ComboBox cboExternalLeadIn, cboExternalLeadOut;
|
private readonly TabControl tabControl;
|
||||||
private ComboBox cboInternalLeadIn, cboInternalLeadOut;
|
private readonly ComboBox cboExternalLeadIn, cboExternalLeadOut;
|
||||||
private ComboBox cboArcCircleLeadIn, cboArcCircleLeadOut;
|
private readonly ComboBox cboInternalLeadIn, cboInternalLeadOut;
|
||||||
|
private readonly ComboBox cboArcCircleLeadIn, cboArcCircleLeadOut;
|
||||||
|
|
||||||
private Panel pnlExternalLeadIn, pnlExternalLeadOut;
|
private readonly Panel pnlExternalLeadIn, pnlExternalLeadOut;
|
||||||
private Panel pnlInternalLeadIn, pnlInternalLeadOut;
|
private readonly Panel pnlInternalLeadIn, pnlInternalLeadOut;
|
||||||
private Panel pnlArcCircleLeadIn, pnlArcCircleLeadOut;
|
private readonly Panel pnlArcCircleLeadIn, pnlArcCircleLeadOut;
|
||||||
|
|
||||||
private CheckBox chkTabsEnabled;
|
private readonly CheckBox chkTabsEnabled;
|
||||||
private NumericUpDown nudTabWidth;
|
private readonly NumericUpDown nudTabWidth;
|
||||||
private NumericUpDown nudPierceClearance;
|
private readonly NumericUpDown nudAutoTabMin;
|
||||||
|
private readonly NumericUpDown nudAutoTabMax;
|
||||||
|
private readonly NumericUpDown nudPierceClearance;
|
||||||
|
|
||||||
private bool hasCustomParameters;
|
private readonly Button btnAutoAssign;
|
||||||
private CuttingParameters parameters = new CuttingParameters();
|
|
||||||
|
|
||||||
public CuttingParameters Parameters
|
private bool suppressEvents;
|
||||||
|
|
||||||
|
public event EventHandler ParametersChanged;
|
||||||
|
public event EventHandler AutoAssignClicked;
|
||||||
|
|
||||||
|
public bool ShowAutoAssign
|
||||||
{
|
{
|
||||||
get => parameters;
|
get => btnAutoAssign.Visible;
|
||||||
|
set => btnAutoAssign.Visible = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContourType? ActiveContourType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return tabControl.SelectedIndex switch
|
||||||
|
{
|
||||||
|
0 => ContourType.External,
|
||||||
|
1 => ContourType.Internal,
|
||||||
|
2 => ContourType.ArcCircle,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
parameters = value;
|
if (value == null)
|
||||||
hasCustomParameters = true;
|
return;
|
||||||
|
|
||||||
|
var index = value.Value switch
|
||||||
|
{
|
||||||
|
ContourType.External => 0,
|
||||||
|
ContourType.Internal => 1,
|
||||||
|
ContourType.ArcCircle => 2,
|
||||||
|
_ => -1
|
||||||
|
};
|
||||||
|
|
||||||
|
if (index >= 0 && tabControl.SelectedIndex != index)
|
||||||
|
tabControl.SelectedIndex = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CuttingParametersForm()
|
public CuttingPanel()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
AutoScroll = true;
|
||||||
|
BackColor = Color.White;
|
||||||
|
|
||||||
SetupTab(tabExternal,
|
// Tab control for contour types — wrapped in a fixed-height panel for Dock.Top
|
||||||
out cboExternalLeadIn, out pnlExternalLeadIn,
|
tabControl = new TabControl
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill
|
||||||
|
};
|
||||||
|
|
||||||
|
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, out cboExternalLeadIn, out pnlExternalLeadIn,
|
||||||
out cboExternalLeadOut, out pnlExternalLeadOut);
|
out cboExternalLeadOut, out pnlExternalLeadOut);
|
||||||
SetupTab(tabInternal,
|
SetupTab(tabInternal, out cboInternalLeadIn, out pnlInternalLeadIn,
|
||||||
out cboInternalLeadIn, out pnlInternalLeadIn,
|
|
||||||
out cboInternalLeadOut, out pnlInternalLeadOut);
|
out cboInternalLeadOut, out pnlInternalLeadOut);
|
||||||
SetupTab(tabArcCircle,
|
SetupTab(tabArcCircle, out cboArcCircleLeadIn, out pnlArcCircleLeadIn,
|
||||||
out cboArcCircleLeadIn, out pnlArcCircleLeadIn,
|
|
||||||
out cboArcCircleLeadOut, out pnlArcCircleLeadOut);
|
out cboArcCircleLeadOut, out pnlArcCircleLeadOut);
|
||||||
|
|
||||||
SetupTabsSection();
|
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);
|
||||||
|
|
||||||
|
// Tabs section
|
||||||
|
var tabsPanel = new CollapsiblePanel
|
||||||
|
{
|
||||||
|
HeaderText = "Tabs",
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
ExpandedHeight = 120,
|
||||||
|
IsExpanded = false
|
||||||
|
};
|
||||||
|
|
||||||
|
chkTabsEnabled = new CheckBox
|
||||||
|
{
|
||||||
|
Text = "Enable Tabs",
|
||||||
|
Location = new Point(12, 4),
|
||||||
|
AutoSize = true
|
||||||
|
};
|
||||||
|
chkTabsEnabled.CheckedChanged += (s, e) =>
|
||||||
|
{
|
||||||
|
nudTabWidth.Enabled = chkTabsEnabled.Checked;
|
||||||
|
OnParametersChanged();
|
||||||
|
};
|
||||||
|
tabsPanel.ContentPanel.Controls.Add(chkTabsEnabled);
|
||||||
|
|
||||||
|
tabsPanel.ContentPanel.Controls.Add(new Label
|
||||||
|
{
|
||||||
|
Text = "Width:",
|
||||||
|
Location = new Point(160, 6),
|
||||||
|
AutoSize = true
|
||||||
|
});
|
||||||
|
|
||||||
|
nudTabWidth = CreateNumeric(215, 3, 0.25, 0.0625);
|
||||||
|
nudTabWidth.Enabled = false;
|
||||||
|
tabsPanel.ContentPanel.Controls.Add(nudTabWidth);
|
||||||
|
|
||||||
|
tabsPanel.ContentPanel.Controls.Add(new Label
|
||||||
|
{
|
||||||
|
Text = "Auto-Tab Min Size:",
|
||||||
|
Location = new Point(12, 32),
|
||||||
|
AutoSize = true
|
||||||
|
});
|
||||||
|
|
||||||
|
nudAutoTabMin = CreateNumeric(140, 29, 0, 0.0625);
|
||||||
|
tabsPanel.ContentPanel.Controls.Add(nudAutoTabMin);
|
||||||
|
|
||||||
|
tabsPanel.ContentPanel.Controls.Add(new Label
|
||||||
|
{
|
||||||
|
Text = "Auto-Tab Max Size:",
|
||||||
|
Location = new Point(12, 58),
|
||||||
|
AutoSize = true
|
||||||
|
});
|
||||||
|
|
||||||
|
nudAutoTabMax = CreateNumeric(140, 55, 0, 0.0625);
|
||||||
|
tabsPanel.ContentPanel.Controls.Add(nudAutoTabMax);
|
||||||
|
|
||||||
|
// Pierce section
|
||||||
|
var piercePanel = new CollapsiblePanel
|
||||||
|
{
|
||||||
|
HeaderText = "Pierce",
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
ExpandedHeight = 60,
|
||||||
|
IsExpanded = true
|
||||||
|
};
|
||||||
|
|
||||||
|
piercePanel.ContentPanel.Controls.Add(new Label
|
||||||
|
{
|
||||||
|
Text = "Pierce Clearance:",
|
||||||
|
Location = new Point(12, 6),
|
||||||
|
AutoSize = true
|
||||||
|
});
|
||||||
|
|
||||||
|
nudPierceClearance = CreateNumeric(130, 3, 0.0625, 0.0625);
|
||||||
|
piercePanel.ContentPanel.Controls.Add(nudPierceClearance);
|
||||||
|
|
||||||
|
// Auto-Assign button — wrapped in a panel for Dock.Top with padding
|
||||||
|
btnAutoAssign = new Button
|
||||||
|
{
|
||||||
|
Text = "Auto-Assign Lead-ins",
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Height = 32,
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
btnAutoAssign.Click += (s, e) => AutoAssignClicked?.Invoke(this, EventArgs.Empty);
|
||||||
|
|
||||||
|
var btnWrapper = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
Height = 36,
|
||||||
|
Padding = new Padding(4, 2, 4, 2)
|
||||||
|
};
|
||||||
|
btnWrapper.Controls.Add(btnAutoAssign);
|
||||||
|
|
||||||
|
// Add in reverse order — Dock.Top stacks top-down
|
||||||
|
Controls.Add(btnWrapper);
|
||||||
|
Controls.Add(piercePanel);
|
||||||
|
Controls.Add(tabsPanel);
|
||||||
|
Controls.Add(tabWrapper);
|
||||||
|
|
||||||
|
// Wire up change events
|
||||||
PopulateDropdowns();
|
PopulateDropdowns();
|
||||||
|
WireChangeEvents();
|
||||||
cboExternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
|
||||||
cboInternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
|
||||||
cboArcCircleLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
|
||||||
|
|
||||||
cboExternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
|
||||||
cboInternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
|
||||||
cboArcCircleLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnLoad(EventArgs e)
|
public CuttingParameters BuildParameters()
|
||||||
{
|
{
|
||||||
base.OnLoad(e);
|
return new CuttingParameters
|
||||||
|
|
||||||
// If caller didn't provide custom parameters, try loading saved ones
|
|
||||||
if (!hasCustomParameters)
|
|
||||||
{
|
{
|
||||||
var json = Properties.Settings.Default.CuttingParametersJson;
|
ExternalLeadIn = BuildLeadIn(cboExternalLeadIn, pnlExternalLeadIn),
|
||||||
if (!string.IsNullOrEmpty(json))
|
ExternalLeadOut = BuildLeadOut(cboExternalLeadOut, pnlExternalLeadOut),
|
||||||
{
|
InternalLeadIn = BuildLeadIn(cboInternalLeadIn, pnlInternalLeadIn),
|
||||||
try { Parameters = CuttingParametersSerializer.Deserialize(json); }
|
InternalLeadOut = BuildLeadOut(cboInternalLeadOut, pnlInternalLeadOut),
|
||||||
catch { /* use defaults on corrupt data */ }
|
ArcCircleLeadIn = BuildLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn),
|
||||||
}
|
ArcCircleLeadOut = BuildLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut),
|
||||||
}
|
TabsEnabled = chkTabsEnabled.Checked,
|
||||||
|
TabConfig = new NormalTab { Size = (double)nudTabWidth.Value },
|
||||||
LoadFromParameters(Parameters);
|
PierceClearance = (double)nudPierceClearance.Value,
|
||||||
|
AutoTabMinSize = (double)nudAutoTabMin.Value,
|
||||||
|
AutoTabMaxSize = (double)nudAutoTabMax.Value
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
public void LoadFromParameters(CuttingParameters p)
|
||||||
{
|
{
|
||||||
base.OnFormClosing(e);
|
suppressEvents = true;
|
||||||
|
|
||||||
if (DialogResult == System.Windows.Forms.DialogResult.OK)
|
LoadLeadIn(cboExternalLeadIn, pnlExternalLeadIn, p.ExternalLeadIn);
|
||||||
{
|
LoadLeadOut(cboExternalLeadOut, pnlExternalLeadOut, p.ExternalLeadOut);
|
||||||
var json = CuttingParametersSerializer.Serialize(BuildParameters());
|
LoadLeadIn(cboInternalLeadIn, pnlInternalLeadIn, p.InternalLeadIn);
|
||||||
Properties.Settings.Default.CuttingParametersJson = json;
|
LoadLeadOut(cboInternalLeadOut, pnlInternalLeadOut, p.InternalLeadOut);
|
||||||
Properties.Settings.Default.Save();
|
LoadLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn, p.ArcCircleLeadIn);
|
||||||
}
|
LoadLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut, p.ArcCircleLeadOut);
|
||||||
|
|
||||||
|
chkTabsEnabled.Checked = p.TabsEnabled;
|
||||||
|
if (p.TabConfig != null)
|
||||||
|
nudTabWidth.Value = (decimal)p.TabConfig.Size;
|
||||||
|
nudPierceClearance.Value = (decimal)p.PierceClearance;
|
||||||
|
nudAutoTabMin.Value = (decimal)p.AutoTabMinSize;
|
||||||
|
nudAutoTabMax.Value = (decimal)p.AutoTabMaxSize;
|
||||||
|
|
||||||
|
suppressEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnParametersChanged()
|
||||||
|
{
|
||||||
|
if (!suppressEvents)
|
||||||
|
ParametersChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetupTab(TabPage tab,
|
private static void SetupTab(TabPage tab,
|
||||||
@@ -100,30 +257,30 @@ namespace OpenNest.Forms
|
|||||||
var grpLeadIn = new GroupBox
|
var grpLeadIn = new GroupBox
|
||||||
{
|
{
|
||||||
Text = "Lead-In",
|
Text = "Lead-In",
|
||||||
Location = new System.Drawing.Point(4, 4),
|
Location = new Point(4, 4),
|
||||||
Size = new System.Drawing.Size(364, 168)
|
Size = new Size(340, 148)
|
||||||
};
|
};
|
||||||
tab.Controls.Add(grpLeadIn);
|
tab.Controls.Add(grpLeadIn);
|
||||||
|
|
||||||
grpLeadIn.Controls.Add(new Label
|
grpLeadIn.Controls.Add(new Label
|
||||||
{
|
{
|
||||||
Text = "Type:",
|
Text = "Type:",
|
||||||
Location = new System.Drawing.Point(8, 22),
|
Location = new Point(8, 22),
|
||||||
AutoSize = true
|
AutoSize = true
|
||||||
});
|
});
|
||||||
|
|
||||||
leadInCombo = new ComboBox
|
leadInCombo = new ComboBox
|
||||||
{
|
{
|
||||||
DropDownStyle = ComboBoxStyle.DropDownList,
|
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||||
Location = new System.Drawing.Point(90, 19),
|
Location = new Point(90, 19),
|
||||||
Size = new System.Drawing.Size(250, 24)
|
Size = new Size(230, 24)
|
||||||
};
|
};
|
||||||
grpLeadIn.Controls.Add(leadInCombo);
|
grpLeadIn.Controls.Add(leadInCombo);
|
||||||
|
|
||||||
leadInPanel = new Panel
|
leadInPanel = new Panel
|
||||||
{
|
{
|
||||||
Location = new System.Drawing.Point(8, 48),
|
Location = new Point(8, 48),
|
||||||
Size = new System.Drawing.Size(340, 112),
|
Size = new Size(320, 92),
|
||||||
AutoScroll = true
|
AutoScroll = true
|
||||||
};
|
};
|
||||||
grpLeadIn.Controls.Add(leadInPanel);
|
grpLeadIn.Controls.Add(leadInPanel);
|
||||||
@@ -131,106 +288,35 @@ namespace OpenNest.Forms
|
|||||||
var grpLeadOut = new GroupBox
|
var grpLeadOut = new GroupBox
|
||||||
{
|
{
|
||||||
Text = "Lead-Out",
|
Text = "Lead-Out",
|
||||||
Location = new System.Drawing.Point(4, 176),
|
Location = new Point(4, 156),
|
||||||
Size = new System.Drawing.Size(364, 132)
|
Size = new Size(340, 132)
|
||||||
};
|
};
|
||||||
tab.Controls.Add(grpLeadOut);
|
tab.Controls.Add(grpLeadOut);
|
||||||
|
|
||||||
grpLeadOut.Controls.Add(new Label
|
grpLeadOut.Controls.Add(new Label
|
||||||
{
|
{
|
||||||
Text = "Type:",
|
Text = "Type:",
|
||||||
Location = new System.Drawing.Point(8, 22),
|
Location = new Point(8, 22),
|
||||||
AutoSize = true
|
AutoSize = true
|
||||||
});
|
});
|
||||||
|
|
||||||
leadOutCombo = new ComboBox
|
leadOutCombo = new ComboBox
|
||||||
{
|
{
|
||||||
DropDownStyle = ComboBoxStyle.DropDownList,
|
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||||
Location = new System.Drawing.Point(90, 19),
|
Location = new Point(90, 19),
|
||||||
Size = new System.Drawing.Size(250, 24)
|
Size = new Size(230, 24)
|
||||||
};
|
};
|
||||||
grpLeadOut.Controls.Add(leadOutCombo);
|
grpLeadOut.Controls.Add(leadOutCombo);
|
||||||
|
|
||||||
leadOutPanel = new Panel
|
leadOutPanel = new Panel
|
||||||
{
|
{
|
||||||
Location = new System.Drawing.Point(8, 48),
|
Location = new Point(8, 48),
|
||||||
Size = new System.Drawing.Size(340, 76),
|
Size = new Size(320, 76),
|
||||||
AutoScroll = true
|
AutoScroll = true
|
||||||
};
|
};
|
||||||
grpLeadOut.Controls.Add(leadOutPanel);
|
grpLeadOut.Controls.Add(leadOutPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupTabsSection()
|
|
||||||
{
|
|
||||||
var grpTabs = new GroupBox
|
|
||||||
{
|
|
||||||
Text = "Tabs",
|
|
||||||
Location = new System.Drawing.Point(4, 350),
|
|
||||||
Size = new System.Drawing.Size(372, 55),
|
|
||||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
|
||||||
};
|
|
||||||
|
|
||||||
chkTabsEnabled = new CheckBox
|
|
||||||
{
|
|
||||||
Text = "Enable Tabs",
|
|
||||||
Location = new System.Drawing.Point(12, 22),
|
|
||||||
AutoSize = true
|
|
||||||
};
|
|
||||||
chkTabsEnabled.CheckedChanged += (s, e) => nudTabWidth.Enabled = chkTabsEnabled.Checked;
|
|
||||||
grpTabs.Controls.Add(chkTabsEnabled);
|
|
||||||
|
|
||||||
grpTabs.Controls.Add(new Label
|
|
||||||
{
|
|
||||||
Text = "Width:",
|
|
||||||
Location = new System.Drawing.Point(160, 23),
|
|
||||||
AutoSize = true
|
|
||||||
});
|
|
||||||
|
|
||||||
nudTabWidth = new NumericUpDown
|
|
||||||
{
|
|
||||||
Location = new System.Drawing.Point(215, 20),
|
|
||||||
Size = new System.Drawing.Size(100, 22),
|
|
||||||
DecimalPlaces = 4,
|
|
||||||
Increment = 0.0625m,
|
|
||||||
Minimum = 0,
|
|
||||||
Maximum = 9999,
|
|
||||||
Value = 0.25m,
|
|
||||||
Enabled = false
|
|
||||||
};
|
|
||||||
grpTabs.Controls.Add(nudTabWidth);
|
|
||||||
|
|
||||||
Controls.Add(grpTabs);
|
|
||||||
|
|
||||||
var grpPierce = new GroupBox
|
|
||||||
{
|
|
||||||
Text = "Pierce",
|
|
||||||
Location = new System.Drawing.Point(4, 410),
|
|
||||||
Size = new System.Drawing.Size(372, 55),
|
|
||||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right
|
|
||||||
};
|
|
||||||
|
|
||||||
grpPierce.Controls.Add(new Label
|
|
||||||
{
|
|
||||||
Text = "Pierce Clearance:",
|
|
||||||
Location = new System.Drawing.Point(12, 23),
|
|
||||||
AutoSize = true
|
|
||||||
});
|
|
||||||
|
|
||||||
nudPierceClearance = new NumericUpDown
|
|
||||||
{
|
|
||||||
Location = new System.Drawing.Point(130, 20),
|
|
||||||
Size = new System.Drawing.Size(100, 22),
|
|
||||||
DecimalPlaces = 4,
|
|
||||||
Increment = 0.0625m,
|
|
||||||
Minimum = 0,
|
|
||||||
Maximum = 9999,
|
|
||||||
Value = 0.0625m
|
|
||||||
};
|
|
||||||
grpPierce.Controls.Add(nudPierceClearance);
|
|
||||||
|
|
||||||
Controls.Add(grpPierce);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PopulateDropdowns()
|
private void PopulateDropdowns()
|
||||||
{
|
{
|
||||||
foreach (var combo in new[] { cboExternalLeadIn, cboInternalLeadIn, cboArcCircleLeadIn })
|
foreach (var combo in new[] { cboExternalLeadIn, cboInternalLeadIn, cboArcCircleLeadIn })
|
||||||
@@ -246,12 +332,24 @@ namespace OpenNest.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void WireChangeEvents()
|
||||||
|
{
|
||||||
|
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)
|
private void OnLeadInTypeChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var combo = (ComboBox)sender;
|
var combo = (ComboBox)sender;
|
||||||
var panel = GetLeadInPanel(combo);
|
var panel = GetLeadInPanel(combo);
|
||||||
if (panel != null)
|
if (panel != null)
|
||||||
BuildLeadInParamControls(panel, combo.SelectedIndex);
|
BuildLeadInParamControls(panel, combo.SelectedIndex);
|
||||||
|
OnParametersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLeadOutTypeChanged(object sender, EventArgs e)
|
private void OnLeadOutTypeChanged(object sender, EventArgs e)
|
||||||
@@ -260,6 +358,7 @@ namespace OpenNest.Forms
|
|||||||
var panel = GetLeadOutPanel(combo);
|
var panel = GetLeadOutPanel(combo);
|
||||||
if (panel != null)
|
if (panel != null)
|
||||||
BuildLeadOutParamControls(panel, combo.SelectedIndex);
|
BuildLeadOutParamControls(panel, combo.SelectedIndex);
|
||||||
|
OnParametersChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Panel GetLeadInPanel(ComboBox combo)
|
private Panel GetLeadInPanel(ComboBox combo)
|
||||||
@@ -278,31 +377,31 @@ namespace OpenNest.Forms
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BuildLeadInParamControls(Panel panel, int typeIndex)
|
private void BuildLeadInParamControls(Panel panel, int typeIndex)
|
||||||
{
|
{
|
||||||
panel.Controls.Clear();
|
panel.Controls.Clear();
|
||||||
var y = 0;
|
var y = 0;
|
||||||
|
|
||||||
switch (typeIndex)
|
switch (typeIndex)
|
||||||
{
|
{
|
||||||
case 1: // Line
|
case 1:
|
||||||
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
||||||
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
||||||
break;
|
break;
|
||||||
case 2: // Arc
|
case 2:
|
||||||
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
||||||
break;
|
break;
|
||||||
case 3: // Line + Arc
|
case 3:
|
||||||
AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength");
|
AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength");
|
||||||
AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius");
|
AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius");
|
||||||
AddNumericField(panel, "Approach Angle:", 135, ref y, "ApproachAngle");
|
AddNumericField(panel, "Approach Angle:", 135, ref y, "ApproachAngle");
|
||||||
break;
|
break;
|
||||||
case 4: // Clean Hole
|
case 4:
|
||||||
AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength");
|
AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength");
|
||||||
AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius");
|
AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius");
|
||||||
AddNumericField(panel, "Kerf:", 0.06, ref y, "Kerf");
|
AddNumericField(panel, "Kerf:", 0.06, ref y, "Kerf");
|
||||||
break;
|
break;
|
||||||
case 5: // Line + Line
|
case 5:
|
||||||
AddNumericField(panel, "Length 1:", 0.25, ref y, "Length1");
|
AddNumericField(panel, "Length 1:", 0.25, ref y, "Length1");
|
||||||
AddNumericField(panel, "Angle 1:", 90, ref y, "Angle1");
|
AddNumericField(panel, "Angle 1:", 90, ref y, "Angle1");
|
||||||
AddNumericField(panel, "Length 2:", 0.25, ref y, "Length2");
|
AddNumericField(panel, "Length 2:", 0.25, ref y, "Length2");
|
||||||
@@ -311,67 +410,56 @@ namespace OpenNest.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BuildLeadOutParamControls(Panel panel, int typeIndex)
|
private void BuildLeadOutParamControls(Panel panel, int typeIndex)
|
||||||
{
|
{
|
||||||
panel.Controls.Clear();
|
panel.Controls.Clear();
|
||||||
var y = 0;
|
var y = 0;
|
||||||
|
|
||||||
switch (typeIndex)
|
switch (typeIndex)
|
||||||
{
|
{
|
||||||
case 1: // Line
|
case 1:
|
||||||
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
||||||
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
||||||
break;
|
break;
|
||||||
case 2: // Arc
|
case 2:
|
||||||
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
||||||
break;
|
break;
|
||||||
case 3: // Microtab
|
case 3:
|
||||||
AddNumericField(panel, "Gap Size:", 0.06, ref y, "GapSize");
|
AddNumericField(panel, "Gap Size:", 0.06, ref y, "GapSize");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddNumericField(Panel panel, string label, double defaultValue,
|
private void AddNumericField(Panel panel, string label, double defaultValue,
|
||||||
ref int y, string tag)
|
ref int y, string tag)
|
||||||
{
|
{
|
||||||
panel.Controls.Add(new Label
|
panel.Controls.Add(new Label
|
||||||
{
|
{
|
||||||
Text = label,
|
Text = label,
|
||||||
Location = new System.Drawing.Point(0, y + 3),
|
Location = new Point(0, y + 3),
|
||||||
AutoSize = true
|
AutoSize = true
|
||||||
});
|
});
|
||||||
|
|
||||||
panel.Controls.Add(new NumericUpDown
|
var nud = CreateNumeric(130, y, defaultValue, 0.0625);
|
||||||
{
|
nud.Tag = tag;
|
||||||
Location = new System.Drawing.Point(130, y),
|
nud.ValueChanged += (s, e) => OnParametersChanged();
|
||||||
Size = new System.Drawing.Size(120, 22),
|
panel.Controls.Add(nud);
|
||||||
DecimalPlaces = 4,
|
|
||||||
Increment = 0.0625m,
|
|
||||||
Minimum = 0,
|
|
||||||
Maximum = 9999,
|
|
||||||
Value = (decimal)defaultValue,
|
|
||||||
Tag = tag
|
|
||||||
});
|
|
||||||
|
|
||||||
y += 30;
|
y += 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadFromParameters(CuttingParameters p)
|
private static NumericUpDown CreateNumeric(int x, int y, double defaultValue, double increment)
|
||||||
{
|
{
|
||||||
LoadLeadIn(cboExternalLeadIn, pnlExternalLeadIn, p.ExternalLeadIn);
|
return new NumericUpDown
|
||||||
LoadLeadOut(cboExternalLeadOut, pnlExternalLeadOut, p.ExternalLeadOut);
|
{
|
||||||
|
Location = new Point(x, y),
|
||||||
LoadLeadIn(cboInternalLeadIn, pnlInternalLeadIn, p.InternalLeadIn);
|
Size = new Size(120, 22),
|
||||||
LoadLeadOut(cboInternalLeadOut, pnlInternalLeadOut, p.InternalLeadOut);
|
DecimalPlaces = 4,
|
||||||
|
Increment = (decimal)increment,
|
||||||
LoadLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn, p.ArcCircleLeadIn);
|
Minimum = 0,
|
||||||
LoadLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut, p.ArcCircleLeadOut);
|
Maximum = 9999,
|
||||||
|
Value = (decimal)defaultValue
|
||||||
chkTabsEnabled.Checked = p.TabsEnabled;
|
};
|
||||||
if (p.TabConfig != null)
|
|
||||||
nudTabWidth.Value = (decimal)p.TabConfig.Size;
|
|
||||||
|
|
||||||
nudPierceClearance.Value = (decimal)p.PierceClearance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LoadLeadIn(ComboBox combo, Panel panel, LeadIn leadIn)
|
private static void LoadLeadIn(ComboBox combo, Panel panel, LeadIn leadIn)
|
||||||
@@ -435,88 +523,61 @@ namespace OpenNest.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CuttingParameters BuildParameters()
|
|
||||||
{
|
|
||||||
var p = new CuttingParameters
|
|
||||||
{
|
|
||||||
ExternalLeadIn = BuildLeadIn(cboExternalLeadIn, pnlExternalLeadIn),
|
|
||||||
ExternalLeadOut = BuildLeadOut(cboExternalLeadOut, pnlExternalLeadOut),
|
|
||||||
InternalLeadIn = BuildLeadIn(cboInternalLeadIn, pnlInternalLeadIn),
|
|
||||||
InternalLeadOut = BuildLeadOut(cboInternalLeadOut, pnlInternalLeadOut),
|
|
||||||
ArcCircleLeadIn = BuildLeadIn(cboArcCircleLeadIn, pnlArcCircleLeadIn),
|
|
||||||
ArcCircleLeadOut = BuildLeadOut(cboArcCircleLeadOut, pnlArcCircleLeadOut),
|
|
||||||
TabsEnabled = chkTabsEnabled.Checked,
|
|
||||||
TabConfig = new NormalTab { Size = (double)nudTabWidth.Value },
|
|
||||||
PierceClearance = (double)nudPierceClearance.Value
|
|
||||||
};
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LeadIn BuildLeadIn(ComboBox combo, Panel panel)
|
private static LeadIn BuildLeadIn(ComboBox combo, Panel panel)
|
||||||
{
|
{
|
||||||
switch (combo.SelectedIndex)
|
return combo.SelectedIndex switch
|
||||||
{
|
{
|
||||||
case 1:
|
1 => new LineLeadIn
|
||||||
return new LineLeadIn
|
{
|
||||||
{
|
Length = GetParam(panel, "Length", 0.25),
|
||||||
Length = GetParam(panel, "Length", 0.25),
|
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
||||||
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
},
|
||||||
};
|
2 => new ArcLeadIn
|
||||||
case 2:
|
{
|
||||||
return new ArcLeadIn
|
Radius = GetParam(panel, "Radius", 0.25)
|
||||||
{
|
},
|
||||||
Radius = GetParam(panel, "Radius", 0.25)
|
3 => new LineArcLeadIn
|
||||||
};
|
{
|
||||||
case 3:
|
LineLength = GetParam(panel, "LineLength", 0.25),
|
||||||
return new LineArcLeadIn
|
ArcRadius = GetParam(panel, "ArcRadius", 0.125),
|
||||||
{
|
ApproachAngle = GetParam(panel, "ApproachAngle", 135)
|
||||||
LineLength = GetParam(panel, "LineLength", 0.25),
|
},
|
||||||
ArcRadius = GetParam(panel, "ArcRadius", 0.125),
|
4 => new CleanHoleLeadIn
|
||||||
ApproachAngle = GetParam(panel, "ApproachAngle", 135)
|
{
|
||||||
};
|
LineLength = GetParam(panel, "LineLength", 0.25),
|
||||||
case 4:
|
ArcRadius = GetParam(panel, "ArcRadius", 0.125),
|
||||||
return new CleanHoleLeadIn
|
Kerf = GetParam(panel, "Kerf", 0.06)
|
||||||
{
|
},
|
||||||
LineLength = GetParam(panel, "LineLength", 0.25),
|
5 => new LineLineLeadIn
|
||||||
ArcRadius = GetParam(panel, "ArcRadius", 0.125),
|
{
|
||||||
Kerf = GetParam(panel, "Kerf", 0.06)
|
Length1 = GetParam(panel, "Length1", 0.25),
|
||||||
};
|
ApproachAngle1 = GetParam(panel, "Angle1", 90),
|
||||||
case 5:
|
Length2 = GetParam(panel, "Length2", 0.25),
|
||||||
return new LineLineLeadIn
|
ApproachAngle2 = GetParam(panel, "Angle2", 90)
|
||||||
{
|
},
|
||||||
Length1 = GetParam(panel, "Length1", 0.25),
|
_ => new NoLeadIn()
|
||||||
ApproachAngle1 = GetParam(panel, "Angle1", 90),
|
};
|
||||||
Length2 = GetParam(panel, "Length2", 0.25),
|
|
||||||
ApproachAngle2 = GetParam(panel, "Angle2", 90)
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return new NoLeadIn();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LeadOut BuildLeadOut(ComboBox combo, Panel panel)
|
private static LeadOut BuildLeadOut(ComboBox combo, Panel panel)
|
||||||
{
|
{
|
||||||
switch (combo.SelectedIndex)
|
return combo.SelectedIndex switch
|
||||||
{
|
{
|
||||||
case 1:
|
1 => new LineLeadOut
|
||||||
return new LineLeadOut
|
{
|
||||||
{
|
Length = GetParam(panel, "Length", 0.25),
|
||||||
Length = GetParam(panel, "Length", 0.25),
|
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
||||||
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
},
|
||||||
};
|
2 => new ArcLeadOut
|
||||||
case 2:
|
{
|
||||||
return new ArcLeadOut
|
Radius = GetParam(panel, "Radius", 0.25)
|
||||||
{
|
},
|
||||||
Radius = GetParam(panel, "Radius", 0.25)
|
3 => new MicrotabLeadOut
|
||||||
};
|
{
|
||||||
case 3:
|
GapSize = GetParam(panel, "GapSize", 0.06)
|
||||||
return new MicrotabLeadOut
|
},
|
||||||
{
|
_ => new NoLeadOut()
|
||||||
GapSize = GetParam(panel, "GapSize", 0.06)
|
};
|
||||||
};
|
|
||||||
default:
|
|
||||||
return new NoLeadOut();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetParam(Panel panel, string tag, double value)
|
private static void SetParam(Panel panel, string tag, double value)
|
||||||
-156
@@ -1,156 +0,0 @@
|
|||||||
namespace OpenNest.Forms
|
|
||||||
{
|
|
||||||
partial class CuttingParametersForm
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
this.tabControl = new System.Windows.Forms.TabControl();
|
|
||||||
this.tabExternal = new System.Windows.Forms.TabPage();
|
|
||||||
this.tabInternal = new System.Windows.Forms.TabPage();
|
|
||||||
this.tabArcCircle = new System.Windows.Forms.TabPage();
|
|
||||||
this.acceptButton = new System.Windows.Forms.Button();
|
|
||||||
this.cancelButton = new System.Windows.Forms.Button();
|
|
||||||
this.bottomPanel = new OpenNest.Controls.BottomPanel();
|
|
||||||
this.tabControl.SuspendLayout();
|
|
||||||
this.bottomPanel.SuspendLayout();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// tabControl
|
|
||||||
//
|
|
||||||
this.tabControl.Controls.Add(this.tabExternal);
|
|
||||||
this.tabControl.Controls.Add(this.tabInternal);
|
|
||||||
this.tabControl.Controls.Add(this.tabArcCircle);
|
|
||||||
this.tabControl.Dock = System.Windows.Forms.DockStyle.Top;
|
|
||||||
this.tabControl.Location = new System.Drawing.Point(0, 0);
|
|
||||||
this.tabControl.Margin = new System.Windows.Forms.Padding(4);
|
|
||||||
this.tabControl.Name = "tabControl";
|
|
||||||
this.tabControl.SelectedIndex = 0;
|
|
||||||
this.tabControl.Size = new System.Drawing.Size(380, 348);
|
|
||||||
this.tabControl.TabIndex = 0;
|
|
||||||
//
|
|
||||||
// tabExternal
|
|
||||||
//
|
|
||||||
this.tabExternal.Location = new System.Drawing.Point(4, 25);
|
|
||||||
this.tabExternal.Margin = new System.Windows.Forms.Padding(4);
|
|
||||||
this.tabExternal.Name = "tabExternal";
|
|
||||||
this.tabExternal.Padding = new System.Windows.Forms.Padding(8);
|
|
||||||
this.tabExternal.Size = new System.Drawing.Size(372, 319);
|
|
||||||
this.tabExternal.TabIndex = 0;
|
|
||||||
this.tabExternal.Text = "External";
|
|
||||||
this.tabExternal.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// tabInternal
|
|
||||||
//
|
|
||||||
this.tabInternal.Location = new System.Drawing.Point(4, 25);
|
|
||||||
this.tabInternal.Margin = new System.Windows.Forms.Padding(4);
|
|
||||||
this.tabInternal.Name = "tabInternal";
|
|
||||||
this.tabInternal.Padding = new System.Windows.Forms.Padding(8);
|
|
||||||
this.tabInternal.Size = new System.Drawing.Size(372, 319);
|
|
||||||
this.tabInternal.TabIndex = 1;
|
|
||||||
this.tabInternal.Text = "Internal";
|
|
||||||
this.tabInternal.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// tabArcCircle
|
|
||||||
//
|
|
||||||
this.tabArcCircle.Location = new System.Drawing.Point(4, 25);
|
|
||||||
this.tabArcCircle.Margin = new System.Windows.Forms.Padding(4);
|
|
||||||
this.tabArcCircle.Name = "tabArcCircle";
|
|
||||||
this.tabArcCircle.Padding = new System.Windows.Forms.Padding(8);
|
|
||||||
this.tabArcCircle.Size = new System.Drawing.Size(372, 319);
|
|
||||||
this.tabArcCircle.TabIndex = 2;
|
|
||||||
this.tabArcCircle.Text = "Arc / Circle";
|
|
||||||
this.tabArcCircle.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// acceptButton
|
|
||||||
//
|
|
||||||
this.acceptButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.acceptButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
|
||||||
this.acceptButton.Location = new System.Drawing.Point(165, 11);
|
|
||||||
this.acceptButton.Margin = new System.Windows.Forms.Padding(4);
|
|
||||||
this.acceptButton.Name = "acceptButton";
|
|
||||||
this.acceptButton.Size = new System.Drawing.Size(90, 28);
|
|
||||||
this.acceptButton.TabIndex = 8;
|
|
||||||
this.acceptButton.Text = "OK";
|
|
||||||
this.acceptButton.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// cancelButton
|
|
||||||
//
|
|
||||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
|
||||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
|
||||||
this.cancelButton.Location = new System.Drawing.Point(263, 11);
|
|
||||||
this.cancelButton.Margin = new System.Windows.Forms.Padding(4);
|
|
||||||
this.cancelButton.Name = "cancelButton";
|
|
||||||
this.cancelButton.Size = new System.Drawing.Size(90, 28);
|
|
||||||
this.cancelButton.TabIndex = 9;
|
|
||||||
this.cancelButton.Text = "Cancel";
|
|
||||||
this.cancelButton.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// bottomPanel
|
|
||||||
//
|
|
||||||
this.bottomPanel.Controls.Add(this.acceptButton);
|
|
||||||
this.bottomPanel.Controls.Add(this.cancelButton);
|
|
||||||
this.bottomPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
|
|
||||||
this.bottomPanel.Location = new System.Drawing.Point(0, 466);
|
|
||||||
this.bottomPanel.Name = "bottomPanel";
|
|
||||||
this.bottomPanel.Size = new System.Drawing.Size(380, 50);
|
|
||||||
this.bottomPanel.TabIndex = 1;
|
|
||||||
//
|
|
||||||
// CuttingParametersForm
|
|
||||||
//
|
|
||||||
this.AcceptButton = this.acceptButton;
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.CancelButton = this.cancelButton;
|
|
||||||
this.ClientSize = new System.Drawing.Size(380, 516);
|
|
||||||
this.Controls.Add(this.tabControl);
|
|
||||||
this.Controls.Add(this.bottomPanel);
|
|
||||||
this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
|
||||||
this.Margin = new System.Windows.Forms.Padding(4);
|
|
||||||
this.MaximizeBox = false;
|
|
||||||
this.MinimizeBox = false;
|
|
||||||
this.Name = "CuttingParametersForm";
|
|
||||||
this.ShowIcon = false;
|
|
||||||
this.ShowInTaskbar = false;
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
|
||||||
this.Text = "Cutting Parameters";
|
|
||||||
this.tabControl.ResumeLayout(false);
|
|
||||||
this.bottomPanel.ResumeLayout(false);
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.TabControl tabControl;
|
|
||||||
private System.Windows.Forms.TabPage tabExternal;
|
|
||||||
private System.Windows.Forms.TabPage tabInternal;
|
|
||||||
private System.Windows.Forms.TabPage tabArcCircle;
|
|
||||||
private Controls.BottomPanel bottomPanel;
|
|
||||||
private System.Windows.Forms.Button acceptButton;
|
|
||||||
private System.Windows.Forms.Button cancelButton;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@ using System.Text.Json;
|
|||||||
|
|
||||||
namespace OpenNest.Forms
|
namespace OpenNest.Forms
|
||||||
{
|
{
|
||||||
internal static class CuttingParametersSerializer
|
public static class CuttingParametersSerializer
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,9 @@ namespace OpenNest.Forms
|
|||||||
ArcCircleLeadOut = ToLeadOutDto(p.ArcCircleLeadOut),
|
ArcCircleLeadOut = ToLeadOutDto(p.ArcCircleLeadOut),
|
||||||
TabsEnabled = p.TabsEnabled,
|
TabsEnabled = p.TabsEnabled,
|
||||||
TabWidth = p.TabConfig?.Size ?? 0.25,
|
TabWidth = p.TabConfig?.Size ?? 0.25,
|
||||||
PierceClearance = p.PierceClearance
|
PierceClearance = p.PierceClearance,
|
||||||
|
AutoTabMinSize = p.AutoTabMinSize,
|
||||||
|
AutoTabMaxSize = p.AutoTabMaxSize
|
||||||
};
|
};
|
||||||
return JsonSerializer.Serialize(dto, JsonOptions);
|
return JsonSerializer.Serialize(dto, JsonOptions);
|
||||||
}
|
}
|
||||||
@@ -44,7 +46,9 @@ namespace OpenNest.Forms
|
|||||||
ArcCircleLeadOut = FromLeadOutDto(dto.ArcCircleLeadOut),
|
ArcCircleLeadOut = FromLeadOutDto(dto.ArcCircleLeadOut),
|
||||||
TabsEnabled = dto.TabsEnabled,
|
TabsEnabled = dto.TabsEnabled,
|
||||||
TabConfig = new NormalTab { Size = dto.TabWidth },
|
TabConfig = new NormalTab { Size = dto.TabWidth },
|
||||||
PierceClearance = dto.PierceClearance
|
PierceClearance = dto.PierceClearance,
|
||||||
|
AutoTabMinSize = dto.AutoTabMinSize,
|
||||||
|
AutoTabMaxSize = dto.AutoTabMaxSize
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +113,8 @@ namespace OpenNest.Forms
|
|||||||
public bool TabsEnabled { get; set; }
|
public bool TabsEnabled { get; set; }
|
||||||
public double TabWidth { get; set; }
|
public double TabWidth { get; set; }
|
||||||
public double PierceClearance { get; set; }
|
public double PierceClearance { get; set; }
|
||||||
|
public double AutoTabMinSize { get; set; }
|
||||||
|
public double AutoTabMaxSize { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LeadInDto
|
private class LeadInDto
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ namespace OpenNest.Forms
|
|||||||
private Button btnNextPlate;
|
private Button btnNextPlate;
|
||||||
private Button btnLastPlate;
|
private Button btnLastPlate;
|
||||||
|
|
||||||
|
private SplitContainer viewSplitContainer;
|
||||||
|
private Panel sidePanel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to distinguish between single/double click on drawing within drawinglistbox.
|
/// Used to distinguish between single/double click on drawing within drawinglistbox.
|
||||||
/// If double click, this is set to false so the single click action won't be triggered.
|
/// If double click, this is set to false so the single click action won't be triggered.
|
||||||
@@ -53,8 +56,9 @@ namespace OpenNest.Forms
|
|||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
CreatePlateHeader();
|
CreatePlateHeader();
|
||||||
|
CreateSidePanel();
|
||||||
|
|
||||||
splitContainer.Panel2.Controls.Add(PlateView);
|
splitContainer.Panel2.Controls.Add(viewSplitContainer);
|
||||||
splitContainer.Panel2.Controls.Add(plateHeaderPanel);
|
splitContainer.Panel2.Controls.Add(plateHeaderPanel);
|
||||||
|
|
||||||
var renderer = new ToolStripRenderer(ToolbarTheme.Toolbar);
|
var renderer = new ToolStripRenderer(ToolbarTheme.Toolbar);
|
||||||
@@ -146,6 +150,43 @@ namespace OpenNest.Forms
|
|||||||
navPanel.Top = (plateHeaderPanel.Height - navPanel.Height) / 2;
|
navPanel.Top = (plateHeaderPanel.Height - navPanel.Height) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateSidePanel()
|
||||||
|
{
|
||||||
|
sidePanel = new Panel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
AutoScroll = true,
|
||||||
|
BackColor = Color.White
|
||||||
|
};
|
||||||
|
|
||||||
|
viewSplitContainer = new SplitContainer
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Orientation = Orientation.Vertical,
|
||||||
|
FixedPanel = FixedPanel.Panel2,
|
||||||
|
Panel2MinSize = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
viewSplitContainer.Panel1.Controls.Add(PlateView);
|
||||||
|
viewSplitContainer.Panel2.Controls.Add(sidePanel);
|
||||||
|
viewSplitContainer.Panel2Collapsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowSidePanel(Control content, int width = 390)
|
||||||
|
{
|
||||||
|
sidePanel.Controls.Clear();
|
||||||
|
content.Dock = DockStyle.Fill;
|
||||||
|
sidePanel.Controls.Add(content);
|
||||||
|
viewSplitContainer.SplitterDistance = viewSplitContainer.Width - width;
|
||||||
|
viewSplitContainer.Panel2Collapsed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HideSidePanel()
|
||||||
|
{
|
||||||
|
viewSplitContainer.Panel2Collapsed = true;
|
||||||
|
sidePanel.Controls.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
private static Button CreateNavButton(System.Drawing.Image image)
|
private static Button CreateNavButton(System.Drawing.Image image)
|
||||||
{
|
{
|
||||||
return new Button
|
return new Button
|
||||||
@@ -725,15 +766,19 @@ namespace OpenNest.Forms
|
|||||||
|
|
||||||
var plate = PlateView.Plate;
|
var plate = PlateView.Plate;
|
||||||
|
|
||||||
using var form = new CuttingParametersForm();
|
if (plate.CuttingParameters == null)
|
||||||
if (plate.CuttingParameters != null)
|
{
|
||||||
form.Parameters = plate.CuttingParameters;
|
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||||
|
if (!string.IsNullOrEmpty(json))
|
||||||
if (form.ShowDialog(this) != DialogResult.OK)
|
{
|
||||||
return;
|
try { plate.CuttingParameters = CuttingParametersSerializer.Deserialize(json); }
|
||||||
|
catch { plate.CuttingParameters = new CuttingParameters(); }
|
||||||
var parameters = form.BuildParameters();
|
}
|
||||||
plate.CuttingParameters = parameters;
|
else
|
||||||
|
{
|
||||||
|
plate.CuttingParameters = new CuttingParameters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var assigner = new LeadInAssigner
|
var assigner = new LeadInAssigner
|
||||||
{
|
{
|
||||||
@@ -784,11 +829,18 @@ namespace OpenNest.Forms
|
|||||||
if (Nest == null)
|
if (Nest == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using var form = new CuttingParametersForm();
|
CuttingParameters parameters;
|
||||||
if (form.ShowDialog(this) != DialogResult.OK)
|
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||||
return;
|
if (!string.IsNullOrEmpty(json))
|
||||||
|
{
|
||||||
|
try { parameters = CuttingParametersSerializer.Deserialize(json); }
|
||||||
|
catch { parameters = new CuttingParameters(); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parameters = new CuttingParameters();
|
||||||
|
}
|
||||||
|
|
||||||
var parameters = form.BuildParameters();
|
|
||||||
var assigner = new LeadInAssigner
|
var assigner = new LeadInAssigner
|
||||||
{
|
{
|
||||||
Sequencer = new LeftSideSequencer()
|
Sequencer = new LeftSideSequencer()
|
||||||
@@ -835,14 +887,19 @@ namespace OpenNest.Forms
|
|||||||
|
|
||||||
var plate = PlateView.Plate;
|
var plate = PlateView.Plate;
|
||||||
|
|
||||||
// Ensure cutting parameters are configured
|
// If no cutting parameters exist, initialize from saved settings or defaults
|
||||||
if (plate.CuttingParameters == null)
|
if (plate.CuttingParameters == null)
|
||||||
{
|
{
|
||||||
using var form = new CuttingParametersForm();
|
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||||
if (form.ShowDialog(this) != DialogResult.OK)
|
if (!string.IsNullOrEmpty(json))
|
||||||
return;
|
{
|
||||||
|
try { plate.CuttingParameters = CuttingParametersSerializer.Deserialize(json); }
|
||||||
plate.CuttingParameters = form.BuildParameters();
|
catch { plate.CuttingParameters = new CuttingParameters(); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plate.CuttingParameters = new CuttingParameters();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlateView.SetAction(typeof(Actions.ActionLeadIn));
|
PlateView.SetAction(typeof(Actions.ActionLeadIn));
|
||||||
|
|||||||
Reference in New Issue
Block a user