|
25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more... |
Home Projects Up Sitemap Search Blog Forum+Chat About Us Privacy Terms of Use Feedback FAQ Images Services Ads Donate Humor |
Continuously generates random iterated function sets (IFS) and displays in color the fractal images they define. This version is in DeSmet C. It uses the color graphics library functions I wrote for the Heathkit H-100 computer.
Other versions:
/* autorand.c 4-19-91 4-28-93
Copyright (C)1991, 1993 Steven Whitney.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
Version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
continuously generates random IFS fractals.
IFS = Iterated Function System or Iterated Function Set.
translation of my autorand.bas program to c, modified from showifs.c
4-26-93 added color options
4-28-93 screen now saved using zedsave()
4-28-93 added option to automatically archive files as they're created
now bind with: BIND EXEC AUTORAND MYLIB.S -OAUTORAND
4-28-93 converted display and file output to polar coordinates
.IFS now saved as .PFS (the P stands for Polar, easier to work with)
4-28-93 option to force x and y scaling to be the same
4-30-93 each batch of 10 archived files is transferred to drive B:
so I: (which was my H-100 ramdrive) doesn't fill up.
11-1-93 not sure you can exec "B:\command.com".
in net.c, it always uses a: no matter what I tell it.
revise if necessary.
THIS PROGRAM REQUIRES SEVERAL OF THE FUNCTIONS FROM MY FUNCTION LIBRARIES.
YOU SHOULD ALSO REVIEW IT LINE BY LINE BEFORE YOU COMPILE AND RUN IT.
IT MAKES REFERENCE BY LETTER TO ABSOLUTE DISK DRIVES.
IT ALSO HAS A NUMBER OF AUTOMATION FEATURES THAT YOU MAY OR MAY NOT BE ABLE (OR WANT) TO USE:
The program runs continuously, generating a sequence of fractal designs.
While generating each fractal, it decides whether the design is finished by counting
the number of plotted points that land on screen pixels that have already been
previously plotted. When a design is finished, it uses another test to decide
whether it was interesting. If it was, it automatically saves it. After each
batch (10, I think) of interesting designs, it uses the ARC512.EXE program to
compress them into a .ARC file. I used to run this program overnight, and then
review the .ARC file to see if it turned up anything interesting.
A more complete discussion of IFS fractals and of some of the options in this
program can be found in the Windows .RTF help file for my later Borland C++ OWL
version of this program, WSHOWFS.CPP.
*/
#include "stdio.h"
#define zArray(a) _setmem(a, sizeof(a), 0)
double posrnd() /* returns only a positive random number */
{ /* (math.s has a bug, frand() sometimes returns -) */
double r;
do
{
r = frand();
}
while(r < 0.0);
return r;
}
main(argc,argv)
int argc;
char *argv[];
{
int i; /* temporary */
int t; /* number of transforms */
int k; /* transformation choice */
int archive = FALSE; /* flag: whether to automatically archive */
int beepon = TRUE; /* flag: whether to beep near completion */
int colorfound; /* color found at point */
int dups; /* counts duplicated pixels */
int duplimit = 150; /* when reached, image is saved */
int dupmargin = 100; /* beep sounds while dup > limit - margin */
int upsdwn = TRUE; /* flag: whether to invert y axis */
int showequat = TRUE; /* flag: whether to show equations */
int polar = TRUE; /* flag: whether to generate ifs by polar */
int proportional = FALSE; /* flag: force x and y linear scaling to equal */
int outrange; /* flag: whether window limits exceeded */
int seed; /* user inputs random number seed */
int tempx, tempy; /* scaled values to plot */
int piccount = 0; /* counts number of .ZED files created */
int arccount = 0; /* counts # of .ARCs transferred to B: */
double a[20], b[20], c[20]; /* transform arrays */
double d[20], e[20], f[20];
double p[20]; /* probabilities */
double r; /* a random number */
double cp[20]; /* stores probability thresholds */
double x, y, newx, newy; /* numeric values to plot */
double minx, maxx, miny, maxy; /* screen limits */
double xrange, yrange; /* screen ranges */
double xfactor, yfactor; /* scaling factors */
double xr[20], ys[20]; /* linear scaling of transforms */
double theta[20], phi[20]; /* rotations of transforms, in radians */
double thetaangle[20]; /* theta and phi, as angles */
double phiangle[20];
long n; /* counts iterations */
long nonpts = 1000; /* number of points to not display */
long throwout = 20; /* points merely bring near attractor */
long pix; /* number of pixels turned on */
FILE *outfile;
char fnam[81]; /* for holding input file name */
char diskerr[25]; /* just contains error text */
char ch; /* tests for user keyboard input */
char dispmode = 'm'; /* display: <M>ono, <C>olor (by # of hits) */
/* or <T>ransform (color by trans. used) */
freeall(1024); /* initializes malloc area, but in */
/* this case, just dups the default */
strcpy(diskerr,"\nFile write error.\n");
puts("\033z"); /* reset terminal */
puts("\nUsage: AUTORAND -options\n");
puts("Example: autorand -rca\n");
puts("Options: r = allow x and y axes to rotate independently\n");
puts(" h = just show this help screen and exit\n");
puts(" b = suppress beep when image (may be) near completion\n");
puts(" d = user will enter # of duplicate points to force .ZED save\n");
puts(" c = set color according to how many times a point gets hit\n");
puts(" t = set color according to which transform was chosen\n");
puts(" (default color is mono: green)\n");
puts(" a = automatically archive (compress) the files created\n");
puts(" p = make fractal of exactly proportional smaller copies of itself\n");
puts("\nWHILE PROGRAM IS RUNNING:\n");
puts("\nPress <SPACE> to abort & start a new design.\n");
puts("Press B to toggle (enable/disable) beep when near completion\n");
puts("Press E to display (or re-display) equations.\n");
puts("Press N to display number of points plotted so far.\n");
puts("Press P to save current picture and .PFS files.\n");
puts("Press Q to Quit.\n");
if(argc > 1) /* just print help & quit */
if(index(strlwr(argv[1]),'h')) /* (to lowercase for later tests) */
exit(0);
puts("\nEnter number of transformations: ");
scanf("%d",&t);
puts("Enter random number seed (-32768 to 32767): ");
scanf("%d",&seed);
srand(seed); /* seed random number generator */
if(argc > 1) /* interpret command line options */
{
if(index(argv[1],'a'))
{
archive = TRUE;
if(!(outfile = fopen("ARC512.EXE","r"))) /* is file there? */
abort("ARC512.EXE must be in the default directory.");
fclose(outfile);
if(!(outfile = fopen("A:\COMMAND.COM","r"))) /* file there? */
abort("Drive A: must contain COMMAND.COM for system to reset.");
fclose(outfile);
if(!(outfile = fopen("B:\COMMAND.COM","r"))) /* file there? */
abort("Drive B: must contain a nearly-empty disk with COMMAND.COM.");
fclose(outfile);
}
if(index(argv[1],'p')) proportional = TRUE;
if(index(argv[1],'c')) dispmode = 'c';
if(index(argv[1],'t')) dispmode = 't';
if(index(argv[1],'r')) polar = FALSE;
if(index(argv[1],'b')) beepon = FALSE;
if(index(argv[1],'d'))
{
puts("Save .ZED after how many duplicated points?: ");
scanf("%d",&duplimit);
dupmargin = MIN(duplimit/2,100);
}
}
puts("\033x1"); /* enable 25th line */
puts("\033x<"); /* disable keyboard auto-repeat */
puts("\033y@"); /* disable event key up/down mode */
_outb(0x78,0xD8); /* initialize Z100 video port D8 */
/* enable all planes */
do /* do until user quits (see end) */
{
puts("\033E"); /* clear screen */
locate(25,1); /* locate on 25th line */
puts("\033l"); /* erase entire 25th line (lowercase L) */
zArray(a); zArray(b); zArray(c); zArray(d); /* initialize arrays */
zArray(e); zArray(f); zArray(p); zArray(cp); /* to zero */
zArray(xr); zArray(ys); zArray(theta); zArray(phi);
zArray(thetaangle); zArray(phiangle);
for(i = 1 ; i <= t ; i++) /* generate transform data */
{
xr[i] = posrnd() * 200. - 100.; /* x axis length scaling factor */
if(proportional)
ys[i] = xr[i]; /* y axis length scaling factor */
else
ys[i] = posrnd() * 200. - 100.;
thetaangle[i] = posrnd() * 360.; /* x axis rotation, */
theta[i] = thetaangle[i] * 3.1415926 / 180.; /* to radians */
if(polar) /* when x and y rotations are */
{ /* not equal, image "squished" */
phiangle[i] = thetaangle[i]; /* with axes not perpendicular */
phi[i] = theta[i];
}
else
{
phiangle[i] = posrnd() * 360.; /* y axis rotation, */
phi[i] = phiangle[i] * 3.1415926 / 180.; /* to radians */
}
a[i] = xr[i] * cos(theta[i]); /* convert to rectangular */
b[i] = -ys[i] * sin(phi[i]); /* because it's faster */
c[i] = xr[i] * sin(theta[i]); /* for calculations */
d[i] = ys[i] * cos(phi[i]);
e[i] = posrnd() * 20. - 10.; /* x axis translation distance */
f[i] = posrnd() * 20. - 10.; /* y axis translation distance */
p[i] = 1./t; /* probability of being picked */
}
locate(1,1); /* data area on video screen */
if(showequat)
printf("%d RANDOM TRANSFORMS IN: %d\n",t,piccount);
for(i = 1 ; i <= t ; i++)
{
if(showequat) /* polar form */
printf("%.0f %.0f %.0f %.0f %.0f %.0f %.2f\n",
xr[i],ys[i],thetaangle[i],phiangle[i],e[i],f[i],p[i]);
a[i] *= .01; b[i] *= .01; /* adjust to usable form */
c[i] *= .01; d[i] *= .01;
cp[i] = cp[i-1] + p[i-1]; /* fill probability array */
}
x = 0. ; y = 0. ; /* initialize x and y */
n = 0; /* initialize iteration counter */
dups = 0; /* initialize duplicate count */
pix = 0; /* initialize set-pixel count */
ch = '\0'; /* reset user input char */
outrange = 0; /* reset out of range flag */
if(t == 1) /* 1transform requires preset window */
{
duplimit = 50;
dupmargin = 25;
minx = miny = -30.;
maxx = maxy = 30.;
xrange = maxx - minx;
yrange = maxy - miny;
xfactor = 640./xrange;
yfactor = 225./yrange;
}
else
{
minx = miny = 1.0E+300; /* init. screen limits */
maxx = maxy = -1.0E+300; /* for multi-transform sets */
}
do /* until runs off screen, user aborts, or completed */
{
n++; /* increment iteration counter */
if(ch) /* most of the time, just test ch once, for speed */
{
if(ch == 'b') /* enable/disable beep */
beepon = !beepon;
if((ch == 'e') || (ch == 'p'))
{
locate(1,1);
printf("%d RANDOM TRANSFORMS IN: %d\n",t,piccount);
for(i = 1 ; i <= t ; i++) /* polar */
printf("%.0f %.0f %.0f %.0f %.0f %.0f %.2f\n",
xr[i],ys[i],thetaangle[i],phiangle[i],e[i],f[i],p[i]);
}
if((ch == 'n') || (ch == 'e') || (ch == 'p'))
{
locate(t+2,1);
printf("%ld points",n-nonpts);
}
if(ch == 'p')
{
sprintf(fnam,"%d.PFS",piccount);
if((outfile = fopen(fnam,"w")) == NULL)
abort(diskerr);
if(fprintf(outfile,"%d\n",t) == ERR)
abort(diskerr);
for(i = 1 ; i <= t ; i++) /* polar */
if(fprintf(outfile,"%.0f %.0f %.0f %.0f %.0f %.0f %.2f\n",
xr[i],ys[i],thetaangle[i],phiangle[i],e[i],f[i],p[i]) == ERR)
abort(diskerr);
if(fclose(outfile) == ERR)
abort(diskerr);
zedsave(); /* save screen */
sprintf(fnam,"%d.ZED",piccount); /* build file name */
rename("SCREEN.ZED",fnam); /* rename */
if(archive) /* can be a function, but */
{ /* it's much simpler this way */
sprintf(fnam," a ZEDS %d.PFS %d.ZED",piccount,piccount);
exec("ARC512.EXE",fnam); /* archive this set */
sprintf(fnam,"%d.PFS",piccount); /* rebuild .PFS name */
unlink(fnam); /* and delete it */
sprintf(fnam,"%d.ZED",piccount); /* rebuild .ZED */
unlink(fnam); /* and delete it */
if(piccount == 9) /* copy .ARC to B: every 10 files */
{
sprintf(fnam,"/cCOPY ZEDS.ARC B:ZEDS%d.ARC",arccount);
exec("B:\COMMAND.COM",fnam);
unlink("ZEDS.ARC");
piccount = -1;
arccount++;
}
}
piccount++;
}
if(ch == 'q')
{
puts("\033z"); /* restore normal screen */
exit(0); /* and exit program */
}
}
k = 0; /* initialize transformation choice */
do
{
r = frand(); /* generate random number */
}
while(r <= 0.); /* r must be > 0.0 */
for(i = 1 ; i <= t ; i++) /* bump transformation choice up */
if(r > cp[i]) /* depending on where r falls */
k += 1; /* within the possible distribution */
newx = (a[k])*x + (b[k])*y + e[k]; /* calculate new points */
newy = (c[k])*x + (d[k])*y + f[k];
x = newx ; y = newy;
if(n <= nonpts) /* only 1 test most of the time, for speed */
{
if(t > 1) /* if t==1, window is preset earlier */
{
if(n <= throwout) /* just loop if working on throwouts */
continue;
if(n < nonpts) /* tally min and max values seen */
{
minx = MIN(minx,x);
maxx = MAX(maxx,x);
miny = MIN(miny,y);
maxy = MAX(maxy,y);
continue;
}
if(n == nonpts) /* compute screen window size */
{
xrange = maxx - minx;
yrange = maxy - miny;
minx -= (.10 * xrange); /* enlarge window */
maxx += (.10 * xrange); /* by 20% */
miny -= (.10 * yrange); /* in each axis */
maxy += (.10 * yrange);
xrange = maxx - minx; /* you have to calculate */
yrange = maxy - miny; /* the ranges twice!! */
if((xrange == 0.) || (yrange == 0.))
abort("\nRange allows division by zero!\n");
xfactor = 640./xrange;
yfactor = 225./yrange;
continue;
} /* end if n == nonpts */
} /* end if t > 1 */
} /* end if n <= nonpts */
tempx = (int)((x-minx)*xfactor );
tempy = (int)((y-miny)*yfactor );
if(upsdwn) /* invert y axis */
tempy = 224 - tempy;
colorfound = point(tempx,tempy); /* can be 0 - 7 */
if(colorfound == 0) /* if pixel has not been set at all, */
{ /* reset consecutive dup. count */
dups = 0; /* to zero (it's a totally new point) */
pix++; /* and increment pixel-on count */
}
else /* otherwise, it was a duplicate, */
dups++; /* so increment dup. counter */
switch(dispmode) /* set point, whether or not it was */
{ /* a dup., because it might be in a */
case 'm': /* new color */
outrange = pset(tempx,tempy,4);
break;
case 'c':
outrange = pset(tempx,tempy,MIN(colorfound+1,7));
break;
case 't':
outrange = pset(tempx,tempy,MIN(k,7));
break;
}
if(beepon)
if((dups > (duplimit - dupmargin)) || (outrange == ERR))
putchar(7);
}
while((!outrange) && (dups < duplimit) && ((ch = tolower(csts())) != ' '));
/* falls through if: ran off screen, was completed, or user aborted */
/* save pic below only if picture was completed (and is 'interesting') */
if((ch != ' ') && (!outrange) && (pix > 1500))
{
sprintf(fnam,"%d.PFS",piccount);
if((outfile = fopen(fnam,"w")) == NULL)
abort(diskerr);
if(fprintf(outfile,"%d\n",t) == ERR)
abort(diskerr);
for(i = 1 ; i <= t ; i++) /* polar */
if(fprintf(outfile,"%.0f %.0f %.0f %.0f %.0f %.0f %.2f\n",
xr[i],ys[i],thetaangle[i],phiangle[i],e[i],f[i],p[i]) == ERR)
abort(diskerr);
if(fclose(outfile) == ERR)
abort(diskerr);
locate(1,1); /* refresh overwritten data area */
printf("%d RANDOM TRANSFORMS IN: %d\n",t,piccount);
for(i = 1 ; i <= t ; i++) /* polar */
printf("%.0f %.0f %.0f %.0f %.0f %.0f %.2f\n",
xr[i],ys[i],thetaangle[i],phiangle[i],e[i],f[i],p[i]);
locate(t+2,1); /* show number of points so far */
printf("%ld points",n-nonpts);
zedsave();
sprintf(fnam,"%d.ZED",piccount); /* build file name */
rename("SCREEN.ZED",fnam); /* rename */
if(archive)
{
sprintf(fnam," a ZEDS %d.PFS %d.ZED",piccount,piccount);
exec("ARC512.EXE",fnam); /* archive this set */
sprintf(fnam,"%d.PFS",piccount); /* rebuild .PFS name */
unlink(fnam); /* and delete it */
sprintf(fnam,"%d.ZED",piccount); /* rebuild .ZED */
unlink(fnam); /* and delete it */
if(piccount == 9) /* copy .ARC to B: every 10 files */
{
sprintf(fnam,"/cCOPY ZEDS.ARC B:ZEDS%d.ARC",arccount);
exec("B:\COMMAND.COM",fnam);
unlink("ZEDS.ARC");
piccount = -1;
arccount++;
}
}
piccount++;
}
}
while(1); /* do forever - exit is within the point plotting loop */
}
If you wish, you can download ARC512EXE.ZIP (17KB), which contains the well known freeware file compression program from the 1980's called ARC512.EXE. It was written for "generic MSDOS", so it will run on the H-100 and also on PC-compatibles. It even runs beautifully under Windows XP, but it has no ability to understand "modern" file and path names that are long or have spaces in them. Therefore, it and the files it operates on must:
Suggested method:
IFS2PFS.C is a program that can (unreliably) translate an IFS set from rectangular to polar notation. The page has links to other versions that do it better.
|
|
|
|
|
|