

Title  Draw "stars" inside regular polygons in VB .NET 
Description  This example shows how to draw "stars" inside regular polygons in Visual Basic .NET. 
Keywords  star, polygon, VB.NET 
Categories  Graphics, VB.NET 


The program draws stars by drawing lines between the vertices on a regular polygon. It always connects the current vertex to the Kth vertex after it. For example, a normal fivepointed star is drawn inside a pentagon by connecting every 2nd vertex. I.e. vertex 0 is connected to vertex 2, then vertex 4, then vertex 1, then vertex 3, then vertex 0 (draw one on paper if you don't understand this).
This drawing scheme will visit every vertex in the polygon before repeating if and only if the number of vertices N and the number K is relatively prime (i.e. have no common factors). I'll leave the proof to you. In the previous example, N = 5 and K = 2 are relatively prime so that drawing method visits every point before repeating.
Note that K = 1 is relatively prime to any number N so drawing with K = 1 visits every vertex before repeating. That just gives the polygon itself.
Also note that K = k and K = N  k draw the same "star." Try K = 2 and K = 3 for a pentagon.
The picCanvas control's Paint event handler draws the stars. It allocates space for the polygon's points and places them evenly spaced around a circle. It then loops over the numbers 1 through N \ 2 and tries using them as K. It doesn't need to examine values N \ 2 through N because of the second note above.
For each skip (K) value, the program determines the greatest common divisor (GCD) of K and N. If the GCD is 1, then N and K are relatively prime so the program calls subroutine DrawStar to draw the "star" and draws a label showing the number K.


' Draw the applicable stars.
Private Sub picCanvas_Paint(ByVal sender As Object, ByVal e _
As System.Windows.Forms.PaintEventArgs) Handles _
picCanvas.Paint
If m_NumPoints < 3 Then Exit Sub
Const RADIUS As Integer = 40
Dim x, y As Integer
' Position the original points.
Dim pts(m_NumPoints  1) As PointF
Dim theta As Double = PI / 2
Dim dtheta As Double = 2 * PI / m_NumPoints
For i As Integer = 0 To m_NumPoints  1
pts(i).X = RADIUS * Cos(theta)
pts(i).Y = RADIUS * Sin(theta)
theta += dtheta
Next i
' Draw stars.
y = RADIUS + 5
x = RADIUS + 5
Dim sf As New StringFormat
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Near
e.Graphics.Clear(picCanvas.BackColor)
For skip As Integer = 1 To m_NumPoints \ 2
' See if they are relatively prime.
If GCD(skip, m_NumPoints) = 1 Then
' Draw the star.
DrawStar(e.Graphics, x, y, pts, skip)
' Draw a label.
e.Graphics.DrawString(skip.ToString, _
picCanvas.Font, Brushes.Black, x, y + _
RADIUS + 2, sf)
x += 2 * RADIUS + 5
If x + RADIUS >= picCanvas.Width Then
y += 2 * RADIUS + 15
x = RADIUS + 5
End If
End If
Next skip
End Sub


Subroutine DrawStar draws a "star" centered at a point. It makes a new array containing the polygon's vertices in the proper order to draw the "star," translates the Graphics object to position the "star," and then draws it.


' Draw a star centered at (x, y) using this skip value.
Private Sub DrawStar(ByVal gr As Graphics, ByVal x As _
Integer, ByVal y As Integer, ByVal orig_pts() As _
PointF, ByVal skip As Integer)
' Make a PointF array with the points in the proper
' order.
Dim pts(m_NumPoints  1) As PointF
For i As Integer = 0 To m_NumPoints  1
pts(i) = orig_pts((i * skip) Mod m_NumPoints)
Next i
' Draw the star.
gr.TranslateTransform(x, y)
gr.DrawPolygon(Pens.Blue, pts)
gr.ResetTransform()
End Sub


Subroutine GCD determines the greatest common divisor of two numbers. I'll leave this proof to you, too.


' Return the greatest common divisor (GCD) of a and b.
Public Function GCD(ByVal a As Long, ByVal b As Long) As _
Long
Dim tmp As Long
Dim remainder As Long
' Make a >= b.
a = Abs(a)
b = Abs(b)
If a < b Then
tmp = a
a = b
b = tmp
End If
' Pull out remainders.
Do
remainder = a Mod b
If remainder = 0 Then Exit Do
a = b
b = remainder
Loop
Return b
End Function





