# Koch curve

Koch curve is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Draw Koch curve. See details: Koch curve

## C

Interactive program which takes the width, height (of the Graphics window) and recursion level of the Koch curve as inputs, prints out usage on incorrect invocation. Requires the WinBGIm library.

` #include<graphics.h>#include<stdlib.h>#include<stdio.h>#include<math.h> #define pi M_PI typedef struct{	double x,y;}point; void kochCurve(point p1,point p2,int times){	point p3,p4,p5;	double theta = pi/3; 	if(times>0){		p3 = (point){(2*p1.x+p2.x)/3,(2*p1.y+p2.y)/3};		p5 = (point){(2*p2.x+p1.x)/3,(2*p2.y+p1.y)/3}; 		p4 = (point){p3.x + (p5.x - p3.x)*cos(theta) + (p5.y - p3.y)*sin(theta),p3.y - (p5.x - p3.x)*sin(theta) + (p5.y - p3.y)*cos(theta)}; 		kochCurve(p1,p3,times-1);		kochCurve(p3,p4,times-1);		kochCurve(p4,p5,times-1);		kochCurve(p5,p2,times-1);	} 	else{		line(p1.x,p1.y,p2.x,p2.y);	}} int main(int argC, char** argV){	int w,h,r;	point p1,p2; 	if(argC!=4){		printf("Usage : %s <window width> <window height> <recursion level>",argV[0]);	} 	else{		w = atoi(argV[1]);		h = atoi(argV[2]);		r = atoi(argV[3]); 		initwindow(w,h,"Koch Curve"); 		p1 = (point){10,h-10};		p2 = (point){w-10,h-10}; 		kochCurve(p1,p2,r); 		getch(); 		closegraph();	} 	return 0;} `

## Go

Library: Go Graphics
Translation of: Ring
`package main import (    "github.com/fogleman/gg"    "math") var dc = gg.NewContext(512, 512) func koch(x1, y1, x2, y2 float64, iter int) {    angle := math.Pi / 3 // 60 degrees    x3 := (x1*2 + x2) / 3    y3 := (y1*2 + y2) / 3    x4 := (x1 + x2*2) / 3    y4 := (y1 + y2*2) / 3    x5 := x3 + (x4-x3)*math.Cos(angle) + (y4-y3)*math.Sin(angle)    y5 := y3 - (x4-x3)*math.Sin(angle) + (y4-y3)*math.Cos(angle)    if iter > 0 {        iter--        koch(x1, y1, x3, y3, iter)        koch(x3, y3, x5, y5, iter)        koch(x5, y5, x4, y4, iter)        koch(x4, y4, x2, y2, iter)    } else {        dc.LineTo(x1, y1)        dc.LineTo(x3, y3)        dc.LineTo(x5, y5)        dc.LineTo(x4, y4)        dc.LineTo(x2, y2)    }} func main() {    dc.SetRGB(1, 1, 1) // White background    dc.Clear()    koch(100, 100, 400, 400, 4)    dc.SetRGB(0, 0, 1) // Blue curve    dc.SetLineWidth(2)    dc.Stroke()    dc.SavePNG("koch.png")}`
Output:
```Image is similar to Ring entry.
```

## Kotlin

Translation of: Ring

This incorporates code from other relevant tasks in order to provide a runnable example. The image produced is saved to disk where it can be viewed with a utility such as EOG.

