rsalz@uunet.UU.NET (Rich Salz) (10/20/87)
Submitted-by: Nick Christopher <nwc@cunixc.columbia.edu> Posting-number: Volume 12, Issue 24 Archive-name: ln03-plot [ This program reads output from the plot(3) library and generates SIXEL files. I don't have an LN03 to test this with. --r$ ] The following is an ln03 printer library for the UNIX plot system. It has been tested to a limited degree and the only known problem is that labels are hard to place, this is because graphics and text are placed by different scaling methods on the ln03 and I have yet to find an accurate conversion equation. Please, if bugs are found, report them to me (with fixes?) so that a unified update can periodically be posted. #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Makefile # drive.c # lno.h # order.c # manual.txt # ln03.man export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'Makefile'" '(351 characters)' if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' FILES= Makefile drive.c lno.h order.c OBJECTS= drive.o order.o LIBS= -lm CFLAGS= -O all: lib ln03 lib: order.o ar cr libln03.a order.o ln03: $(OBJECTS) cc $(CFLAGS) $(OBJECTS) $(LIBS) -o ln03plot order.o: lno.h clean: -rm -f *.o *~ package: $(FILES) manual.txt ln03.man shar -cv $(FILES) manual.txt ln03.man > package print: lpr $(FILES) SHAR_EOF if test 351 -ne "`wc -c < 'Makefile'`" then echo shar: "error transmitting 'Makefile'" '(should have been 351 characters)' fi fi echo shar: "extracting 'drive.c'" '(4076 characters)' if test -f 'drive.c' then echo shar: "will not over-write existing file 'drive.c'" else cat << \SHAR_EOF > 'drive.c' /* Any problems here? Talk to David Chang. 1986, Nicholas Christopher */ #include <stdio.h> main(argc,argv) char **argv; { int std=1; FILE *fin; int deltx,delty; while(argc-- > 1) { if(*argv[1] == '-') switch(argv[1][1]) { case 'l': deltx = atoi(&argv[1][2]) - 1; break; case 'w': delty = atoi(&argv[1][2]) - 1; break; } else { std = 0; if ((fin = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "can't open %s\n", argv[1]); exit(1); } fplt(fin); } argv++; } if (std) fplt( stdin ); exit(0); } fplt(fin) FILE *fin; { int c; char s[256]; int xi,yi,x0,y0,x1,y1,r,dx,n,i; int pat[256]; openpl(); while((c=getc(fin)) != EOF){ switch(c){ case 'm': xi = getsi(fin); yi = getsi(fin); move(xi,yi); break; case 'l': x0 = getsi(fin); y0 = getsi(fin); x1 = getsi(fin); y1 = getsi(fin); line(x0,y0,x1,y1); break; case 't': mygets(s,fin); label(s); break; case 'e': erase(); break; case 'p': xi = getsi(fin); yi = getsi(fin); point(xi,yi); break; case 'n': xi = getsi(fin); yi = getsi(fin); cont(xi,yi); break; case 's': x0 = getsi(fin); y0 = getsi(fin); x1 = getsi(fin); y1 = getsi(fin); space(x0,y0,x1,y1); break; case 'b': x0 = getsi(fin); y0 = getsi(fin); x1 = getsi(fin); y1 = getsi(fin); box(x0,y0,x1,y1); break; case 'a': xi = getsi(fin); yi = getsi(fin); x0 = getsi(fin); y0 = getsi(fin); x1 = getsi(fin); y1 = getsi(fin); arc(xi,yi,x0,y0,x1,y1); break; case 'c': xi = getsi(fin); yi = getsi(fin); r = getsi(fin); circle(xi,yi,r); break; case 'f': mygets(s,fin); linemod(s); break; } } closepl(); } getsi(fin) FILE *fin; { /* get an integer stored in 2 ascii bytes. */ short a, b; if((b = getc(fin)) == EOF) return(EOF); if((a = getc(fin)) == EOF) return(EOF); a = a<<8; return(a|b); } mygets(s,fin) char *s; FILE *fin; { for( ; *s = getc(fin); s++) if(*s == '\n') break; *s = '\0'; return; } SHAR_EOF if test 4076 -ne "`wc -c < 'drive.c'`" then echo shar: "error transmitting 'drive.c'" '(should have been 4076 characters)' fi fi echo shar: "extracting 'lno.h'" '(1527 characters)' if test -f 'lno.h' then echo shar: "will not over-write existing file 'lno.h'" else cat << \SHAR_EOF > 'lno.h' /* (C) Copyright 1986 Nicholas Christopher. * * lno.h * This .h file accompanies my code, order.c, to produce graphics on sixel * systems. If any modification are made to this code, while I am still * employed by the Columbia University Center for Computing Activities, * please notify me. * */ #include <stdio.h> #define MAXVERT 243 /* verticle axis (1455) div sixels (6) */ #define Xaxis 1185 /* horizontal pixel resolution */ #define Yaxis 1455 /* vertical pixzel resolution */ #define Xdec 5665 /* horizantal decipoint resolution */ #define Ydec 7235 /* vertical decipoint resolution */ #define abs(x) ((x>=0) ? (x) :-(x)) /* absolut value */ #define newcount() (count = 1) /* reset pattern count */ int cx = 0; /* memory value of x coordinate */ int cy = 0; /* memory value of y coordinate */ float xscale = 1.0; /* x axis scaling factor */ float yscale = 1.0; /* y axis scaling factor */ int xoffset = 0; int yoffset = 0; int mode = 1; /* flag of patern dot, solid, long, etc. */ int count = 1; /* pattern position count, dot or space? */ struct sixel { unsigned int pixels :6; /* bit vector of the six pixels */ int horiz; /* horiz coord in sparse matrix */ struct sixel *next; }; struct sixel *vert[MAXVERT]; /* vert spine of sparse matrix */ SHAR_EOF if test 1527 -ne "`wc -c < 'lno.h'`" then echo shar: "error transmitting 'lno.h'" '(should have been 1527 characters)' fi fi echo shar: "extracting 'order.c'" '(17190 characters)' if test -f 'order.c' then echo shar: "will not over-write existing file 'order.c'" else cat << \SHAR_EOF > 'order.c' /* * The following code is designed to be used in conjunction with the UNIX * * plot facilities, but may be used on its own to produce output to any * * sixels printing system. * * * * If any modification are made to this code, while I am still employed by * * the Columbia University Center for Computing Activities, please notify * * me, nwc@cunixc.columbia.edu. * * */ #include "lno.h" #include <stdio.h> #include <math.h> openpl() /* nothing really needed here */ { } move(x,y) /* set cx,cy memory of last points, scale them, and clear pattern counter. */ int x,y; { extern int cx,cy; newcount(); ln03scale(&x,&y); cx = x; cy = y; } cont(x,y) /* scaled coordinates and then pass them to extend */ { ln03scale(&x,&y); ln03extend(x,y); } point(x,y) /* scale coordinates and pass them to spot */ { ln03scale(&x,&y); ln03spot(x,y); } line(x1,y1,x2,y2) /* mark a starting point and then simply use continue to go to second point */ int x1,y1,x2,y2; { move(x1,y1); ln03scale(&x2,&y2); ln03extend(x2,y2); } label(m) /* place ascii text or math font in graph page. This is done by direct * * decipoint location addressing. The escape codes and text if placed in * * the output file before the sixels output. */ char *m; { extern int cy,cx; /* coordinates to place label */ double xx,yy,tempx,tempy; tempx = cx; tempy = cy; /*next two lines convert unscaled pixel coordinates to scaled decipoints, * *the unit the LN03 positions text by. */ xx =(Xdec * (tempx/Xaxis)) + 0.07 * tempx; yy =Ydec - (Ydec * (tempy/Yaxis) - 0.8 * tempy); /* If a label starts in a "~" then tell the LN03 to use its math font. * * A non math font label can begin with a tilda, just prefix it by a space. */ if(*m == '~'){ printf("\033*>\033n\033[2 I\033[11h"); printf("\033[%d`\033[%dd%s",ln03round(xx),ln03round(yy),++m); } else printf("\017\033[2 I\033[11h\033[%d`\033[%dd%s",ln03round(xx),ln03round(yy),m); cx += (strlen(m)*15); } arc(x,y,x1,y1,x2,y2) /* This arc generation routine is pretty bad... I do not use it for * * generating circles for this reason. Much of it depends on floating point * * which, depending on the machine may not be that accurate. */ int x,y,x1,y1,x2,y2; { double sqrt(),temp; register int dx,dy,radsqr; register int plotx,ploty,quad,rad,reps = 0; ln03scale(&x,&y); ln03scale(&x1,&y1); ln03scale(&x2,&y2); dx = abs(x1-x); dy = abs(y1-y); radsqr = dx*dx + dy*dy; temp = radsqr; rad = sqrt(temp); plotx = x1-x; /* x coord of first point in arc */ ploty = y1-y; /* y " " " " " " */ if(x1 > x+rad/2) quad = 1; /* what quadrant are we in ? */ else if(x1 > x) quad = 2; else quad = 3; if(y1 < y && quad == 2 ) quad = 4; /* under horizon of y is 4 not 2 */ ln03filterP(x1,y1); while(ln03aprox(plotx+x,x2,ploty+y,y2) != 1){ /* until final coord hit, go */ if(quad == 2){ /* quadrants not standard, my are by the compass. */ plotx--; /* we are in North quadrant so inc x and calculate y */ temp = radsqr - plotx*plotx; ploty = ln03round(sqrt(temp)); ln03extend(plotx+x,ploty+y); if(plotx+x < x-rad/2){ quad = 3; reps++; } } else if(quad == 3){ /* in west quad, inc y and calc x */ ploty--; temp = radsqr - ploty*ploty; plotx =0-ln03round(sqrt(temp)); ln03extend(plotx+x,ploty+y); if(plotx+x >= x-rad/2){ quad = 4; reps++; } } else if(quad == 4){ /* we are in south quad, mirror north*/ plotx++; temp = radsqr - plotx*plotx; ploty =0-ln03round(sqrt(temp)); ln03extend(plotx+x,ploty+y); if(plotx+x > x+rad/2){ quad = 1; reps++; } } else{ /* east quad, mirror west */ ploty++; temp = radsqr - ploty*ploty; plotx = ln03round(sqrt(temp)); ln03extend(plotx+x,ploty+y); if(plotx+x <= x+rad/2){ quad = 2; reps++; } } if(reps > 4) /* We have been around the circle more than once...oops! */ { fprintf(stderr,"Second point is not in arc of center and first point.\n"); fprintf(stderr,"Bad arc is %d, %d, %d, %d, %d, %d.\n",x,y,x1,y1,x2,y2); fprintf(stderr," Converting sparse matrix built to date and exiting.\n"); ln03conv(); exit(1); } } } circle(x,y,r) /* this generates 45 degrees of a circle, passing each point to circpoint * * which distributes the point to all eight 45 degree segments. */ int x,y,r; { register int xx,yy,d; extern int cx,cy; extern float xscale,yscale; int dummy = 1; newcount(); ln03scale(&x,&y); r = ln03round(r * xscale); xx = 0; yy = r; d = 3-2*r; while( xx < yy){ ln03circpoint(xx,yy,x,y); if(d < 0) d = d+4*xx+6; else{ d = d+4*(xx-yy) + 10; yy--; } xx++; } if(xx == yy) ln03circpoint(xx,yy,x,y); cx = xx+x; cy = yy+y; } erase() /* Just convert what we have, and start fresh. */ { ln03conv(); } linemod(s) /* set varible "mode" to reflect pattern chosen. */ char *s; { extern int mode; switch(s[0]){ case 'l': mode = 4; break; case 'd': if(s[3] == 'd') mode = 5; else mode = 2; break; case 's': if(s[5] != '\0') mode = 1; else mode = 3; } } space(x1,y1,x2,y2) /* set a scaling factor at users request. scale is defaulted to 1 */ int x1,y1,x2,y2; { extern float xscale,yscale; float temp; extern int xoffset,yoffset; if (x1 < 0) xoffset = -x1; if (y1 < 0) yoffset = -y1; temp = (float)Xaxis/(x2-x1); xscale = floor(temp * 100.0)/100.0; temp = (float)Xaxis/(y2-y1); yscale = floor(temp * 100.0) / 100.0; } closepl() { ln03conv(); } /*---------------------------------------------------------------------------*/ /* BEGIN SUPPORT ROUTINES */ /*---------------------------------------------------------------------------*/ ln03extend(x1,y1) /* Don't ask, I got this from a book, it forms a line by increment to a * * point in the area nearest the line. negative slopes are achived by * * mirroring a positive slope. */ register int x1,y1; { extern int cx,cy; register int dx,dy,yincr1,mid,yincr2,yd,xincr1,xincr2,xd,x,y,xend,yend; register int xx,yy; register int neg=0; dx = abs(x1-cx); dy = abs(y1-cy); yd = 2*dy-dx; yincr1 = 2*dy; yincr2 = 2*(dy-dx); xd = 2*dx-dy; xincr1 = 2*dx; xincr2 = 2*(dx-dy); if (cx > x1){ /* set up initial variables */ x = x1; y = y1; xend = cx; yend = cy; if(cy < y1 && cx != x1){ /* BELLS AND WISTLES negative slope */ neg = 1; mid = y1; yend = cy+(2*dy); /*set y to its + slope equivalent */ } } else { x = cx; y = cy; xend = x1; yend = y1; if(y1 < cy && cx != x1){ /* BELLS AND WISTLES negative slope */ neg = 1; mid = cy; yend = y1+(2*dy); } } ln03filterP(x,y); xx = x; yy = y; if (x == xend) /* we have a totally verticle line. */ while (y != yend){ if (y < yend) y++; else y--; ln03filterP(x,y); } while (x < xend){ if (yd < 0) yd += yincr1; else{ if (y < yend) y++; else if (y > yend) y--; yd += yincr2; } if (xd < 0) xd += xincr1; else{ x++; xd += xincr2; } if (xx != x || yy != y){ if(neg) ln03filterP(x,2*mid-y); else ln03filterP(x,y); xx = x; yy = y; } } cx = x1; /* remember last points */ cy = y1; } int ln03round(num) /* float number rounding */ double num; { int inum; double rnum; inum = num; rnum = num - inum; return((rnum < .5)?inum:inum+1); } int ln03power(z) /* this rountine accepts an integer 0-5 and first takes its five compliment * * then it returns 2 to the power of the result. exmp 3 = (5-3)^2 = 4 */ int z; { register int inc,final = 2; z = 5-z; if(z ==0) final = 1; else if(z==1) final = 2; else for(inc = 2;z >= inc; inc++) final *= 2; return(final); } int ln03aprox(a,b,c,d) /* check to see if a is aprox equal to b and if c is aprox equal to d * * this is done because I don't trust arc's floating point to generate * * the circumference points exactly. */ int a,b,c,d; { if( a <= b+1 && a >= b-1 && c <= d+1 && c >= d-1) return(1); else return(-1); } death() /* Something, some where has created an error, or we are out of RAM, * * convert the graph as it stands. */ { fprintf(stderr,"We have ran out of memory for sparse matrix nodes.\n"); fprintf(stderr," We will convert what has been done to date and leave.\n"); ln03conv(); exit(1); } ln03spot(x,y) /* place a point given by coordinates in sparse matrix. */ int x,y; { extern struct sixel *vert[MAXVERT]; /* this is the plotting grid */ struct sixel *temp,*mark,*malloc(); extern int cy,cx; register int Vval; /* verticle coordinate to the nearest sixel */ register int Svval; /* verticle coordinate, pixel remainder of sixels*/ if(x >= 0 && x <= Xaxis && y >= 0 && y <= Yaxis){ cy = y; cx = x; Vval =(Yaxis-(y-2))/6; /* div 6 to obtain sixels */ Svval = y%6; /* modulo to obtain pixels remainder */ if(vert[Vval] == NULL){ /* this row is new, start it */ if((temp = malloc(sizeof(struct sixel)))==NULL) death(); temp->pixels = 0|(ln03power(Svval));/* calc sixels' pixel value */ temp->horiz = x; temp->next = NULL; vert[Vval] = temp; } else{ /* row already has member(s) */ mark = vert[Vval]; /* set a marker to move along list */ while(mark->next != NULL && mark->horiz < x) mark = mark->next; /* we are now a) at row's end, b) an equal horiz, * * c) a greater horiz. */ if(mark->next == NULL && mark->horiz < x ){ /* time to add a node because horiz is too big and no next node. */ if((temp = malloc(sizeof(struct sixel)))==NULL) death(); temp->pixels = 0|(ln03power(Svval)); temp->horiz = x; temp->next = NULL; /* Better safe...... */ mark->next = temp; /* Add new node to vert structure. */ } else if(mark->horiz == x) mark->pixels |= ln03power(Svval); /* just modify this node */ else if(mark->horiz > x){ /* insert new node between two present cause we have passed its spot */ if((temp = malloc(sizeof(struct sixel)))==NULL) death(); temp->pixels = mark->pixels; temp->horiz = mark->horiz; temp->next = mark->next; mark->pixels = 0|(ln03power(Svval)); mark->horiz = x; mark->next = temp; } } } } ln03conv() /* This routine coverts a sparce matrix to LN03 format of sixels. The * * size of the output is minimized by using the LN03's repeat format: * * !10? performs ? (a space) 10 times. */ { register int count,rep; register int Hplace; /* horizontal displacement */ register int lastc = 0; /* sixel pixel pattern holder */ int x; struct sixel *temp; extern struct sixel *vert[MAXVERT]; /* sparse matrix of sixels */ /* ESC codes to get ln03 sixels mode */ printf("\033[2 I\033[1`\033[1d\033P000;0000;000q\"1;1"); for(count = 0; count < MAXVERT; count++) if(vert[count] == NULL) printf("?-"); /* LF for a blank row */ else{ temp = vert[count]; if(temp->horiz>0) printf("!%d?",temp->horiz-1);/*tab to 1st char */ printf("%c",temp->pixels+63); Hplace = temp->horiz; lastc = temp->pixels; rep = 0; while(temp->next != NULL){ temp = temp->next; /* move one node horizontally */ if(temp->horiz == Hplace+1 && temp->pixels == lastc){ rep++; Hplace++; } else{ if(rep > 0) printf("!%d%c",rep,lastc+63); if(temp->horiz != Hplace+1 && temp->horiz <= Xaxis) printf("!%d?",temp->horiz - Hplace - 1); printf("%c",temp->pixels+63); Hplace = temp->horiz; lastc = temp->pixels; rep = 0; } } if(rep > 0) printf("!%d%c-",rep,lastc+63); else printf("-"); } printf("\033\\"); /* Tell ln03 we are done with sixels */ for(x = 0; x < MAXVERT; x++) vert[x] = (struct sixel *)NULL; } box(x0,y0,x1,y1) /* box drawing routine */ int x0,y0,x1,y1; { int xhold,yhold; xhold = x0; yhold = y0; ln03scale(&x0,&y0); ln03scale(&x1,&y1); move(xhold,yhold); ln03extend(x1,y0); ln03extend(x1,y1); move(xhold,yhold); ln03extend(x0,y1); ln03extend(x1,y1); } ln03circpoint(xx,yy,x,y) /* circle() only calculates 45 degrees of a circle, this distributes the * * coordinates given into an entire circle. The decrementing of count is so * * that the position in a pattern, i.e. point or space in "dot dash" is * * not lost. */ int xx,yy,x,y; { extern int cx,cy,count; ln03filterP(xx+x,yy+y); count--; ln03filterP(yy+x,xx+y); count--; ln03filterP(yy+x,-xx+y); count--; ln03filterP(xx+x,-yy+y); count--; ln03filterP(-xx+x,-yy+y); count--; ln03filterP(-yy+x,-xx+y); count--; ln03filterP(-yy+x,xx+y); count--; ln03filterP(-xx+x,yy+y); } ln03filterP(x,y) /* filter() acts as a middle man between a caller and spot(), i.e. if our * * position in the line pattern (example: dotted line) is a blank space * * then spot should not be called. */ int x,y; { extern int mode,count; switch(mode){ case 1: ln03spot(x,y); /* solid line */ break; case 2: if(count <= 3 ) ln03spot(x,y); /* dotted line */ if(count == 6) count = 0; break; case 3: if(count <= 6 ) ln03spot(x,y); /* short dash */ if(count == 9) count =0; break; case 4: if(count <= 9 ) ln03spot(x,y); /* long dash */ if(count == 12) count =0; break; /* dot dash */ case 5: if((count <= 6)||((count ==11)||(count==12))) ln03spot(x,y); if(count == 17) count = 0; break; } count++; /* increment pattern position. */ } ln03scale(x,y) int *x,*y; { extern float xscale,yscale; extern int xoffset,yoffset; int tempx,tempy; tempx = *x; tempy = *y; tempx += xoffset; tempy += yoffset; tempx = ln03round(tempx*xscale); tempy = ln03round(tempy*yscale); *x = tempx; *y = tempy; } SHAR_EOF if test 17190 -ne "`wc -c < 'order.c'`" then echo shar: "error transmitting 'order.c'" '(should have been 17190 characters)' fi fi echo shar: "extracting 'manual.txt'" '(6901 characters)' if test -f 'manual.txt' then echo shar: "will not over-write existing file 'manual.txt'" else cat << \SHAR_EOF > 'manual.txt' USERS GUIDE FOR PLOT FILTERS David Chang Nicholas Christopher 16 June 1987 1. INTRODUCTION TO PLOT FILTERS The UNIX operating system has, as one of its standard libraries, a library which produces graphics output in a device-independent manner. This output can then be used as input for any compatible device-specific plot filter. The plot filter generates commands, that when redirected to its corresponding graphics device, will generate the desired graphics output. The graphics library should be linked to your C program by using the -lplot compiler switch. 2. COMMANDS The subroutines that are included in the standard UNIX Plot library are as follows: - openpl() Prepares the output device for taking commands. It should always be called before calling any other plot subroutines. - erase() Reinitializes the output device. - label(s) char[s]; Places text in the output at the current point. It takes a string variable or a string in quotes as its argument. The argument is null-terminated and does not contain newlines. A local modification of the command allows the LN03 to use its technical font. To use the LN03 technical font begin the label with a tilde character ("~"). A space-tilde, " ~", will allow a label in the regular font to begin with a tilde. - line(x1,y1,x2,y2) Produces a line that starts at the point designated by the first two arguments that are passed to the subroutine and terminates at the point designated by the final two arguments. - circle(x,y,r) Produces a circle whose center is given by the first two arguments and whose radius is given by the final argument. - arc(x,y,x1,y1,x2,y2) Produces an arc whose center is determined by the first two arguments. The starting point is given by the third and fourth arguments and the end point is given by the final two arguments. The arc is drawn counter-clockwise. - move(x,y) Changes the current point to the point given by the two arguments. - cont(x,y) Draws a point from the current point to the point given by the two arguments. - point(x,y) Draws a single point at the given coordinates. - linemod(s) char[s]; Changes the line style to the given style. the styles that are available are `dotted', `longdashed', `shortdashed', and `dotdashed'. - space(x1,y1,x2,y2) Changes the plot area, using the first two coordinates as the upper right hand corner of the plotting area and the final two arguments as the lower left hand corner of the plotting area. The plot will be reduced or magnified to fit the device as closely as possible. - closepl() Closes the output device. This should always be called at the end of your program. There are two subroutines that have been added to the standard Plot library here at Columbia. They are as follows: - box(x1,y1,x2,y2) Draws a box using the two points that are passed as arguments as two corners. This available on all the devices. - color(n) Changes the pen on a multicolor pen plotter to the pen number designated by the argument. This is only available on the pen plotters and ink-jet printer. This graphics package can be used on the Hewlett-Packard 7470A, the DEC LVP16, the DEC LN03 laser printer, and the DEC LCP01 color ink-jet printer. The HP 7470A is a two pen plotter. The DEC LVP16 is a six pen plotter. Columbia has several pen plotters available at 251 Engineering Terrace and LN03s at both the Engineering Terrace and SIA terminal room. The use of the plotters requires your own plotter pens, which can be obtained in the Business Office, and your own 8.5" by 11" or 11" by 17" paper. 3. SAMPLE SESSION Below is an example program in the language C to put a round peg in a square hole. If you are not familiar with the C language you should be warned that it is case sensitive and so if you plan to try running the following program maintain the capitalization exactly. /* This is a comment */ main() /* Start of program */ { openpl(); /* Initialize plot routines */ move(10,10); /* Position cursor */ label("Demo."); /* Text starts at cursor */ box(100,100,500,500); /* Draw a square hole */ circle(300,300,200); /* Put the round peg in */ move(10,600); /* Position cursor */ label("Done!"); /* Some more text */ closepl(); /* Close the plot routines */ } Note that the only C in the entire program was "main() { }" the rest was entirely plot commands. C code could have been present, to calculate a sin wave by points for example, but knowledge of C is not required to use plot. The above code must be compiled before it will run. Assume that the above C program is in a file named peg.c. The command to compile C code which uses plot commands is as follows: cc -o peg peg.c -lplot The above command generates the program peg can be run at any time, however it is still not producing output for any specific printing device. Suppose that you were sitting at a Tektronics terminal and wanted to see the demonstration right on the screen. The command to give would be: peg | tek The above command takes the generalized output from peg and feeds it to the program tek which knows how to display graphics on a Tektronics terminal (the "|" character is called a pipe in UNIX and must be included). The tek program then produces the graphics on your screen. The command: peg | ln03 | lpr -Pmuddl1 Would take the same generalized output from peg feed it to ln03 a program which creates output for the DEC LN03 printer. Then ln03 program would feeds its output to the print command, lpr -Pmuddl1, which actually prints the given output on the LN03 printer located in 251 Engineering Terrace. For further documentation look in sections 1,3 and 5 of the UNIX manual under the title plot. On a UNIX machine these manual sections can be read by saying: man 1 plot man 3 plot man 5 plot SHAR_EOF if test 6901 -ne "`wc -c < 'manual.txt'`" then echo shar: "error transmitting 'manual.txt'" '(should have been 6901 characters)' fi fi echo shar: "extracting 'ln03.man'" '(661 characters)' if test -f 'ln03.man' then echo shar: "will not over-write existing file 'ln03.man'" else cat << \SHAR_EOF > 'ln03.man' .TH LNO3PLOT cucca .ds SI S\s-2IX\s+2\s-2ELS\s+2 .SH NAME ln03plot \- convert plot(5) files to S\s-2IX\s+2\s-2ELS\s+2 format .SH SYNOPSIS .B ln03plot [ .I file ] .SH DESCRIPTION .I ln03plot reads a .I file in .IR plot (5) format and converts it to \*(SI format on the standard output. The \*(SI format is used by the LN03 printer as well as other printers. If no .I file is specified, the standard input is used. .SH "SEE ALSO" graph(1), ideal(1), plot(1), plot(3), plot(5), lpr(1). .br .SH BUGS The LN03's printing resolution is considerably smaller than that of many printing devices. Some input, if scaled to much larger devices may produce poor results. SHAR_EOF if test 661 -ne "`wc -c < 'ln03.man'`" then echo shar: "error transmitting 'ln03.man'" '(should have been 661 characters)' fi fi exit 0 # End of shell archive -- "I am the Lorvax. I speak for the machines." ______________________________________________________________________________ nwc%cunixc@columbia, columbia!cunixc!nwc BITNET: nwcus@cuvma USENET: topaz!columbia!cunixc!nwcw