Daniel@0: load ('def.lefty'); Daniel@0: definit (); Daniel@0: # Daniel@0: # initialize window data Daniel@0: # Daniel@0: canvas = defcanvas; Daniel@0: wrect = [0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 400; 'y' = 500;];]; Daniel@0: setwidgetattr (canvas, ['window' = wrect;]); Daniel@0: Daniel@0: sq = function (x) { Daniel@0: return x * x; Daniel@0: }; Daniel@0: Daniel@0: # data structures Daniel@0: # Daniel@0: length = 300; Daniel@0: center = ['x' = 200; 'y' = 250;]; Daniel@0: radius = 2 * length / sqrt (12); Daniel@0: fractalangle = 0; Daniel@0: maxlevel = 2; Daniel@0: Daniel@0: # drawing functions Daniel@0: # Daniel@0: # draw a Koch curve (a ``snowflake'' fractal) Daniel@0: # Daniel@0: # start with a triangle and keep replacing edges Daniel@0: # with the construct: _/\_ Daniel@0: # until the recursion level reaches 'maxlevel' Daniel@0: # Daniel@0: fractal = function (level, length, angle) { Daniel@0: local nlength, newpenpos; Daniel@0: Daniel@0: if (level >= maxlevel) { Daniel@0: newpenpos.x = penpos.x + length * cos (angle); Daniel@0: newpenpos.y = penpos.y + length * sin (angle); Daniel@0: line (canvas, null, penpos, newpenpos, ['color' = 1;]); Daniel@0: penpos = newpenpos; Daniel@0: return; Daniel@0: } Daniel@0: nlength = length / 3; Daniel@0: fractal (level + 1, nlength, angle); Daniel@0: fractal (level + 1, nlength, angle + 60); Daniel@0: fractal (level + 1, nlength, angle - 60); Daniel@0: fractal (level + 1, nlength, angle); Daniel@0: }; Daniel@0: drawfractal = function () { Daniel@0: clear (canvas); Daniel@0: setpick (canvas, center, wrect); Daniel@0: penpos = [ Daniel@0: 'x' = center.x + cos (fractalangle + 210) * radius; Daniel@0: 'y' = center.y + sin (fractalangle + 210) * radius; Daniel@0: ]; Daniel@0: fractal (0, length, fractalangle + 60); Daniel@0: fractal (0, length, fractalangle - 60); Daniel@0: fractal (0, length, fractalangle - 180); Daniel@0: remove ('penpos'); Daniel@0: }; Daniel@0: Daniel@0: # editing functions Daniel@0: # Daniel@0: # transform the fractal. Daniel@0: # Daniel@0: # map point 'prevpoint' to point 'currpoint' Daniel@0: # with respect to the center of the fractal. Daniel@0: # Daniel@0: transformfractal = function (prevpoint, currpoint) { Daniel@0: local prevtan, currtan, prevradius, currradius; Daniel@0: Daniel@0: prevtan = atan (prevpoint.y - center.y, prevpoint.x - center.x); Daniel@0: currtan = atan (currpoint.y - center.y, currpoint.x - center.x); Daniel@0: fractalangle = fractalangle + (currtan - prevtan); Daniel@0: prevradius = sqrt ( Daniel@0: sq (prevpoint.y - center.y) + sq (prevpoint.x - center.x) Daniel@0: ); Daniel@0: currradius = sqrt ( Daniel@0: sq (currpoint.y - center.y) + sq (currpoint.x - center.x) Daniel@0: ); Daniel@0: radius = radius / prevradius * currradius; Daniel@0: length = radius / 2 * sqrt (12); Daniel@0: }; Daniel@0: Daniel@0: # user interface functions Daniel@0: # Daniel@0: # bind changes to the fractal to user actions Daniel@0: # Daniel@0: leftup = function (data) { Daniel@0: transformfractal (data.ppos, data.pos); Daniel@0: drawfractal (); Daniel@0: }; Daniel@0: dops = function () { Daniel@0: local s; Daniel@0: Daniel@0: s = ['x' = 8 * 300; 'y' = 10.5 * 300;]; Daniel@0: canvas = createwidget (-1, ['type' = 'ps'; 'size' = s;]); Daniel@0: setwidgetattr (canvas, ['window' = wrect;]); Daniel@0: drawfractal (); Daniel@0: destroywidget (canvas); Daniel@0: canvas=defcanvas; Daniel@0: }; Daniel@0: transformfractal (['x' = 0; 'y' = 0;], ['x' = 0; 'y' = 0;]); Daniel@0: drawfractal ();