using System.Drawing; using System.Drawing.Drawing2D; using InABox.Core; using netDxf; using netDxf.Entities; using netDxf.Objects; using netDxf.Tables; using Svg; using Syncfusion.Pdf; namespace InABox.Dxf; public class DxfImportSettings { public Size ImageSize; public string[]? SupportFolders; public string? LayoutName { get; set; } public bool AutoFit { get; set; } public DxfImportSettings(Size? imageSize = null, string[]? supportFolders = null, string? layoutName = null, bool autoFit = true) { AutoFit = autoFit; ImageSize = imageSize ?? new(2048, 2048); SupportFolders = supportFolders; LayoutName = layoutName ?? "Model"; } } public class DxfData { public DxfDocument Document { get; set; } public DxfImportSettings Settings { get; set; } public SizeF Size { get; set; } public PointF Origin { get; set; } public Layout Layout { get; set; } public IEnumerable LayoutNames => Document.Layouts.Select(x => x.Name); public HashSet? Layers { get; set; } public bool HasLayer(Layer layer) { return Layers is null || Layers.Contains(layer.Name); } public void SetLayers(params string[] layers) { Layers = layers.ToHashSet(); } public void SetLayers(IEnumerable layers) { Layers = layers.ToHashSet(); } public bool ShouldDraw(EntityObject obj) { return obj.IsVisible && HasLayer(obj.Layer); } public string LayoutName { get => Layout.Name; set { Layout = Document.Layouts.First(x => x.Name == value); UpdateSizeAndOrigin(); } } public DxfData(DxfDocument document, DxfImportSettings settings) { Document = document; Settings = settings; Layout = settings.LayoutName is not null ? document.Layouts.First(x => x.Name == settings.LayoutName) : document.Layouts.First(); UpdateSizeAndOrigin(); } private void UpdateSizeAndOrigin() { if (Settings.AutoFit) { var bounds = DxfUtils.CalculateDxfSize(this) ?? new(); var margin = 0.1f * Math.Min(bounds.Width, bounds.Height); if (bounds.IsEmpty) { bounds.Size = new(100, 100); bounds.Location = new(0, 0); } else { bounds.Size = new(bounds.Width + margin * 2, bounds.Height + margin * 2); bounds.Location = new(bounds.X - margin, bounds.Y - margin); } Size = bounds.Size; Origin = bounds.Location; } else { Size = new((float)(Layout.MaxLimit.X - Layout.MinLimit.X), (float)(Layout.MaxLimit.Y - Layout.MinLimit.Y)); Origin = new((float)Layout.MinLimit.X, (float)Layout.MinLimit.Y); } } } public static class DxfUtils { public static event ProcessError OnProcessError; public delegate void ProcessError(string message); internal static IDxfObject? ConvertEl(EntityObject el) { if(el is Line line) { return new DxfLine { Line = line }; } else if(el is Insert insert) { return new DxfInsert(insert); } else if(el is Ellipse ellipse) { return new DxfEllipse(ellipse); } else if(el is MText text) { return new DxfMText(text); } else if(el is Polyline2D ln2D) { return new DxfPolyline2D(ln2D); } else if(el is Dimension dim) { return new DxfDimension(dim); } else if(el is Solid solid) { return new DxfSolid(solid); } else if (el is netDxf.Entities.Point point) { return null; } else if (el is netDxf.Entities.Viewport viewport) { return null; } else if (el is Arc a) { return new DxfArc(a); } else if(el is Text t) { return new DxfText(t); } else { return null; } } public static void DrawDxf(DxfData data, IGraphics graphics, float width, float height) { // Calculate the scaling factor to fit the image within the bounds float ratioX = (float)data.Settings.ImageSize.Width / data.Size.Width; float ratioY = (float)data.Settings.ImageSize.Height / data.Size.Height; var scale = Math.Min(ratioX, ratioY); var drawData = new DrawData() { Graphics = graphics, Data = data }; graphics.Clear(Color.White); // drawData.Translate(graphics.VisibleClipBounds.Width / 2, graphics.VisibleClipBounds.Height / 2); drawData.Scale(scale, scale); drawData.Translate(-data.Origin.X, -data.Origin.Y); // drawData.Translate(-data.Origin.X - data.Size.Width / 2, -data.Origin.Y - data.Size.Height / 2); foreach(var el in data.Layout.AssociatedBlock.Entities) { var item = ConvertEl(el); item?.Draw(drawData); } graphics.Finish(); } public static DxfData LoadDxf(string filename, DxfImportSettings? settings = null) { using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read); settings ??= new(); var document = DxfDocument.Load(stream, settings.SupportFolders ?? Array.Empty()); document.BuildDimensionBlocks = true; return new(document, settings); } public static DxfData LoadDxf(Stream stream, DxfImportSettings? settings = null) { settings ??= new(); var document = DxfDocument.Load(stream, settings.SupportFolders ?? Array.Empty()); return new(document, settings); } /// /// Returns if the bounds are completely empty. /// /// /// public static RectangleF? CalculateDxfSize(DxfData data) { var transformData = new TransformData { Data = data }; RectangleF? bounds = null; foreach(var el in data.Document.Entities.All) { if(ConvertEl(el) is IDxfObject obj) { bounds = Utils.CombineBounds(bounds, obj.GetBounds(transformData)); } } return bounds; } public static Bitmap ProcessImage(DxfData data) { var height = data.Size.Height; var width = data.Size.Width; // Calculate the scaling factor to fit the image within the bounds float ratioX = (float)data.Settings.ImageSize.Width / width; float ratioY = (float)data.Settings.ImageSize.Height / height; var scale = Math.Min(ratioX, ratioY); var _result = new Bitmap((int)(width * scale), (int)(height * scale)); using (var _graphics = Graphics.FromImage(_result)) { _graphics.SmoothingMode = SmoothingMode.AntiAlias; DrawDxf(data, new GdiGraphics(_graphics), _result.Width, _result.Height); } _result.RotateFlip(RotateFlipType.RotateNoneFlipY); return _result; } public static PdfDocument ProcessPdf(DxfData data) { var doc = new PdfDocument(); doc.PageSettings.Size = data.Size; doc.PageSettings.SetMargins(0); var page = doc.Pages.Add(); var graphics = page.Graphics; var drawData = new DrawData() { Graphics = new PdfGraphics(page.Graphics), Data = data }; drawData.PushTransform(); drawData.Translate(data.Size.Width / 2, data.Size.Height / 2); drawData.Scale(1, -1); drawData.Translate(-data.Size.Width / 2, -data.Size.Height / 2); drawData.Translate(-data.Origin.X, -data.Origin.Y); if (data.Layout.IsPaperSpace) { var modelSpace = data.Document.Layouts.First(x => x.Name == "Model"); foreach(var el in modelSpace.AssociatedBlock.Entities) { var item = ConvertEl(el); item?.Draw(drawData); } } foreach(var el in data.Layout.AssociatedBlock.Entities) { var item = ConvertEl(el); item?.Draw(drawData); } drawData.PopTransform(); drawData.Graphics.Finish(); return doc; } // public static PdfDocument ProcessPdf(DxfData data) // { // var doc = new PdfDocument(); // var size = data.Size; // var origin = data.Origin; // foreach(var layout in data.LayoutNames) // { // data.LayoutName = layout; // Matrix4x4 transform; // if (data.Layout.IsPaperSpace) // { // var viewport = data.Layout.Viewport; // var scale = (float)(viewport.ViewHeight == 0 ? 0 : viewport.Height / viewport.ViewHeight); // data.Origin = new((float)(viewport.ViewCenter.X - viewport.Width / 2), (float)(viewport.ViewCenter.Y - viewport.Height / 2)); // data.Size = new((float)viewport.Width, (float)viewport.Height); // var normal = -System.Numerics.Vector3.Cross(viewport.UcsXAxis.ToVec3(), viewport.UcsYAxis.ToVec3()); // transform = Matrix4x4.CreateLookAt(viewport.UcsOrigin.ToVec3(), viewport.UcsOrigin.ToVec3() + normal, viewport.UcsYAxis.ToVec3()) // * Matrix4x4.CreateScale(scale) // * Matrix4x4.CreateRotationZ((float)viewport.TwistAngle); // } // else // { // data.Size = size; // data.Origin = origin; // transform = Matrix4x4.Identity; // } // var section = doc.Sections.Add(); // section.PageSettings.Size = data.Size; // section.PageSettings.SetMargins(0); // var page = section.Pages.Add(); // var graphics = page.Graphics; // var drawData = new DrawData() { Graphics = new PdfGraphics(page.Graphics), Data = data }; // drawData.PushTransform(); // drawData.Translate(data.Size.Width / 2, data.Size.Height / 2); // drawData.Scale(1, -1); // drawData.Translate(-data.Size.Width / 2, -data.Size.Height / 2); // drawData.Translate(-data.Origin.X, -data.Origin.Y); // drawData.TransformBy(transform); // if (data.Layout.IsPaperSpace) // { // var modelSpace = data.Document.Layouts.First(x => x.Name == "Model"); // foreach(var el in modelSpace.AssociatedBlock.Entities) // { // var item = ConvertEl(el); // item?.Draw(drawData); // } // } // foreach(var el in data.Layout.AssociatedBlock.Entities) // { // var item = ConvertEl(el); // item?.Draw(drawData); // } // drawData.PopTransform(); // drawData.Graphics.Finish(); // } // return doc; // } public static SvgDocument ProcessSvg(DxfData data) { var doc = new SvgDocument { ViewBox = new(data.Origin.X, data.Origin.Y, data.Size.Width, data.Size.Height) }; var drawData = new DrawData() { Graphics = new SvgGraphics(doc), Data = data }; foreach(var el in data.Layout.AssociatedBlock.Entities) { var item = ConvertEl(el); item?.Draw(drawData); } drawData.Graphics.Finish(); return doc; } public static Bitmap ProcessImage(Stream stream, DxfImportSettings? settings = null) { return ProcessImage(LoadDxf(stream, settings)); } public static Result DXFToBitmap(string filename, DxfImportSettings? settings = null) { using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read); try { return Result.Ok(ProcessImage(stream, settings: settings)); } catch (Exception e) { OnProcessError?.Invoke(e.Message); return Result.Error(e); } } }