Objects.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. using InABox.Core;
  2. using netDxf;
  3. using netDxf.Entities;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Data;
  7. using System.Drawing;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. namespace InABox.Dxf;
  12. internal interface IDxfObject
  13. {
  14. void Draw(DrawData data);
  15. RectangleF? GetBounds(TransformData data);
  16. }
  17. internal class DxfLine : IDxfObject
  18. {
  19. public Line Line { get; set; }
  20. public void Draw(DrawData data)
  21. {
  22. if (!data.Data.ShouldDraw(Line)) return;
  23. data.PushTransform();
  24. //data.ArbitraryAxis(Line.Normal);
  25. data.Graphics.DrawLine(
  26. Color.Black, data.ConvertThickness((float)Line.Thickness),
  27. DrawData.ConvertPoint(Line.StartPoint), DrawData.ConvertPoint(Line.EndPoint));
  28. data.PopTransform();
  29. }
  30. public RectangleF? GetBounds(TransformData data)
  31. {
  32. if (!data.Data.ShouldDraw(Line)) return null;
  33. return Utils.RectangleFromPoints(
  34. data.TransformPoint(Line.StartPoint),
  35. data.TransformPoint(Line.EndPoint));
  36. }
  37. }
  38. internal class DxfInsert : IDxfObject
  39. {
  40. public Insert Insert { get; set; }
  41. public List<IDxfObject> Objects { get; set; }
  42. public DxfInsert(Insert insert)
  43. {
  44. Insert = insert;
  45. Objects = insert.Block.Entities.Select(DxfUtils.ConvertEl).NotNull().ToList();
  46. }
  47. public void Draw(DrawData data)
  48. {
  49. if (!data.Data.ShouldDraw(Insert)) return;
  50. // var transformation = Insert.GetTransformation();
  51. // var translation = Insert.Position - transformation * Insert.Block.Origin;
  52. data.PushTransform();
  53. data.Translate(new PointF((float)Insert.Position.X, (float)Insert.Position.Y));
  54. data.ArbitraryAxis(Insert.Normal);
  55. data.Rotate((float)Insert.Rotation);
  56. data.Scale((float)Insert.Scale.X, (float)Insert.Scale.Y);
  57. foreach(var entity in Objects)
  58. {
  59. entity.Draw(data);
  60. }
  61. data.PopTransform();
  62. // foreach(var entity in Insert.Explode())
  63. // {
  64. // // var ent = entity.Clone() as EntityObject;
  65. // // ent.TransformBy(transformation, translation);
  66. // DxfUtils.ConvertEl(entity)?.Draw(data);
  67. // }
  68. // foreach(var obj in Insert.Explode())
  69. // {
  70. // DxfUtils.ConvertEl(obj)?.Draw(data);
  71. // }
  72. }
  73. public RectangleF? GetBounds(TransformData data)
  74. {
  75. if (!data.Data.ShouldDraw(Insert)) return null;
  76. data.PushTransform();
  77. data.Translate(new PointF((float)Insert.Position.X, (float)Insert.Position.Y));
  78. data.ArbitraryAxis(Insert.Normal);
  79. data.Rotate((float)Insert.Rotation);
  80. data.Scale((float)Insert.Scale.X, (float)Insert.Scale.Y);
  81. var bounds = Utils.CombineBounds(Objects.Select(x => x.GetBounds(data)));
  82. data.PopTransform();
  83. return bounds;
  84. }
  85. }
  86. internal class DxfEllipse : IDxfObject
  87. {
  88. public Ellipse Ellipse { get; set; }
  89. public DxfEllipse(Ellipse ellipse)
  90. {
  91. Ellipse = ellipse;
  92. }
  93. public void Draw(DrawData data)
  94. {
  95. if (!data.Data.ShouldDraw(Ellipse)) return;
  96. foreach(var obj in Ellipse.ToPolyline2D(100).Explode())
  97. {
  98. DxfUtils.ConvertEl(obj)?.Draw(data);
  99. }
  100. // var center = DrawData.ConvertPoint(Ellipse.Center);
  101. // var size = new SizeF((float)Ellipse.MajorAxis, (float)Ellipse.MinorAxis);
  102. // var startAngle = (float)(Ellipse.StartAngle);
  103. // var endAngle = (float)(Ellipse.EndAngle);
  104. // data.Graphics.DrawArc(new Pen(Color.Black, data.ConvertThickness((float)Ellipse.Thickness)), center.X - size.Width / 2, center.Y - size.Height / 2, size.Width, size.Height, startAngle, Utils.Mod(endAngle - startAngle, 360));
  105. }
  106. public RectangleF? GetBounds(TransformData data)
  107. {
  108. if (!data.Data.ShouldDraw(Ellipse)) return null;
  109. var halfSize = new netDxf.Vector3(Ellipse.MajorAxis / 2, Ellipse.MinorAxis / 2, 0);
  110. return Utils.RectangleFromPoints(
  111. data.TransformPoint(Ellipse.Center - halfSize),
  112. data.TransformPoint(Ellipse.Center + halfSize));
  113. }
  114. }
  115. internal class DxfSolid : IDxfObject
  116. {
  117. public Solid Solid { get; set; }
  118. public DxfSolid(Solid solid)
  119. {
  120. Solid = solid;
  121. }
  122. public void Draw(DrawData data)
  123. {
  124. if (!data.Data.ShouldDraw(Solid)) return;
  125. var vertices = new Vector2[]
  126. {
  127. Solid.FirstVertex,
  128. Solid.SecondVertex,
  129. Solid.FourthVertex, // Apparently the third and fourth are the wrong way round, so I've mirrored that here.
  130. Solid.ThirdVertex
  131. };
  132. data.Graphics.FillPolygon(Color.Black, vertices.ToArray(x => DrawData.ConvertPoint(x)));
  133. }
  134. public RectangleF? GetBounds(TransformData data)
  135. {
  136. if (!data.Data.ShouldDraw(Solid)) return null;
  137. var vertices = new Vector2[]
  138. {
  139. Solid.FirstVertex,
  140. Solid.SecondVertex,
  141. Solid.FourthVertex, // Apparently the third and fourth are the wrong way round, so I've mirrored that here.
  142. Solid.ThirdVertex
  143. };
  144. return Utils.RectangleFromPoints(
  145. vertices.ToArray(data.TransformPoint));
  146. }
  147. }
  148. internal class DxfPolyline2D : IDxfObject
  149. {
  150. public Polyline2D Polyline { get; set; }
  151. public DxfPolyline2D(Polyline2D polyline)
  152. {
  153. Polyline = polyline;
  154. }
  155. public void Draw(DrawData data)
  156. {
  157. if (!data.Data.ShouldDraw(Polyline)) return;
  158. var entities = Polyline.Explode();
  159. foreach(var entity in entities)
  160. {
  161. DxfUtils.ConvertEl(entity)?.Draw(data);
  162. }
  163. // if(Polyline.SmoothType == PolylineSmoothType.NoSmooth)
  164. // {
  165. // var vertices = Polyline.Vertexes.ToArray(x => new PointF((float)x.Position.X, (float)x.Position.Y));
  166. // if (Polyline.IsClosed)
  167. // {
  168. // data.Graphics.DrawPolygon(
  169. // new Pen(Color.Black, data.ConvertThickness((float)Polyline.Thickness)),
  170. // vertices);
  171. // }
  172. // else
  173. // {
  174. // data.Graphics.DrawLines(
  175. // new Pen(Color.Black, data.ConvertThickness((float)Polyline.Thickness)),
  176. // vertices);
  177. // }
  178. // }
  179. // else
  180. // {
  181. // }
  182. }
  183. public RectangleF? GetBounds(TransformData data)
  184. {
  185. if (!data.Data.ShouldDraw(Polyline)) return null;
  186. var entities = Polyline.Explode();
  187. return Utils.CombineBounds(entities.Select(x => DxfUtils.ConvertEl(x)?.GetBounds(data)));
  188. }
  189. }
  190. internal class DxfMText : IDxfObject
  191. {
  192. public MText MText { get; set; }
  193. public DxfMText(MText text)
  194. {
  195. MText = text;
  196. }
  197. private Font GetFont()
  198. {
  199. FontFamily fontFamily;
  200. if (MText.Style.FontFamilyName.IsNullOrWhiteSpace())
  201. {
  202. fontFamily = SystemFonts.DefaultFont.FontFamily;
  203. }
  204. else
  205. {
  206. fontFamily = new FontFamily(MText.Style.FontFamilyName);
  207. }
  208. return new Font(fontFamily, (float)MText.Height, MText.Style.FontStyle switch
  209. {
  210. netDxf.Tables.FontStyle.Bold => FontStyle.Bold,
  211. netDxf.Tables.FontStyle.Italic => FontStyle.Italic,
  212. netDxf.Tables.FontStyle.Regular or _ => FontStyle.Regular,
  213. });
  214. }
  215. private string GetText()
  216. {
  217. return MText.PlainText().Replace("^M", "");
  218. }
  219. private static Bitmap _placeholderBitmap = new Bitmap(1, 1);
  220. private void Transform(TransformData data, Font font, string text, Graphics g)
  221. {
  222. data.Translate(new PointF((float)MText.Position.X, (float)MText.Position.Y));
  223. data.Rotate((float)MText.Rotation);
  224. data.Scale(1, -1);
  225. var size = g.MeasureString(text, font, new PointF(), StringFormat.GenericTypographic);
  226. switch (MText.AttachmentPoint)
  227. {
  228. case MTextAttachmentPoint.MiddleLeft:
  229. case MTextAttachmentPoint.MiddleCenter:
  230. case MTextAttachmentPoint.MiddleRight:
  231. data.Translate(new PointF(0, -size.Height / 2));
  232. break;
  233. case MTextAttachmentPoint.BottomLeft:
  234. case MTextAttachmentPoint.BottomCenter:
  235. case MTextAttachmentPoint.BottomRight:
  236. data.Translate(new PointF(0, -size.Height));
  237. break;
  238. default:
  239. var ascent = font.FontFamily.GetCellAscent(font.Style);
  240. var lineSpace = font.FontFamily.GetLineSpacing(font.Style);
  241. var baseline = ascent * font.Height / font.FontFamily.GetEmHeight(font.Style);
  242. var ratio = font.GetHeight(g) / lineSpace;
  243. data.Translate(new PointF(0, -baseline + ascent * ratio));
  244. break;
  245. }
  246. switch (MText.AttachmentPoint)
  247. {
  248. case MTextAttachmentPoint.TopLeft:
  249. case MTextAttachmentPoint.MiddleLeft:
  250. case MTextAttachmentPoint.BottomLeft:
  251. break;
  252. case MTextAttachmentPoint.TopCenter:
  253. case MTextAttachmentPoint.MiddleCenter:
  254. case MTextAttachmentPoint.BottomCenter:
  255. data.Translate(new PointF(-(float)size.Width / 2, 0));
  256. break;
  257. case MTextAttachmentPoint.TopRight:
  258. case MTextAttachmentPoint.MiddleRight:
  259. case MTextAttachmentPoint.BottomRight:
  260. data.Translate(new PointF(-(float)size.Width, 0));
  261. break;
  262. }
  263. }
  264. public void Draw(DrawData data)
  265. {
  266. if (!data.Data.ShouldDraw(MText)) return;
  267. var text = GetText();
  268. if (MText.Style.FontFamilyName.IsNullOrWhiteSpace())
  269. {
  270. data.Graphics.SetFont((float)MText.Height, MText.Style.FontStyle switch
  271. {
  272. netDxf.Tables.FontStyle.Bold => FontStyle.Bold,
  273. netDxf.Tables.FontStyle.Italic => FontStyle.Italic,
  274. netDxf.Tables.FontStyle.Regular or _ => FontStyle.Regular,
  275. });
  276. }
  277. else
  278. {
  279. data.Graphics.SetFont(MText.Style.FontFamilyName, (float)MText.Height, MText.Style.FontStyle switch
  280. {
  281. netDxf.Tables.FontStyle.Bold => FontStyle.Bold,
  282. netDxf.Tables.FontStyle.Italic => FontStyle.Italic,
  283. netDxf.Tables.FontStyle.Regular or _ => FontStyle.Regular,
  284. });
  285. }
  286. data.PushTransform();
  287. using var g = Graphics.FromImage(_placeholderBitmap);
  288. Transform(data, GetFont(), text, g);
  289. data.Graphics.DrawText(text, Color.Black, new PointF(0, 0));
  290. data.PopTransform();
  291. }
  292. public RectangleF? GetBounds(TransformData data)
  293. {
  294. if (!data.Data.ShouldDraw(MText)) return null;
  295. var font = GetFont();
  296. var text = GetText();
  297. data.PushTransform();
  298. using var g = Graphics.FromImage(_placeholderBitmap);
  299. Transform(data, font, text, g);
  300. var size = g.MeasureString(text, font, new PointF(), StringFormat.GenericTypographic);
  301. var bounds = Utils.RectangleFromPoints(
  302. data.TransformPoint(0, 0),
  303. data.TransformPoint(size.Width, size.Height));
  304. data.PopTransform();
  305. return bounds;
  306. }
  307. }
  308. internal class DxfDimension : IDxfObject
  309. {
  310. public Dimension Dimension { get; set; }
  311. public List<IDxfObject> Objects { get; set; }
  312. public DxfDimension(Dimension dimension)
  313. {
  314. Dimension = dimension;
  315. if(Dimension.Block is null)
  316. {
  317. Objects = new();
  318. }
  319. else
  320. {
  321. Objects = Dimension.Block.Entities.Select(DxfUtils.ConvertEl).NotNull().ToList();
  322. }
  323. }
  324. public void Draw(DrawData data)
  325. {
  326. if (!data.Data.ShouldDraw(Dimension)) return;
  327. foreach(var entity in Objects)
  328. {
  329. entity.Draw(data);
  330. }
  331. }
  332. public RectangleF? GetBounds(TransformData data)
  333. {
  334. if (!data.Data.ShouldDraw(Dimension)) return null;
  335. return Utils.CombineBounds(Objects.Select(x => x.GetBounds(data)));
  336. }
  337. }