Zum Inhalt

Kleine Code-Beispiele

In diesem Abschnitt geben wir eine sehr kurze Demonstration verschiedener CindyScript-Programmiertechniken. Jedes Beispiel präsentiert eine kleine Aufgabe und eine CindyScript-Implementierung, die sie löst.


Schwerpunkt

Setzen eines Punktes D auf den Schwerpunkt von drei anderen Punkten. Ändern der Farbe basierend auf einer Bedingung.

//in draw
D.xy=(A+B+C)/3;
D.color=if(D.x>0,
   (1,1,0),
   (0,0,1)
)

Der Code ist sehr einfach. Beachten Sie, dass für das Setzen der Koordinate von D die Zuweisung an D.xy erfolgt. Die Bedingung am Ende gibt Farbwerte je nach Position von D zurück.


Auswählen und Clustern

Trennung von Punkten über und unter der x-Achse und Zeichnen der beiden Cluster.

//in draw
pts=allpoints();
above=select(pts,p,p.y>0);
below=pts--above;
segs=pairs(above);
drawall(segs,color->(0.6,0,0));
segs=pairs(below);
drawall(segs,color->(0,0.6,0))

Die Punkte über der x-Achse werden durch Verwendung des select-Operators mit einer passenden Bedingung unterschieden. Die Punkte unter der x-Achse werden durch eine Mengendifferenz berechnet. Die Linien, die die beiden Cluster verbinden, können leicht mit dem pairs-Operator berechnet werden, der alle möglichen Paare in einer Menge berechnet.


Berechnung und Zeichnung einer konvexen Hülle

Berechne die konvexe Hülle aller Punkte in einer Zeichnung. Beachte die Verwendung des ~>-Operators, um mit numerischen Instabilität umzugehen.

//in draw
pts=allpoints();
leftof(A,B):=select(pts,p,area(A,B,p)~>0);
rightof(A,B):=select(pts,p,area(A,B,p)~<0);

isedge(A,B):=(leftof(A,B)==[]%rightof(A,B)==[]);
segments=pairs(pts);
hull=select(segments,seg,isedge(seg_1,seg_2));
drawall(hull);

Die Berechnung der konvexen Hülle wird hier nach einem sehr schönen geometrischen Prinzip durchgeführt: Ein Segment in der konvexen Hülle hat alle anderen Punkte auf einer seiner Seiten. Hier werden zwei Funktionen leftof und rightof definiert, die die beiden Seiten eines Segments trennen. Basierend darauf wird ein Prädikat isedge definiert, das testet, ob ein Paar von Punkten eine Kante der konvexen Hülle bildet. (Beachte die Verwendung des unscharfen Vergleichs ~<0, um numerische Instabilität zu vermeiden). Schließlich werden alle Kanten der konvexen Hülle ausgewählt und gezeichnet.


Erstellen einer analogen Uhr

Erstelle eine Uhr, die Stunden, Minuten und Sekunden anzeigt. Dazu zeichne ein paar Pfeile, deren Endpunkte entsprechende Namen haben, und gib das folgende Skript ein.

//in timerstep
t=time();

p(x):=(sin(2*pi*x),cos(2*pi*x));
B.xy=p(t_3/60)*4;
C.xy=p(t_2/60)*5;
D.xy=p((t_1*60+t_2)/(12*60))*3.5;

apply(1..12,i,draw(p(i/12)*5));
apply(1..60,i,draw(p(i/60)*5,size->1`;

drawtext`3,5),t);

Die Punkte werden durch das Skript gezeichnet. Der Kreis wurde mit einem geometrischen Objekt gezeichnet.

Diese Uhr nutzt die Tatsache, dass der time-Operator Zugriff auf die Systemzeit des Computers gibt. Die Berechnungen werden so durchgeführt, dass die Sekundenzeiger springt, während die beiden anderen Zeiger kontinuierlich zu bewegen scheinen.


