/* to_ps.c */ /* THIS VERSION WORKS both in unix and in TURBO C 7/14/89 */ #define UNIX 1 /* Change to 0 if compiling on non-unix system. */ /* This program translates a modest graphics language into PostScript output. A statement in this language consists of individual ASCII strings separated by newlines, i.e. lines of an ASCII file. The first letter of each command identifies the command; letter may or may not require data following it. After required data, comments can be added, but these will be lost in the` output. There is also an official comment designator, %; comments that start with this character cause PostScript comments to be included in the output. Text is possible in three sizes (T, x and t). Line width is given by W, window coordinates by w. `Move' and `line' by m and l. Exact specifications of the commands can be found by reading code that follows `switch' below. For example, w 0.0 0.0 6.0 6 W 7 m 3 2 start at home plate l 4 3 draw line to first base l 3 4 draw line to second base l 2 3 draw line to third base l 3 2 draw line to home plate m 4.5 3 TFirst base makes the beginnings of a baseball diamond, with first base labeled in the picture. The words following the `l' and `m' commands are comments for the convenience of the user, and will not appear in output. For explanation at greater length, see Chapter 2 of `The geometry of Computer Graphics,' by Walter Taylor, to be published in 1991 by Wadsworth-Brooks-Cole. A few commands not described there have been added here, such as C for color, N for the name of the picture, \ for escapes (i.e. the direct inclusion of PS), d for dots, and z for inserting remarks into the ps printer's output file (the log file). See the corresponding cases below. When used on a unix system, the steps are as follows. On another system, such as a PC, the steps would be slightly different, of course. You do _not_ need to have the header file coords.h in the same directory. (I included the definition of point in this file.) cc -o draw thisfile.c draw < data > picture lpr -PyourfavoritePostScriptPrinter picture run_down_hall_to_collect_your_artwork possible bug: doesn't like a blank line at start of data wtaylor@euclid.colorado.edu 9/18/91 minor modifications to these comments 9/19/95 */ #include #include #if(UNIX) #include #include #endif typedef struct { double x_coord; double y_coord; } point; #define DATAFILE "data" #define ERRORFILE stderr main() { int no_input_errors = 1; int ok_to_draw_line = 0; int N,Q; char in_filename[50], out_filename[50]; char text[100]; char current_line[100]; FILE *fp_in; int fclose(); point lower_left, upper_right, p, q, ttimes(); point farthest_SW, farthest_NE; point r, s; double black=0.0, white=1.0; double dot_size; int initial_point; fp_in = stdin; strcpy(in_filename,"standard input"); lower_left.x_coord = 0.0; lower_left.y_coord = 0.0; upper_right.x_coord = 1.0; upper_right.y_coord = 1.0; farthest_NE.x_coord = -1.0E12; farthest_NE.y_coord = -1.0E12; farthest_SW.x_coord = 1.0E12; farthest_SW.y_coord = 1.0E12; begin_drawing(); N=0; while (no_input_errors) { q = p; if (N>0) { Q = fscanf(fp_in,"\n"); } Q = fscanf(fp_in,"%[^\n]",current_line); if (Q <= 0) {error_1(N,in_filename); break;} switch(current_line[0]) { case '%'/*comment*/: /* this is hardly needed any more fprintf(ERRORFILE,"Line %d treated as comment.\n",N+1) ; */ Q = sscanf(current_line,"%*c%[^\n]",text); comment_print(text); break; case '\\'/*esape*/: Q = sscanf(current_line,"\\%[^\n]",text); escape_print(text); break; case 'N'/*Name of picture*/: Q = sscanf(current_line,"N%[^\n]",text); nameprint(text); break; case 't'/*text, small*/: Q = sscanf(current_line,"t%[^\n]",text); textprint_small(text); break; case 'x'/*text, medium*/: Q = sscanf(current_line,"x%[^\n]",text); textprint_medium(text); break; case 'T'/*text, large*/: Q = sscanf(current_line,"T%[^\n]",text); textprint_large(text); break; case 'z'/* insert comment in log file */: Q = sscanf(current_line,"z%[^\n]",text); logprint(text); break; case 'r'/*clip region*/: Q = sscanf(current_line,"r%lf%lf%lf%lf", &r.x_coord,&r.y_coord, &s.x_coord,&s.y_coord); if (Q <= 3) {error_r0(N+1,in_filename); no_input_errors=0; break;} if ( (r.x_coord==s.x_coord) || (r.y_coord==s.y_coord)) {error_w1(N+1,in_filename); no_input_errors=0;} r.x_coord = (r.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); r.y_coord = (r.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); s.x_coord = (s.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); s.y_coord = (s.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); set_clip_region(r,s,N+1); break; case 'G'/*extremes of gray scale; black then white*/: Q = sscanf(current_line,"G%lf%lf", &black,&white); if (Q <= 1) {error_w0(N+1,in_filename); no_input_errors=0;} if (black==white) {error_w1(N+1,in_filename); no_input_errors=0;} break; case 'w'/*window*/: Q = sscanf(current_line,"w%lf%lf%lf%lf", &lower_left.x_coord,&lower_left.y_coord, &upper_right.x_coord,&upper_right.y_coord); if (Q <= 3) {error_w0(N+1,in_filename); no_input_errors=0;} if ( (lower_left.x_coord==upper_right.x_coord) || (lower_left.y_coord==upper_right.y_coord)) {error_w1(N+1,in_filename); no_input_errors=0;} break; case 'W'/*Width*/: { int width; Q = sscanf(current_line,"W%d",&width); if (Q <= 0) {error_W(N+1,in_filename); no_input_errors=0; break;} set_width(width); } break; case 'g'/*gray_level*/: { double gray_level; Q = sscanf(current_line,"g%lf",&gray_level); if (Q <= 0) {error_W(N+1,in_filename); no_input_errors=0; break;} gray_level = (gray_level - black)/(white - black); if (gray_level<=0.0) gray_level = 0.0; if (gray_level>=1.0) gray_level = 1.0; set_gray(gray_level); } break; case 'C'/*color */: { double red, green, blue; Q = sscanf(current_line,"C%lf %lf %lf", &red,&green,&blue); if (Q <= 2) {error_W(N+1,in_filename); no_input_errors=0; break;} set_colors(red,green,blue); } break; case 'm'/*move*/: ok_to_draw_line = 1; Q = sscanf(current_line,"m%lf%lf",&p.x_coord, &p.y_coord); if (Q <= 1) {error_m(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); move_to(p); break; case 'l'/*line*/: if (!ok_to_draw_line){error_l1(N+1,in_filename ); no_input_errors=0; break;} Q = sscanf(current_line,"l%lf%lf",&p.x_coord, &p.y_coord); if (Q <= 1) {error_l(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); makeline(p,q); break; case 'd'/*dot*/: Q = sscanf(current_line,"d%lf%lf%lf",&p.x_coord, &p.y_coord,&dot_size); if (Q < 3) {error_d(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); make_dot(p,dot_size); break; case 'P': /* path (to be filled) */ printf("newpath\n"); initial_point = 1; break; case 'L': /* point in path */ Q = sscanf(current_line,"L%lf%lf",&p.x_coord,&p.y_coord); if (Q <= 1) {error_l(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); if (initial_point) move_to(p); else line_to(p); initial_point = 0; break; case 'q': /* terminate and fill path */ printf("closepath fill\n"); break; case 'Q': /* terminate, fill path, and stroke */ printf("closepath gsave fill grestore gsave"); printf(" 0.00 setgray stroke grestore\n"); break; default: fprintf(ERRORFILE,"Data of unknown type in line "); fprintf(ERRORFILE,"%d; ignored up to newline.\n",N+1); break; } N++; } fclose(fp_in); end_drawing(); window_advice(farthest_SW,farthest_NE); } window_advice(ll,ur) point ll, ur; { double vertical, horizontal; printf("%%\n%%The minimal window command would be:\n%%\n"); printf("%%w %4.3f %4.3f %4.3f %4.3f\n", ll.x_coord, ll.y_coord, ur.x_coord, ur.y_coord); horizontal = ur.x_coord - ll.x_coord; vertical = ur.y_coord - ll.y_coord; if (horizontal > vertical) { ur.y_coord += (horizontal - vertical)/2; ll.y_coord -= (horizontal - vertical)/2; } else { ur.x_coord += (vertical - horizontal)/2; ll.x_coord -= (vertical - horizontal)/2; } printf("%%\n%%And the minimal square window command would be:\n%%\n"); printf("%%w %4.3f %4.3f %4.3f %4.3f\n", ll.x_coord, ll.y_coord, ur.x_coord, ur.y_coord); } set_gray(gray_level) double gray_level; { printf("%4.3f setgray\n",gray_level); } set_colors(red,green,blue) double red, green, blue; { if ( (red < 0.0) || (green < 0.0) || (blue < 0.0) || (red > 1.0) || (green > 1.0) || (blue > 1.0)) fprintf(ERRORFILE,"Warning: Color value out of range.\n"); printf("%4.3f %4.3f %4.3f setrgbcolor\n",red,green,blue); } make_dot(p,dot_size) point p; double dot_size; { double i, j, k; i = (p.x_coord * 72)*8.5; j = ((p.y_coord * 8.5)+2.5)*72; k = ((dot_size * 8.5)+0.0)*72; printf("newpath\n"); printf("%4.1f %4.1f moveto ",i,j,k); printf("%4.1f %4.1f %4.1f 0 360 arc fill stroke\n",i,j,k); } set_clip_region(p,q,N) point p, q; int N; { double i, j, k, l; i = (p.x_coord * 72)*8.5; j = ((p.y_coord * 8.5)+2.5)*72; k = (q.x_coord * 72)*8.5; l = ((q.y_coord * 8.5)+2.5)*72; if (i>=0.0 && j>=0.0 && k>=0.0 && l>=0.0 && i<=612.0 && j<=792.0 && k<=612.0 && l<=792.0) { printf("grestore gsave "); /* allows changing clip region */ printf(" %% saves the graphics state of no clipping\n"); printf("newpath\n"); printf("%4.1f %4.1f moveto\n",i,j); printf("%4.1f %4.1f lineto\n",i,l); printf("%4.1f %4.1f lineto\n",k,l); printf("%4.1f %4.1f lineto\n",k,j); printf("closepath clip\n"); printf("WIDTH setlinewidth\n"); } else { fprintf(ERRORFILE,"\nWarning: clip region goes outside window"); fprintf(ERRORFILE," in line %d; request ignored\n",N); } } comment_print(text) char text[]; { printf(" %%%s\n",text); } escape_print(text) char text[]; { printf("%s",text); printf("\n"); } nameprint(text) char text[]; { point p; printf("\t(\\tPicture name: "); printf("%s",text); printf("\\n) print\n"); p.x_coord = .35; p.y_coord = -.15; move_to(p); textprint_large(text); } logprint(text) char text[]; { printf("("); printf("%s",text); printf("\\n) print\n"); } textprint_large(text) char text[]; { printf("/Times-Roman findfont 14 scalefont setfont\n"); printf("("); printf("%s",text); printf(") show\n"); } textprint_medium(text) char text[]; { printf("/Times-Roman findfont 10 scalefont setfont\n"); printf("("); printf("%s",text); printf(") show\n"); } textprint_small(text) char text[]; { printf("/Times-Roman findfont 8 scalefont setfont\n"); printf("("); printf("%s",text); printf(") show\n"); } end_drawing() { printf("showpage\n"); } begin_drawing() { #if(UNIX) char *getlogin(); #endif printf("%%!\n"); include_date_stamp(); printf("\t(\\tPostScript file prepared"); #if(UNIX) printf(" by %s",getlogin()); #endif printf(",\\n) print\n"); printf("\t(\\tusing software by W. Taylor. See Section 2.3.1\\n) print\n"); printf("\t(\\tof his \"Geometry of Computer Graphics,\"\\n) print\n"); printf("\t(\\tpublished by Wadsworth-Brooks-Cole, 1991.\\n) print\n"); printf("\t(\\t ISBN 0-534-17100-1 \\n) print\n"); printf("\t(\\t * * * * \\n) print\n"); printf("gsave\n"); printf("/WIDTH %3.1f def\n",0.0); } set_width(width) int width; { double x; x = ((double) width)*(72.0/300.0); /* printf("%3.1f setlinewidth\n",x); */ printf("/WIDTH %3.1f def\n",x); printf("WIDTH setlinewidth\n"); } line_to(p) point p; { double i, j; i = (p.x_coord * 72)*8.5; j = ((p.y_coord * 8.5) + 2.5) *72; /* if (i>0.0 && j>0.0 && i<612.0 && j<792.0) */ { printf("%4.1f %4.1f lineto\n",i,j); } } move_to(p) point p; { double i, j; i = (p.x_coord * 72)*8.5; j = ((p.y_coord * 8.5) + 2.5) *72; /* if (i>0.0 && j>0.0 && i<612.0 && j<792.0) */ { printf("%4.1f %4.1f moveto\n",i,j); } } makeline(p,q) point p, q; { double i, j, k, l; k = (p.x_coord * 72)*8.5; l = ((p.y_coord * 8.5) + 2.5) *72; i = (q.x_coord * 72)*8.5; j = ((q.y_coord * 8.5) + 2.5) *72; /* if (i>0.0 && j>0.0 && k>0.0 && l>0.0 && i<612.0 && j<792.0 && k<612.0 && l<792.0) */ { printf("newpath\n"); printf("%4.1f %4.1f moveto\n",i,j); printf("%4.1f %4.1f lineto\n",k,l); printf("stroke\n"); } } char months[12][20] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; char days[7][20] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; include_date_stamp() { char month[20]; char day[20]; #if(UNIX) char *getlogin(); struct tm *localtime(), *tp; struct timeval tv; struct timezone tz; printf("%% This is a PostScript file that was made"); printf(" by translating a\n"); printf("%% device-independent graphics file in the manner"); printf(" described in section\n"); printf("%% 2.3.1 of W. Taylor's \"The Geometry of Computer"); printf(" Graphics,\" Wadsworth &\n"); printf("%% Brooks/Cole, 1991. ISBN 0-534-17100-1\n"); printf("%%\n"); printf("%% The translation was made by %s on\n",getlogin()); gettimeofday(&tv, &tz); tp = localtime(&tv.tv_sec); printf("%%\n"); printf("%% %s, %s %d, 19%d ", days[tp->tm_wday], months[tp->tm_mon], tp->tm_mday, tp->tm_year); if (tp->tm_hour==0) printf(" %d:%d AM \n", 12 ,tp->tm_min); if (tp->tm_hour<12) printf(" %d:%d AM \n",tp->tm_hour,tp->tm_min); if (tp->tm_hour==12) printf(" %d:%d PM \n", 0 ,tp->tm_min); if (tp->tm_hour>12) printf(" %d:%d PM \n",tp->tm_hour -12,tp->tm_min); printf("%% \n"); #endif } error_1(N,in_filename) int N; char in_filename[]; { fprintf(ERRORFILE,"\nSuccessfully read "); fprintf(ERRORFILE,"%d lines of data from \"%s\"\n",N,in_filename); } error_w1(N) int N; { fprintf(ERRORFILE,"\nWindow error in line %d. Window must have "); fprintf(ERRORFILE,"non-zero",N); fprintf(ERRORFILE," width and height.\nProgram terminated.\n"); } error_r0(N) int N; { fprintf(ERRORFILE,"\nRegion error in line %d. Must give four region", N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_w0(N) int N; { fprintf(ERRORFILE,"\nWindow error in line %d. Must give four window" ,N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_l(N) int N; { fprintf(ERRORFILE,"\nLine error in line %d. Must give two line",N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_l1(N) int N; { fprintf(ERRORFILE,"\nError in line %d. You cannot draw a line",N); fprintf(ERRORFILE," until you have moved at least once.\n"); fprintf(ERRORFILE,"Program terminated.\n"); } error_d(N) int N; { fprintf(ERRORFILE,"\nDot error in line %d. Must give two dot",N); fprintf(ERRORFILE," coordinates\n\t\t\tand one dot radius.\n"); fprintf(ERRORFILE,"Program terminated.\n"); } error_m(N) int N; { fprintf(ERRORFILE,"\nMove error in line %d. Must give two move",N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_W(N) int N; { fprintf(ERRORFILE,"\nWidth error in line %d. Must give a "); fprintf(ERRORFILE,"single integral",N); fprintf(ERRORFILE," coordinate.\nProgram terminated.\n"); } stretch(p,ll,ur) point p, *ll, *ur; { if (ll->x_coord > p.x_coord) ll->x_coord = p.x_coord; if (ll->y_coord > p.y_coord) ll->y_coord = p.y_coord; if (ur->x_coord < p.x_coord) ur->x_coord = p.x_coord; if (ur->y_coord < p.y_coord) ur->y_coord = p.y_coord; }