From 250fdefaeaf3446281414d319e677717988a429e Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Mon, 6 Apr 2026 08:17:49 -0400 Subject: [PATCH] refactor: merge DxfImporter and DxfExporter into single static Dxf class Consolidated two stateless classes into one unified API: Dxf.Import(), Dxf.GetGeometry(), Dxf.ExportPlate(), Dxf.ExportProgram(). Export state moved into a private ExportContext. Removed bool+out pattern from GetGeometry in favor of returning empty list on failure. Co-Authored-By: Claude Opus 4.6 (1M context) --- OpenNest.Api/NestRunner.cs | 5 +- OpenNest.Console/Program.cs | 10 +- OpenNest.IO/Dxf.cs | 378 ++++++++++++++++++ OpenNest.IO/DxfExporter.cs | 297 -------------- OpenNest.IO/DxfImporter.cs | 153 ------- OpenNest.Mcp/Tools/InputTools.cs | 7 +- OpenNest.Tests/Api/NestRunnerTests.cs | 3 +- .../Bending/SolidWorksBendDetectorTests.cs | 6 +- OpenNest.Tests/BestFit/BestFitOverlapTests.cs | 3 +- OpenNest.Tests/Engine/EngineOverlapTests.cs | 3 +- .../Geometry/EllipseConverterTests.cs | 3 +- .../Geometry/GeometrySimplifierTests.cs | 3 +- OpenNest.Tests/IO/DxfRoundtripTests.cs | 9 +- .../Splitting/DrawingSplitterTests.cs | 3 +- .../Splitting/SplitDxfWriterEtchLayerTests.cs | 3 +- .../Strategies/StrategyOverlapTests.cs | 3 +- OpenNest.Training/Program.cs | 4 +- OpenNest/Forms/BomImportForm.cs | 3 +- OpenNest/Forms/CadConverterForm.cs | 6 +- OpenNest/Forms/EditNestForm.cs | 8 +- 20 files changed, 405 insertions(+), 505 deletions(-) create mode 100644 OpenNest.IO/Dxf.cs delete mode 100644 OpenNest.IO/DxfExporter.cs delete mode 100644 OpenNest.IO/DxfImporter.cs diff --git a/OpenNest.Api/NestRunner.cs b/OpenNest.Api/NestRunner.cs index 234061c..db42296 100644 --- a/OpenNest.Api/NestRunner.cs +++ b/OpenNest.Api/NestRunner.cs @@ -25,14 +25,13 @@ public static class NestRunner // 1. Import DXFs → Drawings var drawings = new List(); - var importer = new DxfImporter(); - foreach (var part in request.Parts) { if (!File.Exists(part.DxfPath)) throw new FileNotFoundException($"DXF file not found: {part.DxfPath}", part.DxfPath); - if (!importer.GetGeometry(part.DxfPath, out var geometry) || geometry.Count == 0) + var geometry = Dxf.GetGeometry(part.DxfPath); + if (geometry.Count == 0) throw new InvalidOperationException($"Failed to import DXF: {part.DxfPath}"); var normalized = ShapeProfile.NormalizeEntities(geometry); diff --git a/OpenNest.Console/Program.cs b/OpenNest.Console/Program.cs index 3367193..c819812 100644 --- a/OpenNest.Console/Program.cs +++ b/OpenNest.Console/Program.cs @@ -241,17 +241,11 @@ static class NestConsole static Drawing ImportDxf(string path) { - var importer = new DxfImporter(); - - if (!importer.GetGeometry(path, out var geometry)) - { - Console.Error.WriteLine($"Error: failed to read DXF file: {path}"); - return null; - } + var geometry = Dxf.GetGeometry(path); if (geometry.Count == 0) { - Console.Error.WriteLine($"Error: no geometry found in DXF file: {path}"); + Console.Error.WriteLine($"Error: failed to read DXF file or no geometry found: {path}"); return null; } diff --git a/OpenNest.IO/Dxf.cs b/OpenNest.IO/Dxf.cs new file mode 100644 index 0000000..b60b147 --- /dev/null +++ b/OpenNest.IO/Dxf.cs @@ -0,0 +1,378 @@ +using ACadSharp; +using ACadSharp.IO; +using CSMath; +using OpenNest.CNC; +using OpenNest.Geometry; +using OpenNest.Math; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace OpenNest.IO +{ + using AcadArc = ACadSharp.Entities.Arc; + using AcadCircle = ACadSharp.Entities.Circle; + using AcadLine = ACadSharp.Entities.Line; + using Layer = ACadSharp.Tables.Layer; + + public static class Dxf + { + #region Import + + /// + /// Imports a DXF file, returning both converted entities and the raw CadDocument + /// for bend detection. The CadDocument is NOT disposed — caller can use it for + /// additional analysis (e.g., MText extraction for bend notes). + /// + public static DxfImportResult Import(string path) + { + using var reader = new DxfReader(path); + var doc = reader.Read(); + + return new DxfImportResult + { + Entities = ConvertEntities(doc), + Document = doc + }; + } + + public static List GetGeometry(string path) + { + try + { + using var reader = new DxfReader(path); + var doc = reader.Read(); + return ConvertEntities(doc); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + return new List(); + } + } + + public static List GetGeometry(Stream stream) + { + try + { + using var reader = new DxfReader(stream); + var doc = reader.Read(); + return ConvertEntities(doc); + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + return new List(); + } + } + + #endregion + + #region Export + + public static void ExportProgram(Program program, string path) + { + using var stream = File.Create(path); + ExportProgram(program, stream); + } + + public static void ExportProgram(Program program, Stream stream) + { + var ctx = new ExportContext(); + ctx.AddProgram(program); + + using var writer = new DxfWriter(stream, ctx.Document, false); + writer.Write(); + } + + public static void ExportPlate(Plate plate, string path) + { + using var stream = File.Create(path); + ExportPlate(plate, stream); + } + + public static void ExportPlate(Plate plate, Stream stream) + { + var ctx = new ExportContext(); + ctx.AddPlateOutline(plate); + + foreach (var part in plate.Parts) + { + var endpt = part.Location.ToAcadXYZ(); + ctx.AddLine(ctx.CurPos, endpt, ctx.RapidLayer); + ctx.CurPos = part.Location.ToAcadXYZ(); + ctx.AddProgram(part.Program); + } + + using var writer = new DxfWriter(stream, ctx.Document, false); + writer.Write(); + } + + #endregion + + #region Private + + private static List ConvertEntities(CadDocument doc) + { + var entities = new List(); + var lines = new List(); + var arcs = new List(); + + foreach (var entity in doc.Entities) + { + if (IsNonCutLayer(entity.Layer?.Name)) + continue; + + switch (entity) + { + case ACadSharp.Entities.Line line: + lines.Add(line.ToOpenNest()); + break; + + case ACadSharp.Entities.Arc arc: + arcs.Add(arc.ToOpenNest()); + break; + + case ACadSharp.Entities.Circle circle: + entities.Add(circle.ToOpenNest()); + break; + + case ACadSharp.Entities.Spline spline: + foreach (var e in spline.ToOpenNest()) + { + if (e is Line l) lines.Add(l); + else if (e is Arc a) arcs.Add(a); + } + break; + + case ACadSharp.Entities.LwPolyline lwPolyline: + lines.AddRange(lwPolyline.ToOpenNest()); + break; + + case ACadSharp.Entities.Polyline polyline: + lines.AddRange(polyline.ToOpenNest()); + break; + + case ACadSharp.Entities.Ellipse ellipse: + foreach (var e in ellipse.ToOpenNest()) + { + if (e is Line l) lines.Add(l); + else if (e is Arc a) arcs.Add(a); + } + break; + } + } + + GeometryOptimizer.Optimize(lines); + GeometryOptimizer.Optimize(arcs); + + entities.AddRange(lines); + entities.AddRange(arcs); + + return entities; + } + + private static bool IsNonCutLayer(string layerName) + { + return string.Equals(layerName, "BEND", StringComparison.OrdinalIgnoreCase) + || string.Equals(layerName, "ETCH", StringComparison.OrdinalIgnoreCase); + } + + private class ExportContext + { + public CadDocument Document { get; } + public XYZ CurPos { get; set; } + public Layer CutLayer { get; } + public Layer RapidLayer { get; } + public Layer PlateLayer { get; } + + private Mode mode; + + public ExportContext() + { + Document = new CadDocument(); + + CutLayer = new Layer("Cut") { Color = new Color(1) }; + RapidLayer = new Layer("Rapid") { Color = new Color(5) }; + PlateLayer = new Layer("Plate") { Color = new Color(4) }; + + Document.Layers.Add(CutLayer); + Document.Layers.Add(RapidLayer); + Document.Layers.Add(PlateLayer); + } + + public void AddLine(XYZ start, XYZ end, Layer layer) + { + var ln = new AcadLine + { + StartPoint = start, + EndPoint = end, + Layer = layer + }; + Document.Entities.Add(ln); + } + + public void AddPlateOutline(Plate plate) + { + XYZ pt1, pt2, pt3, pt4; + + switch (plate.Quadrant) + { + case 1: + pt1 = new XYZ(0, 0, 0); + pt2 = new XYZ(0, plate.Size.Width, 0); + pt3 = new XYZ(plate.Size.Length, plate.Size.Width, 0); + pt4 = new XYZ(plate.Size.Length, 0, 0); + break; + + case 2: + pt1 = new XYZ(0, 0, 0); + pt2 = new XYZ(0, plate.Size.Width, 0); + pt3 = new XYZ(-plate.Size.Length, plate.Size.Width, 0); + pt4 = new XYZ(-plate.Size.Length, 0, 0); + break; + + case 3: + pt1 = new XYZ(0, 0, 0); + pt2 = new XYZ(0, -plate.Size.Width, 0); + pt3 = new XYZ(-plate.Size.Length, -plate.Size.Width, 0); + pt4 = new XYZ(-plate.Size.Length, 0, 0); + break; + + case 4: + pt1 = new XYZ(0, 0, 0); + pt2 = new XYZ(0, -plate.Size.Width, 0); + pt3 = new XYZ(plate.Size.Length, -plate.Size.Width, 0); + pt4 = new XYZ(plate.Size.Length, 0, 0); + break; + + default: + return; + } + + AddLine(pt1, pt2, PlateLayer); + AddLine(pt2, pt3, PlateLayer); + AddLine(pt3, pt4, PlateLayer); + AddLine(pt4, pt1, PlateLayer); + + var m1 = new XYZ(pt1.X + plate.EdgeSpacing.Left, pt1.Y + plate.EdgeSpacing.Bottom, 0); + var m2 = new XYZ(m1.X, pt2.Y - plate.EdgeSpacing.Top, 0); + var m3 = new XYZ(pt3.X - plate.EdgeSpacing.Right, m2.Y, 0); + var m4 = new XYZ(m3.X, m1.Y, 0); + + AddLine(m1, m2, PlateLayer); + AddLine(m2, m3, PlateLayer); + AddLine(m3, m4, PlateLayer); + AddLine(m4, m1, PlateLayer); + } + + public void AddProgram(Program program) + { + mode = program.Mode; + + for (var i = 0; i < program.Length; ++i) + { + var code = program[i]; + + switch (code.Type) + { + case CodeType.ArcMove: + AddArcMove((ArcMove)code); + break; + + case CodeType.LinearMove: + AddLinearMove((LinearMove)code); + break; + + case CodeType.RapidMove: + AddRapidMove((RapidMove)code); + break; + + case CodeType.SubProgramCall: + var tmpmode = mode; + AddProgram(((SubProgramCall)code).Program); + mode = tmpmode; + break; + } + } + } + + private void AddLinearMove(LinearMove line) + { + var pt = line.EndPoint.ToAcadXYZ(); + + if (mode == Mode.Incremental) + pt = new XYZ(pt.X + CurPos.X, pt.Y + CurPos.Y, 0); + + AddLine(CurPos, pt, CutLayer); + CurPos = pt; + } + + private void AddRapidMove(RapidMove rapid) + { + var pt = rapid.EndPoint.ToAcadXYZ(); + + if (mode == Mode.Incremental) + pt = new XYZ(pt.X + CurPos.X, pt.Y + CurPos.Y, 0); + + AddLine(CurPos, pt, RapidLayer); + CurPos = pt; + } + + private void AddArcMove(ArcMove arc) + { + var center = arc.CenterPoint.ToAcadXYZ(); + var endpt = arc.EndPoint.ToAcadXYZ(); + + if (mode == Mode.Incremental) + { + endpt = new XYZ(endpt.X + CurPos.X, endpt.Y + CurPos.Y, 0); + center = new XYZ(center.X + CurPos.X, center.Y + CurPos.Y, 0); + } + + var startAngle = System.Math.Atan2( + CurPos.Y - center.Y, + CurPos.X - center.X); + + var endAngle = System.Math.Atan2( + endpt.Y - center.Y, + endpt.X - center.X); + + if (arc.Rotation == RotationType.CW) + Generic.Swap(ref startAngle, ref endAngle); + + var dx = endpt.X - center.X; + var dy = endpt.Y - center.Y; + var radius = System.Math.Sqrt(dx * dx + dy * dy); + + if (startAngle.IsEqualTo(endAngle)) + { + var circle = new AcadCircle + { + Center = center, + Radius = radius, + Layer = CutLayer + }; + Document.Entities.Add(circle); + } + else + { + var acadArc = new AcadArc + { + Center = center, + Radius = radius, + StartAngle = startAngle, + EndAngle = endAngle, + Layer = CutLayer + }; + Document.Entities.Add(acadArc); + } + + CurPos = endpt; + } + } + + #endregion + } +} diff --git a/OpenNest.IO/DxfExporter.cs b/OpenNest.IO/DxfExporter.cs deleted file mode 100644 index ff7faf7..0000000 --- a/OpenNest.IO/DxfExporter.cs +++ /dev/null @@ -1,297 +0,0 @@ -using ACadSharp; -using ACadSharp.IO; -using CSMath; -using OpenNest.CNC; -using OpenNest.Math; -using System.Diagnostics; -using System.IO; - -namespace OpenNest.IO -{ - using AcadArc = ACadSharp.Entities.Arc; - using AcadCircle = ACadSharp.Entities.Circle; - using AcadLine = ACadSharp.Entities.Line; - using Layer = ACadSharp.Tables.Layer; - - public class DxfExporter - { - private CadDocument doc; - private XYZ curpos; - private Mode mode; - private readonly Layer cutLayer; - private readonly Layer rapidLayer; - private readonly Layer plateLayer; - - public DxfExporter() - { - doc = new CadDocument(); - - cutLayer = new Layer("Cut"); - cutLayer.Color = new Color(1); - - rapidLayer = new Layer("Rapid"); - rapidLayer.Color = new Color(5); - - plateLayer = new Layer("Plate"); - plateLayer.Color = new Color(4); - } - - public void ExportProgram(Program program, Stream stream) - { - doc = new CadDocument(); - EnsureLayers(); - AddProgram(program); - using (var writer = new DxfWriter(stream, doc, false)) - { - writer.Write(); - } - } - - public bool ExportProgram(Program program, string path) - { - Stream stream = null; - var success = false; - - try - { - stream = File.Create(path); - ExportProgram(program, stream); - success = true; - } - catch - { - Debug.Fail("DxfExporter.ExportProgram failed to write program to file: " + path); - } - finally - { - if (stream != null) - stream.Close(); - } - - return success; - } - - public void ExportPlate(Plate plate, Stream stream) - { - doc = new CadDocument(); - EnsureLayers(); - AddPlateOutline(plate); - - foreach (var part in plate.Parts) - { - var endpt = part.Location.ToAcadXYZ(); - AddLine(curpos, endpt, rapidLayer); - curpos = part.Location.ToAcadXYZ(); - AddProgram(part.Program); - } - - using (var writer = new DxfWriter(stream, doc, false)) - { - writer.Write(); - } - } - - public bool ExportPlate(Plate plate, string path) - { - Stream stream = null; - var success = false; - - try - { - stream = File.Create(path); - ExportPlate(plate, stream); - success = true; - } - catch - { - Debug.Fail("DxfExporter.ExportPlate failed to write plate to file: " + path); - } - finally - { - if (stream != null) - stream.Close(); - } - - return success; - } - - private void EnsureLayers() - { - doc.Layers.Add(cutLayer); - doc.Layers.Add(rapidLayer); - doc.Layers.Add(plateLayer); - } - - private void AddLine(XYZ start, XYZ end, Layer layer) - { - var ln = new AcadLine(); - ln.StartPoint = start; - ln.EndPoint = end; - ln.Layer = layer; - doc.Entities.Add(ln); - } - - private void AddPlateOutline(Plate plate) - { - XYZ pt1; - XYZ pt2; - XYZ pt3; - XYZ pt4; - - switch (plate.Quadrant) - { - case 1: - pt1 = new XYZ(0, 0, 0); - pt2 = new XYZ(0, plate.Size.Width, 0); - pt3 = new XYZ(plate.Size.Length, plate.Size.Width, 0); - pt4 = new XYZ(plate.Size.Length, 0, 0); - break; - - case 2: - pt1 = new XYZ(0, 0, 0); - pt2 = new XYZ(0, plate.Size.Width, 0); - pt3 = new XYZ(-plate.Size.Length, plate.Size.Width, 0); - pt4 = new XYZ(-plate.Size.Length, 0, 0); - break; - - case 3: - pt1 = new XYZ(0, 0, 0); - pt2 = new XYZ(0, -plate.Size.Width, 0); - pt3 = new XYZ(-plate.Size.Length, -plate.Size.Width, 0); - pt4 = new XYZ(-plate.Size.Length, 0, 0); - break; - - case 4: - pt1 = new XYZ(0, 0, 0); - pt2 = new XYZ(0, -plate.Size.Width, 0); - pt3 = new XYZ(plate.Size.Length, -plate.Size.Width, 0); - pt4 = new XYZ(plate.Size.Length, 0, 0); - break; - - default: - return; - } - - AddLine(pt1, pt2, plateLayer); - AddLine(pt2, pt3, plateLayer); - AddLine(pt3, pt4, plateLayer); - AddLine(pt4, pt1, plateLayer); - - var m1 = new XYZ(pt1.X + plate.EdgeSpacing.Left, pt1.Y + plate.EdgeSpacing.Bottom, 0); - var m2 = new XYZ(m1.X, pt2.Y - plate.EdgeSpacing.Top, 0); - var m3 = new XYZ(pt3.X - plate.EdgeSpacing.Right, m2.Y, 0); - var m4 = new XYZ(m3.X, m1.Y, 0); - - AddLine(m1, m2, plateLayer); - AddLine(m2, m3, plateLayer); - AddLine(m3, m4, plateLayer); - AddLine(m4, m1, plateLayer); - } - - private void AddProgram(Program program) - { - mode = program.Mode; - - for (var i = 0; i < program.Length; ++i) - { - var code = program[i]; - - switch (code.Type) - { - case CodeType.ArcMove: - var arc = (ArcMove)code; - AddArcMove(arc); - break; - - case CodeType.LinearMove: - var line = (LinearMove)code; - AddLinearMove(line); - break; - - case CodeType.RapidMove: - var rapid = (RapidMove)code; - AddRapidMove(rapid); - break; - - case CodeType.SubProgramCall: - var tmpmode = mode; - var subpgm = (CNC.SubProgramCall)code; - AddProgram(subpgm.Program); - mode = tmpmode; - break; - } - } - } - - private void AddLinearMove(LinearMove line) - { - var pt = line.EndPoint.ToAcadXYZ(); - - if (mode == Mode.Incremental) - pt = new XYZ(pt.X + curpos.X, pt.Y + curpos.Y, 0); - - AddLine(curpos, pt, cutLayer); - curpos = pt; - } - - private void AddRapidMove(RapidMove rapid) - { - var pt = rapid.EndPoint.ToAcadXYZ(); - - if (mode == Mode.Incremental) - pt = new XYZ(pt.X + curpos.X, pt.Y + curpos.Y, 0); - - AddLine(curpos, pt, rapidLayer); - curpos = pt; - } - - private void AddArcMove(ArcMove arc) - { - var center = arc.CenterPoint.ToAcadXYZ(); - var endpt = arc.EndPoint.ToAcadXYZ(); - - if (mode == Mode.Incremental) - { - endpt = new XYZ(endpt.X + curpos.X, endpt.Y + curpos.Y, 0); - center = new XYZ(center.X + curpos.X, center.Y + curpos.Y, 0); - } - - var startAngle = System.Math.Atan2( - curpos.Y - center.Y, - curpos.X - center.X); - - var endAngle = System.Math.Atan2( - endpt.Y - center.Y, - endpt.X - center.X); - - if (arc.Rotation == OpenNest.RotationType.CW) - Generic.Swap(ref startAngle, ref endAngle); - - var dx = endpt.X - center.X; - var dy = endpt.Y - center.Y; - - var radius = System.Math.Sqrt(dx * dx + dy * dy); - - if (startAngle.IsEqualTo(endAngle)) - { - var circle = new AcadCircle(); - circle.Center = center; - circle.Radius = radius; - circle.Layer = cutLayer; - doc.Entities.Add(circle); - } - else - { - var arc2 = new AcadArc(); - arc2.Center = center; - arc2.Radius = radius; - arc2.StartAngle = startAngle; - arc2.EndAngle = endAngle; - arc2.Layer = cutLayer; - doc.Entities.Add(arc2); - } - - curpos = endpt; - } - } -} diff --git a/OpenNest.IO/DxfImporter.cs b/OpenNest.IO/DxfImporter.cs deleted file mode 100644 index 20e6321..0000000 --- a/OpenNest.IO/DxfImporter.cs +++ /dev/null @@ -1,153 +0,0 @@ -using ACadSharp; -using ACadSharp.IO; -using OpenNest.Geometry; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; - -namespace OpenNest.IO -{ - public class DxfImporter - { - public DxfImporter() - { - } - - private List GetGeometry(CadDocument doc) - { - var entities = new List(); - var lines = new List(); - var arcs = new List(); - - foreach (var entity in doc.Entities) - { - // Skip bend/etch entities — bends are converted to Bend objects - // separately via bend detection, and etch marks are generated from - // bends during DXF export. Neither should be treated as cut geometry. - if (IsNonCutLayer(entity.Layer?.Name)) - continue; - - switch (entity) - { - case ACadSharp.Entities.Line line: - lines.Add(line.ToOpenNest()); - break; - - case ACadSharp.Entities.Arc arc: - arcs.Add(arc.ToOpenNest()); - break; - - case ACadSharp.Entities.Circle circle: - entities.Add(circle.ToOpenNest()); - break; - - case ACadSharp.Entities.Spline spline: - foreach (var e in spline.ToOpenNest()) - { - if (e is Line l) lines.Add(l); - else if (e is Arc a) arcs.Add(a); - } - break; - - case ACadSharp.Entities.LwPolyline lwPolyline: - lines.AddRange(lwPolyline.ToOpenNest()); - break; - - case ACadSharp.Entities.Polyline polyline: - lines.AddRange(polyline.ToOpenNest()); - break; - - case ACadSharp.Entities.Ellipse ellipse: - foreach (var e in ellipse.ToOpenNest()) - { - if (e is Line l) lines.Add(l); - else if (e is Arc a) arcs.Add(a); - } - break; - } - } - - GeometryOptimizer.Optimize(lines); - GeometryOptimizer.Optimize(arcs); - - entities.AddRange(lines); - entities.AddRange(arcs); - - return entities; - } - - /// - /// Imports a DXF file, returning both converted entities and the raw CadDocument - /// for bend detection. The CadDocument is NOT disposed — caller can use it for - /// additional analysis (e.g., MText extraction for bend notes). - /// - public DxfImportResult Import(string path) - { - using var reader = new DxfReader(path); - var doc = reader.Read(); - var entities = GetGeometry(doc); - - return new DxfImportResult - { - Entities = entities, - Document = doc - }; - } - - public bool GetGeometry(Stream stream, out List geometry) - { - var success = false; - - try - { - using (var reader = new DxfReader(stream)) - { - var doc = reader.Read(); - geometry = GetGeometry(doc); - success = true; - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - geometry = new List(); - } - finally - { - if (stream != null) - stream.Close(); - } - - return success; - } - - public bool GetGeometry(string path, out List geometry) - { - var success = false; - - try - { - using (var reader = new DxfReader(path)) - { - var doc = reader.Read(); - geometry = GetGeometry(doc); - success = true; - } - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - geometry = new List(); - } - - return success; - } - - private static bool IsNonCutLayer(string layerName) - { - return string.Equals(layerName, "BEND", System.StringComparison.OrdinalIgnoreCase) - || string.Equals(layerName, "ETCH", System.StringComparison.OrdinalIgnoreCase); - } - } -} diff --git a/OpenNest.Mcp/Tools/InputTools.cs b/OpenNest.Mcp/Tools/InputTools.cs index 7d20be0..66b2f03 100644 --- a/OpenNest.Mcp/Tools/InputTools.cs +++ b/OpenNest.Mcp/Tools/InputTools.cs @@ -96,13 +96,10 @@ namespace OpenNest.Mcp.Tools if (!File.Exists(path)) return $"Error: file not found: {path}"; - var importer = new DxfImporter(); - - if (!importer.GetGeometry(path, out var geometry)) - return "Error: failed to read DXF file"; + var geometry = Dxf.GetGeometry(path); if (geometry.Count == 0) - return "Error: no geometry found in DXF file"; + return "Error: failed to read DXF file or no geometry found"; var normalized = ShapeProfile.NormalizeEntities(geometry); var pgm = ConvertGeometry.ToProgram(normalized); diff --git a/OpenNest.Tests/Api/NestRunnerTests.cs b/OpenNest.Tests/Api/NestRunnerTests.cs index f0cd4eb..50c5e5f 100644 --- a/OpenNest.Tests/Api/NestRunnerTests.cs +++ b/OpenNest.Tests/Api/NestRunnerTests.cs @@ -70,8 +70,7 @@ public class NestRunnerTests var pgm = ConvertGeometry.ToProgram(shape); var path = Path.Combine(Path.GetTempPath(), $"test-{Guid.NewGuid()}.dxf"); - var exporter = new DxfExporter(); - exporter.ExportProgram(pgm, path); + Dxf.ExportProgram(pgm, path); return path; } diff --git a/OpenNest.Tests/Bending/SolidWorksBendDetectorTests.cs b/OpenNest.Tests/Bending/SolidWorksBendDetectorTests.cs index 4949fbb..40e95b4 100644 --- a/OpenNest.Tests/Bending/SolidWorksBendDetectorTests.cs +++ b/OpenNest.Tests/Bending/SolidWorksBendDetectorTests.cs @@ -35,8 +35,7 @@ public class SolidWorksBendDetectorTests var path = Path.Combine(AppContext.BaseDirectory, "Bending", "TestData", "4526 A14 PT11 Test.dxf"); Assert.True(File.Exists(path), $"Test DXF not found: {path}"); - var importer = new OpenNest.IO.DxfImporter(); - var result = importer.Import(path); + var result = OpenNest.IO.Dxf.Import(path); // EllipseConverter now produces arcs directly during import, // so the imported entities should contain Arc instances from the ellipses @@ -61,8 +60,7 @@ public class SolidWorksBendDetectorTests var path = Path.Combine(AppContext.BaseDirectory, "Bending", "TestData", "4526 A14 PT11.dxf"); Assert.True(File.Exists(path), $"Test DXF not found: {path}"); - var importer = new OpenNest.IO.DxfImporter(); - var result = importer.Import(path); + var result = OpenNest.IO.Dxf.Import(path); // The DXF has 2 trimmed ellipses forming an oblong slot. // Trimmed ellipses must not generate a closing chord line. diff --git a/OpenNest.Tests/BestFit/BestFitOverlapTests.cs b/OpenNest.Tests/BestFit/BestFitOverlapTests.cs index 3e5a983..8a819b3 100644 --- a/OpenNest.Tests/BestFit/BestFitOverlapTests.cs +++ b/OpenNest.Tests/BestFit/BestFitOverlapTests.cs @@ -32,8 +32,7 @@ public class BestFitOverlapTests if (!File.Exists(DxfPath)) return null; - var importer = new DxfImporter(); - importer.GetGeometry(DxfPath, out var geometry); + var geometry = Dxf.GetGeometry(DxfPath); var pgm = ConvertGeometry.ToProgram(geometry); return new Drawing("PT16", pgm); } diff --git a/OpenNest.Tests/Engine/EngineOverlapTests.cs b/OpenNest.Tests/Engine/EngineOverlapTests.cs index 0ce14b9..0e5bdf2 100644 --- a/OpenNest.Tests/Engine/EngineOverlapTests.cs +++ b/OpenNest.Tests/Engine/EngineOverlapTests.cs @@ -20,8 +20,7 @@ public class EngineOverlapTests if (!System.IO.File.Exists(DxfPath)) return null; - var importer = new DxfImporter(); - importer.GetGeometry(DxfPath, out var geometry); + var geometry = Dxf.GetGeometry(DxfPath); var pgm = ConvertGeometry.ToProgram(geometry); return new Drawing("PT15", pgm); } diff --git a/OpenNest.Tests/Geometry/EllipseConverterTests.cs b/OpenNest.Tests/Geometry/EllipseConverterTests.cs index 25ef54d..b068bac 100644 --- a/OpenNest.Tests/Geometry/EllipseConverterTests.cs +++ b/OpenNest.Tests/Geometry/EllipseConverterTests.cs @@ -228,8 +228,7 @@ public class EllipseConverterTests using (var writer = new ACadSharp.IO.DxfWriter(stream, doc, false)) writer.Write(); - var importer = new OpenNest.IO.DxfImporter(); - var result = importer.Import(tempPath); + var result = OpenNest.IO.Dxf.Import(tempPath); var arcCount = result.Entities.Count(e => e is Arc); var lineCount = result.Entities.Count(e => e is Line); diff --git a/OpenNest.Tests/Geometry/GeometrySimplifierTests.cs b/OpenNest.Tests/Geometry/GeometrySimplifierTests.cs index d1573ae..d13e02f 100644 --- a/OpenNest.Tests/Geometry/GeometrySimplifierTests.cs +++ b/OpenNest.Tests/Geometry/GeometrySimplifierTests.cs @@ -138,8 +138,7 @@ public class GeometrySimplifierTests if (!File.Exists(path)) return; // skip if file not available - var importer = new DxfImporter(); - var result = importer.Import(path); + var result = Dxf.Import(path); var shapes = ShapeBuilder.GetShapes(result.Entities); var simplifier = new GeometrySimplifier { Tolerance = 0.004 }; diff --git a/OpenNest.Tests/IO/DxfRoundtripTests.cs b/OpenNest.Tests/IO/DxfRoundtripTests.cs index 25b66a7..452faf5 100644 --- a/OpenNest.Tests/IO/DxfRoundtripTests.cs +++ b/OpenNest.Tests/IO/DxfRoundtripTests.cs @@ -11,17 +11,14 @@ public class DxfRoundtripTests private static List ExportAndReimport(List geometry) { var program = ConvertGeometry.ToProgram(geometry); - var exporter = new DxfExporter(); - var importer = new DxfImporter(); - using var exportStream = new MemoryStream(); - exporter.ExportProgram(program, exportStream); + Dxf.ExportProgram(program, exportStream); var bytes = exportStream.ToArray(); var importStream = new MemoryStream(bytes); - var success = importer.GetGeometry(importStream, out var reimported); + var reimported = Dxf.GetGeometry(importStream); - Assert.True(success, "Failed to re-import exported DXF"); + Assert.NotEmpty(reimported); return reimported; } diff --git a/OpenNest.Tests/Splitting/DrawingSplitterTests.cs b/OpenNest.Tests/Splitting/DrawingSplitterTests.cs index 9b6704f..45ea0d8 100644 --- a/OpenNest.Tests/Splitting/DrawingSplitterTests.cs +++ b/OpenNest.Tests/Splitting/DrawingSplitterTests.cs @@ -369,8 +369,7 @@ public class DrawingSplitterTests var writer = new OpenNest.IO.SplitDxfWriter(); writer.Write(tempPath, results[0]); - var reimporter = new OpenNest.IO.DxfImporter(); - var reimportResult = reimporter.Import(tempPath); + var reimportResult = OpenNest.IO.Dxf.Import(tempPath); var afterArcs = reimportResult.Entities.OfType().Count(); var afterCircles = reimportResult.Entities.OfType().Count(); diff --git a/OpenNest.Tests/Splitting/SplitDxfWriterEtchLayerTests.cs b/OpenNest.Tests/Splitting/SplitDxfWriterEtchLayerTests.cs index 04bd91a..484c0e1 100644 --- a/OpenNest.Tests/Splitting/SplitDxfWriterEtchLayerTests.cs +++ b/OpenNest.Tests/Splitting/SplitDxfWriterEtchLayerTests.cs @@ -185,8 +185,7 @@ public class SplitDxfWriterEtchLayerTests writer.Write(tempPath, splitDrawing); // Re-import via DxfImporter (same path as CadConverterForm) - var importer = new DxfImporter(); - var result = importer.Import(tempPath); + var result = Dxf.Import(tempPath); // ETCH entities should be filtered during import (like BEND) var etchEntities = result.Entities diff --git a/OpenNest.Tests/Strategies/StrategyOverlapTests.cs b/OpenNest.Tests/Strategies/StrategyOverlapTests.cs index b954b5d..8cfa906 100644 --- a/OpenNest.Tests/Strategies/StrategyOverlapTests.cs +++ b/OpenNest.Tests/Strategies/StrategyOverlapTests.cs @@ -23,8 +23,7 @@ public class StrategyOverlapTests if (!System.IO.File.Exists(DxfPath)) return null; - var importer = new DxfImporter(); - importer.GetGeometry(DxfPath, out var geometry); + var geometry = Dxf.GetGeometry(DxfPath); var pgm = ConvertGeometry.ToProgram(geometry); return new Drawing("PT15", pgm); } diff --git a/OpenNest.Training/Program.cs b/OpenNest.Training/Program.cs index eeea637..e78e839 100644 --- a/OpenNest.Training/Program.cs +++ b/OpenNest.Training/Program.cs @@ -104,7 +104,6 @@ int RunDataCollection(string dir, string dbPath, string saveDir, double s, strin if (backfilled > 0) Console.WriteLine($"Backfilled PerimeterToAreaRatio for {backfilled} existing parts"); - var importer = new DxfImporter(); var colorIndex = 0; var processed = 0; var skippedGeometry = 0; @@ -129,7 +128,8 @@ int RunDataCollection(string dir, string dbPath, string saveDir, double s, strin continue; } - if (!importer.GetGeometry(file, out var entities)) + var entities = Dxf.GetGeometry(file); + if (entities.Count == 0) { Console.WriteLine(" - SKIP (no geometry)"); skippedGeometry++; diff --git a/OpenNest/Forms/BomImportForm.cs b/OpenNest/Forms/BomImportForm.cs index 3a49f63..64019a4 100644 --- a/OpenNest/Forms/BomImportForm.cs +++ b/OpenNest/Forms/BomImportForm.cs @@ -382,7 +382,6 @@ namespace OpenNest.Forms } var jobName = txtJobName.Text.Trim(); - var importer = new DxfImporter(); var nestsCreated = 0; var importErrors = new List(); @@ -416,7 +415,7 @@ namespace OpenNest.Forms try { - var result = importer.Import(part.DxfPath); + var result = Dxf.Import(part.DxfPath); var drawingName = Path.GetFileNameWithoutExtension(part.DxfPath); var drawing = new Drawing(drawingName); diff --git a/OpenNest/Forms/CadConverterForm.cs b/OpenNest/Forms/CadConverterForm.cs index d9b44cd..1e58e88 100644 --- a/OpenNest/Forms/CadConverterForm.cs +++ b/OpenNest/Forms/CadConverterForm.cs @@ -74,8 +74,7 @@ namespace OpenNest.Forms { try { - var importer = new DxfImporter(); - var result = importer.Import(file); + var result = Dxf.Import(file); if (result.Entities.Count == 0) return; @@ -383,8 +382,7 @@ namespace OpenNest.Forms newItems.Add(splitPath); // Re-import geometry but keep bends from the split drawing - var importer = new DxfImporter(); - var result = importer.Import(splitPath); + var result = Dxf.Import(splitPath); var splitItem = new FileListItem { diff --git a/OpenNest/Forms/EditNestForm.cs b/OpenNest/Forms/EditNestForm.cs index 9ab33bc..a7e83ce 100644 --- a/OpenNest/Forms/EditNestForm.cs +++ b/OpenNest/Forms/EditNestForm.cs @@ -362,9 +362,8 @@ namespace OpenNest.Forms { if (dlg.FilterIndex == 1) { - var exporter = new DxfExporter(); - var success = exporter.ExportPlate(PlateView.Plate, dlg.FileName); - return success; + Dxf.ExportPlate(PlateView.Plate, dlg.FileName); + return true; } else if (dlg.FilterIndex == 2) { @@ -540,8 +539,7 @@ namespace OpenNest.Forms var plate = PlateView.Plate; var name = string.Format("{0}-P{1}.dxf", Nest.Name, PlateManager.CurrentIndex + 1); var path = Path.Combine(Path.GetTempPath(), name); - var exporter = new DxfExporter(); - exporter.ExportPlate(plate, path); + Dxf.ExportPlate(plate, path); Process.Start(path); }