Compare commits
4 Commits
a6c2235647
...
24babe353e
| Author | SHA1 | Date | |
|---|---|---|---|
| 24babe353e | |||
| e63be93051 | |||
| ba3c3cbea3 | |||
| 572fa06a21 |
@@ -211,8 +211,5 @@ FakesAssemblies/
|
||||
.superpowers/
|
||||
docs/superpowers/
|
||||
|
||||
# Documentation (manuals, templates, etc.)
|
||||
docs/
|
||||
|
||||
# Launch settings
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
@@ -288,6 +288,10 @@ namespace OpenNest.CNC
|
||||
|
||||
private Box BoundingBox(ref Vector pos)
|
||||
{
|
||||
// Capture the frame origin at entry. Sub-program Offsets and
|
||||
// absolute-mode endpoints are relative to this fixed origin.
|
||||
var frameOrigin = pos;
|
||||
|
||||
double minX = 0.0;
|
||||
double minY = 0.0;
|
||||
double maxX = 0.0;
|
||||
@@ -303,7 +307,7 @@ namespace OpenNest.CNC
|
||||
{
|
||||
var line = (LinearMove)code;
|
||||
var pt = Mode == Mode.Absolute ?
|
||||
line.EndPoint :
|
||||
frameOrigin + line.EndPoint :
|
||||
line.EndPoint + pos;
|
||||
|
||||
if (pt.X > maxX)
|
||||
@@ -325,7 +329,7 @@ namespace OpenNest.CNC
|
||||
{
|
||||
var line = (RapidMove)code;
|
||||
var pt = Mode == Mode.Absolute
|
||||
? line.EndPoint
|
||||
? frameOrigin + line.EndPoint
|
||||
: line.EndPoint + pos;
|
||||
|
||||
if (pt.X > maxX)
|
||||
@@ -358,8 +362,8 @@ namespace OpenNest.CNC
|
||||
}
|
||||
else
|
||||
{
|
||||
endpt = arc.EndPoint;
|
||||
centerpt = arc.CenterPoint;
|
||||
endpt = frameOrigin + arc.EndPoint;
|
||||
centerpt = frameOrigin + arc.CenterPoint;
|
||||
}
|
||||
|
||||
double minX1;
|
||||
@@ -433,10 +437,13 @@ namespace OpenNest.CNC
|
||||
case CodeType.SubProgramCall:
|
||||
{
|
||||
var subpgm = (SubProgramCall)code;
|
||||
var subPos = subpgm.Offset.X != 0 || subpgm.Offset.Y != 0
|
||||
? new Vector(subpgm.Offset.X, subpgm.Offset.Y)
|
||||
: pos;
|
||||
var box = subpgm.Program.BoundingBox(ref subPos);
|
||||
if (subpgm.Program == null)
|
||||
break;
|
||||
|
||||
// Sub-program frame origin in this program's frame
|
||||
// is frameOrigin + Offset, regardless of current pos.
|
||||
pos = frameOrigin + subpgm.Offset;
|
||||
var box = subpgm.Program.BoundingBox(ref pos);
|
||||
|
||||
if (box.Left < minX)
|
||||
minX = box.Left;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using OpenNest.Geometry;
|
||||
using System.Text;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
|
||||
namespace OpenNest.CNC
|
||||
@@ -90,9 +91,13 @@ namespace OpenNest.CNC
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"G65 P{Id}");
|
||||
if (Offset.X != 0 || Offset.Y != 0)
|
||||
return string.Format("G65 P{0} X{1} Y{2}", Id, Offset.X, Offset.Y);
|
||||
return string.Format("G65 P{0} R{1}", Id, Rotation);
|
||||
sb.Append($" X{Offset.X} Y{Offset.Y}");
|
||||
if (Rotation != 0)
|
||||
sb.Append($" R{Rotation}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Converters
|
||||
@@ -9,7 +9,6 @@ namespace OpenNest.Converters
|
||||
/// Converts the program to absolute coordinates.
|
||||
/// Does NOT check program mode before converting.
|
||||
/// </summary>
|
||||
/// <param name="pgm"></param>
|
||||
public static void ToAbsolute(Program pgm)
|
||||
{
|
||||
var pos = new Vector(0, 0);
|
||||
@@ -17,21 +16,27 @@ namespace OpenNest.Converters
|
||||
for (int i = 0; i < pgm.Codes.Count; ++i)
|
||||
{
|
||||
var code = pgm.Codes[i];
|
||||
var motion = code as Motion;
|
||||
|
||||
if (motion != null)
|
||||
if (code is SubProgramCall subCall && subCall.Program != null)
|
||||
{
|
||||
motion.Offset(pos);
|
||||
// Sub-program is placed at Offset in this program's frame.
|
||||
// After it runs, the tool is at Offset + (sub's end in its own frame).
|
||||
pos = ComputeEndPosition(subCall.Program, subCall.Offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code is Motion motion)
|
||||
{
|
||||
motion.Offset(pos.X, pos.Y);
|
||||
pos = motion.EndPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the program to intermental coordinates.
|
||||
/// Converts the program to incremental coordinates.
|
||||
/// Does NOT check program mode before converting.
|
||||
/// </summary>
|
||||
/// <param name="pgm"></param>
|
||||
public static void ToIncremental(Program pgm)
|
||||
{
|
||||
var pos = new Vector(0, 0);
|
||||
@@ -39,9 +44,16 @@ namespace OpenNest.Converters
|
||||
for (int i = 0; i < pgm.Codes.Count; ++i)
|
||||
{
|
||||
var code = pgm.Codes[i];
|
||||
var motion = code as Motion;
|
||||
|
||||
if (motion != null)
|
||||
if (code is SubProgramCall subCall && subCall.Program != null)
|
||||
{
|
||||
// Sub-program is placed at Offset in this program's frame,
|
||||
// regardless of where the tool was before the call.
|
||||
pos = ComputeEndPosition(subCall.Program, subCall.Offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code is Motion motion)
|
||||
{
|
||||
var pos2 = motion.EndPoint;
|
||||
motion.Offset(-pos.X, -pos.Y);
|
||||
@@ -49,5 +61,37 @@ namespace OpenNest.Converters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the tool position after executing <paramref name="pgm"/>,
|
||||
/// given that the program's frame origin is at <paramref name="startPos"/>
|
||||
/// in the caller's frame. Walks nested sub-program calls recursively.
|
||||
/// </summary>
|
||||
private static Vector ComputeEndPosition(Program pgm, Vector startPos)
|
||||
{
|
||||
var pos = startPos;
|
||||
|
||||
for (int i = 0; i < pgm.Codes.Count; ++i)
|
||||
{
|
||||
var code = pgm.Codes[i];
|
||||
|
||||
if (code is SubProgramCall subCall && subCall.Program != null)
|
||||
{
|
||||
// Nested sub's frame origin in the caller's frame is startPos + Offset.
|
||||
pos = ComputeEndPosition(subCall.Program, startPos + subCall.Offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code is Motion motion)
|
||||
{
|
||||
if (pgm.Mode == Mode.Incremental)
|
||||
pos = pos + motion.EndPoint;
|
||||
else
|
||||
pos = startPos + motion.EndPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ namespace OpenNest.Converters
|
||||
|
||||
private static void AddProgram(Program program, ref Mode mode, ref Vector curpos, ref List<Entity> geometry)
|
||||
{
|
||||
// Capture the frame origin at entry. Sub-program Offsets are relative
|
||||
// to this fixed origin, not to the current tool position.
|
||||
var frameOrigin = curpos;
|
||||
mode = program.Mode;
|
||||
|
||||
for (int i = 0; i < program.Length; ++i)
|
||||
@@ -43,20 +46,13 @@ namespace OpenNest.Converters
|
||||
case CodeType.SubProgramCall:
|
||||
var subpgm = (SubProgramCall)code;
|
||||
var savedMode = mode;
|
||||
var savedPos = curpos;
|
||||
|
||||
// Position the sub-program at savedPos + Offset.
|
||||
// savedPos is the base position ((0,0) here, Part.Location in rendering).
|
||||
// Offset is the hole center in drawing-local coordinates.
|
||||
curpos = new Vector(savedPos.X + subpgm.Offset.X, savedPos.Y + subpgm.Offset.Y);
|
||||
// The sub-program's frame origin in this program's frame is
|
||||
// frameOrigin + Offset — independent of current tool position.
|
||||
curpos = new Vector(frameOrigin.X + subpgm.Offset.X, frameOrigin.Y + subpgm.Offset.Y);
|
||||
|
||||
AddProgram(subpgm.Program, ref mode, ref curpos, ref geometry);
|
||||
mode = savedMode;
|
||||
|
||||
// Restore curpos: ConvertMode.ToIncremental skips SubProgramCalls
|
||||
// when computing deltas, so subsequent incremental codes expect
|
||||
// curpos to be where it was before the call.
|
||||
curpos = savedPos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,12 +226,23 @@ public sealed class CincinnatiSheetWriter
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + featureIndex + 1;
|
||||
|
||||
// Shift the local origin to the hole center via G52 (manual §1.52).
|
||||
// G52 does not move the nozzle, so the sub-program's first rapid
|
||||
// (the lead-in to the pierce point) takes the tool straight from the
|
||||
// previous feature's end to pierce. The hole sub-program is authored
|
||||
// in hole-local coordinates and resolves to `hole + local` under the
|
||||
// shift. See docs/cincinnati-post-output.md for the full bracket.
|
||||
var sb = new StringBuilder();
|
||||
if (_config.UseLineNumbers)
|
||||
sb.Append($"N{featureNumber} ");
|
||||
sb.Append($"M98 P{postSubNum} X{_fmt.FormatCoord(call.Offset.X)} Y{_fmt.FormatCoord(call.Offset.Y)}");
|
||||
sb.Append($"G52 X{_fmt.FormatCoord(call.Offset.X)} Y{_fmt.FormatCoord(call.Offset.Y)}");
|
||||
w.WriteLine(sb.ToString());
|
||||
|
||||
w.WriteLine($"M98 P{postSubNum}");
|
||||
|
||||
// Cancel the local shift (manual §1.52).
|
||||
w.WriteLine("G52 X0 Y0");
|
||||
|
||||
if (!isLastFeature)
|
||||
w.WriteLine("M47");
|
||||
}
|
||||
|
||||
@@ -44,6 +44,25 @@ public class HoleSubProgramTests
|
||||
Assert.Contains("Y2.5", str);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubProgramCall_ToString_IncludesOffsetAndRotation()
|
||||
{
|
||||
var call = new SubProgramCall { Id = 1000, Offset = new Vector(1.5, 2.5), Rotation = 30 };
|
||||
var str = call.ToString();
|
||||
Assert.Contains("P1000", str);
|
||||
Assert.Contains("X1.5", str);
|
||||
Assert.Contains("Y2.5", str);
|
||||
Assert.Contains("R30", str);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubProgramCall_ToString_OmitsZeroFields()
|
||||
{
|
||||
var call = new SubProgramCall { Id = 1000 };
|
||||
var str = call.ToString();
|
||||
Assert.Equal("G65 P1000", str);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Program_SubPrograms_EmptyByDefault()
|
||||
{
|
||||
|
||||
@@ -9,6 +9,12 @@ namespace OpenNest.Controls
|
||||
{
|
||||
public static void DrawProgram(Graphics g, DrawControl view, Program pgm, ref Vector pos,
|
||||
Pen pen, double spacing, float arrowSize)
|
||||
{
|
||||
DrawProgram(g, view, pgm, pos, ref pos, pen, spacing, arrowSize);
|
||||
}
|
||||
|
||||
private static void DrawProgram(Graphics g, DrawControl view, Program pgm, Vector basePos, ref Vector pos,
|
||||
Pen pen, double spacing, float arrowSize)
|
||||
{
|
||||
for (var i = 0; i < pgm.Length; ++i)
|
||||
{
|
||||
@@ -19,10 +25,9 @@ namespace OpenNest.Controls
|
||||
var subpgm = (SubProgramCall)code;
|
||||
if (subpgm.Program != null)
|
||||
{
|
||||
var savedPos = pos;
|
||||
pos = new Vector(savedPos.X + subpgm.Offset.X, savedPos.Y + subpgm.Offset.Y);
|
||||
DrawProgram(g, view, subpgm.Program, ref pos, pen, spacing, arrowSize);
|
||||
pos = savedPos;
|
||||
var holeBase = basePos + subpgm.Offset;
|
||||
pos = holeBase;
|
||||
DrawProgram(g, view, subpgm.Program, holeBase, ref pos, pen, spacing, arrowSize);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -31,7 +36,7 @@ namespace OpenNest.Controls
|
||||
|
||||
var endpt = pgm.Mode == Mode.Incremental
|
||||
? motion.EndPoint + pos
|
||||
: motion.EndPoint;
|
||||
: motion.EndPoint + basePos;
|
||||
|
||||
if (code.Type == CodeType.LinearMove)
|
||||
{
|
||||
@@ -46,7 +51,7 @@ namespace OpenNest.Controls
|
||||
{
|
||||
var center = pgm.Mode == Mode.Incremental
|
||||
? arc.CenterPoint + pos
|
||||
: arc.CenterPoint;
|
||||
: arc.CenterPoint + basePos;
|
||||
DrawArcArrows(g, view, pos, endpt, center, arc.Rotation, pen, spacing, arrowSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,8 +395,8 @@ namespace OpenNest.Controls
|
||||
var piercePoint = GetFirstPiercePoint(pgm, part.Location);
|
||||
DrawLine(g, pos, piercePoint, view.ColorScheme.RapidPen);
|
||||
|
||||
pos = part.Location;
|
||||
DrawRapids(g, pgm, ref pos, skipFirstRapid: true);
|
||||
pos = piercePoint;
|
||||
DrawRapids(g, pgm, part.Location, ref pos, skipFirstRapid: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,15 +409,13 @@ namespace OpenNest.Controls
|
||||
|
||||
if (pgm[i] is Motion motion)
|
||||
{
|
||||
if (pgm.Mode == Mode.Incremental)
|
||||
return motion.EndPoint + partLocation;
|
||||
return motion.EndPoint;
|
||||
}
|
||||
}
|
||||
return partLocation;
|
||||
}
|
||||
|
||||
private void DrawRapids(Graphics g, Program pgm, ref Vector pos, bool skipFirstRapid = false)
|
||||
private void DrawRapids(Graphics g, Program pgm, Vector basePos, ref Vector pos, bool skipFirstRapid = false)
|
||||
{
|
||||
var firstRapidSkipped = false;
|
||||
|
||||
@@ -425,60 +423,47 @@ namespace OpenNest.Controls
|
||||
{
|
||||
var code = pgm[i];
|
||||
|
||||
if (code.Type == CodeType.SubProgramCall)
|
||||
if (code is SubProgramCall { Program: { } program } call)
|
||||
{
|
||||
var subpgm = (SubProgramCall)code;
|
||||
var program = subpgm.Program;
|
||||
// A SubProgramCall is a coordinate-frame shift, not a physical
|
||||
// rapid to the hole center. The Cincinnati post emits it as a
|
||||
// G52 bracket, so the physical rapid is the sub-program's first
|
||||
// motion, which goes straight from here to the lead-in pierce.
|
||||
// Look ahead for that pierce point and draw the direct rapid,
|
||||
// then recurse with skipFirstRapid so the sub doesn't also draw
|
||||
// its first rapid on top. See docs/cincinnati-post-output.md.
|
||||
var holeBase = basePos + call.Offset;
|
||||
var firstPierce = GetFirstPiercePoint(program, holeBase);
|
||||
|
||||
if (program != null)
|
||||
{
|
||||
var holePos = new Vector(pos.X + subpgm.Offset.X, pos.Y + subpgm.Offset.Y);
|
||||
if (ShouldDrawRapid(skipFirstRapid, ref firstRapidSkipped))
|
||||
DrawLine(g, pos, firstPierce, view.ColorScheme.RapidPen);
|
||||
|
||||
// Draw rapid from current position to hole center
|
||||
if (!(skipFirstRapid && !firstRapidSkipped))
|
||||
DrawLine(g, pos, holePos, view.ColorScheme.RapidPen);
|
||||
else
|
||||
firstRapidSkipped = true;
|
||||
|
||||
pos = holePos;
|
||||
DrawRapids(g, program, ref pos);
|
||||
// Don't restore pos — let it advance so the next hole's
|
||||
// rapid starts from where this one ended.
|
||||
var subPos = holeBase;
|
||||
DrawRapids(g, program, holeBase, ref subPos, skipFirstRapid: true);
|
||||
pos = subPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (code is Motion motion)
|
||||
{
|
||||
var motion = code as Motion;
|
||||
var endpt = pgm.Mode == Mode.Incremental
|
||||
? motion.EndPoint + pos
|
||||
: motion.EndPoint;
|
||||
|
||||
if (motion != null)
|
||||
{
|
||||
if (pgm.Mode == Mode.Incremental)
|
||||
{
|
||||
var endpt = motion.EndPoint + pos;
|
||||
|
||||
if (code.Type == CodeType.RapidMove)
|
||||
{
|
||||
if (skipFirstRapid && !firstRapidSkipped)
|
||||
firstRapidSkipped = true;
|
||||
else
|
||||
if (code.Type == CodeType.RapidMove && ShouldDrawRapid(skipFirstRapid, ref firstRapidSkipped))
|
||||
DrawLine(g, pos, endpt, view.ColorScheme.RapidPen);
|
||||
}
|
||||
|
||||
pos = endpt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (code.Type == CodeType.RapidMove)
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldDrawRapid(bool skipFirstRapid, ref bool firstRapidSkipped)
|
||||
{
|
||||
if (skipFirstRapid && !firstRapidSkipped)
|
||||
{
|
||||
firstRapidSkipped = true;
|
||||
else
|
||||
DrawLine(g, pos, motion.EndPoint, view.ColorScheme.RapidPen);
|
||||
}
|
||||
pos = motion.EndPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DrawAllPiercePoints(Graphics g)
|
||||
@@ -491,11 +476,11 @@ namespace OpenNest.Controls
|
||||
var part = view.Plate.Parts[i];
|
||||
var pgm = part.Program;
|
||||
var pos = part.Location;
|
||||
DrawProgramPiercePoints(g, pgm, ref pos, brush, pen);
|
||||
DrawProgramPiercePoints(g, pgm, part.Location, ref pos, brush, pen);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawProgramPiercePoints(Graphics g, Program pgm, ref Vector pos, Brush brush, Pen pen)
|
||||
private void DrawProgramPiercePoints(Graphics g, Program pgm, Vector basePos, ref Vector pos, Brush brush, Pen pen)
|
||||
{
|
||||
for (var i = 0; i < pgm.Length; ++i)
|
||||
{
|
||||
@@ -506,10 +491,9 @@ namespace OpenNest.Controls
|
||||
var subpgm = (SubProgramCall)code;
|
||||
if (subpgm.Program != null)
|
||||
{
|
||||
var savedPos = pos;
|
||||
pos = new Vector(savedPos.X + subpgm.Offset.X, savedPos.Y + subpgm.Offset.Y);
|
||||
DrawProgramPiercePoints(g, subpgm.Program, ref pos, brush, pen);
|
||||
pos = savedPos;
|
||||
var holeBase = basePos + subpgm.Offset;
|
||||
pos = holeBase;
|
||||
DrawProgramPiercePoints(g, subpgm.Program, holeBase, ref pos, brush, pen);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -519,7 +503,7 @@ namespace OpenNest.Controls
|
||||
|
||||
var endpt = pgm.Mode == Mode.Incremental
|
||||
? motion.EndPoint + pos
|
||||
: motion.EndPoint;
|
||||
: motion.EndPoint + basePos;
|
||||
|
||||
if (code.Type == CodeType.RapidMove)
|
||||
{
|
||||
|
||||
@@ -98,6 +98,9 @@ namespace OpenNest
|
||||
private static void AddProgramSplit(GraphicsPath cutPath, GraphicsPath leadPath,
|
||||
Program pgm, Mode mode, ref Vector curpos)
|
||||
{
|
||||
// Capture the frame origin at entry. Sub-program Offsets are relative
|
||||
// to this fixed origin, not to the current tool position.
|
||||
var frameOrigin = curpos;
|
||||
mode = pgm.Mode;
|
||||
|
||||
for (var i = 0; i < pgm.Length; ++i)
|
||||
@@ -147,10 +150,8 @@ namespace OpenNest
|
||||
{
|
||||
cutPath.StartFigure();
|
||||
leadPath.StartFigure();
|
||||
var savedPos = curpos;
|
||||
curpos = new Vector(savedPos.X + subpgm.Offset.X, savedPos.Y + subpgm.Offset.Y);
|
||||
curpos = new Vector(frameOrigin.X + subpgm.Offset.X, frameOrigin.Y + subpgm.Offset.Y);
|
||||
AddProgramSplit(cutPath, leadPath, subpgm.Program, mode, ref curpos);
|
||||
curpos = savedPos;
|
||||
}
|
||||
mode = tmpmode;
|
||||
break;
|
||||
@@ -240,6 +241,9 @@ namespace OpenNest
|
||||
|
||||
private static void AddProgram(GraphicsPath path, Program pgm, Mode mode, ref Vector curpos)
|
||||
{
|
||||
// Capture the frame origin at entry. Sub-program Offsets are relative
|
||||
// to this fixed origin, not to the current tool position.
|
||||
var frameOrigin = curpos;
|
||||
mode = pgm.Mode;
|
||||
GraphicsPath currentFigure = null;
|
||||
|
||||
@@ -308,10 +312,8 @@ namespace OpenNest
|
||||
|
||||
if (subpgm.Program != null)
|
||||
{
|
||||
var savedPos = curpos;
|
||||
curpos = new Vector(savedPos.X + subpgm.Offset.X, savedPos.Y + subpgm.Offset.Y);
|
||||
curpos = new Vector(frameOrigin.X + subpgm.Offset.X, frameOrigin.Y + subpgm.Offset.Y);
|
||||
AddProgram(path, subpgm.Program, mode, ref curpos);
|
||||
curpos = savedPos;
|
||||
}
|
||||
|
||||
mode = tmpmode;
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,212 @@
|
||||
# Cincinnati Post Output Reference
|
||||
|
||||
Reference for the G-code structure emitted by `OpenNest.Posts.Cincinnati`.
|
||||
Every code listed here maps to a section in the Cincinnati Laser Programming
|
||||
Manual (`docs/CINCINNATI LASER PROGRAMMING MANUAL.pdf`, EM-423 R-02/11).
|
||||
Section numbers in parentheses (e.g. `§1.52`) refer to the manual.
|
||||
|
||||
If you add a new emission in the post, either cite the manual section it maps
|
||||
to, or flag it here as a known custom extension. "Custom code" in this project
|
||||
means something that is not documented in the manual but that the Cincinnati
|
||||
control is known to accept — none exist today and we should not introduce any
|
||||
without confirming the control behavior.
|
||||
|
||||
## Overall file structure
|
||||
|
||||
A generated file contains, in order:
|
||||
|
||||
1. **Main program** (`CincinnatiPreambleWriter.WriteMainProgram`)
|
||||
Preamble, unit/mode setup, initial library, variable-declaration call, one
|
||||
`M98 P<sheetSubNum>` call per plate quantity, and `M30` to end.
|
||||
|
||||
2. **Variable declaration sub-program** (`CincinnatiPreambleWriter.WriteVariableDeclaration`)
|
||||
Machine variables (`#number = value`) used across the nest, terminated
|
||||
with `M99`.
|
||||
|
||||
3. **Sheet sub-programs** (`CincinnatiSheetWriter.Write`), one per unique plate
|
||||
layout. A sheet sub-program contains the cutting sequence for a whole
|
||||
plate, either with features inlined or with `M98` calls into part
|
||||
sub-programs.
|
||||
|
||||
4. **Part sub-programs** (`CincinnatiPartSubprogramWriter.Write`), one per
|
||||
unique `(drawing, rotation)` pair, only emitted when
|
||||
`Config.UsePartSubprograms` is enabled.
|
||||
|
||||
5. **Hole sub-programs** (`CincinnatiPartSubprogramWriter.Write` reused with a
|
||||
`"HOLE"` label), one per unique hole geometry keyed by radius and lead-in
|
||||
normal angle.
|
||||
|
||||
Sub-program bodies start with a `:<subNum>` label and end with `M99`.
|
||||
|
||||
## Feature blocks
|
||||
|
||||
A "feature" is a single contour: lead-in → cut moves → lead-out. Each feature
|
||||
block in a sheet or sub-program output follows this order
|
||||
(`CincinnatiFeatureWriter.Write`):
|
||||
|
||||
1. `G0 X_ Y_` — rapid to the pierce point (§1.00).
|
||||
2. Optional part-name comment, only on the first feature of each part.
|
||||
3. `G89 P<library>` — load process parameters (§2.89). `P` is a library file
|
||||
name; the `(...)` trailing comment carries speed-class info.
|
||||
4. `G84` (cut) or `G85` (etch / no-pierce) — pierce and start cut, or start
|
||||
cut without pierce (§2.84 / §2.85).
|
||||
5. `M130 (ANTI DIVE OFF)` — disable anti-dive, only if configured (§3.130).
|
||||
6. Contour moves:
|
||||
- `G41` (left) or `G42` (right) kerf compensation on the first cut move
|
||||
(§1.41 / §1.42), suppressed for etch features.
|
||||
- `G1 X_ Y_ [F<feedvar>]` — linear cut move (§1.01). Feedrate references a
|
||||
machine variable such as `#148` and is emitted only when it changes.
|
||||
- `G2 X_ Y_ I_ J_ [F<feedvar>]` (CW) or `G3` (CCW) — arc (§1.02 / §1.03).
|
||||
`I`/`J` are incremental offsets from the current position to the center.
|
||||
7. `G40` — cancel kerf compensation (§1.40), only if it was applied.
|
||||
8. `M35` (or `M135` if SpeedGas is enabled) — beam off (§3.35 / §3.135).
|
||||
9. `M131 (ANTI DIVE ON)` — re-enable anti-dive (§3.131).
|
||||
10. `M47` or `M47 P<distance>` — raise Z-axis, unless this is the last feature
|
||||
on the sheet (§3.47). A leading `/` (block delete, §5.6) is prepended when
|
||||
the configured override distance exceeds the default.
|
||||
|
||||
Sheet sub-program and sheet-level feature calls add `G92 X#5021 Y#5022`
|
||||
(§1.92) at the top so the local origin is anchored to the machine's current
|
||||
absolute position (`#5021`/`#5022` are the machine X/Y system variables).
|
||||
|
||||
## Sub-program call patterns
|
||||
|
||||
There are two distinct call-site patterns, depending on whether the call
|
||||
targets a whole-part sub-program or a hole sub-program.
|
||||
|
||||
### Part sub-program call (`WriteSubprogramCall`)
|
||||
|
||||
Used when `Config.UsePartSubprograms` is enabled. The tool physically rapids
|
||||
to the part corner, then G92 sets the current position as the local origin,
|
||||
the sub-program executes in its own local coordinate frame, and G92 restores
|
||||
the original absolute position after return.
|
||||
|
||||
```
|
||||
G0 X<left> Y<bottom> ; rapid to part bounding box corner (§1.00)
|
||||
(PART: <name>)
|
||||
G92 X0 Y0 ; set local origin at current position (§1.92)
|
||||
M98 P<partSubNum> (<name>) ; call the part sub-program (§3.98)
|
||||
G92 X<left> Y<bottom> ; restore the sheet coordinate system (§1.92)
|
||||
M47 ; head raise unless this is the last part (§3.47)
|
||||
```
|
||||
|
||||
This pattern uses G92 because the tool is physically positioned at the part
|
||||
corner first. The sub-program's coordinates are part-local, so they are
|
||||
interpreted against the new origin until G92 restores the sheet frame.
|
||||
|
||||
### Hole sub-program call (`WriteHoleSubprogramCall`)
|
||||
|
||||
Used for the `SubProgramCall` codes that a `ContourCuttingStrategy` emits for
|
||||
each circular hole. Unlike parts, we do **not** want a physical rapid to the
|
||||
hole center before calling — the sub-program's first rapid is the lead-in to
|
||||
the pierce point, and the machine should travel directly from the previous
|
||||
feature's end to that pierce.
|
||||
|
||||
```
|
||||
G52 X<hole.x> Y<hole.y> ; shift local origin to hole center (§1.52)
|
||||
M98 P<holeSubNum> ; call the shared hole sub-program (§3.98)
|
||||
G52 X0 Y0 ; restore the original coordinate system (§1.52)
|
||||
M47 ; head raise unless this is the last feature (§3.47)
|
||||
```
|
||||
|
||||
G52 specifies the new origin in the current work coordinate system and — per
|
||||
§1.52 — "does not move the cutting nozzle". The hole sub-program is written
|
||||
in hole-local coordinates (origin at the hole center, produced by
|
||||
`ContourCuttingStrategy`), so its first `G0 X_ Y_` resolves to `hole + local`
|
||||
in absolute terms. That is the first physical motion, and it takes the tool
|
||||
straight from wherever it was to the lead-in pierce point. G52 X0 Y0 cancels
|
||||
the shift after `M99` returns control.
|
||||
|
||||
## G-code reference
|
||||
|
||||
These are every G/M code the post emits, grouped by category. Anything here is
|
||||
documented in the programming manual. Anything not here should be audited the
|
||||
next time the post is edited.
|
||||
|
||||
### Motion modes and contouring
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `G0 X_ Y_` | Rapid traverse | §1.00 |
|
||||
| `G1 X_ Y_ F_` | Linear feedrate move | §1.01 |
|
||||
| `G2 X_ Y_ I_ J_ F_` | Clockwise arc | §1.02 |
|
||||
| `G3 X_ Y_ I_ J_ F_` | Counter-clockwise arc | §1.03 |
|
||||
|
||||
### Units and coordinate mode
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `G20` | Inch mode | §1.20 |
|
||||
| `G21` | Metric mode | §1.21 |
|
||||
| `G90` | Absolute mode | §1.90 |
|
||||
|
||||
### Kerf compensation
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `G40` | Cancel kerf compensation | §1.40 |
|
||||
| `G41` | Kerf compensation, left side | §1.41 |
|
||||
| `G42` | Kerf compensation, right side | §1.42 |
|
||||
|
||||
### Work coordinate systems
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `G52 X_ Y_` | Temporary local work coordinate offset. Does not move the tool. `G52 X0 Y0` cancels. | §1.52 |
|
||||
| `G92 X_ Y_` | Sets the current tool position to `(X, Y)` in the work coordinate system, implicitly redefining the WCS origin. | §1.92 |
|
||||
|
||||
### Exact stop
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `G61` | Exact stop mode | §1.61 |
|
||||
|
||||
### Cutting operations (custom Cincinnati G-codes)
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `G84` | Pierce and start cut | §2.84 |
|
||||
| `G85` | Start cut without pierce (used for etch) | §2.85 |
|
||||
| `G89 P<file>` | Load process parameters from a library file | §2.89 |
|
||||
| `G121` | Enable non-stop cutting (Smart Rapids) | §2.121 |
|
||||
|
||||
### Program flow
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `M30` | End of main program with rewind | §3.30 |
|
||||
| `M98 P_` | Sub-program call. **Takes only `P` and `L` — not `X`/`Y`.** | §3.98 |
|
||||
| `M99` | Return from sub-program | §3.99 |
|
||||
|
||||
### Machine state
|
||||
|
||||
| Code | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `M35` | Beam off | §3.35 |
|
||||
| `M42` | Retract Z-axis | §3.42 |
|
||||
| `M47 [P<dist>]` | Raise Z-axis, optionally by a distance | §3.47 |
|
||||
| `M50` | Switch pallets | §3.50 |
|
||||
| `M130` | Anti-dive off | §3.130 |
|
||||
| `M131` | Anti-dive on | §3.131 |
|
||||
| `M135` | Discharge current off (keeps assist gas on) | §3.135 |
|
||||
|
||||
### Comments, labels, and block delete
|
||||
|
||||
| Syntax | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `(text)` | Inline comment | §5.4 |
|
||||
| `:<number>` | Sub-program label | §3.98 |
|
||||
| `/<block>` | Block delete — operator can toggle the line off | §5.6 |
|
||||
| `N<number>` | Line number, used by M99 P / GOTO targets | §5.5 |
|
||||
|
||||
## System variables referenced
|
||||
|
||||
| Variable | Description | Manual |
|
||||
| --- | --- | --- |
|
||||
| `#148` | Default cut feedrate variable (used in `F#148`) | §2.89 |
|
||||
| `#5021` | Current machine X position | §6 (table of system variables) |
|
||||
| `#5022` | Current machine Y position | §6 (table of system variables) |
|
||||
|
||||
Project-defined variables start at `Config.SheetWidthVariable` /
|
||||
`Config.SheetLengthVariable` and at `Config.UserVariableStart`. Those ranges
|
||||
are documented in `CincinnatiPostConfig.cs`.
|
||||
Reference in New Issue
Block a user