# # data structures # length = 300; center = ['x' = 200; 'y' = 250;]; radius = 2 * length / sqrt (12); fractalangle = 0; maxlevel = 2; sizes = [ 'button' = [ 'x' = 100; 'y' = 40; ]; 'canvas' = [ 'x' = 400; 'y' = 500; ]; 'view' = [ 'x' = 400; 'y' = 600; ]; ]; sq = function (x) { return x * x; }; # # create view and other widgets # init = function () { view = createwidget (-1, [ 'type' = 'view'; 'name' = 'fractal'; 'size' = sizes.view; ]); array1 = createwidget (view, [ 'type' = 'array'; 'borderwidth' = 1; 'mode' = 'vertical'; ]); widgets[array1].resize = resize; array2 = createwidget (array1, [ 'type' = 'array'; 'borderwidth' = 1; 'mode' = 'horizontal'; ]); widgets[array2].resize = resize; array3 = createwidget (array2, [ 'type' = 'array'; 'borderwidth' = 1; 'mode' = 'vertical'; ]); widgets[array3].resize = resize; morebutton = createwidget (array3, [ 'type' = 'button'; 'text' = 'more'; ]); widgets[morebutton].pressed = pressed; lessbutton = createwidget (array3, [ 'type' = 'button'; 'text' = 'less'; ]); widgets[lessbutton].pressed = pressed; setwidgetattr (morebutton, ['size' = sizes.button;]); setwidgetattr (lessbutton, ['size' = sizes.button;]); atext = createwidget (array2, [ 'type' = 'text'; 'mode' = 'oneline'; ]); widgets[atext].oneline = oneline; setwidgetattr (atext, [ 'size' = ['x' = sizes.button.x; 'y' = sizes.button.y * 2;]; ]); scroll = createwidget (array1, ['type' = 'scroll';]); canvas = createwidget (scroll, ['type' = 'canvas';]); wrect = [0 = ['x' = 0; 'y' = 0;]; 1 = sizes.canvas;]; setwidgetattr (canvas, ['window' = wrect; 'viewport' = wrect[1];]); }; # # drawing functions # # draw a Koch curve (a ``snowflake'' fractal) # # start with a triangle and keep replacing edges # with the construct: _/\_ # until the recursion level reaches 'maxlevel' # fractal = function (level, length, angle) { local nlength, newpenpos; if (level >= maxlevel) { newpenpos.x = penpos.x + length * cos (angle); newpenpos.y = penpos.y + length * sin (angle); line (canvas, null, penpos, newpenpos, ['color' = 1;]); penpos = newpenpos; return; } nlength = length / 3; fractal (level + 1, nlength, angle); fractal (level + 1, nlength, angle + 60); fractal (level + 1, nlength, angle - 60); fractal (level + 1, nlength, angle); }; redrawfractal = function () { clear (canvas); setpick (canvas, center, wrect); penpos = [ 'x' = center.x + cos (fractalangle + 210) * radius; 'y' = center.y + sin (fractalangle + 210) * radius; ]; fractal (0, length, fractalangle + 60); fractal (0, length, fractalangle - 60); fractal (0, length, fractalangle - 180); remove ('penpos'); }; # # editing functions # # transform the fractal. # # map point 'prevpoint' to point 'currpoint' # with respect to the center of the fractal. # transformfractal = function (prevpoint, currpoint) { local prevtan, currtan, prevradius, currradius; prevtan = atan (prevpoint.y - center.y, prevpoint.x - center.x); currtan = atan (currpoint.y - center.y, currpoint.x - center.x); fractalangle = fractalangle + (currtan - prevtan); prevradius = sqrt (sq (prevpoint.y - center.y) + sq (prevpoint.x - center.x)); currradius = sqrt (sq (currpoint.y - center.y) + sq (currpoint.x - center.x)); radius = radius / prevradius * currradius; length = radius / 2 * sqrt (12); }; # # main actions # redraw = function (data) { redrawfractal (); }; changemaxlevel = function (dn) { maxlevel = maxlevel + dn; if (maxlevel < 0) maxlevel = 0; redrawfractal (); }; resize = function (data) { local ret; if (data.widget == array1) { ret = [ array2 = [ 'x' = data.size.x; 'y' = sizes.button.y * 2; ]; scroll = [ 'x' = data.size.x; 'y' = data.size.y - sizes.button.y * 2; ]; ]; } else if (data.widget == array2) { ret = [ array3 = [ 'x' = sizes.button.x; 'y' = 2 * sizes.button.y; ]; atext = [ 'x' = data.size.x - sizes.button.x; 'y' = 2 * sizes.button.y; ]; ]; } else if (data.widget == array3) { ret = [ morebutton = sizes.button; lessbutton = sizes.button; ]; } return ret; }; # # user interface functions # # bind changes to the fractal to user actions # leftup = function (data) { transformfractal (data.ppos, data.pos); redrawfractal (); }; menu = [ 0 = 'more'; 1 = 'less'; ]; domenu = function (i) { local s; s = menu[i]; if (s == 'more') changemaxlevel (1); else if (s == 'less') changemaxlevel (-1); }; rightdown = function (data) { domenu (displaymenu (canvas, menu)); }; pressed = function (data) { if (data.widget == morebutton) changemaxlevel (1); else if (data.widget == lessbutton) changemaxlevel (-1); }; oneline = function (data) { local dn; dn = ston (data.text); if (dn > 0 | dn < 0) changemaxlevel (dn - maxlevel); }; # # postscript generation # dops = function () { local r; r = [0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 8 * 300; 'y' = 10.5 * 300;];]; canvas = opencanvas ('pscanvas', '', r); setwidgetattr (canvas, ['window' = wrect;]); redraw (); closecanvas (canvas); canvas=defcanvas; }; init (); #txtview ('off');