`// Version 1.2.41 import java.awt.Colorimport java.awt.Graphicsimport java.awt.image.BufferedImageimport kotlin.math.*import java.io.Fileimport javax.imageio.ImageIO val Double.asI get() = this.toInt() class Point(var x: Int, var y: Int) class BasicBitmapStorage(width: Int, height: Int) {    val image = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR)     fun fill(c: Color) {        val g = image.graphics        g.color = c        g.fillRect(0, 0, image.width, image.height)    }     fun setPixel(x: Int, y: Int, c: Color) = image.setRGB(x, y, c.getRGB())     fun getPixel(x: Int, y: Int) = Color(image.getRGB(x, y))     fun drawLine(x0: Int, y0: Int, x1: Int, y1: Int, c: Color) {        val dx = abs(x1 - x0)        val dy = abs(y1 - y0)        val sx = if (x0 < x1) 1 else -1        val sy = if (y0 < y1) 1 else -1        var xx = x0        var yy = y0        var e1 = (if (dx > dy) dx else -dy) / 2        var e2: Int        while (true) {            setPixel(xx, yy, c)            if (xx == x1 && yy == y1) break            e2 = e1            if (e2 > -dx) { e1 -= dy; xx += sx }            if (e2 <  dy) { e1 += dx; yy += sy }        }    }     fun koch(x1: Double, y1: Double, x2: Double, y2: Double, it: Int) {        val angle = PI / 3.0  // 60 degrees        val clr = Color.blue        var iter = it        val x3 = (x1 * 2.0 + x2) / 3.0        val y3 = (y1 * 2.0 + y2) / 3.0        val x4 = (x1 + x2 * 2.0) / 3.0        val y4 = (y1 + y2 * 2.0) / 3.0        val x5 = x3 + (x4 - x3) * cos(angle) + (y4 - y3) * sin(angle)        val y5 = y3 - (x4 - x3) * sin(angle) + (y4 - y3) * cos(angle)         if (iter > 0) {            iter--            koch(x1, y1, x3, y3, iter)            koch(x3, y3, x5, y5, iter)            koch(x5, y5, x4, y4, iter)            koch(x4, y4, x2, y2, iter)         }         else {            drawLine(x1.asI, y1.asI, x3.asI, y3.asI, clr)            drawLine(x3.asI, y3.asI, x5.asI, y5.asI, clr)            drawLine(x5.asI, y5.asI, x4.asI, y4.asI, clr)            drawLine(x4.asI, y4.asI, x2.asI, y2.asI, clr)         }    }} fun main(args: Array<String>) {    val width = 512    val height = 512    val bbs = BasicBitmapStorage(width, height)    with (bbs) {        fill(Color.white)        koch(100.0, 100.0, 400.0, 400.0, 4)        val kFile = File("koch_curve.jpg")        ImageIO.write(image, "jpg", kFile)    }}`
Output:
```Image is similar to Ring entry.
```

## Mathematica

`Graphics[{GeometricTransformation[KochCurve[5], RotationTransform[Pi, {0.5, 0}]],   GeometricTransformation[KochCurve[5], RotationTransform[-Pi/3, {1, 0}]],   GeometricTransformation[KochCurve[5], RotationTransform[Pi/3, {0, 0}]]}]`

## Perl 6

Works with: Rakudo version 2018.03

Koch curve, actually a full Koch snowflake.

`use SVG; role Lindenmayer {    has %.rules;    method succ {        self.comb.map( { %!rules{\$^c} // \$c } ).join but Lindenmayer(%!rules)    }} my \$flake = 'F--F--F' but Lindenmayer( { F => 'F+F--F+F' } ); \$flake++ xx 5;my @points = (50, 440); for \$flake.comb -> \$v {    state (\$x, \$y) = @points[0,1];    state \$d = 2 + 0i;    with \$v {        when 'F' { @points.append: (\$x += \$d.re).round(.01), (\$y += \$d.im).round(.01) }        when '+' { \$d *= .5 + .8660254i }        when '-' { \$d *= .5 - .8660254i }    }} say SVG.serialize(    svg => [        width => 600, height => 600, style => 'stroke:rgb(0,0,255)',        :rect[:width<100%>, :height<100%>, :fill<white>],        :polyline[ points => @points.join(','), :fill<white> ],    ],);`

See: Koch snowflake

Variation using 90° angles:

`use SVG; role Lindenmayer {    has %.rules;    method succ {	    self.comb.map( { %!rules{\$^c} // \$c } ).join but Lindenmayer(%!rules)    }} my \$koch = 'F' but Lindenmayer( { F => 'F+F-F-F+F', } ); \$koch++ xx 4;my @points = (450, 250); for \$koch.comb -> \$v {    state (\$x, \$y) = @points[0,1];    state \$d = -5 - 0i;    with \$v {        when 'F' { @points.append: (\$x += \$d.re).round(.01), (\$y += \$d.im).round(.01) }        when /< + - >/ { \$d *= "{\$v}1i" }    }} say SVG.serialize(    svg => [        width => 500, height => 300, style => 'stroke:rgb(0,0,255)',        :rect[:width<100%>, :height<100%>, :fill<white>],        :polyline[ points => @points.join(','), :fill<white> ],    ],);`

## QBasic

