SVG & Tree
Vektoren laden
Bis dato haben einige von Euch mit viel Aufwand Charakters in Processing erstellt, was sicherlich in Programmen wie Illustrator oder Freehand leichter und schneller vonstatten gegangen wäre. Da es immer sinnvoll ist das richtige Werkzeug für die entsprechende Aufgabe zu verwenden, werden wir jetzt Illustrator & Processing zusammen nutzen.
Als Ideengeber sollen uns die Arbeiten Lovebytes 2007 und Nokia Friends von Karsten Schmidt dienen.
Wir werden dabei aber nicht alles in Processing erstellen, sondern wir werden uns die Grundvektoren in Illustrator anlegen. Um die Vektoren aus Illustrator in Processing nutzen zu können, speichert man aus Illustrator eine SVG-Datei mit den Standardeinstellungen.
Scalable Vector Graphics (SVG) ist ein Standard zur Beschreibung zweidimensionaler Vektorgrafiken auf Basis der XML-Syntax. Die Verwendung der skalierbaren Vektordateien ist die einzige Möglichkeit extern erstellte Vektoren in Processing zu laden.
Die Nutzung der Vektoren besteht aus dem Ladeprozess und dem Zeichnen bzw. Anzeigen des Vektors. Zum Laden verwendet man die Funktion loadShape("shapeFile.svg") und zum Anzeigen die Funktion shape( pshapeInstance, x, y, width, height ).
Spannend wird es, wenn man mit der Funktion pshapeInstance.getChild( "childName" ) auf einzelne Bestandteile der Vektorgrafik zugreift, um diese zu modifizieren. Für den Zugriff ist es essentiell, dass man in Illustrator jeder Ebene, auf die man zugreifen will, einen beschreibenden Name gibt.
So kann man sich vorstellen, dass man in Illustrator verschiedene Vektoren zeichnet, für die man dann ein Programm in Processing schreibt, um Größe, Position, Farbe etc. zu verändern.
Nützlich ist dabei die Funktion pshapeInstance.setVisible(), um die Sichtbarkeit eines Vektorelements zu verändern.
Um den Style zu ändern, muss man zu erst die Informationen aus dem SVG-Format pshapeInstance.disableStyle() deaktivieren, damit mit den definierten Einstellung aus Processing der Vektor gezeichnet wird.
Als Beispiel erstellen wir uns einen ganz simplen Charakter mit Kopf, zwei Armen und zwei Beinen.
Beispiel:
// Shapes definieren PShape character; PShape head; void setup() { size( 1000, 800 ); smooth(); background( 0 ); noStroke(); noLoop(); // SVG-Datei laden character = loadShape("character.svg"); // Element aus der SVG-Datei ansprechen head = character.getChild("headShape"); } void draw() { // Style ausschalten head.disableStyle(); // Shape mit eigener Füllung zeichnen fill(0, 51, 102); shape( head, 0, 0 ); }
Im zweiten Teil der heutigen Vorlesung geht es um rekursive Funktionen.

