Files
OpenNest/OpenNest.Core/BestFit/IBestFitStore.cs
T
ajandClaude Opus 5.5 0ca4e64189 fix(bestfit): drop saved pair sets whose canonical frame changed
Saved best-fit pairs are in the drawing's canonical frame, but the canonical
angle is recomputed on load and was not saved with the set. When that
computation changes (RotatingCalipers checking every hull edge, marks no
longer counted as material), old pairs were replayed in a turned frame and
could overlap.

Each saved set now records canonicalAngle, and BestFitCacheStore.Import
skips sets whose angle no longer matches the recomputed one (1e-9 rad,
modulo a full turn). Sets from older files have no angle and are dropped;
their pairs are recomputed when next needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 22:04:23 -04:00

60 lines
2.1 KiB
C#

using System.Collections.Generic;
namespace OpenNest.BestFit
{
/// <summary>One saved best-fit pair result, as persisted in a .nest archive.</summary>
public sealed record SavedPairResult(
double Part1Rotation,
double Part2Rotation,
double Part2OffsetX,
double Part2OffsetY,
int StrategyType,
int TestNumber,
double CandidateSpacing,
double RotatedArea,
double BoundingWidth,
double BoundingHeight,
double OptimalRotation,
bool Keep,
string Reason,
double TrueArea,
IReadOnlyList<double> HullAngles
);
/// <summary>
/// The saved best-fit results for one drawing at one plate size and spacing.
/// <paramref name="CanonicalAngle"/> is the drawing's canonical angle (radians) when the
/// set was saved: the frame its pair geometry is in. Null means the frame is unknown.
/// </summary>
public sealed record SavedPairSet(
double PlateWidth,
double PlateHeight,
double Spacing,
IReadOnlyList<SavedPairResult> Results,
double? CanonicalAngle = null
);
/// <summary>
/// Persists best-fit pair caches across .nest round trips. Implementations own their
/// cache; readers and writers never assume one exists, and a file without saved sets is
/// always valid because the data can be recomputed.
/// </summary>
public interface IBestFitStore
{
/// <summary>
/// Sets to save for <paramref name="drawing"/>, limited to the given
/// (plate width, plate length, part spacing) keys.
/// </summary>
IReadOnlyList<SavedPairSet> Export(
Drawing drawing,
IReadOnlySet<(double Width, double Length, double Spacing)> plateKeys
);
/// <summary>
/// Restores saved sets for <paramref name="drawing"/>. Sets saved in a frame other
/// than the drawing's current canonical frame, or in an unknown one, are stale.
/// </summary>
void Import(Drawing drawing, IReadOnlyList<SavedPairSet> sets);
}
}