`    ' Chaos:  start at any point,  this program uses the middle of the screen  (or universe.  One of six    ' degrees of freedom (a direction)  is chosen at random  (by throwing a six-sided die),  and a line    ' is drawn from the old point to the new point in the direction indicated by the pip on the die.    '    ' The traverse distance is always a fraction of the last distance drawn;  the fraction (here) uses:    '    '                                       +-                                -+    '                                       |                                  |    '       distance  <===  old_distance *  |  1/2 - 1/8 - 1/32 - 1/128 - ...  |    '                                       |                                  |    '                                       +-                                -+    '            ---or---    '                                       +-                                -+    '                                       |   1     1     1      1           |    '       distance  <===  old_distance *  |  --- - --- - ---- - ----- - ...  |    '                                       |  2**1  2**3  2**5   2**7         |    '                                       +-                                -+    '    ' (The series above has a limit of  1/3.)    '    ' The six degrees of freedom:                      1         6    '    '                                                    \     /    '                                                     \   /    '                                                      \ /    '                                            2  <------ X ------>  5    '                                                      / \    '                                                     /   \    '                                                    /     \    '    '                                                  3         4    '    ' When the amount to be moved is too small to show on the terminal screen,  the chaos curve is    ' starting again  (from the initial point,  the middle of the screen/universe).    '    ' All subsequent chaos curves are superimposed on the first curve.    '    ' The envelope of this chaos curve is defined as the snowflake curve.    '    ' If any cursor key (one of the "arrow" keys) is pressed,  program execution is halted.    '    ' If any function key is pressed during execution, the random chaos curve is stopped, the screen    ' cleared, and the snowflake curve is drawn by a non-random method (brute force).    '    ' Once the random snowflake (chaos) curve is being drawn, the pressing of function keys 1-->9 will    ' force the randomness to move in a particular direction, the direction (the degree of freedom) is    ' the direction indicated by the number of times that function key is pressed for that curve point.    ' That is, function key 1 is used for the first point (part of the chaos curve),  function key 2 is    ' used for the second point, function key 3 for the third point,  etc.     DEFINT A-Y                    ' define variables that begin with   A-->Y   as integers.    DEFSNG Z                      ' define variables that begin with     Z     as single precision.    DIM XP(16,6),YP(16,6),KY(16)  ' define some (integer) arrays.    MP= 16                        ' set the maximum number of points (1st dimension) that can be plotted.    CLS                           ' clear the screen for visual fidelity.    SCREEN 2                      ' make the screen high-res graphics.    GOTO 230                      ' branch around a  RETURN  statement that  ON KEY(i) uses.220 RETURN230 FK= 0                         ' set FK  (used to indicate that a function key was pressed).       FOR I=1  TO 10              ' allow the use of function keys to stop the deliberate snowflake                                  ' curve and start drawing it randomly.      KY(I)= 0      ON KEY(I)  GOSUB 220        ' allow the trapping of function keys,  but don't process it as yet.      KEY(I)  ON      KEY(I) STOP      NEXT I     CLS                           ' clear the screen for visual fidelity.    ZZ= 2 + TIMER                 ' on some PCs, a pause of at least one second prevents scrolling.240 IF TIMER<ZZ  THEN GOTO 240    RANDOMIZE TIMER               ' randomize the RND function from the timer.    XM= 640 - 1                   ' define the number of points on the screen (for plotting).    YM= 200 - 1    XO= XM \ 2                    ' define the origin of the chaos curve.    YO= YM \ 2    ZT= 1 / 3                     ' define the traverse distance,  it's this distance that each part of                                  ' the chaos curve "breaks",  when the distance that the next part of                                  ' the chaos curve is moved to.    ZA= 1                         ' define the aspect ratio for the terminal screen.    ZX= XM * ZA                   ' define the initial distance to be plotted (for a line).    ZY= YM                        '    "    "     "        "     "  "    "      "  "   "           FOR I=1  TO MP         ' compute (once) all the  x & y  distances for each part of the curve.           ZX= ZX * ZT * ZA           ZY= ZY * ZT           XP(I, 1) = -ZX / 2           XP(I, 2) = -ZX           XP(I, 3) = -ZX / 2           XP(I, 4) =  ZX / 2           XP(I, 5) =  ZX           XP(I, 6) =  ZX / 2           YP(I, 1) = -ZY           YP(I, 2) =   0           YP(I, 3) =  ZY           YP(I, 4) =  ZY           YP(I, 5) =   0           YP(I, 6) = -ZY           NEXT I    N0=0           FOR II=1  TO MP        ' find the maximum number of points that can be plotted.             FOR I=1  TO 6             IF XP(II, I) <> 0  THEN N0= II             IF YP(II, I) <> 0  THEN N0= II             NEXT I           NEXT II            FOR I=11  TO 14        ' quit if any cursor key is pressed.           ON KEY(I)  GOSUB 598           KEY(I)  ON           NEXT I            FOR I=1  TO 10         ' If any function key is pressed during execution, the deliberate           ON KEY(I)  GOSUB 400   ' curve is stopped,  the screen is cleared, and the snowflake curve is           KEY(I)  ON             ' drawn by a random process  (AKA,  the chaos curve).           NEXT I     GOTO 500400 FK= 1                         ' come here when any function or cursor key is pressed,  and set  FK                                  ' that is checked by the deliberate snowflake curve generator.    RETURN500 CLS                           ' clear the screen before starting  (for visual fidelity).                  FOR I1=1  TO 6  ' plot the curve via non-random (deliberate calculation) points.                  X1= XO  +  XP(1, I1)                  Y1= YO  +  YP(1, I1)                  IF FK  THEN GOTO 600                  LINE (XO, YO)  -  (X1, Y1)                    FOR I2=1  TO 6                    X2= X1  +  XP(2,I2)                    Y2= Y1  +  YP(2,I2)                    IF FK  THEN GOTO 600                    LINE (X1, Y1)  -  (X2, Y2)                      FOR I3=1  TO 6                      X3= X2  +  XP(3, I3)                      Y3= Y2  +  YP(3, I3)                      IF FK  THEN GOTO 600                      LINE (X2, Y2)  -  (X3, Y3)                        FOR I4=1  TO 6                        X4= X3  +  XP(4, I4)                        Y4= Y3  +  YP(4, I4)                        IF FK  THEN GOTO 600                        LINE (X3, Y3)  -  (X4, Y4)                          FOR I5=1  TO 6                          X5= X4  +  XP(5, I5)                          Y5= Y4  +  YP(5, I5)                          IF FK  THEN GOTO 600                          LINE (X4, Y4)  -  (X5, Y5)                          NEXT I5                        NEXT I4                      NEXT I3                    NEXT I2                  NEXT I1    ZZ= 10+TIMER                  ' The snowflake curve is now complete.555 IF TIMER<ZZ  THEN GOTO 555    ' loop for ten seconds.598 SYSTEM                        ' stick a fork in it, we're all done.600 ON  KEY(1)   GOSUB 710        ' trap all function keys for toggling.    ON  KEY(2)   GOSUB 720    ON  KEY(3)   GOSUB 730    ON  KEY(4)   GOSUB 740    ON  KEY(5)   GOSUB 750    ON  KEY(6)   GOSUB 760    ON  KEY(7)   GOSUB 770    ON  KEY(8)   GOSUB 780    ON  KEY(9)   GOSUB 790    ON  KEY(10)  GOSUB 700               FOR I=1  TO MP      ' re-active trapping all the function keys.              KEY(I)  ON              NEXT I    CLS                           ' clear the screen before starting.    GOTO 900                      ' go and start drawing the chaos curve.700           FOR I0=1  TO MP     ' reset all toggle settings for all points.              KY(I0)= 0              NEXT I0    RETURN710 KI= 1                         ' toggle setting for point #1 (bypass).              GOTO 800720 KI= 2                         ' toggle setting for point #2 (bypass).              GOTO 800730 KI= 3                         ' toggle setting for point #3 (bypass).              GOTO 800740 KI= 4                         ' toggle setting for point #4 (bypass).              GOTO 800750 KI= 5                         ' toggle setting for point #5 (bypass).              GOTO 800760 KI= 6                         ' toggle setting for point #6 (bypass).              GOTO 800770 KI= 7                         ' toggle setting for point #7 (bypass).              GOTO 800780 KI= 8                         ' toggle setting for point #8 (bypass).              GOTO 800790 KI= 9                         ' toggle setting for point #9 (bypass).800 KY(KI)= (1 + KY(KI) )  MOD 7  ' reset toggle settings for all higher points.               FOR IK=KI+1  TO MP              KY(IK)= 0              NEXT IK    RETURN900 N= 0                          ' initialize the number of points in this particular chaos curve.    X= XO                         ' move the start-of-the-chaos-curve to the origin.    Y= YO    LINE (X, Y)  -  (X, Y)    N= N + 1                      ' bump number of points drawn so far.    IF N>N0   THEN GOTO 900       ' # points drawn exceeds possible?  Start another chaos curve.                                  ' start of diminishing loop to create an envelope for the chaos curve.    IF KY(N)  THEN R= KY(N)   ELSE R= 1 + INT(RND*6)    X= X  +  XP(N, R)             ' exercise a degree of freedom (one of six).    Y= Y  +  YP(N, R)    LINE -(X, Y)                  ' depending on the "die",  draw the next part of the chaos curve.                   GOTO 900       ' now, go and do another point.`

