refactor: Redesign nesting engines with pipeline pattern and add exhaustive search
- Rename Result to PackResult to avoid confusion with Result<T> - Add PackingRequest as immutable configuration replacing mutable engine state - Add PackingStrategy enum (AdvancedFit, BestFit, Exhaustive) - Implement pipeline pattern for composable packing steps - Rewrite AdvancedFitEngine as stateless using pipeline - Rewrite BestFitEngine as stateless - Add ExhaustiveFitEngine with symmetry breaking for optimal solutions - Tries all bin assignments to find minimum bins - Falls back to AdvancedFit for >20 items - Configurable threshold via constructor - Update IEngine/IEngineFactory interfaces for new pattern - Add strategy parameter to MCP tools Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
89
CutList.Core/Nesting/Pipeline/PackingContext.cs
Normal file
89
CutList.Core/Nesting/Pipeline/PackingContext.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
namespace CutList.Core.Nesting.Pipeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Mutable context passed through the packing pipeline.
|
||||
/// Contains the working state that pipeline steps modify.
|
||||
/// </summary>
|
||||
public class PackingContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new packing context from a request.
|
||||
/// </summary>
|
||||
public PackingContext(PackingRequest request)
|
||||
{
|
||||
Request = request ?? throw new ArgumentNullException(nameof(request));
|
||||
RemainingItems = new List<BinItem>(request.Items);
|
||||
Bins = new List<Bin>();
|
||||
OversizedItems = new List<BinItem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The original immutable request.
|
||||
/// </summary>
|
||||
public PackingRequest Request { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Items that have not yet been placed in a bin.
|
||||
/// Pipeline steps remove items from this list as they are packed.
|
||||
/// </summary>
|
||||
public List<BinItem> RemainingItems { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Items that are too large to fit in any stock bin.
|
||||
/// </summary>
|
||||
public List<BinItem> OversizedItems { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The bins that have been created and filled.
|
||||
/// </summary>
|
||||
public List<Bin> Bins { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Convenience property for stock length from the request.
|
||||
/// </summary>
|
||||
public double StockLength => Request.StockLength;
|
||||
|
||||
/// <summary>
|
||||
/// Convenience property for spacing from the request.
|
||||
/// </summary>
|
||||
public double Spacing => Request.Spacing;
|
||||
|
||||
/// <summary>
|
||||
/// Convenience property for max bin count from the request.
|
||||
/// </summary>
|
||||
public int MaxBinCount => Request.MaxBinCount;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if more bins can be added without exceeding the limit.
|
||||
/// </summary>
|
||||
public bool CanAddMoreBins()
|
||||
{
|
||||
if (MaxBinCount == -1)
|
||||
return true;
|
||||
|
||||
return Bins.Count < MaxBinCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new bin with the stock length and spacing from the request.
|
||||
/// </summary>
|
||||
public Bin CreateBin()
|
||||
{
|
||||
return new Bin(StockLength)
|
||||
{
|
||||
Spacing = Spacing
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the final PackResult from the current context state.
|
||||
/// </summary>
|
||||
public PackResult ToResult()
|
||||
{
|
||||
var allUnusedItems = new List<BinItem>();
|
||||
allUnusedItems.AddRange(OversizedItems);
|
||||
allUnusedItems.AddRange(RemainingItems);
|
||||
return new PackResult(Bins, allUnusedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user