Annotation of researchv10no/cmd/postscript/dpost/draw.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *
                      3:  * Drawing routines used by dpost. Almost no real work is done here. Instead
                      4:  * the required calculations are done in special Postscript procedures that
                      5:  * include:
                      6:  *
                      7:  *
                      8:  *     Dl
                      9:  *
                     10:  *       x1 y1 x y Dl -
                     11:  *
                     12:  *         Starts a new path and then draws a line from the current point
                     13:  *         (x, y) to (x1, y1).
                     14:  *
                     15:  *     De
                     16:  *
                     17:  *       x y a b De -
                     18:  *
                     19:  *         Starts a new path and then draws an ellipse that has its left side
                     20:  *         at the current point (x, y) and horizontal and vertical axes lengths
                     21:  *         given by a and b respectively.
                     22:  *
                     23:  *     Da
                     24:  *
                     25:  *       x y dx1 dy1 dx2 dy2 Da -
                     26:  *
                     27:  *         Starts a new segment and then draws a circular arc from the current
                     28:  *         point (x, y) to (x + dx1 + dx2, y + dy1 + dy2). The center of the
                     29:  *         circle is at (x + dx1, y + dy1). Arcs always go counter-clockwise
                     30:  *         from the starting point to the end point.
                     31:  *
                     32:  *     DA
                     33:  *
                     34:  *       x y dx1 dy1 dx2 dy2 DA -
                     35:  *
                     36:  *         Draws a clockwise arc from (x, y) to (x + dx1 + dx2, y + dy1 + dy2)
                     37:  *         with center at (x + dx1, y + dy1). Only needed when we're building
                     38:  *         large paths that use arcs and want to control the current point. The
                     39:  *         arguments passed to drawarc() will be whatever they would have been
                     40:  *         for a counter-clockwise arc, so we need to map them into appropriate
                     41:  *         arguments for PostScript's arcn operator. The mapping is,
                     42:  *
                     43:  *                     x = hpos + dx1' + dx2'
                     44:  *                     y = vpos + dy1' + dy2'
                     45:  *                     dx1 = -dx2'
                     46:  *                     dy1 = -dy2'
                     47:  *                     dx2 = -dx1'
                     48:  *                     dy2 = -dy1'
                     49:  *
                     50:  *        where primed values represent the drawarc() arguments and (hpos, vpos)
                     51:  *        is our current position.
                     52:  *
                     53:  *     Ds
                     54:  *
                     55:  *       x0 y0 x1 y1 x2 y2 Ds -
                     56:  *
                     57:  *         Starts a new segment and then draws a quadratic spline connecting
                     58:  *         point ((x0 + x1)/2, (y0 + y1)/2) to ((x1 + x2)/2, (y1 + y2)/2).
                     59:  *         The points used in Postscript's curveto procedure are given by,
                     60:  *
                     61:  *             x0' = (x0 + 5 * x1) / 6
                     62:  *             x1' = (x2 + 5 * x1) / 6
                     63:  *             x2' = (x1 + x2) / 2
                     64:  *
                     65:  *         with similar equations for the y coordinates.
                     66:  *
                     67:  * By default all the PostScript drawing procedures begin with a newpath (just to
                     68:  * be safe) and end with a stroke, which essentially isolates the path elements
                     69:  * built by the drawing procedures. In order to accommodate big paths built from
                     70:  * smaller pieces each of the PostScript drawing procedures can forced to retain
                     71:  * the path that's being built. That's what happens in beginpath() when an "x X
                     72:  * BeginPath" command is read. beginpath() sets the PostScript variable inpath to
                     73:  * true, and that essentially eliminates the newpath/stroke pair that bracket the
                     74:  * individual pieces. In that case the path is terminated and drawn when dpost
                     75:  * reads an "x X DrawPath" command.
                     76:  *
                     77:  * Early versions of dpost included the PostScript drawing procedures as part of
                     78:  * the prologue, and as a result they were included with every job, even if they
                     79:  * were never used. This version has separated the drawing procedures from the
                     80:  * default prologue (they're now in *drawfile) and only includes them if they're
                     81:  * really needed, which is yet another convenient violation of page independence.
                     82:  * Routine getdraw() is responsible for adding *drawfile to the output file, and
                     83:  * if it can't read *drawfile it continues on as if nothing happened. That means
                     84:  * everything should still work if you append *drawfile to *prologue and then
                     85:  * delete *drawfile.
                     86:  *
                     87:  */
                     88: 
                     89: #include <stdio.h>
                     90: #include <math.h>
                     91: 
                     92: #include "gen.h"                       /* general purpose definitions */
                     93: #include "ext.h"                       /* external variable definitions */
                     94: #include "motion.h"                    /* positioning macros */
                     95: 
                     96: int    gotdraw = FALSE;                /* TRUE when *drawfile has been added */
                     97: int    gotbaseline = FALSE;            /* TRUE after *baselinefile is added */
                     98: int    inpath = FALSE;                 /* TRUE if we're putting pieces together */
                     99: 
                    100: /*
                    101:  *
                    102:  * All these should be defined in file dpost.c.
                    103:  *
                    104:  */
                    105: 
                    106: extern int             hpos;
                    107: extern int             vpos;
                    108: extern int             encoding;
                    109: extern int             maxencoding;
                    110: extern int             realencoding;
                    111: 
                    112: extern char            *drawfile;
                    113: extern char            *baselinefile;
                    114: extern FILE            *tf;
                    115: 
                    116: /*****************************************************************************/
                    117: 
                    118: getdraw()
                    119: 
                    120: {
                    121: 
                    122: /*
                    123:  *
                    124:  * Responsible for making sure the PostScript drawing procedures are downloaded
                    125:  * from *drawfile. Stuff is done at most once per job, and only if the job needs
                    126:  * them. For now I've decided not to quit if we can't read the drawing file. That
                    127:  * pretty much assumes an old version of prologue is being used that includes all
                    128:  * the drawing procedures.
                    129:  *
                    130:  */
                    131: 
                    132:     if ( gotdraw == FALSE )
                    133:        exportfile(drawfile);
                    134: 
                    135:     if ( tf == stdout )
                    136:        gotdraw = TRUE;
                    137: 
                    138: }   /* End of getdraw */
                    139: 
                    140: /*****************************************************************************/
                    141: 
                    142: drawline(dx, dy)
                    143: 
                    144:     int                dx, dy;                 /* endpoint is (hpos+dx, vpos+dy) */
                    145: 
                    146: {
                    147: 
                    148: /*
                    149:  *
                    150:  * Draws a line from (hpos, vpos) to (hpos+dx, vpos+dy), and leaves the current
                    151:  * position at the endpoint.
                    152:  *
                    153:  */
                    154: 
                    155:     if ( dx == 0 && dy == 0 )
                    156:        drawcirc(1);
                    157:     else fprintf(tf, "%d %d %d %d Dl\n", hpos + dx, vpos + dy, hpos, vpos);
                    158: 
                    159:     if ( dobbox == TRUE ) {
                    160:        cover((double)hpos, (double)-vpos);
                    161:        cover((double)(hpos + dx), (double)-(vpos + dy));
                    162:     }  /* End if */
                    163: 
                    164:     hgoto(hpos+dx);                    /* where troff expects to be */
                    165:     vgoto(vpos+dy);
                    166: 
                    167:     resetpos();                                /* not sure where the printer is */
                    168: 
                    169: }   /* End of drawline */
                    170: 
                    171: /*****************************************************************************/
                    172: 
                    173: drawcirc(d)
                    174: 
                    175:     int                d;                      /* diameter of the circle */
                    176: 
                    177: {
                    178: 
                    179: /*
                    180:  *
                    181:  * Draws a circle of diameter d with the left 'side' of the circle at the
                    182:  * current point. After we're finished drawing we move the current position
                    183:  * to the right side.
                    184:  *
                    185:  */
                    186: 
                    187:     drawellip(d, d);
                    188: 
                    189: }   /* End of drawcirc */
                    190: 
                    191: /*****************************************************************************/
                    192: 
                    193: drawellip(a, b)
                    194: 
                    195:     int                a, b;                   /* axes lengths for the ellipse */
                    196: 
                    197: {
                    198: 
                    199: /*
                    200:  *
                    201:  * Draws an ellipse having axes lengths horizontally and vertically of a and
                    202:  * b. The left side of the ellipse is at the current point. After we're done
                    203:  * drawing the path we move the current position to the right side.
                    204:  *
                    205:  */
                    206: 
                    207:     if ( a == 0 && b == 0 )
                    208:        return;
                    209: 
                    210:     fprintf(tf, "%d %d %d %d De\n", hpos, vpos, a, b);
                    211: 
                    212:     if ( dobbox == TRUE ) {
                    213:        cover((double)hpos, (double)-(vpos + b/2));
                    214:        cover((double)(hpos+a), (double)-(vpos - b/2));
                    215:     }  /* End if */
                    216: 
                    217:     hgoto(hpos + a);                   /* where troff expects to be */
                    218:     vgoto(vpos);
                    219: 
                    220:     resetpos();                                /* not sure where the printer is */
                    221: 
                    222: }   /* End of drawellip */
                    223: 
                    224: /*****************************************************************************/
                    225: 
                    226: drawarc(dx1, dy1, dx2, dy2, c)
                    227: 
                    228:     int                dx1, dy1;               /* vector from current pos to center */
                    229:     int                dx2, dy2;               /* from center to end of the arc */
                    230:     int                c;                      /* clockwise if c is A */
                    231: 
                    232: {
                    233: 
                    234: /*
                    235:  *
                    236:  * If c isn't set to 'A' a counter-clockwise arc is drawn from the current point
                    237:  * (hpos, vpos) to (hpos+dx1+dx2, vpos+dy1+dy2). The center of the circle is the
                    238:  * point (hpos+dx1, vpos+dy1). If c is 'A' the arc goes clockwise from the point
                    239:  * (hpos+dx1+dx2, vpos+dy1+dy2) to (hpos, vpos). Clockwise arcs are only needed
                    240:  * if we're building a larger path out of pieces that include arcs, and want to
                    241:  * have PostScript manage the path for us. Arguments (for a clockwise arc) are
                    242:  * what would have been supplied if the arc was drawn in a counter-clockwise
                    243:  * direction, and are converted to values suitable for use with PostScript's arcn
                    244:  * operator.
                    245:  *
                    246:  */
                    247: 
                    248:     if ( (dx1 != 0 || dy1 != 0) && (dx2 != 0 || dy2 != 0) ) {
                    249:        if ( c != 'A' )
                    250:            fprintf(tf, "%d %d %d %d %d %d Da\n", hpos, vpos, dx1, dy1, dx2, dy2);
                    251:        else fprintf(tf, "%d %d %d %d %d %d DA\n", hpos+dx1+dx2, vpos+dy1+dy2,
                    252:                                                -dx2, -dy2, -dx1, -dy1);
                    253: 
                    254:        if ( dobbox == TRUE )
                    255:            arc_extreme(dx1, dy1, dx2, dy2);
                    256:     }  /* End if */
                    257: 
                    258:     hgoto(hpos + dx1 + dx2);           /* where troff expects to be */
                    259:     vgoto(vpos + dy1 + dy2);
                    260: 
                    261:     resetpos();                                /* not sure where the printer is */
                    262: 
                    263: }   /* End of drawarc */
                    264: 
                    265: /*****************************************************************************/
                    266: 
                    267: drawspline(fp, flag)
                    268: 
                    269:     FILE       *fp;                    /* input for point list */
                    270:     int                flag;                   /* flag!=1 connect end points */
                    271: 
                    272: {
                    273: 
                    274:     int                x[100], y[100];
                    275:     int                i, N;
                    276: 
                    277: /*
                    278:  *
                    279:  * Spline drawing routine for Postscript printers. The complicated stuff is
                    280:  * handled by procedure Ds, which should be defined in the library file. I've
                    281:  * seen wrong implementations of troff's spline drawing, so fo the record I'll
                    282:  * write down the parametric equations and the necessary conversions to Bezier
                    283:  * cubic splines (as used in Postscript).
                    284:  *
                    285:  *
                    286:  * Parametric equation (x coordinate only):
                    287:  *
                    288:  *
                    289:  *         (x2 - 2 * x1 + x0)    2                    (x0 + x1)
                    290:  *     x = ------------------ * t   + (x1 - x0) * t + ---------
                    291:  *                 2                                      2
                    292:  *
                    293:  *
                    294:  * The coefficients in the Bezier cubic are,
                    295:  *
                    296:  *
                    297:  *     A = 0
                    298:  *     B = (x2 - 2 * x1 + x0) / 2
                    299:  *     C = x1 - x0
                    300:  *
                    301:  *
                    302:  * while the current point is,
                    303:  *
                    304:  *     current-point = (x0 + x1) / 2
                    305:  *
                    306:  * Using the relationships given in the Postscript manual (page 121) it's easy to
                    307:  * see that the control points are given by,
                    308:  *
                    309:  *
                    310:  *     x0' = (x0 + 5 * x1) / 6
                    311:  *     x1' = (x2 + 5 * x1) / 6
                    312:  *     x2' = (x1 + x2) / 2
                    313:  *
                    314:  *
                    315:  * where the primed variables are the ones used by curveto. The calculations
                    316:  * shown above are done in procedure Ds using the coordinates set up in both
                    317:  * the x[] and y[] arrays.
                    318:  *
                    319:  * A simple test of whether your spline drawing is correct would be to use cip
                    320:  * to draw a spline and some tangent lines at appropriate points and then print
                    321:  * the file.
                    322:  *
                    323:  */
                    324: 
                    325:     for ( N = 2; N < sizeof(x)/sizeof(x[0]); N++ )
                    326:        if (fscanf(fp, "%d %d", &x[N], &y[N]) != 2)
                    327:                break;
                    328: 
                    329:     x[0] = x[1] = hpos;
                    330:     y[0] = y[1] = vpos;
                    331: 
                    332:     for (i = 1; i < N; i++) {
                    333:        x[i+1] += x[i];
                    334:        y[i+1] += y[i];
                    335:     }  /* End for */
                    336: 
                    337:     x[N] = x[N-1];
                    338:     y[N] = y[N-1];
                    339: 
                    340:     for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) {
                    341:        fprintf(tf, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]);
                    342:        if ( dobbox == TRUE ) {         /* could be better */
                    343:            cover((double)(x[i] + x[i+1])/2,(double)-(y[i] + y[i+1])/2);
                    344:            cover((double)x[i+1], (double)-y[i+1]);
                    345:            cover((double)(x[i+1] + x[i+2])/2, (double)-(y[i+1] + y[i+2])/2);
                    346:        }   /* End if */
                    347:     }  /* End for */
                    348: 
                    349:     hgoto(x[N]);                       /* where troff expects to be */
                    350:     vgoto(y[N]);
                    351: 
                    352:     resetpos();                                /* not sure where the printer is */
                    353: 
                    354: }   /* End of drawspline */
                    355: 
                    356: /*****************************************************************************/
                    357: 
                    358: arc_extreme(dx1, dy1, dx2, dy2)
                    359: 
                    360:     int                dx1, dy1, dx2, dy2;
                    361: 
                    362: {
                    363: 
                    364:     double     x0, y0, x1, y1, xc, yc;  /* start, end, center */
                    365:     double     r, xmin, ymin, xmax, ymax;
                    366:     int                j, k;
                    367: 
                    368: /*
                    369:  *
                    370:  * bounding box of a circular arc             Eric Grosse  24 May 84
                    371:  *
                    372:  * Conceptually, this routine generates a list consisting of the start,
                    373:  * end, and whichever north, east, south, and west points lie on the arc.
                    374:  * The bounding box is then the range of this list.
                    375:  *     list = {start,end}
                    376:  *     j = quadrant(start)
                    377:  *     k = quadrant(end)
                    378:  *     if( j==k && long way 'round )  append north,west,south,east
                    379:  *     else
                    380:  *       while( j != k )
                    381:  *          append center+radius*[j-th of north,west,south,east unit vectors]
                    382:  *          j += 1  (mod 4)
                    383:  *     return( bounding box of list )
                    384:  * The following code implements this, with simple optimizations.
                    385:  *
                    386:  */
                    387: 
                    388:     x0 = hpos;
                    389:     y0 = -vpos;
                    390:     x1 = hpos + dx1 + dx2;
                    391:     y1 = -(vpos + dy1 + dy2);
                    392:     xc = hpos + dx1;
                    393:     yc = -(vpos + dy1);
                    394: 
                    395:     x0 -= xc; y0 -= yc;                        /* move to center */
                    396:     x1 -= xc; y1 -= yc;
                    397:     xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
                    398:     xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
                    399:     r = sqrt(x0*x0 + y0*y0);
                    400:     if (r > 0.0) {
                    401:        j = quadrant(x0,y0);
                    402:        k = quadrant(x1,y1);
                    403:        if (j == k && y1*x0 < x1*y0) {
                    404:            /* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
                    405:            if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
                    406:            if( xmax <  r) xmax =  r; if( ymax <  r) ymax =  r;
                    407:        } else {
                    408:            while (j != k) {
                    409:                switch (j) {
                    410:                    case 1: if( ymax <  r) ymax =  r; break; /* north */
                    411:                    case 2: if( xmin > -r) xmin = -r; break; /* west */
                    412:                    case 3: if( ymin > -r) ymin = -r; break; /* south */
                    413:                    case 4: if( xmax <  r) xmax =  r; break; /* east */
                    414:                }   /* End switch */
                    415:                j = j%4 + 1;
                    416:            }   /* End while */
                    417:        }   /* End else */
                    418:     }  /* End if */
                    419: 
                    420:     xmin += xc; ymin += yc;
                    421:     xmax += xc; ymax += yc;
                    422:     cover(xmin, ymin);
                    423:     cover(xmax, ymax);
                    424: 
                    425: }   /* End of arc_extreme */
                    426: 
                    427: /*****************************************************************************/
                    428: 
                    429: quadrant(x,y)
                    430: 
                    431:        double x, y;
                    432: 
                    433: {
                    434: 
                    435:     if (     x>=0.0 && y> 0.0) return(1);
                    436:     else if( x< 0.0 && y>=0.0) return(2);
                    437:     else if( x<=0.0 && y< 0.0) return(3);
                    438:     else if( x> 0.0 && y<=0.0) return(4);
                    439:     else                      return 0;        /* shut up lint */
                    440: 
                    441: }   /* End of quadrant */
                    442: 
                    443: /*****************************************************************************/
                    444: 
                    445: beginpath(buf, copy)
                    446: 
                    447:     char       *buf;                   /* whatever followed "x X BeginPath" */
                    448:     int                copy;                   /* ignore *buf if FALSE */
                    449: 
                    450: {
                    451: 
                    452: /*
                    453:  *
                    454:  * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used
                    455:  * to mark the start of a sequence of drawing commands that should be grouped
                    456:  * together and treated as a single path. By default the drawing procedures in
                    457:  * *drawfile treat each drawing command as a separate object, and usually start
                    458:  * with a newpath (just as a precaution) and end with a stroke. The newpath and
                    459:  * stroke isolate individual drawing commands and make it impossible to deal with
                    460:  * composite objects. "x X BeginPath" can be used to mark the start of drawing
                    461:  * commands that should be grouped together and treated as a single object, and
                    462:  * part of what's done here ensures that the PostScript drawing commands defined
                    463:  * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath"
                    464:  * command. At that point the path that's been built up can be manipulated in
                    465:  * various ways (eg. filled and/or stroked with a different line width).
                    466:  *
                    467:  * String *buf is unnecessary and is only included for compatibility with an early
                    468:  * verion of that's still in use. In that version "x X BeginObject" marked the
                    469:  * start of a graphical object, and whatever followed it was passed along in *buf
                    470:  * and copied to the output file. Color selection is one of the options that's
                    471:  * available in parsebuf(), so if we get here we add *colorfile to the output
                    472:  * file before doing anything important.
                    473:  *
                    474:  */
                    475: 
                    476:     if ( inpath == FALSE ) {
                    477:        flushtext();
                    478:        getdraw();
                    479:        getcolor();
                    480:        fprintf(tf, "gsave\n");
                    481:        fprintf(tf, "newpath\n");
                    482:        fprintf(tf, "%d %d m\n", hpos, vpos);
                    483:        fprintf(tf, "/inpath true def\n");
                    484:        if ( copy == TRUE )
                    485:            fprintf(tf, "%s", buf);
                    486:        inpath = TRUE;
                    487:     }  /* End if */
                    488: 
                    489: }   /* End of beginpath */
                    490: 
                    491: /*****************************************************************************/
                    492: 
                    493: drawpath(buf, copy)
                    494: 
                    495:     char       *buf;
                    496:     int                copy;
                    497: 
                    498: {
                    499: 
                    500: /*
                    501:  *
                    502:  * Called from devcntrl() whenever an "x X DrawPath" command is read. It marks the
                    503:  * end of the path started by the last "x X BeginPath" command and uses whatever
                    504:  * has been passed along in *buf to manipulate the path (eg. fill and/or stroke
                    505:  * the path). Once that's been done the drawing procedures are restored to their
                    506:  * default behavior in which each drawing command is treated as an isolated path.
                    507:  * The new version (called after "x X DrawPath") has copy set to FALSE, and calls
                    508:  * parsebuf() to figure out what goes in the output file. It's a feeble attempt
                    509:  * to free users and preprocessors (like pic) from having to know PostScript. The
                    510:  * comments in parsebuf() describe what's handled.
                    511:  *
                    512:  * In the early version a path was started with "x X BeginObject" and ended with
                    513:  * "x X EndObject". In both cases *buf was just copied to the output file, and
                    514:  * was expected to be legitimate PostScript that manipulated the current path.
                    515:  * The old escape sequence will be supported for a while (for Ravi), and always
                    516:  * call this routine with copy set to TRUE.
                    517:  * 
                    518:  *
                    519:  */
                    520: 
                    521:     if ( inpath == TRUE ) {
                    522:        if ( copy == TRUE )
                    523:            fprintf(tf, "%s", buf);
                    524:        else parsebuf(buf);
                    525:        fprintf(tf, "grestore\n");
                    526:        fprintf(tf, "/inpath false def\n");
                    527:        reset();
                    528:        inpath = FALSE;
                    529:     }  /* End if */
                    530: 
                    531: }   /* End of drawpath */
                    532: 
                    533: /*****************************************************************************/
                    534: 
                    535: parsebuf(buf)
                    536: 
                    537:     char       *buf;                   /* whatever followed "x X DrawPath" */
                    538: 
                    539: {
                    540: 
                    541:     char       *p;                     /* usually the next token */
                    542:     char       *p1;                    /* for grabbing arguments */
                    543:     char       *pend;                  /* end of the original string (ie. *buf) */
                    544:     int                gsavelevel = 0;         /* non-zero if we've done a gsave */
                    545: 
                    546: /*
                    547:  *
                    548:  * Simple minded attempt at parsing the string that followed an "x X DrawPath"
                    549:  * command. Everything not recognized here is simply ignored - there's absolutely
                    550:  * no error checking and what was originally in buf is clobbered by strtok().
                    551:  * A typical *buf might look like,
                    552:  *
                    553:  *     gray .9 fill stroke
                    554:  *
                    555:  * to fill the current path with a gray level of .9 and follow that by stroking the
                    556:  * outline of the path. Since unrecognized tokens are ignored the last example
                    557:  * could also be written as,
                    558:  *
                    559:  *     with gray .9 fill then stroke
                    560:  *
                    561:  * The "with" and "then" strings aren't recognized tokens and are simply discarded.
                    562:  * The "stroke", "fill", and "wfill" force out appropriate PostScript code and are
                    563:  * followed by a grestore. In otherwords changes to the grahics state (eg. a gray
                    564:  * level or color) are reset to default values immediately after the stroke, fill,
                    565:  * or wfill tokens. For now "fill" gets invokes PostScript's eofill operator and
                    566:  * "wfill" calls fill (ie. the operator that uses the non-zero winding rule).
                    567:  *
                    568:  * The tokens that cause temporary changes to the graphics state are "gray" (for
                    569:  * setting the gray level), "color" (for selecting a known color from the colordict
                    570:  * dictionary defined in *colorfile), and "line" (for setting the line width). All
                    571:  * three tokens can be extended since strncmp() makes the comparison. For example
                    572:  * the strings "line" and "linewidth" accomplish the same thing. Colors are named
                    573:  * (eg. "red"), but must be appropriately defined in *colorfile. For now all three
                    574:  * tokens must be followed immediately by their single argument. The gray level
                    575:  * (ie. the argument that follows "gray") should be a number between 0 and 1, with
                    576:  * 0 for black and 1 for white.
                    577:  *
                    578:  * To pass straight PostScript through enclose the appropriate commands in double
                    579:  * quotes. Straight PostScript is only bracketed by the outermost gsave/grestore
                    580:  * pair (ie. the one from the initial "x X BeginPath") although that's probably
                    581:  * a mistake. Suspect I may have to change the double quote delimiters.
                    582:  *
                    583:  */
                    584: 
                    585:     pend = buf + strlen(buf);
                    586:     p = strtok(buf, " \n");
                    587: 
                    588:     while ( p != NULL ) {
                    589:        if ( gsavelevel == 0 ) {
                    590:            fprintf(tf, "gsave\n");
                    591:            gsavelevel++;
                    592:        }   /* End if */
                    593:        if ( strcmp(p, "stroke") == 0 ) {
                    594:            fprintf(tf, "closepath stroke\ngrestore\n");
                    595:            gsavelevel--;
                    596:        } else if ( strcmp(p, "openstroke") == 0 ) {
                    597:            fprintf(tf, "stroke\ngrestore\n");
                    598:            gsavelevel--;
                    599:        } else if ( strcmp(p, "fill") == 0 ) {
                    600:            fprintf(tf, "eofill\ngrestore\n");
                    601:            gsavelevel--;
                    602:        } else if ( strcmp(p, "wfill") == 0 ) {
                    603:            fprintf(tf, "fill\ngrestore\n");
                    604:            gsavelevel--;
                    605:        } else if ( strcmp(p, "sfill") == 0 ) {
                    606:            fprintf(tf, "eofill\ngrestore\ngsave\nstroke\ngrestore\n");
                    607:            gsavelevel--;
                    608:        } else if ( strncmp(p, "gray", strlen("gray")) == 0 ) {
                    609:            p1 = strtok(NULL, " \n");
                    610:            fprintf(tf, "%s setgray\n", p1);
                    611:        } else if ( strncmp(p, "color", strlen("color")) == 0 ) {
                    612:            p1 = strtok(NULL, " \n");
                    613:            fprintf(tf, "/%s setcolor\n", p1);
                    614:        } else if ( strncmp(p, "line", strlen("line")) == 0 ) {
                    615:            p1 = strtok(NULL, " \n");
                    616:            fprintf(tf, "%s resolution mul 2 div setlinewidth\n", p1);
                    617:        } else if ( strncmp(p, "reverse", strlen("reverse")) == 0 )
                    618:            fprintf(tf, "reversepath\n");
                    619:        else if ( *p == '"' ) {
                    620:            for ( ; gsavelevel > 0; gsavelevel-- )
                    621:                fprintf(tf, "grestore\n");
                    622:            if ( (p1 = p + strlen(p)) < pend )
                    623:                *p1 = ' ';
                    624:            p = strtok(p, "\"\n");
                    625:            fprintf(tf, "%s\n", p);
                    626:        }   /* End else */
                    627:        p = strtok(NULL, " \n");
                    628:     }  /* End while */
                    629: 
                    630:     for ( ; gsavelevel > 0; gsavelevel-- )
                    631:        fprintf(tf, "grestore\n");
                    632: 
                    633: }   /* End of parsebuf */
                    634: 
                    635: /*****************************************************************************/
                    636: 
                    637: getbaseline()
                    638: 
                    639: {
                    640: 
                    641: /*
                    642:  *
                    643:  * Responsible for making sure the PostScript procedures needed for printing text
                    644:  * along an arbitrary baseline are downloaded from *baselinefile. Done at most
                    645:  * once per job, and only if the the stuff is really used.
                    646:  *
                    647:  */
                    648: 
                    649:     if ( gotbaseline == FALSE )
                    650:        exportfile(baselinefile);
                    651: 
                    652:     if ( tf == stdout )
                    653:        gotbaseline = TRUE;
                    654: 
                    655: }   /* End of getbaseline */
                    656: 
                    657: /*****************************************************************************/
                    658: 
                    659: newbaseline(buf)
                    660: 
                    661:     char       *buf;                   /* whatever followed "x X NewBaseline" */
                    662: 
                    663: {
                    664: 
                    665:     char       *p;                     /* for eliminating white space etc. */
                    666: 
                    667: /*
                    668:  *
                    669:  * Called from devcntrl() whenever an "x X NewBaseline" command is recognized. We
                    670:  * assume whatever is in *buf is a set of parametric equations that describe the
                    671:  * new baseline. Equations for x(t), y(t), dx/dt, and dy/dt must be written in
                    672:  * PostScript, bracketed by { and } characters, and supplied in exactly that order.
                    673:  * In particular the equation for x must come first in *buf and it ends up as the
                    674:  * last one on the stack, while the equation for dy/dt comes last (in *buf) and
                    675:  * ends up on the top of the PostScript stack. For example if *buf is given by,
                    676:  *
                    677:  *     {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
                    678:  *
                    679:  * text will be printed along the curve y = cos(x).
                    680:  *
                    681:  * Angles given in radians must be converted to degrees for the PostScript trig
                    682:  * functions, and things are scaled so that 1 unit maps into 1 inch. In the last
                    683:  * example the cosine curve that describes the baseline has an amplitude of 1 inch.
                    684:  * As another example of this rather confusing syntax if *buf is,
                    685:  *
                    686:  *     {} {} {pop 1} {pop 1}
                    687:  *
                    688:  * the baseline will be the 45 degree line y = x.
                    689:  *
                    690:  * When any of the four functions is used they're called with a single number on
                    691:  * the stack that's equal to the current value of the parameter t. The coordinate
                    692:  * system axes run parallel to the PostScript coordinate system that's currently
                    693:  * being used.
                    694:  *
                    695:  */
                    696: 
                    697:     for ( p = buf; *p; p++ )           /* eliminate trailing '\n' */
                    698:        if ( *p == '\n' ) {
                    699:            *p = '\0';
                    700:            break;
                    701:        }   /* End if */
                    702: 
                    703:     for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
                    704: 
                    705:     if ( *p != '\0' ) {                        /* something's there */
                    706:        flushtext();
                    707:        getbaseline();
                    708:        fprintf(tf, "mark resolution %s newbaseline\n", p);
                    709:        reset();
                    710:     }  /* End if */
                    711: 
                    712: }   /* End of newbaseline */
                    713: 
                    714: /*****************************************************************************/
                    715: 
                    716: drawtext(buf)
                    717: 
                    718:     char       *buf;                   /* whatever followed "x X DrawText */
                    719: 
                    720: {
                    721: 
                    722:     char       *p;                     /* for eliminating white space etc. */
                    723: 
                    724: /*
                    725:  *
                    726:  * Called from devcntrl() whenever an "x X DrawText command is recognized. *buf
                    727:  * should contain three arguments in the following order. First comes the text we
                    728:  * want to print along the current baseline. Right now the string should be given
                    729:  * as a PostScript string using characters '(' and ')' as the delimiters. Next in
                    730:  * *buf comes a justification mode that can be the words left, right, or center.
                    731:  * Last comes a number that represents the starting value of the parameter t that's
                    732:  * given as the argument to the parametric equations that describe the current
                    733:  * baseline. For example if *buf is given by,
                    734:  *
                    735:  *     (hello world) left .5
                    736:  *
                    737:  * hello world will be printed along the path described by the current baseline
                    738:  * and left justified at whatever (x(.5), y(.5)) happens to be. Usually will be
                    739:  * preceeded by an "x X NewBaseline" call that defines the current baseline. The
                    740:  * origin of the coordinate system used by the parametric equations will be the
                    741:  * current point.
                    742:  *
                    743:  */
                    744: 
                    745:     for ( p = buf; *p; p++ )           /* eliminate trailing '\n' */
                    746:        if ( *p == '\n' ) {
                    747:            *p = '\0';
                    748:            break;
                    749:        }   /* End if */
                    750: 
                    751:     for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
                    752: 
                    753:     if ( *p != '\0' ) {                        /* something's there */
                    754:        flushtext();
                    755:        getbaseline();
                    756:        xymove(hpos, vpos);
                    757:        fprintf(tf, "mark %s drawfunnytext\n", p);
                    758:        resetpos();
                    759:     }  /* End if */
                    760: 
                    761: }   /* End of drawtext */
                    762: 
                    763: /*****************************************************************************/
                    764: 
                    765: settext(buf)
                    766: 
                    767:     char       *buf;
                    768: 
                    769: {
                    770: 
                    771:     char       *p;
                    772: 
                    773: /*
                    774:  *
                    775:  * Does whatever is needed to ensure any text that follows will be set along the
                    776:  * curve described by the PostScript procedures listed in *buf. If *buf doesn't
                    777:  * contain anything useful (eg. just a newline) things are restored to whatever
                    778:  * they originally were. Doesn't work well if we try to start in the middle of a
                    779:  * line of text.
                    780:  *
                    781:  * The parametric equations needed are,
                    782:  *
                    783:  *     x = f(t)
                    784:  *     y = g(t)
                    785:  *     dx/dt = f'(t)
                    786:  *     dy/dt = g'(t)
                    787:  *
                    788:  * and must be given as proper PostScript procedures. The equation for x must come
                    789:  * first (ie. it ends up on the bottom of the stack) and the equation for dy/dt
                    790:  * must be given last (ie. it ends up on top of the stack). For example if *buf
                    791:  * is given by,
                    792:  *
                    793:  *     {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
                    794:  *
                    795:  * text will be set along the curve y=cos(x).
                    796:  *
                    797:  */
                    798: 
                    799:     flushtext();
                    800:     getbaseline();
                    801: 
                    802:     for ( p = buf; *p && *p == ' '; p++ ) ;
                    803: 
                    804:     if ( *p && *p != '\n' ) {
                    805:        encoding = maxencoding + 2;
                    806:        fprintf(tf, "mark resolution %s newbaseline\n", buf);
                    807:     } else encoding = realencoding;
                    808: 
                    809:     fprintf(tf, "%d setdecoding\n", encoding);
                    810:     resetpos();
                    811: 
                    812: }   /* End of settext */
                    813: 
                    814: /*****************************************************************************/
                    815: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.