Nächster Punkt

Markiere den Punkt, der A am nächsten ist, mit einem großen grünen Punkt.

//in draw
pts=allpoints();
s=sort(pts,|#-A|);
p=s_2;
draw(p,size->20);

Beachte, dass wir im Skript den zweiten nächsten Punkt verwenden müssen, da A sich selbst am nächsten ist. Eine andere Lösung wäre, A aus der Liste zu entfernen, bevor wir sie sortieren:

//in draw
pts=allpoints()--[A];
s=sort(pts,|#-A|);
p=s_1;
draw(p,size->20);

Einfaches Ornament

Zeichne ein einfaches Ornament durch das Bewegen von Punkten. Die Farbe der Striche sollte der Farbe der Punkte ähneln.

//in draw
forall(pts,p,
   p:"trace"=p:"trace" ++ [p.xy]


![](../assets/wiki_up/Ex6.png)
);

tr0=[[1,0],[0,1]];
tr1=[[-1,0],[0,1]];
tr2=[[-1,0],[0,-1]];
tr3=[[1,0],[0,-1]];

trs=[tr0,tr1,tr2,tr3];

forall(trs,t,
 forall(pts,p,
   connect((p:"trace")*t,color->p.color,size->2);
 );
);

//in init
pts=allpoints();
forall(pts,p,p:"trace"=[]);

Beachte, dass jeder Punkt seine eigene Spur in der Schlüsselvariablen "trace" speichert. Die Transformationen werden durch zweidimensionale Matrizenmultiplikationen durchgeführt. Durch Änderung der Werte (und Anzahl) der Matrizen können viel kompliziertere Ornamente erstellt werden.


Lineare Regression

Berechne und zeichne die Linie der linearen Regression zu allen Punkten. Markiere die Quadrate, die der zugrundeliegenden Methode der kleinsten Quadrate entsprechen.

//in draw

//Least-square line
pts=allpoints();
m=apply(pts,(1,#.x));
y=apply(pts,#.y);


![](../assets/wiki_up/Ex7.png)
ma=transpose(m)*m;
mb=transpose(m)*y;
mainv=inverse(ma);
v=mainv*mb;
f(x):=v_2*x+v_1;
plot(f(x));

//Draw the squares

sq(x,y1,y2):=(
   d=y2-y1;
   p=((x,y1),(x,y2),(x+d,y2),(x+d,y1),(x,y1));
   drawpoly(p,color->(1,0.5,0.5),alpha->0.4);
   connect(p,color->(.8,0,0));
);

forall(pts,sq(#.x,#.y,(f(#.x))));

Der Code verwendet hochwertige Matrizenberechnungen, um die Linie der linearen Regression zu finden. Die Berechnung folgt dem Standardverfahren für diese Berechnung aus einem Grundkurs in linearer Algebra. Mit fast dem gleichen Code ist es sogar möglich, Annäherungen (kleinste Quadrate) durch einen ganzen Satz von Basisfunktionen zu berechnen.

Sonnenblume

Erstelle eine schöne Version des Sonnenblumen-Applets aus dem Tutorial.

//in draw
n=round(100*|B,E|);
d=0.01*(|D,F|/|D,C|-.5);
ang=137.508°+d;
repeat(n,i,
  w=ang*i;
  r=sqrt(i)*.2;
  p=(sin(w),cos(w))*r;
  draw(p,color->(1,0.8,0`;


![](../assets/wiki_up/Ex8.png)
);
drawtext`-5,-6),"n="+n);
drawtext((0,-6),"w="+180*ang/pi+"¡");

Dieser Code basiert auf der Wirkung, dass ein sehr bestimmter Winkel ang=137.508° unter dem Wachstumsverhalten einer Sonnenblume eine dichte Packung erzeugt. Das Beispiel zeigt auch, dass eine leichte Störung dieses Winkels sofort zu sehr prominenten Spiralen führt, bei denen die Packung nicht sehr isotrop ist.


Funktionszeichner

Implementiere einen Funktionszeichner mit einer frei eingebbaren Funktion und anpassbaren Parametern.

//in draw

//Parameter sliders
a=K.x;
b=L.x;
c=M.x;
d=N.x;
drawtext(K+(0.2,0.2),"a="+a);
drawtext(L+(0.2,0.2),"b="+b);
drawtext(M+(0.2,0.2),"c="+c);
drawtext(N+(0.2,0.2),"d="+d);


![](../assets/wiki_up/Ex9.png)
//Parse and plot
f(x):=parse(Text0.val);
plot(f(x),color->red(0.6),size->2);

Die Funktion wird in einem Cinderella-Eingabefeld namens Text0 eingegeben. Der Text in diesem Eingabefeld wird direkt geparst. Die Parameter werden aus den geometrisch gezeichneten Schiebereglern entnommen.


Farbmischung

Simuliere additive Farbmischung von drei Glühbirnen (Rot, Grün und Blau). Die Lampen werden durch geometrische Punkte A, B und C dargestellt.

//in draw

colorplot(
 (1-|#,A|/4,
  1-|#,B|/4,
  1-|#,C|/4),
 (-5,-5),(5,5),pxlres->3
)

Dieser Farbmischer ist wirklich extrem einfach. Er nutzt die Tatsache, dass man die Slots eines RGB-Farbvektors direkt berechnen kann. Der colorplot-Befehl macht im Wesentlichen den Rest der Arbeit.


Julia-Mengen

Berechne und zeichne die Julia-Menge, ein bekanntes Fraktal, das durch die komplexe Zahl bestimmt wird, die durch den Punkt C dargestellt wird.

//in draw

g(z,c):=z^2+c;

julia(z):=(
  iter=0;
  while(iter<100 & |z|<2,
    z=g(z,complex(C.xy));
    iter=iter+1;
  );
  1-iter/100;
);

colorplot(julia(complex(#))
   ,A,B,startres->16,pxlres->1);

Auch hier ist die Verwendung des colorplot-Befehls der mächtigste Ansatz für diese Aufgabe. Die oben stehende Funktion julia berechnet iterativ die Farbe jedes Pixels. Die Verwendung von startres und pxlres sorgt für ein flüssiges Benutzererlebnis.


Schwarmimulation

Simuliere eine Schule von Fischen. Jeder Fisch sollte versuchen, in die gleiche Richtung wie seine Nachbarn zu schwimmen und versuchen, an die ungefähre Stelle zu schwimmen, wo sich die Nachbarn befinden. Alle Fische sollten ein Hindernis vermeiden, das durch einen Punkt U gegeben ist. Um dies zu versuchen, erstelle ein paar Massen und stelle sicher, dass eine U heißt, oder ändere die entsprechende Zeile im Skript. Baue auch einen Zaun mit Springern um das "Aquarium".

//in draw

ms=allmasses()--[U];
lim=0.5;
apply(ms,m,
  near=select(ms,p,|p-m|<4);
  avg=sum(near,m,m.v)/length(near);
  m.v=m.v+.2*(avg);
  if(|m.v|>lim,m.v=lim*m.v/|m.v|);
  //Draw connections
  apply(near,draw(#,m,color->(0,0,0),alpha->0.2));
);

Hier werden alle Fische (sowie das Hindernis) durch Massen mit positiver Ladung modelliert. Dadurch stoßen sie sich gegenseitig ab. Das Skript führt Korrektionen an der Geschwindigkeit jedes Punktes durch. Das Verhalten, das dieser sehr einfache Algorithmus erzeugt, ist erstaunlich reichhaltig und sieht ziemlich überzeugend aus.


🤖 Diese Seite wurde automatisch mit KI (Claude) übersetzt und wartet noch auf Überprüfung. → Alle KI-übersetzten Seiten