
A Barnsley fern is a fractal named after British mathematician Michael Barnsley and can be created using an iterated function system (IFS).



Task

Create this fractal fern, using the following transformations:

 ƒ1   (chosen 1% of the time)
        xn + 1 = 0
        yn + 1 = 0.16 yn

 ƒ2   (chosen 85% of the time)
        xn + 1 = 0.85 xn + 0.04 yn
        yn + 1 = −0.04 xn + 0.85 yn + 1.6

 ƒ3   (chosen 7% of the time)
        xn + 1 = 0.2 xn − 0.26 yn
        yn + 1 = 0.23 xn + 0.22 yn + 1.6

 ƒ4   (chosen 7% of the time)
        xn + 1 = −0.15 xn + 0.28 yn
        yn + 1 = 0.26 xn + 0.24 yn + 0.44.

Starting position: x = 0, y = 0




import <Utilities/Math.sl>;
import <Utilities/Random.sl>;
 
transform(p(1), rand) := 
    let
        x := p[1]; y := p[2];
    in
        [0.0, 0.16*y] when rand <= 0.01
    else
        [0.85*x + 0.04*y, -0.04*x + 0.85*y + 1.6] when rand <= 0.86
    else
        [0.2*x - 0.26*y, 0.23*x + 0.22*y + 1.6] when rand <= 0.93
    else
        [-0.15*x + 0.28*y, 0.26*x + 0.24*y + 0.44];
 
barnsleyFern(rand, count, result(2)) :=
    let
        nextRand := getRandom(rand);
        next := transform(result[size(result)], nextRand.value / 2147483647.0);
    in
        result when count <= 0
    else
        barnsleyFern(nextRand.generator, count - 1, result ++ [next]);
 
scale(p(1), width, height) := [round((p[1] + 2.182) * width / 4.8378),
                               round((9.9983 - p[2]) * height / 9.9983)];
 
entry(seed, count, width, height) :=
    let
        fern := barnsleyFern(seedRandom(seed), count, [[0.0,0.0]]);
    in
        scale(fern, width, height);