This example uses recursion to build a fractal tree. It starts by drawing the tree’s trunk. At the end of the trunk, it creates two branches. At the end of each branch, it creates two new branches A and B. It continues recursively creating two new branches at the ends of each branch until it has reached a maximum depth of recursion.

The parameters that you enter are:

- Level: The depth of recursion.
- Angle A: The angle that branch A turns with respect to its parent branch.
- Length Scale A: During each recursive call, the program reduces the length of the A branch by this factor. For example, if a branch X has length 100 and this value is 0.9, then the A branch from the end of X has length 100 * 0.9 = 90.
- Angle B: The angle that branch B turns with respect to its parent branch.
- Length Scale B: During each recursive call, the program reduces the length of the B branch by this factor.

The following `MakeTree` method draws the tree.

// Make the tree. The angles are in radians. private Bitmap MakeTree(int width, int height, int level, float angleA, float angleB, float length_scaleA, float length_scaleB) { // Make the line segments. List<PointF> start_points = new List<PointF>(); List<PointF> end_points = new List<PointF>(); float start_length = picCanvas.ClientSize.Height * 0.33f; const float start_thickness = 10; const float start_direction = (float)(Math.PI * 0.5); FindTreePoints(start_points, end_points, 0, 0, start_direction, level, start_length, angleA, angleB, length_scaleA, length_scaleB); // Find the tree's bounds. float xmin = start_points[0].X; float xmax = xmin; float ymin = start_points[0].Y; float ymax = ymin; foreach (PointF point in end_points) { if (xmin > point.X) xmin = point.X; if (xmax < point.X) xmax = point.X; if (ymin > point.Y) ymin = point.Y; if (ymax < point.Y) ymax = point.Y; } // Make the bitmap. Bitmap bm = new Bitmap( picCanvas.ClientSize.Width, picCanvas.ClientSize.Height); using (Graphics gr = Graphics.FromImage(bm)) { gr.Clear(picCanvas.BackColor); gr.SmoothingMode = SmoothingMode.AntiAlias; // Map the tree onto the PictureBox. xmin -= start_thickness; xmax += start_thickness; ymin -= start_thickness; ymax += start_thickness; RectangleF world_rect = new RectangleF( xmin, ymin, xmax - xmin, ymax - ymin); const int margin = 4; RectangleF device_rect = new RectangleF( margin, margin, picCanvas.ClientSize.Width - 2 * margin, picCanvas.ClientSize.Height - 2 * margin); SetTransformationWithoutDisortion(gr, world_rect, device_rect, false, true); // Draw the tree. using (Pen pen = new Pen(Color.Blue, 1)) { for (int i = 0; i < start_points.Count; i++) { pen.Width = Distance( start_points[i], end_points[i]) / 10f; gr.DrawLine(pen, start_points[i], end_points[i]); } } } return bm; }

The method first creates the points that define the tree's branches. It creates the `start_points` and `end_points` lists to keep track of the branches' start and end points.

It calculates a reasonable starting length and thickness for the tree's trunk, and it sets the starting angle to be π/2 so the trunk points upward.

The code then calls the `FindTreePoints` method described shortly to generate the tree's points.

Next the method finds the tree's coordinate bounds. It sets variables `xmin`, `xmax`, `ymin`, and `ymax` to the first point in the `start_points` list, which is the bottom of the tree's trunk. (Its root, if you will.) It then loops through the `end_points` list and updates the minimum and maximum X and Y coordinate values as needed.

Note that the program doesn't need to loop through the `start_points` list because every point in that list except for its first point is also in the `end_points` list. That's true because every branch's start point is the end point of the branch's parent branch. That's true for every branch except the trunk, which has no parent branch. That point is considered first when the code initializes the `xmin`, `xmax`, `ymin`, and `ymax` variables.

The `end_points` list also contains the leaves, branch end points that are not also start points. The leaves are contained in the `end_points` list but not in the `start_points` list.

So by considering the trunk's root and the points in the `end_points` list, the code has considered every point in the tree.

Next the code creates a `Bitmap` to hold the drawn tree. After some setup, it expands the coordinate bounds a bit to add a margin around the tree. It makes `RectangleF` structures to represent the area that the tree occupies and the area on the `PictureBox` where it should be drawn. It then calls `SetTransformationWithoutDisortion` to map the drawing area onto the `PictureBox` area. See the post Map drawing coordinates without distortion in C# for information on that method.

That mapping was the reason why the program generated the tree's branches first without drawing them. Depending on the tree's parameters, it can be hard to figure out exactly where the finished tree will be drawn. Rather than trying to do that, the program just generates the points and finds their bounds. It then creates the mapping to make the tree fit the `PictureBox` nicely.

The method finishes by drawing the tree and returning the resulting bitmap.

The following code shows the recursive `FindTreePoints` method.

// Generate segments for the tree. // The direction parameter is in radians. private void FindTreePoints( List<PointF> start_points, List<PointF> end_points, float x, float y, float direction, int level, float length, float angleA, float angleB, float length_scaleA, float length_scaleB) { // Find the new segment. if (length < 0.1) return; start_points.Add(new PointF(x, y)); x += (float)(length * Math.Cos(direction)); y += (float)(length * Math.Sin(direction)); end_points.Add(new PointF(x, y)); if (level > 0) { FindTreePoints(start_points, end_points, x, y, direction + angleA, level - 1, length * length_scaleA, angleA, angleB, length_scaleA, length_scaleB); FindTreePoints(start_points, end_points, x, y, direction + angleB, level - 1, length * length_scaleB, angleA, angleB, length_scaleA, length_scaleB); } }

This remarkably simple method first checks the length of the current branch and returns if the length is less than 0.1. Branches that small can make the program do a lot of work to just fill in a single pixel.

Next the method calculates the new branch's end point and adds the start and end points to the `start_points` and `end_points` lists.

If the level is greater than zero, the method has not reached the desired depth of recursion so the method calls itself recursively to draw smaller branches. It adds the A and B branch angles to its correct direction and it shortens the new branches.

By changing the drawing parameters, you can generate a nice variety of trees such as the following.