| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743 | using InABox.Core;using netDxf;using netDxf.Tables;using Svg;using Svg.Transforms;using Syncfusion.Pdf;using Syncfusion.Pdf.Graphics;using Syncfusion.Pdf.Parsing;using System;using System.Collections.Generic;using System.Drawing;using System.Drawing.Drawing2D;using System.Linq;using System.Numerics;using System.Text;using System.Threading.Tasks;using FontStyle = System.Drawing.FontStyle;using Vector2 = System.Numerics.Vector2;using Vector3 = System.Numerics.Vector3;using Vector4 = System.Numerics.Vector4;using SPdfGraphics = Syncfusion.Pdf.Graphics.PdfGraphics;using Syncfusion.Pdf.Tables;using netDxf.Entities;namespace InABox.Dxf;public enum TextAlignment{    Left,    Center,    Right,    Fit,    Justify}public enum TextLineAlignment{    Top,    Center,    Bottom,    Baseline}public class TextFormat{    public TextAlignment Alignment { get; set; } = TextAlignment.Left;    public TextLineAlignment LineAlignment { get; set; } = TextLineAlignment.Top;}public class TransformData{    public DxfData Data { get; set; }    private Stack<Matrix4x4> MatrixStack = new();    public Matrix4x4 Transform { get; private set; } = Matrix4x4.Identity;    public void PushTransform()    {        MatrixStack.Push(Transform);    }    public void TransformBy(Matrix4x4 matrix)    {        Transform = matrix * Transform;    }    protected virtual void UpdateTransform()    {    }    protected Matrix ProjectMatrix(Matrix4x4 matrix)    {        var elMatrix = new Matrix3x2();        elMatrix.M11 = (float)matrix.M11;        elMatrix.M12 = (float)matrix.M12;        elMatrix.M21 = (float)matrix.M21;        elMatrix.M22 = (float)matrix.M22;        elMatrix.M31 = (float)matrix.M41;        elMatrix.M32 = (float)matrix.M42;        var newMatrix = new Matrix();        newMatrix.MatrixElements = elMatrix;        return newMatrix;    }    public void PopTransform()    {        Transform = MatrixStack.Pop();        UpdateTransform();    }    public static Matrix4x4 ArbitraryAxisMatrix(Vector3 zAxis)    {        if (zAxis.Equals(Vector3.UnitZ))        {            return Matrix4x4.Identity;        }        var unitY = Vector3.UnitY;        var unitZ = Vector3.UnitZ;        var v = ((!(Math.Abs(zAxis.X) < 1.0 / 64.0) || !(Math.Abs(zAxis.Y) < 1.0 / 64.0)) ? Vector3.Cross(unitZ, zAxis) : Vector3.Cross(unitY, zAxis));        v = Vector3.Normalize(v);        var vector = Vector3.Cross(zAxis, v);        vector = Vector3.Normalize(vector);        return new Matrix4x4(v.X, vector.X, zAxis.X, 0, v.Y, vector.Y, zAxis.Y, 0, v.Z, vector.Z, zAxis.Z, 0, 0, 0, 0, 1);    }    public void ArbitraryAxis(netDxf.Vector3 zAxis)    {        Transform = ArbitraryAxisMatrix(new((float)zAxis.X, (float)zAxis.Y, (float)zAxis.Z)) * Transform;        UpdateTransform();    }    public void ArbitraryAxis(Vector3 zAxis)    {        Transform = ArbitraryAxisMatrix(zAxis) * Transform;        UpdateTransform();    }    public void Translate(float x, float y)    {        Transform = Transform.Translate(x, y, 0);        UpdateTransform();    }    public void Translate(PointF point)    {        Transform = Transform.Translate(point.X, point.Y, 0);        UpdateTransform();    }    public void Rotate(float angle)    {        Transform = Transform.Rotate(0, 0, 1, angle);        UpdateTransform();    }    public void Scale(float scale)    {        Scale(scale, scale);    }    public void Scale(float scaleX, float scaleY)    {        Transform = Transform.Scale(scaleX, scaleY, 1);        UpdateTransform();    }    public PointF TransformPoint(float x, float y)    {        var nVec = Vector4.Transform(new Vector4(x, y, 0, 1), Transform);        return new(nVec.X, nVec.Y);    }    public PointF TransformPoint(PointF vec)    {        var nVec = Vector4.Transform(new Vector4(vec.X, vec.Y, 0, 1), Transform);        return new(nVec.X, nVec.Y);    }    public PointF TransformPoint(netDxf.Vector2 vec)    {        var nVec = Vector4.Transform(new Vector4((float)vec.X, (float)vec.Y, 0, 1), Transform);        return new(nVec.X, nVec.Y);    }    public PointF TransformPoint(netDxf.Vector3 vec)    {        var nVec = Vector4.Transform(new Vector4((float)vec.X, (float)vec.Y, (float)vec.Z, 1), Transform);        return new(nVec.X, nVec.Y);    }    public PointF TransformVec(PointF vec)    {        var nVec = Vector4.Transform(new Vector4(vec.X, vec.Y, 0, 0), Transform);        return new(nVec.X, nVec.Y);    }    public Vector2 TransformVec(Vector2 vec)    {        var nVec = Vector4.Transform(new Vector4(vec.X, vec.Y, 0, 0), Transform);        return new(nVec.X, nVec.Y);    }    public float ScaleFactor()    {        return (TransformVec(new Vector2(1, 0))).Length();    }    public static PointF ConvertPoint(netDxf.Vector2 vec)    {        return new PointF((float)vec.X, (float)vec.Y);    }    public static PointF ConvertPoint(netDxf.Vector3 vec)    {        return new PointF((float)vec.X, (float)vec.Y);    }}public class DrawData : TransformData{    private IGraphics _graphics;    public IGraphics Graphics    {        get => _graphics;        set        {            _graphics = value;            _graphics.DrawData = this;        }    }    private Stack<Color> _blockColours = new();    public Color BlockColour { get; set; } = Color.Black;    public void PushBlockColour(AciColor colour, EntityObject? obj)    {        _blockColours.Push(BlockColour);        BlockColour = ResolveColour(colour, obj);    }    public void PushBlockColour(Color colour)    {        _blockColours.Push(BlockColour);        BlockColour = colour;    }    public void PopBlockColour()    {        BlockColour = _blockColours.Pop();    }    public Color ResolveColour(AciColor colour, EntityObject? obj)    {        if (colour.IsByBlock)        {            return _blockColours.Count > 0                ? BlockColour                : (obj?.Layer is null ? Color.Black : ResolveColour(obj.Layer.Color, null));        }        else if (colour.IsByLayer)        {            return obj?.Layer is null ? Color.Black : ResolveColour(obj.Layer.Color, null);        }        if(colour.Index == 7)        {            return Color.Black;        }        else        {            return colour.ToColor();        }    }    protected override void UpdateTransform()    {        base.UpdateTransform();        Graphics.SetTransform(ProjectMatrix(Transform));    }}public interface IGraphics{    DrawData DrawData { get; set; }    void SetTransform(Matrix transform);    void DrawLine(Color color, float thickness, params PointF[] points);    void DrawPoint(Color color, float thickness, PointF point);    void FillPolygon(Color color, params PointF[] points);    /// <summary>    /// Set the current font to be the default font at the given <paramref name="fontSize"/>.    /// </summary>    /// <param name="fontSize">Size of the new font.</param>    void SetFont(float fontSize, FontStyle fontStyle = FontStyle.Regular);    void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular);    void DrawText(string text, Color color, PointF position, float rotation, TextFormat format);    void DrawText(string text, Color color, PointF position, float rotation, float width, PointF scale);    void DrawText(string text, Color color, PointF position, float rotation, SizeF size, PointF scale);    void Clear(Color color);    void Finish();}public class GdiGraphics : IGraphics{    public Graphics Graphics { get; set; }    private Font Font { get; set; }    public DrawData DrawData { get; set; }    public GdiGraphics(Graphics graphics)    {        Graphics = graphics;    }    // public float ConvertThickness(float thickness)    // {    //     return thickness == 0 ? 1f / ScaleFactor() : thickness;    // }    public void DrawLine(Color color, float thickness, params PointF[] points)    {        if(points.Length == 2)        {            Graphics.DrawLine(new Pen(color, thickness), points[0], points[1]);        }        else        {            Graphics.DrawLines(new Pen(color, thickness), points);        }    }    public void DrawPoint(Color color, float thickness, PointF point)    {        Graphics.FillEllipse(new SolidBrush(color), point.X - thickness / 2, point.Y - thickness / 2, point.X + thickness / 2, point.Y + thickness / 2);    }    private void TransformTextVertical(string text, Font font, PointF position, float rotation, TextFormat format)    {        DrawData.Translate(position);        DrawData.Rotate(rotation);        DrawData.Scale(1, -1);        var ascentRatio = (float)font.FontFamily.GetCellAscent(font.Style) / font.FontFamily.GetLineSpacing(font.Style);        var size = Graphics.MeasureString(text, font, new PointF(), StringFormat.GenericTypographic);        var scaleFactor = ascentRatio * font.Height / size.Height;        DrawData.Scale(scaleFactor, scaleFactor);        switch (format.LineAlignment)        {            case TextLineAlignment.Center:                DrawData.Translate(new PointF(0, -size.Height / 2));                break;            case TextLineAlignment.Bottom:                DrawData.Translate(new PointF(0, -size.Height));                break;            case TextLineAlignment.Baseline:                var baseline = ascentRatio * font.Height;                DrawData.Translate(new PointF(0, -baseline));                break;            case TextLineAlignment.Top:                baseline = ascentRatio * font.Height;                var lineSpace = font.FontFamily.GetLineSpacing(font.Style);                var ratio = font.GetHeight(Graphics) / lineSpace;                DrawData.Translate(new PointF(0, -baseline + font.FontFamily.GetCellAscent(font.Style) * ratio));                break;        }    }    public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)    {        if (text.IsNullOrWhiteSpace())        {            return;        }        DrawData.PushTransform();        TransformTextVertical(text, Font, position, rotation, format);        var pos = 0;        foreach(var line in text.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))        {            DrawData.PushTransform();            DrawData.Translate(0, pos * Font.Height);            var size = Graphics.MeasureString(line, Font);            switch (format.Alignment)            {                case TextAlignment.Left:                    break;                case TextAlignment.Center:                    DrawData.Translate(new PointF(-(float)size.Width / 2, 0));                    break;                case TextAlignment.Right:                    DrawData.Translate(new PointF(-(float)size.Width, 0));                    break;            }            Graphics.DrawString(line, Font, new SolidBrush(color), new PointF(0, 0), StringFormat.GenericTypographic);            DrawData.PopTransform();            ++pos;        }        DrawData.PopTransform();    }    public void DrawText(string text, Color color, PointF position, float rotation, float width, PointF scale)    {        var size = Graphics.MeasureString(text, Font, new PointF(), StringFormat.GenericTypographic);        DrawText(text, color, position, rotation, new SizeF(width, size.Height * width / size.Width), scale);    }    public void DrawText(string text, Color color, PointF position, float rotation, SizeF size, PointF scale)    {        DrawData.PushTransform();        DrawData.Translate(position);        DrawData.Rotate(rotation);        DrawData.Scale(1, -1);        var (width, height) = (size.Width, size.Height);        DrawData.Translate(width / 2, height / 2);        DrawData.Scale(scale.X, scale.Y);        DrawData.Translate(-width / 2, -height / 2);        DrawData.Scale(width / size.Width, height / size.Height);        Graphics.DrawString(text, Font, new SolidBrush(color), new PointF(0, 0), StringFormat.GenericTypographic);        DrawData.PopTransform();    }    public void FillPolygon(Color color, params PointF[] points)    {        Graphics.FillPolygon(new SolidBrush(color), points);    }    public void SetFont(string fontName, float fontSize, FontStyle fontStyle)    {        var fontFamily = new FontFamily(fontName);        var font = new Font(fontFamily, fontSize, fontStyle);        Font = font;    }    public void SetFont(float fontSize, FontStyle fontStyle)    {        var fontFamily = SystemFonts.DefaultFont.FontFamily;        var font = new Font(fontFamily, fontSize, fontStyle);        Font = font;    }    public void SetTransform(Matrix transform)    {        Graphics.Transform = transform;    }    public void Clear(Color color)    {        Graphics.Clear(color);    }    public void Finish()    {    }}public class PdfGraphics : IGraphics{    public DrawData DrawData { get; set; }    private SPdfGraphics Graphics { get; set; }    private Matrix _transform = new();    private PdfFont _font = new PdfStandardFont(PdfFontFamily.Helvetica, 12, PdfFontStyle.Regular);    private float _ascentRatio = 0;    public PdfGraphics(SPdfGraphics graphics)    {        Graphics = graphics;    }    public void Clear(Color color)    {    }    public void SetTransform(Matrix transform)    {        _transform = transform;    }    public void DrawLine(Color color, float thickness, params PointF[] points)    {        _transform.TransformPoints(points);        var pen = new PdfPen(color, thickness);        for(int i = 0; i < points.Length - 1; ++i)        {            Graphics.DrawLine(pen, points[i], points[i + 1]);        }    }    public void DrawPoint(Color color, float thickness, PointF point)    {        var transformed = _transform.Transform(point);        var brush = new PdfSolidBrush(color);        Graphics.DrawEllipse(brush, transformed.X - thickness / 2, transformed.Y - thickness / 2, transformed.X + thickness / 2, transformed.Y + thickness / 2);    }    public void SetFont(float fontSize, FontStyle fontStyle = FontStyle.Regular)    {        var font = new Font(SystemFonts.DefaultFont.FontFamily, fontSize);        _ascentRatio = (float)font.FontFamily.GetCellAscent(font.Style) / (float)font.FontFamily.GetLineSpacing(font.Style);        _font = new PdfTrueTypeFont(font);    }    public void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular)    {        var font = new Font(fontName, fontSize);        _ascentRatio = (float)font.FontFamily.GetCellAscent(font.Style) / (float)font.FontFamily.GetLineSpacing(font.Style);        _font = new PdfTrueTypeFont(new Font(fontName, fontSize));    }    public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)    {        var fmt = new PdfStringFormat();        fmt.Alignment = format.Alignment switch        {            TextAlignment.Center => PdfTextAlignment.Center,            TextAlignment.Right => PdfTextAlignment.Right,            TextAlignment.Justify => PdfTextAlignment.Justify,            _ => PdfTextAlignment.Left,        };        fmt.LineAlignment = format.LineAlignment switch        {            TextLineAlignment.Center => PdfVerticalAlignment.Middle,            TextLineAlignment.Bottom => PdfVerticalAlignment.Bottom,            TextLineAlignment.Baseline => PdfVerticalAlignment.Bottom,            _ => PdfVerticalAlignment.Top        };        if(format.LineAlignment == TextLineAlignment.Baseline)        {            fmt.EnableBaseline = true;        }        Graphics.Save();        var point = _transform.Transform(position);        Graphics.TranslateTransform(point.X, point.Y);        Graphics.RotateTransform(_transform.GetRotation() - rotation);        var scaled = _transform.GetScale();        Graphics.ScaleTransform(scaled / _ascentRatio, scaled / _ascentRatio);        Graphics.DrawString(text, _font, new PdfSolidBrush(color), new PointF(), fmt);        Graphics.Restore();    }    public void DrawText(string text, Color color, PointF position, float rotation, float width, PointF scale)    {        Graphics.Save();        var point = _transform.Transform(position);        Graphics.TranslateTransform(point.X, point.Y);        Graphics.RotateTransform(_transform.GetRotation() - rotation);        var scaleFactor = (_font.Height / _font.Size) * _transform.GetScale();        Graphics.ScaleTransform(scaleFactor, scaleFactor * scale.Y);        if(scale.X != 1)        {            Graphics.TranslateTransform(width / 2, 0);            Graphics.ScaleTransform(scale.X, 1);            Graphics.TranslateTransform(-width / 2, 0);        }        Graphics.DrawString(text, _font, new PdfSolidBrush(color), new RectangleF(0, 0, width, float.MaxValue), new PdfStringFormat        {            Alignment = PdfTextAlignment.Justify,            LineAlignment = PdfVerticalAlignment.Top,            EnableBaseline = true        });        Graphics.Restore();    }    public void DrawText(string text, Color color, PointF position, float rotation, SizeF size, PointF scale)    {        Graphics.Save();        var point = _transform.Transform(position);        Graphics.TranslateTransform(point.X, point.Y);        Graphics.RotateTransform(_transform.GetRotation() - rotation);        var scaleFactor = (_font.Height / _font.Size) * _transform.GetScale();        Graphics.ScaleTransform(scaleFactor, scaleFactor * scale.Y);        if(scale.X != 1 || scale.Y != 1)        {            Graphics.TranslateTransform(size.Width / 2, size.Height / 2);            Graphics.ScaleTransform(scale.X, 1);            Graphics.TranslateTransform(-size.Width / 2, size.Height / 2);        }        Graphics.DrawString(text, _font, new PdfSolidBrush(color), new RectangleF(0, 0, size.Width, size.Height), new PdfStringFormat        {            Alignment = PdfTextAlignment.Justify,            LineAlignment = PdfVerticalAlignment.Top,            EnableBaseline = true        });        Graphics.Restore();    }    public void FillPolygon(Color color, params PointF[] points)    {        _transform.TransformPoints(points);        var brush = new PdfSolidBrush(color);        Graphics.DrawPolygon(brush, points);    }    public void Finish()    {    }}public class SvgGraphics : IGraphics{    public DrawData DrawData { get; set; }    public SvgDocument Document { get; set; }    private SvgMatrix _transform = new(new Matrix().Elements.ToList());    private SvgGroup _group;    private Matrix _groupTransform = new();    private static string[][] _groupProps = new[]    {        new[] { "stroke-width", "style" },        new[] { "vector-effect" }    };    public SvgGraphics(SvgDocument document)    {        Document = document;        _group = new SvgGroup();        Document.Stroke = new SvgColourServer(Color.Black);    }    private void PushGroup()    {        if(_group.Children.Count > 0)        {            Document.Children.Add(_group);        }    }    private void AddChild(SvgElement item)    {        var transMat = _transform.Matrix;        if(!Equals(transMat, _groupTransform))        {            PushGroup();            _group = new();            _group.Transforms = new() { _transform };            _groupTransform = transMat;        }        _group.Children.Add(item);    }    public void SetTransform(Matrix transform)    {        _transform = new(transform.Elements.ToList());    }    public void DrawLine(Color color, float thickness, params PointF[] points)    {        if(points.Length == 2)        {            var line = new SvgLine            {                StartX = points[0].X,                StartY = points[0].Y,                EndX = points[1].X,                EndY = points[1].Y            };            if(color != Color.Black)            {                line.Stroke = new SvgColourServer(color);            }            if(thickness == 0)            {                line.StrokeWidth = 1;                line.CustomAttributes.Add("vector-effect", "non-scaling-stroke");            }            else            {                line.StrokeWidth = thickness;            }            AddChild(line);        }        else        {            var line = new SvgPolyline();            if(color != Color.Black)            {                line.Stroke = new SvgColourServer(color);            }            foreach(var point in points)            {                line.Points.Add(point.X);                line.Points.Add(point.Y);            }            if(thickness == 0)            {                line.StrokeWidth = 1;                line.CustomAttributes.Add("vector-effect", "non-scaling-stroke");            }            else            {                line.StrokeWidth = thickness;            }            AddChild(line);        }    }    public void DrawPoint(Color color, float thickness, PointF point)    {    }    public void FillPolygon(Color color, params PointF[] points)    {    }    public void SetFont(float fontSize, FontStyle fontStyle = FontStyle.Regular)    {    }    public void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular)    {    }    public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)    {    }    public void Clear(Color color)    {    }    public void Finish()    {        PushGroup();    }    public void DrawText(string text, Color color, PointF position, float rotation, float width, PointF scale)    {    }    public void DrawText(string text, Color color, PointF position, float rotation, SizeF size, PointF scale)    {    }}
 |