## Ring

` # Project : Koch curve load "guilib.ring" paint = null new qapp         {        win1 = new qwidget() {                  setwindowtitle("Koch curve")                  setgeometry(100,100,500,600)                  label1 = new qlabel(win1) {                              setgeometry(10,10,400,400)                              settext("")                  }                  new qpushbutton(win1) {                          setgeometry(150,500,100,30)                          settext("draw")                          setclickevent("draw()")                  }                  show()        }        exec()        } func draw        p1 = new qpicture()               color = new qcolor() {               setrgb(0,0,255,255)        }        pen = new qpen() {                 setcolor(color)                 setwidth(1)        }        paint = new qpainter() {                  begin(p1)                  setpen(pen)         koch(100, 100, 400, 400, 4)         endpaint()        }        label1 { setpicture(p1) show() } func koch x1, y1, x2, y2, it         angle = 60*3.14/180        x3 = (2*x1+x2)/3        y3 = (2*y1+y2)/3         x4 = (x1+2*x2)/3        y4 = (y1+2*y2)/3         x = x3 + (x4-x3)*cos(angle)+(y4-y3)*sin(angle)        y = y3 - (x4-x3)*sin(angle)+(y4-y3)*cos(angle)        if (it > 0)          koch(x1, y1, x3, y3, it-1)          koch(x3, y3, x, y, it-1)          koch(x, y, x4, y4, it-1)          koch(x4, y4, x2, y2, it-1)       else          paint.drawline(x1, y1, x3, y3)          paint.drawline(x3, y3, x, y)          paint.drawline(x, y, x4, y4)          paint.drawline(x4, y4, x2, y2)      ok `

