|
|
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 five-pointed 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
|
|
|
|
|
|