The making of Fourier (04/2002, Dir 8)

In diesem Bereich befinden sich Artikel und Tutorials zum Thema Director.

Moderatoren: Bär, Admin

Antworten
Admin
Site Admin
Beiträge: 41344
Registriert: 07.02.2006, 2006 16:09
Wohnort: München
Kontaktdaten:

The making of Fourier (04/2002, Dir 8)

Beitrag von Admin » 11.02.2006, 2006 18:04

Visualisierung von mathematischen Zusammenhängen oder The making of Fourier

Einleitung

Als leidgeprüfter Mediensystem-Student, muss man sich im Verlauf des Studiums mit einer Menge Mathematik herumärgern. Aus der Not heraus, sich mit dem entsprechenden Stoff auseinandersetzen zu müssen entstand dieses Directorprojekt.

Der mathematische Hintergrund der Visualisierung soll hier aber nur eine untergeordnete Rolle spielen. Vielmehr möchte ich den Weg, von der Grundidee, über einzelne Problemlösungen innerhalb des Projektes, bis zum fertigen Programm beschreiben um so auch Nichtmathematikern (zu denen ich mich übrigens auch zähle) von meinen hierbei gewonnenen Erfahrungen profitieren zu lassen. So werde ich im Verlaufe dieser Beschreibung auf so grundlegende Themen wie repeat-Schleifen, Spritekomunikation, "vorsichtiger" Umgang mit Textmembern und Listen, Button-Funktionen bis hin zur Gestaltung einer entsprechenden grafischen Oberfläche zu sprechen kommen.

Ich werde versuchen, alle Gedankengänge und Probleme, die während der Erstellung des Movies aufkamen, nacheinander zu rekonstruieren, mit Scriptbeispielen zu erklären und Vor- und Nachteile einzelner Lösungen abzuwägen. Sollten hier und da Unklarheiten zu den benutzten Lingo - Befehlen bestehen, sollte zunächst die Director-Hilfe konsultiert werden.


Fourier ? (nur ganz kurz etwas Mathematik)

Vor langer Zeit entdeckte ein Mathematiker namens Fourier, dass man jede 2pi-periodische Funktion (z.B Sägezahn-Funktionen oder Rechteck-Funktionen), aus der Summe unendlich vieler Sinus- und Kosinusglieder nach folgender Vorschrift darstellen kann.

Bild

Umso mehr Glieder berechnet werden, umso stärker nähert sich das Bild dieser "Fourierreihe" der darzustellenden Funktion an. Die Anzahl der Glieder bestimmt das "n" welches von 1 bis unendlich gehen kann. Da der Sinus an der Stelle 0 gleich 0 ist,

Code: Alles auswählen

put sin(0.0)
-- 0.0000
gibt es kein b an der Stelle n = 0. a0 (a an der Stelle n = 0) hingegen spielt eine sehr wichtige Rolle, nämlich die Vertikale Position des Graphen (Y-Offset) und steht deshalb vor der Summe.

Die n’ten Glieder der Reihe werden durch einen von an und bn bestimmten Anteil auf die Funktion "moduliert" (überlagert), wodurch sich die einzelnen Glieder an einigen Stellen des Graphen addieren, an andern wiederum aufheben. So entstehen aus einfachen Sinus- und Kosinusgliedern alle erdenklich periodischen Funktionsbilder.

Wenn Sie das Ganze gerade nicht verstanden haben, machen Sie sich keine Sorgen. Sie müssen nur wissen, dass wir hier eine Funktion zeichnen wollen die von mehreren Variablen (an, bn, a0, n und x) abhängig ist, das ist alles.


Am Anfang...

...steht die Spielerei. Zunächst wollen wir versuchen ein ganz einfaches Funktionsbild auf die Bühne zu zaubern, um zu sehen, wie sich Director bei solchen Aufgaben verhält. Nehmen wir zu Begin eine einfache Quadratische Funktion: " y = x² " die jeder aus seiner Schulzeit kennt.

Zwei Hürden gibt es zunächst zu meistern:

