I woke up early a couple of days ago and to pass the time till the rest of the house woke up, I decided to do a little hobby programming. I wanted to do a little animation around a star fractal. I didn't find the Koch snowflake aesthetically pleasing, so I thought I'd make my own based on a tree fractal algorithm that I knew gave pleasing results. This got lost somewhere a long the way and I ended up reducing my goal to creating a pleasing tree.
Rather than talk about the structure of the code, which is pretty simple, I thought it would interesting to review the sequence of images I created and talk about the decisions I made to come up with the next version. The code to produce the images is available on github.com/robertpi/FractalTree and will be linked to, if you want to see what the code changes look like. I didn't store my earlier version of the algorithm in git, so some of the earlier versions have been reversed engineered from later versions, but I think they're pretty close to what I had.
I found the process interesting of creating the tree interesting. The algorithm is simple and probably took about 10 mins to implement the original version, but since then I have I spent a few hours tuning it to give prettier results. This seems to embody the trade off faced in almost every domain of software development: basic results can be achieved quickly but producing better or more pleasing results can take much effort tuning the code.
For the first cut I simply copied and pasted the pseudo code given in the tree fractal algorithm article and fixed it up till it was valid F#. The algorithm is simple, calculate the start and end of a branch from its length and angle, then plot the branch, adjust the length and angles before plotting the next branch.
It struck me that the tree was very pixelated. That seemed strange to me, since I can't remember the last time I saw an image that looked pixelated, unless it was a deliberately added effect. I thought this was down to hardware improvements, and maybe a lot of it is, but it seems that most drawing libraries have some kind of smoothing turned on by default. The System.Drawing namespace does not have smoothing by default, but it is simple to opt-in. Once I added smoothing, the pixilation went away.
I thought my trees looked more like grass. A little web searching led me to this article about fractal trees, where the trees have a much more pleasing astatic. I noticed they weren't based on randomness but alternating angle sizes for the branches. It was fairly easy to modify my program to produce that effect.
I liked this style, but the trees in the article looked better. I liked the way the branches slimmed on the way up the tree, this too was a straight forward modification (just one line moved).
The tree still looked a bit square, I was hoping for something a little more organic looking. I decided to make the branches from ellipses.
The tree was looking fairly good by this point, but I thought I could do better. I didn't like the the look of the joints in the branches, my calculations left bits sticking out which looked messy. I could have tried to tune my calculations so this didn't happen, but another approach occurred to me. The System.Drawing namespace has methods that allow you to draw individual shapes like ellipses, but it also has methods that allow you to draw polygons by defined by a list of points that form a path to plot. I decided to try and plot a whole path for the tree and then let the method FillClosedCurve draw me a smooth tree.
This approach is tricky as it matters in which order the points are passed to the FillClosedCurve method, since this is the order they are drawn in. Any error in the ordering of the points leads to a tree that curls around in strange way. This is differs from the approach of drawing individual branches, as the order individual branches are drawn in doesn't matter.
To make this approach work I embarked on a major refactoring of the program. This included creating a type that modelled the tree, using the type to generate a tree and then generating the path from the tree structure. The technique works okay, but I'm not that happy with the program's structure, there seems to be quite a lot of repetition, particular I call Math.Sin and Math.Cos in a few different places, where I'm basically doing the same thing. But the effort of coming up with a better structure doesn't really seem worth it at this point.
I like the resulting tree a lot, but it's also not exactly what I had in mind. The calculation for the position of the edge of the branches is wrong somehow, but it's wrong in a way that produces a consistent art-deco like scroll effect, so I'll settle for that.
Now all that remains is to vary the parameters to create an animation, but that's for another day.
I hope this little tour of my programming decisions has interested you. Feel free to get in touch with any comments.