diff --git a/OpenNest.Engine/BestFit/BestFitCache.cs b/OpenNest.Engine/BestFit/BestFitCache.cs index 8a12faa..5664388 100644 --- a/OpenNest.Engine/BestFit/BestFitCache.cs +++ b/OpenNest.Engine/BestFit/BestFitCache.cs @@ -24,6 +24,9 @@ namespace OpenNest.Engine.BestFit if (_cache.TryGetValue(key, out var cached)) return cached; + // Operate on the canonical frame so cached pair positions are orientation-invariant. + var canonical = CanonicalFrame.AsCanonicalCopy(drawing); + IPairEvaluator evaluator = null; ISlideComputer slideComputer = null; @@ -31,7 +34,7 @@ namespace OpenNest.Engine.BestFit { if (CreateEvaluator != null) { - try { evaluator = CreateEvaluator(drawing, spacing); } + try { evaluator = CreateEvaluator(canonical, spacing); } catch { /* fall back to default evaluator */ } } @@ -42,7 +45,7 @@ namespace OpenNest.Engine.BestFit } var finder = new BestFitFinder(plateWidth, plateHeight, evaluator, slideComputer); - var results = finder.FindBestFits(drawing, spacing, StepSize); + var results = finder.FindBestFits(canonical, spacing, StepSize); _cache.TryAdd(key, results); return results; @@ -86,9 +89,12 @@ namespace OpenNest.Engine.BestFit try { + // Operate on the canonical frame so cached pair positions are orientation-invariant. + var canonical = CanonicalFrame.AsCanonicalCopy(drawing); + if (CreateEvaluator != null) { - try { evaluator = CreateEvaluator(drawing, spacing); } + try { evaluator = CreateEvaluator(canonical, spacing); } catch { /* fall back to default evaluator */ } } @@ -100,7 +106,7 @@ namespace OpenNest.Engine.BestFit // Compute candidates and evaluate once with the largest plate. var finder = new BestFitFinder(maxWidth, maxHeight, evaluator, slideComputer); - var baseResults = finder.FindBestFits(drawing, spacing, StepSize); + var baseResults = finder.FindBestFits(canonical, spacing, StepSize); // Cache a filtered copy for each plate size. foreach (var size in needed) diff --git a/OpenNest.Engine/DefaultNestEngine.cs b/OpenNest.Engine/DefaultNestEngine.cs index 1a2a021..3d99834 100644 --- a/OpenNest.Engine/DefaultNestEngine.cs +++ b/OpenNest.Engine/DefaultNestEngine.cs @@ -139,6 +139,10 @@ namespace OpenNest var bestFits = BestFitCache.GetOrCompute( drawing, Plate.Size.Length, Plate.Size.Width, Plate.PartSpacing); + // Build pair candidates with a canonical drawing so their geometry matches + // the coordinate frame of the cached fit results. + var canonicalDrawing = CanonicalFrame.AsCanonicalCopy(drawing); + List bestPlacement = null; foreach (var fit in bestFits) @@ -152,7 +156,7 @@ namespace OpenNest if (fit.LongestSide > System.Math.Max(workArea.Width, workArea.Length) + Tolerance.Epsilon) continue; - var landscape = fit.BuildParts(drawing); + var landscape = fit.BuildParts(canonicalDrawing); var portrait = RotatePair90(landscape); var lFits = TryOffsetToWorkArea(landscape, workArea); @@ -174,6 +178,8 @@ namespace OpenNest bestPlacement = candidate; } + // Parts are returned in canonical frame, bound to the canonical drawing. + // The outer Fill wrapper (Task 7) rebinds to `drawing` and composes sourceAngle onto rotation. return bestPlacement; }