WaBis

walter.bislins.ch

JavaScript: Annähernd lineare Sweep-Funktion

Montag, 4. Mai 2015 - 22:41 | Autor: wabis | Themen: Wissen, Mathematik, Programmierung, Animation
Sweep-Funktionen können in Animationen verwendet werden, um einen linearen Zeit-Parameter in eine bestimmte Bewegung umzuwandeln, so dass zum Beispiel ein Animations-Objekt langsam beschleunigt, eine maximale Geschwindigkeit erreicht und dann bei einem genau definierten Punkt auf 0 abbremst.

Es gibt unendlich viele solche Sweep-Funktionen. Hier leite ich eine Sweep-Funktion her, die möglichst lange einen linearen Verlauf hat, aber am Anfang weich beschleunigt und am Ende weich verzögert.

Eigenschaften einer Sweep-Funktion

Um eine Sweep-Funktion universal einsetzen zu können, wird sie so definiert, dass der Definitions-Bereich zwischen 0 und 1 in einen Werte-Bereich zwischen 0 und 1 abgebildet wird, sodass also f(0) = 0 und f(1) = 1 ist. Mit folgender Formel kann jederzeit ein beliebiger Zeitabschnitt in einen beliebigen Wegabschnitt transformiert werden, sodass immer dieselbe Sweep-Funktion verwendet werden kann:

(1)
x = \color{blue}{ x_\mathrm{min} + (x_\mathrm{max} - x_\mathrm{min}) } \cdot f( \color{green}{ (t - t_\mathrm{min}) / (t_\mathrm{max} - t_\mathrm{min}) } )
wobei'
f(t) ' =' 'Sweep-Funktion
x ' =' 'Wegabschnitt zwischen xmin und xmax
t ' =' 'Zeitabschnitt zwischen tmin und tmax

Der grüne Teil der Formel transformiert einen Zeitabschnitt von tmin bis tmax in einen Wertebereich zwischen 0 und 1, wie er von der Sweep-Funktion erwartet wird. Die Sweep-Funktion liefert ihrerseits einen Wert zwischen 0 und 1. Mit dem blauen Teil der Formel wird dieser in einen Wegbereich zwischen xmin und xmax transformiert.

Anwendungsbeispiel Cosinus-Sweep

Zur Demonstration einer Sweep-Funktion nehme ich folgende einfache Formel und erstelle damit eine Animation. Die Grafik zur Formel ist rechts abgebildet.

(2)
f(t) = 0{,}5 - 0{,}5 \cdot \cos( \pi \cdot t )

Die Animation starte bei tmin = 0 s und ende bei tmax = 3 s. In dieser Zeit soll ein Objekt eine Strecke auf dem Bildschirm von xmin = 50 px bis xmax = 450 px zurücklegen. Mit der Formel (2) sieht der Bewegungsablauf folgendermassen aus:

Geschwindigkeitsfunktion

Für ein Panorama-Plugin, welches ein Panoramabild in einem Fenster langsam hin und her schwenkt, suche ich eine Sweep-Funktion, welche in einem weiten Bereich möglichst linear verläuft, jedoch am Umkehrpunkt, also am Anfang und am Ende der Sweep-Funktion, langsam abbremst.

Die Graphik einer solchen Funktion ähnelt jener der Cosinus-Funktion oben, ist jedoch nur ganz am Anfang und am Ende abgerundet und dazwischen praktisch eine Gerade. Die Steigung der Sweep-Funktion muss bei t = 0 und bei t = 1 horizontal sein, damit ein Umkehren der Bewegung ohne Sprung erfolgt.

Um eine solche Sweep-Funktion zu entwickeln, beginne ich bei der Betrachtung des Geschwindigkeitsverlaufs. Der Geschwindigkeitsverlauf hat folgende Eigenschaften:

  • Geschwindigkeit ist bei t = 0 und bei t = 1 gleich Null
  • Geschwindigkeit ist dazwischen möglichst lange praktisch konstant

Wenn ich eine Funktion y = v(t) gefunden habe, welche diese Eigenschaften erfüllt, kann ich durch Integrieren der Funktion die entsprechende Sweep-Funktion y = f(t) erhalten. Die t-Achse entspricht in der Grafik der x-Achse. Ich verwende ab jetzt die Variable x anstelle von t.

Die Sweep-Funktion ist in beiden Achsen symmetrisch, wobei die Symmetrieachsen durch den Punkt (0,5, 0,5) laufen. Für die Herleitung der Sweepfunktion ist es einfacher, wenn ich zunächst die X- und Y-Achse als Symmetrieachsen verwende und die gefundene Sweepfunktion erst danach in den gewünschten Bereich transformiere.

Ich suche also zunächst eine Geschwindigkeitsfunktion v(x), welche bei x = −1 und x = +1 den Wert y = 0 hat und dazwischen möglichst lange einen konstanten Wert, zum Beispiel y = 1 hat. Eine Geschwindigkeitsfunktion mit dem gewünschten Verhalten erhalte ich über eine umgekehrte Parabel (orange Kurve in der Grafik):

(3)
v(x) = 1 - x^2

welche durch Potenzieren von x mit einer ganzen Zahl n in die gewünschte Form gebracht werden kann (grüne Kurve: n = 2 und blaue Kurve n = 6):

(4)
v_1(x) = 1 - {(x^{\color{red}{2}})}^2 = 1 - x^4
(5)
v_2(x) = 1 - {(x^{\color{red}{6}})}^2 = 1 - x^{12}

