home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
04
/
fractal.asc
< prev
next >
Wrap
Text File
|
1991-03-15
|
52KB
|
1,229 lines
_FRACTALS IN THE REAL WORLD_
by Dick Oliver
[LISTING 1]
/****************************************************************
SIERP.C -- (C) 1990 by Dick Oliver, R1 Box 5140, Morrisville, VT 05661
A program to "draw" and "paint" Sierpinksi's Triangle, defined by a
"seed" (or "parent") shape and three transformations of that shape
("children"). The author makes no claims as to readability or
suitability for a particular task, but I'll be happy to give advice
and assistance.
*****************************************************************/
#include <stdio.h> /* For getch() */
#include <math.h> /* For cos() and sin() */
#include <graph.h> /* For graphics calls */
#include "sierp.h" /* You can change this for other template definitions */
int seedx[NPOINTS] = {SEEDX}, /* The "parent" polygon */
seedy[NPOINTS] = {SEEDY};
/* The tranformations which define the "children" */
float movex[NTRANS] = {MOVEX}, /* Displacement */
movey[NTRANS] = {MOVEY},
sizex[NTRANS] = {SIZEX}, /* Size change */
sizey[NTRANS] = {SIZEY},
spinx[NTRANS] = {SPINX}, /* Rotation */
spiny[NTRANS] = {SPINY},
/* The transformation matrix T, computed from the above variables */
Ta[NTRANS], Tb[NTRANS], Tc[NTRANS], Td[NTRANS];
/* Function prototypes */
void draw(float a, float b, float c, float d, float mx, float my, int iter);
void paint(int mx, int my);
void main(void)
{ int t;
_setvideomode(_VRES16COLOR); /* Initialize the screen */
_clearscreen(_GCLEARSCREEN);
/* Compute a,b,c,d from the move, size, and spin variables */
for (t = 0; t < NTRANS; t++)
{ Ta[t] = sizex[t] * cos(spinx[t]);
Tb[t] = - sizey[t] * sin(spiny[t]);
Tc[t] = sizex[t] * sin(spinx[t]);
Td[t] = sizey[t] * cos(spiny[t]);
}
/* Invoke draw with an initial transformation to move the triangle
to the center of the screen, unchanged in size or rotation */
draw(1.0, 0.0, 0.0, 1.0, (float) CENTERX, (float) CENTERY, NLEVELS);
_settextposition(30,0);
_outtext("Press any key to paint.");
getch();
_clearscreen(_GCLEARSCREEN);
/* Invoke paint, specifying the center of the screen */
paint(CENTERX, CENTERY);
_settextposition(30,0);
_outtext("Press any key to exit.");
getch();
_setvideomode(_DEFAULTMODE); /* Go back to text mode and exit */
}
/* This recursive routine draws one "parent" polygon, then calls itself
to draw the "children" using the transformations defined above */
void draw(float a, float b, float c, float d, float mx, float my, int iter)
{ int t;
iter--; /* Count one more level of drawing depth */
{ /* Use a,b,c,d,mx,my to transform the polygon */
float x1, y1; /* Point on the parent */
int p, x2[NTRANS], y2[NTRANS]; /* Points on the child */
for (p = 0; p < NPOINTS; p++)
{ x1 = seedx[p];
y1 = seedy[p];
x2[p] = a * x1 + b * y1 + mx;
y2[p] = c * x1 + d * y1 + my;
}
/* Now draw the new polygon on the screen */
_moveto(x2[NPOINTS - 1], y2[NPOINTS - 1]);
for (p = 0; p < NPOINTS; p++) _lineto(x2[p], y2[p]);
}
if (iter < 0) return; /* If we're at the deepest level, back out */
/* Do a recursive call for each "child" of the polygon we just drew */
for (t = 0; t < NTRANS; t++)
{ draw(Ta[t] * a + Tc[t] * b,
Tb[t] * a + Td[t] * b,
Ta[t] * c + Tc[t] * d,
Tb[t] * c + Td[t] * d,
movex[t] * a + movey[t] * b + mx,
movex[t] * c + movey[t] * d + my,
iter);
}
}
/* This routine uses "random iteration" to paint the fractal dot-by-dot.
The resulting shape will be the same as if we called draw with a
huge value for the number of levels */
void paint(int mx, int my)
{ int t;
unsigned long ct = 0; /* Counter for number of dots painted so far */
float x1 = 0.0, y1 = 0.0, x2, y2; /* Current and next dot */
/* Keep going until a key is pressed or we reach the COUNT limit */
while(!kbhit() && (++ct < COUNT))
{ t = rand() % NTRANS; /* Pick one of the transformations at random */
/* Then move from a dot on the "whole" to the corresponding dot
on some transformed "part" */
x2 = x1 * Ta[t] + y1 * Tb[t] + movex[t];
y2 = x1 * Tc[t] + y1 * Td[t] + movey[t];
x1 = x2, y1 = y2;
/* Skip the first few dots--it takes a while to "find" the fractal */
if (ct > 8) _setpixel((int) x2 + mx, (int) y2 + my);
}
}
[LISTING TWO]
/****************************************************************
SIERP.H -- Header file for Sierpinski's Triangle template
This (and the other header files like it) can be used to define
the initial fractal template for the SIERP.C and FRACDRAW.C programs
*****************************************************************/
#define NPOINTS 3 /* Number of points on the "parent" polygon */
#define NTRANS 3 /* Number of transformed "children" */
#define NLEVELS 6 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen x, y*/
#define CENTERY 240
#define SEEDX -200, 200, 0 /* The "parent" polygon */
#define SEEDY -200, -200, 200
/* The tranformations which define the "children" */
#define MOVEX -100.0, 100.0, 0.0 /* Displacement */
#define MOVEY -100.0, -100.0, 100.0
#define SIZEX 0.5, 0.5, 0.5 /* Size change */
#define SIZEY 0.5, 0.5, 0.5
#define SPINX 0.0, 0.0, 0.0 /* Rotation */
#define SPINY 0.0, 0.0, 0.0
/* The following color definitions are ignored by the SIERP program
and used only by FRACDRAW.
PALETTE defines the 16-color VGA palette
COLOR intializes a two-dimensional array with color values:
each column in the array definition below corresponds to one level
of detail, and each row corresponds to a "part", or transformation.
Note that the array only needs to be 6 by 3 for the template defined
above, but more rows are included in case the user inserts additional
"parts".
*/
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{2, 2, 2, 2, 2, 2},\
{1, 1, 1, 1, 1, 1},\
{5, 5, 5, 5, 5, 5},\
{4, 4, 4, 4, 4, 4},\
{2, 2, 2, 2, 2, 2},\
{3, 3, 3, 3, 3, 3},\
{7, 7, 7, 7, 7, 7},\
{8, 8, 8, 8, 8, 8},\
{1, 1, 1, 1, 1, 1}}
[LISTING THREE]
/*****************************************************************
MAPLE.H --- Header file for maple tree template
This (and the other header files like it) can be used to define
the initial fractal template for the SIERP.C and FRACDRAW.C programs
*****************************************************************/
#define NPOINTS 4 /* Number of points on the "parent" polygon */
#define NTRANS 3 /* Number of transformed "children" */
#define NLEVELS 6 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 350
/* The "parent" polygon */
#define SEEDX 6,20,-6,-12
#define SEEDY -120,120,120,-120
/* The tranformations which define the "children" */
#define MOVEX -6.1,-46,48 /* Displacement */
#define MOVEY -156,-40,-38
#define SIZEX .65,.57,.58 /* Size change */
#define SIZEY .56,.77,.82
#define SPINX 6.28,5.52,.44 /* Rotation */
#define SPINY 6.28,5.52,.44
/* The following color definitions are ignored by the SIERP program
and used only by FRACDRAW. See similar #defines in SIERP.H (Listing 2)
*/
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2}}
[LISTING FOUR]
/*****************************************************************
FRACDRAW.C -- Drawing with fractals
Copyright 1990 by Dick Oliver, R1 Box 5140, Morrisville, VT 05661
A program for interactive fractal drawing.
The author makes no claims as to readability or suitability for a
particular task, but I'll be happy to give advice and assistance.
*****************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <graph.h>
#include <math.h>
#include <ctype.h>
#include <bios.h>
/* #include file for initial template definition, can be changed */
#include "maple.h"
/* Numerical constants */
#define PI 3.141592
#define TWOPI 6.283853
#define HALFPI 1.570796
#define ALMOSTZERO 0.00002
#define MAXSIZE 0.998
#define MAXINT 32767
/* Keyboard constants */
#define ENTER 13
#define BACKSPACE 8
#define ESC 27
#define END -'O'
#define HOME -'G'
#define INSERT -'R'
#define DELETE -'S'
#define TAB 9
#define UNTAB -15
#define UP -'H'
#define DN -'P'
#define LT -'K'
#define RT -'M'
#define NULLKEY '^'
/* Generic getch() replacement */
#define geta if ((a = getch()) == 0) a = -getch();\
else if (a > 0) a = toupper(a)
/* Main menu */
#define MENUMSG "ACTION KEY\n"\
" Draw D\n"\
" Paint P\n"\
" Both B\n"\
" Next Part Tab\n"\
" NextPoint ~\n"\
" Insert Ins\n"\
" Delete Del\n"\
" Grow *\n"\
" Shrink /\n"\
" Spin + -\n"\
" Skew ; \'\n"\
" Squish [\n"\
" Stretch ]\n"\
" Quit ESC\n\n\n"\
" DRAWING\n WITH\n FRACTALS\n\n"\
" (C) 1990 by\n Dick Oliver"
#define MENUKEYS {'D', 'P', 'B', TAB, '`', INSERT, DELETE, \
'*', '/', '+', ';', '[', ']', ESC}
#define MENUWD 15 /* width of menu in characters */
#define NMENUITEMS 14 /* number of menu items */
#define HAND 64 /* size of handle in pixels */
#define MAXPTS 19 /* max. no. of points on seed */
#define MAXTRANS 19 /* max. no. of parts of template */
/* template variables:
spininc is the amount to rotate (in radians) each time spin is picked
sizeinc is the amount to grow or shrink
ra, rb, rc, rd, rmx, and rmy are the reverse of the initial tranformation
fa, fb, fc, and fd are the tranformations computed from
sizex, sizey, spinx, and spiny
movex and movey are the translation part of the transformations
asprat is the aspect ratio (always 1 for VGA)
fx and fy are used for various temporary storage purposes
x and y are the points on the seed polygon */
float sizeinc = 0.16, spininc = PI / 16,
ra, rb, rc, rd, rmx, rmy,
fa[MAXTRANS + 1], fb[MAXTRANS + 1], fc[MAXTRANS + 1], fd[MAXTRANS + 1],
sizex[MAXTRANS + 1] = {1, SIZEX}, sizey[MAXTRANS + 1] = {1, SIZEY},
spinx[MAXTRANS + 1] = {0, SPINX}, spiny[MAXTRANS + 1] = {0, SPINY},
movex[MAXTRANS + 1] = {CENTERX, MOVEX},
movey[MAXTRANS + 1] = {CENTERY, MOVEY},
asprat, fx, fy, x[MAXPTS] = {SEEDX}, y[MAXPTS] = {SEEDY};
/* menu vars */
char a, menukeys[] = MENUKEYS;
/* xtop, etc. are the points on the handle
drawclr is the text and handle color
xx, yy, midx, and midy are used for various pixel-shuffling operations
menuitem is the current menu choice
hand is the size of the handle in pixels
sk is used to keep track of when to re-sketch the template
xo and yo are the current template corners for quick erasing
thispt & thistran are the current point/part
npts is the number of point, ntrans is the number of parts,
level is the number of levels of detail to draw or paint
color determines the color to make each part at each level
*/
int xtop, ytop, xctr, yctr, xlft, ylft, xrgt, yrgt,
drawclr, i, j, xx, yy, midx, midy, menuitem = 0, hand = HAND, sk,
xo[MAXTRANS + 1][MAXPTS], yo[MAXTRANS + 1][MAXPTS], moveinc = 16,
thispt = 0, thistran = 0, npts = NPOINTS, ntrans = NTRANS,
level = NLEVELS - 1, color[MAXTRANS][NLEVELS] = COLOR;
/* ptmode means we're in "point" mode rather than "part" mode*/
enum {OFF, ON} ptmode = OFF;
/* standard Microsoft video variables */
struct videoconfig vc;
long palette[16] = PALETTE;
/* these function prototypes are needed to avoid confusion about parameter
* types (most of the functions aren't prototyped) */
void draw(float a, float b, float c, float d, float mx, float my, int iter);
void warp(float spinxinc, float spinyinc, float sizexinc, float sizeyinc);
main()
{ hello(); /* initialize everything */
while(1) /* the main event-processing loop */
{ geta; /* geta is a #define */
switch(a) /* what shall we do now? */
{ case BACKSPACE:
case ' ':
/* move ">" to new menu item */
_settextposition(menuitem + 2, 1);
_outtext(" ");
if (a == ' ')
{ if (++menuitem == NMENUITEMS) menuitem = 0;
}
else if (--menuitem < 0) menuitem = NMENUITEMS - 1;
_settextposition(menuitem + 2, 1);
_outtext(">");
break;
case ENTER: /* pick a menu item */
ungetch(menukeys[menuitem]);
break;
default:
sk = 0;
switch(a)
{ case LT: case DN:
case RT: case UP:
/* move a point or part of the template */
xx = 0, yy = 0;
switch (a)
{ case LT: xx = -moveinc; break;
case RT: xx = moveinc; break;
case UP: yy = -moveinc; break;
case DN: yy = moveinc; break;
}
if (!ptmode && (thistran == 0))
*movex += xx, *movey += yy;
else
{ if (ptmode)
{ x[thispt] += xx * ra + yy * rb;
y[thispt] += xx * rc + yy * rd;
}
else movex[thistran] += xx * ra + yy * rb,
movey[thistran] += xx * rc + yy * rd;
}
break;
case '/': /* Shrink */
if (ptmode)
{ fx = 1 / (sizeinc + 1);
warp(0.0, 0.0, fx, fx);
}
else
{ if ((sizex[thistran] /= sizeinc + 1) == 0)
sizex[thistran] = ALMOSTZERO;
if ((sizey[thistran] /= sizeinc + 1) == 0)
sizey[thistran] = ALMOSTZERO;
computef(thistran);
}
break;
case '*': /* Grow */
if (ptmode) warp(0.0, 0.0,sizeinc+1, sizeinc+1);
else
{ if (((sizex[thistran] *= sizeinc + 1)
> MAXSIZE)
&& (thistran > 0))
sizex[thistran] = MAXSIZE;
if (((sizey[thistran] *= sizeinc + 1)
> MAXSIZE)
&& (thistran > 0))
sizey[thistran] = MAXSIZE;
computef(thistran);
}
break;
case '[': /* Squish x-axis */
if (ptmode) warp(0.0, 0.0, 1/(sizeinc + 1), 1.0);
else
{ if ((sizex[thistran] /= (sizeinc + 1)) == 0)
sizex[thistran] = ALMOSTZERO;
computef(thistran);
}
break;
case ']': /* Stretch x-axis */
if (ptmode) warp(0.0, 0.0, sizeinc + 1, 1.0);
else
{ if (((sizex[thistran] *= sizeinc + 1)
> MAXSIZE)
&& (thistran > 0))
sizex[thistran] = MAXSIZE;
computef(thistran);
}
break;
case '-': /* Spin counter-clockwise */
if (ptmode) warp(-spininc, -spininc, 1.0, 1.0);
else
{ if ((spinx[thistran] -= spininc) < 0)
spinx[thistran] += TWOPI;
if ((spiny[thistran] -= spininc) < 0)
spiny[thistran] += TWOPI;
computef(thistran);
}
break;
case '+': /* Spin clockwise */
if (ptmode) warp(spininc, spininc, 1.0, 1.0);
else
{ if ((spinx[thistran] += spininc) >= TWOPI)
spinx[thistran] -= TWOPI;
if ((spiny[thistran] += spininc) >= TWOPI)
spiny[thistran] -= TWOPI;
computef(thistran);
}
break;
case ';': /* Skew x-axis counter-clockwise */
if (ptmode) warp(spininc, 0.0, 1.0, 1.0);
else
{ if ((spinx[thistran] += spininc) >= TWOPI)
spinx[thistran] -= TWOPI;
computef(thistran);
}
break;
case '\'': /* Skew x-axis clockwise */
if (ptmode) warp(-spininc, 0.0, 1.0, 1.0);
else
{ if ((spinx[thistran] -= spininc) < 0)
spinx[thistran] += TWOPI;
computef(thistran);
}
break;
case '`': /* NextPoint */
if (ptmode) ++thispt;
else ptmode = ON, thistran = 0;
if (thispt >= npts) thispt = 0;
break;
default:
switch(a)
{ case TAB: /* Next part */
if (ptmode)
{ ptmode = OFF;
midpoint();
}
else
{ if (++thistran > ntrans) thistran = 0;
}
break;
case 'D':
case 'P':
case 'B': /* Draw and/or Paint */
_clearscreen(_GCLEARSCREEN);
_setcliprgn(0, 0,
vc.numxpixels - 1,
vc.numypixels - 1);
_setcolor(**color);
if ((a == 'D') || (a == 'B'))
draw(*fa, *fb, *fc, *fd,
*movex, *movey, level);
if ((a == 'P') || (a == 'B')) paint();
printf("\7");
getch();
_clearscreen(_GCLEARSCREEN);
printmenu();
break;
case ESC: /* Quit */
_setvideomode(_DEFAULTMODE);
printf("Seeyalater!");
exit(0);
case INSERT: /* Insert a point or part */
if (ptmode)
{ if (npts < MAXPTS)
{ erase();
++npts;
for (i = npts - 1; i > thispt; i--)
x[i] = x[i - 1],
y[i] = y[i - 1];
if (thispt > 0)
xx = x[thispt - 1],
yy = y[thispt - 1];
else xx = x[npts - 1],
yy = y[npts - 1];
if ((xx == x[thispt]) &&
(yy == y[thispt]))
x[thispt] += moveinc,
y[thispt] += moveinc;
else x[thispt] =
(xx + x[thispt]) / 2,
y[thispt] =
(yy + y[thispt]) / 2;
}
else printf("\7");
}
else
{ if ((ntrans < MAXTRANS) && (ntrans > 0))
{ ++ntrans;
for (i = ntrans; i > thistran; i--)
{ if (i > 1)
{ movex[i] = movex[i - 1];
movey[i] = movey[i - 1];
spinx[i] = spinx[i - 1];
spiny[i] = spiny[i - 1];
sizex[i] = sizex[i - 1];
sizey[i] = sizey[i - 1];
for (j = 0; j < NLEVELS;
j++)
color[i - 1][j] =
color[i - 2][j];
fa[i] = fa[i - 1];
fb[i] = fb[i - 1];
fc[i] = fc[i - 1];
fd[i] = fd[i - 1];
}
else
{ spinx[1] = 0;
spiny[1] = 0;
sizex[1] = sizey[1];
computef(1);
}
}
if (thistran == 0) thistran = 1,i = 1;
if (thistran > 1) j = thistran - 1;
else j = ntrans;
if ((movex[i] == movex[j]) &&
(movey[i] == movey[j]))
movex[i] += moveinc,
movey[i] += moveinc;
else movex[i] =
(movex[i] + movex[j]) / 2,
movey[i] =
(movey[i] + movey[j]) / 2;
}
else
{ if (ntrans == 0) thistran = ++ntrans;
else printf("\7");
}
}
break;
case DELETE: /* Delete a point or part */
erase();
if (ptmode)
{ if (npts > 1)
{ if (thispt == --npts) --thispt;
else for (i = thispt; i < npts; i++)
x[i] = x[i + 1],
y[i] = y[i + 1];
}
else printf("\7");
}
else
{ if (ntrans > 0)
{ --ntrans;
}
else printf("\7");
if (ntrans > 0)
{ if (thistran == 0) thistran = 1;
else
for (i = thistran;
i <= ntrans; i++)
{ movex[i] = movex[i + 1];
movey[i] = movey[i + 1];
spinx[i] = spinx[i + 1];
spiny[i] = spiny[i + 1];
sizex[i] = sizex[i + 1];
sizey[i] = sizey[i + 1];
for (j = 0; j < NLEVELS;
j++)
color[i - 1][j] =
color[i][j];
fa[i] = fa[i + 1];
fb[i] = fb[i + 1];
fc[i] = fc[i + 1];
fd[i] = fd[i + 1];
}
}
if (thistran > ntrans) --thistran;
}
}
sk = 1;
}
erase();
sketch(sk);
}
}
}
/* midpoint() -- find the center of the seed */
midpoint()
{ int xx, yy;
midx = 0, midy = 0;
for (i = 0; i < npts; i++) midx += x[i], midy += y[i];
midx /= npts, midy /= npts;
for (i = 0; i < npts; i++) x[i] -= midx, y[i] -= midy;
for (i = 1; i <= ntrans; i++)
{ xx = midx * fa[i] + midy * fb[i];
yy = midx * fc[i] + midy * fd[i];
movex[i] -= midx - xx;
movey[i] -= midy - yy;
}
xx = midx * *fa + midy * *fb,
yy = midx * *fc + midy * *fd;
*movex += xx,
*movey += yy;
}
/* compute the affine transformations expressed by the template */
computef(int i)
{ fa[i] = sizex[i] * cos(spinx[i]);
fb[i] = -sizey[i] * sin(spiny[i]);
fc[i] = sizex[i] * sin(spinx[i]);
fd[i] = sizey[i] * cos(spiny[i]);
if (i == 0)
{ if ((fx = *fa * *fd - *fb * *fc) == 0) fx = 0.001;
ra = *fd / fx;
rb = - *fb / fx;
rc = - *fc / fx;
rd = *fa / fx;
}
}
/* warp the seed shape (used to skew, squish, and stretch) */
void warp(float spinxinc, float spinyinc, float sizexinc, float sizeyinc)
{ float a, b, c, d, dsizex, dsizey, dspinx, dspiny;
dspinx = spinxinc + *spinx;
dspiny = spinyinc + *spiny;
dsizex = sizexinc * *sizex;
dsizey = sizeyinc * *sizey;
a = cos(dspinx) * dsizex;
b = -sin(dspiny) * dsizey;
c = sin(dspinx) * dsizex;
d = cos(dspiny) * dsizey;
for (i = 0; i < MAXPTS; i++)
{ fx = x[i] * a + y[i] * b;
fy = x[i] * c + y[i] * d;
x[i] = fx * ra + fy * rb;
y[i] = fx * rc + fy * rd;
}
}
/* sketch() -- sketch the template and the handle.
* Note that the handle shows not only which part you are on,
* but also the relative size and orientation of both axes. */
sketch(int all)
{ int i, j, x1, y1, inc, tran0 = 0;
float x2, y2, a, b, c, d, mx, my;
inc = hand;
if (ptmode)
{ tran0 = 1;
inc *= *sizey / 2;
fx = x[thispt], fy = y[thispt];
x1 = fx * *fa + fy * *fb + *movex;
y1 = fx * *fc + fy * *fd + *movey;
xctr = x1, yctr = (y1 + inc) * asprat;
xtop = x1, ytop = (y1 - inc) * asprat;
y1 *= asprat;
xlft = x1 - inc, ylft = y1;
xrgt = x1 + inc, yrgt = y1;
}
else
{ if (thistran == 0) x1 = 0, y1 = 0, tran0 = 1;
else x1 = movex[thistran], y1 = movey[thistran];
if (tran0) fx = x1, fy = y1 - inc;
else fx = x1 - inc * fb[thistran],
fy = y1 - inc * fd[thistran];
xtop = fx * *fa + fy * *fb + *movex;
ytop = (fx * *fc + fy * *fd + *movey) * asprat;
xctr = x1 * *fa + y1 * *fb + *movex;
yctr = (x1 * *fc + y1 * *fd + *movey) * asprat;
inc /= 2;
if (tran0) fx = x1 - inc, fy = y1;
else fx = x1 - inc * fa[thistran],
fy = y1 - inc * fc[thistran];
xlft = fx * *fa + fy * *fb + *movex;
ylft = (fx * *fc + fy * *fd + *movey) * asprat;
if (tran0) fx = x1 + inc, fy = y1;
else fx = x1 + inc * fa[thistran],
fy = y1 + inc * fc[thistran];
xrgt = fx * *fa + fy * *fb + *movex;
yrgt = (fx * *fc + fy * *fd + *movey) * asprat;
}
_setcolor(**color);
for (j = 0; j < npts; j++)
{ x1 = x[j] * *fa + y[j] * *fb + *movex;
y1 = (x[j] * *fc + y[j] * *fd + *movey) * asprat;
(*xo)[j] = x1, (*yo)[j] = y1;
if (j == 0) _moveto(x1, y1);
else _lineto(x1, y1);
}
_lineto(**xo, **yo);
for (i = 1; i <= ntrans; i++)
{ if ((thistran == 0) || (i == thistran) || (all))
{ _setcolor(color[i - 1][level]);
a = fa[i] * *fa + fc[i] * *fb;
b = fb[i] * *fa + fd[i] * *fb;
c = fa[i] * *fc + fc[i] * *fd;
d = fb[i] * *fc + fd[i] * *fd;
mx = movex[i] * *fa + movey[i] * *fb + *movex;
my = movex[i] * *fc + movey[i] * *fd + *movey;
for (j = 0; j < npts; j++)
{ x1 = a * x[j] + b * y[j] + mx;
y1 = (c * x[j] + d * y[j] + my) * asprat;
if (j == 0) _moveto(x1, y1);
else _lineto(x1, y1);
xo[i][j] = x1, yo[i][j] = y1;
}
_lineto(*(xo[i]), *(yo[i]));
}
}
_setcolor(drawclr);
_moveto(xtop, ytop);
_lineto(xctr, yctr);
_moveto(xlft, ylft);
_lineto(xrgt, yrgt);
}
/* erase the template */
erase()
{ _setcolor(0);
_moveto(**xo, **yo);
for (i = 1; i < npts; i++) _lineto((*xo)[i], (*yo)[i]);
_lineto(**xo, **yo);
for (i = 1; i <= ntrans; i++)
{ if ((thistran == 0) || (i == thistran))
{ _moveto(*(xo[i]), *(yo[i]));
for (j = 0; j < npts; j++) _lineto(xo[i][j], yo[i][j]);
_lineto(*(xo[i]), *(yo[i]));
}
}
_moveto(xtop, ytop);
_lineto(xctr, yctr);
_moveto(xlft, ylft);
_lineto(xrgt, yrgt);
}
/* paint() -- uses the "Chaos Game", or "random iteration" algorithm
* to paint the "infinite-level" fractal on the screen. */
paint()
{ int i, j, p[MAXTRANS], tc, tp, ci[NLEVELS], cc = 0, mx, my;
unsigned long ct = COUNT;
float x1 = 0.0, y1 = 0.0, x2, y2 = 0, sx[MAXTRANS], sy[MAXTRANS];
mx = *movex, my = *movey;
/* First, we need to compute the relative area of each part of the
template. This is done by comparing the size of the determinants
of the matrix (a,b,c,d). These weights are then used to decide
how often to visit each part--big parts get more visits than small
ones, giving the overall fractal an even density. */
for (i = 1; i <= ntrans; i++)
y2 += (sx[i - 1] =
fabs(fa[i] * fd[i] - fb[i] * fc[i]));
if (y2 == 0) y2 = 0.01;
x2 = MAXINT / y2;
j = 0;
for (i = 0; i < ntrans; i++)
{ if ((xx = sx[i] * x2) == 0) xx = 1;
p[i] = (j += xx);
}
/* We skip the first eight points on our journey, because it may take
that long to settle down from wherever we started onto the fractal.*/
for (j = 0; j < 8; j++)
{ i = rand() % ntrans + 1;
x2 = x1 * fa[i] + y1 * fb[i] + movex[i];
y2 = x1 * fc[i] + y1 * fd[i] + movey[i];
x1 = x2, y1 = y2;
ci[cc] = i;
if (++cc == level) cc = 0;
}
/* Now we put it on the screen. The cc, tc, and ci variables are used
to determine coloring. At each iteration, we choose a level at
random out of all the levels we will be coloring. We then find the
color for that level based on which part was "visited" that many
iterations ago. How does this work? Each iteration of the orbit
goes from a point on the "whole" to a point on a "part". Therefore,
if we were in part #3 one iteration ago, we are now in a level 1
reflection of part #3 within the current part. If we were at part #5
two cycles ago, we are now painting a point within a level 2
reflection of part #5, and so on. */
while(!kbhit() && (--ct != 0))
{ j = rand();
for (i = 0; i < ntrans; i++) if (j < p[i]) break;
i++;
x2 = x1 * fa[i] + y1 * fb[i] + movex[i];
y2 = x1 * fc[i] + y1 * fd[i] + movey[i];
x1 = x2, y1 = y2;
ci[cc] = i - 1;
j = rand() % level;
if ((i = cc - j) < 0) i += level;
if ((tc = color[ci[i]][j + 1]) > 0)
{ _setcolor(tc);
_setpixel((int) (x2 * *fa + y2 * *fb + mx),
(int) ((x2 * *fc + y2 * *fd + my) * asprat));
}
if (++cc == level) cc = 0;
}
}
/* draw() -- uses the "successive approximation" algorithm to draw
the fractal.*/
void draw(float a, float b, float c, float d, float mx, float my, int iter)
{ int i;
/* When we start drawing, iter is the number of levels to draw.
Each time we go down one level, we decrement iter. */
iter--;
/* If user hits ESC, pass that keypress up through the recursive
calls until we get back to the main procedure.*/
if (kbhit() && (getch() == ESC))
{ ungetch(ESC);
return;
}
/* Draw a reflection of the seed polygon using the current
transformation */
for (i = 0; i < npts; i++)
{ fx = x[i] * a + y[i] * b + mx;
fy = x[i] * c + y[i] * d + my;
if (i == 0)
{ xx = fx, yy = fy;
_moveto((int) fx, (int) (fy * asprat));
}
else _lineto((int) fx, (int) (fy * asprat));
}
_lineto((int) xx, (int) (yy * asprat));
/* If iter has counted all the way down to zero, don't draw the next
deepest level, but back out one level instead */
if (iter < 0) return;
else
{ /* Call draw recursively for each transformation, drawing the
next deepest level of each part */
for (i = 1; i <= ntrans; i++)
{ _setcolor(color[i - 1][level - iter]);
draw(fa[i] * a + fc[i] * b,
fb[i] * a + fd[i] * b,
fa[i] * c + fc[i] * d,
fb[i] * c + fd[i] * d,
a * movex[i] + b * movey[i] + mx,
c * movex[i] + d * movey[i] + my,
iter);
}
}
}
/* display the menu */
printmenu()
{ _settextwindow(1, vc.numtextcols - MENUWD,
vc.numtextrows, vc.numtextcols);
_clearscreen(_GWINDOW);
_outtext(MENUMSG);
_settextposition(menuitem + 2, 1);
_outtext(">");
_setcliprgn(0, 0, vc.numxpixels - (MENUWD + 1) *
(vc.numxpixels / vc.numtextcols) - 1,
vc.numypixels - 1);
}
/* hello() -- initialize everything */
hello()
{ if (!_setvideomode(_VRES16COLOR))
{ printf("Can't set video mode. VGA required.");
}
_getvideoconfig(&vc);
_remapallpalette(palette);
_wrapon(_GWRAPOFF);
_clearscreen(_GCLEARSCREEN);
printmenu();
asprat = (float) (4 * vc.numypixels) / (float) (3 * vc.numxpixels);
drawclr = vc.numcolors - 1;
for (i = 0; i <= ntrans; i++) computef(i);
sketch(0);
}
[LISTING FIVE]
/*****************************************************************
FLAKE.H --- Header file for snowflake template
This (and the other header files like it) can be used to define
the initial fractal template for the SIERP.C and FRACDRAW.C programs
This template models the crystalization process to draw a realistic
snowflake shape.
See additional comments in SIERP.H
*****************************************************************/
#define NPOINTS 6 /* Number of points on the "parent" polygon */
#define NTRANS 6 /* Number of transformed "children" */
#define NLEVELS 5 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 240
#define SEEDX 1,21,21,1,-21,-21 /* The "parent" polygon */
#define SEEDY -27,-15,9,40,9,-15
/* The tranformations which define the "children" */
#define MOVEX -1,55,55,1,-55,-55 /* Displacement */
#define MOVEY -65,-35,35,65,35,-35
#define SIZEX .18,.18,.18,.18,.18,.18 /* Size change */
#define SIZEY .91,.91,.91,.91,.91,.91
#define SPINX 0,1.05,2.09,3.14,4.19,5.24 /* Rotation */
#define SPINY 0,1.05,2.09,3.14,4.19,5.24
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15}}
[LISTING SIX]
/****************************************************************
CUMULUS.H--- Header file for cumulus cloud template
This (and the other header files like it) can be used to define
the initial fractal template for the SIERP.C and FRACDRAW.C programs
See additional comments in SIERP.H
****************************************************************/
#define NPOINTS 7 /* Number of points on the "parent" polygon */
#define NTRANS 6 /* Number of transformed "children" */
#define NLEVELS 5 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 240
#define SEEDX 23,17,-4,-10,-27,7,44 /* The "parent" polygon */
#define SEEDY 0,55,55,0,9,-66,10
/* The tranformations which define the "children" */
#define MOVEX 85,-94,-3,51.5,-49,0 /* Displacement */
#define MOVEY 15,13,3.5,-35,-40,40
#define SIZEX .36,.4,.53,.48,.4,.87 /* Size change */
#define SIZEY .36,.47,.53,.53,.4,.33
#define SPINX .25,6,6.2,0.15,6.2,0 /* Rotation */
#define SPINY .25,6,6.2,0.15,6.2,6.3
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{15,15,15, 7, 8},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15}}
/*****************************************************************
CIRRUS.H-- Header file for cirrus cloud template
In this and the other cloud models (STRATUS and CUMULUS), the air
currents which control cloud formation are modelled as arrows.
When those forces are reflected throughout all levels of scale,
a realistic image of the cloud type that results from those air
currents appears. Cirrus clouds are characterized by high-altitude
rising cross winds, stratus clouds by slow horizontal air flow,
and cumulus clouds by warm air rising from the ground.
*****************************************************************/
#define NPOINTS 7 /* Number of points on the "parent" polygon */
#define NTRANS 6 /* Number of transformed "children" */
#define NLEVELS 5 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 180 /* Center of the screen */
#define CENTERY 240
#define SEEDX 16,-27,-42,-7,-27,54,23 /* The "parent" polygon */
#define SEEDY 33,52,36,-7,-13,-43,36
/* The tranformations which define the "children" */
#define MOVEX 143.4,-90,5,-4 /* Displacement */
#define MOVEY 11.08,13.6,-15.5,45
#define SIZEX .75,.43,.38,.75 /* Size change */
#define SIZEY .45,.47,.44,.21
#define SPINX 6.07,0.05,0.02,0.0 /* Rotation */
#define SPINY 6.07,0.05,0.02,6.28
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{15,15,15, 7, 8},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15}}
/*****************************************************************
LEAF.H --- Header file for maple leaf template
This is the "geometric genetic code" for a maple leaf. Note the close
similarity to the MAPLE tree template.
*****************************************************************/
#define NPOINTS 4 /* Number of points on the "parent" polygon */
#define NTRANS 4 /* Number of transformed "children" */
#define NLEVELS 6 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 350
#define SEEDX 6,20,-6,-12 /* The "parent" polygon */
#define SEEDY -120,120,120,-120
/* The tranformations which define the "children" */
#define MOVEX -1.15,-53,51,-6 /* Displacement */
#define MOVEY 35,7,6,-111
#define SIZEX 0.14,0.62,0.65,0.49 /* Size change */
#define SIZEY 0.51,0.72,0.68,0.51
#define SPINX 6.26,5.47,0.81,6.28 /* Rotation */
#define SPINY 6.26,5.47,0.81,6.28
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2},\
{6, 6,14,14,10, 2}}
/*****************************************************************
MOUSE.H -- Header file for cartoon mouse template
This template was made by tracing the rough outline of an image and
tiling with copies of itself.
*****************************************************************/
#define NPOINTS 14 /* Number of points on the "parent" polygon */
#define NTRANS 18 /* Number of transformed "children" */
#define NLEVELS 2 /* Number of levels to draw */
#define COUNT 50000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 240
#define SEEDX 131,140,97,6,-56,-97,-146,-148,-121,-101,-47,-3,32,29
#define SEEDY 5,55,99,133,121,70,21,-17,-17,-31,-20,-78,-93,-71
/* The tranformations which define the "children" */
#define MOVEX -89,36,-60,-4,4,61,-71,1,81,-49,-133,-130,-8,-3,-36,-24,13,15
#define MOVEY -3,13,25,-35,-63,-43,101,116,56,87,-50,-24,104,-1,-20,-27,-16,76
#define SIZEX .31,.4,.62,.07,.19,.32,.19,.4,.55,.31,.12,.17,.21,.06,.06,\
.08,.11,.42
#define SIZEY .18,.35,.44,.27,.27,.48,.06,.13,.33,.20,.04,.23,.12,.16,.14,\
.2,.23,.2
#define SPINX 3.23,6.4,.32,2.72,5.84,4.61,.75,6.25,5.34,.29,3.16,5.9,3.04,\
4.15,4.32,.91,1.1,2.55
#define SPINY 3.6,6.5,.77,.37,3.49,4.28,.75,6.25,5.27,.1,2.85,2.65,2.53,\
3.56,3.73,3.73,3.53,5.89
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{6,6},\
{6,6},\
{6,6},\
{6,6},\
{6,6},\
{6,6},\
{1,1},\
{6,6}, {6,6}, {1,1}, {7,7}, {8,8}, {12,12},\
{9,9}, {9,9}, {15,15}, {15,15}, {1,1}}
/*****************************************************************
PINE.H --- Header file for pine tree template
This (and the other header files like it) can be used to define
the initial fractal template for the SIERP.C and FRACDRAW.C programs
*****************************************************************/
#define NPOINTS 4 /* Number of points on the "parent" polygon */
#define NTRANS 6 /* Number of transformed "children" */
#define NLEVELS 5 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 350
#define SEEDX 6,20,-6,-12 /* The "parent" polygon */
#define SEEDY -120,120,120,-120
/* The tranformations which define the "children" */
#define MOVEX -41.2,36.9,5.13,-14.64,2.2,40.07 /* Displacement */
#define MOVEY 14.987,-61.31,7.10,-32.33,-50.46
#define SIZEX 0.39,0.41,0.52,0.35,0.86,0.37 /* Size change */
#define SIZEY 0.39,0.31,0.17,0.24,0.79,0.42
#define SPINX 5.62,0.61,6.15,5.43,3.27,0.54 /* Rotation */
#define SPINY 4.91,1.27,0.13,4.71,6.28,1.4
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{6, 6,14,10, 2},\
{6, 6,14,10, 2},\
{6, 6,14,10, 2},\
{6, 6,14,10, 2},\
{6, 6,14,10, 2},\
{6, 6,14,10, 2},\
{6, 6,14,10, 2},\
{6, 6,14,10, 2},\
{6, 6,14,10, 2}}
/*****************************************************************
STRATUS.H -- Header file for stratus cloud template
****************************************************************/
#define NPOINTS 6 /* Number of points on the "parent" polygon */
#define NTRANS 5 /* Number of transformed "children" */
#define NLEVELS 5 /* Number of levels to draw */
#define COUNT 10000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 240
#define SEEDX 40,80,40,-40,-80,-40 /* The "parent" polygon */
#define SEEDY 22,-2,-22,-22,2,22
/* The tranformations which define the "children" */
#define MOVEX -70,-44,45,60,-3.3 /* Displacement */
#define MOVEY 11,-34,-31,1.6,42
#define SIZEX .75,.43,.38,.75,.8 /* Size change */
#define SIZEY .45,.47,.44,.61,.2
#define SPINX 6.3,6.3,6.3,6.3,0 /* Rotation */
#define SPINY 6.3,6.3,6.3,6.3,6.3
#define PALETTE {_BLACK, _RED, _GREEN, _CYAN, \
_BLUE, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{15,15,15, 7, 8},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15},\
{15,15,15,15,15}}
/*****************************************************************
ZOOM.H -- Header file for abstract zooming artwork template
Note that this very simple template creates a visually complex image,
while seemingly simple linear forms like the cartoon mouse require
much more work and information to express as fractals. When drawing
with fractals, richly detailed trees are simpler and easier to create
than smooth objects like tables and chairs!
*****************************************************************/
#define NPOINTS 5 /* Number of points on the "parent" polygon */
#define NTRANS 5 /* Number of transformed "children" */
#define NLEVELS 4 /* Number of levels to draw */
#define COUNT 20000 /* Number of dots to paint */
#define CENTERX 320 /* Center of the screen */
#define CENTERY 340
#define SEEDX -66,-334,60,272,66
#define SEEDY -7,100,-120,-27,55
/* The tranformations which define the "children" */
#define MOVEX 55,104,185,30,-45
#define MOVEY -309,-1,-50,28,-25
#define SIZEX .27,.36,.5,.28,.98
#define SIZEY .27,.27,.18,.21,.5
#define SPINX 4.71,3.88,3.34,4.3,6
#define SPINY 2.48,.93,.39,1.16,6
#define PALETTE {_BLUE, _RED, _GREEN, _CYAN, \
_BLACK, _MAGENTA, _BROWN, _WHITE, \
_GRAY, _LIGHTBLUE, _LIGHTGREEN, _LIGHTCYAN, \
_LIGHTRED, _LIGHTMAGENTA, _LIGHTYELLOW, _BRIGHTWHITE}
#define COLOR {{15,15,15,15},\
{14,14,14,14},\
{14,14,14,14},\
{14,14,14,14},\
{14,14,14,14},\
{15,15,15,15},\
{15,15,15,15}}