09.04.2012

Xcode 4

Sierpinski-Dreieck in eine Custom-View zeichnen

In der folgenden Beispielanwendung wird ein Sierpinski-Dreieck in eine Cocoa Custom-View gezeichnet. Der Algorithmus für das Sierpinkski-Dreieck ist in Objective-C umgesetzt. Bei dem Sierpinkski-Dreieck handelt es sich um ein Fraktal, welches durch folgende rekusive Regel entsteht:

  • Zeichne ein gleichseitiges Dreieck
  • Suche die Mitte von jeder Linie des Dreiecks und verbinde sie
  • Die Fläche des neuen Dreiecks wird entfernt
  • Die letzten beiden Schritte mit den neu entstandenen Dreiecken wiederholen.

In dem Tutorial Custom-Views wird beschrieben, wie man mit Objective-C und Cocoa eine Custom-View anlegt. Hier wird nun die Methode - (void)drawRect:(NSRect)dirtyRect mit ein paar Programmzeilen gefüllt.

In dem Beispiel wird ein Dreieck mit der Kantenlänge 500 Pixel gezeichnet. Dazu sind drei Punkte notwendig. Der erste Punkt wird bei (0,0) gesetzt. Der zweite bei (500,0). Bei dem dritten Punkt ist der x-Wert einfach 500/2=250 und der y-Wert berechnet sich aus der Formel h=(sqrt(3)/2)*500 (Höhe eine gleichseitigen Dreiecks).

Da das Sierpinksi-Dreieck rekursiv aufgebaut wird, erstellen wir eine Methode - (void)sierpinski:(NSPoint)A:(NSPoint)B:(NSPoint)C:(int)d:(NSBezierPath*)shape. Es werden jeweils die drei Punkte des Dreickes, die zu berechnende Tiefe der Rekursion und der NSBezierPath mitgegeben.

Wenn die Rekusionstiefe noch größer als 0 ist, dann werden jeweils Mittelpunkte der drei Linien des Dreiecks berechnet und die neu entstandenen Punkte erneut als Parameter an die Methode - (void)sierpinski:(NSPoint)A:(NSPoint)B:(NSPoint)C:(int)d:(NSBezierPath*)shape übergeben. Außerdem muß die Rekursionstiefe um 1 verringert werden, damit die Rekursion irgendwann abbricht.

Wenn die Rekursionstiefe gleich 0 ist, dann wird ein Dreieck mit den drei übergebenen Punkten gezeichnet und ausgefüllt.

- (void)drawRect:(NSRect)dirtyRect
{
    NSBezierPath *shape = [NSBezierPath bezierPath];
    int d = 6; // Rekursionstiefe
    NSPoint A = NSMakePoint(0 , 0);
    NSPoint B = NSMakePoint(500, 0);
    NSPoint C = NSMakePoint(250,(sqrt(3.0f)/2)*500); //Hoehe des Dreiecks berechnen
    
    [self sierpinski:A:B:C:d:shape];
}

- (void)sierpinski:(NSPoint)A:(NSPoint)B:(NSPoint)C:(int)d:(NSBezierPath*)shape {
    if(d>0) {
        NSPoint mA = NSMakePoint((B.x + C.x) / 2, (B.y + C.y) / 2);
        NSPoint mB = NSMakePoint((A.x + C.x) / 2, (A.y + C.y) / 2);
        NSPoint mC = NSMakePoint((A.x + B.x) / 2, (A.y + B.y) / 2);
        
        d--;
        
        [self sierpinski:A :mB :mC :d :shape];
        [self sierpinski:mC :mA :B :d :shape];
        [self sierpinski:mB :mA :C :d :shape];
        
    }
    else {
        [shape moveToPoint:A]; // Startpunkt
        [shape lineToPoint:B]; // Linie 1
        [shape lineToPoint:C]; // Linie 2
        [shape lineToPoint:A]; // Linie 3

        [[NSColor blackColor] set];
        [shape stroke]; //Zeichne Dreieck
        [shape fill]; //ausfuellen
    }
}

Damit das Sierpinkski-Dreick in die Custom-View aus dem Beispiel paßt, muß noch die Breite und Höhe in der Datei MainMenu.xib angepaßt werden. Die Breite des Fensters ergibt sich aus den 500 Pixel und einen Seitenabstand von 20 Pixeln links und rechts. Also 540 Pixel. Die Höhe wird mit der Höhenformel berechnet. Also (sqrt(3)/2)*500 = 433.01. Addiert werden noch die Randabstände, wodurch sich ungefähr 474 Pixel ergeben.

Wenn man nun mit der Rekusionstiefe d experimentiert, erhält man folgende Darstellungen für die Werte 0-7.

Sierpinski Dreieck 0 Sierpinski Dreieck 1 Sierpinski Dreieck 2 Sierpinski Dreieck 3
Sierpinski Dreieck 4 Sierpinski Dreieck 5 Sierpinski Dreieck 6 Sierpinski Dreieck 7