| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 | 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<string> LayoutNames => Document.Layouts.Select(x => x.Name);    public HashSet<string>? 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<string> 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<string>());        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<string>());        return new(document, settings);    }    /// <summary>    /// Returns <see langword="null"/> if the bounds are completely empty.    /// </summary>    /// <param name="data"></param>    /// <returns></returns>    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<Bitmap, Exception> 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);        }    }}
 |