fix(report): keep IDs on neighboring part groups one spacing apart

Each dotted group outline was padded 1 pt beyond its parts. At overview scale
a 0.25 in part spacing is only ~1.3 pt, so the outlines of two adjacent
clusters (e.g. the six small bars and the two holed plates on N26-27Y plate 1)
overlapped, and the later group - with its ID - was silently dropped.

Pad outlines by under half the part spacing instead, so neighboring clusters
both get their outline and ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-11-05 12:49:02 -05:00
1 parent a994bae76f
commit fbe82d198a
4 files changed
+32 -3

No files matched your search

+4 -1
View File
@@ -63,6 +63,9 @@ internal static class NestReportDiagram
var groups = new List<DiagramGroup>();
// A small screen-space gap also accommodates tightly packed parts with unset spacing.
var gap = System.Math.Max(4, plate.PartSpacing * fit.Scale * 2);
// Outlines stay under half the part spacing from their members, so the outlines of two
// neighboring clusters (different IDs one spacing apart) never meet or overlap.
var margin = plate.PartSpacing > 0 ? System.Math.Min(1, plate.PartSpacing * fit.Scale * 0.45) : 1;
var remaining = failed.ToHashSet();
foreach (var seed in failed)
{
@@ -90,7 +93,7 @@ internal static class NestReportDiagram
var boundary = boxes[seed];
foreach (var member in members.Skip(1))
boundary.Union(boxes[member]);
boundary.Inflate(1, 1);
boundary.Inflate(margin, margin);
var memberSet = members.ToHashSet();
// A rectangular group must not imply that unrelated or ungrouped parts belong to it.
if (!view.Contains(boundary)
@@ -256,6 +256,30 @@ public sealed class NestPdfLayoutTests : IDisposable
Assert.False(plan.Groups[0].Boundary.IntersectsWith(plan.Groups[1].Boundary));
}
[Fact]
public void Plan_NeighboringClustersOfDifferentPartsOneSpacingApartAreBothGrouped()
{
// A second washer drawing (another ID) packed one part spacing to the right of the first
// cluster: their outlines must not meet, or the second group and its ID were dropped.
var nest = NestReportTestData.CreateDenseNest();
var plate = nest.Plates[0];
var other = new Drawing("Other washer", NestReportTestData.HoledSquare(1, 0.25));
nest.Drawings.Add(other);
var right = plate.Parts.Max(part => part.BoundingBox.Right);
for (var row = 0; row < 4; row++)
plate.Parts.Add(new Part(other, new Vector(right + plate.PartSpacing, 30 + row * 1.5)));
var snapshot = NestReportBuilder.Capture(nest, NestReportTestData.GeneratedAt);
var plan = NestReportDiagram.Plan(snapshot.Plates[0], 720, 320);
Assert.Equal(2, plan.Groups.Count);
Assert.Equal(["2", "3"], plan.Groups.Select(group => group.Label.Id).Order());
Assert.False(plan.Groups[0].Boundary.IntersectsWith(plan.Groups[1].Boundary));
foreach (var group in plan.Groups)
Assert.All(group.Parts, index => Assert.True(group.Boundary.Contains(
plan.Fit.Rect(snapshot.Plates[0].Parts[index].Geometry.Bounds))));
}
[SkippableFact]
public void Write_LabelOnHoledPartAvoidsTheHole()
{
@@ -126,7 +126,7 @@ public static class NestReportTestData
return drawing;
}
private static Program HoledSquare(double size, double radius)
internal static Program HoledSquare(double size, double radius)
{
var program = RectangleProgram(size, size);
var center = size / 2;
+3 -1
View File
@@ -93,7 +93,9 @@ and a part too small to label never prevents export. Every part remains in the
quantity tables even when its diagram label cannot fit.
Nearby small parts with the same report ID may share a dotted rectangular outline
and one ID beside it. Separate clusters get separate outlines. A group is omitted
and one ID beside it. Separate clusters get separate outlines; an outline stays
within half the part spacing of its parts, so clusters of different parts packed
one spacing apart each keep their own outline and ID. A group is omitted
if its rectangle includes any other part or cutoff, or if there is no clear space
for its label. Clearance is tested against real contours, not bounding boxes, so a
cluster nested in a larger part's cutout or notch is still grouped and labeled. Dotted group outlines are distinct from dashed scrap cutoffs.