Draw a Barnsley fern fractal in C#

This example draws a Barnsley fern fractal. For information about this kind of fractal, see Barnsley’s Fern by Eric W. Weisstein from MathWorld, a Wolfram Web Resource.

The program starts from a random point. At each step, it randomly picks a function (with non-uniform probability) and applies the function to the point to find the next point. It then plots that point.

Each function has the form:

X(n+1) = A * X(n) + B * Y(n) + C
Y(n+1) = D * X(n) + E * Y(n) + F

The following code initializes the probability and function parameters.

private float[] Prob = { 0.01f, 0.85f, 0.08f, 0.06f };
private float[, ,] Func =
{
    {
        {0, 0},
        {0, 0.16f},
    },
    {
        {0.85f, 0.04f},
        {-0.04f, 0.85f},
    },
    {
        {0.2f, -0.26f},
        {0.23f, 0.22f},
    },
    {
        {-0.15f, 0.28f},
        {0.26f, 0.24f},
    },
};
private float[,] Plus =
{
    {0, 0},
    {0, 1.6f},
    {0, 1.6f},
    {0, 0.44f},
};

The Prob array gives the probabilities of picking each of the different functions. The Func array contains the values A, B, D, and E. The Plus array holds the values C and F.

The following MakeFern method draws the fractal into a Bitmap and displays it.

private void MakeFern()
{
    int wid = picCanvas.ClientSize.Width;
    int hgt = picCanvas.ClientSize.Height;
    Bitmap bm = new Bitmap(wid, hgt);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        gr.Clear(Color.Black);

        Random rnd = new Random();
        int func_num = 0, ix, iy;
        float x = 1, y = 1, x1, y1;
        for (int i = 1; i <= 100000; i++)
        {
            double num = rnd.NextDouble();
            for (int j = 0; j <= 3; j++)
            {
                num = num - Prob[j];
                if (num <= 0)
                {
                    func_num = j;
                    break;
                }
            }

            x1 = x * Func[func_num, 0, 0] +
                 y * Func[func_num, 0, 1] +
                 Plus[func_num, 0];
            y1 = x * Func[func_num, 1, 0] +
                 y * Func[func_num, 1, 1] +
                 Plus[func_num, 1];
            x = x1;
            y = y1;

            const float w_xmin = -4;
            const float w_xmax = 4;
            const float w_ymin = -0.1f;
            const float w_ymax = 10.1f;
            const float w_wid = w_xmax - w_xmin;
            const float w_hgt = w_ymax - w_ymin;
            ix = (int)Math.Round((x - w_xmin) /
                w_wid * picCanvas.ClientSize.Width);
            iy = (int)Math.Round(
                (picCanvas.ClientSize.Height - 1) - 
                (y - w_ymin) / w_hgt * hgt);
            if ((ix >= 0) && (iy >= 0) &&
                (ix < wid) && (iy < hgt))
            {
                bm.SetPixel(ix, iy, Color.Lime);
            }
        }
    }

    // Display the result.
    picCanvas.BackgroundImage = bm;
}

The MakeFern method starts at point (1, 1) and repeatedly applies randomly selected functions, plotting each point on the Bitmap.




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

6 Responses to Draw a Barnsley fern fractal in C#

  1. gopal says:

    hi ,i am trying to draw some fractal image ,i am stuck here,can u help ?
    http://stackoverflow.com/questions/25424978/how-to-make-diagram-fit-with-in-panel

  2. RodStephens says:

    One problem here is that you’re using CreateGraphics to make the Graphics object. That’s rarely the right thing to do.

    If you’re drawing in a Paint event handler, use the e.Graphics parameter.

    In this example, pass e.Graphics into the draw_T method:

    private void Canvas_Paint(object sender, PaintEventArgs e)
    {
        start_x = Canvas.Width / 2;
        start_y = Canvas.Height / 2;
        for (int i = 0; i < 400; i++)
            draw_T(e.Graphics);
    }
    
    public void draw_T(Graphics g)
    {
        ...
    }

    It looks like you may have a sizing problem, too, but if you make this change at least you can see some results and then try to fix them. Give it a try and post again if you get stuck.

  3. Eddie Bole says:

    Hi Rod. I recently made something similar in Vb6 at http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=75599&lngWId=1 I tried altering the colours of the fern needles to try to imitate the fern colours in real life, with mostly green and adding a bit of yellow and off white to imitate snow. Would you possibly be able to show how to introduce a variation of colours with your example in csharp? I was also wondering if transparency could be variable, so the inner parts near the stem are opaque (non see through) and the tips (which tend to be over drawn) are made slightly transparent.

    • RodStephens says:

      (Your program looks pretty cool!)

      Unfortunately I don’t know how to do that. This fractal is a strange attractor, so each point seems to appear sort of randomly and it’s only when you plot a lot of them that the pattern appears. That means there’s no obvious way to know when a point is at a certain position in the fractal.

      If you could tell where a point was in the fractal, you would probably see a recursive effect. For example, if you make the tips of the big leaves white, then the tips of the smaller leaves that make up the big ones would probably also be white. And the even smaller leaves that make up the small leaves. Etc.

      I think your best bet may be to look at the absolute positions of the points and use that to color them. For example, you could draw a curve down the middle of the main branch. Then you could change a point’s color depending on how far it was from that curve. You might also want to look at how far up the main branch the point is so the smaller leaves at the top also get white edges.

      You might also look at the side of the main branch where the point lies. For example, you could make the points to the left of the main branch be lighter than those to the right.

      Unfortunately all of that sounds kind of hard. If you can find a way to draw a fern recursively, as you did with the Pythagoras tree, then you could use the depth of recursion to change the color.

  4. Eddie Bole says:

    Yes by changing the RGB colours I was able to make some bits a bit whiter, so I will play around a bit to perhaps try alter the transparency of that part so then next step would be to play around with ARGB. What I noticed was the tips tend to be over saturated with colour, so their features are less distinguishable (so I thought by making them a touch transparent the whole picture would come up a bit clearer). In the vb6 version I also made the colour mostly green and introduced variable amounts of Red and Blue to add some realism. Thanks for replying. Much appreciated.

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.