mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 17:21:34 -04:00
Saved pairs are in the drawing's canonical frame, but loaded candidates held the source drawing, so BuildCanonicalParts/BuildSourceParts rebuilt a different pair for any drawing with a non-zero canonical angle (a 30 degree T-shape came back 16.57 x 10.39 instead of its saved 16.92 x 8). That reached the Irregular engine's pair catalog and the best-fit viewer after opening a saved nest. Import now binds every candidate to one canonical copy, as computed candidates are; fills already passed the canonical drawing explicitly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
100 lines
3.8 KiB
C#
100 lines
3.8 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenNest.BestFit;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Engine.BestFit
|
|
{
|
|
/// <summary>
|
|
/// Saves and restores <see cref="BestFitCache"/> entries for .nest archives. Only kept
|
|
/// results are exported; imported sets are added without replacing computed ones.
|
|
/// </summary>
|
|
public sealed class BestFitCacheStore : IBestFitStore
|
|
{
|
|
/// <summary>The store over the process-wide <see cref="BestFitCache"/>.</summary>
|
|
public static BestFitCacheStore Shared { get; } = new();
|
|
|
|
private BestFitCacheStore() { }
|
|
|
|
public IReadOnlyList<SavedPairSet> Export(
|
|
Drawing drawing,
|
|
IReadOnlySet<(double Width, double Length, double Spacing)> plateKeys
|
|
)
|
|
{
|
|
var allBestFits = BestFitCache.GetAllForDrawing(drawing);
|
|
var sets = new List<SavedPairSet>();
|
|
|
|
foreach (var kvp in allBestFits)
|
|
{
|
|
if (!plateKeys.Contains((kvp.Key.PlateWidth, kvp.Key.PlateHeight, kvp.Key.Spacing)))
|
|
continue;
|
|
|
|
var results = kvp
|
|
.Value.Where(r => r.Keep)
|
|
.Select(r => new SavedPairResult(
|
|
r.Candidate.Part1Rotation,
|
|
r.Candidate.Part2Rotation,
|
|
r.Candidate.Part2Offset.X,
|
|
r.Candidate.Part2Offset.Y,
|
|
r.Candidate.StrategyIndex,
|
|
r.Candidate.TestNumber,
|
|
r.Candidate.Spacing,
|
|
r.RotatedArea,
|
|
r.BoundingWidth,
|
|
r.BoundingHeight,
|
|
r.OptimalRotation,
|
|
r.Keep,
|
|
r.Reason,
|
|
r.TrueArea,
|
|
r.HullAngles
|
|
))
|
|
.ToList();
|
|
|
|
sets.Add(new SavedPairSet(kvp.Key.PlateWidth, kvp.Key.PlateHeight, kvp.Key.Spacing, results));
|
|
}
|
|
|
|
return sets;
|
|
}
|
|
|
|
public void Import(Drawing drawing, IReadOnlyList<SavedPairSet> sets)
|
|
{
|
|
// Saved pairs are in the canonical frame, so their candidates hold a canonical copy,
|
|
// as computed ones do; the source drawing would rebuild a different pair.
|
|
Drawing canonical = null;
|
|
|
|
foreach (var set in sets)
|
|
{
|
|
if (set.Results.Count == 0)
|
|
continue;
|
|
|
|
canonical ??= CanonicalFrame.AsCanonicalCopy(drawing);
|
|
var results = set
|
|
.Results.Select(r => new BestFitResult
|
|
{
|
|
Candidate = new PairCandidate
|
|
{
|
|
Drawing = canonical,
|
|
Part1Rotation = r.Part1Rotation,
|
|
Part2Rotation = r.Part2Rotation,
|
|
Part2Offset = new Vector(r.Part2OffsetX, r.Part2OffsetY),
|
|
StrategyIndex = r.StrategyType,
|
|
TestNumber = r.TestNumber,
|
|
Spacing = r.CandidateSpacing,
|
|
},
|
|
RotatedArea = r.RotatedArea,
|
|
BoundingWidth = r.BoundingWidth,
|
|
BoundingHeight = r.BoundingHeight,
|
|
OptimalRotation = r.OptimalRotation,
|
|
Keep = r.Keep,
|
|
Reason = r.Reason,
|
|
TrueArea = r.TrueArea,
|
|
HullAngles = r.HullAngles?.ToList(),
|
|
})
|
|
.ToList();
|
|
|
|
BestFitCache.Populate(drawing, set.PlateWidth, set.PlateHeight, set.Spacing, results);
|
|
}
|
|
}
|
|
}
|
|
}
|