It will generate a picture something like this[but with color]

[https://upload.wikimedia.org/wikipedia/commons/f/f8/Sierpinski_m100000.png](https://upload.wikimedia.org/wikipedia/commons/f/f8/Sierpinski_m100000.png)

I wrote it first, a perl script:
    
    
    #!/usr/bin/perl
    use Cairo;
    
    my $size    = 2000;
    my $border  = 10;
    my $level   = 12;
    my $image   = 'perl.png';
    my $surface = Cairo::ImageSurface->create( 'argb32', $size, $size );
    my $cr      = Cairo::Context->create($surface);
    
    sub X()     { 0 }
    sub Y()     { 1 }
    sub head()  { 0 }
    sub left()  { 1 }
    sub right() { 2 }
    sub some    { $level, @_ }
    
    sub triangle {
        my $x        = $size / 2 - $border;
        my $y        = $x * sqrt 3;
        my $v        = ( $size - $y ) / 2;
        my $triangle = [
            [ $size / 2,       $v ],
            [ $border,         $size - $v ],
            [ $size - $border, $size - $v ]
        ];
        [$triangle]
    
    }
    
    sub fill {
        my ( $left, $right, $tail ) = @_;
        my @color = (
            ( $size - $tail->[Y] ) / $size,
            ( $size - $tail->[X] ) / $size,
            $tail->[X] / $size
        );
        $cr->set_source_rgb(@color);
        $cr->move_to(@$left);
        $cr->line_to(@$right), $cr->line_to(@$tail);
        $cr->fill;
    }
    
    sub draw {
        my ( $level, $triangle ) = @_;
        return unless $level;
        my $x = ( $triangle->[0][head][X] - $triangle->[0][left][X] ) / 2;
        return if $x < 1;
        my $y = ( $triangle->[0][left][Y] - $triangle->[0][head][Y] ) / 2;
        
        my @next = map {
            my ( $HEAD, $LEFT, $RIGHT ) = @$_;
            my $left = [ $HEAD->[X] - $x, $HEAD->[Y] + $y ];
            my $right = [ $HEAD->[X] + $x, $HEAD->[Y] + $y ];
            my $tail = [ $HEAD->[X], $LEFT->[Y] ];
            
            fill $left, $right, $tail;
            
            [ $HEAD,    $left, $right ],
              [ $left,  $LEFT, $tail ],
              [ $right, $tail, $RIGHT ]
        } @$triangle;
        
        draw( $level - 1, \@next );
    }
    
    sub go {
        $cr->rectangle( 0, 0, $size, $size );
        $cr->fill;
        $cr->set_line_width(.5);
        draw some triangle;
        $surface->write_to_png($image);
    }
    
    go;
    
    

and then. I translate it to nim:
    
    
    import math, cairo
    
    type point = tuple[x, y: float]
    type trian = tuple[head, left, right: point]
    type trias = seq[trian]
    
    let
        size  : float = 2000
        border: float = 10
        level = 12
        image = "nim.png"
    
    var
        surface: PSurface
        cr: PContext
    
    proc triangle: trian =
        let x = size / 2.0 - border
        let y = x * 3.float64.sqrt
        let v = (size - y) / 2.0
        
        ((size / 2.0, v), (border, size - v), (size - border, size - v))
    
    proc fill(left, right, tail: point) =
        let
            r = ( size - tail.y ) / size
            g = ( size - tail.x ) / size
            b = tail.x / size
        
        cr.set_source_rgb(r, g, b)
        cr.move_to(left.x, left.y)
        cr.line_to(right.x, right.y)
        cr.line_to(tail.x, tail.y)
        cr.fill
    
    proc draw(level: int, ts: trias): trias =
        if level == 0: return
        let x = (ts[0].head.x - ts[0].left.x) / 2.0
        if x < 1.0: return
        let y = (ts[0].left.y - ts[0].head.y) / 2.0
        var next: trias
        for it in ts:
            let (HEAD, LEFT, RIGHT) = it
            let left  = (HEAD.x - x, HEAD.y + y)
            let right = (HEAD.x + x, HEAD.y + y)
            let tail  = (HEAD.x, LEFT.y)
            fill left, right, tail
            next = next & @[(HEAD, left, right), (left, LEFT, tail), (right, 
tail, RIGHT)]
        
        draw( level - 1, next )
    
    proc go =
        let SIZE = size.int32
        surface = image_surface_create(TFORMAT.FORMAT_ARGB32, SIZE, SIZE)
        cr = surface.create
        cr.rectangle(0, 0, size, size)
        cr.fill
        cr.set_line_width 0.5
        let t1 = @[triangle()]
        discard draw(level, t1)
        discard surface.write_to_png image
    
    go()
    
    

the time: 
    
    
    perl: 2.3s
    nim: 9.0s [--cc=gcc, -d:release]
    

My question is: 
    
    
    1: Why it is so slow? my nim code.
    2: How to speed up my nim code?
    

Reply via email to