//// This code is part of Document Solutions for Imaging demos.// Copyright (c) MESCIUS inc. All rights reserved.//using System;using System.Drawing;using System.Collections.Generic;using System.Linq;using System.Numerics;using GrapeCity.Documents.Drawing;using GrapeCity.Documents.Text;using GrapeCity.Documents.Imaging;using GrapeCity.Documents.Svg;
namespace DsImagingWeb.Demos{ // This sample draws some geometric shapes using GcSvgDocument and GcGraphics.DrawSvg(). // The code and the results are similar to the Shapes sample. public class SvgShapes { // Helper method to draw a polygon and a caption beneath it. // Can also be used to just calculate the points without actual drawing. // startAngle is for the first point, clockwise from (1,0). // Points are relative to 'center'. private SvgPoint[] DrawPolygon(GcGraphics g, PointF center, float r, int n, float startAngle, SvgPaint stroke, string caption = null) { const float Q = 1.4f; SvgPolygonElement plgn = new SvgPolygonElement(); plgn.Points = new List<SvgPoint>(n); for (int i = 0; i < n; ++i) plgn.Points.Add(new SvgPoint( new SvgLength((float)(r * Math.Cos(startAngle + 2 * Math.PI * i / n)) * Q, SvgLengthUnits.Percentage), new SvgLength((float)(r * Math.Sin(startAngle + 2 * Math.PI * i / n)) * Q, SvgLengthUnits.Percentage)));
if (stroke != null) { plgn.Stroke = stroke; plgn.Fill = new SvgPaint(SvgColor.Transparent); var svgDoc = new GcSvgDocument(); var svg = svgDoc.RootSvg; svg.Children.Add(plgn); g.DrawSvg(svgDoc, new RectangleF(center.X, center.Y, r * 2, r * 2)); }
if (!string.IsNullOrEmpty(caption)) DrawCaption(g, center, r, caption);
return plgn.Points.ToArray(); } // Helper method to draw a caption beneath a shape: private void DrawCaption(GcGraphics g, PointF center, float r, string caption) { g.DrawString(caption, new TextFormat() { FontSize = 10, }, new RectangleF(center.X - r, center.Y + r + 24, r * 2, 24), TextAlignment.Center, ParagraphAlignment.Center, false); } // Main entry point. public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null) { var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi); using var g = bmp.CreateGraphics(Color.White); // Document header: g.DrawString("Shapes (SVG)", new TextFormat() { FontSize = 14, Underline = true, }, new RectangleF(PointF.Empty, new SizeF(pixelSize.Width, 44)), TextAlignment.Center, ParagraphAlignment.Far); // Pen used to draw shapes:
// Set up the helper layout grid: var grid = new { Cols = 3, Rows = 5, MarginX = dpi, MarginY = dpi / 2, Radius = dpi / 2, StepX = (pixelSize.Width - dpi * 2) / 3, StepY = (pixelSize.Height - dpi) / 5, };
// Insertion point of the next figure's center: PointF startIp = new PointF(grid.MarginX + grid.StepX / 2, grid.MarginY + grid.StepY / 2 + 10); PointF ip = startIp; // Debug code to show the layout grid: /* var ipp = ip; for (int i = 0; i < grid.Cols; ++i) { ipp.Y = ip.Y; for (int j = 0; j < grid.Rows; ++j) { g.DrawRectangle(new RectangleF(ipp.X - grid.Radius, ipp.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2), Color.LightGreen, 0.5f); ipp.Y += grid.StepY; } ipp.X += grid.StepX; } */
// Reusable SVG primitives: var len0 = new SvgLength(0, SvgLengthUnits.Percentage); var len10 = new SvgLength(10, SvgLengthUnits.Percentage); var len20 = new SvgLength(20, SvgLengthUnits.Percentage); var len30 = new SvgLength(30, SvgLengthUnits.Percentage); var len40 = new SvgLength(40, SvgLengthUnits.Percentage); var len50 = new SvgLength(50, SvgLengthUnits.Percentage); var len60 = new SvgLength(60, SvgLengthUnits.Percentage); var len70 = new SvgLength(70, SvgLengthUnits.Percentage); var len80 = new SvgLength(80, SvgLengthUnits.Percentage); var len90 = new SvgLength(90, SvgLengthUnits.Percentage); var len100 = new SvgLength(100, SvgLengthUnits.Percentage); var paintTrans = new SvgPaint(SvgColor.Transparent); var pntStroke0 = new SvgPaint(new SvgColor(Color.Green)); var pntStroke0inv = new SvgPaint(new SvgColor(Color.FromArgb(100, Color.Green))); var pntFill0 = new SvgPaint(new SvgColor(Color.FromArgb(100, Color.Orange))); var pt0_0 = new SvgPoint(len0, len0); var pt100_100 = new SvgPoint(len100, len100);
// Circle: var svgDoc = new GcSvgDocument(); var svg = svgDoc.RootSvg; svg.Children.Add(new SvgEllipseElement() { CenterX = len50, CenterY = len50, RadiusX = len50, RadiusY = len50, Fill = paintTrans, Stroke = pntStroke0, }); g.DrawSvg(svgDoc, new RectangleF(ip.X - grid.Radius, ip.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2)); DrawCaption(g, ip, grid.Radius, "Circle"); ip.X += grid.StepX;
// Ellipse: svg.Children.Clear(); svg.Children.Add(new SvgEllipseElement() { CenterX = len50, CenterY = len50, RadiusX = len50, RadiusY = len50, Fill = paintTrans, Stroke = pntStroke0, }); g.DrawSvg(svgDoc, new RectangleF(ip.X - grid.Radius * 1.4f, ip.Y - grid.Radius / 2, grid.Radius * 2 * 1.4f, grid.Radius)); DrawCaption(g, ip, grid.Radius, "Ellipse"); ip.X += grid.StepX;
// Cylinder: svg.Children.Clear(); float radX = grid.Radius / 1.4f; float radY = grid.Radius / 6; float height = grid.Radius * 1.8f; svg.Children.Add(new SvgEllipseElement() { CenterX = len50, CenterY = len10, RadiusX = len50, RadiusY = len10, Fill = paintTrans, Stroke = pntStroke0, }); svg.Children.Add(new SvgEllipseElement() { CenterX = len50, CenterY = len90, RadiusX = len50, RadiusY = len10, Fill = pntFill0, Stroke = pntStroke0, }); svg.Children.Add(new SvgLineElement() { X1 = len0, Y1 = len10, X2 = len0, Y2 = len90, Stroke = pntStroke0, }); svg.Children.Add(new SvgLineElement() { X1 = len100, Y1 = len10, X2 = len100, Y2 = len90, Stroke = pntStroke0, }); g.DrawSvg(svgDoc, new RectangleF(ip.X - grid.Radius, ip.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2)); DrawCaption(g, ip, grid.Radius, "Cylinder"); ip.X = startIp.X; ip.Y += grid.StepY;
// Square: DrawPolygon(g, ip, grid.Radius, 4, (float)-Math.PI / 4, pntStroke0, "Square"); ip.X += grid.StepX;
// Rectangle: svg.Children.Clear(); svg.Children.Add(new SvgRectElement() { X = new SvgLength(-20, SvgLengthUnits.Percentage), Y = len20, Width = new SvgLength(140, SvgLengthUnits.Percentage), Height = len60, Stroke = pntStroke0, Fill = paintTrans, }); g.DrawSvg(svgDoc, new RectangleF(ip.X - grid.Radius, ip.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2)); DrawCaption(g, ip, grid.Radius, "Rectangle"); ip.X += grid.StepX;
// Cube: svg.Children.Clear(); svg.Children.Add(new SvgRectElement() { X = len10, Y = len10, Width = len60, Height = len60, Stroke = pntStroke0, Fill = paintTrans, }); svg.Children.Add(new SvgRectElement() { X = len30, Y = len30, Width = len60, Height = len60, Stroke = pntStroke0, Fill = paintTrans, }); svg.Children.Add(new SvgLineElement() { X1 = len10, Y1 = len10, X2 = len30, Y2 = len30, Stroke = pntStroke0, }); svg.Children.Add(new SvgLineElement() { X1 = len10, Y1 = len70, X2 = len30, Y2 = len90, Stroke = pntStroke0, }); svg.Children.Add(new SvgLineElement() { X1 = len70, Y1 = len10, X2 = len90, Y2 = len30, Stroke = pntStroke0, }); svg.Children.Add(new SvgLineElement() { X1 = len70, Y1 = len70, X2 = len90, Y2 = len90, Stroke = pntStroke0, }); g.DrawSvg(svgDoc, new RectangleF(ip.X - grid.Radius, ip.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2)); DrawCaption(g, ip, grid.Radius, "Cube"); ip.X = startIp.X; ip.Y += grid.StepY;
// Pentagon: DrawPolygon(g, ip, grid.Radius, 5, (float)-Math.PI / 2, pntStroke0, "Pentagon"); ip.X += grid.StepX;
// Hexagon: // For sample sake, we apply a transform to make the hexagon wider and shorter: g.Transform = Matrix3x2.CreateScale(1.4f, 0.8f) * Matrix3x2.CreateTranslation(ip.X, ip.Y); DrawPolygon(g, PointF.Empty, grid.Radius, 6, 0, pntStroke0, null); g.Transform = Matrix3x2.Identity; DrawCaption(g, ip, grid.Radius, "Hexagon"); ip.X += grid.StepX;
// Octagon: DrawPolygon(g, ip, grid.Radius, 8, (float)-Math.PI / 8, pntStroke0, "Octagon"); ip.X = startIp.X; ip.Y += grid.StepY;
// Triangle: DrawPolygon(g, ip, grid.Radius, 3, (float)-Math.PI / 2, pntStroke0, "Triangle"); ip.X += grid.StepX;
// Filled pentagram: var svgPts = DrawPolygon(g, ip, grid.Radius, 5, (float)-Math.PI / 2, pntStroke0, "Pentagram"); svg.Children.Clear(); svg.Children.Add(new SvgPolygonElement() { Points = new List<SvgPoint>() { svgPts[0], svgPts[2], svgPts[4], svgPts[1], svgPts[3], }, Stroke = pntStroke0, Fill = pntFill0, FillRule = SvgFillRule.EvenOdd, }); g.DrawSvg(svgDoc, new RectangleF(ip.X, ip.Y, grid.Radius * 2, grid.Radius * 2)); ip.X += grid.StepX;
// Set up a simple kind of oblique projection to draw a pyramid: var angle = Math.PI / 6; float s = (float)Math.Sin(angle); float c = (float)Math.Cos(angle); Func<float, float, float, PointF> project = (x_, y_, z_) => new PointF(x_ - c * y_ * 0.5f, -(z_ - s * y_ * 0.5f)); Func<Vector3, PointF> p3d = v_ => project(v_.X, v_.Y, v_.Z); float hedge = grid.Radius; // 1/2 edge // Debug - draw the 3 axis: /* g.DrawLine(project(0, 0, 0), project(100, 0, 0), Color.Red); g.DrawLine(project(0, 0, 0), project(0, 100, 0), Color.Green); g.DrawLine(project(0, 0, 0), project(0, 0, 100), Color.Blue); */ // 3d points forming a square pyramid: var pts3d = new Vector3[] { new Vector3(-hedge, -hedge, 0), new Vector3(hedge, -hedge, 0), new Vector3(hedge, hedge, 0), new Vector3(-hedge, hedge, 0), new Vector3(0, 0, hedge * 2), }; // Project the points to draw the pyramid: var pts = pts3d.Select(v_ => p3d(v_)); svgPts = pts.Select(p_ => new SvgPoint(new SvgLength(p_.X, SvgLengthUnits.Percentage), new SvgLength(p_.Y, SvgLengthUnits.Percentage))).ToArray(); g.Transform = Matrix3x2.CreateTranslation(0, hedge * 0.7f); svg.Children.Clear(); // Visible edges: svg.Children.Add(new SvgPolygonElement() { Points = new List<SvgPoint>() { svgPts[4], svgPts[1], svgPts[2], svgPts[3], svgPts[4], svgPts[2], }, Stroke = pntStroke0, Fill = paintTrans, }); // Bottom: svg.Children.Add(new SvgPolygonElement() { Points = svgPts.Take(4).ToList(), Fill = pntFill0, }); // Invisible edges: svg.Children.Add(new SvgLineElement() { X1 = svgPts[0].X, Y1 = svgPts[0].Y, X2 = svgPts[4].X, Y2 = svgPts[4].Y, Stroke = pntStroke0inv, }); svg.Children.Add(new SvgLineElement() { X1 = svgPts[0].X, Y1 = svgPts[0].Y, X2 = svgPts[1].X, Y2 = svgPts[1].Y, Stroke = pntStroke0inv, }); svg.Children.Add(new SvgLineElement() { X1 = svgPts[0].X, Y1 = svgPts[0].Y, X2 = svgPts[3].X, Y2 = svgPts[3].Y, Stroke = pntStroke0inv, }); g.DrawSvg(svgDoc, new RectangleF(ip.X, ip.Y, grid.Radius * 2, grid.Radius * 2)); g.Transform = Matrix3x2.Identity; DrawCaption(g, ip, grid.Radius, "Pyramid"); ip.X = startIp.X; ip.Y += grid.StepY;
// Cone: float baseh = grid.Radius * 0.3f; svgPts = DrawPolygon(g, ip, grid.Radius, 3, (float)-Math.PI / 2, null, "Cone"); svg.Children.Clear(); svg.Children.Add(new SvgPolylineElement() { Points = new List<SvgPoint>() { svgPts[2], svgPts[0], svgPts[1], }, Stroke = pntStroke0, Fill = paintTrans, }); svg.Children.Add(new SvgEllipseElement() { CenterX = new SvgLength(svgPts[0].X.Value, SvgLengthUnits.Percentage), CenterY = svgPts[2].Y, RadiusX = new SvgLength((svgPts[1].X.Value - svgPts[2].X.Value) / 2, SvgLengthUnits.Percentage), RadiusY = len10, Fill = pntFill0, Stroke = pntStroke0, }); g.DrawSvg(svgDoc, new RectangleF(ip.X, ip.Y, grid.Radius * 2, grid.Radius * 2)); ip.X += grid.StepX;
// Parallelogram (use graphics.Transform on a rectangle): svg.Children.Clear(); var svgParal = new SvgRectElement() { X = new SvgLength(-20, SvgLengthUnits.Percentage), Y = len20, Width = new SvgLength(140, SvgLengthUnits.Percentage), Height = len60, Stroke = pntStroke0, Fill = paintTrans, }; svg.Children.Add(svgParal); g.Transform = Matrix3x2.CreateSkew((float)Math.PI / 6, 0) * Matrix3x2.CreateTranslation(ip.X, ip.Y); g.DrawSvg(svgDoc, new RectangleF(-grid.Radius, -grid.Radius, grid.Radius * 2, grid.Radius * 2)); g.Transform = Matrix3x2.Identity; DrawCaption(g, ip, grid.Radius, "Parallelogram"); ip.X += grid.StepX;
// Trapezoid (use DrawPolygon to just get the points of the square): svg.Children.Clear(); float dx = 10; svgPts = DrawPolygon(g, ip, grid.Radius, 4, (float)-Math.PI / 4, null, "Trapezoid"); svg.Children.Add(new SvgPolygonElement() { Points = new List<SvgPoint>() { new SvgPoint(new SvgLength(svgPts[0].X.Value - dx, SvgLengthUnits.Percentage), svgPts[0].Y), new SvgPoint(new SvgLength(svgPts[1].X.Value + dx, SvgLengthUnits.Percentage), svgPts[1].Y), new SvgPoint(new SvgLength(svgPts[2].X.Value - dx, SvgLengthUnits.Percentage), svgPts[2].Y), new SvgPoint(new SvgLength(svgPts[3].X.Value + dx, SvgLengthUnits.Percentage), svgPts[3].Y), }, Stroke = pntStroke0, Fill = paintTrans, }); g.DrawSvg(svgDoc, new RectangleF(ip.X, ip.Y, grid.Radius * 2, grid.Radius * 2));
// Done: return bmp; } }}