eleqtriq

Ich möchte an dieser Stelle eine Technik vorstellen um kubische Bezier-Kurven in Flash zu zeichnen. Falls kubische Bezier-Kurven Neuland für Euch sind, solltet ihr vorher einen kurzen Abstecher zur Wikipedia machen.

Beispiel öffnen

Ein Nachteil von Flash ist die Tatsache, dass esnicht in der Lage ist kubische Bezierkurven darzustellen. Nutzt man die Flash IDE um eine Kurve von Hand zu zeichnen, wird Flash diese in eine Anzahl kleiner Einzelsegmente zerlegen, und die ursprüngliche kubische Bezierkurve wird mit vielen kleinen quadratischen Bezierkurven genähert (den meisten Flash-Designern wird das schon einmal passiert sein: zeichnet eine einfache Bezierkurve in Flash. Hebt die Auswahl auf und selektiert die Kurve anschließend wieder. Plötzlich ist die Kurve in lauter kurze Abschnitte aufgeteilt, auch wenn sie vorher nur wenige Ankerpunkte hatte). Wenn man eine Kurve mit der Flash Drawing-API zeichnen möchte, gibt es ohnehin keine andere Möglichkeit als die "curveTo()"-Methode, die neben Start- und End- nur einen lausigen quadratischen Kontrollpunkt zulässt.

Generische Mittelpunkt Näherung

Die „normale” Art und Weise, dieses Problem zu handhaben ist eine Technik namens "Generische Mittelpunkt Näherung". Es existieren diverse Actionscript-Klassen, die diese Technik verwenden, um Flash dazu zu bringen kubische Beziwerkurven darzustellen. Das Prinzip hinter der generischen Mittelpunkt Näherung ist im Diagramm links dargestellt. Im Grunde genommen ist es ein Algorithmus um eine kubische Bezierkurve in 4 quadratische Bezierkurven zu zerlegen. Diese Methode ist recht anspruchslos in Bezug auf Rechenleistung und verspricht in den meisten Fällen gute Ergebnisse. Dafür zahlt man aber mit einem Mangel an Präzision. In der Regel fällt das nicht weiter auf, aber manchmal (z. B. bei extrem steilen, oder sich selbst schneidenden Kurven) sind die Ergebnisse "hubbelig" oder unförmig. Es ist halt nicht für jeden Anwendungsfall die beste Lösung.

Die gute Nachricht: es ist nicht unbedingt sehr bekannt, aber in der Tat existiert eine Flash-Klasse für kubische Bezier-Kurven. Sie heisst "BezierSegment" und ist im "fl.motion" Package versteckt. Die schlechte Nachricht: sie wurde nicht dafür vorgesehen, Objekte auf der Bühne darzustellen, sondern für Animationen mittels Actionscript. Mit ein paar kleinen Basteleien lässt sich diese Klasse aber sehr wohl dafür einsetzen, hochpräzise kubische Bezierkurven mittels Actionscript zu zeichnen.

Kubische Bezierkurve mit der BezierSegment-Klasse:

1. Imort der Klasse:

import fl.motion.BezierSegment;

2. Ein neues BezierSegment erstellen:

var bezier:BezierSegment=new BezierSegment(point_1, control_1, point_2, control_2);

3. Das Segment zerlegen:

Die Kordinaten eines Punktes auf dem Bezier-Segment ermittelt man mit der getValue(t:Number)-Methode. t interpoliert einen Wert auf der Kurve, t=1 ist dabei der Maximalwert (der Endpunkt). Wollen wir also die Koordinaten desjenigen Punktes ermitteln, der genau bei 50% auf der Kurve liegt, sagen wir einfach

var val:Point=bezier.getValue(0.5)

Cool, oder?

Beispiel: eine gepunktete Linie

Wir fangen mal mit etwas einfachem an, einer gepunkteten Linie. Zuerst legen wir die Auflösung fest, sagen wir mal 20. Jetzt müssen wir nur noch jede (1/20)te Position einen Punkt zeichnen:

Sorry, no Flash
var resolution:uint=20; var step:Number =1/resolution; var t:Number=0; while(t<=1){ var pos:Point=bezier.getValue(t); with(this.graphics){ beginFill(0x990000, 1); drawCircle(pos.x, pos.y, 5); endFill; } t+=step; }

Das Ergebnis ist eine hübsche gepunktete Linie.

Schön und gut. Aber wie verbindet man die Punkte denn jetzt bitteschön?

Das BezierSegment zerlegen

Kommen wir also zum kniffligen Teil: um die Punkte mit Kurven zu verbinden, brauchen wir die Koordinaten für einen quadratischen Kontrollpunkt. Diesen finden wir folgendermaßen:

1. Wir ermitteln die Tangente durch den ersten und den letzten Punkt unseres Abschnittes. Die geschieht mit dem sogenannten Decasteljau-Algorithmus.

2. Wir suchen den Schnittpunkt der beiden Tangenten und...

3. ...nutzen diesen Schnittpunkt als Kontrollpunkt unserer quadratischen Kurve.

BezierSegment Fehler beim Zerlegen

Manchmal kann es vorkommen, dass die Kurve derart außergewöhnlich ist und gleichzeitig die gewählte Auflösung derart niedrig, dass wir das Segment einmal mehr zerteilen müssen. Anschließend muss erneut geprüft werden, ob der Darstellungsfehler noch besteht und falls ja, müssen die beiden Segmente erneut zerlegt werden, solange bis der Fehler verschwunden ist. Wie erkennen wir, ob der Schnittpunkt korrekt ermittelt wurde? Ganz einfach: die Entfernung punkt1-Kontrollpunkt oder punkt2-Kontrollpunkt darf nicht größer sein, als die Entfernung Punkt1-Punkt2.

Nun haben wir also eine nette kleine Klasse um in Flash sehr präzise Bezierkurven zu zeichnen. Im Beispiel könnt Ihr vergleichen, wie eine mit GMA erstellte Kurve neben einer mittels BezierSegment gezeichneten Kurve aussieht. Natürlich stellt die BezierSegment-Kurve etwas höhere Anforderungen an die Rechenleistung. Andererseits liegt es in der Hand des Entwicklers, wie hoch er die Auflösung wählt. Neben der besseren Darstellung hat die BS-Kurve andere Vorteile: es existieren Beispielsweise diverse mehr oder weniger komplizierte Methoden um Schnittpunkte zu interpolieren. Aber da wir die Kurve ja schon in eine Reihe von Einzelsegmenten aufgeteilt haben, könnten wir genauso einfach mit brutaler Gewalt über alle Segmente loopen, prüfen ob die Umgebungsrechtecke sich überschneiden, Segmente erneut aufteilen, wieder loopen, bis wir nahe genug an einem Schnittpunkt sind.

Show Source

Wenn Ihr mit dem Code herumspielen wollt, könnt Ihr ihn hier herunterladen. Wie immer gebe ich keine Garantien und gestatte außerdem niemandem, meinen Code zum Bau von Cruise-Missiles oder zum quälen von Hamstern zu verwenden. Viel Spaß!

Trackback

2 Kommentare zu „Kubische Bezierkurven in Flash“

  1. Kommentar by Daniel Fr. 10. Sep 2010, 04:23

    Beautifull !… congratulations !.

    Daniel.

  2. Kommentar by Eke Mi. 20. Apr 2011, 13:21

    Thanks, it helped me a lot :)