Compare commits
12 Commits
3d4204db7b
...
d16ef36d34
| Author | SHA1 | Date | |
|---|---|---|---|
| d16ef36d34 | |||
| 5307c5c85a | |||
| 21321740d6 | |||
| 7f8c708d3f | |||
| ab4f806820 | |||
| c9b5ee1918 | |||
| f34dce95da | |||
| a2a19938d3 | |||
| c064c7647a | |||
| 8a712b9755 | |||
| 82de512f44 | |||
| f903cbe18a |
@@ -65,7 +65,8 @@ namespace OpenNest.CNC
|
||||
{
|
||||
return new ArcMove(EndPoint, CenterPoint, Rotation)
|
||||
{
|
||||
Layer = Layer
|
||||
Layer = Layer,
|
||||
Suppressed = Suppressed
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
result.Codes.AddRange(leadOut.Generate(perimeterPt, normal, winding));
|
||||
}
|
||||
|
||||
// Convert to incremental mode to match the convention used by
|
||||
// the rest of the system (rendering, bounding box, drag, etc.).
|
||||
result.Mode = Mode.Incremental;
|
||||
|
||||
return new CuttingResult
|
||||
{
|
||||
Program = result,
|
||||
@@ -102,7 +106,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return ordered;
|
||||
}
|
||||
|
||||
private ContourType DetectContourType(Shape cutout)
|
||||
public static ContourType DetectContourType(Shape cutout)
|
||||
{
|
||||
if (cutout.Entities.Count == 1 && cutout.Entities[0] is Circle)
|
||||
return ContourType.ArcCircle;
|
||||
@@ -110,7 +114,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return ContourType.Internal;
|
||||
}
|
||||
|
||||
private double ComputeNormal(Vector point, Entity entity, ContourType contourType)
|
||||
public static double ComputeNormal(Vector point, Entity entity, ContourType contourType)
|
||||
{
|
||||
double normal;
|
||||
|
||||
@@ -141,7 +145,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return Math.Angle.NormalizeRad(normal);
|
||||
}
|
||||
|
||||
private RotationType DetermineWinding(Shape shape)
|
||||
public static RotationType DetermineWinding(Shape shape)
|
||||
{
|
||||
// Use signed area: positive = CCW, negative = CW
|
||||
var area = shape.Area();
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return new List<ICode>
|
||||
{
|
||||
new RapidMove(piercePoint),
|
||||
new ArcMove(contourStartPoint, arcCenter, winding)
|
||||
new ArcMove(contourStartPoint, arcCenter, winding) { Layer = LayerType.Leadin }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return new List<ICode>
|
||||
{
|
||||
new RapidMove(piercePoint),
|
||||
new LinearMove(arcStart),
|
||||
new ArcMove(contourStartPoint, arcCenter, winding)
|
||||
new LinearMove(arcStart) { Layer = LayerType.Leadin },
|
||||
new ArcMove(contourStartPoint, arcCenter, winding) { Layer = LayerType.Leadin }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return new List<ICode>
|
||||
{
|
||||
new RapidMove(piercePoint),
|
||||
new LinearMove(arcStart),
|
||||
new ArcMove(contourStartPoint, arcCenter, winding)
|
||||
new LinearMove(arcStart) { Layer = LayerType.Leadin },
|
||||
new ArcMove(contourStartPoint, arcCenter, winding) { Layer = LayerType.Leadin }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return new List<ICode>
|
||||
{
|
||||
new RapidMove(piercePoint),
|
||||
new LinearMove(contourStartPoint)
|
||||
new LinearMove(contourStartPoint) { Layer = LayerType.Leadin }
|
||||
};
|
||||
}
|
||||
|
||||
public override Vector GetPiercePoint(Vector contourStartPoint, double contourNormalAngle)
|
||||
{
|
||||
var approachAngle = contourNormalAngle + Angle.ToRadians(ApproachAngle);
|
||||
var approachAngle = contourNormalAngle + Angle.HalfPI - Angle.ToRadians(ApproachAngle);
|
||||
return new Vector(
|
||||
contourStartPoint.X + Length * System.Math.Cos(approachAngle),
|
||||
contourStartPoint.Y + Length * System.Math.Sin(approachAngle));
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
{
|
||||
var piercePoint = GetPiercePoint(contourStartPoint, contourNormalAngle);
|
||||
|
||||
var secondAngle = contourNormalAngle + Angle.ToRadians(ApproachAngle1);
|
||||
var secondAngle = contourNormalAngle + Angle.HalfPI - Angle.ToRadians(ApproachAngle1);
|
||||
var midPoint = new Vector(
|
||||
contourStartPoint.X + Length2 * System.Math.Cos(secondAngle),
|
||||
contourStartPoint.Y + Length2 * System.Math.Sin(secondAngle));
|
||||
@@ -24,14 +24,14 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
return new List<ICode>
|
||||
{
|
||||
new RapidMove(piercePoint),
|
||||
new LinearMove(midPoint),
|
||||
new LinearMove(contourStartPoint)
|
||||
new LinearMove(midPoint) { Layer = LayerType.Leadin },
|
||||
new LinearMove(contourStartPoint) { Layer = LayerType.Leadin }
|
||||
};
|
||||
}
|
||||
|
||||
public override Vector GetPiercePoint(Vector contourStartPoint, double contourNormalAngle)
|
||||
{
|
||||
var secondAngle = contourNormalAngle + Angle.ToRadians(ApproachAngle1);
|
||||
var secondAngle = contourNormalAngle + Angle.HalfPI - Angle.ToRadians(ApproachAngle1);
|
||||
var midX = contourStartPoint.X + Length2 * System.Math.Cos(secondAngle);
|
||||
var midY = contourStartPoint.Y + Length2 * System.Math.Sin(secondAngle);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
|
||||
return new List<ICode>
|
||||
{
|
||||
new ArcMove(endPoint, arcCenter, winding)
|
||||
new ArcMove(endPoint, arcCenter, winding) { Layer = LayerType.Leadout }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,14 +12,14 @@ namespace OpenNest.CNC.CuttingStrategy
|
||||
public override List<ICode> Generate(Vector contourEndPoint, double contourNormalAngle,
|
||||
RotationType winding = RotationType.CW)
|
||||
{
|
||||
var overcutAngle = contourNormalAngle + Angle.ToRadians(ApproachAngle);
|
||||
var overcutAngle = contourNormalAngle + Angle.HalfPI - Angle.ToRadians(ApproachAngle);
|
||||
var endPoint = new Vector(
|
||||
contourEndPoint.X + Length * System.Math.Cos(overcutAngle),
|
||||
contourEndPoint.Y + Length * System.Math.Sin(overcutAngle));
|
||||
|
||||
return new List<ICode>
|
||||
{
|
||||
new LinearMove(endPoint)
|
||||
new LinearMove(endPoint) { Layer = LayerType.Leadout }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ namespace OpenNest.CNC
|
||||
{
|
||||
return new LinearMove(EndPoint)
|
||||
{
|
||||
Layer = Layer
|
||||
Layer = Layer,
|
||||
Suppressed = Suppressed
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace OpenNest.CNC
|
||||
|
||||
public int Feedrate { get; set; }
|
||||
|
||||
public bool Suppressed { get; set; }
|
||||
|
||||
protected Motion()
|
||||
{
|
||||
Feedrate = CNC.Feedrate.UseDefault;
|
||||
|
||||
@@ -26,7 +26,10 @@ namespace OpenNest.CNC
|
||||
|
||||
public override ICode Clone()
|
||||
{
|
||||
return new RapidMove(EndPoint);
|
||||
return new RapidMove(EndPoint)
|
||||
{
|
||||
Suppressed = Suppressed
|
||||
};
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace OpenNest
|
||||
{
|
||||
private Vector location;
|
||||
private bool ownsProgram;
|
||||
private double preLeadInRotation;
|
||||
|
||||
public readonly Drawing BaseDrawing;
|
||||
|
||||
@@ -56,6 +57,38 @@ namespace OpenNest
|
||||
|
||||
public bool HasManualLeadIns { get; set; }
|
||||
|
||||
public bool LeadInsLocked { get; set; }
|
||||
|
||||
public CNC.CuttingStrategy.CuttingParameters CuttingParameters { get; set; }
|
||||
|
||||
public void ApplyLeadIns(CNC.CuttingStrategy.CuttingParameters parameters, Vector approachPoint)
|
||||
{
|
||||
preLeadInRotation = Rotation;
|
||||
var strategy = new CNC.CuttingStrategy.ContourCuttingStrategy { Parameters = parameters };
|
||||
var result = strategy.Apply(Program, approachPoint);
|
||||
Program = result.Program;
|
||||
CuttingParameters = parameters;
|
||||
HasManualLeadIns = true;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
public void RemoveLeadIns()
|
||||
{
|
||||
var rotation = preLeadInRotation;
|
||||
var location = Location;
|
||||
Program = BaseDrawing.Program.Clone() as Program;
|
||||
ownsProgram = true;
|
||||
|
||||
if (!Math.Tolerance.IsEqualTo(rotation, 0))
|
||||
Program.Rotate(rotation);
|
||||
|
||||
Location = location;
|
||||
HasManualLeadIns = false;
|
||||
LeadInsLocked = false;
|
||||
CuttingParameters = null;
|
||||
UpdateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation of the part in radians.
|
||||
/// </summary>
|
||||
|
||||
@@ -88,6 +88,8 @@ namespace OpenNest
|
||||
/// </summary>
|
||||
public Material Material { get; set; }
|
||||
|
||||
public CNC.CuttingStrategy.CuttingParameters CuttingParameters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Material grain direction in radians. 0 = horizontal.
|
||||
/// </summary>
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace OpenNest
|
||||
|
||||
public static readonly Layer Display = new Layer("DISPLAY") { Color = Color.Cyan };
|
||||
|
||||
public static readonly Layer Leadin = new Layer("LEADIN") { Color = Color.Yellow };
|
||||
public static readonly Layer Leadin = new Layer("LEADIN") { Color = Color.Brown };
|
||||
|
||||
public static readonly Layer Leadout = new Layer("LEADOUT") { Color = Color.Yellow };
|
||||
public static readonly Layer Leadout = new Layer("LEADOUT") { Color = Color.Brown };
|
||||
|
||||
public static readonly Layer Scribe = new Layer("SCRIBE") { Color = Color.Magenta };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using OpenNest.Engine.Sequencing;
|
||||
using OpenNest.Geometry;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenNest.Engine
|
||||
{
|
||||
public class LeadInAssigner
|
||||
{
|
||||
public IPartSequencer Sequencer { get; set; }
|
||||
|
||||
public void Assign(Plate plate)
|
||||
{
|
||||
var parameters = plate.CuttingParameters;
|
||||
if (parameters == null)
|
||||
return;
|
||||
|
||||
var sequenced = Sequencer.Sequence(plate.Parts.ToList(), plate);
|
||||
var currentPoint = PlateHelper.GetExitPoint(plate);
|
||||
|
||||
foreach (var sp in sequenced)
|
||||
{
|
||||
var part = sp.Part;
|
||||
|
||||
if (part.LeadInsLocked)
|
||||
{
|
||||
currentPoint = part.Location;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part.HasManualLeadIns)
|
||||
part.RemoveLeadIns();
|
||||
|
||||
var localApproach = currentPoint - part.Location;
|
||||
part.ApplyLeadIns(parameters, localApproach);
|
||||
|
||||
currentPoint = part.Location;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,8 @@ namespace OpenNest.IO
|
||||
public double X { get; init; }
|
||||
public double Y { get; init; }
|
||||
public double Rotation { get; init; }
|
||||
public bool HasManualLeadIns { get; init; }
|
||||
public bool LeadInsLocked { get; init; }
|
||||
}
|
||||
|
||||
public record CutOffDto
|
||||
|
||||
@@ -214,6 +214,8 @@ namespace OpenNest.IO
|
||||
var part = new Part(dwg);
|
||||
part.Rotate(partDto.Rotation);
|
||||
part.Offset(new Vector(partDto.X, partDto.Y));
|
||||
part.HasManualLeadIns = partDto.HasManualLeadIns;
|
||||
part.LeadInsLocked = partDto.LeadInsLocked;
|
||||
plate.Parts.Add(part);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,7 +173,9 @@ namespace OpenNest.IO
|
||||
DrawingId = match.Key,
|
||||
X = part.Location.X,
|
||||
Y = part.Location.Y,
|
||||
Rotation = part.Rotation
|
||||
Rotation = part.Rotation,
|
||||
HasManualLeadIns = part.HasManualLeadIns,
|
||||
LeadInsLocked = part.LeadInsLocked
|
||||
});
|
||||
}
|
||||
|
||||
@@ -336,6 +338,9 @@ namespace OpenNest.IO
|
||||
if (arcMove.Layer != LayerType.Cut)
|
||||
sb.Append(GetLayerString(arcMove.Layer));
|
||||
|
||||
if (arcMove.Suppressed)
|
||||
sb.Append(":SUPPRESSED");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
@@ -357,6 +362,9 @@ namespace OpenNest.IO
|
||||
if (linearMove.Layer != LayerType.Cut)
|
||||
sb.Append(GetLayerString(linearMove.Layer));
|
||||
|
||||
if (linearMove.Suppressed)
|
||||
sb.Append(":SUPPRESSED");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ namespace OpenNest.IO
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
var layer = LayerType.Cut;
|
||||
var suppressed = false;
|
||||
|
||||
while (section == CodeSection.Line)
|
||||
{
|
||||
@@ -164,25 +165,32 @@ namespace OpenNest.IO
|
||||
|
||||
case ':':
|
||||
{
|
||||
var value = code.Value.Trim().ToUpper();
|
||||
var tags = code.Value.Trim().ToUpper().Split(':');
|
||||
|
||||
switch (value)
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
switch (tag)
|
||||
{
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
|
||||
case "SUPPRESSED":
|
||||
suppressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -195,7 +203,7 @@ namespace OpenNest.IO
|
||||
if (isRapid)
|
||||
program.Codes.Add(new RapidMove(x, y));
|
||||
else
|
||||
program.Codes.Add(new LinearMove(x, y) { Layer = layer });
|
||||
program.Codes.Add(new LinearMove(x, y) { Layer = layer, Suppressed = suppressed });
|
||||
}
|
||||
|
||||
private void ReadArc(RotationType rotation)
|
||||
@@ -205,6 +213,7 @@ namespace OpenNest.IO
|
||||
double i = 0;
|
||||
double j = 0;
|
||||
var layer = LayerType.Cut;
|
||||
var suppressed = false;
|
||||
|
||||
while (section == CodeSection.Arc)
|
||||
{
|
||||
@@ -236,25 +245,32 @@ namespace OpenNest.IO
|
||||
|
||||
case ':':
|
||||
{
|
||||
var value = code.Value.Trim().ToUpper();
|
||||
var tags = code.Value.Trim().ToUpper().Split(':');
|
||||
|
||||
switch (value)
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
switch (tag)
|
||||
{
|
||||
case "DISPLAY":
|
||||
layer = LayerType.Display;
|
||||
break;
|
||||
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
case "LEADIN":
|
||||
layer = LayerType.Leadin;
|
||||
break;
|
||||
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
case "LEADOUT":
|
||||
layer = LayerType.Leadout;
|
||||
break;
|
||||
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
case "SCRIBE":
|
||||
layer = LayerType.Scribe;
|
||||
break;
|
||||
|
||||
case "SUPPRESSED":
|
||||
suppressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -269,7 +285,8 @@ namespace OpenNest.IO
|
||||
EndPoint = new Vector(x, y),
|
||||
CenterPoint = new Vector(i, j),
|
||||
Rotation = rotation,
|
||||
Layer = layer
|
||||
Layer = layer,
|
||||
Suppressed = suppressed
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Engine;
|
||||
using OpenNest.Engine.Sequencing;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests;
|
||||
|
||||
public class LeadInAssignerTests
|
||||
{
|
||||
private static Part MakeSquarePartAt(double x, double y)
|
||||
{
|
||||
var pgm = new Program();
|
||||
pgm.Codes.Add(new RapidMove(new Vector(0, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, 10)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(10, 10)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(10, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, 0)));
|
||||
var drawing = new Drawing("test", pgm);
|
||||
return new Part(drawing, new Vector(x, y));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Assign_SetsHasManualLeadInsOnAllParts()
|
||||
{
|
||||
var plate = new Plate(60, 120);
|
||||
plate.Parts.Add(MakeSquarePartAt(10, 10));
|
||||
plate.Parts.Add(MakeSquarePartAt(30, 30));
|
||||
plate.CuttingParameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
var assigner = new LeadInAssigner { Sequencer = new LeftSideSequencer() };
|
||||
assigner.Assign(plate);
|
||||
|
||||
Assert.All(plate.Parts, p => Assert.True(p.HasManualLeadIns));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Assign_SkipsLockedParts()
|
||||
{
|
||||
var plate = new Plate(60, 120);
|
||||
var lockedPart = MakeSquarePartAt(10, 10);
|
||||
lockedPart.LeadInsLocked = true;
|
||||
lockedPart.HasManualLeadIns = true;
|
||||
var originalProgram = lockedPart.Program;
|
||||
|
||||
plate.Parts.Add(lockedPart);
|
||||
plate.Parts.Add(MakeSquarePartAt(30, 30));
|
||||
plate.CuttingParameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
var assigner = new LeadInAssigner { Sequencer = new LeftSideSequencer() };
|
||||
assigner.Assign(plate);
|
||||
|
||||
Assert.Same(originalProgram, lockedPart.Program);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Assign_RemovesExistingLeadInsBeforeReapply()
|
||||
{
|
||||
var plate = new Plate(60, 120);
|
||||
plate.Parts.Add(MakeSquarePartAt(10, 10));
|
||||
plate.CuttingParameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
var assigner = new LeadInAssigner { Sequencer = new LeftSideSequencer() };
|
||||
assigner.Assign(plate);
|
||||
var countAfterFirst = plate.Parts[0].Program.Codes.Count;
|
||||
|
||||
assigner.Assign(plate);
|
||||
var countAfterSecond = plate.Parts[0].Program.Codes.Count;
|
||||
|
||||
Assert.Equal(countAfterFirst, countAfterSecond);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Assign_PartsContainLeadinLayerCodes()
|
||||
{
|
||||
var plate = new Plate(60, 120);
|
||||
plate.Parts.Add(MakeSquarePartAt(10, 10));
|
||||
plate.CuttingParameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
var assigner = new LeadInAssigner { Sequencer = new LeftSideSequencer() };
|
||||
assigner.Assign(plate);
|
||||
|
||||
var hasLeadin = plate.Parts[0].Program.Codes.OfType<LinearMove>().Any(m => m.Layer == LayerType.Leadin);
|
||||
Assert.True(hasLeadin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests;
|
||||
|
||||
public class LeadInLayerTagTests
|
||||
{
|
||||
private static readonly Vector Point = new(5, 5);
|
||||
private const double Normal = 0.0;
|
||||
|
||||
[Fact]
|
||||
public void LineLeadIn_SetsLeadinLayer()
|
||||
{
|
||||
var leadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 };
|
||||
var codes = leadIn.Generate(Point, Normal);
|
||||
var linear = codes.OfType<LinearMove>().Single();
|
||||
Assert.Equal(LayerType.Leadin, linear.Layer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArcLeadIn_SetsLeadinLayer()
|
||||
{
|
||||
var leadIn = new ArcLeadIn { Radius = 0.25 };
|
||||
var codes = leadIn.Generate(Point, Normal);
|
||||
var arc = codes.OfType<ArcMove>().Single();
|
||||
Assert.Equal(LayerType.Leadin, arc.Layer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LineArcLeadIn_SetsLeadinLayerOnAllMoves()
|
||||
{
|
||||
var leadIn = new LineArcLeadIn { LineLength = 0.5, ArcRadius = 0.25, ApproachAngle = 135 };
|
||||
var codes = leadIn.Generate(Point, Normal);
|
||||
Assert.All(codes.OfType<LinearMove>(), m => Assert.Equal(LayerType.Leadin, m.Layer));
|
||||
Assert.All(codes.OfType<ArcMove>(), m => Assert.Equal(LayerType.Leadin, m.Layer));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CleanHoleLeadIn_SetsLeadinLayerOnAllMoves()
|
||||
{
|
||||
var leadIn = new CleanHoleLeadIn { LineLength = 0.5, ArcRadius = 0.25, Kerf = 0.05 };
|
||||
var codes = leadIn.Generate(Point, Normal);
|
||||
Assert.All(codes.OfType<LinearMove>(), m => Assert.Equal(LayerType.Leadin, m.Layer));
|
||||
Assert.All(codes.OfType<ArcMove>(), m => Assert.Equal(LayerType.Leadin, m.Layer));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LineLineLeadIn_SetsLeadinLayerOnAllMoves()
|
||||
{
|
||||
var leadIn = new LineLineLeadIn { Length1 = 0.5, Length2 = 0.3, ApproachAngle1 = 90, ApproachAngle2 = 90 };
|
||||
var codes = leadIn.Generate(Point, Normal);
|
||||
Assert.All(codes.OfType<LinearMove>(), m => Assert.Equal(LayerType.Leadin, m.Layer));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoLeadIn_NoLinearOrArcMoves()
|
||||
{
|
||||
var leadIn = new NoLeadIn();
|
||||
var codes = leadIn.Generate(Point, Normal);
|
||||
Assert.Empty(codes.OfType<LinearMove>());
|
||||
Assert.Empty(codes.OfType<ArcMove>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LineLeadOut_SetsLeadoutLayer()
|
||||
{
|
||||
var leadOut = new LineLeadOut { Length = 0.5, ApproachAngle = 90 };
|
||||
var codes = leadOut.Generate(Point, Normal);
|
||||
var linear = codes.OfType<LinearMove>().Single();
|
||||
Assert.Equal(LayerType.Leadout, linear.Layer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArcLeadOut_SetsLeadoutLayer()
|
||||
{
|
||||
var leadOut = new ArcLeadOut { Radius = 0.25 };
|
||||
var codes = leadOut.Generate(Point, Normal);
|
||||
var arc = codes.OfType<ArcMove>().Single();
|
||||
Assert.Equal(LayerType.Leadout, arc.Layer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoLeadOut_ReturnsEmptyList()
|
||||
{
|
||||
var leadOut = new NoLeadOut();
|
||||
var codes = leadOut.Generate(Point, Normal);
|
||||
Assert.Empty(codes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests;
|
||||
|
||||
public class MotionSuppressedTests
|
||||
{
|
||||
[Fact]
|
||||
public void LinearMove_Suppressed_DefaultsFalse()
|
||||
{
|
||||
var move = new LinearMove(new Vector(1, 2));
|
||||
Assert.False(move.Suppressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArcMove_Suppressed_DefaultsFalse()
|
||||
{
|
||||
var move = new ArcMove(new Vector(1, 2), new Vector(0, 0));
|
||||
Assert.False(move.Suppressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RapidMove_Suppressed_DefaultsFalse()
|
||||
{
|
||||
var move = new RapidMove(new Vector(1, 2));
|
||||
Assert.False(move.Suppressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Suppressed_CanBeSet()
|
||||
{
|
||||
var move = new LinearMove(new Vector(1, 2));
|
||||
move.Suppressed = true;
|
||||
Assert.True(move.Suppressed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clone_PreservesSuppressed()
|
||||
{
|
||||
var move = new LinearMove(new Vector(1, 2));
|
||||
move.Suppressed = true;
|
||||
var clone = (LinearMove)move.Clone();
|
||||
Assert.True(clone.Suppressed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests;
|
||||
|
||||
public class PartLeadInTests
|
||||
{
|
||||
private static Part MakeSquarePart()
|
||||
{
|
||||
var pgm = new Program();
|
||||
pgm.Codes.Add(new RapidMove(new Vector(0, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, 10)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(10, 10)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(10, 0)));
|
||||
pgm.Codes.Add(new LinearMove(new Vector(0, 0)));
|
||||
var drawing = new Drawing("test", pgm);
|
||||
return new Part(drawing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyLeadIns_SetsHasManualLeadIns()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
|
||||
InternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
|
||||
Assert.True(part.HasManualLeadIns);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyLeadIns_StoresCuttingParameters()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 },
|
||||
InternalLeadIn = new LineLeadIn { Length = 0.25, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
|
||||
Assert.Same(parameters, part.CuttingParameters);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyLeadIns_ProgramContainsLeadinCodes()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
|
||||
var hasLeadin = part.Program.Codes.OfType<LinearMove>().Any(m => m.Layer == LayerType.Leadin);
|
||||
Assert.True(hasLeadin);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveLeadIns_RestoresOriginalProgram()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
var originalCodeCount = part.Program.Codes.Count;
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
part.RemoveLeadIns();
|
||||
|
||||
Assert.False(part.HasManualLeadIns);
|
||||
Assert.Null(part.CuttingParameters);
|
||||
Assert.Equal(originalCodeCount, part.Program.Codes.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveLeadIns_PreservesRotation()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
part.Rotate(System.Math.PI / 4); // 45 degrees
|
||||
var rotation = part.Rotation;
|
||||
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
part.RemoveLeadIns();
|
||||
|
||||
Assert.Equal(rotation, part.Rotation, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveLeadIns_PreservesLocation()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
part.Offset(20, 30);
|
||||
var location = part.Location;
|
||||
|
||||
var parameters = new CuttingParameters
|
||||
{
|
||||
ExternalLeadIn = new LineLeadIn { Length = 0.5, ApproachAngle = 90 }
|
||||
};
|
||||
|
||||
part.ApplyLeadIns(parameters, new Vector(-5, -5));
|
||||
part.RemoveLeadIns();
|
||||
|
||||
Assert.Equal(location.X, part.Location.X, 6);
|
||||
Assert.Equal(location.Y, part.Location.Y, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LeadInsLocked_DefaultsFalse()
|
||||
{
|
||||
var part = MakeSquarePart();
|
||||
Assert.False(part.LeadInsLocked);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Controls;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Geometry;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenNest.Actions
|
||||
{
|
||||
[DisplayName("Place Lead-in")]
|
||||
public class ActionLeadIn : Action
|
||||
{
|
||||
private LayoutPart selectedLayoutPart;
|
||||
private Part selectedPart;
|
||||
private ShapeProfile profile;
|
||||
private List<ShapeInfo> contours;
|
||||
private Vector snapPoint;
|
||||
private Entity snapEntity;
|
||||
private ContourType snapContourType;
|
||||
private double snapNormal;
|
||||
private bool hasSnap;
|
||||
private ContextMenuStrip contextMenu;
|
||||
|
||||
public ActionLeadIn(PlateView plateView)
|
||||
: base(plateView)
|
||||
{
|
||||
ConnectEvents();
|
||||
}
|
||||
|
||||
public override void ConnectEvents()
|
||||
{
|
||||
plateView.MouseMove += OnMouseMove;
|
||||
plateView.MouseDown += OnMouseDown;
|
||||
plateView.KeyDown += OnKeyDown;
|
||||
plateView.Paint += OnPaint;
|
||||
}
|
||||
|
||||
public override void DisconnectEvents()
|
||||
{
|
||||
plateView.MouseMove -= OnMouseMove;
|
||||
plateView.MouseDown -= OnMouseDown;
|
||||
plateView.KeyDown -= OnKeyDown;
|
||||
plateView.Paint -= OnPaint;
|
||||
|
||||
contextMenu?.Dispose();
|
||||
contextMenu = null;
|
||||
|
||||
selectedLayoutPart = null;
|
||||
selectedPart = null;
|
||||
profile = null;
|
||||
contours = null;
|
||||
hasSnap = false;
|
||||
plateView.Invalidate();
|
||||
}
|
||||
|
||||
public override void CancelAction() { }
|
||||
|
||||
public override bool IsBusy() => selectedPart != null;
|
||||
|
||||
private void OnMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (selectedPart == null || contours == null)
|
||||
return;
|
||||
|
||||
var worldPt = plateView.CurrentPoint;
|
||||
|
||||
// Transform world point into program-local space by subtracting the
|
||||
// part's location. The contour shapes are already in the program's
|
||||
// rotated coordinate system, so no additional un-rotation is needed.
|
||||
var localPt = new Vector(worldPt.X - selectedPart.Location.X,
|
||||
worldPt.Y - selectedPart.Location.Y);
|
||||
|
||||
// Find closest contour and point
|
||||
var bestDist = double.MaxValue;
|
||||
hasSnap = false;
|
||||
|
||||
foreach (var info in contours)
|
||||
{
|
||||
var closest = info.Shape.ClosestPointTo(localPt, out var entity);
|
||||
var dist = closest.DistanceTo(localPt);
|
||||
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
snapPoint = closest;
|
||||
snapEntity = entity;
|
||||
snapContourType = info.ContourType;
|
||||
snapNormal = ContourCuttingStrategy.ComputeNormal(closest, entity, info.ContourType);
|
||||
hasSnap = true;
|
||||
}
|
||||
}
|
||||
|
||||
plateView.Invalidate();
|
||||
}
|
||||
|
||||
private void OnMouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
if (selectedPart == null)
|
||||
{
|
||||
// First click: select a part
|
||||
SelectPartAtCursor();
|
||||
}
|
||||
else if (hasSnap)
|
||||
{
|
||||
// Second click: commit lead-in at snap point
|
||||
CommitLeadIn();
|
||||
}
|
||||
}
|
||||
else if (e.Button == MouseButtons.Right)
|
||||
{
|
||||
if (selectedPart != null && selectedPart.HasManualLeadIns)
|
||||
ShowContextMenu(e.Location);
|
||||
else
|
||||
DeselectPart();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape)
|
||||
{
|
||||
if (selectedPart != null)
|
||||
DeselectPart();
|
||||
else
|
||||
plateView.SetAction(typeof(ActionSelect));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPaint(object sender, PaintEventArgs e)
|
||||
{
|
||||
if (!hasSnap || selectedPart == null)
|
||||
return;
|
||||
|
||||
var parameters = plateView.Plate?.CuttingParameters;
|
||||
if (parameters == null)
|
||||
return;
|
||||
|
||||
// Transform snap point from local part space to world space
|
||||
var worldSnap = TransformToWorld(snapPoint);
|
||||
|
||||
// Get the appropriate lead-in for this contour type
|
||||
var leadIn = SelectLeadIn(parameters, snapContourType);
|
||||
if (leadIn == null)
|
||||
return;
|
||||
|
||||
// Get the pierce point (in local space)
|
||||
var piercePoint = leadIn.GetPiercePoint(snapPoint, snapNormal);
|
||||
var worldPierce = TransformToWorld(piercePoint);
|
||||
|
||||
var g = e.Graphics;
|
||||
var oldSmooth = g.SmoothingMode;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
// Draw the lead-in preview as a line from pierce point to contour point
|
||||
var pt1 = plateView.PointWorldToGraph(worldPierce);
|
||||
var pt2 = plateView.PointWorldToGraph(worldSnap);
|
||||
|
||||
using var pen = new Pen(Color.Yellow, 2.0f / plateView.ViewScale);
|
||||
g.DrawLine(pen, pt1, pt2);
|
||||
|
||||
// Draw a small circle at the pierce point
|
||||
var radius = 3.0f / plateView.ViewScale;
|
||||
g.FillEllipse(Brushes.Yellow, pt1.X - radius, pt1.Y - radius, radius * 2, radius * 2);
|
||||
|
||||
// Draw a small circle at the contour start point
|
||||
g.FillEllipse(Brushes.Lime, pt2.X - radius, pt2.Y - radius, radius * 2, radius * 2);
|
||||
|
||||
g.SmoothingMode = oldSmooth;
|
||||
}
|
||||
|
||||
private void SelectPartAtCursor()
|
||||
{
|
||||
var layoutPart = plateView.GetPartAtPoint(plateView.CurrentPoint);
|
||||
if (layoutPart == null)
|
||||
return;
|
||||
|
||||
var part = layoutPart.BasePart;
|
||||
|
||||
// Don't allow lead-in placement on cut-off parts
|
||||
if (part.BaseDrawing.IsCutOff)
|
||||
return;
|
||||
|
||||
// If part already has locked lead-ins, don't allow re-placement
|
||||
if (part.LeadInsLocked)
|
||||
return;
|
||||
|
||||
selectedLayoutPart = layoutPart;
|
||||
selectedPart = part;
|
||||
|
||||
// Build contour info from the part's program geometry
|
||||
BuildContourInfo();
|
||||
|
||||
// Highlight the selected part
|
||||
layoutPart.IsSelected = true;
|
||||
plateView.Invalidate();
|
||||
}
|
||||
|
||||
private void BuildContourInfo()
|
||||
{
|
||||
// Get a clean program (no lead-ins) in the part's current rotated space.
|
||||
// If the part has manual lead-ins, rebuild from base drawing + rotation.
|
||||
// Otherwise the current Program is already clean and rotated.
|
||||
CNC.Program cleanProgram;
|
||||
|
||||
if (selectedPart.HasManualLeadIns)
|
||||
{
|
||||
cleanProgram = selectedPart.BaseDrawing.Program.Clone() as CNC.Program;
|
||||
if (!OpenNest.Math.Tolerance.IsEqualTo(selectedPart.Rotation, 0))
|
||||
cleanProgram.Rotate(selectedPart.Rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanProgram = selectedPart.Program;
|
||||
}
|
||||
|
||||
var entities = ConvertProgram.ToGeometry(cleanProgram);
|
||||
profile = new ShapeProfile(entities);
|
||||
|
||||
contours = new List<ShapeInfo>();
|
||||
|
||||
// Perimeter is always External
|
||||
if (profile.Perimeter != null)
|
||||
{
|
||||
contours.Add(new ShapeInfo
|
||||
{
|
||||
Shape = profile.Perimeter,
|
||||
ContourType = ContourType.External
|
||||
});
|
||||
}
|
||||
|
||||
// Cutouts
|
||||
foreach (var cutout in profile.Cutouts)
|
||||
{
|
||||
contours.Add(new ShapeInfo
|
||||
{
|
||||
Shape = cutout,
|
||||
ContourType = ContourCuttingStrategy.DetectContourType(cutout)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void CommitLeadIn()
|
||||
{
|
||||
var parameters = plateView.Plate?.CuttingParameters;
|
||||
if (parameters == null)
|
||||
return;
|
||||
|
||||
// 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);
|
||||
selectedPart.LeadInsLocked = true;
|
||||
|
||||
// Rebuild the layout part's graphics
|
||||
selectedLayoutPart.IsDirty = true;
|
||||
selectedLayoutPart.Update();
|
||||
|
||||
// Deselect and reset
|
||||
DeselectPart();
|
||||
plateView.Invalidate();
|
||||
}
|
||||
|
||||
private void DeselectPart()
|
||||
{
|
||||
if (selectedLayoutPart != null)
|
||||
{
|
||||
selectedLayoutPart.IsSelected = false;
|
||||
selectedLayoutPart = null;
|
||||
}
|
||||
|
||||
selectedPart = null;
|
||||
profile = null;
|
||||
contours = null;
|
||||
hasSnap = false;
|
||||
plateView.Invalidate();
|
||||
}
|
||||
|
||||
private void ShowContextMenu(Point location)
|
||||
{
|
||||
contextMenu?.Dispose();
|
||||
contextMenu = new ContextMenuStrip();
|
||||
|
||||
var removeItem = new ToolStripMenuItem("Remove All Lead-ins");
|
||||
removeItem.Click += (s, e) =>
|
||||
{
|
||||
selectedPart.RemoveLeadIns();
|
||||
selectedLayoutPart.IsDirty = true;
|
||||
selectedLayoutPart.Update();
|
||||
DeselectPart();
|
||||
plateView.Invalidate();
|
||||
};
|
||||
|
||||
contextMenu.Items.Add(removeItem);
|
||||
contextMenu.Show(plateView, location);
|
||||
}
|
||||
|
||||
private Vector TransformToWorld(Vector localPt)
|
||||
{
|
||||
// The contours are already in rotated local space (we rotated the program
|
||||
// before building the profile), so just add the part location offset
|
||||
return new Vector(localPt.X + selectedPart.Location.X,
|
||||
localPt.Y + selectedPart.Location.Y);
|
||||
}
|
||||
|
||||
private static LeadIn SelectLeadIn(CuttingParameters parameters, ContourType contourType)
|
||||
{
|
||||
return contourType switch
|
||||
{
|
||||
ContourType.ArcCircle => parameters.ArcCircleLeadIn ?? parameters.InternalLeadIn,
|
||||
ContourType.Internal => parameters.InternalLeadIn,
|
||||
_ => parameters.ExternalLeadIn
|
||||
};
|
||||
}
|
||||
|
||||
private class ShapeInfo
|
||||
{
|
||||
public Shape Shape { get; set; }
|
||||
public ContourType ContourType { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
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, 406);
|
||||
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, 456);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,476 @@
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace OpenNest.Forms
|
||||
{
|
||||
public partial class CuttingParametersForm : Form
|
||||
{
|
||||
private static readonly string[] LeadInTypes =
|
||||
{ "None", "Line", "Arc", "Line + Arc", "Clean Hole", "Line + Line" };
|
||||
|
||||
private static readonly string[] LeadOutTypes =
|
||||
{ "None", "Line", "Arc", "Microtab" };
|
||||
|
||||
private ComboBox cboExternalLeadIn, cboExternalLeadOut;
|
||||
private ComboBox cboInternalLeadIn, cboInternalLeadOut;
|
||||
private ComboBox cboArcCircleLeadIn, cboArcCircleLeadOut;
|
||||
|
||||
private Panel pnlExternalLeadIn, pnlExternalLeadOut;
|
||||
private Panel pnlInternalLeadIn, pnlInternalLeadOut;
|
||||
private Panel pnlArcCircleLeadIn, pnlArcCircleLeadOut;
|
||||
|
||||
private CheckBox chkTabsEnabled;
|
||||
private NumericUpDown nudTabWidth;
|
||||
|
||||
public CuttingParameters Parameters { get; set; } = new CuttingParameters();
|
||||
|
||||
public CuttingParametersForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
SetupTab(tabExternal,
|
||||
out cboExternalLeadIn, out pnlExternalLeadIn,
|
||||
out cboExternalLeadOut, out pnlExternalLeadOut);
|
||||
SetupTab(tabInternal,
|
||||
out cboInternalLeadIn, out pnlInternalLeadIn,
|
||||
out cboInternalLeadOut, out pnlInternalLeadOut);
|
||||
SetupTab(tabArcCircle,
|
||||
out cboArcCircleLeadIn, out pnlArcCircleLeadIn,
|
||||
out cboArcCircleLeadOut, out pnlArcCircleLeadOut);
|
||||
|
||||
SetupTabsSection();
|
||||
PopulateDropdowns();
|
||||
|
||||
cboExternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
||||
cboInternalLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
||||
cboArcCircleLeadIn.SelectedIndexChanged += OnLeadInTypeChanged;
|
||||
|
||||
cboExternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
||||
cboInternalLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
||||
cboArcCircleLeadOut.SelectedIndexChanged += OnLeadOutTypeChanged;
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
LoadFromParameters(Parameters);
|
||||
}
|
||||
|
||||
private static void SetupTab(TabPage tab,
|
||||
out ComboBox leadInCombo, out Panel leadInPanel,
|
||||
out ComboBox leadOutCombo, out Panel leadOutPanel)
|
||||
{
|
||||
var grpLeadIn = new GroupBox
|
||||
{
|
||||
Text = "Lead-In",
|
||||
Location = new System.Drawing.Point(4, 4),
|
||||
Size = new System.Drawing.Size(364, 168)
|
||||
};
|
||||
tab.Controls.Add(grpLeadIn);
|
||||
|
||||
grpLeadIn.Controls.Add(new Label
|
||||
{
|
||||
Text = "Type:",
|
||||
Location = new System.Drawing.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)
|
||||
};
|
||||
grpLeadIn.Controls.Add(leadInCombo);
|
||||
|
||||
leadInPanel = new Panel
|
||||
{
|
||||
Location = new System.Drawing.Point(8, 48),
|
||||
Size = new System.Drawing.Size(340, 112),
|
||||
AutoScroll = true
|
||||
};
|
||||
grpLeadIn.Controls.Add(leadInPanel);
|
||||
|
||||
var grpLeadOut = new GroupBox
|
||||
{
|
||||
Text = "Lead-Out",
|
||||
Location = new System.Drawing.Point(4, 176),
|
||||
Size = new System.Drawing.Size(364, 132)
|
||||
};
|
||||
tab.Controls.Add(grpLeadOut);
|
||||
|
||||
grpLeadOut.Controls.Add(new Label
|
||||
{
|
||||
Text = "Type:",
|
||||
Location = new System.Drawing.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)
|
||||
};
|
||||
grpLeadOut.Controls.Add(leadOutCombo);
|
||||
|
||||
leadOutPanel = new Panel
|
||||
{
|
||||
Location = new System.Drawing.Point(8, 48),
|
||||
Size = new System.Drawing.Size(340, 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);
|
||||
}
|
||||
|
||||
private void PopulateDropdowns()
|
||||
{
|
||||
foreach (var combo in new[] { cboExternalLeadIn, cboInternalLeadIn, cboArcCircleLeadIn })
|
||||
{
|
||||
combo.Items.AddRange(LeadInTypes);
|
||||
combo.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
foreach (var combo in new[] { cboExternalLeadOut, cboInternalLeadOut, cboArcCircleLeadOut })
|
||||
{
|
||||
combo.Items.AddRange(LeadOutTypes);
|
||||
combo.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLeadInTypeChanged(object sender, EventArgs e)
|
||||
{
|
||||
var combo = (ComboBox)sender;
|
||||
var panel = GetLeadInPanel(combo);
|
||||
if (panel != null)
|
||||
BuildLeadInParamControls(panel, combo.SelectedIndex);
|
||||
}
|
||||
|
||||
private void OnLeadOutTypeChanged(object sender, EventArgs e)
|
||||
{
|
||||
var combo = (ComboBox)sender;
|
||||
var panel = GetLeadOutPanel(combo);
|
||||
if (panel != null)
|
||||
BuildLeadOutParamControls(panel, combo.SelectedIndex);
|
||||
}
|
||||
|
||||
private Panel GetLeadInPanel(ComboBox combo)
|
||||
{
|
||||
if (combo == cboExternalLeadIn) return pnlExternalLeadIn;
|
||||
if (combo == cboInternalLeadIn) return pnlInternalLeadIn;
|
||||
if (combo == cboArcCircleLeadIn) return pnlArcCircleLeadIn;
|
||||
return null;
|
||||
}
|
||||
|
||||
private Panel GetLeadOutPanel(ComboBox combo)
|
||||
{
|
||||
if (combo == cboExternalLeadOut) return pnlExternalLeadOut;
|
||||
if (combo == cboInternalLeadOut) return pnlInternalLeadOut;
|
||||
if (combo == cboArcCircleLeadOut) return pnlArcCircleLeadOut;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void BuildLeadInParamControls(Panel panel, int typeIndex)
|
||||
{
|
||||
panel.Controls.Clear();
|
||||
var y = 0;
|
||||
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 1: // Line
|
||||
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
||||
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
||||
break;
|
||||
case 2: // Arc
|
||||
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
||||
break;
|
||||
case 3: // Line + Arc
|
||||
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
|
||||
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
|
||||
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");
|
||||
AddNumericField(panel, "Angle 2:", 90, ref y, "Angle2");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BuildLeadOutParamControls(Panel panel, int typeIndex)
|
||||
{
|
||||
panel.Controls.Clear();
|
||||
var y = 0;
|
||||
|
||||
switch (typeIndex)
|
||||
{
|
||||
case 1: // Line
|
||||
AddNumericField(panel, "Length:", 0.25, ref y, "Length");
|
||||
AddNumericField(panel, "Approach Angle:", 90, ref y, "ApproachAngle");
|
||||
break;
|
||||
case 2: // Arc
|
||||
AddNumericField(panel, "Radius:", 0.25, ref y, "Radius");
|
||||
break;
|
||||
case 3: // Microtab
|
||||
AddNumericField(panel, "Gap Size:", 0.06, ref y, "GapSize");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static 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),
|
||||
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
|
||||
});
|
||||
|
||||
y += 30;
|
||||
}
|
||||
|
||||
private void LoadFromParameters(CuttingParameters p)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
private static void LoadLeadIn(ComboBox combo, Panel panel, LeadIn leadIn)
|
||||
{
|
||||
switch (leadIn)
|
||||
{
|
||||
case LineLeadIn line:
|
||||
combo.SelectedIndex = 1;
|
||||
SetParam(panel, "Length", line.Length);
|
||||
SetParam(panel, "ApproachAngle", line.ApproachAngle);
|
||||
break;
|
||||
case ArcLeadIn arc:
|
||||
combo.SelectedIndex = 2;
|
||||
SetParam(panel, "Radius", arc.Radius);
|
||||
break;
|
||||
case LineArcLeadIn lineArc:
|
||||
combo.SelectedIndex = 3;
|
||||
SetParam(panel, "LineLength", lineArc.LineLength);
|
||||
SetParam(panel, "ArcRadius", lineArc.ArcRadius);
|
||||
SetParam(panel, "ApproachAngle", lineArc.ApproachAngle);
|
||||
break;
|
||||
case CleanHoleLeadIn cleanHole:
|
||||
combo.SelectedIndex = 4;
|
||||
SetParam(panel, "LineLength", cleanHole.LineLength);
|
||||
SetParam(panel, "ArcRadius", cleanHole.ArcRadius);
|
||||
SetParam(panel, "Kerf", cleanHole.Kerf);
|
||||
break;
|
||||
case LineLineLeadIn lineLine:
|
||||
combo.SelectedIndex = 5;
|
||||
SetParam(panel, "Length1", lineLine.Length1);
|
||||
SetParam(panel, "Angle1", lineLine.ApproachAngle1);
|
||||
SetParam(panel, "Length2", lineLine.Length2);
|
||||
SetParam(panel, "Angle2", lineLine.ApproachAngle2);
|
||||
break;
|
||||
default:
|
||||
combo.SelectedIndex = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadLeadOut(ComboBox combo, Panel panel, LeadOut leadOut)
|
||||
{
|
||||
switch (leadOut)
|
||||
{
|
||||
case LineLeadOut line:
|
||||
combo.SelectedIndex = 1;
|
||||
SetParam(panel, "Length", line.Length);
|
||||
SetParam(panel, "ApproachAngle", line.ApproachAngle);
|
||||
break;
|
||||
case ArcLeadOut arc:
|
||||
combo.SelectedIndex = 2;
|
||||
SetParam(panel, "Radius", arc.Radius);
|
||||
break;
|
||||
case MicrotabLeadOut microtab:
|
||||
combo.SelectedIndex = 3;
|
||||
SetParam(panel, "GapSize", microtab.GapSize);
|
||||
break;
|
||||
default:
|
||||
combo.SelectedIndex = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
};
|
||||
return p;
|
||||
}
|
||||
|
||||
private static LeadIn BuildLeadIn(ComboBox combo, Panel panel)
|
||||
{
|
||||
switch (combo.SelectedIndex)
|
||||
{
|
||||
case 1:
|
||||
return new LineLeadIn
|
||||
{
|
||||
Length = GetParam(panel, "Length", 0.25),
|
||||
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
||||
};
|
||||
case 2:
|
||||
return new ArcLeadIn
|
||||
{
|
||||
Radius = GetParam(panel, "Radius", 0.25)
|
||||
};
|
||||
case 3:
|
||||
return new LineArcLeadIn
|
||||
{
|
||||
LineLength = GetParam(panel, "LineLength", 0.25),
|
||||
ArcRadius = GetParam(panel, "ArcRadius", 0.125),
|
||||
ApproachAngle = GetParam(panel, "ApproachAngle", 135)
|
||||
};
|
||||
case 4:
|
||||
return 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
|
||||
{
|
||||
Length1 = GetParam(panel, "Length1", 0.25),
|
||||
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)
|
||||
{
|
||||
switch (combo.SelectedIndex)
|
||||
{
|
||||
case 1:
|
||||
return new LineLeadOut
|
||||
{
|
||||
Length = GetParam(panel, "Length", 0.25),
|
||||
ApproachAngle = GetParam(panel, "ApproachAngle", 90)
|
||||
};
|
||||
case 2:
|
||||
return new ArcLeadOut
|
||||
{
|
||||
Radius = GetParam(panel, "Radius", 0.25)
|
||||
};
|
||||
case 3:
|
||||
return new MicrotabLeadOut
|
||||
{
|
||||
GapSize = GetParam(panel, "GapSize", 0.06)
|
||||
};
|
||||
default:
|
||||
return new NoLeadOut();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetParam(Panel panel, string tag, double value)
|
||||
{
|
||||
foreach (Control c in panel.Controls)
|
||||
{
|
||||
if (c is NumericUpDown nud && (string)nud.Tag == tag)
|
||||
{
|
||||
nud.Value = (decimal)value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double GetParam(Panel panel, string tag, double defaultValue)
|
||||
{
|
||||
foreach (Control c in panel.Controls)
|
||||
{
|
||||
if (c is NumericUpDown nud && (string)nud.Tag == tag)
|
||||
return (double)nud.Value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+26
-2
@@ -38,6 +38,8 @@
|
||||
this.qtyColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
|
||||
this.toolStripButton1 = new System.Windows.Forms.ToolStripButton();
|
||||
this.btnAssignLeadIns = new System.Windows.Forms.ToolStripButton();
|
||||
this.btnPlaceLeadIn = new System.Windows.Forms.ToolStripButton();
|
||||
this.tabPage2 = new System.Windows.Forms.TabPage();
|
||||
this.drawingListBox1 = new OpenNest.Controls.DrawingListBox();
|
||||
this.toolStrip2 = new System.Windows.Forms.ToolStrip();
|
||||
@@ -133,7 +135,9 @@
|
||||
this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||
this.toolStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripButton1});
|
||||
this.toolStripButton1,
|
||||
this.btnAssignLeadIns,
|
||||
this.btnPlaceLeadIn});
|
||||
this.toolStrip1.Location = new System.Drawing.Point(3, 3);
|
||||
this.toolStrip1.Name = "toolStrip1";
|
||||
this.toolStrip1.Size = new System.Drawing.Size(227, 31);
|
||||
@@ -151,7 +155,25 @@
|
||||
this.toolStripButton1.Size = new System.Drawing.Size(38, 28);
|
||||
this.toolStripButton1.Text = "Calculate Cut Time";
|
||||
this.toolStripButton1.Click += new System.EventHandler(this.CalculateSelectedPlateCutTime_Click);
|
||||
//
|
||||
//
|
||||
// btnAssignLeadIns
|
||||
//
|
||||
this.btnAssignLeadIns.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.btnAssignLeadIns.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.btnAssignLeadIns.Name = "btnAssignLeadIns";
|
||||
this.btnAssignLeadIns.Size = new System.Drawing.Size(96, 28);
|
||||
this.btnAssignLeadIns.Text = "Assign Lead-ins";
|
||||
this.btnAssignLeadIns.Click += new System.EventHandler(this.AssignLeadIns_Click);
|
||||
//
|
||||
// btnPlaceLeadIn
|
||||
//
|
||||
this.btnPlaceLeadIn.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.btnPlaceLeadIn.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.btnPlaceLeadIn.Name = "btnPlaceLeadIn";
|
||||
this.btnPlaceLeadIn.Size = new System.Drawing.Size(90, 28);
|
||||
this.btnPlaceLeadIn.Text = "Place Lead-in";
|
||||
this.btnPlaceLeadIn.Click += new System.EventHandler(this.PlaceLeadIn_Click);
|
||||
//
|
||||
// tabPage2
|
||||
//
|
||||
this.tabPage2.Controls.Add(this.drawingListBox1);
|
||||
@@ -266,5 +288,7 @@
|
||||
private System.Windows.Forms.ToolStripButton toolStripButton2;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
|
||||
private System.Windows.Forms.ToolStripButton toolStripButton3;
|
||||
private System.Windows.Forms.ToolStripButton btnAssignLeadIns;
|
||||
private System.Windows.Forms.ToolStripButton btnPlaceLeadIn;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using OpenNest.CNC.CuttingStrategy;
|
||||
using OpenNest.Collections;
|
||||
using OpenNest.Controls;
|
||||
using OpenNest.Engine;
|
||||
using OpenNest.Engine.Sequencing;
|
||||
using OpenNest.IO;
|
||||
using OpenNest.Math;
|
||||
@@ -711,6 +712,52 @@ namespace OpenNest.Forms
|
||||
CalculateCurrentPlateCutTime();
|
||||
}
|
||||
|
||||
private void AssignLeadIns_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (PlateView?.Plate == null)
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
var assigner = new LeadInAssigner
|
||||
{
|
||||
Sequencer = new LeftSideSequencer()
|
||||
};
|
||||
assigner.Assign(plate);
|
||||
|
||||
PlateView.Invalidate();
|
||||
}
|
||||
|
||||
private void PlaceLeadIn_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (PlateView?.Plate == null)
|
||||
return;
|
||||
|
||||
var plate = PlateView.Plate;
|
||||
|
||||
// Ensure cutting parameters are configured
|
||||
if (plate.CuttingParameters == null)
|
||||
{
|
||||
using var form = new CuttingParametersForm();
|
||||
if (form.ShowDialog(this) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
plate.CuttingParameters = form.BuildParameters();
|
||||
}
|
||||
|
||||
PlateView.SetAction(typeof(Actions.ActionLeadIn));
|
||||
}
|
||||
|
||||
private void ImportDrawings_Click(object sender, EventArgs e)
|
||||
{
|
||||
Import();
|
||||
|
||||
Generated
+57
-59
@@ -28,77 +28,75 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.numericUpDown1 = new OpenNest.Controls.NumericUpDown();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
label1 = new System.Windows.Forms.Label();
|
||||
numericUpDown1 = new OpenNest.Controls.NumericUpDown();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)numericUpDown1).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 2;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.numericUpDown1, 1, 0);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 1;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(220, 36);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
tableLayoutPanel1.ColumnCount = 2;
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.Controls.Add(label1, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(numericUpDown1, 1, 0);
|
||||
tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 1;
|
||||
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.Size = new System.Drawing.Size(266, 35);
|
||||
tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(3, 11);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(62, 13);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "Sequence :";
|
||||
label1.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
label1.AutoSize = true;
|
||||
label1.Location = new System.Drawing.Point(4, 10);
|
||||
label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
label1.Name = "label1";
|
||||
label1.Size = new System.Drawing.Size(64, 15);
|
||||
label1.TabIndex = 0;
|
||||
label1.Text = "Sequence :";
|
||||
//
|
||||
// numericUpDown1
|
||||
//
|
||||
this.numericUpDown1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.numericUpDown1.Location = new System.Drawing.Point(71, 8);
|
||||
this.numericUpDown1.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.numericUpDown1.Name = "numericUpDown1";
|
||||
this.numericUpDown1.Size = new System.Drawing.Size(146, 20);
|
||||
this.numericUpDown1.TabIndex = 1;
|
||||
this.numericUpDown1.Value = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.numericUpDown1.Leave += new System.EventHandler(this.numericUpDown1_Leave);
|
||||
numericUpDown1.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
numericUpDown1.Location = new System.Drawing.Point(76, 6);
|
||||
numericUpDown1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
numericUpDown1.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
|
||||
numericUpDown1.Name = "numericUpDown1";
|
||||
numericUpDown1.Size = new System.Drawing.Size(186, 23);
|
||||
numericUpDown1.Suffix = "";
|
||||
numericUpDown1.TabIndex = 1;
|
||||
numericUpDown1.Value = new decimal(new int[] { 1, 0, 0, 0 });
|
||||
numericUpDown1.Leave += numericUpDown1_Leave;
|
||||
//
|
||||
// SequenceForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(220, 36);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Location = new System.Drawing.Point(100, 100);
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "SequenceForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||
this.Text = "Set Sequence";
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
ClientSize = new System.Drawing.Size(266, 35);
|
||||
ControlBox = false;
|
||||
Controls.Add(tableLayoutPanel1);
|
||||
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
|
||||
Location = new System.Drawing.Point(100, 100);
|
||||
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
|
||||
MaximizeBox = false;
|
||||
MinimizeBox = false;
|
||||
MinimumSize = new System.Drawing.Size(268, 74);
|
||||
Name = "SequenceForm";
|
||||
ShowIcon = false;
|
||||
ShowInTaskbar = false;
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||
Text = "Set Sequence";
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel1.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)numericUpDown1).EndInit();
|
||||
ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
||||
@@ -85,6 +85,74 @@ namespace OpenNest
|
||||
return img;
|
||||
}
|
||||
|
||||
public static void GetGraphicsPaths(this Program pgm, Vector origin,
|
||||
out GraphicsPath cutPath, out GraphicsPath leadPath)
|
||||
{
|
||||
cutPath = new GraphicsPath();
|
||||
leadPath = new GraphicsPath();
|
||||
var curpos = origin;
|
||||
|
||||
AddProgramSplit(cutPath, leadPath, pgm, pgm.Mode, ref curpos);
|
||||
}
|
||||
|
||||
private static void AddProgramSplit(GraphicsPath cutPath, GraphicsPath leadPath,
|
||||
Program pgm, Mode mode, ref Vector curpos)
|
||||
{
|
||||
mode = pgm.Mode;
|
||||
|
||||
for (var i = 0; i < pgm.Length; ++i)
|
||||
{
|
||||
var code = pgm[i];
|
||||
|
||||
switch (code.Type)
|
||||
{
|
||||
case CodeType.ArcMove:
|
||||
var arc = (ArcMove)code;
|
||||
if (arc.Suppressed)
|
||||
{
|
||||
var endpt = arc.EndPoint;
|
||||
if (mode == Mode.Incremental) endpt += curpos;
|
||||
curpos = endpt;
|
||||
break;
|
||||
}
|
||||
var arcPath = (arc.Layer == LayerType.Leadin || arc.Layer == LayerType.Leadout)
|
||||
? leadPath : cutPath;
|
||||
AddArc(arcPath, arc, mode, ref curpos);
|
||||
break;
|
||||
|
||||
case CodeType.LinearMove:
|
||||
var line = (LinearMove)code;
|
||||
if (line.Suppressed)
|
||||
{
|
||||
var endpt = line.EndPoint;
|
||||
if (mode == Mode.Incremental) endpt += curpos;
|
||||
curpos = endpt;
|
||||
break;
|
||||
}
|
||||
var linePath = (line.Layer == LayerType.Leadin || line.Layer == LayerType.Leadout)
|
||||
? leadPath : cutPath;
|
||||
AddLine(linePath, line, mode, ref curpos);
|
||||
break;
|
||||
|
||||
case CodeType.RapidMove:
|
||||
AddLine(cutPath, (RapidMove)code, mode, ref curpos);
|
||||
break;
|
||||
|
||||
case CodeType.SubProgramCall:
|
||||
var tmpmode = mode;
|
||||
var subpgm = (SubProgramCall)code;
|
||||
if (subpgm.Program != null)
|
||||
{
|
||||
cutPath.StartFigure();
|
||||
leadPath.StartFigure();
|
||||
AddProgramSplit(cutPath, leadPath, subpgm.Program, mode, ref curpos);
|
||||
}
|
||||
mode = tmpmode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddArc(GraphicsPath path, ArcMove arc, Mode mode, ref Vector curpos)
|
||||
{
|
||||
var endpt = arc.EndPoint;
|
||||
|
||||
+26
-2
@@ -15,6 +15,7 @@ namespace OpenNest
|
||||
private static Color selectedColor;
|
||||
private static Pen selectedPen;
|
||||
private static Brush selectedBrush;
|
||||
private static Pen leadInPen;
|
||||
|
||||
private Color color;
|
||||
private Brush brush;
|
||||
@@ -34,6 +35,7 @@ namespace OpenNest
|
||||
{
|
||||
programIdFont = new Font(SystemFonts.DefaultFont, FontStyle.Bold | FontStyle.Underline);
|
||||
SelectedColor = Color.FromArgb(90, 150, 200, 255);
|
||||
leadInPen = new Pen(Color.OrangeRed, 1.5f);
|
||||
}
|
||||
|
||||
private LayoutPart(Part part)
|
||||
@@ -52,6 +54,8 @@ namespace OpenNest
|
||||
|
||||
public GraphicsPath Path { get; private set; }
|
||||
|
||||
public GraphicsPath LeadInPath { get; private set; }
|
||||
|
||||
public Color Color
|
||||
{
|
||||
get { return color; }
|
||||
@@ -83,6 +87,9 @@ namespace OpenNest
|
||||
g.FillPath(brush, Path);
|
||||
g.DrawPath(pen, Path);
|
||||
}
|
||||
|
||||
if (LeadInPath != null)
|
||||
g.DrawPath(leadInPen, LeadInPath);
|
||||
}
|
||||
|
||||
public void Draw(Graphics g, string id)
|
||||
@@ -98,6 +105,9 @@ namespace OpenNest
|
||||
g.DrawPath(pen, Path);
|
||||
}
|
||||
|
||||
if (LeadInPath != null)
|
||||
g.DrawPath(leadInPen, LeadInPath);
|
||||
|
||||
using var sf = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Center,
|
||||
@@ -138,8 +148,22 @@ namespace OpenNest
|
||||
|
||||
public void Update(DrawControl plateView)
|
||||
{
|
||||
Path = GraphicsHelper.GetGraphicsPath(BasePart.Program, BasePart.Location);
|
||||
Path.Transform(plateView.Matrix);
|
||||
if (BasePart.HasManualLeadIns)
|
||||
{
|
||||
BasePart.Program.GetGraphicsPaths(BasePart.Location, out var cutPath, out var leadPath);
|
||||
cutPath.Transform(plateView.Matrix);
|
||||
leadPath.Transform(plateView.Matrix);
|
||||
Path = cutPath;
|
||||
LeadInPath?.Dispose();
|
||||
LeadInPath = leadPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
Path = GraphicsHelper.GetGraphicsPath(BasePart.Program, BasePart.Location);
|
||||
Path.Transform(plateView.Matrix);
|
||||
LeadInPath?.Dispose();
|
||||
LeadInPath = null;
|
||||
}
|
||||
|
||||
_labelPoint ??= ComputeLabelPoint();
|
||||
var rotatedLabel = _labelPoint.Value.Rotate(BasePart.Rotation);
|
||||
|
||||
Reference in New Issue
Block a user