From a92ba7af89a128abe2e5a129ae62876244c0fbf3 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sun, 8 Mar 2026 13:27:56 -0400 Subject: [PATCH] feat: resolve per-entity color and line type from DXF imports Add LineTypeName to Layer and propagate resolved color/line-type through all DXF entity conversions (Arc, Circle, Line, Spline, Polyline, LwPolyline, Ellipse). Entities that inherit ByLayer properties now correctly resolve to their layer's values. Co-Authored-By: Claude Opus 4.6 --- OpenNest.Core/Geometry/Layer.cs | 2 + OpenNest/IO/Extensions.cs | 98 +++++++++++++++++++++++++++------ 2 files changed, 82 insertions(+), 18 deletions(-) diff --git a/OpenNest.Core/Geometry/Layer.cs b/OpenNest.Core/Geometry/Layer.cs index 7147a4a..b623b34 100644 --- a/OpenNest.Core/Geometry/Layer.cs +++ b/OpenNest.Core/Geometry/Layer.cs @@ -21,6 +21,8 @@ namespace OpenNest.Geometry public Color Color { get; set; } + public string LineTypeName { get; set; } + public override string ToString() { return Name; diff --git a/OpenNest/IO/Extensions.cs b/OpenNest/IO/Extensions.cs index 21e3cbd..faa1f71 100644 --- a/OpenNest/IO/Extensions.cs +++ b/OpenNest/IO/Extensions.cs @@ -22,33 +22,39 @@ namespace OpenNest.IO public static Geometry.Arc ToOpenNest(this ACadSharp.Entities.Arc arc) { - return new Geometry.Arc( + var result = new Geometry.Arc( arc.Center.X, arc.Center.Y, arc.Radius, arc.StartAngle, arc.EndAngle) { Layer = arc.Layer.ToOpenNest() }; + result.ApplyDxfProperties(arc); + return result; } public static Geometry.Circle ToOpenNest(this ACadSharp.Entities.Circle circle) { - return new Geometry.Circle( + var result = new Geometry.Circle( circle.Center.X, circle.Center.Y, circle.Radius) { Layer = circle.Layer.ToOpenNest() }; + result.ApplyDxfProperties(circle); + return result; } public static Geometry.Line ToOpenNest(this ACadSharp.Entities.Line line) { - return new Geometry.Line( + var result = new Geometry.Line( line.StartPoint.X, line.StartPoint.Y, line.EndPoint.X, line.EndPoint.Y) { Layer = line.Layer.ToOpenNest() }; + result.ApplyDxfProperties(line); + return result; } public static List ToOpenNest(this Spline spline) @@ -59,21 +65,28 @@ namespace OpenNest.IO if (pts.Count == 0) return lines; + var layer = spline.Layer.ToOpenNest(); + var color = spline.ResolveColor(); + var lineTypeName = spline.ResolveLineTypeName(); var lastPoint = pts[0].ToOpenNest(); for (var i = 1; i < pts.Count; i++) { var nextPoint = pts[i].ToOpenNest(); - lines.Add(new Geometry.Line( - lastPoint, - nextPoint) { Layer = spline.Layer.ToOpenNest() }); + lines.Add(new Geometry.Line(lastPoint, nextPoint) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); lastPoint = nextPoint; } if (spline.IsClosed) - lines.Add(new Geometry.Line(lastPoint, pts[0].ToOpenNest()) { Layer = spline.Layer.ToOpenNest() }); + lines.Add(new Geometry.Line(lastPoint, pts[0].ToOpenNest()) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); return lines; } @@ -85,15 +98,19 @@ namespace OpenNest.IO if (polyline.Vertices.Count == 0) return lines; + var layer = polyline.Layer.ToOpenNest(); + var color = polyline.ResolveColor(); + var lineTypeName = polyline.ResolveLineTypeName(); var lastPoint = polyline.Vertices[0].Location.ToOpenNest(); for (var i = 1; i < polyline.Vertices.Count; i++) { var nextPoint = polyline.Vertices[i].Location.ToOpenNest(); - lines.Add(new Geometry.Line( - lastPoint, - nextPoint) { Layer = polyline.Layer.ToOpenNest() }); + lines.Add(new Geometry.Line(lastPoint, nextPoint) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); lastPoint = nextPoint; } @@ -101,7 +118,10 @@ namespace OpenNest.IO var isClosed = (polyline.Flags & PolylineFlags.ClosedPolylineOrClosedPolygonMeshInM) != 0; if (isClosed) - lines.Add(new Geometry.Line(lastPoint, polyline.Vertices[0].Location.ToOpenNest()) { Layer = polyline.Layer.ToOpenNest() }); + lines.Add(new Geometry.Line(lastPoint, polyline.Vertices[0].Location.ToOpenNest()) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); return lines; } @@ -113,15 +133,19 @@ namespace OpenNest.IO if (polyline.Vertices.Count == 0) return lines; + var layer = polyline.Layer.ToOpenNest(); + var color = polyline.ResolveColor(); + var lineTypeName = polyline.ResolveLineTypeName(); var lastPoint = polyline.Vertices[0].ToOpenNest(); for (var i = 1; i < polyline.Vertices.Count; i++) { var nextPoint = polyline.Vertices[i].ToOpenNest(); - lines.Add(new Geometry.Line( - lastPoint, - nextPoint) { Layer = polyline.Layer.ToOpenNest() }); + lines.Add(new Geometry.Line(lastPoint, nextPoint) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); lastPoint = nextPoint; } @@ -129,7 +153,10 @@ namespace OpenNest.IO var isClosed = (polyline.Flags & LwPolylineFlags.Closed) != 0; if (isClosed) - lines.Add(new Geometry.Line(lastPoint, polyline.Vertices[0].ToOpenNest()) { Layer = polyline.Layer.ToOpenNest() }); + lines.Add(new Geometry.Line(lastPoint, polyline.Vertices[0].ToOpenNest()) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); return lines; } @@ -170,10 +197,15 @@ namespace OpenNest.IO } var layer = ellipse.Layer.ToOpenNest(); + var color = ellipse.ResolveColor(); + var lineTypeName = ellipse.ResolveLineTypeName(); for (var i = 0; i < points.Count - 1; i++) { - lines.Add(new Geometry.Line(points[i], points[i + 1]) { Layer = layer }); + lines.Add(new Geometry.Line(points[i], points[i + 1]) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); } // Close the ellipse if it's a full ellipse @@ -181,7 +213,10 @@ namespace OpenNest.IO { var first = lines.First(); var last = lines.Last(); - lines.Add(new Geometry.Line(last.EndPoint, first.StartPoint) { Layer = layer }); + lines.Add(new Geometry.Line(last.EndPoint, first.StartPoint) + { + Layer = layer, Color = color, LineTypeName = lineTypeName + }); } return lines; @@ -192,10 +227,37 @@ namespace OpenNest.IO return new Geometry.Layer(layer.Name) { Color = Color.FromArgb(layer.Color.R, layer.Color.G, layer.Color.B), - IsVisible = layer.IsOn + IsVisible = layer.IsOn, + LineTypeName = layer.LineType?.Name }; } + public static Color ResolveColor(this ACadSharp.Entities.Entity entity) + { + var color = entity.Color; + + if (color.IsByLayer) + color = entity.Layer.Color; + + return Color.FromArgb(color.R, color.G, color.B); + } + + public static string ResolveLineTypeName(this ACadSharp.Entities.Entity entity) + { + var lt = entity.LineType; + + if (lt == null || string.Equals(lt.Name, "ByLayer", System.StringComparison.OrdinalIgnoreCase)) + return entity.Layer.LineType?.Name ?? "Continuous"; + + return lt.Name; + } + + public static void ApplyDxfProperties(this Geometry.Entity target, ACadSharp.Entities.Entity source) + { + target.Color = source.ResolveColor(); + target.LineTypeName = source.ResolveLineTypeName(); + } + public static Vector ToOpenNest(this LwPolyline.Vertex v) { return new Vector(v.Location.X, v.Location.Y);