From b1e872577c65ad28dce40da952fac0cceb478322 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sat, 21 Mar 2026 19:38:54 -0400 Subject: [PATCH] feat: add Description/ShortName attributes to NestPhase with extension methods Co-Authored-By: Claude Sonnet 4.6 --- OpenNest.Engine/NestProgress.cs | 48 +++++++++++++++++++--- OpenNest.Tests/NestPhaseExtensionsTests.cs | 28 +++++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 OpenNest.Tests/NestPhaseExtensionsTests.cs diff --git a/OpenNest.Engine/NestProgress.cs b/OpenNest.Engine/NestProgress.cs index a8ff655..0a6801f 100644 --- a/OpenNest.Engine/NestProgress.cs +++ b/OpenNest.Engine/NestProgress.cs @@ -1,16 +1,52 @@ using OpenNest.Geometry; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; namespace OpenNest { + [AttributeUsage(AttributeTargets.Field)] + internal class ShortNameAttribute(string name) : Attribute + { + public string Name { get; } = name; + } + public enum NestPhase { - Linear, - RectBestFit, - Pairs, - Nfp, - Extents, - Custom + [Description("Trying rotations..."), ShortName("Linear")] Linear, + [Description("Trying best fit..."), ShortName("BestFit")] RectBestFit, + [Description("Trying pairs..."), ShortName("Pairs")] Pairs, + [Description("Trying NFP..."), ShortName("NFP")] Nfp, + [Description("Trying extents..."), ShortName("Extents")] Extents, + [Description("Custom"), ShortName("Custom")] Custom + } + + public static class NestPhaseExtensions + { + private static readonly ConcurrentDictionary DisplayNames = new(); + private static readonly ConcurrentDictionary ShortNames = new(); + + public static string DisplayName(this NestPhase phase) + { + return DisplayNames.GetOrAdd(phase, p => + { + var field = typeof(NestPhase).GetField(p.ToString()); + var attr = field?.GetCustomAttribute(); + return attr?.Description ?? p.ToString(); + }); + } + + public static string ShortName(this NestPhase phase) + { + return ShortNames.GetOrAdd(phase, p => + { + var field = typeof(NestPhase).GetField(p.ToString()); + var attr = field?.GetCustomAttribute(); + return attr?.Name ?? p.ToString(); + }); + } } public class PhaseResult diff --git a/OpenNest.Tests/NestPhaseExtensionsTests.cs b/OpenNest.Tests/NestPhaseExtensionsTests.cs new file mode 100644 index 0000000..4ebeab4 --- /dev/null +++ b/OpenNest.Tests/NestPhaseExtensionsTests.cs @@ -0,0 +1,28 @@ +namespace OpenNest.Tests; + +public class NestPhaseExtensionsTests +{ + [Theory] + [InlineData(NestPhase.Linear, "Trying rotations...")] + [InlineData(NestPhase.RectBestFit, "Trying best fit...")] + [InlineData(NestPhase.Pairs, "Trying pairs...")] + [InlineData(NestPhase.Nfp, "Trying NFP...")] + [InlineData(NestPhase.Extents, "Trying extents...")] + [InlineData(NestPhase.Custom, "Custom")] + public void DisplayName_ReturnsDescription(NestPhase phase, string expected) + { + Assert.Equal(expected, phase.DisplayName()); + } + + [Theory] + [InlineData(NestPhase.Linear, "Linear")] + [InlineData(NestPhase.RectBestFit, "BestFit")] + [InlineData(NestPhase.Pairs, "Pairs")] + [InlineData(NestPhase.Nfp, "NFP")] + [InlineData(NestPhase.Extents, "Extents")] + [InlineData(NestPhase.Custom, "Custom")] + public void ShortName_ReturnsShortLabel(NestPhase phase, string expected) + { + Assert.Equal(expected, phase.ShortName()); + } +}