Wir beginnen mit einer ganz einfachen Aufgabe. Wir wollen Punkte zeichnen, die auf einem Kreis liegen. Im Mathematikunterricht haben wir gelernt, dass die Koordinaten auf einer Kreisline mit Radius R durch ( Rcos(w) / Rsin(w) ) gegeben sind, wobei w der Winkel im Bogenmaß ist.
Für 70 Punkte genügt uns folgendes Programm:
kreis_1.pde
// Kreis aus Punkten
void setup() {
size(400,400);
frameRate(30);
}
void draw() {
float w,x,y; // Winkel und Koordinaten
for (int n=0; n<70; n++) {
w = TWO_PI*n/70;
x = cos(w);
y = sin(w);
stroke(255);
fill(0,0,160);
ellipse(200+150*x,200-150*y,20,20);
}
}
So sieht das Ganze dann aus:

Wollten wir nun etwa 100 Punkte zeichnen und dem Kreis eine andere Größe geben, müssten wir die entsprechenden Zahlen im Programm suchen und ausbessern. Und hoffen, dass wir nichts übersehen. Eine andere Größe des Fensters würde zu einem veränderten Mittelpunkt führen, wodurch auch hier viele Folgeänderungen gemacht werden müssen.
Viel besser wäre es, hätten wir Variable eingesetzt, die diese Werte enthalten. Bei kluger Wahl ihrer Namen wären die einzelnen Programmzeilen auch viel leichter verständlich (die wichtigsten Änderungen habe ich hervorgehoben):
kreis_2.pde
// Variable fuer Groesse und Punktzahl
float rMax; // maximale Groesse
float x0,y0; // Bildschirm Mitte
int num; // Anzahl berechnete Punkte
void setup() {
size(400,400);
rMax = 150;
x0 = width/2;
y0 = height/2;
num = 70;
frameRate(30);
}
void draw() {
float w,x,y; // Winkel und Koordinaten
for (int n=0; n<num; n++) {
w = TWO_PI*n/num;
x = cos(w);
y = sin(w);
stroke(255);
fill(0,0,160);
ellipse(x0+rMax*x,y0-rMax*y,20,20);
}
}
Speziell die letzte Programmzeile spricht nun für sich selbst! Die Ausgabe des Programms ist natürlich unverändert.
Wir lagern die Arbeit des Zeichnens in eine eigene Funktion aus und übergeben ihr die (mathematischen) Koordinaten des Zielpunktes. Somit erledigt diese neue Funktion die Umwandlung der mathematischen Koordinaten in Bildschirmkoordinaten, sowie ihre Darstellung.
kreis_3.pde
// eigene Funktion zum Zeichnen
float rMax; // maximale Groesse
float x0,y0; // Bildschirm Mitte
int num; // Anzahl berechnete Punkte
void setup() {
size(400,400);
rMax = 150;
x0 = width/2;
y0 = height/2;
num = 70;
frameRate(30);
}
void draw() {
float w,x,y; // Winkel und Koordinaten
for (int n=0; n<num; n++) {
w = TWO_PI*n/num;
x = cos(w);
y = sin(w);
plot(x,y);
}
}
// Punkt (x/y) auf Bildschirmkoordinaten umrechnen und zeichnen
void plot(float xx, float yy) {
float x = x0+rMax*xx;
float y = y0-rMax*yy;
stroke(255);
fill(0,0,160);
ellipse(x,y,20,20);
}
Das sieht noch klarer aus! Wir haben zwar deutlich mehr Zeilen tippen müssen, aber der Text ist klar strukturiert, leicht lesbar und verständlich. Und was für uns besonders wichtig ist: nachträgliche Änderungen und Erweiterungen lassen sich ganz leicht einbauen.
Statt eines einfachen Kreises zeichnen wir eine Kurve, die beim Abrollen eines kleinen Kreises auf einem großen entsteht. Falls Du das nette Spielzeug 'Spirograph' kennst - genau so etwas ist das. Wir addieren zu den Kreiskoordinaten einen zweiten Kreis dazu. Sein Radius soll r2 heißen, seine Frequenz (Umdrehungsgeschwindigkeit) f2.
kreis_4.pde
// einen Kreis auf dem Kreis rotieren lassen
float rMax; // maximale Groesse
float x0,y0; // Bildschirm Mitte
int num; // Anzahl berechnete Punkte
float r2,f2; // Radius und Frequenz des zweiten Kreises
void setup() {
size(400,400);
rMax = 150;
x0 = width/2;
y0 = height/2;
num = 70; // versuche 300;
r2 = 1.5;
f2 = 3; // versuche 6,7,..,-5
frameRate(30);
}
void draw() {
float w,x,y; // Winkel und Koordinaten
for (int n=0; n<num; n++) {
w = TWO_PI*n/num;
x = cos(w)+r2*cos(f2*w);
y = sin(w)+r2*sin(f2*w);
plot(x,y);
}
}
// Punkt (x/y) auf Bildschirmkoordinaten umrechnen
// und zeichnen
void plot(float xx, float yy) {
float rSize = rMax/(1+r2); // Vergroesserungsfaktor
float x = x0+rSize*xx;
float y = y0-rSize*yy;
stroke(255);
fill(0,0,160);
ellipse(x,y,20,20);
}
Das ergibt folgendes Bild
Eine sehr einfache und praktische Möglichkeit der interaktiven Steuerung von Parametern ist die Bibliothek controlP5, die im Internet (auch über die Processing-Homepage) erhältlich ist. Man bekommt eine kleine gepackte Datei, die im Processing-Verzeichnis ins Verzeichnis 'libraries' gehört. Dazu erstellen wir dort ein neues Verzeichnis namens 'controlP5' und entpacken den Inhalt der zip-Datei dort hinein.
Mit Hilfe dieser Bibliothek erzeugen wir einen Schieberegler für die Frequenz f2 des kleinen Kreises. Es genügt, dem Slider den Namen der Variable f2 anzugeben, schon ist die Variable ferngesteuert. Die Syntax lautet:
addSlider("variable", minimalWert, maximalWert, posX, posY, groesseX, groesseY)
kreis_5.pde
// viele Punkte berechnen und einen
// Schieberegler fuer die Frequenz des zweiten Kreises
import controlP5.*; // Bibliothek der GUI-Widgets
ControlP5 steuerung; // Zugriff auf die Steuerelemente
float rMax; // maximale Groesse
float x0,y0; // Bildschirm Mitte
int num; // Anzahl berechnete Punkte
float r2; // Radius und Frequenz des zweiten Kreises
int f2;
void setup() {
size(400+100,400); // links Platz fuer den Regler schaffen
rMax = 150;
x0 = (width-100)/2+100; // 100 Pixel Platz für Regler
y0 = height/2;
num = 400;
r2 = 0.5;
f2 = 3;
frameRate(30);
steuerung = new ControlP5(this);
Slider s1 = steuerung.addSlider("f2",-20,20, 20,20, 10,200);
}
void draw() {
float w,x,y; // Winkel und Koordinaten
background(0);
for (int n=0; n<num; n++) {
w = TWO_PI*n/num;
x = cos(w)+r2*cos(f2*w);
y = sin(w)+r2*sin(f2*w);
plot(x,y);
}
}
// Punkt (x/y) auf Bildschirmkoordinaten umrechnen und zeichnen
void plot(float xx, float yy) {
float rSize = rMax/(1+abs(r2)); // Vergroesserungsfaktor
float x = x0+rSize*xx;
float y = y0-rSize*yy;
stroke(255);
fill(0,0,160);
ellipse(x,y,20,20);
}
Das Programmfenster sieht nun so aus:
Links ist der Regler zu sehen. controlP5 ist nicht sehr konfigurierbar, aber ganz leicht anzuwenden.
Nun kann man immer mehr nette Ideen verwirklichen. Lade Dir die Quelltexte aller Sketche herunter und vollziehe sie schrittweise nach - es ist nicht schwierig!
Die Lininen müssen nicht unbedingt vom Nachbarpunkt aus gezeichnet werden - die Variable 'prev' (previous) bestimmt, der wievielte Punkt als Nachbar angesehen werden soll. Wir erhalten damit interessante Grafiken, die an die Fadengrafiken des GZ-Unterrichts erinnern. Mit hübschen Schiebereglern lässt sich eine Unmenge von Mustern erzeugen:
kreis_9.pde

