Title: Draw stars inside polygons in C#
This example shows how to draw stars inside a polygon by connecting every M-th vertex as it draws. If the polygon has N sides and N and M are relatively prime (have no common factors except 1), then the lines visit every vertex and the result is a star. Note if M is 1, then the lines draw the polygon.
The PictureBox's Paint event handler loops for i = 1 to N - 1, drawing each star in the center of the PictureBox. It also draws each star near the i-th vertex.
// Draw the stars.
private void picCanvas_Paint(object sender, PaintEventArgs e)
{
if (NumPoints < 3) return;
e.Graphics.Clear(picCanvas.BackColor);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Get the radii.
int r1, r2, r3;
r3 = Math.Min(
picCanvas.ClientSize.Width,
picCanvas.ClientSize.Height) / 2;
r1 = r3 / 2;
r2 = r3 / 4;
r3 = r1 + r2;
// Position variables.
int cx = picCanvas.ClientSize.Width / 2;
int cy = picCanvas.ClientSize.Height / 2;
// Position the original points.
PointF[] pts1 = new PointF[NumPoints];
PointF[] pts2 = new PointF[NumPoints];
double theta = -Math.PI / 2;
double dtheta = 2 * Math.PI / NumPoints;
for (int i = 0; i < NumPoints; i++)
{
pts1[i].X = (float)(r1 * Math.Cos(theta));
pts1[i].Y = (float)(r1 * Math.Sin(theta));
pts2[i].X = (float)(r2 * Math.Cos(theta));
pts2[i].Y = (float)(r2 * Math.Sin(theta));
theta += dtheta;
}
// Draw stars.
int max = NumPoints - 1;
if (chkHalfOnly.Checked) max = (int)(NumPoints / 2);
for (int skip = 1; skip <= max; skip++)
{
// See if they are relatively prime.
bool draw_all = !chkRelPrimeOnly.Checked;
if (draw_all || GCD(skip, NumPoints) == 1)
{
// Draw the big version of the star.
DrawStar(e.Graphics, cx, cy, pts1, skip);
// Draw the smaller version.
theta = -Math.PI / 2 + skip * 2 * Math.PI / NumPoints;
int x = (int)(cx + r3 * Math.Cos(theta));
int y = (int)(cy + r3 * Math.Sin(theta));
DrawStar(e.Graphics, x, y, pts2, skip);
}
}
}
The Paint event handler starts by making arrays holding points to draw the central and outer stars. These points would draw a polygon centered at the origin if they were drawn as they are in the arrays.
Next the code starts a for loop to draw the smaller polygons. If you check the "Half only" CheckBox, the program loops from 1 to N/2. If you don't check this box, the program loops through all of the values between 1 and N - 1. (You only need to draw half of them to make all of the possible patterns, but drawing them all produces a nice symmetrical result.)
If you check the "Relatively prime only" CheckBox, the program calls the GCD function to decide whether the skip value and the number of sides are relatively prime, and it only draws the line if they are.
Finally, after all this work to decide whether it should draw the lines, the program calls the DrawStar method to do so. It then calculates where the smaller polygon should be drawn and calls DrawStar again to draw it there.
See the example Calculate the greatest common divisor (GCD) and least common multiple (LCM) of two integers in C# for more information on the GCD function.
The DrawStar method shown in the following code shows draws a polygon and the lines connecting vertices.
// Draw a star centered at (x, y) using this skip value.
private void DrawStar(Graphics gr, int x, int y,
PointF[] orig_pts, int skip)
{
// Make a PointF array with the points in the proper order.
PointF[] pts = new PointF[NumPoints];
for (int i = 0; i < NumPoints; i++)
{
pts[i] = orig_pts[(i * skip) % NumPoints];
}
// Draw the star.
gr.TranslateTransform(x, y);
gr.DrawPolygon(Pens.Blue, pts);
gr.ResetTransform();
}
The code makes an array of PointF objects and then copies the vertices into it in the proper order. The code then calls DrawPolygon to connect the vertices in their new order.
Download the example to experiment with it and to see additional details.
|