1. Der Punkt (0,0) ist nicht in der Mitte der Bühne, sondern links, oben in der Ecke.

2. Würden wir die Resultierenden Werte für y einfach so darstellen, bekämen wir nicht sehr viel zusehen, da sie ja den Pixeln auf der Bühne entsprechen, es wird also alles viel zu klein.

Beide Probleme werden wir in Kürze lösen, zunächst bereiten wir alles für unseren Director-Film vor:

a.) Erstellen Sie eine Bitmap von der Größe 1x1 Pixel, nennen Sie dieses „sprite_dot“ und importieren Sie es in die Besetzung. Damit wird später unseren Graphen gezeichnet.

b.) Stellen Sie die Abmessung der Bühne auf 400x400 Pixel ein.

c.) Ziehen sie nun das Bitmap "sprite_dot" aus der Besetzung auf die Bühne und aktivieren Sie im Property Inspector die Trails-Funktion.

Nun kommt das Behavior zum Zeichnen des Funktionsbildes das wir auf den Sprite legen. Zum schnellen berechnen der Funktionswerte und der Positionierung des Sprites, bietet sich eine repeat-Schleife an, die wir beispielsweise von -2 bis 2 laufen lassen. Zwischendurch aktualisieren wir die Bühne mit updatestage.

Vorsicht: Verwenden wir später die repeat-Schleife für größere Operationen, kann es sehr lang dauern bis diese Abgeschlossen ist. Wird der Director-Film als Schockwave im Browser abgespielt, steht dieser wie bei einem Absturz und kann nicht beendet werden, solang die Schleife nicht durchlaufen ist. Die Lösung wäre hier, eine Tastaturabfrage in die Schleife einzubauen

Code: Alles auswählen

if the keyPressed = RETURN then exit
was jedoch gerade bei häufigerem Durchlaufen der Schleife zu starken Verzögerungen führt.

Das Script könnte so aussehen:

Code: Alles auswählen

-- Script 01, Behavior: "script_Dot"

on enterSprite me

  repeat with counter = -2 to 2

    myX = counter.float

    myy = myX*myX

    sprite(me.spritenum).loc = point(myX,myY)

    updatestage

  end repeat

end enterSprite
Wie erwartet ist beim Abspielen des Movies nicht wirklich etwas zu sehen, was uns wieder auf die schon oben erkannten Probleme bringt. Als erstes bringen wir den Graphen in die Mitte der Bühne, in dem wir jeweils ein Offset auf x und y addieren, z.B: myOffset = point(200, 200). Da auf der Bühne die Y-Koordinaten (.locV) nach unten größer werden (anstatt nach oben), müssen wir das Funktionsbild noch um die x-Achse spiegeln ((-1)*myY ).

Das zweite Problem lösen wir, indem wir den Graphen um den Faktor 100 aufblasen. 100 Pixel auf der Bühne entsprechen dann also dem Wert 1 der Berechnung. Das Script sieht nun so aus:

Code: Alles auswählen

-- Script 02, Behavior: "script_Dot"

property myOffset

on beginSprite me

  myOffset = point(200, 200)

end beginSprite


on enterFrame me

  repeat with counter = -2*100 to 2*100

    myX = counter.float/100.00   

    myy = myX*myX -- Quadratische Funktion

    sprite(me.spritenum).loc = point(myX*100+myOffset[1],(-1)*myY*100+myOffset[2])

    updatestage

  end repeat

end enterFrame

Lassen Sie uns nun etwas herumprobieren. Wir haben hier ein universelles Grundgerüst geschrieben, mit dem man etliche Funktionen zeichnen kann. Man muss nur die Formel myY = myX*myX gegen eine andere austauschen. Hier einige Beispiele:

Code: Alles auswählen

myy = myX             -- Lineare Funktion
myy = sin(myX)        -- Sinus Funktion
myy = sin(myX*4)      -- Sinus Funktion mit geviertelter Periodendauer
myy = cos(myX)        -- Kosinus Funktion
myy = tan(myX*2)      -- Tangens Funktion mit halbierter Periodendauer