Wir lassen aus einer kleinen Idee ein immer größeres und mächtigeres Programm entstehen!
Die letzte Stufe soll ein Programm sein, das sogar eine Rotation der Figur erlaubt, die nun aus Linienstücken zusammengesetzt ist.
kreis_11.pde
// Regler fuer Drehung, Zeichenstil
import controlP5.*; // Bibliothek der GUI-Widgets
ControlP5 steuerung; // Zugriff auf die Steuerelemente
float rMax; // maximale Groesse
float x0,y0; // Bildschirm Mitte
int num; // Anzahl berechnete Punkte
int style;
float r2; // Radius und Frequenz des zweiten Kreises
int f2;
int prev; // wievielter Vorgaenger
float phase=0;
float tempo=0.02; // Geschwindigkeit der Drehung
void setup() {
size(600,400);
rMax = 150;
x0 = (width-200)/2+200; // 100 Pixel Platz fuer Regler
y0 = height/2;
style = 1;
num = 200;
prev = 1;
r2 = 0.55;
f2 = 4;
menu();
frameRate = 25;
}
void menu() {
steuerung = new ControlP5(this);
Slider s1 = steuerung.addSlider("f2", -20, 20, 20,20, 10,200);
Slider s2 = steuerung.addSlider("r2", 0, 2, 50,20, 10,200);
Slider s3 = steuerung.addSlider("num", 1,600, 80,20, 10,360);
Slider s4 = steuerung.addSlider("prev", 1,300, 110,20, 10,200);
Slider s5 = steuerung.addSlider("tempo",-0.1,0.1, 140,20, 10,200);
Slider s6 = steuerung.addSlider("style", 1,3.9, 170,20, 10,200);
}
float[] xx = new float[1000]; // Felder mit 1000 Elementen vorbereiten
float[] yy = new float[1000];
// ----------------------------------------------------------
void draw() {
float w,x,y; // Winkel und Koordinaten
background(0);
for (int n=0; n<num; n++) {
w = TWO_PI*n/num;
// berechnete Werte in die Felder schreiben
xx[n] = cos(w+phase)+r2*cos(f2*w+phase);
yy[n] = sin(w+phase)+r2*sin(f2*w+phase);
}
for (int n=0; n<num; n++) {
if (style==1) { plot(n); }
if (style==2) { plot2(n); }
if (style==3) { plot(n); plot2(n); }
}
phase += tempo;
}
// ----------------------------------------------------------
////////////////////////////////////
// zeichne eine Linie zum Vorgaenger
void plot(int n) {
float rSize = rMax/(1+abs(r2));
float x = x0+rSize*xx[n];
float y = y0-rSize*yy[n];
int vorher = (n-prev)%num; // Divisionsrest klappt immer
if (vorher..0) { vorher = vorher+num; }
float x2 = x0+rSize*xx[vorher];
float y2 = y0-rSize*yy[vorher];
stroke(255);
line(x2,y2,x,y);
}
////////////////////////////////////
// zeichne einen 'Punkt'
void plot2(int n) {
float rSize = rMax/(1+abs(r2));
float x = x0+rSize*xx[n];
float y = y0-rSize*yy[n];
noStroke();
fill(50,220,50,150);
ellipse(x,y,15,15);
}
Dieses Programm sieht so aus:
Hier kann man schon sehr viel einstellen und ändern.
Du kannst das Programm weiter ausbauen - bis zu einem Programm, das großartige Grafiken nach unterschiedlichen Methoden erzeugt. Details im Unterricht!
Was alles möglich ist, zeigt zu einem kleinen Teil das folgende Programm (Javascript und ein aktueller Browser sind notwendig...)
kreis_demo.pde