Zusammenhänge mit callback unklar

BAGZZlash

Moderator
Teammitglied
...und hier gleich noch ein zweiter Thread zu der Fluidsimulation. Verdammt, die Navier-Stokes-Gleichungen und das Gauß-Seidel-Verfahren zum Lösen nichtlinearer Differentialgleichungssysteme zu verstehen, bereitet mir schon genug Kopfzerbrechen. Die JavaScript-Quirks sind mir da gerade wirklich ein Bisschen zuviel, sorry. :sneaky: Schon dieses Rumgeturne mit var i0 = x | 0;. Bis ich da mal drauf gekommen bin, was das macht... Und welchen Datentyp i0 da hat, darf man auch schön raten. Naja, egal, genug Dampf abgelassen.

Ich verstehe hier die Zusammenhänge nicht: update erzeugt einen neuen Frame der Animation, ja? Da drin wird als erstes eine Funktion queryUI aufgerufen. Diese Funktion setzt alle Werte der drei übergebenen Arrays auf 0. Wenn ich das bei meiner Portierung mache, sieht man keine Animation, weil ja die Werte vom Frame davor wichtig sind für den neuen Frame, warum sollte man das alles löschen?

Als nächstes wird dann noch uiCallback aufgerufen. Schaut man oben, scheint diese Funktion genau nichts zu machen. Außerdem erwartet sie drei Parameter, warum wird sie dann also mit dem Argument new Field(dens, u, v) aufgerufen? Okay, Field ist eine Funktion, die diese drei Parameter erwartet. Also erzeugt new... Was, irgendwie eine neue Instanz davon, wie bei einer Klasse?

In update werden dann vel_step und dens_step aufgerufen, okay, kein Problem. Anschließend dann die Funktion displayFunc. displayFunc ist weiter unten aber auch eine Variable (innerhalb desselben Scope, oder?), außerdem wird displayFunc in der Funktion setDisplayFunction der Wert func zugewiesen. Aufgerufen wird setDisplayFunction durch einen Button in der html-Datei, dort wird der Zeichenmodus umgeschaltet. Okay, das will ich zwar später auch haben, ist aber für's bloße Funktionieren momentan erstmal nicht so wichtig.

Javascript:
    var uiCallback = function(d,u,v) {};

    function Field(dens, u, v) {
        // Just exposing the fields here rather than using accessors is a measurable win during display (maybe 5%)
        // but makes the code ugly.
        this.setDensity = function(x, y, d) {
             dens[(x + 1) + (y + 1) * rowSize] = d;
        }
        this.getDensity = function(x, y) {
             return dens[(x + 1) + (y + 1) * rowSize];
        }
        this.setVelocity = function(x, y, xv, yv) {
             u[(x + 1) + (y + 1) * rowSize] = xv;
             v[(x + 1) + (y + 1) * rowSize] = yv;
        }
        this.getXVelocity = function(x, y) {
             return u[(x + 1) + (y + 1) * rowSize];
        }
        this.getYVelocity = function(x, y) {
             return v[(x + 1) + (y + 1) * rowSize];
        }
        this.width = function() { return width; }
        this.height = function() { return height; }
    }
    function queryUI(d, u, v)
    {
        for (var i = 0; i < size; i++)
        {
            d[i] = 0.0;
            v[i] = 0.0;
            u[i] = 0.0;
        }
        uiCallback(new Field(d, u, v));
    }

    this.update = function () {
        queryUI(dens_prev, u_prev, v_prev);
        vel_step(u, v, u_prev, v_prev, dt);
        dens_step(dens, dens_prev, u, v, dt);
        displayFunc(new Field(dens, u, v));
    }
    this.setDisplayFunction = function(func) {
        displayFunc = func;
    }
 
    this.iterations = function() { return iterations; }
    this.setIterations = function(iters) {
        if (iters > 0 && iters <= 100)
           iterations = iters;
    }
    this.setUICallback = function(callback) {
        uiCallback = callback;
    }
    var iterations = 10;
    var visc = 0.5;
    var dt = 0.1;
    var dens;
    var dens_prev;
    var u;
    var u_prev;
    var v;
    var v_prev;
    var width;
    var height;
    var rowSize;
    var size;
    var displayFunc;
 
Bei OOP mit JavaScript bin ich auch raus. Aber such mal im Rest des Codes nach einem Aufruf von setUICallback. Dort sollte dann dieses nichts machende Default mit einer sinnvollen Funktion ersetzt werden.
 
Ja, stimmt. Die Funktion lautet

Javascript:
this.setUICallback = function(callback)
{
        uiCallback = callback;
}

Aufgerufen wird die durch JS-Code, der in der index.html steht, und zwar bei window.onload:

Javascript:
field.setUICallback(prepareFrame);

prepareFrame ist eine Funktion (ebenfalls in der index.html), die im Wesentlichen die Nutzereingaben verarbeitet und beim Mausklicken und -ziehen dafür sorgt, das was passiert. Okay, also hier mal etwas "rubber duck debugging" (diesen Ausdruck habe ich bei dev-community gelernt :)):

1.) Der Nutzer geht auf die Webseite, bei onload wird setUICallback(prepareFrame) gerufen. Wie der Name suggeriert, scheint das eine Callback-Funktion zu sein, die das Betriebssystem (bzw. der Browser?) immer von sich aus aufruft, wenn der User was macht, den Parameter kann ich mir so ähnlich wie einen Funktionspointer vorstellen, der Callback-Funktion wird also gesagt, welche weitere Funktion sie callen soll.
2.) Am Ende des JS-Teils der index.html wird startAnimation() aufgerufen. Diese Funktion prüft und setzt eine globale boolsche Variable running und ruft dann mit Timeout die Funktion updateFrame.
3.) updateFrame ruft im Wesentlichen field.update() auf.
4.) update() macht zuerst dieses queryUI, das die Werte in den Arrays auf 0 setzt. Beim ersten Durchlauf habe ich dafür ja auch vollstes Verständnis.
5.) update() macht als nächstes die ganze Voodoo-Magic, die hier nicht das eigentliche Problem darstellt.
6.) Zum Schluss ruft update() dann noch displayFunc(new Field(dens, u, v));. Das ist ein merkwürdiges Konstrukt wieder mit Funktionspointer und new, stellt aber letzten Endes nur den Drawmode ein. Wird hier auch das Zeichnen des Frames angestoßen? Das ganze canvas-Zeug steht in der pressure-display.js. Den Code da finde ich nicht so schwer zu verstehen, im Wesentlichen wird das RGB-Feld weggeschrieben, das mache ich in VB genauso.

Danach ist update() zu Ende, damit auch startAnimation(). Ich kann nicht erkennen, wo hier überhaupt der Loop beginnt. Oder wird das alles über die Callback-Funktion gesteuert? Feuert der Browser immer dann die Callback-Funktion, wenn er "fertig" ist (z.B. damit, das canvas vollzuzeichnen), sodass automatisch ein neuer Frame berechnet wird? Aber warum dann nochmal der manuelle Aufruf von uiCallback durch queryUI, wiederum durch update?
 
Zurück
Oben Unten