mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 18:31:08 -04:00
- Add Drawing.HasCustomColor, set when a color is picked in Drawing Properties or comes from a library record with a stored color. - Persist it as customColor in .nest files (omitted when false) and keep it out of drawing packages; split pieces inherit it. - Recolor non-custom drawings from the active palette when a nest opens and when the scheme changes; custom colors keep their palette slot. - Library settings store a color only when it is custom. - Document drawing colors in nest-file-format.md and nesting-view-colors.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
284 lines
11 KiB
C#
284 lines
11 KiB
C#
using System.Security.Cryptography;
|
|
using OpenNest.CNC.CuttingStrategy;
|
|
using OpenNest.Data;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.Shapes;
|
|
|
|
namespace OpenNest.Tests.Data;
|
|
|
|
public class LibraryDrawingInsertTests
|
|
{
|
|
private const string Server = "http://library.test:8090";
|
|
private static readonly Guid LibraryId = Guid.Parse("3f1e2d4c-5b6a-4987-8a1b-2c3d4e5f6a7b");
|
|
private static readonly byte[] PackageBytes = { (byte)'P', (byte)'K', 3, 4, 1, 2 };
|
|
|
|
private static Nest MatchingNest() => new("Synthetic job")
|
|
{
|
|
Units = Units.Inches,
|
|
Thickness = 0.25,
|
|
Material = new Material("Synthetic Steel", "Grade A"),
|
|
};
|
|
|
|
private static DrawingLibraryRecord Record(int revision = 3, string name = "SYN-101", byte[]? package = null) => new()
|
|
{
|
|
Id = LibraryId,
|
|
Revision = revision,
|
|
Name = name,
|
|
Customer = "Synthetic customer",
|
|
MaterialName = "Synthetic Steel",
|
|
MaterialGrade = "Grade A",
|
|
Thickness = 0.25,
|
|
Units = Units.Inches,
|
|
CutType = CutType.Plasma,
|
|
Notes = "Deburr",
|
|
PackageSha256 = Convert.ToHexString(SHA256.HashData(package ?? PackageBytes)).ToLowerInvariant(),
|
|
};
|
|
|
|
private static LibraryPackage Package(Units units = Units.Inches, IReadOnlyList<string>? warnings = null)
|
|
{
|
|
var drawing = new RectangleShape { Name = "old package name", Length = 4, Width = 2 }.GetDrawing();
|
|
drawing.Material = new Material("Package material", "Package grade", 0.284);
|
|
drawing.Customer = "Package customer";
|
|
drawing.CutPins.Add(new ContourCutPin(new Vector(4, 2), new LineLeadIn { Length = 0.25 }, new NoLeadOut(),
|
|
new NormalTab { Size = 0.03 }));
|
|
return new LibraryPackage(PackageBytes, drawing, units, warnings);
|
|
}
|
|
|
|
[Fact]
|
|
public void Matching_AddsAnExactCopyCarryingTheLinkAndKeepsPins()
|
|
{
|
|
var nest = MatchingNest();
|
|
var package = Package();
|
|
|
|
var insert = LibraryDrawingInsert.Plan(nest, Server + "/", Record(), package, 5);
|
|
|
|
Assert.Equal(LibraryInsertKind.AddDrawing, insert.Kind);
|
|
Assert.True(insert.KeepPins);
|
|
Assert.Empty(insert.Warnings);
|
|
Assert.Empty(nest.Drawings);
|
|
|
|
insert.Apply();
|
|
|
|
var drawing = Assert.Single(nest.Drawings);
|
|
Assert.Same(package.Drawing, drawing);
|
|
Assert.Equal(new Vector(4, 2), Assert.Single(drawing.CutPins).Point);
|
|
Assert.Equal(("SYN-101", "Synthetic customer", 5), (drawing.Name, drawing.Customer, drawing.Quantity.Required));
|
|
Assert.Equal(("Synthetic Steel", "Grade A", 0.284), (drawing.Material.Name, drawing.Material.Grade, drawing.Material.Density));
|
|
var link = drawing.Library!;
|
|
Assert.Equal(
|
|
(Server, LibraryId, 3, CutType.Plasma, 0.25, "Synthetic Steel", "Grade A", Units.Inches, "Deburr", Record().PackageSha256),
|
|
(link.ServerKey, link.Id, link.Revision, link.CutType, link.Thickness, link.MaterialName, link.MaterialGrade,
|
|
link.Units, link.Notes, link.PackageSha256));
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordSettings_ApplyOverWhateverThePackageHolds()
|
|
{
|
|
var nest = MatchingNest();
|
|
var package = Package();
|
|
package.Drawing.CutFirst = false;
|
|
package.Drawing.Priority = 7;
|
|
package.Drawing.Constraints = new NestConstraints { StepAngle = 1, StartAngle = 1, EndAngle = 2 };
|
|
var record = Record();
|
|
record.Settings = new DrawingNestingSettings
|
|
{
|
|
CutFirst = true,
|
|
Priority = 1,
|
|
StepAngle = System.Math.PI / 2,
|
|
EndAngle = System.Math.PI,
|
|
Allow180Equivalent = true,
|
|
ColorArgb = System.Drawing.Color.FromArgb(255, 40, 50, 60).ToArgb(),
|
|
};
|
|
|
|
LibraryDrawingInsert.Plan(nest, Server, record, package, 1).Apply();
|
|
|
|
var drawing = Assert.Single(nest.Drawings);
|
|
Assert.True(drawing.HasCustomColor);
|
|
Assert.Equal(record.Settings, DrawingNestingSettings.FromDrawing(drawing));
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordWithoutAColor_GetsAVisiblePartColor()
|
|
{
|
|
var nest = MatchingNest();
|
|
|
|
LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1).Apply();
|
|
|
|
var drawing = Assert.Single(nest.Drawings);
|
|
Assert.Equal(255, drawing.Color.A);
|
|
// A palette color stays a palette color: it follows the scheme and isn't stored back.
|
|
Assert.False(drawing.HasCustomColor);
|
|
Assert.Equal(0, DrawingNestingSettings.FromDrawing(drawing).ColorArgb);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpacingCaseAndThicknessRounding_StillMatch()
|
|
{
|
|
var nest = MatchingNest();
|
|
nest.Material = new Material(" synthetic STEEL ", "grade a");
|
|
nest.Thickness = 0.250004;
|
|
|
|
var insert = LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1);
|
|
|
|
Assert.True(insert.KeepPins);
|
|
Assert.Empty(insert.Warnings);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("Other Steel", "Grade A", 0.25, "material Synthetic Steel (nest Other Steel)")]
|
|
[InlineData("Synthetic Steel", "Grade B", 0.25, "grade Grade A (nest Grade B)")]
|
|
[InlineData("Synthetic Steel", "Grade A", 0.1875, "thickness 0.25 (nest 0.1875)")]
|
|
[InlineData("", "", 0.0, "material Synthetic Steel (nest not set)")]
|
|
public void Mismatch_AddsButDropsPinsAndNamesTheDifference(string material, string grade, double thickness, string expected)
|
|
{
|
|
var nest = MatchingNest();
|
|
nest.Material = new Material(material, grade);
|
|
nest.Thickness = thickness;
|
|
|
|
var insert = LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 2);
|
|
|
|
Assert.Equal(LibraryInsertKind.AddDrawing, insert.Kind);
|
|
Assert.False(insert.KeepPins);
|
|
var warning = Assert.Single(insert.Warnings);
|
|
Assert.Contains(expected, warning);
|
|
Assert.Contains("'SYN-101'", warning);
|
|
Assert.Contains("cut pins are dropped", warning);
|
|
Assert.Empty(insert.Drawing!.CutPins);
|
|
insert.Apply();
|
|
var drawing = Assert.Single(nest.Drawings);
|
|
Assert.Empty(drawing.CutPins);
|
|
Assert.NotNull(drawing.Library);
|
|
}
|
|
|
|
[Fact]
|
|
public void EveryDifference_IsNamed()
|
|
{
|
|
var nest = new Nest("Other job") { Units = Units.Inches, Thickness = 0.1875, Material = new Material("Other Steel", "Grade B") };
|
|
|
|
var warning = Assert.Single(LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1).Warnings);
|
|
|
|
Assert.Contains("material Synthetic Steel (nest Other Steel)", warning);
|
|
Assert.Contains("grade Grade A (nest Grade B)", warning);
|
|
Assert.Contains("thickness 0.25 (nest 0.1875)", warning);
|
|
}
|
|
|
|
[Fact]
|
|
public void PackageWarnings_AreShownBeforeTheAdd()
|
|
{
|
|
var insert = LibraryDrawingInsert.Plan(MatchingNest(), Server, Record(),
|
|
Package(warnings: new[] { "reader note" }), 1);
|
|
|
|
Assert.Equal(new[] { "reader note" }, insert.Warnings);
|
|
Assert.True(insert.KeepPins);
|
|
}
|
|
|
|
[Fact]
|
|
public void DifferentUnits_AreRefused()
|
|
{
|
|
var nest = MatchingNest();
|
|
nest.Units = Units.Millimeters;
|
|
|
|
var insert = LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1);
|
|
|
|
AssertRefused(insert, nest, "inches", "millimeters");
|
|
}
|
|
|
|
[Fact]
|
|
public void PackageDisagreeingWithItsRecord_IsRefused()
|
|
{
|
|
var nest = MatchingNest();
|
|
|
|
AssertRefused(LibraryDrawingInsert.Plan(nest, Server, Record(), Package(Units.Millimeters), 1), nest, "library record says inches");
|
|
AssertRefused(LibraryDrawingInsert.Plan(nest, Server, Record(package: new byte[] { 9 }), Package(), 1), nest, "does not match");
|
|
}
|
|
|
|
[Fact]
|
|
public void SameRevisionAlreadyInTheNest_AddsQuantityOnly()
|
|
{
|
|
var nest = MatchingNest();
|
|
LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 4).Apply();
|
|
var existing = Assert.Single(nest.Drawings);
|
|
|
|
var insert = LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 3);
|
|
|
|
Assert.Equal(LibraryInsertKind.AddQuantity, insert.Kind);
|
|
Assert.Same(existing, insert.Drawing);
|
|
insert.Apply();
|
|
Assert.Same(existing, Assert.Single(nest.Drawings));
|
|
Assert.Equal(7, existing.Quantity.Required);
|
|
}
|
|
|
|
[Fact]
|
|
public void SameRevisionRenamedInTheNest_StillAddsQuantity()
|
|
{
|
|
var nest = MatchingNest();
|
|
var first = LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1);
|
|
first.Drawing!.Name = "renamed";
|
|
first.Apply();
|
|
|
|
var insert = LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1);
|
|
|
|
Assert.Equal(LibraryInsertKind.AddQuantity, insert.Kind);
|
|
}
|
|
|
|
[Fact]
|
|
public void OtherRevisionOfTheSameDrawing_IsRefused()
|
|
{
|
|
var nest = MatchingNest();
|
|
var first = LibraryDrawingInsert.Plan(nest, Server, Record(revision: 2), Package(), 1);
|
|
first.Drawing!.Name = "renamed";
|
|
first.Apply();
|
|
|
|
AssertRefused(LibraryDrawingInsert.Plan(nest, Server, Record(revision: 3), Package(), 1), nest,
|
|
"revision 2", "'renamed'", "Update Drawings");
|
|
}
|
|
|
|
[Fact]
|
|
public void DifferentDrawingWithTheSameName_IsRefusedNamingBoth()
|
|
{
|
|
var nest = MatchingNest();
|
|
nest.Drawings.Add(new RectangleShape { Name = "SYN-101", Length = 1, Width = 1 }.GetDrawing());
|
|
|
|
AssertRefused(LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1), nest,
|
|
"'SYN-101' (not from the drawing library)", "library drawing 'SYN-101' (Synthetic customer) revision 3");
|
|
}
|
|
|
|
[Fact]
|
|
public void SameRevisionFromAnotherServer_IsADifferentDrawing()
|
|
{
|
|
var nest = MatchingNest();
|
|
LibraryDrawingInsert.Plan(nest, "http://other.test:8090", Record(), Package(), 1).Apply();
|
|
|
|
AssertRefused(LibraryDrawingInsert.Plan(nest, Server, Record(), Package(), 1), nest,
|
|
"library revision 3 from http://other.test:8090");
|
|
}
|
|
|
|
[Fact]
|
|
public void Apply_RunsOnce()
|
|
{
|
|
var insert = LibraryDrawingInsert.Plan(MatchingNest(), Server, Record(), Package(), 1);
|
|
insert.Apply();
|
|
|
|
Assert.Throws<InvalidOperationException>(insert.Apply);
|
|
}
|
|
|
|
[Fact]
|
|
public void Plan_RefusesMissingInputs()
|
|
{
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => LibraryDrawingInsert.Plan(MatchingNest(), Server, Record(), Package(), 0));
|
|
Assert.Throws<ArgumentException>(() => LibraryDrawingInsert.Plan(MatchingNest(), " / ", Record(), Package(), 1));
|
|
}
|
|
|
|
private static void AssertRefused(LibraryDrawingInsert insert, Nest nest, params string[] fragments)
|
|
{
|
|
var before = nest.Drawings.Select(d => (d, d.Quantity.Required)).ToList();
|
|
|
|
Assert.True(insert.IsRefused);
|
|
Assert.Null(insert.Drawing);
|
|
foreach (var fragment in fragments)
|
|
Assert.Contains(fragment, insert.Refusal);
|
|
Assert.Throws<InvalidOperationException>(insert.Apply);
|
|
Assert.Equal(before, nest.Drawings.Select(d => (d, d.Quantity.Required)).ToList());
|
|
}
|
|
}
|