Diffusion Limited Aggregate Fractal
news
news at sun.Eng.Sun.COM
Sat Sep 1 02:35:09 AEST 1990
Submitted-by: reed!news
Posting-number: Volume 9, Issue 12
Archive-name: dlaf/part01
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\End\Of\Shar\'
This generates a "Diffusion Limited Aggregate Fractal", as described
in some issue of Scientific American last year or so. Lots of silly
features have been added, and there are some optimizations for the
default case (instead of letting the new particle wander all over an
empty screen, we contrain it to a vicinity of the existing mass of
particles). Other than being a memory pig and being poorly
documented, it's a rather nice program. The -shape flag doesn't seem
to work correctly -- something change after keith at expo made a few
changes, and I haven't bothered to track it down.
(Gee, that was great! I haven't been able to blame Keith for
something in years. :-) )
Let's see... -lifetime sets the lifetime of a moving particle, -decay
sets the lifetime of all the other particles. -expire is a synonym
for one of these. -border controls the border around the already
existing mass (the optimization I mentioned). -flash and -lightning
are synonyms as well.
Oh yeah, "q" lets you quit if you aren't running it in the root window.
Comments, problems, and code to trost%reed at cse.ogi.edu. I haven't
touched the code in months, though, so I'm not certain what the state
of the internals is.
Enjoy!
\End\Of\Shar\
else
echo "will not over write ./README"
fi
if [ `wc -c ./README | awk '{printf $1}'` -ne 1214 ]
then
echo `wc -c ./README | awk '{print "Got " $1 ", Expected " 1214}'`
fi
if `test ! -s ./Imakefile`
then
echo "writing ./Imakefile"
cat > ./Imakefile << '\End\Of\Shar\'
DEFINES =
INCLUDES = -I$(TOP) -I$(TOP)/X11
DEPLIBS = $(DEPXLIB)
LOCAL_LIBRARIES = $(XLIB)
SYS_LIBRARIES =
SRCS = addpoint.c args.c assert.c bits.c flags.c main.c usage.c
OBJS = addpoint.o args.o assert.o bits.o flags.o main.o usage.o
ComplexProgramTarget(xdla)
\End\Of\Shar\
else
echo "will not over write ./Imakefile"
fi
if [ `wc -c ./Imakefile | awk '{printf $1}'` -ne 263 ]
then
echo `wc -c ./Imakefile | awk '{print "Got " $1 ", Expected " 263}'`
fi
if `test ! -s ./Makefile.simple`
then
echo "writing ./Makefile.simple"
cat > ./Makefile.simple << '\End\Of\Shar\'
SRCS = addpoint.c args.c assert.c bits.c flags.c main.c usage.c
OBJS = addpoint.o args.o assert.o bits.o flags.o main.o usage.o
XLIB = -lX11
xdla: $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(XLIB)
clean:
rm -f $(OBJS) xdla
addpoint.o: main.h
args.o: main.h
assert.o:
bits.o: main.h
flags.o: main.h
main.o: main.h
usage.o: main.h
\End\Of\Shar\
else
echo "will not over write ./Makefile.simple"
fi
if [ `wc -c ./Makefile.simple | awk '{printf $1}'` -ne 353 ]
then
echo `wc -c ./Makefile.simple | awk '{print "Got " $1 ", Expected " 353}'`
fi
if `test ! -s ./addpoint.c`
then
echo "writing ./addpoint.c"
cat > ./addpoint.c << '\End\Of\Shar\'
#include "main.h"
static void
DrawLightning(np)
int np;
{
if (useroot)
XLowerWindow(dpy, lightningWindow);
XMapWindow(dpy, lightningWindow);
XDrawPoints(dpy, lightningWindow, lgc, pl, np, CoordModeOrigin);
}
int
AddPoint()
{
int x, y, dx = 0, dy = 0;
int top_area, middle_area, bottom_area;
int total_area;
int a;
int i;
int np = 0;
top_area = (curright - curleft) * curtop;
middle_area = dla_width * (curbottom - curtop);
bottom_area = (curright - curleft) * (dla_height - curbottom);
total_area = top_area + middle_area + bottom_area;
do {
a = random() % total_area;
if (a < top_area) {
y = a / (curright - curleft);
x = a % (curright - curleft) + curleft;
} else if ((a -= top_area) < middle_area) {
y = a / dla_width + curtop;
x = a % dla_width;
} else {
a -= middle_area;
y = a / (curright - curleft) + curbottom;
x = a % (curright - curleft) + curleft;
}
} while (GetBit(x, y));
for (i = 0; (life == 0 || i < life) && !GetBit(x + dx, y + dy); i++) {
if (lightning && np > 16000) {
DrawLightning(np);
np = 0;
}
if (lightning && (np == 0 || pl[np - 1].x != x || pl[np - 1].y != y)) {
pl[np].x = x;
pl[np++].y = y;
}
if ((x += dx) < curleft)
x = curleft;
else if (x > curright)
x = curright;
if ((y += dy) < curtop)
y = curtop;
else if (y > curbottom)
y = curbottom;
do {
a = random () % 9;
dx = (a % 3) - 1;
dy = (a / 3) - 1;
} while (folds == 4 && dx && dy);
if (folds == 6 && dx)
dy = 0;
}
SetBit(x, y);
if (lightning) {
DrawLightning(np);
XFlush(dpy);
XUnmapWindow(dpy, lightningWindow);
}
if (expire) {
/* yes, this misses the corner, but close enough */
if (oldpoint[last].x != 0 || oldpoint[last].y != 0) {
ResetBit(oldpoint[last].x, oldpoint[last].y);
XClearArea(dpy, win, oldpoint[last].x - BORDER,
oldpoint[last].y - BORDER, 1, 1, 0);
}
oldpoint[last].x = x;
oldpoint[last++].y = y;
last %= expire;
}
XDrawPoint(dpy, win, gc, x - BORDER, y - BORDER);
/* compute new bounds */
if (x - BORDER < curleft) {
curleft = x - BORDER;
if (curleft <= 0) {
curleft = 1;
return 0;
}
}
else if (x + BORDER > curright) {
curright = x + BORDER;
if (curright >= dla_width + 2 * BORDER - 1) {
curright = dla_width + 2 * BORDER - 2;
return 0;
}
}
if (y - BORDER < curtop) {
curtop = y - BORDER;
if (curtop <= 0) {
curtop = 1;
return 0;
}
}
else if (y + BORDER > curbottom) {
curbottom = y + BORDER;
if (curbottom >= dla_height + 2 * BORDER - 1) {
curbottom = dla_height + 2 * BORDER - 2;
return 0;
}
}
return 1;
}
char*
Bounds(n)
int n;
{
static char buf[256];
int i, l = pl[0].x, r = pl[0].x, t = pl[0].y, b = pl[0].y;
for (i = 1; i < n; i++) {
if (pl[i].x < l)
l = pl[i].x;
else if (pl[i].x > r)
r = pl[i].x;
if (pl[i].y < t)
t = pl[i].y;
else if (pl[i].y > b)
b = pl[i].y;
}
sprintf(buf, "(%d, %d, %d, %d)", l, r, t, b);
return buf;
}
\End\Of\Shar\
else
echo "will not over write ./addpoint.c"
fi
if [ `wc -c ./addpoint.c | awk '{printf $1}'` -ne 3236 ]
then
echo `wc -c ./addpoint.c | awk '{print "Got " $1 ", Expected " 3236}'`
fi
if `test ! -s ./args.c`
then
echo "writing ./args.c"
cat > ./args.c << '\End\Of\Shar\'
#include "main.h"
void
ParseArgs(argc, argv)
int argc;
char** argv;
{
for (progname = *argv++, argc--; argc; argv++, argc--) {
Argassoc* a;
for (a = map; a->name; a++)
if (**argv == '-' && strcmp(a->name, *argv + 1) == 0) {
switch (a->type) {
case Boolean:
*((int *) a->ref) = (int) a->value;
break;
case String:
*((char **) a->ref) = *++argv;
--argc;
break;
case Integer:
*((int *) a->ref) = atoi(*++argv);
--argc;
break;
case Function:
(*(void (*)()) a->ref)();
break;
}
break;
}
if (!a->name)
Usage();
}
}
int
ParseShape(s)
char* s;
{
static struct {
char* s;
int i;
} tbl[] = {
"dot", DOT,
"point", DOT,
"line", LINE,
0, 0
}, *here;
for (here = tbl; here->s; here++)
if (strcmp(here->s, s) == 0)
return here->i;
fprintf (stderr, "valid shape types are:");
for (here = tbl; here->s; here++)
fprintf (stderr, " %s", here->s);
fprintf (stderr, "\n");
return -1;
}
\End\Of\Shar\
else
echo "will not over write ./args.c"
fi
if [ `wc -c ./args.c | awk '{printf $1}'` -ne 1340 ]
then
echo `wc -c ./args.c | awk '{print "Got " $1 ", Expected " 1340}'`
fi
if `test ! -s ./assert.c`
then
echo "writing ./assert.c"
cat > ./assert.c << '\End\Of\Shar\'
#include <stdio.h>
#include <varargs.h>
/*
* error routines
*/
void
complain(cond, fmt, args)
int cond;
char* fmt;
va_list args;
{
if (cond)
_doprnt(fmt, &args, stderr);
}
void
assert(cond, fmt, args)
int cond;
char* fmt;
va_list args;
{
if (!cond) {
_doprnt(fmt, &args, stderr);
exit(1);
}
}
void
panic(cond, fmt, args)
int cond;
char* fmt;
va_list args;
{
if (cond) {
_doprnt(fmt, &args, stderr);
abort();
}
}
\End\Of\Shar\
else
echo "will not over write ./assert.c"
fi
if [ `wc -c ./assert.c | awk '{printf $1}'` -ne 540 ]
then
echo `wc -c ./assert.c | awk '{print "Got " $1 ", Expected " 540}'`
fi
if `test ! -s ./bits.c`
then
echo "writing ./bits.c"
cat > ./bits.c << '\End\Of\Shar\'
#include "main.h"
#ifndef SetBit
void
SetBit(x, y)
int x, y;
{
char* line = bits[y];
if (line == 0)
line = bits[y] = (char *) calloc(dpywidth / 8 + 1, sizeof(char));
line[x / 8] |= 1 << (x & 7);
}
#endif
#ifndef ResetBit
void
ResetBit(x, y)
int x, y;
{
bits[y][x / 8] &= ~(1 << (x & 7));
}
#endif
#ifndef GetBit
int
GetBit(x, y)
int x, y;
{
char* line = bits[y];
if (line == 0)
return 0;
return line[x / 8] & (1 << (x & 7));
}
#endif
\End\Of\Shar\
else
echo "will not over write ./bits.c"
fi
if [ `wc -c ./bits.c | awk '{printf $1}'` -ne 496 ]
then
echo `wc -c ./bits.c | awk '{print "Got " $1 ", Expected " 496}'`
fi
if `test ! -s ./flags.c`
then
echo "writing ./flags.c"
cat > ./flags.c << '\End\Of\Shar\'
#include "main.h"
Argassoc map[] = {
{ String, "display", (char *) &displayname },
{ String, "fg", (char *) &foreground },
{ String, "bg", (char *) &background },
{ Integer, "border", (char *) &BORDER },
{ Integer, "decay", (char*) &expire },
{ Integer, "expire", (char *) &expire },
{ Integer, "folds", (char *) &folds },
{ Boolean, "flash", (char *) &lightning, (char *) 1},
{ Integer, "lifetime", (char *) &life },
{ Boolean, "lightning", (char *) &lightning, (char *) 1},
{ String, "lightningcolor", (char *) &lightningColor },
{ String, "shape", (char *) &shape },
{ Boolean, "root", (char *) &useroot, (char*) 1 },
{ Function, "help", (char *) Usage },
{ Integer, "update", (char *) &update },
{ String, "geometry", (char *) &geometry },
{ Boolean, 0, 0 },
};
\End\Of\Shar\
else
echo "will not over write ./flags.c"
fi
if [ `wc -c ./flags.c | awk '{printf $1}'` -ne 841 ]
then
echo `wc -c ./flags.c | awk '{print "Got " $1 ", Expected " 841}'`
fi
if `test ! -s ./main.c`
then
echo "writing ./main.c"
cat > ./main.c << '\End\Of\Shar\'
#include "main.h"
#include <X11/keysym.h>
int screen;
unsigned dla_width, dla_height;
unsigned curleft, curright, curbottom, curtop;
Display* dpy;
Window win;
char** bits;
unsigned long fg, bg;
char* displayname = 0;
char* progname;
char* foreground;
char* background;
char* foldstr = 0;
char* shape = "dot";
char* geometry = "500x500";
int useroot = 0;
int BORDER;
int folds;
int life;
int lightning;
Window lightningWindow;
XPoint pl[32767];
char* lightningColor;
int update = 20;
GC gc, lgc;
Pixmap pic;
XGCValues gcv;
int expire, last;
XPoint* oldpoint;
main(argc, argv)
int argc;
char* argv[];
{
int noquit;
int mask;
int screen;
int x, y;
int i;
Window gunk, parent;
XColor cdef;
Colormap dcm;
XSizeHints xsh;
unsigned int width, height;
XSetWindowAttributes attrs;
ParseArgs(argc, argv);
if (BORDER <= 0)
BORDER = 10; /* very arbitrary */
assert(dpy = XOpenDisplay(displayname),
"unable to open display \"%s\".\n", XDisplayName (displayname));
screen = XDefaultScreen (dpy);
dcm = DefaultColormap(dpy, screen);
if (background && XParseColor(dpy, dcm, background, &cdef) &&
XAllocColor(dpy, dcm, &cdef))
bg = cdef.pixel;
else
bg = BlackPixel(dpy, screen);
if (foreground && XParseColor(dpy, dcm, foreground, &cdef) &&
XAllocColor(dpy, dcm, &cdef))
fg = cdef.pixel;
else
fg = WhitePixel(dpy, screen);
if (useroot) {
win = XRootWindow(dpy, screen);
width = DisplayWidth (dpy, screen);
height = DisplayHeight (dpy, screen);
} else {
mask = XParseGeometry (geometry, &x, &y, &width, &height);
xsh.flags = PSize;
xsh.width = width;
xsh.height = height;
parent = XCreateSimpleWindow(dpy, XRootWindow(dpy, screen),
x, y, width, height, 1, fg, bg);
win = XCreateSimpleWindow(dpy, parent,
0, 0, width, height, 0, fg, bg);
XSetStandardProperties (dpy, parent, "Diffusion Limited Aggregates",
"xdla", None, argv, argc, &xsh);
XSelectInput (dpy, win, KeyPressMask|KeyReleaseMask);
}
dla_width = width + 2 * BORDER;
dla_height = height + 2 * BORDER;
attrs.backing_store = Always;
attrs.win_gravity = CenterGravity;
XChangeWindowAttributes (dpy, win, CWBackingStore|CWWinGravity, &attrs);
gcv.foreground = fg;
gc = XCreateGC(dpy, win, GCForeground, &gcv);
if (lightningColor)
lightning = 1;
if (lightning) {
attrs.override_redirect = 1;
lightningWindow = XCreateWindow(dpy, win, -BORDER, -BORDER,
width, height, 0, CopyFromParent,
InputOutput, CopyFromParent,
CWOverrideRedirect, &attrs);
if (lightningColor && XParseColor(dpy, dcm, lightningColor, &cdef) &&
XAllocColor(dpy, dcm, &cdef))
gcv.foreground = cdef.pixel;
lgc = XCreateGC(dpy, lightningWindow, GCForeground, &gcv);
}
if (expire) {
noquit = 1;
oldpoint = (XPoint*) calloc(expire, sizeof(oldpoint[0]));
}
srandom(getpid());
bits = (char **) calloc(dla_height, sizeof(*bits));
switch (ParseShape(shape)) {
case -1:
Usage ();
break;
case DOT:
(void) SetBit(dla_width / 2, dla_height / 2);
(void) XDrawPoint(dpy, win, gc,
dla_width / 2 - BORDER,
dla_height / 2 - BORDER);
if (life) {
curleft = curtop = 1;
curright = width - 1;
curbottom = height - 1;
}
else {
curleft = dla_width / 2 - BORDER;
curright = dla_width / 2 + BORDER;
curtop = dla_height / 2 - BORDER;
curbottom = dla_height / 2 + BORDER;
}
break;
case LINE:
noquit = 1;
for (i = 0; i < dla_width; i++) {
SetBit(i, dla_height - 1);
XDrawPoint(dpy, win, gc, i, dla_height - 1 - BORDER);
}
curleft = 0;
curright = dla_width;
curbottom = dla_height - 1;
curtop = dla_height - BORDER - 1;
break;
}
if (folds == 0)
folds = 8;
assert(folds == 4 || folds == 6 || folds == 8,
"folds must be one of 4, 6, or 8, not %d.\n", folds);
if (useroot) {
XSetWindowBackground (dpy, win, bg);
XClearWindow(dpy, win);
}
else {
XMapWindow(dpy, win);
XMapWindow (dpy, parent);
}
if (life)
noquit = 1;
i = 0;
while (AddPoint() || noquit) {
if (++i >= update) {
XEvent ev;
i = XEventsQueued (dpy, QueuedAfterFlush);
while (i--) {
XNextEvent (dpy, &ev);
Dispatch (&ev);
}
}
}
for (;;) {
XEvent ev;
XNextEvent (dpy, &ev);
Dispatch (&ev);
}
}
Dispatch (ev)
XEvent *ev;
{
switch (ev->type) {
case KeyPress:
switch (XLookupKeysym (ev, 0)) {
case XK_Q:
case XK_q:
case XK_Cancel:
case XK_Break:
exit (0);
}
}
}
\End\Of\Shar\
else
echo "will not over write ./main.c"
fi
if [ `wc -c ./main.c | awk '{printf $1}'` -ne 4659 ]
then
echo `wc -c ./main.c | awk '{print "Got " $1 ", Expected " 4659}'`
fi
if `test ! -s ./main.h`
then
echo "writing ./main.h"
cat > ./main.h << '\End\Of\Shar\'
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h>
#define DOT 0
#define LINE 1
typedef enum { Boolean, String, Integer, Function } ArgType;
typedef struct {
ArgType type;
char* name;
char* ref;
char* value; /* wildcard thingie */
} Argassoc;
extern int screen;
extern unsigned dla_width, dla_height;
extern unsigned curleft, curright, curbottom, curtop;
extern Display* dpy;
extern Window win;
extern char** bits;
extern unsigned long fg;
extern char* displayname;
extern char* progname;
extern char* foreground;
extern char* background;
extern char* foldstr;
extern char* shape;
extern char* geometry;
extern int useroot;
extern int BORDER;
extern int folds;
extern int life;
extern int lightning;
extern Window lightningWindow;
extern XPoint pl[];
extern char* lightningColor;
extern int update;
extern GC gc, gcr, lgc;
extern Pixmap pic;
extern XGCValues gcv;
extern Argassoc map[];
extern int expire, last;
extern XPoint* oldpoint;
int AddPoint();
void ParseArgs();
void SetBit();
void Usage();
char* calloc();
char* getenv();
#define SetBit(x,y) (\
(bits[y] ? 0 : (bits[y] = (char *) calloc (dla_width / 8 + 1,sizeof (char)))),\
(bits[y][(x)>>3] |= 1 << (x & 7))\
)
#define ResetBit(x,y) (bits[y][x / 8] &= ~(1 << (x & 7)))
#define GetBit(x,y) (bits[y] ? bits[y][(x) >> 3] & (1 << (x & 7)) : 0)
\End\Of\Shar\
else
echo "will not over write ./main.h"
fi
if [ `wc -c ./main.h | awk '{printf $1}'` -ne 1442 ]
then
echo `wc -c ./main.h | awk '{print "Got " $1 ", Expected " 1442}'`
fi
if `test ! -s ./patchlevel.h`
then
echo "writing ./patchlevel.h"
cat > ./patchlevel.h << '\End\Of\Shar\'
#define PATCHLEVEL 0
\End\Of\Shar\
else
echo "will not over write ./patchlevel.h"
fi
if [ `wc -c ./patchlevel.h | awk '{printf $1}'` -ne 21 ]
then
echo `wc -c ./patchlevel.h | awk '{print "Got " $1 ", Expected " 21}'`
fi
if `test ! -s ./usage.c`
then
echo "writing ./usage.c"
cat > ./usage.c << '\End\Of\Shar\'
#include "main.h"
extern char *progname;
void
Usage()
{
Argassoc* here;
fprintf(stderr, "usage: %s", progname);
for (here = map; here->name; here++) {
fprintf(stderr, " [-%s", here->name);
switch (here->type) {
case String:
case Integer:
fprintf(stderr, " %s", here->name);
break;
}
fprintf(stderr, "]");
}
fprintf(stderr, "\n");
exit(1);
}
\End\Of\Shar\
else
echo "will not over write ./usage.c"
fi
if [ `wc -c ./usage.c | awk '{printf $1}'` -ne 433 ]
then
echo `wc -c ./usage.c | awk '{print "Got " $1 ", Expected " 433}'`
fi
echo "Finished archive 1 of 1"
exit
dan
----------------------------------------------------
O'Reilly && Associates argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.
More information about the Comp.sources.x
mailing list