DrawData.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. using netDxf;
  2. using netDxf.Tables;
  3. using Svg;
  4. using Svg.Transforms;
  5. using Syncfusion.Pdf;
  6. using Syncfusion.Pdf.Graphics;
  7. using Syncfusion.Pdf.Parsing;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Drawing;
  11. using System.Drawing.Drawing2D;
  12. using System.Linq;
  13. using System.Numerics;
  14. using System.Text;
  15. using System.Threading.Tasks;
  16. using FontStyle = System.Drawing.FontStyle;
  17. using Vector2 = System.Numerics.Vector2;
  18. using Vector3 = System.Numerics.Vector3;
  19. using Vector4 = System.Numerics.Vector4;
  20. using SPdfGraphics = Syncfusion.Pdf.Graphics.PdfGraphics;
  21. using Syncfusion.Pdf.Tables;
  22. using netDxf.Entities;
  23. namespace InABox.Dxf;
  24. public enum TextAlignment
  25. {
  26. Left,
  27. Center,
  28. Right,
  29. Justify
  30. }
  31. public enum TextLineAlignment
  32. {
  33. Top,
  34. Center,
  35. Bottom,
  36. Baseline
  37. }
  38. public class TextFormat
  39. {
  40. public TextAlignment Alignment { get; set; } = TextAlignment.Left;
  41. public TextLineAlignment LineAlignment { get; set; } = TextLineAlignment.Top;
  42. }
  43. public class TransformData
  44. {
  45. public DxfData Data { get; set; }
  46. private Stack<Matrix4x4> MatrixStack = new();
  47. public Matrix4x4 Transform { get; private set; } = Matrix4x4.Identity;
  48. public void PushTransform()
  49. {
  50. MatrixStack.Push(Transform);
  51. }
  52. public void TransformBy(Matrix4x4 matrix)
  53. {
  54. Transform = matrix * Transform;
  55. }
  56. protected virtual void UpdateTransform()
  57. {
  58. }
  59. protected Matrix ProjectMatrix(Matrix4x4 matrix)
  60. {
  61. var elMatrix = new Matrix3x2();
  62. elMatrix.M11 = (float)matrix.M11;
  63. elMatrix.M12 = (float)matrix.M12;
  64. elMatrix.M21 = (float)matrix.M21;
  65. elMatrix.M22 = (float)matrix.M22;
  66. elMatrix.M31 = (float)matrix.M41;
  67. elMatrix.M32 = (float)matrix.M42;
  68. var newMatrix = new Matrix();
  69. newMatrix.MatrixElements = elMatrix;
  70. return newMatrix;
  71. }
  72. public void PopTransform()
  73. {
  74. Transform = MatrixStack.Pop();
  75. UpdateTransform();
  76. }
  77. public static Matrix4x4 ArbitraryAxisMatrix(Vector3 zAxis)
  78. {
  79. if (zAxis.Equals(Vector3.UnitZ))
  80. {
  81. return Matrix4x4.Identity;
  82. }
  83. var unitY = Vector3.UnitY;
  84. var unitZ = Vector3.UnitZ;
  85. 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));
  86. v = Vector3.Normalize(v);
  87. var vector = Vector3.Cross(zAxis, v);
  88. vector = Vector3.Normalize(vector);
  89. 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);
  90. }
  91. public void ArbitraryAxis(netDxf.Vector3 zAxis)
  92. {
  93. Transform = ArbitraryAxisMatrix(new((float)zAxis.X, (float)zAxis.Y, (float)zAxis.Z)) * Transform;
  94. UpdateTransform();
  95. }
  96. public void ArbitraryAxis(Vector3 zAxis)
  97. {
  98. Transform = ArbitraryAxisMatrix(zAxis) * Transform;
  99. UpdateTransform();
  100. }
  101. public void Translate(float x, float y)
  102. {
  103. Transform = Transform.Translate(x, y, 0);
  104. UpdateTransform();
  105. }
  106. public void Translate(PointF point)
  107. {
  108. Transform = Transform.Translate(point.X, point.Y, 0);
  109. UpdateTransform();
  110. }
  111. public void Rotate(float angle)
  112. {
  113. Transform = Transform.Rotate(0, 0, 1, angle);
  114. UpdateTransform();
  115. }
  116. public void Scale(float scale)
  117. {
  118. Scale(scale, scale);
  119. }
  120. public void Scale(float scaleX, float scaleY)
  121. {
  122. Transform = Transform.Scale(scaleX, scaleY, 1);
  123. UpdateTransform();
  124. }
  125. public PointF TransformPoint(float x, float y)
  126. {
  127. var nVec = Vector4.Transform(new Vector4(x, y, 0, 1), Transform);
  128. return new(nVec.X, nVec.Y);
  129. }
  130. public PointF TransformPoint(PointF vec)
  131. {
  132. var nVec = Vector4.Transform(new Vector4(vec.X, vec.Y, 0, 1), Transform);
  133. return new(nVec.X, nVec.Y);
  134. }
  135. public PointF TransformPoint(netDxf.Vector2 vec)
  136. {
  137. var nVec = Vector4.Transform(new Vector4((float)vec.X, (float)vec.Y, 0, 1), Transform);
  138. return new(nVec.X, nVec.Y);
  139. }
  140. public PointF TransformPoint(netDxf.Vector3 vec)
  141. {
  142. var nVec = Vector4.Transform(new Vector4((float)vec.X, (float)vec.Y, (float)vec.Z, 1), Transform);
  143. return new(nVec.X, nVec.Y);
  144. }
  145. public PointF TransformVec(PointF vec)
  146. {
  147. var nVec = Vector4.Transform(new Vector4(vec.X, vec.Y, 0, 0), Transform);
  148. return new(nVec.X, nVec.Y);
  149. }
  150. public Vector2 TransformVec(Vector2 vec)
  151. {
  152. var nVec = Vector4.Transform(new Vector4(vec.X, vec.Y, 0, 0), Transform);
  153. return new(nVec.X, nVec.Y);
  154. }
  155. public float ScaleFactor()
  156. {
  157. return (TransformVec(new Vector2(1, 0))).Length();
  158. }
  159. public static PointF ConvertPoint(netDxf.Vector2 vec)
  160. {
  161. return new PointF((float)vec.X, (float)vec.Y);
  162. }
  163. public static PointF ConvertPoint(netDxf.Vector3 vec)
  164. {
  165. return new PointF((float)vec.X, (float)vec.Y);
  166. }
  167. }
  168. public class DrawData : TransformData
  169. {
  170. private IGraphics _graphics;
  171. public IGraphics Graphics
  172. {
  173. get => _graphics;
  174. set
  175. {
  176. _graphics = value;
  177. _graphics.DrawData = this;
  178. }
  179. }
  180. private Stack<Color> _blockColours = new();
  181. public Color BlockColour { get; set; } = Color.Black;
  182. public void PushBlockColour(AciColor colour, EntityObject? obj)
  183. {
  184. _blockColours.Push(BlockColour);
  185. BlockColour = ResolveColour(colour, obj);
  186. }
  187. public void PushBlockColour(Color colour)
  188. {
  189. _blockColours.Push(BlockColour);
  190. BlockColour = colour;
  191. }
  192. public void PopBlockColour()
  193. {
  194. BlockColour = _blockColours.Pop();
  195. }
  196. public Color ResolveColour(AciColor colour, EntityObject? obj)
  197. {
  198. if (colour.IsByBlock)
  199. {
  200. return _blockColours.Count > 0
  201. ? BlockColour
  202. : (obj?.Layer is null ? Color.Black : ResolveColour(obj.Layer.Color, null));
  203. }
  204. else if (colour.IsByLayer)
  205. {
  206. return obj?.Layer is null ? Color.Black : ResolveColour(obj.Layer.Color, null);
  207. }
  208. if(colour.Index == 7)
  209. {
  210. return Color.Black;
  211. }
  212. else
  213. {
  214. return colour.ToColor();
  215. }
  216. }
  217. protected override void UpdateTransform()
  218. {
  219. base.UpdateTransform();
  220. Graphics.SetTransform(ProjectMatrix(Transform));
  221. }
  222. }
  223. public interface IGraphics
  224. {
  225. DrawData DrawData { get; set; }
  226. void SetTransform(Matrix transform);
  227. void DrawLine(Color color, float thickness, params PointF[] points);
  228. void FillPolygon(Color color, params PointF[] points);
  229. /// <summary>
  230. /// Set the current font to be the default font at the given <paramref name="fontSize"/>.
  231. /// </summary>
  232. /// <param name="fontSize">Size of the new font.</param>
  233. void SetFont(float fontSize, FontStyle fontStyle = FontStyle.Regular);
  234. void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular);
  235. void DrawText(string text, Color color, PointF position, float rotation, TextFormat format);
  236. void Clear(Color color);
  237. void Finish();
  238. }
  239. public class GdiGraphics : IGraphics
  240. {
  241. public Graphics Graphics { get; set; }
  242. private Font Font { get; set; }
  243. public DrawData DrawData { get; set; }
  244. public GdiGraphics(Graphics graphics)
  245. {
  246. Graphics = graphics;
  247. }
  248. // public float ConvertThickness(float thickness)
  249. // {
  250. // return thickness == 0 ? 1f / ScaleFactor() : thickness;
  251. // }
  252. public void DrawLine(Color color, float thickness, params PointF[] points)
  253. {
  254. if(points.Length == 2)
  255. {
  256. Graphics.DrawLine(new Pen(color, thickness), points[0], points[1]);
  257. }
  258. else
  259. {
  260. Graphics.DrawLines(new Pen(color, thickness), points);
  261. }
  262. }
  263. private void TransformText(string text, Font font, PointF position, float rotation, TextFormat format)
  264. {
  265. DrawData.Translate(position);
  266. DrawData.Rotate(rotation);
  267. DrawData.Scale(1, -1);
  268. var size = Graphics.MeasureString(text, font, new PointF(), StringFormat.GenericTypographic);
  269. switch (format.LineAlignment)
  270. {
  271. case TextLineAlignment.Center:
  272. DrawData.Translate(new PointF(0, -size.Height / 2));
  273. break;
  274. case TextLineAlignment.Bottom:
  275. DrawData.Translate(new PointF(0, -size.Height));
  276. break;
  277. case TextLineAlignment.Baseline:
  278. var ascent = font.FontFamily.GetCellAscent(font.Style);
  279. var baseline = ascent * font.Height / font.FontFamily.GetEmHeight(font.Style);
  280. DrawData.Translate(new PointF(0, -baseline));
  281. break;
  282. case TextLineAlignment.Top:
  283. ascent = font.FontFamily.GetCellAscent(font.Style);
  284. baseline = ascent * font.Height / font.FontFamily.GetEmHeight(font.Style);
  285. var lineSpace = font.FontFamily.GetLineSpacing(font.Style);
  286. var ratio = font.GetHeight(Graphics) / lineSpace;
  287. DrawData.Translate(new PointF(0, -baseline + ascent * ratio));
  288. break;
  289. }
  290. switch (format.Alignment)
  291. {
  292. case TextAlignment.Left:
  293. break;
  294. case TextAlignment.Center:
  295. DrawData.Translate(new PointF(-(float)size.Width / 2, 0));
  296. break;
  297. case TextAlignment.Right:
  298. DrawData.Translate(new PointF(-(float)size.Width, 0));
  299. break;
  300. }
  301. }
  302. public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)
  303. {
  304. DrawData.PushTransform();
  305. TransformText(text, Font, position, rotation, format);
  306. Graphics.DrawString(text, Font, new SolidBrush(color), new PointF(0, 0), StringFormat.GenericTypographic);
  307. DrawData.PopTransform();
  308. }
  309. public void FillPolygon(Color color, params PointF[] points)
  310. {
  311. Graphics.FillPolygon(new SolidBrush(color), points);
  312. }
  313. public void SetFont(string fontName, float fontSize, FontStyle fontStyle)
  314. {
  315. var fontFamily = new FontFamily(fontName);
  316. var font = new Font(fontFamily, fontSize, fontStyle);
  317. Font = font;
  318. }
  319. public void SetFont(float fontSize, FontStyle fontStyle)
  320. {
  321. var fontFamily = SystemFonts.DefaultFont.FontFamily;
  322. var font = new Font(fontFamily, fontSize, fontStyle);
  323. Font = font;
  324. }
  325. public void SetTransform(Matrix transform)
  326. {
  327. Graphics.Transform = transform;
  328. }
  329. public void Clear(Color color)
  330. {
  331. Graphics.Clear(color);
  332. }
  333. public void Finish()
  334. {
  335. }
  336. }
  337. public class PdfGraphics : IGraphics
  338. {
  339. public DrawData DrawData { get; set; }
  340. private SPdfGraphics Graphics { get; set; }
  341. private Matrix _transform = new();
  342. private PdfFont _font = new PdfStandardFont(PdfFontFamily.Helvetica, 12, PdfFontStyle.Regular);
  343. public PdfGraphics(SPdfGraphics graphics)
  344. {
  345. Graphics = graphics;
  346. }
  347. public void Clear(Color color)
  348. {
  349. }
  350. public void SetTransform(Matrix transform)
  351. {
  352. _transform = transform;
  353. }
  354. public void DrawLine(Color color, float thickness, params PointF[] points)
  355. {
  356. _transform.TransformPoints(points);
  357. var pen = new PdfPen(color, thickness);
  358. for(int i = 0; i < points.Length - 1; ++i)
  359. {
  360. Graphics.DrawLine(pen, points[i], points[i + 1]);
  361. }
  362. }
  363. public void SetFont(float fontSize, FontStyle fontStyle = FontStyle.Regular)
  364. {
  365. _font = new PdfTrueTypeFont(new Font(SystemFonts.DefaultFont.FontFamily, fontSize));
  366. }
  367. public void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular)
  368. {
  369. _font = new PdfTrueTypeFont(new Font(fontName, fontSize));
  370. }
  371. public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)
  372. {
  373. var fmt = new PdfStringFormat();
  374. fmt.Alignment = format.Alignment switch
  375. {
  376. TextAlignment.Center => PdfTextAlignment.Center,
  377. TextAlignment.Right => PdfTextAlignment.Right,
  378. TextAlignment.Justify => PdfTextAlignment.Justify,
  379. _ => PdfTextAlignment.Left,
  380. };
  381. fmt.LineAlignment = format.LineAlignment switch
  382. {
  383. TextLineAlignment.Center => PdfVerticalAlignment.Middle,
  384. TextLineAlignment.Bottom => PdfVerticalAlignment.Bottom,
  385. _ => PdfVerticalAlignment.Top
  386. };
  387. if(format.LineAlignment == TextLineAlignment.Baseline)
  388. {
  389. fmt.EnableBaseline = true;
  390. }
  391. Graphics.Save();
  392. var point = _transform.Transform(position);
  393. Graphics.TranslateTransform(point.X, point.Y);
  394. Graphics.RotateTransform(-(_transform.GetRotation() + rotation));
  395. var scale = (_font.Height / _font.Size) * _transform.GetScale();
  396. Graphics.ScaleTransform(scale, scale);
  397. Graphics.DrawString(text, _font, new PdfSolidBrush(color), new PointF(), fmt);
  398. Graphics.Restore();
  399. }
  400. public void FillPolygon(Color color, params PointF[] points)
  401. {
  402. _transform.TransformPoints(points);
  403. var brush = new PdfSolidBrush(color);
  404. Graphics.DrawPolygon(brush, points);
  405. }
  406. public void Finish()
  407. {
  408. }
  409. }
  410. public class SvgGraphics : IGraphics
  411. {
  412. public DrawData DrawData { get; set; }
  413. public SvgDocument Document { get; set; }
  414. private SvgMatrix _transform = new(new Matrix().Elements.ToList());
  415. private SvgGroup _group;
  416. private Matrix _groupTransform = new();
  417. private static string[][] _groupProps = new[]
  418. {
  419. new[] { "stroke-width", "style" },
  420. new[] { "vector-effect" }
  421. };
  422. public SvgGraphics(SvgDocument document)
  423. {
  424. Document = document;
  425. _group = new SvgGroup();
  426. Document.Stroke = new SvgColourServer(Color.Black);
  427. }
  428. private void PushGroup()
  429. {
  430. if(_group.Children.Count > 0)
  431. {
  432. Document.Children.Add(_group);
  433. }
  434. }
  435. private void AddChild(SvgElement item)
  436. {
  437. var transMat = _transform.Matrix;
  438. if(!Equals(transMat, _groupTransform))
  439. {
  440. PushGroup();
  441. _group = new();
  442. _group.Transforms = new() { _transform };
  443. _groupTransform = transMat;
  444. }
  445. _group.Children.Add(item);
  446. }
  447. public void SetTransform(Matrix transform)
  448. {
  449. _transform = new(transform.Elements.ToList());
  450. }
  451. public void DrawLine(Color color, float thickness, params PointF[] points)
  452. {
  453. if(points.Length == 2)
  454. {
  455. var line = new SvgLine
  456. {
  457. StartX = points[0].X,
  458. StartY = points[0].Y,
  459. EndX = points[1].X,
  460. EndY = points[1].Y
  461. };
  462. if(color != Color.Black)
  463. {
  464. line.Stroke = new SvgColourServer(color);
  465. }
  466. if(thickness == 0)
  467. {
  468. line.StrokeWidth = 1;
  469. line.CustomAttributes.Add("vector-effect", "non-scaling-stroke");
  470. }
  471. else
  472. {
  473. line.StrokeWidth = thickness;
  474. }
  475. AddChild(line);
  476. }
  477. else
  478. {
  479. var line = new SvgPolyline();
  480. if(color != Color.Black)
  481. {
  482. line.Stroke = new SvgColourServer(color);
  483. }
  484. foreach(var point in points)
  485. {
  486. line.Points.Add(point.X);
  487. line.Points.Add(point.Y);
  488. }
  489. if(thickness == 0)
  490. {
  491. line.StrokeWidth = 1;
  492. line.CustomAttributes.Add("vector-effect", "non-scaling-stroke");
  493. }
  494. else
  495. {
  496. line.StrokeWidth = thickness;
  497. }
  498. AddChild(line);
  499. }
  500. }
  501. public void FillPolygon(Color color, params PointF[] points)
  502. {
  503. }
  504. public void SetFont(float fontSize, FontStyle fontStyle = FontStyle.Regular)
  505. {
  506. }
  507. public void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular)
  508. {
  509. }
  510. public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)
  511. {
  512. }
  513. public void Clear(Color color)
  514. {
  515. }
  516. public void Finish()
  517. {
  518. PushGroup();
  519. }
  520. }