fix: Cincinnati post processor arc feedrate, G89 spacing, pallet exchange, and preamble

- Add radius-based arc feedrate calculation (Variables/Percentages modes)
  with configurable radius ranges (#123/#124/#125 or inline expressions)
- Fix arc distance in SpeedClassifier using actual arc length instead of
  chord length (full circles previously computed as zero)
- Fix G89 P spacing: P now adjacent to filename per CL-707 manual syntax
- Add lead-out feedrate support (#129) and arc lead-in feedrate (#127)
- Fix pallet exchange: StartAndEnd emits M50 in preamble + last sheet only
- Add G121 Smart Rapids emission when UseSmartRapids is enabled
- Add G90 absolute mode to main program preamble alongside G20/G21

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 09:33:50 -04:00
parent 722f758e94
commit 3d4204db7b
10 changed files with 515 additions and 22 deletions
@@ -24,9 +24,9 @@ public class CincinnatiPreambleWriterTests
var output = sb.ToString();
Assert.Contains("( NEST TestNest )", output);
Assert.Contains("( CONFIGURATION - CL940 )", output);
Assert.Contains("G20", output);
Assert.Contains("G20 G90", output);
Assert.Contains("M42", output);
Assert.Contains("G89 P MS135N2PANEL.lib", output);
Assert.Contains("G89 PMS135N2PANEL.lib", output);
Assert.Contains("M98 P100 (Variable Declaration)", output);
Assert.Contains("GOTO1 (GOTO SHEET NUMBER)", output);
Assert.Contains("N1 M98 P101 (SHEET 1)", output);
@@ -44,7 +44,72 @@ public class CincinnatiPreambleWriterTests
writer.WriteMainProgram(sw, "Test", "", 1, "");
Assert.Contains("G21", sb.ToString());
Assert.Contains("G21 G90", sb.ToString());
}
[Fact]
public void WriteMainProgram_EmitsG90WithUnits()
{
var config = new CincinnatiPostConfig { PostedUnits = Units.Inches };
var sb = new StringBuilder();
using var sw = new StringWriter(sb);
var writer = new CincinnatiPreambleWriter(config);
writer.WriteMainProgram(sw, "Test", "", 1, "");
Assert.Contains("G20 G90", sb.ToString());
}
[Fact]
public void WriteMainProgram_EmitsG121_WhenSmartRapidsEnabled()
{
var config = new CincinnatiPostConfig { UseSmartRapids = true };
var sb = new StringBuilder();
using var sw = new StringWriter(sb);
var writer = new CincinnatiPreambleWriter(config);
writer.WriteMainProgram(sw, "Test", "", 1, "");
Assert.Contains("G121 (SMART RAPIDS)", sb.ToString());
}
[Fact]
public void WriteMainProgram_OmitsG121_WhenSmartRapidsDisabled()
{
var config = new CincinnatiPostConfig { UseSmartRapids = false };
var sb = new StringBuilder();
using var sw = new StringWriter(sb);
var writer = new CincinnatiPreambleWriter(config);
writer.WriteMainProgram(sw, "Test", "", 1, "");
Assert.DoesNotContain("G121", sb.ToString());
}
[Fact]
public void WriteMainProgram_EmitsM50_WhenStartAndEnd()
{
var config = new CincinnatiPostConfig { PalletExchange = PalletMode.StartAndEnd };
var sb = new StringBuilder();
using var sw = new StringWriter(sb);
var writer = new CincinnatiPreambleWriter(config);
writer.WriteMainProgram(sw, "Test", "", 1, "");
Assert.Contains("M50", sb.ToString());
}
[Fact]
public void WriteMainProgram_OmitsM50_WhenEndOfSheet()
{
var config = new CincinnatiPostConfig { PalletExchange = PalletMode.EndOfSheet };
var sb = new StringBuilder();
using var sw = new StringWriter(sb);
var writer = new CincinnatiPreambleWriter(config);
writer.WriteMainProgram(sw, "Test", "", 1, "");
Assert.DoesNotContain("M50", sb.ToString());
}
[Fact]