feat(engine): BestFitCache operates in canonical frame; TryPlaceBestFitPair builds from canonical drawing
This commit is contained in:
@@ -24,6 +24,9 @@ namespace OpenNest.Engine.BestFit
|
|||||||
if (_cache.TryGetValue(key, out var cached))
|
if (_cache.TryGetValue(key, out var cached))
|
||||||
return cached;
|
return cached;
|
||||||
|
|
||||||
|
// Operate on the canonical frame so cached pair positions are orientation-invariant.
|
||||||
|
var canonical = CanonicalFrame.AsCanonicalCopy(drawing);
|
||||||
|
|
||||||
IPairEvaluator evaluator = null;
|
IPairEvaluator evaluator = null;
|
||||||
ISlideComputer slideComputer = null;
|
ISlideComputer slideComputer = null;
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ namespace OpenNest.Engine.BestFit
|
|||||||
{
|
{
|
||||||
if (CreateEvaluator != null)
|
if (CreateEvaluator != null)
|
||||||
{
|
{
|
||||||
try { evaluator = CreateEvaluator(drawing, spacing); }
|
try { evaluator = CreateEvaluator(canonical, spacing); }
|
||||||
catch { /* fall back to default evaluator */ }
|
catch { /* fall back to default evaluator */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +45,7 @@ namespace OpenNest.Engine.BestFit
|
|||||||
}
|
}
|
||||||
|
|
||||||
var finder = new BestFitFinder(plateWidth, plateHeight, evaluator, slideComputer);
|
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);
|
_cache.TryAdd(key, results);
|
||||||
return results;
|
return results;
|
||||||
@@ -86,9 +89,12 @@ namespace OpenNest.Engine.BestFit
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Operate on the canonical frame so cached pair positions are orientation-invariant.
|
||||||
|
var canonical = CanonicalFrame.AsCanonicalCopy(drawing);
|
||||||
|
|
||||||
if (CreateEvaluator != null)
|
if (CreateEvaluator != null)
|
||||||
{
|
{
|
||||||
try { evaluator = CreateEvaluator(drawing, spacing); }
|
try { evaluator = CreateEvaluator(canonical, spacing); }
|
||||||
catch { /* fall back to default evaluator */ }
|
catch { /* fall back to default evaluator */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +106,7 @@ namespace OpenNest.Engine.BestFit
|
|||||||
|
|
||||||
// Compute candidates and evaluate once with the largest plate.
|
// Compute candidates and evaluate once with the largest plate.
|
||||||
var finder = new BestFitFinder(maxWidth, maxHeight, evaluator, slideComputer);
|
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.
|
// Cache a filtered copy for each plate size.
|
||||||
foreach (var size in needed)
|
foreach (var size in needed)
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ namespace OpenNest
|
|||||||
var bestFits = BestFitCache.GetOrCompute(
|
var bestFits = BestFitCache.GetOrCompute(
|
||||||
drawing, Plate.Size.Length, Plate.Size.Width, Plate.PartSpacing);
|
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<Part> bestPlacement = null;
|
List<Part> bestPlacement = null;
|
||||||
|
|
||||||
foreach (var fit in bestFits)
|
foreach (var fit in bestFits)
|
||||||
@@ -152,7 +156,7 @@ namespace OpenNest
|
|||||||
if (fit.LongestSide > System.Math.Max(workArea.Width, workArea.Length) + Tolerance.Epsilon)
|
if (fit.LongestSide > System.Math.Max(workArea.Width, workArea.Length) + Tolerance.Epsilon)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var landscape = fit.BuildParts(drawing);
|
var landscape = fit.BuildParts(canonicalDrawing);
|
||||||
var portrait = RotatePair90(landscape);
|
var portrait = RotatePair90(landscape);
|
||||||
|
|
||||||
var lFits = TryOffsetToWorkArea(landscape, workArea);
|
var lFits = TryOffsetToWorkArea(landscape, workArea);
|
||||||
@@ -174,6 +178,8 @@ namespace OpenNest
|
|||||||
bestPlacement = candidate;
|
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;
|
return bestPlacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user