Draw a randomly colored Sierpinski pentagon in C#

[example]

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.

Those are the most interesting changes to the program. Download the example to see additional details and to experiment with the program.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in drawing, fractals, graphics, recursion and tagged , , , , , , , , , , . Bookmark the permalink.

5 Responses to Draw a randomly colored Sierpinski pentagon in C#

  1. Eddie Bole says:

    Hi Rod.
    I finally installed Vs2008 after my laptop went down and out. I’ve been playing around with the “Draw a randomly colored Sierpinski pentagon in C#” code and have added a refresh, as well as changed it to produce octagons with the same effect. I was wondering how one could change the number of sides from 5 sides to say 4, 5, 6, 7, 8, 9 or 10 sides using an up/down control? I can change the number of sides and internal angle manually, but I was a bit stumped doing it with an up/down control, similar to the depth control. I also changed the the colors so that they were a bit more pale (I was also going to work on setting the back ground color and adding a save picture feature). Lastly, when the depth level is set to 2, I had noticed that 2 neighboring pentagons/octagons had the same color. Is their a way that can ensure that 2 shapes that are next to each other never have the same color (possibly a Boolean operator)? I will email what I have done (minus exe files). Thanks for your great help. I’m slowly learning csharp so I apologize if I’m asking some basic questions.

    • RodStephens says:

      Your program looks great! Nice selection of colors, too. When you have it working the way you want, I’ll make a brief post so people can download it (unless you say you don’t want me to).

      One way to let the user change the number of sides would be to make the up/down control select the number of sides. Instead of a GetPentagonPoints method, you would need to make a GetPolygonPoints method that takes the number of sides as a parameter. If the polygon has N sides, then the dtheta value would be 2 π / N.

      Otherwise the program would work mostly as it does now.

      You might consider giving background the color Transparent. Then if you save the image into a file, you can draw it on top of other images and the background won’t cover anything behind it. (Although offhand I can’t think why you’d need to do that ;-))

      As for adjacent polygons having the same color, that may be harder than it should be. First, you’ll need to detect when two polygons are adjacent. Then you can check whether they have the same color. When you draw a new polygon, check its neighbors and pick randomly until you get a color that isn’t used by a neighbor.

      When you subdivide a single polygon, you can keep track of the neighboring sub-polygons. Keeping track of neighbors in adjacent parent polygons (or ancestor polygons) would be harder. It may be easiest to just make a list of all polygons and then compare their sides to see if two are adjacent. Be sure to look at the distance between two points to see if they are equal because rounding errors may make two points slightly different when they should be the same.

  2. Eddie Bole says:

    With the duplicate colors, I noticed that for low depth levels there are usually two polygons of the same color next to each other. I thought that it may be due to the recursive nature of procedure being called again and again (which produces the polygons). I thought of 2 coloring strategies:
    1. Start with one color and then randomly add or subtract the Green and say Blue component each time new color is called.
    2. Place say 200 different hex colors in a listbox or an array, randomize the listbox or array and then take out that color each time a color is selected (thus ensuring that no color is the same). Then when all colors are used up refill the listbox or array with the colors and start the process again. The depth levels would probably from 1 to 5 as the black edges in the pattern gets a bit dark and indistinguishable at the higher levels.
    A thought of a few more features to add.
    1. When the depth level is made higher I thought of having a checkbox switch to have a scroll-able “larger than window picture box size” to show extra detail in that higher level pattern.
    2. Also to have an incremental change in color, start with one color and then incrementally add or subtract one color component (say Blue component) each time the recursion is called, so that there is a gradual change in the color.
    I teach maths at a school so I have taught my students how to triangulate polygons to get the relationship between the number of sides and their internal angles. Your sample code is one fantastic example of how that rule can be applied. Also any code that I send to you can be put up on your site for others to play around with (it might have to be cleaned up a bit as my csharp skills are at the training wheel stages but slowly on the improve). I’ve been vb6 programming for many years, so new syntax and ways of doing things still need to be learned. I understand bits and pieces of you csharp code but need to read up and practice a bit more. Once again thanks for the great examples and your help on your csharp helper site.

    • RodStephens says:

      The four color theorem says that you can color the polygons with at most four colors. The “best” approach would be to build a graph describing the polygons and then find a map coloring for it. You could use only four colors, but that can be hard and slow.

      There is a constructive way to find a coloring with five colors, but that’s also hard (although not slow).

      Another approach is to loop through the polygons and pick a random color from the colors that are not yet used by its neighbors. If there are no unused colors for a polygon, backtrack and change the selection at a higher level of recursion. (Lots of details omitted.)

      Your thoughts about adjusting a component at each level of recursion would work, too, and might produce an interesting result, too.

  3. Pingback: Draw a randomly colored Sierpinski octagon in C# - C# HelperC# Helper

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.