home *** CD-ROM | disk | FTP | other *** search
- /*
- * ifsshow.c -- show an ifs.
- *
- * 4 june 1989 Olle Olsson
- */
-
- #include <stdlib.h>
- #include <conio.h>
- #include <math.h>
- #include "ifs.h"
-
- /* * /
- #define PRONLY 1 /* for test */
- /* */
-
- #define FSCL 0x10000 /* fixed point scale */
-
- typedef union
- {
- long l; /* fixed point long */
- struct
- {
- int lw; /* low word, fraction part */
- int hw; /* high word, integer part */
- } w;
- } fpl;
-
- #define FINT( x ) (((fpl *)&x)->w.hw) /* fixed point integer part */
-
- typedef struct /* fixed point version */
- {
- long a11, a12; /* one transformation matrix */
- long a21, a22;
- long b1, b2; /* translation vector */
- int color; /* color index */
- double prob; /* probability */
- int iprob; /* probability fitted to rand() */
- int group; /* group index */
- } ftrans;
-
- typedef struct /* group member spec. */
- {
- int nels; /* number of elements */
- long tcount; /* total number of iterations to do */
- long dcount; /* delta count (for mixing of groups) */
- double frcnt; /* fraction part of dcount */
- double sumfrcnt; /* accumulator for fraction part of dcount */
- long x, y; /* current point */
- int color; /* current color */
- } gr_el;
-
-
- /* local routines */
- static void fixptr( ifsdes *dp, ftrans *tp0 );
- static int gcomp( const void *tr1, const void *tr2 );
- static int no_stop( void );
- static void far no_wpix( int x, int y, int color );
- static unsigned far no_rpix( int x, int y );
- static long dtl( double d );
- static double ltd( long l );
- static void probint( ftrans ftp[], int size, gr_el groups[], int ngroups,
- long gt_count, long delta_count );
- static int riterate( ftrans *ftp, gr_el *gp, int im, long count, long *ecountp,
- int (*stop)( void ),
- void (far *wpix)( int x, int y, int color ),
- unsigned (far *rpix)( int x, int y )
- );
-
- /* C or assembly routine */
- /*#define mul4f( a, b ) cmul4f( a, b ); /* */
- static long cmul4f( long a, long b );
-
-
- void ifsshow( dp, stop, estop, wpix, rpix )
- ifsdes *dp; /* the transformations */
- int (*stop)( void ); /* stop function */
- int estop; /* early miss stop flag */
- void (far *wpix)( int x, int y, int color ); /* write pixel */
- unsigned (far *rpix)( int x, int y ); /* read pixel, returns color */
- {
- int i;
- register int j;
- int size = dp -> size; /* number of transforms */
- ftrans *tp0; /* fixed point base pointer */
- register ftrans *tp; /* tmp */
- gr_el *grps; /* group specifier */
- gr_el *gp; /* tmp */
- int ngrps = dp -> maxgroup + 1; /* number of groups */
- int running; /* flag */
- long count; /* iteration count */
- long mcnt; /* miss count */
- long dcnt; /* tmp */
-
- /* normalize probabilities */
- normprob( dp -> tp, size );
-
- /* allocate a fixed point matrix array */
- if (!(tp0 = (ftrans *) malloc( size * sizeof (ftrans) + 100 )))
- error( "Out of memory for transformations (ifsshow)" );
-
- /* allocate group specifiers */
- if (!(grps = (gr_el *) malloc( ngrps * sizeof (gr_el) + 100 )))
- error( "Out of memory for groups (ifsshow)" );
-
- /* recompute the transforms to fixed point */
- fixptr( dp, tp0 );
-
- /* sort groups */
- qsort( tp0, size, sizeof (ftrans), gcomp );
-
- /* find the total number of iterations */
- count = DENS2ITER( dp -> density );
-
- /* set the group probabilities and such things */
- probint( tp0, size, grps, ngrps, count, 100L );
-
- /* the fifty initial iterations are not shown */
- for (gp = grps, i = 0, tp = tp0; (i < ngrps) && (tp < &tp0[size]); ++gp, ++i)
- {
- /* skip if it is an empty group */
- if (gp -> nels <= 0)
- continue;
-
- /* set current point & set color to background */
- gp -> x = gp -> y = gp -> color = 0;
-
- /* iterate */
- (void) riterate( tp, gp, dp -> im, 50L, &mcnt,
- no_stop, no_wpix, no_rpix );
-
- /* next group */
- tp += gp -> nels;
- }
-
- /* max missing count is controlled by the early stop parameter */
- mcnt = estop ? (count / 5) : count;
-
- /* now show the fractals */
- for (running = 1; running && (count > 0);)
- for (gp = grps, i = 0, tp = tp0; (i < ngrps) && (tp < &tp0[size]); ++gp, ++i)
- {
- /* skip if it is an empty group */
- if (gp -> nels <= 0)
- continue;
-
- /* how many iterations for this group? */
- /* accumulate fraction count (for groups with very low prob.) */
- j = (gp -> sumfrcnt += gp -> frcnt);
- gp -> sumfrcnt -= j;
- count -= (dcnt = gp -> dcount + j);
-
- /* iterate */
- if (!riterate( tp, gp, dp -> im, dcnt, &mcnt, stop, wpix, rpix ))
- {
- /* the stop() functions has sayed stop, so stop! */
- running = 0;
- break;
- }
- else if (mcnt < 0)
- {
- /* to many misses stop! */
- running = 0;
- break;
- }
-
- /* next group */
- tp += gp -> nels;
- }
-
- /* remember the density */
- dp -> prrdens = dp -> density - ITER2DENS( count );
-
- /* free() the vectors */
- free( tp0 );
- free( grps );
- }
-
- /* local routines */
-
- static void fixptr( dp, tp0 )
- ifsdes *dp; /* the transformations */
- ftrans *tp0; /* fixed point base pointer */
- {
- int i; /* tmp */
- area *ap = &dp -> area; /* the area */
- register transform *dtp; /* tmp */
- register ftrans *tp; /* tmp */
- double sx, sy; /* tmp */
-
- /* recompute the transformation matrix to fixed point, scaled to the screen */
- /*
- * One transformation is: Ax + b, x is the position,
- * g(x) takes this to screen coordinates.
- * Recompute the transformation to screen coordinates!
- * I.e. solve H and k from: g(Ax + b) = Hg(x) + k.
- * g(x) is the ap parameter and the screen size combined.
- */
- if (fabs( ap -> xlen ) > 1e-20)
- sx = MAX_COL / ap -> xlen;
- else
- sx = 1e20;
-
- if (fabs( ap -> ylen ) > 1e-20)
- sy = MAX_ROW / ap -> ylen;
- else
- sy = 1e20;
-
- for (i = dp -> size, tp = tp0, dtp = dp -> tp; i; --i, ++tp, ++dtp)
- {
- double z;
-
- tp -> a11 = dtl( dtp -> a11 );
- tp -> a12 = dtl( dtp -> a12 * sx / sy );
- tp -> a21 = dtl( dtp -> a21 * sy / sx );
- tp -> a22 = dtl( dtp -> a22 );
- z = dtp -> b1 + ap -> xlow * (dtp -> a11 - 1) + dtp -> a12 * ap -> ylow;
- tp -> b1 = dtl( sx * z );
- z = dtp -> b2 + ap -> ylow * (dtp -> a22 - 1) + dtp -> a21 * ap -> xlow;
- tp -> b2 = dtl( sy * z );
-
- /* copy the probability, the color and the group */
- tp -> prob = dtp -> prob;
- tp -> color = dtp -> color;
- tp -> group = dtp -> group;
- }
- }
-
- static int gcomp( const void *tr1, const void *tr2 )
- {
- /* group comparing function for sorting */
- return (((ftrans *)tr1) -> group - ((ftrans *)tr2) -> group);
- }
-
- static int no_stop( void )
- {
- /* fake function for the initial iterations */
- return (0);
- }
-
- static void far no_wpix( int x, int y, int color )
- {
- /* fake function for the initial iterations */
- /* fool the compiler to not warn about unused arguments */
- x = y; y = color; color = x;
- return;
- }
-
- static unsigned far no_rpix( int x, int y )
- {
- /* fake function for the initial iterations */
- /* fool the compiler to not warn about unused arguments */
- x = y; y = x;
- return (0);
- }
-
-
- static int riterate( ftp, gp, im, count, ecountp, stop, wpix, rpix )
- ftrans *ftp; /* the transformations */
- gr_el *gp; /* current group */
- int im; /* invariant measure mode flag */
- long count; /* number of iterations */
- long *ecountp; /* error max count */
- int (*stop)( void ); /* stop function */
- void (far *wpix)( int x, int y, int color ); /* write pixel */
- unsigned (far *rpix)( int x, int y ); /* read pixel, returns color */
- {
- register ftrans *tp; /* current transform */
- register int j; /* tmp */
- int r;
- int size1; /* one less than the number of transforms */
- long x, y; /* current point */
- long xt;
- unsigned int ix, iy;
- int prevclr; /* previous color */
-
- /* get number of transforms - 1, in this group */
- size1 = gp -> nels - 1;
-
- /* pick up where we left off */
- x = gp -> x;
- y = gp -> y;
- prevclr = gp -> color;
-
- for (; count > 0; --count)
- {
- if ((*stop)())
- {
- /* remember the stop and then stop */
- count = -1;
- break;
- }
-
- /* select */
- r = rand();
-
- /* use size1 to not fall out of the group */
- for (j = 0, tp = ftp; j < size1; ++j, ++tp)
- if (r < tp -> iprob) break;
-
- /* transform */
- /*xt = tp -> a11 * x + tp -> a12 * y + tp -> b1;*/
- xt = cmul4f( tp -> a11, x ) + cmul4f( tp -> a12, y ) + tp -> b1;
-
- /*y = tp -> a21 * x + tp -> a22 * y + tp -> b2;*/
- y = cmul4f( tp -> a21, x ) + cmul4f( tp -> a22, y ) + tp -> b2;
-
- x = xt;
-
- /* show */
- #ifdef PRONLY
- printf( "%d: tp0 %d tp %d delta %d ", j, tp0, tp, tp - tp0 );
- printf( "x %ld, y %ld (%d,%d)\n", x, y, FINT( x ), FINT( y ) );
-
- /* printf( "%10ld%10ld", x, y );*/
- continue;
- #endif
- ix = FINT( x );
- iy = FINT( y );
-
- if (ix >= MAX_COL || iy >= MAX_ROW)
- {
- /* decrease the error max */
- --(*ecountp);
- continue;
- }
-
- if (im)
- {
- /* invariant measure mode */
- /* check if max color index is reached */
- if ((j = (*rpix)( ix, MAX_ROW - iy )) >= im)
- continue;
- else ++j;
- }
- else if ((j = tp -> color) < 0) /* -1 means prev color */
- j = prevclr;
-
- /* show it */
- wpix( ix, MAX_ROW - iy, prevclr = j );
- }
-
- /* remember the status */
- gp -> x = x;
- gp -> y = y;
- gp -> color = prevclr;
-
- /* return 0 if (*stop)() or 1 if ok */
- return (count == 0);
- }
-
- static long dtl( d )
- double d;
- {
- /* convert to fixed point */
- /*printf( " %lf --> %ld ", d, (long)(d*FSCL) );*/
- return ((long)(d*FSCL));
- }
-
- static double ltd( l )
- long l;
- {
- /* convert from fixed point */
- /*printf( " %ld --> %lf ", d, ((double) l)/FSCL );*/
- return ((double)(l/FSCL));
- }
-
- /* Test versions */
- static long cmul4f( a, b )
- long a, b;
- {
- double d = a;
-
- d *= b;
- d /= FSCL;
- #ifdef PRONLY
- /*printf( " cmul4f:%lf ", d );*/
- #endif
- return ((long) d);
- }
-
- /* * /
- static long csq4f( a )
- long a;
- {
- return (cmul4f( a, a ));
- }
- /* */
-
- static void probint( ftp, size, grps, ngrps, count, dcount )
- ftrans ftp[]; /* the transformations */
- int size; /* number of transformations */
- gr_el grps[]; /* the group specs to be filled in */
- int ngrps; /* number of groups */
- long count; /* grand total count to distribute */
- long dcount; /* delta count wanted */
- {
- register int i, ig;
- gr_el *gp; /* current group */
- int prevp;
- ftrans *tp;
- double v;
-
- /* the ftp[] vector is sorted on groups */
-
- /* set up the group sizes and sum each groups prob. (temp use of sumfrcnt) */
- for (gp = grps, ig = 0, tp = ftp; ig < ngrps; ++gp, ++ig)
- {
- gp -> sumfrcnt = 0;
- gp -> dcount = 0;
- gp -> frcnt = 0;
- gp -> nels = 0;
- gp -> tcount = 0;
-
- /* out of transforms means empty group */
- if (tp)
- {
- /* count and sum up prob. */
- for (; tp -> group == ig; ++gp -> nels, ++tp)
- if (tp >= &ftp[size])
- {
- /* out of transforms! */
- tp = 0;
- break;
- }
- else gp -> sumfrcnt += tp -> prob;
-
- /* set the count for this group */
- gp -> tcount = count * gp -> sumfrcnt;
- v = dcount * gp -> sumfrcnt;
- gp -> dcount = v; /* integer part */
- gp -> frcnt = v - gp -> dcount; /* fraction */
-
- /* sumfrcnt should not be zero, see below */
- if (gp -> sumfrcnt <= 0) gp -> sumfrcnt = MINPROB;
- }
- }
-
- /* */
- /* recalculate the probabilities to suit rand() (integers) */
- /* make a sequence withint each group */
- for (tp = ftp, prevp = 0, i = 0, ig = tp -> group; i < size; ++tp, ++i)
- {
- /* new group? */
- if (tp -> group != ig)
- {
- prevp = 0;
- ig = tp -> group;
- }
-
- /* set and sum (sumfrcnt is not zero!) */
- prevp = (tp -> iprob = prevp +
- MAXRAND * tp -> prob / grps[ig].sumfrcnt);
- }
-
- /* clear sumfrcnt (usage as temp storage is over) */
- for (gp = grps, ig = 0; ig < ngrps; ++gp, ++ig)
- gp -> sumfrcnt = 0;
- }
-
-
-