diff --git a/OpenNest.Core/Shapes/PipeSizes.cs b/OpenNest.Core/Shapes/PipeSizes.cs new file mode 100644 index 0000000..d577a3a --- /dev/null +++ b/OpenNest.Core/Shapes/PipeSizes.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Linq; + +namespace OpenNest.Shapes +{ + public static class PipeSizes + { + public readonly record struct Entry(string Label, double OuterDiameter); + + public static IReadOnlyList All { get; } = new List + { + new Entry("1/8", 0.405), + new Entry("1/4", 0.540), + new Entry("3/8", 0.675), + new Entry("1/2", 0.840), + new Entry("3/4", 1.050), + new Entry("1", 1.315), + new Entry("1 1/4", 1.660), + new Entry("1 1/2", 1.900), + new Entry("2", 2.375), + new Entry("2 1/2", 2.875), + new Entry("3", 3.500), + new Entry("3 1/2", 4.000), + new Entry("4", 4.500), + new Entry("4 1/2", 5.000), + new Entry("5", 5.563), + new Entry("6", 6.625), + new Entry("7", 7.625), + new Entry("8", 8.625), + new Entry("9", 9.625), + new Entry("10", 10.750), + new Entry("11", 11.750), + new Entry("12", 12.750), + new Entry("14", 14.000), + new Entry("16", 16.000), + new Entry("18", 18.000), + new Entry("20", 20.000), + new Entry("24", 24.000), + new Entry("26", 26.000), + new Entry("28", 28.000), + new Entry("30", 30.000), + new Entry("32", 32.000), + new Entry("34", 34.000), + new Entry("36", 36.000), + new Entry("42", 42.000), + new Entry("48", 48.000), + }; + + public static bool TryGetOD(string label, out double outerDiameter) + { + foreach (var entry in All) + { + if (entry.Label == label) + { + outerDiameter = entry.OuterDiameter; + return true; + } + } + + outerDiameter = 0; + return false; + } + + public static IEnumerable GetFittingSizes(double maxOD) + { + return All.Where(e => e.OuterDiameter <= maxOD); + } + } +} diff --git a/OpenNest.Tests/Shapes/PipeSizesTests.cs b/OpenNest.Tests/Shapes/PipeSizesTests.cs new file mode 100644 index 0000000..bb588cd --- /dev/null +++ b/OpenNest.Tests/Shapes/PipeSizesTests.cs @@ -0,0 +1,54 @@ +using OpenNest.Shapes; + +namespace OpenNest.Tests.Shapes; + +public class PipeSizesTests +{ + [Fact] + public void All_ContainsExpectedCount() + { + Assert.Equal(35, PipeSizes.All.Count); + } + + [Fact] + public void All_IsSortedByOuterDiameterAscending() + { + for (var i = 1; i < PipeSizes.All.Count; i++) + Assert.True(PipeSizes.All[i].OuterDiameter > PipeSizes.All[i - 1].OuterDiameter); + } + + [Theory] + [InlineData("1/8", 0.405)] + [InlineData("1/2", 0.840)] + [InlineData("2", 2.375)] + [InlineData("2 1/2", 2.875)] + [InlineData("12", 12.750)] + [InlineData("48", 48.000)] + public void TryGetOD_KnownLabel_ReturnsExpectedOD(string label, double expected) + { + Assert.True(PipeSizes.TryGetOD(label, out var od)); + Assert.Equal(expected, od, 0.001); + } + + [Fact] + public void TryGetOD_UnknownLabel_ReturnsFalse() + { + Assert.False(PipeSizes.TryGetOD("bogus", out _)); + } + + [Fact] + public void GetFittingSizes_FiltersByMaxOD() + { + var results = PipeSizes.GetFittingSizes(3.0).ToList(); + + Assert.Contains(results, e => e.Label == "2 1/2"); + Assert.DoesNotContain(results, e => e.Label == "3"); + Assert.DoesNotContain(results, e => e.Label == "4"); + } + + [Fact] + public void GetFittingSizes_MaxSmallerThanSmallest_ReturnsEmpty() + { + Assert.Empty(PipeSizes.GetFittingSizes(0.1)); + } +}