Shapes.vb
```''
'' This code is part of Document Solutions for Imaging demos.
''
Imports System.IO
Imports System.Drawing
Imports System.Numerics
Imports GrapeCity.Documents.Drawing
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Imaging
Imports GCTEXT = GrapeCity.Documents.Text
Imports GCDRAW = GrapeCity.Documents.Drawing

'' Demonstrates how various shapes can be drawn in DsImaging.
'' 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 pen 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 pen IsNot Nothing Then
g.DrawPolygon(pts, pen)
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 = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "times.ttf")), .FontSize = 10},
New RectangleF(center.X - r, center.Y + r, r * 2, 24),
TextAlignment.Center, ParagraphAlignment.Center, False)
End Sub

'' Main entry point.
Function GenerateImage(
ByVal pixelSize As Size,
ByVal dpi As Single,
ByVal opaque As Boolean,
Optional ByVal sampleParams As String() = Nothing) As GcBitmap

Dim Inch = dpi
Dim bmp = New GcBitmap(pixelSize.Width, pixelSize.Height, True, dpi, dpi)
Using g = bmp.CreateGraphics(Color.White)
g.DrawString("Shapes",
New TextFormat() With {.Font = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "timesbd.ttf")), .FontSize = 14, .Underline = True},
New RectangleF(PointF.Empty, New SizeF(bmp.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 = Inch / 4,
.MarginY = Inch / 3,
.StepX = (bmp.Width - Inch / 2) / 3,
.StepY = (bmp.Height - Inch / 4) / 5.5F
}

'' 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
ipp.Y += grid.StepY
Next
ipp.X += grid.StepX
Next
#End If
'' Circle:
ip.X += grid.StepX

'' Ellipse:
ip.X += grid.StepX

'' Cylinder:
Dim height = grid.Radius * 1.8F
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)
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)
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))
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
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
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):
g.Transform = Matrix3x2.CreateSkew(Math.PI / 6, 0) * Matrix3x2.CreateTranslation(ip.X, ip.Y)
g.DrawRectangle(rect, pen)
g.Transform = Matrix3x2.Identity
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)

'' Draw border around the whole image
g.DrawRectangle(New RectangleF(0, 0, bmp.Width, bmp.Height), Color.DarkSlateBlue, 4)
End Using
'' Done
Return bmp
End Function
End Class

```