DxfUtils.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. using System.Drawing;
  2. using System.Drawing.Drawing2D;
  3. using netDxf;
  4. using netDxf.Entities;
  5. using Point = System.Drawing.Point;
  6. namespace InABox.Dxf
  7. {
  8. public static class DxfUtils
  9. {
  10. public static event ProcessError OnProcessError;
  11. // Draw a rotated string at a particular position.
  12. private static void DrawRotatedTextAt(Graphics gr, float angle,
  13. string txt, float x, float y, Font the_font, Brush the_brush)
  14. {
  15. // Save the graphics state.
  16. var state = gr.Save();
  17. gr.ResetTransform();
  18. // Rotate.
  19. gr.RotateTransform(angle);
  20. // Translate to desired position. Be sure to append
  21. // the rotation so it occurs after the rotation.
  22. gr.TranslateTransform(x, y, MatrixOrder.Append);
  23. // Draw the text at the origin.
  24. gr.DrawString(txt, the_font, the_brush, 0, 0);
  25. // Restore the graphics state.
  26. gr.Restore(state);
  27. }
  28. private static void CheckPoints(double x, double y, ref double minX, ref double minY, ref double maxX, ref double maxY)
  29. {
  30. minX = x < minX ? x : minX;
  31. minY = y < minY ? y : minY;
  32. maxX = x > maxX ? x : maxX;
  33. maxY = y > maxY ? y : maxY;
  34. }
  35. private static float Scale(int value, float offset, double scale, int border)
  36. {
  37. return (value - offset) * (float)scale + border;
  38. }
  39. private static float Scale(double value, float offset, double scale, int border)
  40. {
  41. return ((float)value - offset) * (float)scale + border;
  42. }
  43. private static PointF VectorToPointF(Vector3 vector, PointF offset, float scale, Point border)
  44. {
  45. return new PointF(Scale(vector.X, offset.X, scale, border.X), Scale(vector.Y, offset.Y, scale, border.Y));
  46. }
  47. private static PointF VectorToPointF(Vector2 vector, PointF offset, int scale, Point border)
  48. {
  49. return new PointF(Scale(vector.X, offset.X, scale, border.X), Scale(vector.Y, offset.Y, scale, border.Y));
  50. }
  51. public delegate void ProcessError(string message);
  52. public static Bitmap ProcessImage(Stream stream, string caption = null, bool dimensionmarks = true)
  53. {
  54. var minX = double.MaxValue;
  55. var minY = double.MaxValue;
  56. var maxX = double.MinValue;
  57. var maxY = double.MinValue;
  58. var document = DxfDocument.Load(stream);
  59. // Lets Explode all the various bits into their component atoms
  60. // (i.e. everything is gonna be a line)
  61. List<EntityObject> objects = new();
  62. ProcessEntities(document.Entities.All, objects, new Vector3());
  63. if (!objects.Any())
  64. throw new Exception(string.Format("No Data Found in {0}!", caption));
  65. foreach (var line in objects.OfType<Line>())
  66. {
  67. CheckPoints(line.StartPoint.X, line.StartPoint.Y, ref minX, ref minY, ref maxX, ref maxY);
  68. CheckPoints(line.EndPoint.X, line.EndPoint.Y, ref minX, ref minY, ref maxX, ref maxY);
  69. }
  70. var height = (int)Math.Abs(maxY - minY);
  71. var width = (int)Math.Abs(maxX - minX);
  72. // Calculate the scaling factor to fit the image within the bounds
  73. float ratioX = (float)2048 / height;
  74. float ratioY = (float)2048 / width;
  75. var scale = Math.Min(ratioX, ratioY);
  76. var margin = 100;
  77. var offset = new PointF((float)minX, (float)minY);
  78. var border = new Point(margin, margin);
  79. var _result = new Bitmap((int)(width * scale) + (margin * 2), (int)(height * scale) + (margin * 2));
  80. var _pen = new Pen(new SolidBrush(Color.Black), 3.0F);
  81. using (var _graphics = Graphics.FromImage(_result))
  82. {
  83. Brush _brush = new SolidBrush(Color.White);
  84. _graphics.FillRectangle(_brush, 0, 0, _result.Width, _result.Height);
  85. foreach (var line in objects.OfType<Line>())
  86. {
  87. try
  88. {
  89. var _start = VectorToPointF(line.StartPoint, offset, scale, border);
  90. var _end = VectorToPointF(line.EndPoint, offset, scale, border);
  91. _graphics.DrawLine(_pen, _start, _end);
  92. }
  93. catch (Exception e)
  94. {
  95. }
  96. }
  97. foreach (var text in objects.OfType<MText>().Where(x=>!string.IsNullOrWhiteSpace(x.Value)))
  98. {
  99. try
  100. {
  101. var font = new Font(text.Style.FontFamilyName, 12.0f, (FontStyle)text.Style.FontStyle);
  102. var dimensions = _graphics.MeasureString(text.Value, font);
  103. var anchor = VectorToPointF(text.Position, offset, scale, border);
  104. var textwidth = Scale(text.RectangleWidth, 0, scale, 0);
  105. float textRatioX = text.RectangleWidth == 0 ? int.MaxValue : textwidth / dimensions.Width;
  106. var textheight = Scale(text.Height, 0, scale, 0);
  107. float textRatioY = textheight / dimensions.Height;
  108. var textScale = Math.Min(textRatioX, textRatioY);
  109. font = new Font(text.Style.FontFamilyName, 12.0f * textScale, (FontStyle)text.Style.FontStyle);
  110. var topleft = (text.AttachmentPoint) switch
  111. {
  112. MTextAttachmentPoint.TopLeft => anchor,
  113. MTextAttachmentPoint.TopCenter => new PointF(anchor.X - (dimensions.Width / 2.0f), anchor.Y),
  114. MTextAttachmentPoint.TopRight => new PointF(anchor.X - dimensions.Width, anchor.Y),
  115. MTextAttachmentPoint.MiddleLeft => new PointF(anchor.X, anchor.Y - (textheight / 2.0f)),
  116. MTextAttachmentPoint.MiddleCenter => new PointF(anchor.X - (dimensions.Width / 2.0f), anchor.Y- (textheight / 2.0f)),
  117. MTextAttachmentPoint.MiddleRight => new PointF(anchor.X - dimensions.Width, anchor.Y- (textheight / 2.0f)),
  118. MTextAttachmentPoint.BottomLeft => anchor,
  119. MTextAttachmentPoint.BottomCenter => new PointF(anchor.X - (dimensions.Width / 2.0f), anchor.Y - textheight),
  120. MTextAttachmentPoint.BottomRight => new PointF(anchor.X - dimensions.Width, anchor.Y - textheight),
  121. };
  122. //var rectangle = new RectangleF(topleft, new SizeF(dimensions.Width, textheight));
  123. //_graphics.FillRectangle(new SolidBrush(Color.Yellow), rectangle);
  124. _graphics.DrawString(text.Value, font, new SolidBrush(Color.Navy),topleft);
  125. }
  126. catch (Exception e)
  127. {
  128. }
  129. }
  130. try
  131. {
  132. var font = new Font("Arial", 20.0F);
  133. var brush = new SolidBrush(Color.Blue);
  134. _pen = new Pen(brush);
  135. if (!string.IsNullOrWhiteSpace(caption))
  136. {
  137. var crect = _graphics.MeasureString(caption, font);
  138. _graphics.DrawString(caption, font, brush,
  139. new PointF(_result.Width / 2.0F - crect.Width / 2.0F, 10));
  140. }
  141. if (dimensionmarks)
  142. {
  143. var heightrect = _graphics.MeasureString(height.ToString(), font);
  144. _graphics.DrawLine(_pen, new PointF(_result.Width - (heightrect.Height + 10.0F), 100),
  145. new PointF(_result.Width - 30, 100));
  146. _graphics.DrawLine(_pen,
  147. new PointF(_result.Width - (heightrect.Height + 10.0F), _result.Height - 100),
  148. new PointF(_result.Width - 30, _result.Height - 100));
  149. _graphics.DrawLine(_pen, new PointF(_result.Width - (20.0F + heightrect.Height / 2.0F), 105),
  150. new PointF(_result.Width - (20.0F + heightrect.Height / 2.0F), _result.Height - 105));
  151. var aX = _result.Width - (20.0F + heightrect.Height / 2.0F);
  152. float aY = 105;
  153. _graphics.FillPolygon(brush, new[]
  154. {
  155. new(aX, aY),
  156. new PointF(aX - 10.0F, aY + 10.0F),
  157. new PointF(aX + 10.0F, aY + 10.0F)
  158. });
  159. aY = _result.Height - 105;
  160. _graphics.FillPolygon(brush, new[]
  161. {
  162. new(aX, aY),
  163. new PointF(aX - 10.0F, aY - 10.0F),
  164. new PointF(aX + 10.0F, aY - 10.0F)
  165. });
  166. _graphics.FillRectangle(_brush, _result.Width - (heightrect.Height + 15.0F),
  167. _result.Height / 2.0F - heightrect.Width / 2.0F, heightrect.Height,
  168. heightrect.Width);
  169. DrawRotatedTextAt(_graphics, 270.0F, height.ToString(),
  170. _result.Width - (heightrect.Height + 15.0F),
  171. _result.Height / 2.0F + heightrect.Width / 2.0F, font, brush);
  172. var widthrect = _graphics.MeasureString(width.ToString(), font);
  173. _graphics.DrawLine(_pen, new PointF(100, _result.Height - (widthrect.Height + 10.0F)),
  174. new PointF(100, _result.Height - 30));
  175. _graphics.DrawLine(_pen,
  176. new PointF(_result.Width - 100, _result.Height - (widthrect.Height + 10.0F)),
  177. new PointF(_result.Width - 100, _result.Height - 30));
  178. _graphics.DrawLine(_pen, new PointF(105, _result.Height - (20.0F + widthrect.Height / 2.0F)),
  179. new PointF(_result.Width - 105, _result.Height - (20.0F + widthrect.Height / 2.0F)));
  180. aX = 105;
  181. aY = _result.Height - (20.0F + widthrect.Height / 2.0F);
  182. _graphics.FillPolygon(brush, new[]
  183. {
  184. new(aX, aY),
  185. new PointF(aX + 10.0F, aY - 10.0F),
  186. new PointF(aX + 10.0F, aY + 10.0F)
  187. });
  188. aX = _result.Width - 105;
  189. _graphics.FillPolygon(brush, new[]
  190. {
  191. new(aX, aY),
  192. new PointF(aX - 10.0F, aY - 10.0F),
  193. new PointF(aX - 10.0F, aY + 10.0F)
  194. });
  195. _graphics.FillRectangle(_brush, _result.Width / 2.0F - widthrect.Width / 2.0F,
  196. _result.Height - (widthrect.Height + 15.0F), widthrect.Width,
  197. widthrect.Height);
  198. _graphics.DrawString(width.ToString(), font, brush,
  199. new PointF(_result.Width / 2.0F - widthrect.Width / 2.0F,
  200. _result.Height - (widthrect.Height + 15.0F)));
  201. }
  202. }
  203. catch (Exception e)
  204. {
  205. }
  206. }
  207. return _result;
  208. }
  209. private static void ProcessEntities(IEnumerable<EntityObject> entities, List<EntityObject> results, Vector3 offset)
  210. {
  211. foreach (var entity in entities)
  212. {
  213. try
  214. {
  215. if (entity is Line l)
  216. AddLine(l, results, offset);
  217. else if (entity is Insert i)
  218. InsertToLines(i, results, offset);
  219. else if (entity is Polyline2D p2d)
  220. PolylineToLines(p2d, results, offset);
  221. else if (entity is Arc a)
  222. ArcToLines(a, results, offset);
  223. else if (entity is Ellipse e)
  224. EllipseToLines(e, results, offset);
  225. else if (entity is MText t)
  226. AddText(t, results, offset);
  227. else if (entity is Dimension d)
  228. DimensionToLines(d, results, offset);
  229. else
  230. {
  231. }
  232. }
  233. catch (Exception e)
  234. {
  235. }
  236. }
  237. }
  238. private static void DimensionToLines(Dimension dimension, List<EntityObject> results, Vector3 offset)
  239. {
  240. //dimension.
  241. ProcessEntities(dimension.Block.Entities, results, offset);
  242. }
  243. private static void AddText(MText text, List<EntityObject> results, Vector3 offset)
  244. {
  245. text.Position += offset;
  246. results.Add(text);
  247. }
  248. private static void AddLine(Line line, List<EntityObject> results, Vector3 offset)
  249. {
  250. line.StartPoint += offset;
  251. line.EndPoint += offset;
  252. results.Add(line);
  253. }
  254. private static void EllipseToLines(Ellipse ellipse, List<EntityObject> results, Vector3 offset)
  255. {
  256. var precision = Math.Max(2, (int)((ellipse.MajorAxis + ellipse.MinorAxis) * 2.0F * Math.PI));
  257. var polyline = ellipse.ToPolyline2D(precision);
  258. var segments = polyline.Explode();
  259. ProcessEntities(segments, results, offset);
  260. }
  261. private static void InsertToLines(Insert insert, List<EntityObject> results, Vector3 offset)
  262. {
  263. ProcessEntities(insert.Block.Entities, results, insert.Position += offset);
  264. }
  265. private static void PolylineToLines(Polyline2D polyline, List<EntityObject> results, Vector3 offset)
  266. {
  267. var components = polyline.Explode();
  268. ProcessEntities(components, results, offset);
  269. }
  270. private static void ArcToLines(Arc arc, List<EntityObject> results, Vector3 offset)
  271. {
  272. var precision = Math.Max(2, (int)(arc.Radius * 2.0F * Math.PI));
  273. var polyline = arc.ToPolyline2D(precision);
  274. var segments = polyline.Explode();
  275. ProcessEntities(segments, results, offset);
  276. }
  277. public static Bitmap? DXFToBitmap(string filename)
  278. {
  279. using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
  280. try
  281. {
  282. return ProcessImage(stream, Path.GetFileNameWithoutExtension(filename));
  283. }
  284. catch (Exception e)
  285. {
  286. OnProcessError?.Invoke(e.Message);
  287. return null;
  288. }
  289. }
  290. }
  291. }