Go Fern Fractal

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)
}

Advertisements

5 thoughts on “Go Fern Fractal

  1. Pingback: A Scala Fractal | Olivier's Technology Blog

  2. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s