mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-26 22:01:06 -04:00
fix(io): give re-imported unchanged DXFs the same entity ids
Entity ids came from a process-random sequence, so importing the same DXF twice produced different source-entity ids and therefore a different drawing library package (different SHA-256), and an importer could not tell an unchanged file from a changed one. CadImporter.Import now derives each entity id from the file's SHA-256 and the entity's position in the import. An unchanged file gives the same ids and the same package bytes; any change to the file gives entirely new ids, so suppression, roles and edge selections keyed by id never move to a different entity.
This commit is contained in:
1 parent
ba2102c793
commit
bc21382c5d
2 files changed
+76
No files matched your search
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using OpenNest.Bending;
|
||||
using OpenNest.Breakoffs;
|
||||
using OpenNest.Converters;
|
||||
@@ -77,6 +80,8 @@ namespace OpenNest.IO
|
||||
repairReports = BendRepair.Apply(dxf.Entities, bends, options.BendRepair);
|
||||
}
|
||||
|
||||
AssignFileIds(path, dxf.Entities);
|
||||
|
||||
return new CadImportResult
|
||||
{
|
||||
Entities = dxf.Entities,
|
||||
@@ -89,6 +94,31 @@ namespace OpenNest.IO
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives each imported entity an id derived from the file's bytes and the entity's
|
||||
/// position in the import, so importing an unchanged file again yields the same ids
|
||||
/// (and the same library package), while any change to the file yields entirely new
|
||||
/// ids: ids key suppression, roles and edge selections, so one must never move to
|
||||
/// another entity.
|
||||
/// </summary>
|
||||
private static void AssignFileIds(string path, IList<Entity> entities)
|
||||
{
|
||||
Span<byte> input = stackalloc byte[32 + 4];
|
||||
Span<byte> digest = stackalloc byte[32];
|
||||
using (var stream = File.OpenRead(path))
|
||||
SHA256.HashData(stream, input[..32]);
|
||||
|
||||
for (var i = 0; i < entities.Count; i++)
|
||||
{
|
||||
BinaryPrimitives.WriteInt32LittleEndian(input[32..], i);
|
||||
SHA256.HashData(input, digest);
|
||||
// RFC 9562 version 8 (custom) layout.
|
||||
digest[7] = (byte)((digest[7] & 0x0F) | 0x80);
|
||||
digest[8] = (byte)((digest[8] & 0x3F) | 0x80);
|
||||
entities[i].Id = new Guid(digest[..16]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience for headless callers: Import a file and build a Drawing
|
||||
/// in a single call, using all loaded entities and detected bends.
|
||||
|
||||
@@ -156,5 +156,51 @@ namespace OpenNest.Tests.IO
|
||||
Assert.NotNull(drawing.Program);
|
||||
Assert.NotNull(drawing.SourceEntities);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImportDrawing_UnchangedFile_GivesTheSameLibraryPackage()
|
||||
{
|
||||
var first = CadImporter.ImportDrawing(TestDxf);
|
||||
var second = CadImporter.ImportDrawing(TestDxf);
|
||||
|
||||
Assert.Equal(
|
||||
first.SourceEntities.Select(e => e.Id),
|
||||
second.SourceEntities.Select(e => e.Id)
|
||||
);
|
||||
Assert.Equal(
|
||||
DrawingPackage.Write(first, Units.Inches),
|
||||
DrawingPackage.Write(second, Units.Inches)
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Import_EntityIdsAreUniqueAndNonempty()
|
||||
{
|
||||
var ids = CadImporter.Import(TestDxf).Entities.Select(e => e.Id).ToList();
|
||||
|
||||
Assert.DoesNotContain(System.Guid.Empty, ids);
|
||||
Assert.Equal(ids.Count, ids.Distinct().Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Import_ChangedFile_ReusesNoEntityIds()
|
||||
{
|
||||
// Ids key suppression, roles and edge selections, so a changed file must not
|
||||
// hand an old id to whatever entity now sits at that position.
|
||||
var changed = Path.Combine(Path.GetTempPath(), $"cadimporter-changed-{System.Guid.NewGuid():N}.dxf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(changed, "999\nchanged\n" + File.ReadAllText(TestDxf));
|
||||
var original = CadImporter.Import(TestDxf).Entities.Select(e => e.Id).ToHashSet();
|
||||
var edited = CadImporter.Import(changed).Entities.Select(e => e.Id).ToList();
|
||||
|
||||
Assert.NotEmpty(edited);
|
||||
Assert.DoesNotContain(edited, original.Contains);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user