feat(diagnostics): cache overlap material and recheck incrementally
PlateOverlapAnalyzer.Capture(parts, OverlapMaterialCache) reuses each clean program's converted entities and prepared material across requests, and Analyze(snapshot, previous) reuses pair results whose two parts kept the same source, exact pose and relative order, renumbering them. A recheck after moving one part only clips that part's neighbors again. On 501 real PEP plates: full check median 1 ms / max 6.4 s; incremental recheck after one move median 0.1 ms / max 38 ms. Incremental results matched uncached full analysis exactly across 2505 edits.
This commit is contained in:
@@ -7,12 +7,17 @@ namespace OpenNest.Diagnostics;
|
||||
/// <summary>An owned diagnostic result. An empty Pairs list is clear only if IsComplete is true.</summary>
|
||||
public sealed class PlateOverlapReport
|
||||
{
|
||||
internal PlateOverlapReport(List<PlateOverlapPair> pairs, List<PlateOverlapIssue> issues)
|
||||
internal PlateOverlapReport(List<PlateOverlapPair> pairs, List<PlateOverlapIssue> issues,
|
||||
PlateOverlapSnapshot snapshot)
|
||||
{
|
||||
Pairs = pairs.AsReadOnly();
|
||||
Issues = issues.AsReadOnly();
|
||||
Snapshot = snapshot;
|
||||
}
|
||||
|
||||
/// <summary>The owned input this report was computed from; the baseline for incremental rechecks.</summary>
|
||||
internal PlateOverlapSnapshot Snapshot { get; }
|
||||
|
||||
public IReadOnlyList<PlateOverlapPair> Pairs { get; }
|
||||
public IReadOnlyList<PlateOverlapIssue> Issues { get; }
|
||||
public bool IsComplete => Issues.Count == 0;
|
||||
@@ -24,6 +29,23 @@ public sealed class PlateOverlapPair
|
||||
{
|
||||
private readonly Box bounds;
|
||||
|
||||
private PlateOverlapPair(PlateOverlapPair source, int partAId, int partBId, string partAName,
|
||||
string partBName)
|
||||
{
|
||||
PartAId = partAId;
|
||||
PartBId = partBId;
|
||||
PartAName = partAName;
|
||||
PartBName = partBName;
|
||||
Regions = source.Regions;
|
||||
Area = source.Area;
|
||||
Centroid = source.Centroid;
|
||||
bounds = source.bounds;
|
||||
}
|
||||
|
||||
/// <summary>The same immutable geometry under new input positions and captured names.</summary>
|
||||
internal PlateOverlapPair Renumber(int partAId, int partBId, string partAName, string partBName) =>
|
||||
new(this, partAId, partBId, partAName, partBName);
|
||||
|
||||
internal PlateOverlapPair(int partAId, int partBId, string partAName, string partBName,
|
||||
List<PlateOverlapRegion> regions, Vector centroid)
|
||||
{
|
||||
@@ -90,5 +112,5 @@ public sealed class PlateOverlapSnapshot
|
||||
internal IReadOnlyList<PlateOverlapIssue> Issues { get; }
|
||||
}
|
||||
|
||||
internal sealed record CapturedOverlapPart(int Id, string Name, List<Entity> Entities,
|
||||
internal sealed record CapturedOverlapPart(int Id, string Name, OverlapSource Source,
|
||||
double Rotation, Vector Location);
|
||||
|
||||
Reference in New Issue
Block a user