refactor: extract PlacedPart/SequenceEntry types, add IFP caching
Move PlacedPart to its own file. Replace tuple-based sequences with SequenceEntry struct for clarity. Add IProgress parameter to INestOptimizer. Add IFP caching to NfpCache to avoid recomputing inner fit polygons for the same drawing/rotation/workArea. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using OpenNest.Engine.Fill;
|
using OpenNest.Engine.Fill;
|
||||||
using OpenNest.Geometry;
|
using OpenNest.Geometry;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -11,9 +12,9 @@ namespace OpenNest.Engine.Nfp
|
|||||||
public class OptimizationResult
|
public class OptimizationResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The best sequence found: (drawingId, rotation, drawing) tuples in placement order.
|
/// The best placement sequence found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<(int drawingId, double rotation, Drawing drawing)> Sequence { get; set; }
|
public List<SequenceEntry> Sequence { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The score achieved by the best sequence.
|
/// The score achieved by the best sequence.
|
||||||
@@ -34,6 +35,7 @@ namespace OpenNest.Engine.Nfp
|
|||||||
{
|
{
|
||||||
OptimizationResult Optimize(List<NestItem> items, Box workArea, NfpCache cache,
|
OptimizationResult Optimize(List<NestItem> items, Box workArea, NfpCache cache,
|
||||||
Dictionary<int, List<double>> candidateRotations,
|
Dictionary<int, List<double>> candidateRotations,
|
||||||
|
IProgress<NestProgress> progress = null,
|
||||||
CancellationToken cancellation = default);
|
CancellationToken cancellation = default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace OpenNest.Engine.Nfp
|
|||||||
private readonly Dictionary<NfpKey, Polygon> cache = new Dictionary<NfpKey, Polygon>();
|
private readonly Dictionary<NfpKey, Polygon> cache = new Dictionary<NfpKey, Polygon>();
|
||||||
private readonly Dictionary<int, Dictionary<double, Polygon>> polygonCache
|
private readonly Dictionary<int, Dictionary<double, Polygon>> polygonCache
|
||||||
= new Dictionary<int, Dictionary<double, Polygon>>();
|
= new Dictionary<int, Dictionary<double, Polygon>>();
|
||||||
|
private readonly Dictionary<(int drawingId, double rotation), Polygon> ifpCache
|
||||||
|
= new Dictionary<(int drawingId, double rotation), Polygon>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a pre-computed polygon for a drawing at a specific rotation.
|
/// Registers a pre-computed polygon for a drawing at a specific rotation.
|
||||||
@@ -28,6 +30,26 @@ namespace OpenNest.Engine.Nfp
|
|||||||
}
|
}
|
||||||
|
|
||||||
rotations[rotation] = polygon;
|
rotations[rotation] = polygon;
|
||||||
|
|
||||||
|
// Clear IFP cache if a polygon is updated (though usually they aren't).
|
||||||
|
ifpCache.Remove((drawingId, rotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or computes the IFP for a drawing at a specific rotation within a work area.
|
||||||
|
/// </summary>
|
||||||
|
public Polygon GetIfp(int drawingId, double rotation, Box workArea)
|
||||||
|
{
|
||||||
|
if (ifpCache.TryGetValue((drawingId, rotation), out var ifp))
|
||||||
|
return ifp;
|
||||||
|
|
||||||
|
var polygon = GetPolygon(drawingId, rotation);
|
||||||
|
if (polygon == null)
|
||||||
|
return new Polygon();
|
||||||
|
|
||||||
|
ifp = InnerFitPolygon.Compute(workArea, polygon);
|
||||||
|
ifpCache[(drawingId, rotation)] = ifp;
|
||||||
|
return ifp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using OpenNest.Geometry;
|
||||||
|
|
||||||
|
namespace OpenNest.Engine.Nfp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a part that has been placed by the BLF algorithm.
|
||||||
|
/// </summary>
|
||||||
|
public class PlacedPart
|
||||||
|
{
|
||||||
|
public int DrawingId { get; set; }
|
||||||
|
public double Rotation { get; set; }
|
||||||
|
public Vector Position { get; set; }
|
||||||
|
public Drawing Drawing { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace OpenNest.Engine.Nfp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An entry in a placement sequence — identifies which drawing to place and at what rotation.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct SequenceEntry
|
||||||
|
{
|
||||||
|
public int DrawingId { get; }
|
||||||
|
public double Rotation { get; }
|
||||||
|
public Drawing Drawing { get; }
|
||||||
|
|
||||||
|
public SequenceEntry(int drawingId, double rotation, Drawing drawing)
|
||||||
|
{
|
||||||
|
DrawingId = drawingId;
|
||||||
|
Rotation = rotation;
|
||||||
|
Drawing = drawing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SequenceEntry WithRotation(double rotation)
|
||||||
|
{
|
||||||
|
return new SequenceEntry(DrawingId, rotation, Drawing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user