Back to index

radiance  4R0+20100331
mplot.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: mplot.c,v 1.3 2003/11/15 02:13:37 schorsch Exp $";
00003 #endif
00004 /*
00005  *   Plotting routines for meta-files to line-at-a-time printers
00006  */
00007 
00008 
00009 #include  <stdio.h>
00010 #include  <string.h>
00011 #include  <fcntl.h>
00012 
00013 #include  "platform.h"
00014 #include  "meta.h"
00015 #include  "plot.h"
00016 #include  "span.h"
00017 
00018 
00019 
00020 int  minwidth = 0;
00021 
00022 static PLIST  inqueue = {NULL, NULL};
00023 
00024 static PRIMITIVE  nextp;
00025 
00026 static void initplot(void);
00027 static void plotspan(FILE *infp);
00028 static void doglobal(PRIMITIVE *g);
00029 static void doprim(PRIMITIVE *p);
00030 static void outputspan(void);
00031 static void tfill(PRIMITIVE *p);
00032 static void fill(int attrib, int xmin, int ymin, int xmax, int ymax);
00033 static void paintline(int x, int y, int run, int rise, int hrad, int vrad,
00034        int lpat, long run2, long rise2, int n);
00035 static void nextspan(void);
00036 
00037 
00038 void
00039 plot(         /* plot meta-file */
00040        FILE  *infp
00041 )
00042 {
00043 
00044     do {
00045        readp(&nextp, infp);
00046        initplot();
00047        while (inqueue.ptop != NULL || isprim(nextp.com))
00048            plotspan(infp);
00049        doglobal(&nextp);
00050        fargs(&nextp);
00051     } while (nextp.com != PEOF);
00052 
00053 }
00054 
00055 
00056 void
00057 initplot(void)                     /* initialize this plot */
00058 {
00059     thispage();
00060     outspan.xleft = 0;
00061     outspan.xright = dxsize - 1;
00062     outspan.ytop = dysize + linhite - 1;
00063     outspan.ybot = dysize;
00064 
00065 }
00066 
00067 
00068 
00069 void
00070 doglobal(                   /* execute a global command */
00071        PRIMITIVE  *g
00072 )
00073 {
00074     char  c;
00075     int  tty;
00076 
00077     switch (g->com) {
00078 
00079        case PEOF:
00080            break;
00081 
00082        case PDRAW:
00083            fflush(stdout);
00084            break;
00085 
00086        case PEOP:
00087            if (g->arg0 & 0200)            /* advance page */
00088               nextpage();
00089            else if (g->arg0 == 3)  /* continue down */
00090                contpage();
00091            else
00092                error(USER, "illegal continue direction in doglobal");
00093            break;
00094 
00095        case PPAUS:
00096            fflush(stdout);
00097            tty = open(TTY, O_RDWR);
00098            if (g->args != NULL) {
00099               write(tty, g->args, strlen(g->args));
00100               write(tty, " - (hit return to continue)", 27);
00101            } else
00102               write(tty, "\007", 1);
00103            do {
00104                c = '\n';
00105                read(tty, &c, 1);
00106            } while (c != '\n');
00107            close(tty);
00108            break;
00109 
00110        case PSET:
00111            set(g->arg0, g->args);
00112            break;
00113 
00114        case PUNSET:
00115            unset(g->arg0);
00116            break;
00117 
00118        case PRESET:
00119            reset(g->arg0);
00120            break;
00121 
00122        default:
00123            sprintf(errmsg, "unknown command '%c' in doglobal", g->com);
00124            error(WARNING, errmsg);
00125            break;
00126        }
00127 
00128 }
00129 
00130 
00131 
00132 void
00133 plotspan(                   /* plot next span */
00134        FILE  *infp
00135 )
00136 {
00137     PLIST  lastinq;
00138     register PRIMITIVE  *p;
00139 
00140                                    /* clear span */
00141     nextspan();
00142                                    /* plot from queue */
00143     lastinq.ptop = inqueue.ptop;
00144     lastinq.pbot = inqueue.pbot;
00145     inqueue.ptop = inqueue.pbot = NULL;
00146     while ((p = pop(&lastinq)) != NULL) {
00147        doprim(p);
00148        pfree(p);
00149     }
00150                                    /* plot from file */
00151     while (isprim(nextp.com) && CONV(nextp.xy[YMX],dysize) >= outspan.ybot) {
00152         doprim(&nextp);
00153        fargs(&nextp);
00154        readp(&nextp, infp);
00155     }
00156                                    /* print out span */
00157     outputspan();
00158 
00159 }
00160 
00161 
00162 void
00163 nextspan(void)              /* prepare next span */
00164 {
00165     register int  i;
00166     register char  *colp, *tcolp;
00167        
00168     if (spanmin <= spanmax) {                    /* clear span */
00169 
00170        i = nrows*dxsize;
00171        colp = outspan.cols;
00172        tcolp = outspan.tcols;
00173        while (i--)
00174            *colp++ = *tcolp++ = '\0';
00175     }
00176             
00177     outspan.ytop -= linhite;                     /* advance to next */
00178     outspan.ybot -= linhite;
00179     spanmin = dxsize;
00180     spanmax = 0;
00181 
00182 }
00183 
00184 
00185 void
00186 outputspan(void)            /* output span to printer */
00187 {
00188     register int  i;
00189     register char  *colp, *tcolp;
00190 
00191     if (spanmin <= spanmax) {                    /* overlay spans */
00192 
00193        i = nrows*dxsize;
00194        colp = outspan.cols;
00195        tcolp = outspan.tcols;
00196        while (i--)
00197            *colp++ |= *tcolp++;
00198     }
00199     printspan();                   /* print span */
00200 }
00201 
00202 
00203 void
00204 doprim(              /* plot primitive */
00205 register PRIMITIVE  *p
00206 )
00207 {
00208     register PRIMITIVE  *newp;
00209     
00210     switch (p->com) {
00211 
00212        case PLSEG:
00213            plotlseg(p);
00214            break;
00215 
00216        case PRFILL:
00217            fill((p->arg0&0103) | (pati[(p->arg0>>2)&03]<<2),
00218                      CONV(p->xy[XMN],dxsize),CONV(p->xy[YMN],dysize),
00219                      CONV(p->xy[XMX],dxsize)+(p->arg0&0100?-1:0),
00220                      CONV(p->xy[YMX],dysize)+(p->arg0&0100?-1:0));
00221            break;
00222 
00223        case PTFILL:
00224            tfill(p);
00225            break;
00226               
00227        case PMSTR:
00228            printstr(p);
00229            break;
00230 
00231        default:
00232            sprintf(errmsg, "unknown command '%c' in doprim", p->com);
00233            error(WARNING, errmsg);
00234            return;
00235     }
00236 
00237     if (CONV(p->xy[YMN],dysize) < outspan.ybot) {       /* save for next time */
00238         if ((newp = palloc()) == NULL)
00239             error(SYSTEM, "memory limit exceeded in doprim");
00240        mcopy((char *)newp, (char *)p, sizeof(PRIMITIVE));
00241        newp->args = savestr(p->args);
00242         add(newp, &inqueue);
00243     }
00244         
00245 }
00246 
00247 
00248 
00249 void
00250 plotlseg(            /* plot a line segment */
00251        register PRIMITIVE  *p
00252 )
00253 {
00254     register int  ti;
00255     long  run2 = 0L, rise2 = 0L;
00256     int  x, y, run, rise, xstop, ystop, hrad, vrad, lpat, n;
00257 
00258                                           /* compute line pattern */
00259     lpat = (p->arg0 >> 2) & 014;
00260     if (p->arg0 & 0100 && lpat != 0)
00261        lpat += 014;
00262     lpat |= p->arg0 & 03;
00263 
00264     ti = (p->arg0 >> 2) & 03;                    /* compute line radius */
00265     ti = WIDTH(ti) / 2;
00266     hrad = CONV(ti, dxsize);
00267     vrad = CONV(ti, dysize);
00268     if (hrad < minwidth)
00269        hrad = minwidth;
00270     if (vrad < minwidth)
00271        vrad = minwidth;
00272 
00273     x = CONV(p->xy[XMX], dxsize);         /* start at top */
00274     y = CONV(p->xy[YMX], dysize);
00275     run = CONV(p->xy[XMN], dxsize) - x;
00276     rise = CONV(p->xy[YMN], dysize) - y;
00277 
00278     if (p->arg0 & 0100)                          /* slope < 0; reverse x */
00279        x -= (run = -run);
00280 
00281     xstop = x + run;                      /* compute end point */
00282     ystop = y + rise;
00283 
00284     if ((ti = outspan.ytop+vrad+1-y) < 0) {      /* adjust to top of span */
00285        run2 = rise2 = (long)ti*run;
00286        x += rise2/rise;
00287        y += ti;
00288     }
00289 
00290     if ((ti = outspan.ybot-vrad-1-ystop) > 0) {  /* adjust to bottom of span */
00291         xstop += (long)ti*run/rise;
00292        ystop += ti;
00293     }
00294 
00295     if (abs(run) > -rise)
00296        n = abs(xstop - x);
00297     else
00298        n = y - ystop;
00299     
00300     paintline(x, y, run, rise, hrad, vrad, lpat, run2, rise2, n);
00301 
00302 }
00303 
00304 
00305 
00306 /*
00307  *  This routine paints a line with calls to fill().  The line can
00308  *    start and end at arbitrary points on a longer line segment.
00309  */
00310 void
00311 paintline(
00312        register int  x,
00313        register int  y,
00314        int  run,
00315        int  rise,
00316        int  hrad,
00317        int  vrad,
00318        int  lpat,
00319        long  run2,
00320        long  rise2,
00321        int  n
00322 )
00323 {
00324     int  xstep, ystep;
00325 
00326     if (run >= 0)
00327        xstep = 1;
00328     else {
00329        xstep = -1;
00330        run = -run;
00331     }
00332     if (rise >= 0)
00333        ystep = 1;
00334     else {
00335        ystep = -1;
00336        rise = -rise;
00337     }
00338     if (n < 0)
00339        n = max(run, rise);
00340 
00341     if (run > rise)
00342        while (n >= 0)
00343            if (run2 >= rise2) {
00344               fill(lpat, x-hrad, y-vrad, x+hrad, y+vrad);
00345               n--;
00346               x += xstep;
00347               rise2 += rise;
00348            } else {
00349               y += ystep;
00350               run2 += run;
00351            }
00352     else
00353        while (n >= 0)
00354            if (rise2 >= run2) {
00355               fill(lpat, x-hrad, y-vrad, x+hrad, y+vrad);
00356               n--;
00357               y += ystep;
00358               run2 += run;
00359            } else {
00360               x += xstep;
00361               rise2 += rise;
00362            }
00363 
00364 }
00365 
00366 
00367 void
00368 tfill(               /* fill a triangle */
00369        register PRIMITIVE  *p
00370 )
00371 {
00372     register int  x, txmin, txmax; 
00373     int  xmn, ymn, tpat;
00374     long  xsz, ysz;
00375 
00376     xmn = CONV(p->xy[XMN], dxsize);
00377     xsz = CONV(p->xy[XMX], dxsize) - xmn;
00378     ymn = CONV(p->xy[YMN], dysize);
00379     ysz = CONV(p->xy[YMX], dysize) - ymn;
00380     if (xsz <= 0 || ysz <= 0)
00381        return;       
00382     txmin = (outspan.ybot - ymn)*xsz/ysz;
00383     txmax = (outspan.ytop - ymn)*xsz/ysz;
00384     if (p->arg0 & 020) {                         /* up or down */
00385        x = txmin;
00386        txmin = xsz - txmax;
00387        txmax = xsz - x;
00388     }
00389     txmin += xmn;
00390     txmax += xmn;
00391     txmin = max(txmin, xmn);
00392     txmax = min(txmax, xmn + (int)xsz - 1);
00393     tpat = (p->arg0&0103) | (pati[(p->arg0>>2)&03]<<2);
00394 
00395     if (p->arg0 & 040) {                         /* left or down */
00396        fill(tpat, xmn, ymn, txmin - 1, ymn + (int)ysz - 1);
00397        for (x = txmin; x <= txmax; x++)
00398            if (p->arg0 & 020)                    /* down */
00399               fill(tpat, x, ymn, x, (int)(ysz-(x-xmn)*ysz/xsz) + ymn - 1);
00400            else                           /* left */
00401               fill(tpat, x, (int)((x-xmn)*ysz/xsz) + ymn, x, ymn + (int)ysz - 1);
00402     } else {                                     /* right or up */
00403        for (x = txmin; x <= txmax; x++)
00404            if (p->arg0 & 020)                    /* up */
00405               fill(tpat, x, (int)(ysz-(x-xmn)*ysz/xsz) + ymn, x, ymn + (int)ysz - 1);
00406            else                           /* right */
00407               fill(tpat, x, ymn, x, (int)((x-xmn)*ysz/xsz) + ymn - 1);
00408        fill(tpat, txmax + 1, ymn, xmn + (int)xsz - 1, ymn + (int)ysz - 1);
00409     }
00410 }
00411 
00412 
00413 
00414 void
00415 fill(  /* fill rectangle with attribute */
00416        int  attrib,
00417        int  xmin,
00418        int ymin,
00419        int xmax,
00420        int ymax
00421 )
00422 {
00423     int  filpat;
00424     int  rpos;
00425     unsigned char  *pattr;
00426     register char  *colp;
00427     register int  i;
00428 
00429     xmin = max(xmin, outspan.xleft) - outspan.xleft;
00430     ymin = max(ymin, outspan.ybot) - outspan.ybot;
00431     xmax = min(xmax, outspan.xright) - outspan.xleft;
00432     ymax = min(ymax, outspan.ytop) - outspan.ybot;
00433 
00434     for (rpos = 0; rpos < nrows; rpos++)
00435 
00436        if (rpos >= ymin >> 3 && rpos <= ymax >> 3) {
00437 
00438            filpat = 0377;
00439            if (rpos == ymin >> 3) {
00440               i = ymin & 07;
00441               filpat = (filpat >> i) << i;
00442            }
00443            if (rpos == ymax >> 3) {
00444               i = ~ymax & 07;
00445               filpat = ((filpat << i) & 0377) >> i;
00446            }
00447 
00448            pattr = pattern[(attrib&074)>>2]
00449                             [((outspan.ybot>>3)+rpos)%(PATSIZE>>3)];
00450 
00451            if (attrib & 0100) {
00452               colp = &outspan.tcols[rpos*dxsize + xmin];
00453               for (i = xmin; i <= xmax; i++)
00454                   *colp++ ^= filpat & pattr[i%PATSIZE];
00455            } else {
00456               colp = &outspan.cols[rpos*dxsize + xmin];
00457               for (i = xmin; i <= xmax; i++)
00458                   *colp++ |= filpat & pattr[i%PATSIZE];
00459            }
00460 
00461            spanmin = min(xmin, spanmin);
00462            spanmax = max(xmax, spanmax);
00463        }
00464 
00465 }