feat: add entity-based suppression with stable GUIDs

Entities now have a Guid Id for stable identity across edit sessions.
Drawing stores the full source entity set (SourceEntities) and a set of
suppressed entity IDs (SuppressedEntityIds), replacing the previous
SuppressedProgram approach. Unchecked entities in the converter are
suppressed rather than permanently removed, so they can be re-enabled
when editing drawings again.

Entities are serialized as JSON in the nest file (entities/entities-N)
alongside the existing G-code programs. Backward compatible with older
nest files that lack entity data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-08 13:25:48 -04:00
parent df86d4367b
commit c1e6092e83
8 changed files with 274 additions and 10 deletions
+38 -8
View File
@@ -610,17 +610,31 @@ namespace OpenNest.Forms
{
foreach (var drawing in drawings)
{
var entities = ConvertProgram.ToGeometry(drawing.Program);
List<Entity> entities;
// Re-apply source offset so entities appear in their natural position
if (drawing.Source?.Offset != null && drawing.Source.Offset != Vector.Zero)
if (drawing.SourceEntities != null)
{
foreach (var entity in entities)
entity.Offset(drawing.Source.Offset);
}
// Use stored entities with stable GUIDs; apply suppression state
entities = new List<Entity>(drawing.SourceEntities);
// Remove rapid traversals — they aren't part of the cut geometry
entities.RemoveAll(e => e.Layer == SpecialLayers.Rapid);
foreach (var entity in entities)
entity.IsVisible = !drawing.SuppressedEntityIds.Contains(entity.Id);
}
else
{
// Fallback: derive entities from Program (older drawings without source entities)
entities = ConvertProgram.ToGeometry(drawing.Program);
// Re-apply source offset so entities appear in their natural position
if (drawing.Source?.Offset != null && drawing.Source.Offset != Vector.Zero)
{
foreach (var entity in entities)
entity.Offset(drawing.Source.Offset);
}
// Remove rapid traversals — they aren't part of the cut geometry
entities.RemoveAll(e => e.Layer == SpecialLayers.Rapid);
}
var bounds = entities.GetBoundingBox();
@@ -682,6 +696,22 @@ namespace OpenNest.Forms
drawing.Program = programEditor.Program;
else
drawing.Program = pgm;
// Store all entities with stable GUIDs; track suppressed by ID
var bendSources = new HashSet<Entity>(
(item.Bends ?? new List<Bend>())
.Where(b => b.SourceEntity != null)
.Select(b => b.SourceEntity));
drawing.SourceEntities = item.Entities
.Where(e => !bendSources.Contains(e))
.ToList();
drawing.SuppressedEntityIds = new HashSet<Guid>(
drawing.SourceEntities
.Where(e => !(e.Layer.IsVisible && e.IsVisible))
.Select(e => e.Id));
drawings.Add(drawing);
Thread.Sleep(20);
+2
View File
@@ -883,6 +883,8 @@ namespace OpenNest.Forms
if (newByName.TryGetValue(existing.Name, out var updated))
{
existing.Program = updated.Program;
existing.SourceEntities = updated.SourceEntities;
existing.SuppressedEntityIds = updated.SuppressedEntityIds;
existing.Source = updated.Source;
existing.Customer = updated.Customer;
existing.Quantity.Required = updated.Quantity.Required;