fix(bom): combine BOM rows that use the same drawing in one nest

When two BOM rows named the same drawing file and shared a material and
thickness (the same part in two subassemblies), Create Nests imported
the file twice. Nest.Drawings is a set keyed by drawing name, so the
second drawing was dropped with its quantity: PT01 x2 plus PT01 x3
gave a nest needing 2, while the Groups tab showed 5.

Each drawing file is now imported once and needs the total of its
rows. Build_CombinesRowsThatUseTheSameDrawing required [2, 1] where
[5, 1] was expected against the previous commit.

Project Memory: 44293f97-a027-4c29-bc2d-bb789c796746
This commit is contained in:
aj committed 2026-10-05 17:52:32 -04:00
1 parent b83aeb0e41
commit 0ac72fad70
2 files changed
+25 -5

No files matched your search

+9 -5
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenNest.Geometry;
namespace OpenNest.IO.Bom;
@@ -48,9 +49,9 @@ public static class BomNestBuilder
/// Creates a nest named "<paramref name="jobName"/> - thickness material".
/// <paramref name="applySavedDefaults"/> runs first (units, quadrant,
/// plate), then the group's plate size and spacing, material and
/// thickness are set. Each row's drawing is imported with the row's
/// quantity (1 when blank). The nest gets one plate when at least one
/// drawing imported.
/// thickness are set. Each drawing file is imported once, needing the
/// total quantity of the rows that name it (a blank quantity counts as
/// 1). The nest gets one plate when at least one drawing imported.
/// </summary>
public static BomNestBuildResult Build(
BomImportGroup group,
@@ -83,8 +84,11 @@ public static class BomNestBuilder
plate.EdgeTop
);
foreach (var part in group.Parts)
// Rows naming the same drawing file become one drawing that needs
// their total: the nest's drawing set is keyed by drawing name.
foreach (var rows in group.Parts.GroupBy(p => p.DxfPath, StringComparer.OrdinalIgnoreCase))
{
var part = rows.First();
if (!File.Exists(part.DxfPath))
{
errors.Add($"{part.FileName}: DXF file not found");
@@ -95,7 +99,7 @@ public static class BomNestBuilder
{
var drawing = CadImporter.ImportDrawing(
part.DxfPath,
new CadImportOptions { Quantity = part.Qty ?? 1 }
new CadImportOptions { Quantity = rows.Sum(p => p.Qty ?? 1) }
);
drawing.Material = new Material(material);
nest.Drawings.Add(drawing);
+16
View File
@@ -61,6 +61,22 @@ public sealed class BomNestBuilderTests : IDisposable
Assert.All(drawings, d => Assert.Equal("Stainless", d.Material.Name));
}
[Fact]
public void Build_CombinesRowsThatUseTheSameDrawing()
{
var first = Row("PT01", qty: 2);
var second = Row("PT01", qty: 3);
second.FileName = "pt01.dxf";
var result = BomNestBuilder.Build(Group(first, second, Row("PT02", qty: 1)), Plate(), "Job", null);
Assert.Empty(result.Errors);
var nest = Assert.IsType<Nest>(result.Nest);
var drawings = nest.Drawings.OrderBy(d => d.Name).ToList();
Assert.Equal(new[] { "PT01", "PT02" }, drawings.Select(d => d.Name));
Assert.Equal(new[] { 5, 1 }, drawings.Select(d => d.Quantity.Required));
}
[Fact]
public void Build_ReportsMissingDrawingAndKeepsTheOthers()
{