/* File: to_ps.c */ /* version modified 9/17/00 by Nick Demos to be ANSI-compliant. So far this can be compiled as C-code using either Borland or the unix compiler cc. It can be compiled as .cpp code only when UNIX is set to 0. Use at your own risk. */ #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 #include #if(UNIX) #include #include #endif #define DATAFILE "data" #define ERRORFILE stderr /* *************************************** Structs ***************************************** */ typedef struct _tag_point { double x_coord; double y_coord; } point; /* ************************************** Prototypes ************************************** */ void set_width(int width); void window_advice(point ll, point ur); void set_gray(double gray_level); void set_colors(double red, double green, double blue); void make_dot(point p, double dot_size); void set_clip_region(point p, point q, int N); void comment_print(char text[]); void escape_print(char text[]); void nameprint(char text[]); void logprint(char text[]); void textprint_large(char text[]); void textprint_medium(char text[]); void textprint_small(char text[]); void end_drawing(void); void begin_drawing(void); void set_width(int width); void line_to(point p); void move_to(point p); void makeline(point p, point q); void include_date_stamp(void); void error_1(int N, char in_filename[]); void error_w1(int N); void error_r0(int N); void error_w0(int N); void error_l(int N); void error_l1(int N); void error_d(int N); void error_m(int N); void error_W(int N); void stretch(point p, point *ll, point *ur); void scalepoint_to_window(point *p, point ll, point ur);/* new */ /* ***************************************** Main ***************************************** */ void 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 = NULL, *fp_out = NULL; point lower_left, upper_right, p, q; point farthest_SW, farthest_NE; point r, s; double black = 0.0, white = 1.0; double dot_size; int initial_point; fp_in = stdin; /* Sets the input stream file pointer to stdin */ strcpy(in_filename, "standard input"); fp_out = stdout; /* Sets the output stream file pointer to stdou*/ strcpy(out_filename, "standard output"); 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"); if((Q = fscanf(fp_in, "%[^\n]", current_line)) <= 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 '\\'/*escape*/: 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); no_input_errors = 0; break; } if((r.x_coord == s.x_coord) || (r.y_coord == s.y_coord)){ error_w1(N + 1); no_input_errors = 0; } scalepoint_to_window(&r, lower_left, upper_right); scalepoint_to_window(&s, lower_left, upper_right); 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); no_input_errors = 0; } if(black == white){ error_w1(N + 1); 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); 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); no_input_errors = 0; } break; case 'W'/*Width*/: { int width; Q = sscanf(current_line, "W%d", &width); if(Q <= 0){ error_W(N + 1); 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); 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); 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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); move_to(p); break; case 'l'/*line*/: if(!ok_to_draw_line){ error_l1(N + 1); 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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); 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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); make_dot(p, dot_size); break; case 'P': /* path (to be filled) */ fprintf(fp_out, "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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); 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; }/* End of switch(current_line[0]) */ N++; }/* End of while(no_input_errors) */ end_drawing(); window_advice(farthest_SW, farthest_NE); fclose(fp_in); }/* End of main() */ /* *************************** Function Definitions ***************************** */ void window_advice(point ll, point 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); } void set_gray(double gray_level) { printf("%4.3f setgray\n", gray_level); } void set_colors(double red, double green, double 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); } void make_dot(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); } void set_clip_region(point p, point 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 && i <= 612.0 && j >= 0.0 && j <= 792.0 && k >= 0.0 && k <= 612.0 && l >= 0.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); } } void comment_print(char text[]) { printf(" %%%s\n", text); } void escape_print(char text[]) { printf("%s", text); printf("\n"); } void nameprint(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); } void logprint(char text[]) { printf("("); printf("%s", text); printf("\\n) print\n"); } void textprint_large(char text[]) { printf("/Times-Roman findfont 14 scalefont setfont\n"); printf("("); printf("%s", text); printf(") show\n"); } void textprint_medium(char text[]) { printf("/Times-Roman findfont 10 scalefont setfont\n"); printf("("); printf("%s", text); printf(") show\n"); } void textprint_small(char text[]) { printf("/Times-Roman findfont 8 scalefont setfont\n"); printf("("); printf("%s", text); printf(") show\n"); } void end_drawing(void) { printf("showpage\n"); } void begin_drawing(void) { #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); } void set_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"); } void line_to(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 && i < 612.0 && j > 0.0 && j < 792.0){ */ printf("%4.1f %4.1f lineto\n", i, j); /* }*/ } void move_to(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 && i < 612.0 && j > 0.0 && j < 792.0){ */ printf("%4.1f %4.1f moveto\n", i, j); /* }*/ } void makeline(point p, point 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"); /* }*/ } /* *** Month & Day Of Week String Arrays */ 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" }; void include_date_stamp(void) { #if(UNIX) char month[20]; char day[20]; 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 } void error_1(int N, char in_filename[]) { fprintf(ERRORFILE, "\nSuccessfully read "); fprintf(ERRORFILE, "%d lines of data from \"%s\"\n", N, in_filename); } void error_w1(int N) { fprintf(ERRORFILE, "\nWindow error in line %d. Window must have non-zero", N); fprintf(ERRORFILE, " width and height.\nProgram terminated.\n"); } void error_r0(int N) { fprintf(ERRORFILE, "\nRegion error in line %d. Must give four region", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_w0(int N) { fprintf(ERRORFILE, "\nWindow error in line %d. Must give four window", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_l(int N) { fprintf(ERRORFILE, "\nLine error in line %d. Must give two line", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_l1(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"); } void error_d(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"); } void error_m(int N) { fprintf(ERRORFILE, "\nMove error in line %d. Must give two move", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_W(int N) { fprintf(ERRORFILE, "\nWidth error in line %d. Must give a single integral", N); fprintf(ERRORFILE, " coordinate.\nProgram terminated.\n"); } void stretch(point p, point *ll, point *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; } void scalepoint_to_window(point *p, point ll, point ur) { p->x_coord = (p->x_coord - ll.x_coord) / (ur.x_coord - ll.x_coord); p->y_coord = (p->y_coord - ll.y_coord) / (ur.y_coord - ll.y_coord); }