myy = sin(myX) + 1/2.00*sin(2*myX) + 1/3.00*sin(3*myX) + 1/4.00*sin(4*myX)
-- Fourier-Reihe für eine Sägezahn Funktion bis zum vierten Glied (n = 1 bis 4)
-- Sicher können Sie weitere Glieder anhängen z.B 1/5.00*sin(5*myX)...

Beim herumprobieren sind Sie vielleicht auch auf ein weiteres Problem unseres Behaviors aufmerksam geworden. Bei größeren Abständen der y-Werte ist der Graph nicht mehr gleichmäßig durchgezeichnet, sondern löst sich in einzelne Punkte auf, zum Beispiel bei der Tangens Funktion. Es empfiehlt sich also, noch einen Faktor für die Auflösung des Graphen mit ins Spiel zu bringen: precision = 1.00. Schön wäre es noch wenn wir die Zeit, die die Schleife braucht, um durchzulaufen, messen könnten.

Implementieren wir beide Ideen sieht das Script nun folgendermaßen aus:

Code: Alles auswählen

-- Script 03, Behavior: "script_Dot"

property myOffset, precision

on beginSprite me

  myOffset = point(200, 200)

  precision = 1.00

end beginSprite


on enterFrame me

  myStartTime = the milliseconds

  repeat with counter = -2*100*precision to 2*100*precision

    myX = counter.float/100.00/precision

    myy = myX*myX -- Quadratische Funktion

    sprite(me.spritenum).loc = point(myX*100+myOffset[1],(-1)*myY*100+myOffset[2])

    updatestage

  end repeat

  put (the milliseconds - myStartTime)

end enterFrame
Achten Sie darauf, dass Sie Divisoren sicherheitshalber immer als #Float angeben, auch wenn die Dezimalstellen 0 sind. Erhöhen wir nun diesen Wert auf 2.00, verdoppelt sich die Anzahl der zu zeichnenden Punkte auf der selben Strecke der Bühne, bei 0.50 haben wir nur noch die Hälfte der Punkte.

Es gibt jedoch noch weitere, mehr oder weniger effektive Möglichkeiten das "zerkrümeln" des Graphen zu verhindern. Betrachten wir einmal die Funktion myy = 0.5*tan(myX*5). Da das Bild sehr gestreckt ist, stehen nur sehr wenige Punkte pro horizontaler Strecke zur Verfügung. Um die Lücken vollständig zu schließen, müssen wir precision auf etwa 35 stellen, was die Zahl der Schleifendurchläufe auf 7000 ansteigen lässt. Es gilt also die Lücken zwischen den einzelnen Punkten zu schließen ohne den Rechenaufwand so extrem anwachsen zu lassen .

Eine Möglichkeit wäre, sich die Position des Sprites vom letzten Durchlaufe zu merken und mit der des Neuen zu vergleichen. Ist der vertikale Abstand der beiden Punkte größer als 1, verwenden wir den Imaging Lingobefehl draw um die Lücke zwischen den Punkten zu schließen. Implementieren wir diesen Befehl, sieht unser Script so aus:

Code: Alles auswählen

-- Script 04, Behavior: "script_Dot"

property myOffset, precision, myOldLoc

on beginSprite me

  myOffset = point(200, 200)

  precision = 1.00

  myOldLoc = sprite(me.spritenum).loc

end beginSprite


