Shapes.cs
  1. //
  2. // This code is part of Document Solutions for Imaging demos.
  3. // Copyright (c) MESCIUS inc. All rights reserved.
  4. //
  5. using System;
  6. using System.IO;
  7. using System.Drawing;
  8. using System.Numerics;
  9. using System.Linq;
  10. using GrapeCity.Documents.Text;
  11. using GrapeCity.Documents.Drawing;
  12. using GrapeCity.Documents.Imaging;
  13. using GCTEXT = GrapeCity.Documents.Text;
  14. using GCDRAW = GrapeCity.Documents.Drawing;
  15.  
  16. namespace DsImagingWeb.Demos
  17. {
  18. // Demonstrates how various shapes can be drawn in DsImaging.
  19. // Shows how simple shapes can be combined to produce more complex shapes.
  20. // Simple graphics transformations are used to draw some shapes.
  21. public class Shapes
  22. {
  23. // Helper method to draw a polygon and a caption beneath it.
  24. // Can also be used to just calculate the points without actual drawing.
  25. // startAngle is for the first point, clockwise from (1,0).
  26. private PointF[] DrawPolygon(GcGraphics g, PointF center, float r, int n, float startAngle, GCDRAW.Pen pen, string caption = null)
  27. {
  28. PointF[] pts = new PointF[n];
  29. for (int i = 0; i < n; ++i)
  30. pts[i] = new PointF(center.X + (float)(r * Math.Cos(startAngle + 2 * Math.PI * i / n)), center.Y + (float)(r * Math.Sin(startAngle + 2 * Math.PI * i / n)));
  31. if (pen != null)
  32. g.DrawPolygon(pts, pen);
  33. if (!string.IsNullOrEmpty(caption))
  34. DrawCaption(g, center, r, caption);
  35. return pts;
  36. }
  37.  
  38. // Helper method to draw a caption beneath a shape:
  39. private void DrawCaption(GcGraphics g, PointF center, float r, string caption)
  40. {
  41. g.DrawString(caption,
  42. new TextFormat()
  43. {
  44. Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "times.ttf")),
  45. FontSize = 12,
  46. },
  47. new RectangleF(center.X - r, center.Y + r, r * 2, 24),
  48. TextAlignment.Center, ParagraphAlignment.Center, false);
  49. }
  50.  
  51. // Main entry point.
  52. public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
  53. {
  54. var Inch = dpi;
  55. var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi);
  56. using (var g = bmp.CreateGraphics(Color.White))
  57. {
  58. // Document header:
  59. g.DrawString("Shapes",
  60. new TextFormat()
  61. {
  62. Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "timesbd.ttf")),
  63. FontBold = true,
  64. FontSize = 14,
  65. Underline = true,
  66. },
  67. new RectangleF(PointF.Empty, new SizeF(bmp.Width, 44)),
  68. TextAlignment.Center, ParagraphAlignment.Far);
  69. // Pen used to draw shapes:
  70. var pen = new GCDRAW.Pen(Color.Orange, 1);
  71. pen.LineJoin = PenLineJoin.Round;
  72. int fill = 100; // Surfaces fill alpha
  73.  
  74. // Set up the helper layout grid:
  75. var grid = new
  76. {
  77. Cols = 3,
  78. Rows = 5,
  79. MarginX = Inch / 4,
  80. MarginY = Inch / 3,
  81. Radius = Inch * 0.7f,
  82. StepX = (bmp.Width - Inch / 2) / 3,
  83. StepY = (bmp.Height - Inch / 4) / 5.5f,
  84. };
  85.  
  86. // Insertion point of the next figure's center:
  87. PointF startIp = new PointF(grid.MarginX + grid.StepX / 2, grid.MarginY + grid.StepY / 2 + 10);
  88. PointF ip = startIp;
  89. /* // Debug code to show the layout grid:
  90. var ipp = ip;
  91. for (int i = 0; i < grid.Cols; ++i)
  92. {
  93. ipp.Y = ip.Y;
  94. for (int j = 0; j < grid.Rows; ++j)
  95. {
  96. g.DrawRectangle(new RectangleF(ipp.X - grid.Radius, ipp.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2), Color.LightGreen, 0.5f);
  97. ipp.Y += grid.StepY;
  98. }
  99. ipp.X += grid.StepX;
  100. }
  101. */
  102.  
  103. // Circle:
  104. g.DrawEllipse(new RectangleF(ip.X - grid.Radius, ip.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2), pen);
  105. DrawCaption(g, ip, grid.Radius, "Circle");
  106. ip.X += grid.StepX;
  107.  
  108. // Ellipse:
  109. g.DrawEllipse(new RectangleF(ip.X - grid.Radius * 1.4f, ip.Y - grid.Radius / 2, grid.Radius * 2 * 1.4f, grid.Radius), pen);
  110. DrawCaption(g, ip, grid.Radius, "Ellipse");
  111. ip.X += grid.StepX;
  112.  
  113. // Cylinder:
  114. float radX = grid.Radius / 1.4f;
  115. float radY = grid.Radius / 6;
  116. float height = grid.Radius * 1.8f;
  117. g.DrawEllipse(new RectangleF(ip.X - radX, ip.Y - height / 2, radX * 2, radY * 2), pen);
  118. g.FillEllipse(new RectangleF(ip.X - radX, ip.Y + height / 2 - radY * 2, radX * 2, radY * 2), Color.FromArgb(fill, pen.Color));
  119. g.DrawEllipse(new RectangleF(ip.X - radX, ip.Y + height / 2 - radY * 2, radX * 2, radY * 2), pen);
  120. g.DrawLine(new PointF(ip.X - radX, ip.Y - height / 2 + radY), new PointF(ip.X - radX, ip.Y + height / 2 - radY), pen);
  121. g.DrawLine(new PointF(ip.X + radX, ip.Y - height / 2 + radY), new PointF(ip.X + radX, ip.Y + height / 2 - radY), pen);
  122. DrawCaption(g, ip, grid.Radius, "Cylinder");
  123. ip.X = startIp.X;
  124. ip.Y += grid.StepY;
  125. pen.Color = Color.Indigo;
  126.  
  127. // Square:
  128. DrawPolygon(g, ip, grid.Radius, 4, (float)-Math.PI / 4, pen, "Square");
  129. ip.X += grid.StepX;
  130.  
  131. // Rectangle:
  132. float rectQx = 1.4f;
  133. float rectQy = 0.6f;
  134. var rect = new RectangleF(ip.X - grid.Radius * rectQx, ip.Y - grid.Radius * rectQy, grid.Radius * 2 * rectQx, grid.Radius * 2 * rectQy);
  135. g.DrawRectangle(rect, pen);
  136. DrawCaption(g, ip, grid.Radius, "Rectangle");
  137. ip.X += grid.StepX;
  138.  
  139. // Cube:
  140. float cubex = 6;
  141. var cubePtsFar = DrawPolygon(g, new PointF(ip.X - cubex, ip.Y - cubex), grid.Radius, 4, (float)-Math.PI / 4, pen);
  142. var cubePtsNear = DrawPolygon(g, new PointF(ip.X + cubex, ip.Y + cubex), grid.Radius, 4, (float)-Math.PI / 4, pen);
  143. g.DrawLine(cubePtsFar[0], cubePtsNear[0], pen);
  144. g.DrawLine(cubePtsFar[1], cubePtsNear[1], pen);
  145. g.DrawLine(cubePtsFar[2], cubePtsNear[2], pen);
  146. g.DrawLine(cubePtsFar[3], cubePtsNear[3], pen);
  147. g.FillPolygon(new PointF[] { cubePtsFar[1], cubePtsFar[2], cubePtsNear[2], cubePtsNear[1], }, Color.FromArgb(fill, pen.Color));
  148. DrawCaption(g, ip, grid.Radius, "Cube");
  149. ip.X = startIp.X;
  150. ip.Y += grid.StepY;
  151. pen.Color = Color.DarkGreen;
  152.  
  153. // Pentagon:
  154. DrawPolygon(g, ip, grid.Radius, 5, (float)-Math.PI / 2, pen, "Pentagon");
  155. ip.X += grid.StepX;
  156.  
  157. // Hexagon:
  158. // For sample sake, we apply a transform to make the hexagon wider and shorter:
  159. g.Transform = Matrix3x2.CreateScale(1.4f, 0.8f) * Matrix3x2.CreateTranslation(ip.X, ip.Y);
  160. DrawPolygon(g, PointF.Empty, grid.Radius, 6, 0, pen, null);
  161. g.Transform = Matrix3x2.Identity;
  162. DrawCaption(g, ip, grid.Radius, "Hexagon");
  163. ip.X += grid.StepX;
  164.  
  165. // Octagon:
  166. DrawPolygon(g, ip, grid.Radius, 8, (float)-Math.PI / 8, pen, "Octagon");
  167. ip.X = startIp.X;
  168. ip.Y += grid.StepY;
  169. pen.Color = Color.DarkRed;
  170.  
  171. // Triangle:
  172. DrawPolygon(g, ip, grid.Radius, 3, (float)-Math.PI / 2, pen, "Triangle");
  173. ip.X += grid.StepX;
  174.  
  175. // Filled pentagram:
  176. var pts = DrawPolygon(g, ip, grid.Radius, 5, (float)-Math.PI / 2, pen, "Pentagram");
  177. pts = new PointF[] { pts[0], pts[2], pts[4], pts[1], pts[3], };
  178. g.FillPolygon(pts, Color.FromArgb(fill, pen.Color));
  179. g.DrawPolygon(pts, pen);
  180. ip.X += grid.StepX;
  181.  
  182. // Set up a simple kind of oblique projection to draw a pyramid:
  183. var angle = Math.PI / 6;
  184. float s = (float)Math.Sin(angle);
  185. float c = (float)Math.Cos(angle);
  186. Func<float, float, float, PointF> project = (x_, y_, z_) => new PointF(x_ - c * y_ * 0.5f, -(z_ - s * y_ * 0.5f));
  187. Func<Vector3, PointF> p3d = v_ => project(v_.X, v_.Y, v_.Z);
  188. float hedge = grid.Radius; // 1/2 edge
  189. // Debug - draw the 3 axis:
  190. // g.DrawLine(project(0, 0, 0), project(100, 0, 0), Color.Red);
  191. // g.DrawLine(project(0, 0, 0), project(0, 100, 0), Color.Green);
  192. // g.DrawLine(project(0, 0, 0), project(0, 0, 100), Color.Blue);
  193. // 3d points forming a square pyramid:
  194. var pts3d = new Vector3[]
  195. {
  196. new Vector3(-hedge, -hedge, 0),
  197. new Vector3(hedge, -hedge, 0),
  198. new Vector3(hedge, hedge, 0),
  199. new Vector3(-hedge, hedge, 0),
  200. new Vector3(0, 0, hedge * 2),
  201. };
  202. // project the points to draw the pyramid:
  203. pts = pts3d.Select(v_ => p3d(v_)).ToArray();
  204. g.Transform = Matrix3x2.CreateTranslation(ip.X, ip.Y + hedge * 0.7f);
  205. // Visible edges:
  206. g.DrawPolygon(new PointF[] { pts[4], pts[1], pts[2], pts[3], pts[4], pts[2] }, pen);
  207. // Invisible edges:
  208. pen.Width /= 2;
  209. pen.Color = Color.FromArgb(fill, pen.Color);
  210. g.DrawLine(pts[0], pts[4], pen);
  211. g.DrawLine(pts[0], pts[1], pen);
  212. g.DrawLine(pts[0], pts[3], pen);
  213. g.FillPolygon(pts.Take(4).ToArray(), pen.Color);
  214. //
  215. g.Transform = Matrix3x2.Identity;
  216. DrawCaption(g, ip, grid.Radius, "Pyramid");
  217. ip.X = startIp.X;
  218. ip.Y += grid.StepY;
  219. pen.Width *= 2;
  220. pen.Color = Color.Green;
  221.  
  222. // Cone:
  223. float baseh = grid.Radius * 0.3f;
  224. pts = DrawPolygon(g, ip, grid.Radius, 3, (float)-Math.PI / 2, null, "Cone");
  225. g.DrawLines(new PointF[] { pts[2], pts[0], pts[1] }, pen);
  226. rect = new RectangleF(pts[2].X, pts[2].Y - baseh / 2, pts[1].X - pts[2].X, baseh);
  227. g.FillEllipse(rect, Color.FromArgb(fill, pen.Color));
  228. g.DrawEllipse(rect, pen);
  229. ip.X += grid.StepX;
  230.  
  231. // Parallelogram (use graphics.Transform on a rectangle):
  232. rect = new RectangleF(-grid.Radius * rectQx, -grid.Radius * rectQy, grid.Radius * 2 * rectQx, grid.Radius * 2 * rectQy);
  233. g.Transform = Matrix3x2.CreateSkew((float)Math.PI / 6, 0) * Matrix3x2.CreateTranslation(ip.X, ip.Y);
  234. g.DrawRectangle(rect, pen);
  235. g.Transform = Matrix3x2.Identity;
  236. DrawCaption(g, ip, grid.Radius, "Parallelogram");
  237. ip.X += grid.StepX;
  238.  
  239. // Trapezoid (use DrawPolygon to just get the points of the square):
  240. float dx = 10;
  241. pts = DrawPolygon(g, ip, grid.Radius, 4, (float)-Math.PI / 4, null, "Trapezoid");
  242. pts[0].X -= dx;
  243. pts[1].X += dx;
  244. pts[2].X -= dx;
  245. pts[3].X += dx;
  246. g.DrawPolygon(pts, pen);
  247.  
  248. // Draw border around the whole image:
  249. // g.DrawRectangle(new RectangleF(0, 0, bmp.Width, bmp.Height), Color.DarkSlateBlue, 4);
  250. }
  251. // Done:
  252. return bmp;
  253. }
  254. }
  255. }
  256.