Ich könnte noch höhere Potenzen verwenden, um sie oben noch mehr abzuflachen. Ich beschränke mich für dieses Beispiel jedoch auf eine Potenz von 2 und 6.

Integrieren der Geschwindigkeitsfunktion

Die Sweep-Funktion stellt den Weg als Funktion eines Zeitparameters x dar. Ich habe nun aber eine Funktion, welche die Geschwindigkeit als Funktion von x angibt. Um daraus die Weg-Funktion zu berechnen, muss ich die Geschwindigkeitsfunktion integrieren:

(6)
f_1(x) = \int v_1(x)\ \mathrm{d} x = \int (1 - x^4)\ \mathrm{d} x = \int 1\ \mathrm{d} x - \int x^4\ \mathrm{d} x = x - { x^5 \over 5 }
(7)
f_2(x) = \int v_2(x)\ \mathrm{d} x = \int (1 - x^{12})\ \mathrm{d} x = \int 1\ \mathrm{d} x - \int x^{12}\ \mathrm{d} x = x - { x^{13} \over 13 }

Mit n = 2 erhalte ich die hellgrüne Kurve in der Grafik rechts. Diese Kurve muss noch mit einem Faktor s1 multipliziert werden, damit sie genau im Bereich -1 bis +1 zu liegen kommt:

(8)
f_1(x) = s_1 \cdot \left( x - { x^5 \over 5 } \right)

Den Faktor s1 erhalte ich, wenn ich verlange, dass f1(x = 1) = 1 ist:

(9)
f_1(x=1) = s_1 \cdot \left( 1 - { 1^5 \over 5 } \right) = s_1 \cdot { 4 \over 5 } = 1
\Rightarrow s_1 = { 5 \over 4 }

Somit erhalte ich die Formel, welche der grünen Kurve entspricht:

(10)
f_1(x) = { 5 \over 4 } \cdot \left( x - { x^5 \over 5 } \right)

Analog erhalte ich s2 = 13 / 12 für die Funktion f2(x):

(11)
f_2(x) = { 13 \over 12 } \cdot \left( x - { x^{13} \over 13 } \right)

Die grüne Kurve hat bereits den gewünschten Verlauf, sie liegt jedoch noch im Bereich -1 bis +1 in beiden Achsen. Mit ein paar Transformationen kann sie in den Bereich 0 bis 1 skaliert und verschoben werden:

  1. x2 · x: Kurve in X-Richtung um Faktor 2 verschmälern
  2. xx0,5: Kurve um 0,5 Einheiten nach rechts verschieben
  3. f(x)0,5 · f(x): Kurve in Y-Richtung um Faktor 2 stauchen
  4. f(x)0,5 + f(x): Kurve um 0,5 Einheiten nach oben verschieben

Schritt 1 und 2 kann ich zusammenfassen zu 2 · (x0,5) = (2·x1)

Somit erhalte ich die Formeln für die gewünschten Sweep-Funktionen:

(12)
\color{green}{ f_1(x) = {1 \over 2} + {5 \over 8} \cdot \left[(2x - 1) - { (2x - 1)^5 \over 5 } \right] }
(13)
\color{blue}{ f_2(x) = {1 \over 2} + {13 \over 24} \cdot \left[(2x - 1) - { (2x - 1)^{13} \over 13 } \right] }

In der Grafik rechts ist die Sweep-Funktion f1(x) grün und die Funktion f2(x) blau dargestellt. Zum Vergleich ist hellrot nochmals die Cosinus-Funktion eingezeichnet.

Wie man sieht sind die Sweep-Funktionen in einem weiten Bereich annähernd linear, wogegen die Cosinus-Funktion auf dem ganzen Weg gekrümmt ist. Je höher die Potenz n, desto breiter ist der lineare Bereich.

Die allgemeine Formel für ein beliebiges n > 0 ist:

(14)
f_n(x) = { 1 \over 2 } + { 2 \, n + 1 \over 4 \, n } \, \left[ ( 2 \, x - 1 ) - { ( 2 \, x - 1 )^{ 2 \, n + 1 } \over 2 \, n + 1 } \right]

In der folgenden Animation können die verschiedenen Sweep-Funktionen verglichen werden:

  • schwarz: linear
  • blau: Sweep-Funktion mit n = 6
  • grüen: Sweep-Funktion mit n = 2
  • rot: Cosinus-Funktion

JavaScript der Sweep-Funktion

Zum Abschluss noch das JavaScript der Sweep-Funktionen:

function f1( x ) {
  var xx = 2 * x - 1;
  return 0.5 + (5/8) * (xx - (Math.pow( xx, 5 ) / 5));
}

function f2( x ) {
  var xx = 2 * x - 1;
  return 0.5 + (13/24) * (xx - (Math.pow( xx, 13 ) / 13));
}

Dein Kommentar zu diesem Artikel
Name
Email optional; wird nicht angezeigt
Kommentar
  • Name wird bei deinem Kommentar angezeigt.
  • Email ist nur für den Administrator, sie wird nicht angezeigt.
  • Du kannst deine Kommentare eine Zeit lang editieren oder löschen.
  • Du kannst Formatierungen im Kommentar verwenden, z.B: Code, Formeln, usw.
  • Externen Links und Bilder werden nicht angezeigt, bis sie der Admin freischaltet.
Weitere Infos zur Seite
Erzeugt Dienstag, 5. Mai 2015
von wabis
Zum Seitenanfang
Geändert Sonntag, 22. Mai 2016
von wabis