Plotten van de Mandelbrot set

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Cranzai
  • Registratie: November 2012
  • Laatst online: 05-10 15:35
Dag Mede-Tweakers,

Sindskort ben ik de zoveelste dwaas die zichzelf verloren heeft in de wonderlijke wereld van de Mandelbrot set. Voor de hobby ben ik aan de slag gegaan met een html-canvas-javascript-projectje voor het plotten van deze set. Op internet staan vele voorbeelden echter wil ik graag een eigen draai aan het programma geven en mogelijk kan het zelfs simpeler. Met een beetje knutselen heb ik het volgende voor elkaar gekregen:

JavaScript:
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
60
61
62
63
64
65
66
67
function validate() {
    var maximum = document.getElementById('max').value;
    var escaperadius = document.getElementById('e_r').value;
    
    if (maximum < 10 || maximum > 1000) {
        document.getElementById('max').value = Math.min(Math.max(parseInt(maximum), 10), 1000);;
        window.alert("Insert a maximum value between 10 and 1000");
    }
    
    if (escaperadius <= 0 || escaperadius > 1000) {
        document.getElementById('e_r').value = Math.min(Math.max(parseInt(escaperadius), 1), 1000);;
        window.alert(" Value must be higher than 0 and not higher than 1000");
    }
    
    if (maximum >= 10 && maximum <= 1000 && escaperadius > 0 && escaperadius <= 1000) {
        draw(maximum, escaperadius);
    }
}

function draw(max, e_r) {
    //Initiate function timer
    var t0 = performance.now();
    
    //Do the actual drawing
    var canvas = document.getElementById('Mandelbrot-Canvas');
    if (canvas.getContext) {
        var context = canvas.getContext('2d');
        context.clearRect(0, 0, canvas.width, canvas.height);
        canvas.width = canvas.clientWidth;
        canvas.height = canvas.clientWidth * 0.5625;
        
        for (vertical = 0; vertical < canvas.height; vertical++) {
            for (horizontal = 0; horizontal < canvas.width; horizontal++) {
                
                //Conversion of the canvas size to a coordinate system with x = [-2;2] and y = [-2;2]
                var Cr = (horizontal - canvas.width / 2.0) * 4.0 / canvas.width;
                var Ci = (vertical - canvas.height / 2.0) * 4.0 / canvas.height;
                
                //Run the formula for the current pixel and determine colour
                //Z=a+bi
                var a=0, b=0;

                var iteration = 0;
                var modulus = 0;
                while(modulus < e_r && iteration < max){
                    //Z=Z^2+C
                    var a_new = a*a - b*b + Cr;
                    b = 2*a*b + Ci;
                    a = a_new;
                    
                    iteration ++;
                    modulus = Math.sqrt(a*a + b*b);
                }
                var mu = iteration - Math.log(Math.log(modulus)/Math.log(2.0));
                r = Math.floor(255*(mu/max));
                
                context.fillStyle = "rgb(" + r + ", 0, 0)";
                context.fillRect(horizontal, vertical, 1, 1);
            }
        }
        
    }
    
    //Stop function timer and log duration
    var t1 = performance.now();
    console.log("draw() with max=" + max + " took " + (t1 - t0) + " milliseconds");
}


De functie validate wordt getriggerd door een button op een website, vervolgens worden de escape radius en het maximale aantal iterations binnen gehaald van twee inputs. De rest legt zichzelf hopelijk grotendeels uit. Het grootste obstakel bij het schrijven van dit scriptje was voor mij gebrekkige wiskundige kennis, daarom heb ik dankbaar gebruik gemaakt van het volgende:

Theorie:
http://linas.org/art-gallery/escape/smooth.html
http://linas.org/art-gallery/escape/escape.html
Uitgewerkt voorbeeld:
tilde.club/~david/m/

Met het bovenstaande hoop ik jullie voldoende geïnformeerd te hebben om mij te kunnen helpen met het volgende:In eerste instantie bepaalde ik de kleur van elke pixel door simpelweg 255 te vermenigvuldigen met het aantal iteraties delen door het maximum. Toen ik de genoemde sites tegenkwam wilde ik echter overstappen op een logaritmische schaalverdeling (als ik de sites goed begrepen heb). Het idee van de dubbele log zoals uitgelegd in de linas.org pages heb ik geprobeerd toe te passen en dit is aardig gelukt.
Het probleem is echter dat deze code soms een NaN geeft wat leidt tot strepen in de afbeeldingen:

Afbeeldingslocatie: https://tweakers.net/ext/f/FprSptJOHVWzsxYvYiV3DsG1/medium.png
maximum = 85; escape-radius = 2;


Mijn gebrekkige kennis maakt dat ik niet begrijp hoe die NaN's ontstaan en ook niet hoe ik ze eruit zou moeten halen. Afgezien van de NaN's komen er ook wat negatieve getallen naar voren (getest met console.log()). Deze ontstaan vermoedelijk door het aftrekken van de dubbele log van het aantal iteraties maar gezien het idee van een colourmap lijken negatieve waardes mij niet gewenst. Daarnaast is het natuurlijk zo dat ik nog niet echt een logaritmische colourmap gebruik.

Kunnen jullie mij helpen met de NaN's en het implementeren van een daadwerkelijke logaritmische colourmap gebaseerd op de modulus?

Acties:
  • +1 Henk 'm!

  • superschotje
  • Registratie: Juni 2010
  • Laatst online: 18-04 15:18
Er gaat iets mis met dit stukje: Math.log(Math.log(modulus)/Math.log(2.0));

Math.log(modulus) geeft soms een negatieve waarde, en als je daar nog een keer Math.log op loslaat krijg je NaN. Je moet dus nog even kijken naar de berekening.

Acties:
  • 0 Henk 'm!

  • Cranzai
  • Registratie: November 2012
  • Laatst online: 05-10 15:35
superschotje schreef op zaterdag 11 maart 2017 @ 18:08:
Er gaat iets mis met dit stukje: Math.log(Math.log(modulus)/Math.log(2.0));

Math.log(modulus) geeft soms een negatieve waarde, en als je daar nog een keer Math.log op loslaat krijg je NaN. Je moet dus nog even kijken naar de berekening.
Ah, thnx. Stom van me deze wiskunde moet ik kennen :+
De strepen heb ik weg kunnen halen door een simpele aanpassing waarbij eerst gecheckt wordt of "modulus" wel groter is dan 1.

Het enige waar ik nu nog mee zit is de toepassing van een logaritmische kleurenschaal....