style: apply CSharpier formatting to files merged from arc-tangency branch

This commit is contained in:
aj
2026-09-20 16:54:16 -04:00
parent 54694f9b17
commit 27684c3782
12 changed files with 790 additions and 260 deletions
+299 -82
View File
@@ -48,16 +48,99 @@ namespace OpenNest.Posts.GravographIS
// fixed return-to-home block.
private static readonly byte[] PreambleTemplate = new byte[]
{
0x21, 0x41, 0x53, 0x20, 0x33, 0x38, 0x3b, 0x01, 0x90, 0x01,
0xf4, 0x01, 0x90, 0x01, 0xf4, 0x01, 0x90, 0x01, 0xf4, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x09, 0x00, 0x00, 0x03, 0xe8, 0x05, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfd, 0x32, 0x44, 0x00,
0x00, 0xff, 0xfd, 0x4d, 0x43, 0x00, 0x01, 0xff, 0xfd, 0x4f,
0x55, 0xff, 0xfb, 0xff, 0xfd, 0x4f, 0x55, 0xff, 0xfa, 0xff,
0xfd, 0x50, 0x5a, 0x00, 0x00, 0xff, 0xfd, 0x56, 0x53, 0x00,
0x23, 0xff, 0xfd, 0x56, 0x5a, 0x00, 0x23, 0xff, 0xfd, 0x44,
0x5a, 0x01, 0xfc,
0x21,
0x41,
0x53,
0x20,
0x33,
0x38,
0x3b,
0x01,
0x90,
0x01,
0xf4,
0x01,
0x90,
0x01,
0xf4,
0x01,
0x90,
0x01,
0xf4,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x09,
0x00,
0x00,
0x03,
0xe8,
0x05,
0x06,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0xff,
0xfd,
0x32,
0x44,
0x00,
0x00,
0xff,
0xfd,
0x4d,
0x43,
0x00,
0x01,
0xff,
0xfd,
0x4f,
0x55,
0xff,
0xfb,
0xff,
0xfd,
0x4f,
0x55,
0xff,
0xfa,
0xff,
0xfd,
0x50,
0x5a,
0x00,
0x00,
0xff,
0xfd,
0x56,
0x53,
0x00,
0x23,
0xff,
0xfd,
0x56,
0x5a,
0x00,
0x23,
0xff,
0xfd,
0x44,
0x5a,
0x01,
0xfc,
};
// Stripped 36-byte postamble: lift, aux off, motor off, operator beep,
@@ -73,11 +156,36 @@ namespace OpenNest.Posts.GravographIS
// lift + PU travel to the operator-set origin before these final commands.
private static readonly byte[] EndJobBytes = new byte[]
{
0xff, 0xfd, 0x4f, 0x55, 0xff, 0xfa, // OU 0xFFFA aux off
0xff, 0xfd, 0x4f, 0x55, 0xff, 0xfb, // OU 0xFFFB aux off
0xff, 0xfd, 0x4d, 0x43, 0x00, 0x00, // MC 0x0000 motor off
0xff, 0xfd, 0x4f, 0x50, 0x00, 0x00, // OP 0x0000 operator beep
0xff, 0xfd, 0x4a, 0x46, 0x00, 0x00, // JF 0x0000 job finish
0xff,
0xfd,
0x4f,
0x55,
0xff,
0xfa, // OU 0xFFFA aux off
0xff,
0xfd,
0x4f,
0x55,
0xff,
0xfb, // OU 0xFFFB aux off
0xff,
0xfd,
0x4d,
0x43,
0x00,
0x00, // MC 0x0000 motor off
0xff,
0xfd,
0x4f,
0x50,
0x00,
0x00, // OP 0x0000 operator beep
0xff,
0xfd,
0x4a,
0x46,
0x00,
0x00, // JF 0x0000 job finish
};
// 80 steps/mm × 25.4 mm/in
@@ -86,9 +194,7 @@ namespace OpenNest.Posts.GravographIS
public GravographISWriterOptions Options { get; }
public GravographISWriter()
: this(new GravographISWriterOptions())
{
}
: this(new GravographISWriterOptions()) { }
public GravographISWriter(GravographISWriterOptions options)
{
@@ -103,21 +209,25 @@ namespace OpenNest.Posts.GravographIS
/// </summary>
public void Write(IEnumerable<IReadOnlyList<Vector>> polylines, Stream output)
{
if (polylines == null) throw new ArgumentNullException(nameof(polylines));
if (polylines == null)
throw new ArgumentNullException(nameof(polylines));
// A single pass at the configured feed/depth — byte-identical to the
// original single-group output (no transitions, no pause).
Write(new[]
{
new GravographPass
Write(
new[]
{
Polylines = polylines,
FeedMmPerSec = Options.FeedMmPerSec,
DepthInches = Options.DepthInches,
PauseBefore = false,
PauseMessage = "",
new GravographPass
{
Polylines = polylines,
FeedMmPerSec = Options.FeedMmPerSec,
DepthInches = Options.DepthInches,
PauseBefore = false,
PauseMessage = "",
},
},
}, output);
output
);
}
/// <summary>
@@ -128,8 +238,10 @@ namespace OpenNest.Posts.GravographIS
/// </summary>
public void Write(IReadOnlyList<GravographPass> passes, Stream output)
{
if (passes == null) throw new ArgumentNullException(nameof(passes));
if (output == null) throw new ArgumentNullException(nameof(output));
if (passes == null)
throw new ArgumentNullException(nameof(passes));
if (output == null)
throw new ArgumentNullException(nameof(output));
var firstFeed = passes.Count > 0 ? passes[0].FeedMmPerSec : Options.FeedMmPerSec;
var firstDepth = passes.Count > 0 ? passes[0].DepthInches : Options.DepthInches;
@@ -146,10 +258,16 @@ namespace OpenNest.Posts.GravographIS
// catch bad records before they ship to the engraver.
var headX = 0;
var headY = 0;
var envelopeXSteps = (int)System.Math.Round(Options.WorkEnvelopeXMm * StepsPerMm,
MidpointRounding.AwayFromZero);
var envelopeYSteps = (int)System.Math.Round(Options.WorkEnvelopeYMm * StepsPerMm,
MidpointRounding.AwayFromZero);
var envelopeXSteps = (int)
System.Math.Round(
Options.WorkEnvelopeXMm * StepsPerMm,
MidpointRounding.AwayFromZero
);
var envelopeYSteps = (int)
System.Math.Round(
Options.WorkEnvelopeYMm * StepsPerMm,
MidpointRounding.AwayFromZero
);
var firstPolyline = true;
var polyIndex = 0;
@@ -167,9 +285,18 @@ namespace OpenNest.Posts.GravographIS
// Park: lift Z, then rapid (pen-up) back to the operator origin so
// the head is clear of the work while the tool is swapped.
WriteLiftOnly(output);
WriteTravel(output, (byte)'P', (byte)'U',
checked(-headX), checked(-headY),
ref headX, ref headY, envelopeXSteps, envelopeYSteps, polyIndex);
WriteTravel(
output,
(byte)'P',
(byte)'U',
checked(-headX),
checked(-headY),
ref headX,
ref headY,
envelopeXSteps,
envelopeYSteps,
polyIndex
);
WritePauseCore(output, pass.PauseMessage);
}
@@ -182,12 +309,18 @@ namespace OpenNest.Posts.GravographIS
if (pass.DepthInches != currentDepth)
{
WriteCommand(output, (byte)'D', (byte)'Z', DepthInStepsAsInt16(pass.DepthInches));
WriteCommand(
output,
(byte)'D',
(byte)'Z',
DepthInStepsAsInt16(pass.DepthInches)
);
currentDepth = pass.DepthInches;
}
}
if (pass.Polylines == null) continue;
if (pass.Polylines == null)
continue;
foreach (var poly in pass.Polylines)
{
@@ -195,31 +328,62 @@ namespace OpenNest.Posts.GravographIS
if (poly == null || poly.Count < 2)
continue;
WritePolyline(output, poly, ref firstPolyline, ref headX, ref headY,
envelopeXSteps, envelopeYSteps, polyIndex);
WritePolyline(
output,
poly,
ref firstPolyline,
ref headX,
ref headY,
envelopeXSteps,
envelopeYSteps,
polyIndex
);
}
}
WriteLiftOnly(output);
if (Options.ReturnToOriginAtEnd && !firstPolyline)
{
WriteTravel(output, (byte)'P', (byte)'U',
checked(-headX), checked(-headY),
ref headX, ref headY, envelopeXSteps, envelopeYSteps, polyIndex);
WriteTravel(
output,
(byte)'P',
(byte)'U',
checked(-headX),
checked(-headY),
ref headX,
ref headY,
envelopeXSteps,
envelopeYSteps,
polyIndex
);
}
output.Write(EndJobBytes, 0, EndJobBytes.Length);
}
private void WritePolyline(Stream output, IReadOnlyList<Vector> poly,
ref bool firstPolyline, ref int headX, ref int headY,
int envelopeXSteps, int envelopeYSteps, int polyIndex)
private void WritePolyline(
Stream output,
IReadOnlyList<Vector> poly,
ref bool firstPolyline,
ref int headX,
ref int headY,
int envelopeXSteps,
int envelopeYSteps,
int polyIndex
)
{
var (startX, startY) = ToWire(poly[0]);
WriteTravel(output,
WriteTravel(
output,
firstPolyline ? (byte)'D' : (byte)'P',
firstPolyline ? (byte)'R' : (byte)'U',
checked(startX - headX), checked(startY - headY),
ref headX, ref headY, envelopeXSteps, envelopeYSteps, polyIndex);
checked(startX - headX),
checked(startY - headY),
ref headX,
ref headY,
envelopeXSteps,
envelopeYSteps,
polyIndex
);
// PD command + single records-follow flag, then one record per segment.
output.WriteByte(0xFF);
@@ -236,8 +400,15 @@ namespace OpenNest.Posts.GravographIS
var (cx, cy) = ToWire(poly[i]);
var dx = checked(cx - prevX);
var dy = checked(cy - prevY);
EnsureEnvelope(headX + dx, headY + dy, envelopeXSteps, envelopeYSteps,
polyIndex, segment: i, isTravel: false);
EnsureEnvelope(
headX + dx,
headY + dy,
envelopeXSteps,
envelopeYSteps,
polyIndex,
segment: i,
isTravel: false
);
WriteRecord(output, dx, dy);
prevX = cx;
prevY = cy;
@@ -267,7 +438,8 @@ namespace OpenNest.Posts.GravographIS
// space-padded to a whole number of packets so widths stay 2 bytes.
private static void WriteMessagePackets(Stream s, string message)
{
if (string.IsNullOrEmpty(message)) return;
if (string.IsNullOrEmpty(message))
return;
var chars = Encoding.ASCII.GetBytes(message);
for (var i = 0; i < chars.Length; i += 2)
@@ -295,11 +467,18 @@ namespace OpenNest.Posts.GravographIS
private const double StepsPerMm = 80.0;
private void EnsureEnvelope(int wireX, int wireY,
int envXSteps, int envYSteps,
int polyIndex, int segment, bool isTravel)
private void EnsureEnvelope(
int wireX,
int wireY,
int envXSteps,
int envYSteps,
int polyIndex,
int segment,
bool isTravel
)
{
if (!Options.EnvelopeGuardEnabled) return;
if (!Options.EnvelopeGuardEnabled)
return;
// Wire frame: X is identity to input; Y is negated. With the operator
// origin set at the upper-left of the work envelope and an OpenNest
@@ -313,16 +492,21 @@ namespace OpenNest.Posts.GravographIS
var inputY = -wireY / (double)StepsPerInch;
var kind = isTravel ? "pen-up travel" : "cut segment";
throw new InvalidOperationException(
$"Polyline {polyIndex} {kind} (segment {segment}) would place the head at " +
$"({inputX:F3}\", {inputY:F3}\"), outside the {Options.WorkEnvelopeXMm}×{Options.WorkEnvelopeYMm} mm " +
$"work envelope from upper-left origin. Refusing to emit the record.");
$"Polyline {polyIndex} {kind} (segment {segment}) would place the head at "
+ $"({inputX:F3}\", {inputY:F3}\"), outside the {Options.WorkEnvelopeXMm}×{Options.WorkEnvelopeYMm} mm "
+ $"work envelope from upper-left origin. Refusing to emit the record."
);
}
private static short DepthInStepsAsInt16(double depthInches)
{
var steps = (long)System.Math.Round(depthInches * StepsPerInch, MidpointRounding.AwayFromZero);
var steps = (long)
System.Math.Round(depthInches * StepsPerInch, MidpointRounding.AwayFromZero);
if (steps < short.MinValue || steps > short.MaxValue)
throw new ArgumentOutOfRangeException(nameof(depthInches), $"Depth {depthInches} in. → {steps} steps overflows int16.");
throw new ArgumentOutOfRangeException(
nameof(depthInches),
$"Depth {depthInches} in. → {steps} steps overflows int16."
);
return (short)steps;
}
@@ -335,10 +519,18 @@ namespace OpenNest.Posts.GravographIS
return (x, y);
}
private void WriteTravel(Stream s, byte c0, byte c1, int dx, int dy,
ref int headX, ref int headY,
int envelopeXSteps, int envelopeYSteps,
int polyIndex)
private void WriteTravel(
Stream s,
byte c0,
byte c1,
int dx,
int dy,
ref int headX,
ref int headY,
int envelopeXSteps,
int envelopeYSteps,
int polyIndex
)
{
if (dx == 0 && dy == 0)
return;
@@ -352,20 +544,31 @@ namespace OpenNest.Posts.GravographIS
var chunks = System.Math.Max(
(int)System.Math.Ceiling(System.Math.Abs(dx) / (double)short.MaxValue),
(int)System.Math.Ceiling(System.Math.Abs(dy) / (double)short.MaxValue));
if (chunks < 1) chunks = 1;
(int)System.Math.Ceiling(System.Math.Abs(dy) / (double)short.MaxValue)
);
if (chunks < 1)
chunks = 1;
var emittedX = 0;
var emittedY = 0;
for (var i = 1; i <= chunks; i++)
{
var targetX = (int)System.Math.Round(dx * (i / (double)chunks), MidpointRounding.AwayFromZero);
var targetY = (int)System.Math.Round(dy * (i / (double)chunks), MidpointRounding.AwayFromZero);
var targetX = (int)
System.Math.Round(dx * (i / (double)chunks), MidpointRounding.AwayFromZero);
var targetY = (int)
System.Math.Round(dy * (i / (double)chunks), MidpointRounding.AwayFromZero);
var chunkX = checked(targetX - emittedX);
var chunkY = checked(targetY - emittedY);
EnsureEnvelope(headX + chunkX, headY + chunkY, envelopeXSteps, envelopeYSteps,
polyIndex, segment: 0, isTravel: true);
EnsureEnvelope(
headX + chunkX,
headY + chunkY,
envelopeXSteps,
envelopeYSteps,
polyIndex,
segment: 0,
isTravel: true
);
WriteRecord(s, chunkX, chunkY);
emittedX = targetX;
@@ -399,11 +602,16 @@ namespace OpenNest.Posts.GravographIS
private static void WriteRecord(Stream s, int dx, int dy)
{
if (dx < short.MinValue || dx > short.MaxValue ||
dy < short.MinValue || dy > short.MaxValue)
if (
dx < short.MinValue
|| dx > short.MaxValue
|| dy < short.MinValue
|| dy > short.MaxValue
)
{
throw new InvalidOperationException(
$"Move delta ({dx}, {dy}) steps overflows signed int16 — split moves upstream.");
$"Move delta ({dx}, {dy}) steps overflows signed int16 — split moves upstream."
);
}
int word1;
@@ -423,11 +631,15 @@ namespace OpenNest.Posts.GravographIS
else
{
var maxAbs = System.Math.Max(absDx, absDy);
word1 = (int)System.Math.Round(16384.0 * maxAbs / len, MidpointRounding.AwayFromZero);
word1 = (int)
System.Math.Round(16384.0 * maxAbs / len, MidpointRounding.AwayFromZero);
param = (int)System.Math.Round(len / 22.4, MidpointRounding.AwayFromZero);
if (param < 1) param = 1;
if (param > 180) param = 180;
if (word1 > 16384) word1 = 16384;
if (param < 1)
param = 1;
if (param > 180)
param = 180;
if (word1 > 16384)
word1 = 16384;
}
WriteBigEndianInt16(s, (short)word1);
@@ -448,8 +660,12 @@ namespace OpenNest.Posts.GravographIS
{
for (int i = 0; i <= buffer.Length - 6; i++)
{
if (buffer[i] == 0xFF && buffer[i + 1] == 0xFD &&
buffer[i + 2] == c0 && buffer[i + 3] == c1)
if (
buffer[i] == 0xFF
&& buffer[i + 1] == 0xFD
&& buffer[i + 2] == c0
&& buffer[i + 3] == c1
)
{
buffer[i + 4] = (byte)((value >> 8) & 0xFF);
buffer[i + 5] = (byte)(value & 0xFF);
@@ -458,7 +674,8 @@ namespace OpenNest.Posts.GravographIS
}
throw new InvalidOperationException(
$"Command '{(char)c0}{(char)c1}' not found in preamble template.");
$"Command '{(char)c0}{(char)c1}' not found in preamble template."
);
}
}
}