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