Unter rekursiven Funktionen versteht man Funktionen, die sich immer wieder selbst aufrufen, solange bis eine Ausstiegsbedingung eintritt.
Das Ergebnis davon können im allgemeinen Fraktale oder wie in dem folgenden Beispiel einfache Baumstrukturen sein. Fraktale begegnen uns auf dem Esstisch. Zum Beispiel sind im Romanesco oder auch im Blumenkohl fraktale Konzepte zu erkennen.
Unser heutiges Beispiel orientiert sich stark an dem Beispiel von Daniel Shiffman auf Processing.org, um eine Baumstruktur zu erstellen. Es soll für uns aber nur der Startpunkt zu weiteren Experimenten sein.
Zu erst definieren wir eine Farbe für den Hintergrund und die Linien.
Um die rekursive Funktionalität besser zu visualisieren nutzen wir die Maus, um verschiedene Winkel zu berechnen. Wir berechnen die Mausposition auf der X-Achse und setzen sie ins Verhältnis zu der Bühnenbreite. Die prozentuale Position multiplizieren wir mit 90 Grad, um für die Variable a einen Wert zwischen 0 und 90 zu erhalten.
Beispiel:
// Mausposition umrechnen in 0 - 90 Grad float a = ( mouseX / ( float ) width ) * 90.0;
Der nächste Schritt ist die Umwandlung des Wertes in Radianten, die Processing für die Rotation der Zeichenfläche benötigt.
Beispiel:
// Umwandlung in Radianten ( Bogenmaß ) angle = radians( a );
Danach setzt man den Zeichenstartpunkt mit dem Befehl translate() auf den unteren mittleren Rand der Zeichenfläche und zeichnet den Baumstamm mit 120 Pixel nach oben.
Nun versetzt man den Zeichenstartpunkt wieder mit translate() für die nächste Aktion auf das Stammende und führt die rekursive Funktion drawBranch() mit einer Starthöhe von 150 Pixel für den Stamm aus.
Beispiel:
// Startpunkt der Anwendung verschieben // auf den unteren Rand in der Mitte translate( width / 2, height ); // Linie von unten nach oben zeichnen line( 0, 0, 0, -120 ); // Zeichenstartpunkt auf das Ende // der Linie setzen translate( 0, -120 ); // Start der rekursiven Funktion drawBranch( 150 );
Die eigentliche Arbeit erfolgt in der rekursiven Funktion drawBranch(), die sich so lange selber aufruft, bis die Ausstiegsbedingung eintrifft.
Im ersten Schritt wird die übergebene Höhe mit 0.66 multipliziert, um die Zweiglänge von Schritt zu Schritt zu verkleinern.
Beispiel:
// jeder Zweig wird 2/3 kleiner als sein // Mutterzweig h = h * 0.66;
Im ersten Abschnitt der Funktion drawBranch() wird der rechte Zweig gezeichnet.
Wichtig bei der Verwendung von Transformationsbefehlen in Processing ist zu wissen, dass jede neue Transformation auf die bereits vorhandene addiert wird.
Somit speichert man vor der Anwendung oft die aktuelle Transformation mit dem Befehl pushMatrix() ab, um die Transformation später wieder zurück zu setzen.
Nun erfolgt eine Rotation um den eingangs berechneten Wert, damit ein weiterer Zweig gezeichnet wird.
Beispiel:
// speichert den aktuellen Zustand der Transformation pushMatrix(); // Rotation rotate( angle ); // drawBranch zeichnen line( 0, 0, 0, -h );
Nach dem Zeichnen des ersten Zweiges versetzt man den Startpunkt für das Zeichnen auf das Ende des Zweiges.
Beispiel:
// neuen Zeichenstartpunkt setzen translate( 0, -h );
Erneut wird die Funktion drawBranch() mit der neuen Höhe h ausgeführt und danach wird der alte Transformationszustand mit dem Befehl popMatrix() wiederhergestellt.
Beispiel:
// die nächsten Zweige zeichnen drawBranch( h ); // Zeichenstartpunkt auf den Anfang // dieser Runde zurücksetzen popMatrix();
Der zweite Abschnitt, um den linken Zweig zu zeichnen ist fast identisch mit dem ersten Abschnitt mit der Ausnahme, dass die Rotation gegen den Uhrzeigersinn erfolgt.
Beispiel:
pushMatrix(); rotate( -angle ); line( 0, 0, 0, -h ); translate( 0, -h ); drawBranch( h ); popMatrix();
Hausaufgabe
In der heutigen Woche sind zwei Beispiel zum Thema SVG und ein Beispiel zum Thema Tree zu erstellen.
Informationen zum Dateiformat, der Bezeichnung und zum Upload der Dateien sind unter dem Punkt Prüfungsleistung zu finden.
Die Beispiele der Woche können hier herunter geladen werden.