[C# Helper]
Index Books FAQ Contact About Rod
[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Draw a randomly colored Sierpinski pentagon in C#

[Draw a randomly colored Sierpinski pentagon in C#]

The example Draw a colored Sierpinski pentagon in C# lets the user click on the parts of a Sierpinski pentagon to change their colors. Eddie Bole thought it would be interesting to color the larger pentagons in addition to the smaller ones into which each is divided. This example does that.

To make that easier, I modified the Pentagon class to more accurately reflect the recursive structure of the Sierpinski pentagon. The following code shows the new Pentagon class.

class Pentagon { // Colors. private static Random Rand = new Random(); private static Color[] MyColors = { Color.Black, Color.Red, Color.Orange, Color.Yellow, Color.Lime, Color.LightGreen, Color.Cyan, Color.Blue, Color.LightBlue, Color.Fuchsia, }; public PointF[] Points = null; public Color FillColor = Color.Black; public List<Pentagon> Children = new List<Pentagon>(); // Constructor. public Pentagon(PointF[] points) { Points = points; FillColor = MyColors[Rand.Next(0, MyColors.Length)]; FillColor = Color.FromArgb(128, FillColor); } // Draw. public void Draw(Graphics gr) { // Draw this Pentagon. using (Brush brush = new SolidBrush(FillColor)) { gr.FillPolygon(brush, Points); } gr.DrawPolygon(Pens.Black, Points); // Draw child Pentagons (if any). foreach (Pentagon child in Children) child.Draw(gr); } }

The new class defines the colors that a Pentagon could have. The MyColors array is static so it is shared by all instances of the class. (There's no point making each object take up room for its own separate copy.)

The new Children list gives the pentagons into which the current pentagon is divided to make the Sierpinski pentagon. At the deepest level of recursion, the smallest pentagons are not divided so their Children lists are empty.

The class's constructor saves the pentagon's points and then picks a random color from the MyColors array. It then recreates the color setting its alpha component to 128 so the color is semi-transparent. Alternatively, you could make the MyColors array contain colors with alpha is already 128, but then you would have to specify the colors by giving their red, green, blue, and alpha color components instead of using their names. The code shown here specifies the colors by name so it's easier to know what the colors are.

The Pentagon class's Draw method now draws the current Pentagon. It then recursively calls the Draw methods for its children.

The main program uses the following code to build its Pentagon objects.

// The root of the Pentagon object hierarchy. private Pentagon Root = null; // Make the Pentagon objects and redraw. private void MakePentagons() { // Build the Root. int depth = (int)nudDepth.Value; PointF center = new PointF( picPentagon.ClientSize.Width / 2, picPentagon.ClientSize.Height / 2); float radius = (float)Math.Min(center.X, center.Y); Root = MakePentagon(depth, center, radius); // Redraw. picPentagon.Refresh(); }

The program stores the largest Pentagon object in the variable Root.

The MakePentagons method builds the Sierpinski pentagon. It gets the desired depth of recursion, finds the center of the drawing area, and sets the large pentagon's radius. It then calls the following MakePentagon method to create the largest pentagon.

// Recursively generate a Pentagon and its descendants. private Pentagon MakePentagon(int depth, PointF center, float radius) { // Make the Pentagon. Pentagon parent = new Pentagon(GetPentagonPoints(center, radius)); // If we are not done recursing, make children. if (depth > 0) { // Find the smaller pentagons' centers. float d = radius - radius * size_scale; PointF[] centers = GetPentagonPoints(center, d); // Recursively draw the smaller pentagons. foreach (PointF point in centers) { parent.Children.Add(MakePentagon( depth - 1, point, radius * size_scale)); } } return parent; }

This method first creates a new Pentagon object.

If the depth of recursion has not reached zero, the method gets the pentagon's vertices. The method then loops through the vertices and recursively calls itself to make smaller pentagons at each of the vertices.

When the program needs to redraw the Sierpinski pentagon, it refreshes the picPentagon PictureBox and the following Paint event handler executes.

// Draw. private void picPentagon_Paint(object sender, PaintEventArgs e) { e.Graphics.Clear(picPentagon.BackColor); e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; if (Root == null) return; Root.Draw(e.Graphics); }

This code simply prepares the Graphics object and then calls the Root pentagon's Draw method. that method recursively calls the Draw methods for all of the smaller pentagons.

Note that the pentagons are drawn in order from largest to smallest. That ensures that the smaller pentagons are drawn on top of the larger ones.

Download the example to experiment with it and to see additional details.

© 2009-2023 Rocky Mountain Computer Consulting, Inc. All rights reserved.