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