feat: add SpeedClassifier for FAST/MEDIUM/SLOW cut distance classification

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-22 23:29:14 -04:00
parent a323dcc230
commit 95a0db1983
2 changed files with 57 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
namespace OpenNest.Posts.Cincinnati
{
public sealed class SpeedClassifier
{
public double FastThreshold { get; set; } = 0.5;
public double SlowThreshold { get; set; } = 0.1;
public string Classify(double contourLength, double sheetDiagonal)
{
var ratio = contourLength / sheetDiagonal;
if (ratio > FastThreshold) return "FAST";
if (ratio <= SlowThreshold) return "SLOW";
return "MEDIUM";
}
public string FormatCutDist(double contourLength, double sheetDiagonal)
{
return $"CutDist={FormatValue(contourLength)}/{FormatValue(sheetDiagonal)}";
}
private static string FormatValue(double value)
{
// Cincinnati convention: no leading zero for values < 1 (e.g., ".8702" not "0.8702")
var rounded = System.Math.Round(value, 4);
var str = rounded.ToString("0.####");
if (rounded > 0 && rounded < 1 && str.StartsWith("0."))
return str.Substring(1);
return str;
}
}
}

View File

@@ -0,0 +1,26 @@
using OpenNest.Posts.Cincinnati;
namespace OpenNest.Tests.Cincinnati;
public class SpeedClassifierTests
{
[Theory]
[InlineData(20.0, 10.0, "FAST")]
[InlineData(5.0, 10.0, "MEDIUM")]
[InlineData(0.5, 10.0, "SLOW")]
public void Classify_ReturnsExpectedClass(double contourLength, double sheetDiagonal, string expected)
{
var classifier = new SpeedClassifier();
Assert.Equal(expected, classifier.Classify(contourLength, sheetDiagonal));
}
[Theory]
[InlineData(0.8702, 3.927, "CutDist=.8702/3.927")]
[InlineData(18.9722, 3.927, "CutDist=18.9722/3.927")]
[InlineData(0.0, 10.0, "CutDist=0/10")]
public void FormatCutDist_IncludesLengthAndDiagonal(double contour, double diag, string expected)
{
var classifier = new SpeedClassifier();
Assert.Equal(expected, classifier.FormatCutDist(contour, diag));
}
}