on enterFrame me

  myStarttime = the milliseconds

  repeat with counter = -2*100*precision to 2*100*precision

    myX = counter.float/100.00/precision

    myy = 0.5*tan(myX*5) -- Tangens Funktion

    sprite(me.spritenum).loc = point(myX*100+myOffset[1],(-1)*myY*100+myOffset[2])

     -- Lücken schließen

    if abs(sprite(me.spritenum).locV - myOldLoc[2]) > 1 then 

      member("bg_Skalierung").image.draw(sprite(me.spritenum).loc, myOldLoc,\

                             [#color: rgb(0, 255, 0), #linesize:1])  

    end if

    myOldLoc = sprite(me.spritenum).loc

    updatestage

  end repeat

  put (the milliseconds - myStarttime)

end enterFrame
Doch schon beim Beispiel Tangens Funktion zeigt sich ein großer Nachteil dieser Methode. Der Sprung im Graphen wird durch unsere Implementierung durchgezeichnet, was schlicht mathematisch falsch ist. Dieser Fehler würde bei allen Sprungfunktionen (unstetige Funktionen) auftreten und ist deshalb für unsere Aufgabe ungeeignet. Auch wird der Member des Hintergrundbildes bemalt, wir müssten ihn also vor jeder Zeichnung durch eine Kopie des Orginalbildes ersetzten.

Eine weiter, weitaus aufwändigere Möglichkeit wäre, den Wert precision dynamisch der Zeichnung anzupassen. Ist der vertikale Abstand zweier Punkte größer als 1, springen wir eine X-Position zurück und erhöhen diesen Wert solange, bis der Graph geschlossen ist. Die Routine dafür ist jedoch wie schon erwähnt relativ aufwändig und Rechenintensiv. Für die bloße Zeichnung eines Graphen ist diese Methode meines Erachtens etwas zu viel Arbeit. Würde mal die Berechnung von Fraktalen, wie zum Beispiel eines Apfelmännchens (nach Mandelbrot), als Aufgabe stehen, sollten wir noch einmal über diese Möglichkeit nachdenken.


Grundlagen (noch mal ein bisschen Mathe)

Nachdem wir uns ausreichend mit dem Plotten von Funktionsbildern beschäftigt haben, wollen wir nun das Ganze auf die Darstellung von Fourierreihen anwenden. Wie schon anfangs erwähnt, bestehen Fourierreihen, wie der Name „Reihe“ schon sagt, nicht nur aus einer einzigen Funktion, sondern aus der anteiligen Addition vieler gleichartiger Funktionen. Der grundlegende Aufbau der einzelnen Glieder ist durch die Bildungsvorschrift gegeben, sie unterscheiden sich jedoch in der Stärke, mit der sie auf das Funktionsbild einwirken. Geregelt wird dies durch das jeweiligen Faktoren an und bn (auch ak und bk wie unten in den Formeln), für die es ebenfalls Bildungsvorschriften gibt.

Bild

Bild

Durch Berechnung der Integrale für an und bn erhalten wir allgemeine Formeln mit denen wir a bzw. b für jede Stelle n berechnen können. Wie das im Einzelnen funktioniert (ich könnte jetzt Bände über Integrationsregeln, Substitution, partieller Integration usw. schreiben) möchte ich hier, im Interesse des allgemeinen Wohlbefindens auslassen und bevor uns allen richtig schlecht wird, zu einem Beispiel übergehen.

Nach einer wilden Rechenorgie bekommen wir für bn (oder eben bk) zum Beispiel den Wert "1/n" heraus, für an den Wert 0. Schauen wir uns jetzt die Bildungsvorschrift für die Fourierreihe an, erkennt wir, dass unsere hier vorliegende Fourierreihe nur aus Sinusgliedern besteht. Man nennt solche Funktionen auch "ungerade". Würde man also die Funktion um den Punkt (0,0), um 180 Grad drehen, erhielten wir wieder die Ausgangsfunktion (f(x) = -f(-x)). Die Sinusfunktion ist beispielsweise eine ungerade Funktion.

Bild

Setzen man nun unser gewonnenes bn in die Fourierreihe ein, erhält man folgende Formel:

f(x) = a0/2+summe(1/n*sin(nx)).

Ganz am Anfang habe ich schon erwähnt, dass a0 den Y-Offset des Bildes regelt, wir setzen a0 deshalb der Einfachheit halber auf 0: f(x) = ∑(1/n*sin(nx)). Vielleicht erkennen Sie schon, dass diese Reihe uns schon im Script02 als Beispiel diente. Es handelt sich (für n = 1 bis unendlich) um eine Sägezahnfunktion.


repeat the repeat

Nun zur Implementation dieser Reihe in unser Behavior. Wir haben bisher für jedes x genau ein y berechnet. Dies machen wir im Prinzip auch weiterhin, nur setzt sich das y nun aus einer von n bestimmten Anzahl von Gliedern der Formel zusammen, die wir einfach addieren. Im Script fügen wir deshalb eine weitere Schleife ein, welche die einzelnen Glieder summiert. Eine Variable n wird zusätzlich definiert, die die Anzahl der zu berechnenden Glieder bestimmt. Die Bühne und der zu berechnende Bereich wird etwas erweitert, damit man auch sieht was passiert.

Code: Alles auswählen

-- Script 05, Behavior: "script_Dot"

property myOffset, precision, n

on beginSprite me

  myOffset = point(300, 200)

  precision = 1.00

  n = 1

end beginSprite

 
on enterFrame me

  myStarttime = the milliseconds

  repeat with counter = -3*100*precision to 3*100*precision

    myX = counter.float/100.00/precision

    -- Innere Schleife zum Addieren der Glieder

    myY = 0

    repeat with myN = 1 to n

      myN = myN.float

      myY = myY + 1/myN*sin(myN*myX) -- Summierung der Glieder

    end repeat

        

    sprite(me.spritenum).loc = point(myX*100+myOffset[1],\

                                    (-1)*myY*100+myOffset[2])

    updatestage

  end repeat

  put (the milliseconds - myStarttime)

end enterFrame
Starten wir nun den Film zeichnet uns das Behavior eine ganz normale Sinusfunktion. Da n = 1 ist, wird auch nur ein Glied der Reihe berechnet: f(x) = 1/1*sin(1*x), was nun mal einer ganz normale Sinusfunktion entspricht. Erhöhen wir nun aber das n, verändert sich der Graph sichtbar zu einer Sägezahnfunktion. Für n = 3 sieht die Funktion schon so aus: f(x) = 1/1*sin(1*x)+ 1/2*sin(2*x)+ 1/3*sin(3*x). Wird die Kurve dabei zu bröselig, erhöhen wir einfach zusätzlich noch den Wert für precision.

Für die Werte precision = 50.00 und n = 70 erhalten wir dabei schon ein sehr ansehnliches Bild. Man sieht sehr schön, wie der Graph vor größeren Amplitudenänderungen ausbricht.

Allerdings zeigt sich schon bei dieser, eher einfachen Berechnung, dass Lingo als untypisierte Skriptsprache an seine Leistungsgrenzen stößt. Für die oben genannten Werte braucht ein Athlon 1.4 Ghz geschlagene 7.079 Sekunden, weshalb man für die kommerzielle Verwendung solcher Berechnungen, die Programmierung eines Xtras in Erwägung ziehen sollte.

Wir wollen uns jedoch von dieser kleinen Performanceschlappe nicht einschüchtern lassen und weitermachen.

Sehr wirksame Optimierungstechniken für Schleifen finden sich auch im Buch "Lingo objektorientiert" von Martin Kloss auf Seite 281 „unrolled loops“. Wir werden diese Techniken in späteren Implementationen einsetzen.


Einer für alles

Bis jetzt haben wir die für die Berechnung nötigen Parameter immer nur direkt im Source manipuliert. Was uns fehlt ist ein Interface, über das wir die Parameter setzen können. Auch war für mich von Anfang der Entwicklung an klar, dass das Programm nicht nur eine, sondern jede beliebige Fourierreihe darstellen können muss. Das Implementieren von Felddarstellern, in die man die Werte für n, a0 oder precision eingeben kann, sollte kein Problem darstellen. Die Variablen müssen dann nur vor der Berechnung an das Behavior übergeben werden.

Schnell zur Funktionsweise der Buttons für N, Xscale, Yscale, myInvert, aNull und Precision (script_Buttons.html). Ich habe weitestgehend auf Globals verzichtet, da dies rein optisch mit der Zeit zu unübersichtlich wurde. Jedem Button wird ein Textmember zugewiesen, den es aktuell zu halten gilt. Bei beginSprite schickt das Behavior mit der Zeile

Code: Alles auswählen

call #TakeValues, sprite(2), this, myTask, myValue, myTextmember
vorher eingestellte Werte aus der PropertyDescriptionList an das Plott-Behavior. myTask beinhaltet die Funktion des Buttons als String, myValue den Zahlenwert als Float und myTextmember den Textmember (!) des Buttons. Beim mouseDown auf einen Button wird geschaut ob dieser rechts oder links von der Mitte stattgefunden hat. Das spart Spritekanäle gegenüber der Verwendung zweier Member für Plus und Minus. Entsprechend wird der Member des Sprites ausgetauscht und der Wert myklick = 1 oder myklick = -1 für das Hoch- oder Runterzählen bei gedrückter Mouse gesetzt. Erfolg ein mouseUp bzw. ein mouseUpOutside, werden die aktualisierten Werte wieder per call verschickt.

Der Empfangs-Handler #TakeValues, schreibt die bekommenen Werte, abhängig von myTask, in das jeweilige Property des Plott-Behaviors.

Code: Alles auswählen

-- Script 06

-- Werte von Buttons Empfangen und Umsetzen

on TakeValues(thisSprite, theCaller, myTask, myValue, myTextmember)

  case myTask of

    "Xscale" :

      Xscale = myValue

    "Yscale" :

      Yscale = myValue*100.00

    "myInvert" :

      myInvert = myValue

    "Strength" :

      this.width = myValue

      this.height = myValue

    "N" :

      N = myValue.integer 

    "aNull" :

      aNull = myValue

    "Precision" :

      -- Auflösung abhägig von n und der gesetzten Auflösung

      Precision = (N/2.00)*myValue 

  end case

end TakeValues
Viel mehr Kopfzerbrechen bereitete mir die Verwaltung der Werte für an und bn. Das Programm sollte auf Wunsch, die Reihen bis zur Genauigkeit von n = 99 berechnen können, was heißt es gibt 99 an’s und 99 bn’s die irgendwo herkommen müssen. Der einfachste Weg wäre sicher gewesen, die innere Schleife durch vorgefertigte Bildungsvorschriften (presents) austauschbar zu gestalten. Somit hätte man aber z.B. den an-Wert an der Stelle n = 50 nicht manipulieren können. Ziel war es doch aber, nicht nur etwas vorgefertigtes Zeichnen zu lassen, sondern eben jede Reihe.

Natürlich kommen in Director für die Speicherung solcher Variablenmengen nur Listen in Frage. So besteht die hier verwendete globale Liste myNth = [] aus 198 Werten. Dabei sollen die ungeraden Stellen der Liste (myNth[i*2-1]) die an-Werte und die geraden (myNth[i*2]) die bn-Werte speichern. Die Liste für die oben fest implementierte Reihe für bn = 1/n, würde also beispielsweise so aussehen:

Code: Alles auswählen

myNth = [0.0000, 1.0000, 0.0000, 0.5000, 0.0000, 0.3333, 0.0000, 0.2500, 0.0000, 0.2000, 0.0000, 0.1667, 0.0000, 0.1429, 0.0000, 0.1250, 0.0000, 0.1111, 0.0000, 0.1000, 0.0000, 0.0909, 0.0000, 0.0833, 0.0000, 0.0769, 0.0000, 0.0714, 0.0000, 0.0667, 0.0000, 0.0625, 0.0000, 0.0588, 0.0000, 0.0556, 0.0000, 0.0526, 0.0000, 0.0500, 0.0000, 0.0476, 0.0000, 0.0455, 0.0000, 0.0435, 0.0000, 0.0417, 0.0000, 0.0400, 0.0000, 0.0385, 0.0000, 0.0370, 0.0000, 0.0357, 0.0000, 0.0345, 0.0000, 0.0333, 0.0000, 0.0323, 0.0000, 0.0313, 0.0000, 0.0303, 0.0000, 0.0294, 0.0000, 0.0286, 0.0000, 0.0278, 0.0000, 0.0270, 0.0000, 0.0263, 0.0000, 0.0256, 0.0000, 0.0250, 0.0000, 0.0244, 0.0000, 0.0238, 0.0000, 0.0233, 0.0000, 0.0227, 0.0000, 0.0222, 0.0000, 0.0217, 0.0000, 0.0213, 0.0000, 0.0208, 0.0000, 0.0204, 0.0000, 0.0200, 0.0000, 0.0196, 0.0000, 0.0192, 0.0000, 0.0189, 0.0000, 0.0185, 0.0000, 0.0182, 0.0000, 0.0179, 0.0000, 0.0175, 0.0000, 0.0172, 0.0000, 0.0169, 0.0000, 0.0167, 0.0000, 0.0164, 0.0000, 0.0161, 0.0000, 0.0159, 0.0000, 0.0156, 0.0000, 0.0154, 0.0000, 0.0152, 0.0000, 0.0149, 0.0000, 0.0147, 0.0000, 0.0145, 0.0000, 0.0143, 0.0000, 0.0141, 0.0000, 0.0139, 0.0000, 0.0137, 0.0000, 0.0135, 0.0000, 0.0133, 0.0000, 0.0132, 0.0000, 0.0130, 0.0000, 0.0128, 0.0000, 0.0127, 0.0000, 0.0125, 0.0000, 0.0123, 0.0000, 0.0122, 0.0000, 0.0120, 0.0000, 0.0119, 0.0000, 0.0118, 0.0000, 0.0116, 0.0000, 0.0115, 0.0000, 0.0114, 0.0000, 0.0112, 0.0000, 0.0111, 0.0000, 0.0110, 0.0000, 0.0109, 0.0000, 0.0108, 0.0000, 0.0106, 0.0000, 0.0105, 0.0000, 0.0104, 0.0000, 0.0103, 0.0000, 0.0102, 0.0000, 0.0101]

Ich hatte mir in den Kopf gesetzt, für das Setzten der beiden Werte an und bn, Buttons zu verwenden. Die schon fertigen Plus- und Minusschalter für die anderen Werte kamen dafür nicht in Frage, da der abzudeckende Zahleninterfall und die Genauigkeit der Werte darin, einfach zu groß waren. Würde man beispielsweise den Wert von 0.0000 auf 2.0000 stellen wollen, würde es bei 30 fps 66 Sekunden dauern diesen Wert zu erreichen.

Die eingesetzten Drag-Buttons (Fourier_Script_07.dir) bieten zwar keine Exaktheit bis zur letzten Stelle nach dem Komma, sind aber für unsere Zwecke ausreichend. Die Bedienung ist nicht ganz intuitiv, eine bei mousedown eingeblendete Skala würde da aber schon Abhilfe schaffen. Auf ein größeres Problem verwies mich ein Studienkollege. Er konnte die Werte zwischen -0.2500 und -0.7500 nicht einstellen. Nach längerem hin und her bekam ich dann mit, dass er seinen Bildschirm nur mit 800x600 betrieb. Das Projekt war für die Zielgruppe „Mediensystemer“ gedacht, ich hätte nie gedacht, dass es unter ihnen jemanden gab, der so niedrige Auflösungen fährt. Da er der einzige war, bei dem dieses Problem bestand, verzichtete ich auf eine Nachbesserung, die hier ja auf Kosten der Genauigkeit gegangen wäre.

Hier zeigt sich jedoch die große Schwäche dieser Lösung. Je genauer der Interfall bestimmbar gemacht werden soll, umso größer ist der Bereich, den die Mouse benötigt. Deshalb ist es sehr wichtig zu wissen, wie hoch die Bildschirmauflösung des Anwenders ist und wo sich die Buttons auf der Bühne befinden.

Für größere Zahleninterfalle sind scheinbar Feld- oder Textdarsteller unumgänglich, hier hat aber meine Sturheit (die auch im Design begründet war) die Oberhand behalten was mit (bei professionellen / kommerziellen Projekten) unakzeptablen Kompromissen bezahlt wurde.

Beispielfilm als Download: upload/Fourier.zip


Autor: Felix Weißig

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste