home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
07
/
recursiv.asc
< prev
next >
Wrap
Text File
|
1991-06-11
|
22KB
|
610 lines
_RECURSIVE IMAGES_
by Steven Janke
[LISTING ONE]
PROGRAM RECURTRE;
uses graph;
var inc,firstdirection :real;
gd,gm,depth,scale :integer;
startx,starty :integer;
xasp,yasp :word;
asp :real;
const pi:real=3.14159;
procedure TREE(X,Y:integer; DIR:real; LEVEL:integer);
var xnew,ynew:integer;
begin
if level>0 then {At level zero, recursion ends.}
begin
xnew:= round(level*scale*cos(dir))+x; {Multiplying by level }
ynew:= round(asp*level*scale*sin(dir))+y; {varies the branch size.}
if level<3 then setcolor(green) else setcolor(brown); {Green leaves}
line(x,y,xnew,ynew);
TREE(xnew,ynew,dir+random*inc,level-1); {Two recursive calls - one}
TREE(xnew,ynew,dir-random*inc,level-1); {for each new branch.}
end;
end;
procedure INIT;
begin
firstdirection:=-pi/2; {Negative since y increases down the screen.}
inc:=pi/4;
scale:=5;
depth:=10;
startx:=round(GETMAXX/2); starty:=round(0.75*GETMAXY);
GETAspectRatio(xasp,yasp); asp:=xasp/yasp; {Find aspect ratio}
end;
BEGIN
gd:=detect;
initgraph(gd,gm,'\tp\units'); {Graphic drivers kept in \tp\units.}
cleardevice; randomize;
INIT;
TREE(startx, starty, firstdirection, depth);
readln;
closegraph;
END.
[LISTING TWO]
PROGRAM IFSDRAW; {Random Algorithm for drawing IFS attractor.}
uses graph;
var gd, gm :integer; {For graphics initialization}
xoff, yoff :integer; {Offset to determine origin}
xsc, ysc :real; {Scale variables}
n, cl :integer; {Index variable, color variable}
x,y,asp :real; {Starting point and aspect ratio}
xasp,yasp :word; {Used to determine aspect ratio}
const {Normally, these constants would be read from a data file. They
are listed as constants here only for illustration. These
particular transformations form an IFS for Sierpinski's triangle.}
Totaltran:integer=3;
CT:array[1..3,1..7] of real =
{Format: a, b, c, d, e, f, probability}
(( 0.5, 0, 0, 0, 0.5, 0, 0.33),
( 0.5, 0, 100, 0, 0.5, 0, 0.33),
( 0.5, 0, 50, 0, 0.5, -100, 0.33));
procedure SETPROB;
{To get a running sum of the probabilities for random number generation.}
var i:integer;
sum:real;
begin
sum:=0;
for i:=1 to totaltran-1 do
begin sum:=sum+CT[i,7]; CT[i,7]:=sum; end;
CT[totaltran,7]:=1; {This is set to 1 to avoid any round-off problem.}
end;
procedure MAKETRAN;
{Determine which transformation is next and then apply it.}
var nx,ny:real;
s:integer;
function FINDTRAN:integer;
{Return a random number between 1 and the number of transformations.}
var i:integer;
w:real;
begin
w:=random; i:=1;
while w>CT[i,7] do i:=i+1;
FINDTRAN:=i;
end;
begin
S:=FINDTRAN;
NX:=CT[S,1]*X + CT[S,2]*Y + CT[S,3];
NY:=CT[S,4]*X + CT[S,5]*Y + CT[S,6];
X:=NX; Y:=NY;
end;
procedure INIT;
begin
XSC:=1; YSC:=1; {Scale factors}
XOFF:=round(GETMAXX/2); YOFF:=round(GETMAXY/2); {Determines origin}
X:=0; Y:=0; {Starting point}
cl:=white;
GETAspectRatio(xasp,yasp); {BGI function for determining aspect ratio}
asp:=xasp/yasp;
end;
BEGIN
gd:=detect; initgraph(gd,gm,' '); cleardevice;
INIT; SETPROB;
for N:=1 to 5000 do
begin
MAKETRAN;
putpixel(round(X*XSC)+XOFF, (round(asp*Y*YSC)+YOFF),cl);
end;
readln;
closegraph;
END.
[LISTING THREE]
PROGRAM IFS; {ITERATED FUNCTION SYSTEM DESIGNER}
uses graph,crt;
type matrix = array[1..2,1..3] of real;
var points:array[1..100,1..2] of integer; {Points and Pts store vertices}
pts:array[1..100,1..2] of real; {of main figure.}
gd,gm: integer; {For graphics initialization.}
cp:integer; {Total number of vertices in main figure.}
xoff,yoff:integer; {Offset for main figure placement.}
asp,xt,yt:real; {Aspect ratio and offsets for transformation.}
select:boolean; {For menu selection.}
tran:matrix; {Coefficients of current transformation.}
tranlist: array[1..50] of matrix; {List of transformations}
totaltran:integer; {Total number of transformations.}
procedure APPLYTRAN; {--------------------------------------------}
{Applies the current transformation to the vertices of main figure.}
var i:integer;
a:real;
begin
for i:=1 to cp do
begin
a:=tran[1,1]*pts[i,1]+tran[1,2]*pts[i,2];
pts[i,2]:=tran[2,1]*pts[i,1]+tran[2,2]*pts[i,2];
pts[i,1]:=a;
end;
end;
procedure INIT; {-------------------------------------------------}
var xasp,yasp:word;
begin
cp:=1;
xoff:=round(GETMAXX/2); yoff:=round(GETMAXY/2);
xt:=0; yt:=0;
GETASPECTRATIO(Xasp,Yasp); asp:=xasp/yasp;
totaltran:=0;
end;
procedure INITTRAN; {---------------------------------------------}
begin
tran[1,1]:=1; tran[1,2]:=0; tran[2,1]:=0; tran[2,2]:=1;
end;
procedure SAVETRAN(n:integer); {----------------------------------}
begin
tranlist[n]:=tran;
tranlist[n,1,3]:=xt; tranlist[n,2,3]:=yt;
xt:=0; yt:=0;
end;
procedure CONVPOINTS; {-------------------------------------------}
{Converts screen coordinates in Points to world coordinates in Pts.}
var i:integer;
begin
for i:=1 to cp do
begin
pts[i,1]:=points[i,1]-xoff;
pts[i,2]:=(points[i,2]-yoff)/asp;
end;
end;
procedure DRAWFIG(col:integer); {---------------------------------}
var i,holdcol:integer;
begin
holdcol:=getcolor; setcolor(col);
for i:=1 to cp-1 do
line(round(pts[i,1]+xoff+xt),round(pts[i,2]*asp+yoff+yt*asp),
round(pts[i+1,1]+xoff+xt),round(pts[i+1,2]*asp+yoff+yt*asp));
setcolor(holdcol);
end;
procedure REDRAW(N:integer); {-------------------------------------}
{Redraws orignial figure plus the results of each transformation.}
{Transformation number N is not drawn.}
var i:integer;
begin
xt:=0; yt:=0;
cleardevice; CONVPOINTS; DRAWFIG(blue);
for i:=1 to totaltran do
if i<>n then
begin
CONVPOINTS; tran:=tranlist[i];
xt:=tranlist[i,1,3]; yt:=tranlist[i,2,3];
APPLYTRAN;
DRAWFIG(red);
end;
xt:=0; yt:=0;
end;
procedure SCALE(xsize,ysize:real); {-------------------------------}
{Changes the size of a figure.}
var i,j:integer;
begin
for i:=1 to cp do
begin pts[i,1]:=xsize*pts[i,1];
pts[i,2]:=ysize*pts[i,2];
end;
for i:=1 to 2 do tran[1,i]:=xsize*tran[1,i];
for i:=1 to 2 do tran[2,i]:=ysize*tran[2,i];
end;
procedure POSITION; {---------------------------------------------}
{Positions figure as a new transformation is constructed.}
var k:char;
xx,yy:integer;
procedure DIRECTIONS; {....................................}
begin
gotoxy(1,16); writeln('SCALE (S/W)');
writeln('SCALEX (A/Q)');
writeln('SCALEY (D/E)');
writeln('ROTATE (R/F)');
writeln('ROTATEX (T/G)');
writeln('ROTATEY (Y/H)');
writeln('REFLECT (X)');
writeln('Use ARROWS to translate.');
gotoxy(1,25); write('... Press Enter when finished ...');
end;
procedure REFLECT; {......................................}
{Flips the figure around the line x=y.}
var i:integer;
xx:real;
begin
for i:=1 to cp do
begin xx:=pts[i,1]; pts[i,1]:=pts[i,2]; pts[i,2]:=xx; end;
xx:=tran[1,1]; tran[1,1]:=tran[2,1]; tran[2,1]:=xx;
xx:=tran[1,2]; tran[1,2]:=tran[2,2]; tran[2,2]:=xx;
end;
procedure ROTATE(xangle,yangle:real); {...................}
{Rotates the figure. If xangle and yangle are unequal, rotation}
{is skewed.}
var i,j:integer;
a,b,xca,xsa,yca,ysa:real;
begin
xca:=cos(xangle); xsa:=sin(xangle);
yca:=cos(yangle); ysa:=sin(yangle);
for i:=1 to cp do
begin
a:=pts[i,1]*xca-pts[i,2]*ysa;
pts[i,2]:=pts[i,1]*xsa+pts[i,2]*yca;
pts[i,1]:=a;
end;
a:=tran[1,1]*xca-tran[2,1]*ysa;
b:=tran[1,2]*xca-tran[2,2]*ysa;
tran[2,1]:=tran[1,1]*xsa+tran[2,1]*yca;
tran[2,2]:=tran[1,2]*xsa+tran[2,2]*yca;
tran[1,1]:=a; tran[1,2]:=b;
end;
procedure WRITETRAN; {......................................}
var i,j:integer;
begin
gotoxy(1,3); writeln('Current Transformation: ');
for i:=1 to 2 do
begin
for j:=1 to 2 do
begin
gotoxy(1+(j-1)*10, 5+(i-1));
writeln(tran[i,j]:7:2);
end;
gotoxy(21, 5+(i-1));
if i=1 then writeln(xt:7:2) else writeln(yt:7:2);
end;
end;
begin
xx:=round(xt); yy:=round(asp*yt);
WRITETRAN; DIRECTIONS;
k:=readkey;
while ord(k)<>13 do
begin
DRAWFIG(green);
case ord(k) of
0: begin
k:=readkey;
case ord(k) of
72: yy:=yy-3;
77: xx:=xx+4;
80: yy:=yy+3;
75: xx:=xx-4;
end;
end;
83,115: scale(0.9,0.9); { S for decrease }
87,119: scale(1.1,1.1); { W for increase }
65,97 : scale(0.9,1); { A for x decrease }
68,100: scale(1,0.9); { D for y decrease }
81,113: scale(1.1,1); { Q for x increase }
69,101: scale(1,1.1); { E for y decrease }
82,114: rotate(0.1,0.1); { R for rotate cw }
70,102: rotate(-0.1,-0.1); { F for rotate ccw }
84,116: rotate(-0.1,0); { T for x rotate cw }
71,103: rotate(0.1,0); { G for x rotate ccw }
89,121: rotate(0,-0.1); { Y for y rotate cw }
72,104: rotate(0,0.1); { H for y rotate ccw }
88,120: reflect; { X to reflect in x=y }
end;
xt:=xx; yt:=yy/asp; DRAWFIG(green);
WRITETRAN;
k:=readkey;
end;
end;
procedure SHAPE; {-------- SECTION I ------------------------------}
{Sets up the main figure.}
var i,j,er:integer;
k:char;
procedure BOX(x,y,col:integer); {..........................}
var vs,hs,holdcol:integer;
begin
hs:=3; vs:=2; holdcol:=getcolor; setcolor(col);
line(x-hs,y-vs,x+hs,y-vs);
line(x+hs,y-vs,x+hs,y+vs);
line(x+hs,y+vs,x-hs,y+vs);
line(x-hs,y+vs,x-hs,y-vs);
setcolor(holdcol);
end;
begin
gotoxy(1,1); writeln('ITERATED FUNCTION SYSTEM DESIGNER');
writeln('Section I: Draw outline of desired figure ....');
gotoxy(1,23); writeln('Use arrows to position cursor.');
writeln('Press P to place a vertex.');
write('Press Enter when finished.');
i:=xoff; j:=yoff; setwritemode(xorput);
BOX(i,j,white);
k:=readkey; er:=1; {Variable er used to determine when to draw box.}
while ord(k)<>13 do
begin
case ord(k) of
0: begin if er=1 then BOX(i,j,white); er:=1;
k:=readkey;
case ord(k) of
72: j:=j-6;
77: i:=i+8;
80: j:=j+6;
75: i:=i-8;
end;
BOX(i,j,white);
end;
80,112: begin er:=0; points[cp,1]:=i; points[cp,2]:=j;
if cp>1 then begin setcolor(blue);
line(points[cp-1,1],points[cp-1,2],
points[cp,1], points[cp,2]);
setcolor(white); end;
cp:=cp+1;
end;
end;
k:=readkey;
end;
points[cp,1]:=points[1,1]; points[cp,2]:=points[1,2];
setcolor(blue);
line(points[cp-1,1],points[cp-1,2],points[1,1],points[1,2]);
setcolor(white); setwritemode(copyput);
end;
procedure MAKETRAN; {---------- SECTION II ------------------------}
{Allows construction and alteration of transformations.}
var nt,choice:integer;
s,me:char;
function MENUII:integer; {........................................}
var xn:integer;
begin
gotoxy(1,1); writeln('1. Another Transformation');
writeln('2. Next Transformation');
writeln('3. Prepare to Draw');
gotoxy(1,5); writeln('Select Number: '); me:=readkey;
while (ord(me)<49) or (ord(me)>51) do me:=readkey;
MENUII:=ord(me)-48;
gotoxy(1,1);
for xn:=1 to 5 do writeln(' ');
end;
begin
gotoxy(1,1); writeln('Section II: Build Transformations ...');
choice:=1; nt:=0;
if totaltran<>0 then choice:=2;
while choice<>3 do
begin
if choice=2 then
begin nt:=nt+1;
if nt>totaltran then nt:=1;
REDRAW(nt);
tran:=tranlist[nt];
xt:=tranlist[nt,1,3]; yt:=tranlist[nt,2,3];
end
else begin INITTRAN; totaltran:=totaltran+1;
nt:=totaltran;end;
CONVPOINTS;
if choice=2 then APPLYTRAN else SCALE(0.5,0.5);
setwritemode(xorput);
DRAWFIG(green);
POSITION;
setwritemode(copyput);
SAVETRAN(NT);
REDRAW(0);
CHOICE:=MENUII;
end;
cleardevice;
end;
procedure GENERATE; {------------ SECTION III ---------------------}
{Draw the resulting picture by applying transformations at random.}
var xx,nm,wh,bd,cl,choice:integer;
x,y:real;
me:char;
probs:array[1..50] of real;
procedure ASSIGNPROB; {....................................}
{Determines probability of each transformation.}
var i:integer;
s:real;
begin
for i:=1 to totaltran do
begin
tran:=tranlist[i];
probs[i]:=abs(tran[1,1]*tran[2,2] - tran[1,2]*tran[2,1]);
if probs[i]<0.02 then probs[i]:=0.02;
end;
s:=0; for i:=1 to totaltran do s:=s+probs[i];
for i:=1 to totaltran do probs[i]:=probs[i]/s;
s:=0; for i:=1 to totaltran do begin s:=s+probs[i]; probs[i]:=s; end;
probs[i]:=1;
end;
function PICK:integer; {..................................}
{Picks a transformation with designated probability distribution.}
var j:integer;
p:real;
begin
p:=random; j:=1;
while p>probs[j] do j:=j+1;
PICK:=j;
end;
procedure APPLY(w:integer); {..............................}
{Applies chosen transformation to current point X,Y.}
var z:real;
begin
tran:=tranlist[w];
z:=tran[1,1]*X+tran[1,2]*Y;
Y:=tran[2,1]*X+tran[2,2]*Y;
X:=z+tran[1,3];
Y:=Y+tran[2,3];
end;
procedure PUTIT(cc:integer); {.............................}
begin
if cl=0 then cc:=white;
putpixel(round(X+xoff),round(Y*asp+yoff),cc);
end;
procedure MENUIII; {.......................................}
var s:string;
xx:integer;
begin
bd:=0;cl:=0;
gotoxy(1,3); write('1. Border (Toggles)');
gotoxy(25,3); writeln('Excluded');
write('2. Color (Toggles)');
gotoxy(25,4); writeln('No');
writeln('3. Draw Image');
writeln;writeln('Select Number: ');
me:='5';
while (ord(me)<>51) do
begin
me:=readkey;
while (ord(me)<49) or (ord(me)>51) do me:=readkey;
case ord(me) of
49: begin if bd=0 then begin bd:=1; s:='Included'; end
else begin bd:=0; s:='Excluded'; end;
gotoxy(25,3);write(s);
end;
50: begin if cl=0 then begin cl:=1; s:='Yes';end
else begin cl:=0; s:='No ';end;
gotoxy(25,4);write(s);
end;
end;
end;
gotoxy(1,3);
for xx:=1 to 5 do writeln(' ');
end;
begin
cleardevice; ASSIGNPROB; randomize;
gotoxy(1,1); writeln('Section III: Draw Image ... ');
MENUIII;
if bd=1 then begin CONVPOINTS; DRAWFIG(blue); end;
nm:=3000; {Number of points to plotted in final image.}
X:=0;Y:=0; {Initial point drawn.}
PUTIT(7);
for xx:=1 to nm do
begin
wh:=PICK; APPLY(wh); PUTIT((wh mod 7)+1);
end;
end;
procedure FILESAVE;
{To save transformations on disk.}
var i:integer;
tranfile:file of matrix;
begin
assign(tranfile, 'IFS.DAT');
rewrite(tranfile);
for i:=1 to totaltran do write(tranfile, tranlist[i]);
close(tranfile);
end;
function MENUIV:boolean; {.......................................}
var s:string;
me:char;
begin
gotoxy(1,3); writeln('1. Return to Section II');
writeln('2. Save transformations on file');
writeln('3. Quit');
writeln;writeln('Select Number: ');
me:='2';
while me='2' do
begin
me:=readkey;
while (ord(me)<49) or (ord(me)>51) do me:=readkey;
if me='2' then begin FILESAVE;
gotoxy(1,9); writeln('DATA SAVED');
end;
end;
if me='1' then MENUIV:=true else MENUIV:=false;
end;
BEGIN {----------------- Main Body ------------------------------}
gd:=detect; initgraph(gd,gm,'');
directvideo:=false; {Allows text using WRITE statements.}
INIT; cleardevice;
SHAPE; {... Section I ...}
select:=true;
while select do
begin
REDRAW(0);
MAKETRAN; {... Section II ...}
GENERATE; {... Section III ...}
select:=MENUIV;
end;
cleardevice; closegraph;
END.
[LISTING FOUR]
PROGRAM FOREST; {A mixture of two systems to produce a forest of ferns}
uses graph;
var n,xoff,yoff,gd,gm,cl: integer;
xsc,ysc,x,y,bx,by,asp:real;
xasp,yasp:word;
const
{CT holds the IFS for a fern}
CT:array[1..4,1..7] of real =
(( 0, 0, 0, 0, 0.16, 0, 0.02),
( 0.2,-0.26, 0, 0.23, 0.22, -24, 0.065),
(-0.15, 0.28, 0, 0.26, 0.24, -6.6, 0.065),
( 0.85, 0.04, 0,-0.04, 0.85, -24, 0.85));
{PL holds additional IFS functions to produce the forest}
PL:array[1..2,1..6] of real =
(( 0.8, 0, 80, 0, 0.8, -65),
( 0.8, 0, -80, 0, 0.8, -60));
PROB:array[1..6] of real = (0.008, 0.034, 0.06, 0.4, 0.7, 1.0);
procedure MAKETRAN;
var nx,ny:real;
s:integer;
function FINDTRAN:integer;
var i:integer;
w:real;
begin
w:=random; I:=1;
while w>PROB[i] do i:=i+1;
FINDTRAN:=i;
end;
begin
s:=FINDTRAN;
if s<5 then {Generate another point in the fern.}
begin
nx:=CT[s,1]*x + CT[s,2]*y + CT[s,3];
ny:=CT[s,4]*x + CT[S,5]*y + CT[s,6];
x:=nx; y:=ny; bx:=x; by:=y;
end
else {Generate another point in the forest.}
begin
s:=s-4;
nx:=PL[s,1]*bx + PL[s,2]*by + PL[s,3];
ny:=PL[s,4]*bx + PL[s,5]*by + PL[s,6];
bx:=nx; by:=ny;
end;
end;
procedure INIT;
begin
xsc:=1.3; ysc:=1;
xoff:=round(GETMAXX/2); yoff:=GETMAXY-50;
x:=0; y:=0;
bx:=0; by:=0;
GETAspectRatio(xasp,yasp); asp:=xasp/yasp;
end;
BEGIN
gd:=detect; initgraph(gd,gm,' ');
INIT; cleardevice;
for N:=1 to 32000 do
begin
MAKETRAN;
putpixel(round(bx*xsc)+xoff,(round(asp*by*ysc)+yoff),green);
end;
readln; cleardevice; closegraph;
END.