mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 12:41:06 -04:00
feat(desktop): mark cut-plan issues on the plate and trim the inspection panel
Plan Cutting findings dropped the checker's geometry, so selecting one could only zoom to part extents, and overlap-blocked plates (no preview) did nothing at all. Findings now keep the check's world-coordinate witness (overlap regions, rapid, contacts); selecting a row draws it with the Validate Nest overlay, on the proposal or a blocked plate's live sheet. The witness is excluded from finding equality so repeated search rejections still collapse to one finding. The side panel's scrolling report was a wall of text operators skipped. It is now a colored outcome line, one line for the shown plate, and one remedy or marker hint above the issue grid, with secondary detail moved to tooltips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
658c1c9ee3
commit
c3fa8e79e0
10 files changed
+379
-147
No files matched your search
@@ -66,7 +66,8 @@ internal static class BestEffortCuttingPlan
|
||||
f.PartNumber is int ordinal ? snapshot.Placements[ordinal - 1].SourcePart : null,
|
||||
f.OtherPartNumber is int other ? other - 1 : null,
|
||||
f.OtherPartNumber is int otherOrdinal ? snapshot.Placements[otherOrdinal - 1].SourcePart : null,
|
||||
f.Kind, f.Message)));
|
||||
f.Kind, f.Message)
|
||||
{ Witness = f }));
|
||||
distance += execution.RapidDistanceFrom(position);
|
||||
if (!double.IsFinite(distance))
|
||||
throw new ArgumentException("Best-effort travel is not finite.");
|
||||
|
||||
@@ -238,7 +238,11 @@ public sealed class CuttingPlanPlateResult
|
||||
|
||||
/// <summary>A diagnostic tied to captured plate and source part positions, not display text.</summary>
|
||||
public sealed record CuttingPlanDiagnosticRow(int PlateIndex, int PlateNumber, int? PartNumber,
|
||||
int? OtherPartNumber, string Message);
|
||||
int? OtherPartNumber, string Message)
|
||||
{
|
||||
/// <summary>World-coordinate markers for the problem (overlap area, rapid, contacts); null when none.</summary>
|
||||
public PostVerificationFinding Witness { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The outcome of a batch. Apply is all-or-nothing. Unverified output needs explicit acceptance.
|
||||
@@ -277,9 +281,16 @@ public sealed class CuttingPlanProposal
|
||||
if (plate.Overlap != null)
|
||||
{
|
||||
foreach (var pair in plate.Overlap.Pairs)
|
||||
rows.Add(new(index, plate.PlateNumber, pair.PartAId + 1, pair.PartBId + 1,
|
||||
$"Part {pair.PartAId + 1}{Name(pair.PartAName)} overlaps part "
|
||||
+ $"{pair.PartBId + 1}{Name(pair.PartBName)}."));
|
||||
{
|
||||
var message = $"Part {pair.PartAId + 1}{Name(pair.PartAName)} overlaps part "
|
||||
+ $"{pair.PartBId + 1}{Name(pair.PartBName)}.";
|
||||
rows.Add(new(index, plate.PlateNumber, pair.PartAId + 1, pair.PartBId + 1, message)
|
||||
{
|
||||
Witness = new(PostVerificationKind.Overlap, plate.PlateNumber, pair.PartAId + 1,
|
||||
pair.PartBId + 1, message)
|
||||
{ Location = pair.Marker, Overlap = pair }
|
||||
});
|
||||
}
|
||||
foreach (var issue in plate.Overlap.Issues)
|
||||
rows.Add(new(index, plate.PlateNumber, issue.PartAId + 1,
|
||||
issue.PartBId is int other ? other + 1 : null,
|
||||
@@ -291,7 +302,8 @@ public sealed class CuttingPlanProposal
|
||||
rows.Add(new(index, plate.PlateNumber,
|
||||
finding.SourceOrdinal is int part ? part + 1 : null,
|
||||
finding.OtherSourceOrdinal is int other ? other + 1 : null,
|
||||
DescribeFinding(finding)));
|
||||
DescribeFinding(finding))
|
||||
{ Witness = finding.Witness });
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,23 @@ public enum CuttingPlanStatus
|
||||
|
||||
/// <summary>Ordinals are zero-based source positions, not proposed sequence positions.</summary>
|
||||
public sealed record CuttingPlanFinding(int? SourceOrdinal, Part SourcePart,
|
||||
int? OtherSourceOrdinal, Part OtherSourcePart, PostVerificationKind? Kind, string Message);
|
||||
int? OtherSourceOrdinal, Part OtherSourcePart, PostVerificationKind? Kind, string Message)
|
||||
{
|
||||
/// <summary>
|
||||
/// The check's own finding, for its world-coordinate markers (location, rapid, contacts).
|
||||
/// Its part numbers are check positions, not source ordinals. Null when the check gave none.
|
||||
/// Not part of equality: repeated rejections of the same problem stay one finding.
|
||||
/// </summary>
|
||||
public PostVerificationFinding Witness { get; init; }
|
||||
|
||||
public bool Equals(CuttingPlanFinding other) => other is not null
|
||||
&& SourceOrdinal == other.SourceOrdinal && Equals(SourcePart, other.SourcePart)
|
||||
&& OtherSourceOrdinal == other.OtherSourceOrdinal && Equals(OtherSourcePart, other.OtherSourcePart)
|
||||
&& Kind == other.Kind && Message == other.Message;
|
||||
|
||||
public override int GetHashCode() =>
|
||||
HashCode.Combine(SourceOrdinal, SourcePart, OtherSourceOrdinal, OtherSourcePart, Kind, Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A replayed direct-XY proposal, optionally with regenerated programs, that respects the
|
||||
|
||||
@@ -403,6 +403,7 @@ public static class CuttingPlanService
|
||||
var source = finding.PartNumber is { } part ? snapshot.Placements[part - 1] : null;
|
||||
var other = finding.OtherPartNumber is { } otherPart ? snapshot.Placements[otherPart - 1] : null;
|
||||
return new CuttingPlanFinding(source?.SourceOrdinal, source?.SourcePart,
|
||||
other?.SourceOrdinal, other?.SourcePart, finding.Kind, finding.Message);
|
||||
other?.SourceOrdinal, other?.SourcePart, finding.Kind, finding.Message)
|
||||
{ Witness = finding };
|
||||
});
|
||||
}
|
||||
@@ -179,7 +179,8 @@ internal static class JointCuttingPlanSearch
|
||||
var source = f.PartNumber is { } p ? snapshot.Placements[p - 1] : null;
|
||||
var other = f.OtherPartNumber is { } o ? snapshot.Placements[o - 1] : null;
|
||||
return new CuttingPlanFinding(source?.SourceOrdinal, source?.SourcePart,
|
||||
other?.SourceOrdinal, other?.SourcePart, f.Kind, f.Message);
|
||||
other?.SourceOrdinal, other?.SourcePart, f.Kind, f.Message)
|
||||
{ Witness = f };
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in new issue
Block a user