Output image:

## Sidef

Using the LSystem class defined at Hilbert curve.

`var rules = Hash(    F => 'F+F--F+F',) var lsys = LSystem(    width:  800,    height: 800,     xoff: -210,    yoff: -90,     len:   8,    angle: 60,    color: 'dark green',) lsys.execute('F--F--F', 4, "koch_snowflake.png", rules)`

Output image: Koch snowflake

## zkl

Translation of: Ring

Uses Image Magick and the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl

`var width=512, height=512, img=PPM(width,height,0xFfffFF);   // white canvasvar angle=(60.0).toRad();const green=0x00FF00; fcn koch(x1,y1, x2,y2, it){   x3,y3 := (x1*2 + x2)  /3, (y1*2 + y2)  /3;   x4,y4 := (x1   + x2*2)/3, (y1   + y2*2)/3;   x:=x3 + (x4-x3)*angle.cos() + (y4-y3)*angle.sin();   y:=y3 - (x4-x3)*angle.sin() + (y4-y3)*angle.cos();    if(it>0){      it-=1;      koch(x1,y1, x3,y3, it);      koch(x3,y3, x, y,  it);      koch(x, y,  x4,y4, it);      koch(x4,y4, x2,y2, it);   }else{      x,y, x1,y1, x2,y2, x3,y3, x4,y4 =          T(x,y, x1,y1, x2,y2, x3,y3, x4,y4).apply("toInt");      img.line(x1,y1, x3,y3, green);      img.line(x3,y3, x, y,  green);      img.line(x, y,  x4,y4, green);      img.line(x4,y4, x2,y2, green);   }} koch(100.0,100.0, 400.0,400.0, 4);img.writeJPGFile("koch.zkl.jpg");`

Image at koch curve

Using a Lindenmayer system and turtle graphics to draw a Koch snowflake:

`lsystem("F--F--F", Dictionary("F","F+F--F+F"), "+-", 4)  // snowflake//lsystem("F", Dictionary("F","F+F--F+F"), "+-", 3)	 // curve: turtle(_); fcn lsystem(axiom,rules,consts,n){	// Lindenmayer system --> string   foreach k in (consts){ rules.add(k,k) }   buf1,buf2 := Data(Void,axiom).howza(3), Data().howza(3);  // characters   do(n){      buf1.pump(buf2.clear(), rules.get);      t:=buf1; buf1=buf2; buf2=t;	// swap buffers   }   buf1.text		// n=4 snow flake --> 1,792 characters} fcn turtle(koch){   const D=10.0;   dir,deg60, x,y := 0.0, (60.0).toRad(), 20.0, 710.0; // turtle; x,y are float   img,color := PPM(850,950), 0x00ff00;   foreach c in (koch){      switch(c){	 case("F"){   // draw forward	    dx,dy := D.toRectangular(dir);	    tx,ty := x,y; x,y = (x+dx),(y+dy);	    img.line(tx.toInt(),ty.toInt(), x.toInt(),y.toInt(), color);	 }	 case("-"){ dir-=deg60 } // turn right 60*	 case("+"){ dir+=deg60 } // turn left  60*      }   }   img.writeJPGFile("kochSnowFlake.zkl.jpg");}`

Image at Koch snow flake