Shapes.vb
'' '' This code is part of Document Solutions for PDF demos. '' Copyright (c) MESCIUS inc. All rights reserved. '' Imports System.IO Imports System.Drawing Imports System.Numerics Imports System.Linq Imports GrapeCity.Documents.Pdf Imports GrapeCity.Documents.Text Imports GrapeCity.Documents.Drawing Imports GCTEXT = GrapeCity.Documents.Text Imports GCDRAW = GrapeCity.Documents.Drawing '' Demonstrates how various shapes can be drawn in DsPdf. '' Shows how simple shapes can be combined to produce more complex shapes. '' Simple graphics transformations are used to draw some shapes. Public Class Shapes '' 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). Private Function DrawPolygon( ByVal g As GcGraphics, ByVal center As PointF, ByVal r As Single, ByVal n As Integer, ByVal startAngle As Single, ByVal pn As GCDRAW.Pen, Optional ByVal caption As String = Nothing) As PointF() Dim pts(n - 1) As PointF For i = 0 To n - 1 pts(i) = New PointF(center.X + (r * Math.Cos(startAngle + 2 * Math.PI * i / n)), center.Y + (r * Math.Sin(startAngle + 2 * Math.PI * i / n))) Next If pn IsNot Nothing Then g.DrawPolygon(pts, pn) End If If Not String.IsNullOrEmpty(caption) Then DrawCaption(g, center, r, caption) End If Return pts End Function '' Helper method to draw a caption beneath a shape: Private Sub DrawCaption(ByVal g As GcGraphics, ByVal center As PointF, ByVal r As Single, ByVal caption As String) g.DrawString( caption, New TextFormat() With {.Font = StandardFonts.Times, .FontSize = 10}, New RectangleF(center.X - r, center.Y + r, r * 2, 24), TextAlignment.Center, ParagraphAlignment.Center, False) End Sub '' Main entry point. Function CreatePDF(ByVal stream As Stream) As Integer Dim doc = New GcPdfDocument() Dim page = doc.Pages.Add() Dim g = page.Graphics '' Document header: g.DrawString("Shapes", New TextFormat() With {.Font = StandardFonts.TimesBold, .FontSize = 14, .Underline = True}, New RectangleF(PointF.Empty, New SizeF(page.Size.Width, 44)), TextAlignment.Center, ParagraphAlignment.Far) '' Pen used to draw shapes: Dim pen = New GCDRAW.Pen(Color.Orange, 1) pen.LineJoin = PenLineJoin.Round Dim fill = 100 '' Surfaces fill alpha '' Set up the helper layout grid: Dim grid = New With { .Cols = 3, .Rows = 5, .MarginX = 72, .MarginY = 36, .Radius = 36, .StepX = (page.Size.Width - 144) / 3, .StepY = (page.Size.Height - 72) / 5 } '' Insertion point of the next figure's center: Dim startIp = New PointF(grid.MarginX + grid.StepX / 2, grid.MarginY + grid.StepY / 2 + 10) Dim ip = startIp #If False Then '' Debug code to show the layout grid: Dim ipp = ip For i = 1 To grid.Cols ipp.Y = ip.Y For j = 1 To grid.Rows 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 Next ipp.X += grid.StepX Next #End If '' Circle: g.DrawEllipse(New RectangleF(ip.X - grid.Radius, ip.Y - grid.Radius, grid.Radius * 2, grid.Radius * 2), pen) DrawCaption(g, ip, grid.Radius, "Circle") ip.X += grid.StepX '' Ellipse: g.DrawEllipse(New RectangleF(ip.X - grid.Radius * 1.4F, ip.Y - grid.Radius / 2, grid.Radius * 2 * 1.4F, grid.Radius), pen) DrawCaption(g, ip, grid.Radius, "Ellipse") ip.X += grid.StepX '' Cylinder: Dim radX = grid.Radius / 1.4F Dim radY = grid.Radius / 6 Dim height = grid.Radius * 1.8F g.DrawEllipse(New RectangleF(ip.X - radX, ip.Y - height / 2, radX * 2, radY * 2), pen) g.FillEllipse(New RectangleF(ip.X - radX, ip.Y + height / 2 - radY * 2, radX * 2, radY * 2), Color.FromArgb(fill, pen.Color)) g.DrawEllipse(New RectangleF(ip.X - radX, ip.Y + height / 2 - radY * 2, radX * 2, radY * 2), pen) g.DrawLine(New PointF(ip.X - radX, ip.Y - height / 2 + radY), New PointF(ip.X - radX, ip.Y + height / 2 - radY), pen) g.DrawLine(New PointF(ip.X + radX, ip.Y - height / 2 + radY), New PointF(ip.X + radX, ip.Y + height / 2 - radY), pen) DrawCaption(g, ip, grid.Radius, "Cylinder") ip.X = startIp.X ip.Y += grid.StepY pen.Color = Color.Indigo '' Square: DrawPolygon(g, ip, grid.Radius, 4, -Math.PI / 4, pen, "Square") ip.X += grid.StepX '' Rectangle: Dim rectQx = 1.4F Dim rectQy = 0.6F Dim rect = New RectangleF(ip.X - grid.Radius * rectQx, ip.Y - grid.Radius * rectQy, grid.Radius * 2 * rectQx, grid.Radius * 2 * rectQy) g.DrawRectangle(rect, pen) DrawCaption(g, ip, grid.Radius, "Rectangle") ip.X += grid.StepX '' Cube: Dim cubex = 6 Dim cubePtsFar = DrawPolygon(g, New PointF(ip.X - cubex, ip.Y - cubex), grid.Radius, 4, -Math.PI / 4, pen) Dim cubePtsNear = DrawPolygon(g, New PointF(ip.X + cubex, ip.Y + cubex), grid.Radius, 4, -Math.PI / 4, pen) g.DrawLine(cubePtsFar(0), cubePtsNear(0), pen) g.DrawLine(cubePtsFar(1), cubePtsNear(1), pen) g.DrawLine(cubePtsFar(2), cubePtsNear(2), pen) g.DrawLine(cubePtsFar(3), cubePtsNear(3), pen) g.FillPolygon(New PointF() {cubePtsFar(1), cubePtsFar(2), cubePtsNear(2), cubePtsNear(1)}, Color.FromArgb(fill, pen.Color)) DrawCaption(g, ip, grid.Radius, "Cube") ip.X = startIp.X ip.Y += grid.StepY pen.Color = Color.DarkGreen '' Pentagon: DrawPolygon(g, ip, grid.Radius, 5, -Math.PI / 2, pen, "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, pen, Nothing) g.Transform = Matrix3x2.Identity DrawCaption(g, ip, grid.Radius, "Hexagon") ip.X += grid.StepX '' Octagon: DrawPolygon(g, ip, grid.Radius, 8, -Math.PI / 8, pen, "Octagon") ip.X = startIp.X ip.Y += grid.StepY pen.Color = Color.DarkRed '' Triangle: DrawPolygon(g, ip, grid.Radius, 3, -Math.PI / 2, pen, "Triangle") ip.X += grid.StepX '' Filled pentagram: Dim pts = DrawPolygon(g, ip, grid.Radius, 5, -Math.PI / 2, pen, "Pentagram") pts = New PointF() {pts(0), pts(2), pts(4), pts(1), pts(3)} g.FillPolygon(pts, Color.FromArgb(fill, pen.Color)) g.DrawPolygon(pts, pen) ip.X += grid.StepX '' Set up a simple kind of oblique projection to draw a pyramid: Dim angle = Math.PI / 6 Dim s = Math.Sin(angle) Dim c = Math.Cos(angle) Dim project As Func(Of Single, Single, Single, PointF) = Function(ByVal x_, ByVal y_, ByVal z_) Return New PointF(x_ - c * y_ * 0.5F, -(z_ - s * y_ * 0.5F)) End Function Dim p3d As Func(Of Vector3, PointF) = Function(ByVal v_) Return project(v_.X, v_.Y, v_.Z) End Function Dim 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: Dim pts3d As 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: pts = pts3d.Select(Function(v_) p3d(v_)).ToArray() g.Transform = Matrix3x2.CreateTranslation(ip.X, ip.Y + hedge * 0.7F) '' Visible edges: g.DrawPolygon(New PointF() {pts(4), pts(1), pts(2), pts(3), pts(4), pts(2)}, pen) '' Invisible edges: pen.Width /= 2 pen.Color = Color.FromArgb(fill, pen.Color) g.DrawLine(pts(0), pts(4), pen) g.DrawLine(pts(0), pts(1), pen) g.DrawLine(pts(0), pts(3), pen) g.FillPolygon(pts.Take(4).ToArray(), pen.Color) '' g.Transform = Matrix3x2.Identity DrawCaption(g, ip, grid.Radius, "Pyramid") ip.X = startIp.X ip.Y += grid.StepY pen.Width *= 2 pen.Color = Color.Green '' Cone: Dim baseh = grid.Radius * 0.3F pts = DrawPolygon(g, ip, grid.Radius, 3, -Math.PI / 2, Nothing, "Cone") g.DrawLines(New PointF() {pts(2), pts(0), pts(1)}, pen) rect = New RectangleF(pts(2).X, pts(2).Y - baseh / 2, pts(1).X - pts(2).X, baseh) g.FillEllipse(rect, Color.FromArgb(fill, pen.Color)) g.DrawEllipse(rect, pen) ip.X += grid.StepX '' Parallelogram (use graphics.Transform on a rectangle): rect = New RectangleF(-grid.Radius * rectQx, -grid.Radius * rectQy, grid.Radius * 2 * rectQx, grid.Radius * 2 * rectQy) g.Transform = Matrix3x2.CreateSkew(Math.PI / 6, 0) * Matrix3x2.CreateTranslation(ip.X, ip.Y) g.DrawRectangle(rect, pen) 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): Dim dx = 10 pts = DrawPolygon(g, ip, grid.Radius, 4, -Math.PI / 4, Nothing, "Trapezoid") pts(0).X -= dx pts(1).X += dx pts(2).X -= dx pts(3).X += dx g.DrawPolygon(pts, pen) '' '' Done: doc.Save(stream) Return doc.Pages.Count End Function End Class