mario::konrad
programming / C++ / sailing / nerd stuff
Barnsley's Farn
© 2013-03-21 / Mario Konrad

Das Farn wird erzeugt durch eine affine Abbildung:

mit den folgenden Werten, wobei jeweils eine der vier Abbildungen zufällig ermittelt wird. Die Wahrscheinlichkeiten p für die entsprechende Abbildung ist ebenfalls angegeben.

Nummer p a b c d e f
1 1 % 0.0 0.0 0.0 0.16 0.0 0.0
2 85 % 0.85 0.04 -0.04 0.85 0.0 1.6
3 7 % 0.2 -0.26 0.23 0.22 0.0 1.6
4 7 % -0.15 0.28 0.26 0.24 0.0 0.44

Der Algorithmus zum Zeichnen des Fraktals sieht wie folgt aus:

  1. Startpunkt wählen (0,0)(0, 0)
  2. Zeichne Punkt
  3. Zufällige Wahl eine der Zeilen unter Berücksichtigung ihrer Wahrscheinlichkeit.
  4. Berechnung der Abbildung (x,y)(x', y')
  5. Setze die Abbildung als neuen Punkt (x,y)=(x,y)(x, y) = (x', y').
  6. Weiter mit Schritt 2

C++ Demo

Das Demo verwendet OpenGL um das Farn darzustellen. Der Code ist public domain, Verwendung auf eigene Gefahr.

Build

Kompilieren des Programms unter Linux

$ g++ -o barnsley-farn barnsley-farn.cpp -lGL -lGLU -lglut

Kompilieren des Programms unter Cygwin

$ g++ -o barnsley-farn barnsley-farn.cpp -lglut32 -lglu -lgl

HTML5 Canvas Demo

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// tranformation data
var BARNSLEY = [
    //   p     a     b      c     d     e    f
    [ 0.01,  0.0,  0.0,   0.0,  0.16, 0.0, 0.0  ],
    [ 0.85,  0.85, 0.04, -0.04, 0.85, 0.0, 1.6  ],
    [ 0.07,  0.2, -0.26,  0.23, 0.22, 0.0, 1.6  ],
    [ 0.07, -0.15, 0.28,  0.26, 0.24, 0.0, 0.44 ]
];

function choose_line()
{
    var p = Math.random();
    var p_sum = 0.0;
    for (var index = 0; index < BARNSLEY.length; ++index) {
        p_sum += BARNSLEY[index][0];
        if (p < p_sum) return index;
    }
    return 0;
}

function draw_canvas_barnsley()
{
    var canvas = document.getElementById("embed-barnsley");
    var context = canvas.getContext('2d');
    var output = context.createImageData(canvas.width, canvas.height);
    var data = output.data;

    // projection parameters
    var x_min = -5.0;
    var x_max =  5.0;
    var y_min = -2.0;
    var y_max = 12.0;

    var x_n = 0.0;
    var y_n = 0.0;
    for (var i = 0; i < 100000; ++i) {
        // draw current point
        var x = Math.round((x_n - x_min) / (x_max - x_min) * output.width);
        var y = output.height - Math.round((y_n - y_min) / (y_max - y_min) * output.height);
        data[(y*output.width + x)*4 + 0] = 0; // red
        data[(y*output.width + x)*4 + 1] = 0; // green
        data[(y*output.width + x)*4 + 2] = 0; // blue
        data[(y*output.width + x)*4 + 3] = 255; // alpha

        // calculate next
        var index = choose_line();
        var t = BARNSLEY[index];
        var x_n1 = t[1] * x_n + t[2] * y_n + t[5];
        var y_n1 = t[3] * x_n + t[4] * y_n + t[6];
        x_n = x_n1;
        y_n = y_n1;
    }
    context.putImageData(output, 0, 0);
}

window.onload = function()
{
    draw_canvas_barnsley();
}