Draw a recursive snowflake fractal in C#

  


This program draws a recursive snowflake fractal by using an initiator and a generator to define the fractal’s shape.

The initiator is a curve that represent the fractal’s basic shape. In this case, the initiator is the triangle shown in the second picture above where the depth of recursion is zero.

The generator is a curve that shows how to break up a line segment to go to the next level of recursion. In this example, the generator is shown across the top of the third picture above. To draw a line segment, the program draws 1/3 of the distance along the segment, turns -60 degrees, draws 1/3 of the original distance, turns 120 degrees, draws 1/3 of the original distance, turns -60 degrees, and finishes by drawing another 1/3 of the original distance. The result is a series of line segments that start and end at the same points as the original line segment (which would have been drawn directly for a smaller depth of recursion) but that includes a copy of the generator. To go to greater depths of recursion, all of the line segments just drawn would be replaced by smaller copies of the generator.

You can make a less complicated snowflake generator that simply turns as required. By using a separate initiator and generator, this program is more general and can draw other fractals, which I’ll show in later posts.

The following code shows how the program declares its initiator and generator variables. Look at the code to see how these are initialized.

// Coordinates of the points in the initiator.
private List<PointF> Initiator;

// Angles and distances for the generator.
private float ScaleFactor;
private List<float> GeneratorDTheta;

The following code shows the DrawSnowflake method that starts drawing the snowflake fractal.

// Draw the complete snowflake.
private void DrawSnowflake(Graphics gr, int depth)
{
    gr.Clear(picCanvas.BackColor);

    // Draw the snowflake.
    for (int i = 1; i < Initiator.Count; i++)
    {
        PointF p1 = Initiator[i - 1];
        PointF p2 = Initiator[i];

        float dx = p2.X - p1.X;
        float dy = p2.Y - p1.Y;
        float length = (float)Math.Sqrt(dx * dx + dy * dy);
        float theta = (float)Math.Atan2(dy, dx);
        DrawSnowflakeEdge(gr, depth, ref p1, theta, length);
    }
}

This code loops through the points in the initiator and calls DrawSnowflakeEdge to draw each of the edges. Note that in this example to make a closed curve the first initiator point should be repeated as the last point.

The following code shows the recursive DrawSnowflakeEdge method.

// Recursively draw a snowflake edge starting at
// (x1, y1) in direction theta and distance dist.
// Leave the coordinates of the endpoint in
// (x1, y1).
private void DrawSnowflakeEdge(Graphics gr, int depth,
    ref PointF p1, float theta, float dist)
{
    if (depth == 0)
    {
        PointF p2 = new PointF(
            (float)(p1.X + dist * Math.Cos(theta)),
            (float)(p1.Y + dist * Math.Sin(theta)));
        gr.DrawLine(Pens.Blue, p1, p2);
        p1 = p2;
        return;
    }

    // Recursively draw the edge.
    dist *= ScaleFactor;
    for (int i = 0; i < GeneratorDTheta.Count; i++)
    {
        theta += GeneratorDTheta[i];
        DrawSnowflakeEdge(gr, depth - 1, ref p1, theta, dist);
    }
}

If the depth of recursion is 0, the code simply draws a line segment starting at the start point with the indicated direction and distance.

For higher depths of recursion, the method multiples the length that it should draw by the scale factor (in this example 1/3) and then loops through the angles in the generator. For each angle, DrawSnowflakeEdge recursively calls itself to draw a segment in the new direction with the new length.

Download the example to see additional details.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in algorithms, drawing, fractals, graphics, mathematics and tagged , , , , , , , , , , , , , , , , . Bookmark the permalink.

12 Responses to Draw a recursive snowflake fractal in C#

  1. Phan Sang says:

    Marvellous ! Keep working Rod , I’m want to learn more 😀 .

  2. Pingback: Draw a recursive overlapping snowflake fractal curve in C#C# Helper

  3. Phan Sang says:

    Hi Rods, is there any way to automatically redraw the image when I change the window size (by pressing maximize and minimize button), if yes, please show me, Thank you a lot.

    • Phan Sang says:

      And there is more, when your program is running, If I change the depth value and press Enter, it will redraw instantly. But when I do the same(I had copied exactly every piece of code in your program ), It make the sound “pring”. I can only redraw when I press Button “Go”, not when press “Enter”. I have studied your program for a while but I could not find out why. I hope you can help me, thanks.

      • RodStephens says:

        At design time I set the form’s AcceptButton property to the Go button. When you press Enter, the form triggers its AcceptButton. If there isn’t a button assigned to the property, it beeps. (It’s a small thing but doesn’t appear in the code so it can be hard to figure out.)

    • RodStephens says:

      You would need to create a new event handler to detect the change in size and redraw. For example, you could catch the PictureBox’s Resize event and make it call the same code that the button executes.

      To make that cleaner, you could move that code into a new method and then call the method from both the button’s Click event handler and the new Resize event handler.

  4. Pingback: Draw a recursive overlapping snowflake fractal curve in C#C# Helper

  5. Jason says:

    Hi Rod,

    Seems like the example project is no longer available – you mind fixing the link?

    Thanks!

  6. taimeo says:

    hi Rod , can u show me code of Go button please ,

    • RodStephens says:

      I would post it here but it’s pretty long. Mostly it does some calculations to create the initiator and generator, and then it calls DrawSnowflake.

      Click the Download button at the end of the post to download the complete solution. Then you can look at the code to see all of the button’s details.

Leave a Reply

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