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)
wobei'
' =' 'Sweep-Funktion
' =' 'Wegabschnitt zwischen xmin und xmax
' =' '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)

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)

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)
(5)

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)
(7)

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)

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

(9)

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

(10)

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

(11)

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)
(13)

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)

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.
More Page Infos / Sitemap
Created Dienstag, 5. Mai 2015
Scroll to Top of Page
Changed Sonntag, 22. Mai 2016