diff --git a/OpenNest.Engine/DefaultNestEngine.cs b/OpenNest.Engine/DefaultNestEngine.cs index abae5cf..5ac6d77 100644 --- a/OpenNest.Engine/DefaultNestEngine.cs +++ b/OpenNest.Engine/DefaultNestEngine.cs @@ -150,13 +150,15 @@ namespace OpenNest token.ThrowIfCancellationRequested(); var extentsFiller = new FillExtents(workArea, Plate.PartSpacing); + var bestFits2 = BestFitCache.GetOrCompute( + groupParts[0].BaseDrawing, Plate.Size.Length, Plate.Size.Width, Plate.PartSpacing); var extentsAngles2 = new[] { groupParts[0].Rotation, groupParts[0].Rotation + Angle.HalfPI }; List bestExtents2 = null; foreach (var angle in extentsAngles2) { token.ThrowIfCancellationRequested(); - var result = extentsFiller.Fill(groupParts[0].BaseDrawing, angle, PlateNumber, token, progress); + var result = extentsFiller.Fill(groupParts[0].BaseDrawing, angle, PlateNumber, token, progress, bestFits2); if (result != null && result.Count > (bestExtents2?.Count ?? 0)) bestExtents2 = result; } @@ -294,17 +296,19 @@ namespace OpenNest ReportProgress(progress, NestPhase.RectBestFit, PlateNumber, best, workArea, BuildProgressSummary()); } - // Extents phase + // Extents phase — reuse the BestFit cache from the Pairs phase. token.ThrowIfCancellationRequested(); var extentsSw = Stopwatch.StartNew(); var extentsFiller = new FillExtents(workArea, Plate.PartSpacing); + var bestFits = BestFitCache.GetOrCompute( + item.Drawing, Plate.Size.Length, Plate.Size.Width, Plate.PartSpacing); List bestExtents = null; var extentsAngles = new[] { bestRotation, bestRotation + Angle.HalfPI }; foreach (var angle in extentsAngles) { token.ThrowIfCancellationRequested(); - var extentsResult = extentsFiller.Fill(item.Drawing, angle, PlateNumber, token, progress); + var extentsResult = extentsFiller.Fill(item.Drawing, angle, PlateNumber, token, progress, bestFits); if (bestExtents == null || (extentsResult != null && extentsResult.Count > (bestExtents?.Count ?? 0))) bestExtents = extentsResult; } @@ -351,59 +355,10 @@ namespace OpenNest // --- Pattern helpers --- internal static Pattern BuildRotatedPattern(List groupParts, double angle) - { - var pattern = new Pattern(); - var center = ((IEnumerable)groupParts).GetBoundingBox().Center; - - foreach (var part in groupParts) - { - var clone = (Part)part.Clone(); - clone.UpdateBounds(); - - if (!angle.IsEqualTo(0)) - clone.Rotate(angle, center); - - pattern.Parts.Add(clone); - } - - pattern.UpdateBounds(); - return pattern; - } + => FillHelpers.BuildRotatedPattern(groupParts, angle); internal static List FillPattern(FillLinear engine, List groupParts, List angles, Box workArea) - { - var results = new System.Collections.Concurrent.ConcurrentBag<(List Parts, FillScore Score)>(); - - Parallel.ForEach(angles, angle => - { - var pattern = BuildRotatedPattern(groupParts, angle); - - if (pattern.Parts.Count == 0) - return; - - var h = engine.Fill(pattern, NestDirection.Horizontal); - if (h != null && h.Count > 0) - results.Add((h, FillScore.Compute(h, workArea))); - - var v = engine.Fill(pattern, NestDirection.Vertical); - if (v != null && v.Count > 0) - results.Add((v, FillScore.Compute(v, workArea))); - }); - - List best = null; - var bestScore = default(FillScore); - - foreach (var res in results) - { - if (best == null || res.Score > bestScore) - { - best = res.Parts; - bestScore = res.Score; - } - } - - return best; - } + => FillHelpers.FillPattern(engine, groupParts, angles, workArea); } } diff --git a/OpenNest.Engine/Strategies/FillHelpers.cs b/OpenNest.Engine/Strategies/FillHelpers.cs new file mode 100644 index 0000000..1a3c005 --- /dev/null +++ b/OpenNest.Engine/Strategies/FillHelpers.cs @@ -0,0 +1,66 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading.Tasks; +using OpenNest.Geometry; +using OpenNest.Math; + +namespace OpenNest +{ + public static class FillHelpers + { + public static Pattern BuildRotatedPattern(List groupParts, double angle) + { + var pattern = new Pattern(); + var center = ((IEnumerable)groupParts).GetBoundingBox().Center; + + foreach (var part in groupParts) + { + var clone = (Part)part.Clone(); + clone.UpdateBounds(); + + if (!angle.IsEqualTo(0)) + clone.Rotate(angle, center); + + pattern.Parts.Add(clone); + } + + pattern.UpdateBounds(); + return pattern; + } + + public static List FillPattern(FillLinear engine, List groupParts, List angles, Box workArea) + { + var results = new ConcurrentBag<(List Parts, FillScore Score)>(); + + Parallel.ForEach(angles, angle => + { + var pattern = BuildRotatedPattern(groupParts, angle); + + if (pattern.Parts.Count == 0) + return; + + var h = engine.Fill(pattern, NestDirection.Horizontal); + if (h != null && h.Count > 0) + results.Add((h, FillScore.Compute(h, workArea))); + + var v = engine.Fill(pattern, NestDirection.Vertical); + if (v != null && v.Count > 0) + results.Add((v, FillScore.Compute(v, workArea))); + }); + + List best = null; + var bestScore = default(FillScore); + + foreach (var res in results) + { + if (best == null || res.Score > bestScore) + { + best = res.Parts; + bestScore = res.Score; + } + } + + return best; + } + } +}