I’m so stuck in system level programming in C and Go I almost forget how to do ‘normal’ stuff ;-P Therefore I gave myself a small Go programming exercise, something with visual feedback. Recently I read this excellent post on how to draw a fractal in Clojure and I thought it would be fun to rewrite this in Go.

The fractal is a Barnsley Fern and is an example of an iterated function system. You take a function which returns some values and you use the returned values as the input to the same function in the next step, and you keep doing that until eternity or you put a limit on the amount of steps.

With the Barnsley Fern fractal you have four transform function with input x and y. We give it a start point x and y, one of the randomly chosen transform functions will calculate a new x and y. We draw this as a point on an image and than give the new x and y the the next randomly chosen transform function and repeat this 10,000 times.

If you do this with specific parameters you will draw a fern:

And here is the source code:

package main
import (
"fmt"
"image"
"image/draw"
"image/png"
"image/color"
"log"
"os"
"math/rand"
)
func main() {
m := image.NewRGBA(image.Rect(0, 0, 400, 400))
blue := color.RGBA{0, 0, 0, 255}
draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)
drawFern(m, 400, 400, 10000)
f, err := os.OpenFile("fern.png", os.O_CREATE | os.O_WRONLY, 0666)
if(err != nil) {
log.Fatal(err)
}
if err = png.Encode(f, m); err != nil {
log.Fatal(err)
}
fmt.Println("Done")
}
func drawFern(m *image.RGBA, x float32, y float32, steps int) {
if steps != 0 {
x, y = transform(x, y)
drawPoint(m, x, y)
drawFern(m, x, y, steps - 1)
}
}
func drawPoint(m *image.RGBA, x float32, y float32) {
b := m.Bounds()
height := float32(b.Max.Y)
width := float32(b.Max.X )
scale := float32(height / 11)
y = (height - 25) - (scale * y)
x = (width / 2) + (scale * x)
m.Set(int(x), int(y), color.RGBA{0, 255, 0, 255})
}
func transform(x float32, y float32) (float32, float32) {
rnd := rand.Intn(101)
switch {
case rnd == 1: x, y = transformPoint(x,y, 0.0, 0.0, 0.0, 0.16, 0.0)
case rnd <= 7: x, y = transformPoint(x,y, 0.2, -0.26, 0.23, 0.22, 0.0)
case rnd <= 14: x, y = transformPoint(x,y, -0.15, 0.28, 0.26, 0.24, 0.44)
case rnd <= 100: x, y = transformPoint(x,y, 0.85, 0.04, -0.04, 0.85, 1.6)
}
return x, y
}
func transformPoint(x, y, a, b, c ,d , s float32) (float32, float32) {
return ((a * x) + (b * y)), ((c * x) + (d * y) + s)
}

### Like this:

Like Loading...

*Related*

Pingback: A Scala Fractal | Olivier's Technology Blog

We have new QML bindings, you know…

Ha, I wrote this in 2012. I believe the QML Go binding project started a bit later 😉

You have it in the source but not mentioned in the blog: the probability of picking a particular transformation should be proportional to its determinant.This is just a fancy way of saying to pick the transforms that have a large effect more often than ones that have a small effect. This is not strictly necessary but it does help the algorithm explore the whole attractor more quickly.

It’s also worth saying that it can take a little while for the point you’re iterating to get onto the attractor in the first place. It helps if you discard the first 100 points or so just to make sure. I suspect that omission may be why you have those single points all up the right side of your image.

One more thing: why recursion instead of iteration in drawFern? Does go have tail call optimization in the language standard? If not then you’re in danger of blowing the stack on some implementations but not on others.

Recursion: It’s more a personal preference, but Go does not optimize for tail recursion 😦