home *** CD-ROM | disk | FTP | other *** search
- /* stitch.c 1.0++, with no Rlink
- This program maintains a list of squares which define the area on the screen.
- Squares are doubly linked, and abutting squares must be 2x, 1x or .5x in size.
- Squares which are surrounded by neighbors of the same color do not get split.
- /**/
-
- #include <define.h>
- #include <stdio.h>
- #include <debug.h>
- #include <osbind.h>
-
- #define Nsquares 5000
- struct stitches
- { int x, y, lev; /* in raster coords */
- int queue;
- int count;
- int nrec;
- /* long Zr,Zi;/**/ /* 0 L */
- int Llink[4]; /* +-------------+ */
- } *stp; /* st[Nsquares]; /* | links | 1 L */
- long nsquares; /* | from this | */
- /* 3 L | square | */
- /* +-------------+ */
- /* 2 L */
- int free_queue;
- int point_mode; /* -1 = first box, 0 = boxes, 1 = point */
- #define LEVELS 10
- int queue[LEVELS], max_lev;
- int cos[5] = {0,0,1,1,0};
- int rot[5] = {0,1,0,-1,0};
- int xmax, ymax;
- int nrec; /* debug recursive limit */
- int no_check; /* shared with window */
-
- st_inz(log_length, x, y)
- int log_length, x, y;
- { int i, j;
- register long rqd, got;
- register struct stitches *st1;
- xmax = x; ymax = y;
- if (nsquares == 0)
- { got = Malloc( (long) -1);
- rqd = 1<<log_length; rqd = rqd * rqd/4* sizeof(struct stitches);
-
- /* the /8 below is very heuristic! most screens plot 50%, and the square
- defined is 1.5x horiz and 2.5x vertical. 2*1.5*2.5 =~ 8 */
-
- if (got < rqd/8)
- { /*view_screen();*/
- if (1==form_alert(0, "[1][Need more memory! Otherwise\
- |inacurate pictures will be|drawn. Remove RAMDISKS, etc.|and restart]\
- [exit|try anyhow]")) exit();
- /*draw_on_screen();*/
- }
- if (got > rqd) got = rqd;
- stp = Malloc(got);
- if (stp == 0)
- panic("Error getting memory for BOX data structure\n");
- nsquares = got/sizeof(struct stitches);
- }
- free_queue = 2; /* form free queue */
- point_mode = -1;
- for (st1=stp, i=0; i<nsquares; i++)
- { register int *p;
- p = (int *) st1; /* clear whole structure: */
- for (j=sizeof(struct stitches)/sizeof(int); j>0; j--)
- *p++ = 0;
- if (i>=2)
- { st1->queue = i+1;
- st1->lev = -1;
- }
- st1++;
- }
- (stp+nsquares-1)->queue = 0; /* end of free queue */
-
- stp->count = -1; /* NULL has don't care color */
- (stp+1)->lev = log_length; /* starting box defined by args */
- queue[log_length] = 1; /* put starting box on work queue */
-
- max_lev = log_length;
- for (i=0; i<log_length; i++) /* all other queues are empty */
- queue[i] = 0;
- st_check("Inz");
- }
-
- st_do_next()
- { int i, lev, next_sq, count, nr;
- struct stitches *p;
- if (point_mode < 0)
- { (stp + 1)->count = dr_xy(0, 0, 1 << ((stp+1)->lev) );
- point_mode = 0;
- }
- while (1)
- { for (lev = max_lev; queue[lev] == 0; ) /* find lowest level */
- { if (--lev < 0)
- { dprintf(stderr, "queues %d-0 empty, returning (0)\n",
- max_lev);/**/
- return (0);
- } }
- dprintf(stderr, "dequeueing from queue[%d]: %d\n", lev, queue[lev]);/**/
- next_sq = queue[lev];
- queue[lev] = (stp+next_sq)->queue; /* dequeue it */
- if (lev >= max_lev -4 )
- { dprintf(stderr, "Too coarse: %d >= %d\n", lev, max_lev-1);/**/
- st_check("C\b");/**/
- st_chop(next_sq, 0); /* do it if coarse */
- return(1);
- }
- else if (lev != 0)
- { register int ncount;
- register struct stitches *pl, *pr;
- p = stp + next_sq;
- count = p->count >>2; /* >>2 is DIRTY */
- dprintf(stderr, "n="); st_print(next_sq);
- for (i = 0; i<4; i++) /* do it if neighbors differnt*/
- { dprintf(stderr, "L=");st_print(p->Llink[i]);/**/
- pl = stp + p->Llink[i];
- ncount = pl->count >>2;
- if ((ncount >=0) && (count != ncount))
- { dprintf(stderr, "neighbor's color mismatchs\n");/**/
- st_check("c");
- st_chop(next_sq, 0);
- return (1);
- }
- if ((nr = pl->Llink[(i+1)&3]) == 0)
- continue;
- dprintf(stderr, "R=", nr);/**/
- ncount = (stp + nr)->count >>2;
- if ((ncount >=0) && (count != ncount))
- { dprintf(stderr, "neighbor's color mismatchs\n");/**/
- st_check("e");
- st_chop(next_sq, 0);
- return (1);
- } }
- dprintf(stderr, "colors match, no need to split\n");/**/
- }
- else dprintf(stderr, "can't split -- at lowest level\n");/**/
- } }
-
-
- st_chop(square, which) /* into 4 subsquares, maintaining links, and that */
- int square, which; /* all neighbors are within a factor of two in size*/
- /* returns new[which] */
- { /*register*/ struct stitches *p, *p_new[4], *p_neighbor, *p1;
- struct stitches *p_new_i, *p_new_k;
- int new[4], i, j, k, l, neighbor, l_n, lev, len, x, y;
- int m, qv, mask, *pq;
-
- nrec++;
- p = stp + square;
- if (point_mode)
- { register int foo;
- point__mode: l = 1 << p->lev;
- x = p->x; y = p->y;
-
- j=1; /* all boxes except upper left one */
- for (i=0; i<l; i++)
- { for (; j<l; j++)
- dr_xy(x+i, y+j, 1);
- j=0;
- }
- return;
- }
- lev = p->lev - 1;
- /* if (lev > max_lev) max_lev = lev; /* update max level to work on*/
- len = 1 << lev;
- x = p->x; y = p->y;
-
- for (i = 0; i<4; i++)
- { register int *pint;
- if ((new[i]=free_queue)==0)
- { point_mode = 1;
- goto point__mode;
- panic("Ran out of squares\n",0L,0L);/**/
- }
- p1 = stp + free_queue;
- p_new[i] = p1;
- free_queue = p1->queue; /* grab new box */
- }
- pq = queue + lev;
- qv = *pq; /*enqueue "that work needs to be done"*/
- mask = (x+len > xmax)*6 | (y+len > ymax)*12;
- dprintf(stderr,"enqueue[%d]: ", lev);/**/
- for (m=0; m<4; m++, mask >>=1)
- { if ((mask & 1)==0) /* enqueue only if within screen */
- { *pq = new[m];
- pq = &((stp + new[m])->queue);
- dprintf(stderr,"%d#%x, ", new[m], mask);/**/
- } }
- *pq = qv; /* finish enqueue */
- dprintf(stderr,"\n");/**/
-
- for (i = 0; i<4; i++)
- { k = i+1 & 3;
- j = i+2 & 3;
- l = i+3 & 3;
- /* dprintf(stderr,"i=%d",i);/**/
- p_new_i = p_new[i];
- p_new_k = p_new[k];
- p_new_i->x = x + cos[i+1]*len;
- p_new_i->y = y + cos[i]*len;
- p_new_i->lev = lev;
- p_new_i->nrec = nrec;
- p_new_i->Llink[k] = new[k];
- p_new_k->Llink[l] = new[i];
- if ((neighbor = p->Llink[i]) <= 0)
- { /*dprintf(stderr,"null links\n");/**/
- p_new_i->Llink[i] = 0;
- p_new_k->Llink[i] = 0;
- }else
- { p_neighbor = stp + neighbor;
-
- l_n = p->lev - p_neighbor->lev;
- /* dprintf(stderr,"l_n=%d, ",l_n);/**/
- if (l_n > 0) /* if neighbors were smaller: */
- { /*dprintf(stderr,"neighbors were smaller\n");/**/
- p_new_i->Llink[i] = neighbor; /* link left */
- p_neighbor->Llink[j] = new[i];
-
- if (neighbor = p_neighbor->Llink[k])
- { p_neighbor = stp + neighbor;
- p_new_k->Llink[i] = neighbor; /* link right */
- p_neighbor->Llink[j] = new[k];
- }else
- panic("nei<, but no right one\n");
- }
- else
- { /* if neighbor was bigger, split him! */
- if (l_n < 0) /* RECURSIVE CALL */
- { m = (p_neighbor->Llink[j]==square)?j:l;
- neighbor = st_chop(neighbor, m);
- /* dprintf(stderr,"\ndone split, now neighbor=%d\n"
- , neighbor);/**/
- p_neighbor = stp + neighbor;
- } /* neighbor was same size: */
- /* dprintf(stderr,"neighbor was same size\n");/**/
- p_new_i->Llink[i] = neighbor;
- p_new_k->Llink[i] = neighbor;
- p_neighbor->Llink[j] = new[k];
- } }
- if (i==0) /*split-up bead to upper-left bead */
- p_new_i->count = p->count;
- else
- p_new_i->count = dr_xy(p_new_i->x, p_new_i->y,
- 1 << p_new_i->lev);
- }
- p->queue = free_queue; /* split-up bead to free list */
-
- /* diagnostic only */
- p->lev = -1;
- p->x = p->y = p->nrec =0;
- p->Llink[0] = p->Llink[1] = p->Llink[2] = p->Llink[3] = 0;
-
- free_queue = square;
- return (new[which]);
- }
-
- int chk, chk_i, chk_n, bchk;
- #define bcheck(arg1, arg2) check((bchk=(arg1))>=nsquares, 0, "arg2 > nsquares"); check(bchk<0, 0, "arg2 <0");
-
- st_check(label)
- char *label;
- { struct stitches *p, *p_I, *p_IJ, *p_IK;
- int n_I, n_IJ, n_IK, n_IKJ, n_IJL;
- int lev, lev_I;
- int len, len_I;
- int i, j, k, l;
- int x, y, x1, y1, vx, vy;
-
- nrec = 0;
- if (no_check) return;
- printf(label);
- chk = free_queue;
- while (chk)
- { register struct stitches *st1;
- register int *a, b;
- st1 = stp + chk;
- check(st1->x ==0 && st1->y == 0 && st1->nrec ==0, 1,
- "free queue clobbered");
- for (a = &(st1->Llink[0]), b=0; b++<4;)
- if (*a++ != 0)
- check (0,1,"free queue link element clobbered");
- check(st1->lev == -1, 1, "free queue element not -1");
- bcheck (chk = st1->queue, free_queue);
- }
- for (chk = 1; chk<nsquares; chk++)
- { p = stp + chk;
- x = p->x; y = p->y;
- if ((lev = p->lev) <0)
- continue; /* don't process if on free queue*/
- len = 1 << lev;
-
- for (i = 0; i<4; i++)
- { k = i+1 & 3;
- j = i+2 & 3;
- l = i+3 & 3;
- chk_i = i;
- bcheck( chk_n = n_I = p->Llink[i], Llink);
-
- if (n_I == 0)
- continue;
- p_I = stp + n_I;
-
- lev_I = p_I->lev;
- len_I = 1 << lev_I;
- bcheck(n_IJ= p_I->Llink[j], n_IJ);
- p_IJ = stp + n_IJ;
- switch (lev - lev_I) /* relative size of neighbors */
- { case (-1): /* neighbor bigger */
- vy = -6;
- if (n_IJ == chk)
- vx = -2;
- else
- { vx = 2;
- bcheck(n_IJL = p_IJ->Llink[l], n_IJL);
- check(n_IJL, chk, "n_IJL != chk");
- }
- break;
- case (0): /* neighbor same size */
- vy = -4; vx = 0;
- check(n_IJ,chk,"n_IJ != chk");
- break;
- case (1): /* neighbor smaller */
- vy = -3; vx = -1;
-
- bcheck(n_IK = p_I->Llink[k], n_IK);
- p_IK = stp + n_IK;
- bcheck(n_IKJ = p_IK->Llink[j], n_IKJ);
- check(n_IKJ, chk, "n_IKJ != chk");
- break;
- default:
- check(1,0, "sizes not within factor of 2");
- }
- x1 = x + ((2 + rot[i+1]*vx - rot[i]*vy)*len-2*len_I)/4;
- y1 = y + ((2 + rot[i]*vx + rot[i+1]*vy)*len-2*len_I)/4;
- check(p_I->x, x1,"x bad");
- check(p_I->y, y1,"y bad");
- } } }
-
- check(a, b, str)
- int a, b;
- char *str;
- { if (a == b) return;
- printf("==========\n%d|%d Inconsistent with %d\n", chk, chk_i, chk_n);
- printf("'%s', %d != %d.\n", str, a, b);
- st_pl("base", chk);
- st_pl("neighbor", chk_n);
- st_kbd();
- }
-
- st_kbd()
- { char input[50], *ip;
- int i;
- while(1)
- { printf("-* ");
- for (ip=input; (*ip=getchar()) != ' '; ip++);
- *ip = 0;
- switch (input[0])
- { case ('q'): return;
- case ('c'): no_check = 1-no_check;
- case ('C'):
- scanf(input+1, "%d", &i);
- printf("Next pass will be %d\n",i);
- chk = i-1;
- return;
- case ('e'): chk = nsquares; break;
- case ('?'):
- printf("*q*uit, *c*heck off, *e*nd pass\n");
- printf("*C*heck <n>, term with ' '\n");
- break;
- default:
- sscanf(input, "%d",&i);
- st_pl("kbd",i);
- } } }
-
- st_pl(name,s)
- char *name;
- int s;
- { register struct stitches *stf;
- int i;
- stf = stp + s;
- printf("%s: L%d/%d/%d/%d nr=%d\n (%d) q=%d (%d,%d)-%d\n",
- name, stf->Llink[0], stf->Llink[1], stf->Llink[2], stf->Llink[3],
- stf->nrec, s, stf->queue,stf->x, stf->y, ((i=stf->lev) >=0)? 1<<i: i);
- }
-
- st_print(s)
- int s;
- { register struct stitches *stf;
- stf = stp + s;
- dprintf(stderr,"%d c%d %d/%d/%d/%d (%d,%d)-%d\n",
- s, stf->count,
- stf->Llink[0], stf->Llink[1], stf->Llink[2], stf->Llink[3],
- stf->x, stf->y, 1<<stf->lev);/**/
- }
-