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)
|
||||
{
|
||||
var entries = new ContourEntry[cutouts.Count];
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
|
||||
public double PierceClearance { get; set; } = 0.0625;
|
||||
|
||||
public double AutoTabMinSize { get; set; }
|
||||
public double AutoTabMaxSize { get; set; }
|
||||
|
||||
public Tab TabConfig { get; set; }
|
||||
public bool TabsEnabled { get; set; }
|
||||
|
||||
|
||||
@@ -72,6 +72,18 @@ namespace OpenNest
|
||||
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()
|
||||
{
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
private static Drawing ImportDxf()
|
||||
private static Drawing? ImportDxf()
|
||||
{
|
||||
if (!System.IO.File.Exists(DxfPath))
|
||||
return null;
|
||||
|
||||
var importer = new DxfImporter();
|
||||
importer.GetGeometry(DxfPath, out var geometry);
|
||||
var pgm = ConvertGeometry.ToProgram(geometry);
|
||||
@@ -31,6 +34,9 @@ public class EngineOverlapTests
|
||||
public void FillPlate_NoOverlaps(string engineName)
|
||||
{
|
||||
var drawing = ImportDxf();
|
||||
if (drawing is null)
|
||||
return; // Skip if test DXF not available
|
||||
|
||||
var plate = new Plate(60, 120);
|
||||
|
||||
NestEngineRegistry.ActiveEngineName = engineName;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<ProjectReference Include="..\OpenNest.Engine\OpenNest.Engine.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.IO\OpenNest.IO.csproj" />
|
||||
<ProjectReference Include="..\OpenNest.Posts.Cincinnati\OpenNest.Posts.Cincinnati.csproj" />
|
||||
<ProjectReference Include="..\OpenNest\OpenNest.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -18,8 +18,11 @@ public class StrategyOverlapTests
|
||||
_output = output;
|
||||
}
|
||||
|
||||
private static Drawing ImportDxf()
|
||||
private static Drawing? ImportDxf()
|
||||
{
|
||||
if (!System.IO.File.Exists(DxfPath))
|
||||
return null;
|
||||
|
||||
var importer = new DxfImporter();
|
||||
importer.GetGeometry(DxfPath, out var geometry);
|
||||
var pgm = ConvertGeometry.ToProgram(geometry);
|
||||
@@ -30,6 +33,9 @@ public class StrategyOverlapTests
|
||||
public void EachStrategy_CheckOverlaps()
|
||||
{
|
||||
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}");
|
||||
|
||||
var strategies = FillStrategyRegistry.Strategies.ToList();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Controls;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Forms;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
using System.Collections.Generic;
|
||||
@@ -30,9 +31,12 @@ namespace OpenNest.Actions
|
||||
private bool hasSnap;
|
||||
private SnapType activeSnapType;
|
||||
private ShapeInfo hoveredContour;
|
||||
private ShapeInfo lockedContour;
|
||||
private ContextMenuStrip contextMenu;
|
||||
private CuttingPanel cuttingPanel;
|
||||
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 lockedPen = new Pen(Color.Yellow, 3.0f);
|
||||
|
||||
public ActionLeadIn(PlateView plateView)
|
||||
: base(plateView)
|
||||
@@ -46,6 +50,7 @@ namespace OpenNest.Actions
|
||||
plateView.MouseDown += OnMouseDown;
|
||||
plateView.KeyDown += OnKeyDown;
|
||||
plateView.Paint += OnPaint;
|
||||
ShowSidePanel();
|
||||
}
|
||||
|
||||
public override void DisconnectEvents()
|
||||
@@ -55,6 +60,8 @@ namespace OpenNest.Actions
|
||||
plateView.KeyDown -= OnKeyDown;
|
||||
plateView.Paint -= OnPaint;
|
||||
|
||||
HideSidePanel();
|
||||
|
||||
contextMenu?.Dispose();
|
||||
contextMenu = null;
|
||||
|
||||
@@ -72,6 +79,77 @@ namespace OpenNest.Actions
|
||||
|
||||
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)
|
||||
{
|
||||
if (selectedPart == null || contours == null)
|
||||
@@ -91,7 +169,12 @@ namespace OpenNest.Actions
|
||||
activeSnapType = SnapType.None;
|
||||
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 dist = closest.DistanceTo(localPt);
|
||||
@@ -110,8 +193,14 @@ namespace OpenNest.Actions
|
||||
|
||||
// Check endpoint/midpoint snaps on the hovered contour
|
||||
if (hoveredContour != null)
|
||||
{
|
||||
TrySnapToEntityPoints(localPt);
|
||||
|
||||
// Auto-switch tool window tab only when no contour is locked
|
||||
if (cuttingPanel != null && lockedContour == null)
|
||||
cuttingPanel.ActiveContourType = snapContourType;
|
||||
}
|
||||
|
||||
plateView.Invalidate();
|
||||
}
|
||||
|
||||
@@ -124,15 +213,22 @@ namespace OpenNest.Actions
|
||||
// First click: select a part
|
||||
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();
|
||||
}
|
||||
}
|
||||
else if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
if (selectedPart != null && selectedPart.HasManualLeadIns)
|
||||
if (lockedContour != null)
|
||||
UnlockContour();
|
||||
else if (selectedPart != null && selectedPart.HasManualLeadIns)
|
||||
ShowContextMenu(e.Location);
|
||||
else
|
||||
DeselectPart();
|
||||
@@ -143,7 +239,9 @@ namespace OpenNest.Actions
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape)
|
||||
{
|
||||
if (selectedPart != null)
|
||||
if (lockedContour != null)
|
||||
UnlockContour();
|
||||
else if (selectedPart != null)
|
||||
DeselectPart();
|
||||
else
|
||||
plateView.SetAction(typeof(ActionSelect));
|
||||
@@ -159,6 +257,23 @@ namespace OpenNest.Actions
|
||||
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)
|
||||
{
|
||||
foreach (var lp in plateView.LayoutParts)
|
||||
@@ -170,10 +285,24 @@ namespace OpenNest.Actions
|
||||
|
||||
private void DrawHoveredContour(Graphics g)
|
||||
{
|
||||
if (hoveredContour == null || selectedPart == null)
|
||||
if (selectedPart == null)
|
||||
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();
|
||||
contourMatrix.Translate((float)selectedPart.Location.X, (float)selectedPart.Location.Y);
|
||||
contourMatrix.Multiply(plateView.Matrix, MatrixOrder.Append);
|
||||
@@ -181,7 +310,7 @@ namespace OpenNest.Actions
|
||||
|
||||
var prevSmooth = g.SmoothingMode;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.DrawPath(highlightPen, contourPath);
|
||||
g.DrawPath(pen, contourPath);
|
||||
g.SmoothingMode = prevSmooth;
|
||||
}
|
||||
|
||||
@@ -190,9 +319,7 @@ namespace OpenNest.Actions
|
||||
if (!hasSnap || selectedPart == null)
|
||||
return;
|
||||
|
||||
var parameters = plateView.Plate?.CuttingParameters;
|
||||
if (parameters == null)
|
||||
return;
|
||||
var parameters = GetCurrentParameters();
|
||||
|
||||
var leadIn = SelectLeadIn(parameters, snapContourType);
|
||||
if (leadIn == null)
|
||||
@@ -375,29 +502,53 @@ namespace OpenNest.Actions
|
||||
|
||||
private void CommitLeadIn()
|
||||
{
|
||||
var parameters = plateView.Plate?.CuttingParameters;
|
||||
if (parameters == null)
|
||||
return;
|
||||
var parameters = GetCurrentParameters();
|
||||
|
||||
// Remove any existing lead-ins first
|
||||
if (selectedPart.HasManualLeadIns)
|
||||
selectedPart.RemoveLeadIns();
|
||||
|
||||
// Apply lead-ins using the snap point as the approach point.
|
||||
// snapPoint is in the program's local coordinate space (rotated, not offset),
|
||||
// which is what Part.ApplyLeadIns expects.
|
||||
selectedPart.ApplyLeadIns(parameters, snapPoint);
|
||||
ApplyAutoTab(parameters);
|
||||
|
||||
selectedPart.ApplySingleLeadIn(parameters, snapPoint, snapEntity, snapContourType);
|
||||
selectedPart.LeadInsLocked = true;
|
||||
|
||||
// Rebuild the layout part's graphics
|
||||
selectedLayoutPart.IsDirty = true;
|
||||
selectedLayoutPart.Update();
|
||||
|
||||
// Deselect and reset
|
||||
DeselectPart();
|
||||
UnlockContour();
|
||||
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()
|
||||
{
|
||||
if (selectedLayoutPart != null)
|
||||
@@ -409,6 +560,7 @@ namespace OpenNest.Actions
|
||||
selectedPart = null;
|
||||
profile = null;
|
||||
contours = null;
|
||||
lockedContour = null;
|
||||
hasSnap = false;
|
||||
activeSnapType = SnapType.None;
|
||||
hoveredContour = null;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenNest.Forms
|
||||
namespace OpenNest.Controls
|
||||
{
|
||||
public partial class CuttingParametersForm : Form
|
||||
public class CuttingPanel : Panel
|
||||
{
|
||||
private static readonly string[] LeadInTypes =
|
||||
{ "None", "Line", "Arc", "Line + Arc", "Clean Hole", "Line + Line" };
|
||||
@@ -12,85 +13,241 @@ namespace OpenNest.Forms
|
||||
private static readonly string[] LeadOutTypes =
|
||||
{ "None", "Line", "Arc", "Microtab" };
|
||||
|
||||
private ComboBox cboExternalLeadIn, cboExternalLeadOut;
|
||||
private ComboBox cboInternalLeadIn, cboInternalLeadOut;
|
||||
private ComboBox cboArcCircleLeadIn, cboArcCircleLeadOut;
|
||||
private readonly TabControl tabControl;
|
||||
private readonly ComboBox cboExternalLeadIn, cboExternalLeadOut;
|
||||
private readonly ComboBox cboInternalLeadIn, cboInternalLeadOut;
|
||||
private readonly ComboBox cboArcCircleLeadIn, cboArcCircleLeadOut;
|
||||
|
||||
private Panel pnlExternalLeadIn, pnlExternalLeadOut;
|
||||
private Panel pnlInternalLeadIn, pnlInternalLeadOut;
|
||||
private Panel pnlArcCircleLeadIn, pnlArcCircleLeadOut;
|
||||
private readonly Panel pnlExternalLeadIn, pnlExternalLeadOut;
|
||||
private readonly Panel pnlInternalLeadIn, pnlInternalLeadOut;
|
||||
private readonly Panel pnlArcCircleLeadIn, pnlArcCircleLeadOut;
|
||||
|
||||
private CheckBox chkTabsEnabled;
|
||||
private NumericUpDown nudTabWidth;
|
||||
private NumericUpDown nudPierceClearance;
|
||||
private readonly CheckBox chkTabsEnabled;
|
||||
private readonly NumericUpDown nudTabWidth;
|
||||
private readonly NumericUpDown nudAutoTabMin;
|
||||
private readonly NumericUpDown nudAutoTabMax;
|
||||
private readonly NumericUpDown nudPierceClearance;
|
||||
|
||||
private bool hasCustomParameters;
|
||||
private CuttingParameters parameters = new CuttingParameters();
|
||||
private readonly Button btnAutoAssign;
|
||||
|
||||
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
|
||||
{
|
||||
parameters = value;
|
||||
hasCustomParameters = true;
|
||||
}
|
||||
}
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
public CuttingParametersForm()
|
||||
var index = value.Value switch
|
||||
{
|
||||
InitializeComponent();
|
||||
ContourType.External => 0,
|
||||
ContourType.Internal => 1,
|
||||
ContourType.ArcCircle => 2,
|
||||
_ => -1
|
||||
};
|
||||
|
||||
SetupTab(tabExternal,
|
||||
out cboExternalLeadIn, out pnlExternalLeadIn,
|
||||
if (index >= 0 && tabControl.SelectedIndex != index)
|
||||
tabControl.SelectedIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
public CuttingPanel()
|
||||
{
|
||||
AutoScroll = true;
|
||||
BackColor = Color.White;
|
||||
|
||||
// Tab control for contour types — wrapped in a fixed-height panel for Dock.Top
|
||||
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);
|
||||
SetupTab(tabInternal,
|
||||
out cboInternalLeadIn, out pnlInternalLeadIn,
|
||||
SetupTab(tabInternal, out cboInternalLeadIn, out pnlInternalLeadIn,
|
||||
out cboInternalLeadOut, out pnlInternalLeadOut);
|
||||
SetupTab(tabArcCircle,
|
||||
out cboArcCircleLeadIn, out pnlArcCircleLeadIn,
|
||||
SetupTab(tabArcCircle, out cboArcCircleLeadIn, out pnlArcCircleLeadIn,
|
||||
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();
|
||||
|
||||
cboExternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
||||
cboInternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
||||
cboArcCircleLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
||||
|
||||
cboExternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
||||
cboInternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
||||
cboArcCircleLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
||||
WireChangeEvents();
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
public CuttingParameters BuildParameters()
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
// If caller didn't provide custom parameters, try loading saved ones
|
||||
if (!hasCustomParameters)
|
||||
return new CuttingParameters
|
||||
{
|
||||
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
try { Parameters = CuttingParametersSerializer.Deserialize(json); }
|
||||
catch { /* use defaults on corrupt data */ }
|
||||
}
|
||||
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,
|
||||
AutoTabMinSize = (double)nudAutoTabMin.Value,
|
||||
AutoTabMaxSize = (double)nudAutoTabMax.Value
|
||||
};
|
||||
}
|
||||
|
||||
LoadFromParameters(Parameters);
|
||||
public void LoadFromParameters(CuttingParameters p)
|
||||
{
|
||||
suppressEvents = true;
|
||||
|
||||
LoadLeadIn(cboExternalLeadIn, pnlExternalLeadIn, p.ExternalLeadIn);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
private void OnParametersChanged()
|
||||
{
|
||||
base.OnFormClosing(e);
|
||||
|
||||
if (DialogResult == System.Windows.Forms.DialogResult.OK)
|
||||
{
|
||||
var json = CuttingParametersSerializer.Serialize(BuildParameters());
|
||||
Properties.Settings.Default.CuttingParametersJson = json;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
if (!suppressEvents)
|
||||
ParametersChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private static void SetupTab(TabPage tab,
|
||||
@@ -100,30 +257,30 @@ namespace OpenNest.Forms
|
||||
var grpLeadIn = new GroupBox
|
||||
{
|
||||
Text = "Lead-In",
|
||||
Location = new System.Drawing.Point(4, 4),
|
||||
Size = new System.Drawing.Size(364, 168)
|
||||
Location = new Point(4, 4),
|
||||
Size = new Size(340, 148)
|
||||
};
|
||||
tab.Controls.Add(grpLeadIn);
|
||||
|
||||
grpLeadIn.Controls.Add(new Label
|
||||
{
|
||||
Text = "Type:",
|
||||
Location = new System.Drawing.Point(8, 22),
|
||||
Location = new Point(8, 22),
|
||||
AutoSize = true
|
||||
});
|
||||
|
||||
leadInCombo = new ComboBox
|
||||
{
|
||||
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||
Location = new System.Drawing.Point(90, 19),
|
||||
Size = new System.Drawing.Size(250, 24)
|
||||
Location = new Point(90, 19),
|
||||
Size = new Size(230, 24)
|
||||
};
|
||||
grpLeadIn.Controls.Add(leadInCombo);
|
||||
|
||||
leadInPanel = new Panel
|
||||
{
|
||||
Location = new System.Drawing.Point(8, 48),
|
||||
Size = new System.Drawing.Size(340, 112),
|
||||
Location = new Point(8, 48),
|
||||
Size = new Size(320, 92),
|
||||
AutoScroll = true
|
||||
};
|
||||
grpLeadIn.Controls.Add(leadInPanel);
|
||||
@@ -131,106 +288,35 @@ namespace OpenNest.Forms
|
||||
var grpLeadOut = new GroupBox
|
||||
{
|
||||
Text = "Lead-Out",
|
||||
Location = new System.Drawing.Point(4, 176),
|
||||
Size = new System.Drawing.Size(364, 132)
|
||||
Location = new Point(4, 156),
|
||||
Size = new Size(340, 132)
|
||||
};
|
||||
tab.Controls.Add(grpLeadOut);
|
||||
|
||||
grpLeadOut.Controls.Add(new Label
|
||||
{
|
||||
Text = "Type:",
|
||||
Location = new System.Drawing.Point(8, 22),
|
||||
Location = new Point(8, 22),
|
||||
AutoSize = true
|
||||
});
|
||||
|
||||
leadOutCombo = new ComboBox
|
||||
{
|
||||
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||
Location = new System.Drawing.Point(90, 19),
|
||||
Size = new System.Drawing.Size(250, 24)
|
||||
Location = new Point(90, 19),
|
||||
Size = new Size(230, 24)
|
||||
};
|
||||
grpLeadOut.Controls.Add(leadOutCombo);
|
||||
|
||||
leadOutPanel = new Panel
|
||||
{
|
||||
Location = new System.Drawing.Point(8, 48),
|
||||
Size = new System.Drawing.Size(340, 76),
|
||||
Location = new Point(8, 48),
|
||||
Size = new Size(320, 76),
|
||||
AutoScroll = true
|
||||
};
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
var combo = (ComboBox)sender;
|
||||
var panel = GetLeadInPanel(combo);
|
||||
if (panel != null)
|
||||
BuildLeadInParamControls(panel, combo.SelectedIndex);
|
||||
OnParametersChanged();
|
||||
}
|
||||
|
||||
private void OnLeadOutTypeChanged(object sender, EventArgs e)
|
||||
@@ -260,6 +358,7 @@ namespace OpenNest.Forms
|
||||
var panel = GetLeadOutPanel(combo);
|
||||
if (panel != null)
|
||||
BuildLeadOutParamControls(panel, combo.SelectedIndex);
|
||||
OnParametersChanged();
|
||||
}
|
||||
|
||||
private Panel GetLeadInPanel(ComboBox combo)
|
||||
@@ -278,31 +377,31 @@ namespace OpenNest.Forms
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void BuildLeadInParamControls(Panel panel, int typeIndex)
|
||||
private void BuildLeadInParamControls(Panel panel, int typeIndex)
|
||||
{
|
||||
panel.Controls.Clear();
|
||||
var y = 0;
|
||||
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 1: // Line
|
||||
case 1:
|
||||
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
||||
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
||||
break;
|
||||
case 2: // Arc
|
||||
case 2:
|
||||
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
||||
break;
|
||||
case 3: // Line + Arc
|
||||
case 3:
|
||||
AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength");
|
||||
AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius");
|
||||
AddNumericField(panel, "Approach Angle:", 135, ref y, "ApproachAngle");
|
||||
break;
|
||||
case 4: // Clean Hole
|
||||
case 4:
|
||||
AddNumericField(panel, "Line Length:", 0.25, ref y, "LineLength");
|
||||
AddNumericField(panel, "Arc Radius:", 0.125, ref y, "ArcRadius");
|
||||
AddNumericField(panel, "Kerf:", 0.06, ref y, "Kerf");
|
||||
break;
|
||||
case 5: // Line + Line
|
||||
case 5:
|
||||
AddNumericField(panel, "Length 1:", 0.25, ref y, "Length1");
|
||||
AddNumericField(panel, "Angle 1:", 90, ref y, "Angle1");
|
||||
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();
|
||||
var y = 0;
|
||||
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 1: // Line
|
||||
case 1:
|
||||
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
||||
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
||||
break;
|
||||
case 2: // Arc
|
||||
case 2:
|
||||
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
||||
break;
|
||||
case 3: // Microtab
|
||||
case 3:
|
||||
AddNumericField(panel, "Gap Size:", 0.06, ref y, "GapSize");
|
||||
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)
|
||||
{
|
||||
panel.Controls.Add(new Label
|
||||
{
|
||||
Text = label,
|
||||
Location = new System.Drawing.Point(0, y + 3),
|
||||
Location = new Point(0, y + 3),
|
||||
AutoSize = true
|
||||
});
|
||||
|
||||
panel.Controls.Add(new NumericUpDown
|
||||
{
|
||||
Location = new System.Drawing.Point(130, y),
|
||||
Size = new System.Drawing.Size(120, 22),
|
||||
DecimalPlaces = 4,
|
||||
Increment = 0.0625m,
|
||||
Minimum = 0,
|
||||
Maximum = 9999,
|
||||
Value = (decimal)defaultValue,
|
||||
Tag = tag
|
||||
});
|
||||
var nud = CreateNumeric(130, y, defaultValue, 0.0625);
|
||||
nud.Tag = tag;
|
||||
nud.ValueChanged += (s, e) => OnParametersChanged();
|
||||
panel.Controls.Add(nud);
|
||||
|
||||
y += 30;
|
||||
}
|
||||
|
||||
private void LoadFromParameters(CuttingParameters p)
|
||||
private static NumericUpDown CreateNumeric(int x, int y, double defaultValue, double increment)
|
||||
{
|
||||
LoadLeadIn(cboExternalLeadIn, pnlExternalLeadIn, p.ExternalLeadIn);
|
||||
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;
|
||||
if (p.TabConfig != null)
|
||||
nudTabWidth.Value = (decimal)p.TabConfig.Size;
|
||||
|
||||
nudPierceClearance.Value = (decimal)p.PierceClearance;
|
||||
return new NumericUpDown
|
||||
{
|
||||
Location = new Point(x, y),
|
||||
Size = new Size(120, 22),
|
||||
DecimalPlaces = 4,
|
||||
Increment = (decimal)increment,
|
||||
Minimum = 0,
|
||||
Maximum = 9999,
|
||||
Value = (decimal)defaultValue
|
||||
};
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch (combo.SelectedIndex)
|
||||
return combo.SelectedIndex switch
|
||||
{
|
||||
case 1:
|
||||
return new LineLeadIn
|
||||
1 => new LineLeadIn
|
||||
{
|
||||
Length = GetParam(panel, "Length", 0.25),
|
||||
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
||||
};
|
||||
case 2:
|
||||
return new ArcLeadIn
|
||||
},
|
||||
2 => new ArcLeadIn
|
||||
{
|
||||
Radius = GetParam(panel, "Radius", 0.25)
|
||||
};
|
||||
case 3:
|
||||
return new LineArcLeadIn
|
||||
},
|
||||
3 => new LineArcLeadIn
|
||||
{
|
||||
LineLength = GetParam(panel, "LineLength", 0.25),
|
||||
ArcRadius = GetParam(panel, "ArcRadius", 0.125),
|
||||
ApproachAngle = GetParam(panel, "ApproachAngle", 135)
|
||||
};
|
||||
case 4:
|
||||
return new CleanHoleLeadIn
|
||||
},
|
||||
4 => new CleanHoleLeadIn
|
||||
{
|
||||
LineLength = GetParam(panel, "LineLength", 0.25),
|
||||
ArcRadius = GetParam(panel, "ArcRadius", 0.125),
|
||||
Kerf = GetParam(panel, "Kerf", 0.06)
|
||||
};
|
||||
case 5:
|
||||
return new LineLineLeadIn
|
||||
},
|
||||
5 => new LineLineLeadIn
|
||||
{
|
||||
Length1 = GetParam(panel, "Length1", 0.25),
|
||||
ApproachAngle1 = GetParam(panel, "Angle1", 90),
|
||||
Length2 = GetParam(panel, "Length2", 0.25),
|
||||
ApproachAngle2 = GetParam(panel, "Angle2", 90)
|
||||
},
|
||||
_ => new NoLeadIn()
|
||||
};
|
||||
default:
|
||||
return new NoLeadIn();
|
||||
}
|
||||
}
|
||||
|
||||
private static LeadOut BuildLeadOut(ComboBox combo, Panel panel)
|
||||
{
|
||||
switch (combo.SelectedIndex)
|
||||
return combo.SelectedIndex switch
|
||||
{
|
||||
case 1:
|
||||
return new LineLeadOut
|
||||
1 => new LineLeadOut
|
||||
{
|
||||
Length = GetParam(panel, "Length", 0.25),
|
||||
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
||||
};
|
||||
case 2:
|
||||
return new ArcLeadOut
|
||||
},
|
||||
2 => new ArcLeadOut
|
||||
{
|
||||
Radius = GetParam(panel, "Radius", 0.25)
|
||||
};
|
||||
case 3:
|
||||
return new MicrotabLeadOut
|
||||
},
|
||||
3 => new MicrotabLeadOut
|
||||
{
|
||||
GapSize = GetParam(panel, "GapSize", 0.06)
|
||||
},
|
||||
_ => new NoLeadOut()
|
||||
};
|
||||
default:
|
||||
return new NoLeadOut();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
internal static class CuttingParametersSerializer
|
||||
public static class CuttingParametersSerializer
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
@@ -23,7 +23,9 @@ namespace OpenNest.Forms
|
||||
ArcCircleLeadOut = ToLeadOutDto(p.ArcCircleLeadOut),
|
||||
TabsEnabled = p.TabsEnabled,
|
||||
TabWidth = p.TabConfig?.Size ?? 0.25,
|
||||
PierceClearance = p.PierceClearance
|
||||
PierceClearance = p.PierceClearance,
|
||||
AutoTabMinSize = p.AutoTabMinSize,
|
||||
AutoTabMaxSize = p.AutoTabMaxSize
|
||||
};
|
||||
return JsonSerializer.Serialize(dto, JsonOptions);
|
||||
}
|
||||
@@ -44,7 +46,9 @@ namespace OpenNest.Forms
|
||||
ArcCircleLeadOut = FromLeadOutDto(dto.ArcCircleLeadOut),
|
||||
TabsEnabled = dto.TabsEnabled,
|
||||
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 double TabWidth { get; set; }
|
||||
public double PierceClearance { get; set; }
|
||||
public double AutoTabMinSize { get; set; }
|
||||
public double AutoTabMaxSize { get; set; }
|
||||
}
|
||||
|
||||
private class LeadInDto
|
||||
|
||||
@@ -37,6 +37,9 @@ namespace OpenNest.Forms
|
||||
private Button btnNextPlate;
|
||||
private Button btnLastPlate;
|
||||
|
||||
private SplitContainer viewSplitContainer;
|
||||
private Panel sidePanel;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
@@ -53,8 +56,9 @@ namespace OpenNest.Forms
|
||||
|
||||
InitializeComponent();
|
||||
CreatePlateHeader();
|
||||
CreateSidePanel();
|
||||
|
||||
splitContainer.Panel2.Controls.Add(PlateView);
|
||||
splitContainer.Panel2.Controls.Add(viewSplitContainer);
|
||||
splitContainer.Panel2.Controls.Add(plateHeaderPanel);
|
||||
|
||||
var renderer = new ToolStripRenderer(ToolbarTheme.Toolbar);
|
||||
@@ -146,6 +150,43 @@ namespace OpenNest.Forms
|
||||
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)
|
||||
{
|
||||
return new Button
|
||||
@@ -725,15 +766,19 @@ namespace OpenNest.Forms
|
||||
|
||||
var plate = PlateView.Plate;
|
||||
|
||||
using var form = new CuttingParametersForm();
|
||||
if (plate.CuttingParameters != null)
|
||||
form.Parameters = plate.CuttingParameters;
|
||||
|
||||
if (form.ShowDialog(this) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var parameters = form.BuildParameters();
|
||||
plate.CuttingParameters = parameters;
|
||||
if (plate.CuttingParameters == null)
|
||||
{
|
||||
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
try { plate.CuttingParameters = CuttingParametersSerializer.Deserialize(json); }
|
||||
catch { plate.CuttingParameters = new CuttingParameters(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
plate.CuttingParameters = new CuttingParameters();
|
||||
}
|
||||
}
|
||||
|
||||
var assigner = new LeadInAssigner
|
||||
{
|
||||
@@ -784,11 +829,18 @@ namespace OpenNest.Forms
|
||||
if (Nest == null)
|
||||
return;
|
||||
|
||||
using var form = new CuttingParametersForm();
|
||||
if (form.ShowDialog(this) != DialogResult.OK)
|
||||
return;
|
||||
CuttingParameters parameters;
|
||||
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||
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
|
||||
{
|
||||
Sequencer = new LeftSideSequencer()
|
||||
@@ -835,14 +887,19 @@ namespace OpenNest.Forms
|
||||
|
||||
var plate = PlateView.Plate;
|
||||
|
||||
// Ensure cutting parameters are configured
|
||||
// If no cutting parameters exist, initialize from saved settings or defaults
|
||||
if (plate.CuttingParameters == null)
|
||||
{
|
||||
using var form = new CuttingParametersForm();
|
||||
if (form.ShowDialog(this) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
plate.CuttingParameters = form.BuildParameters();
|
||||
var json = Properties.Settings.Default.CuttingParametersJson;
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
try { plate.CuttingParameters = CuttingParametersSerializer.Deserialize(json); }
|
||||
catch { plate.CuttingParameters = new CuttingParameters(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
plate.CuttingParameters = new CuttingParameters();
|
||||
}
|
||||
}
|
||||
|
||||
PlateView.SetAction(typeof(Actions.ActionLeadIn));
|
||||
|
||||
Reference in New Issue
Block a user