Objects.cs 14 KB

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