/* ps.c 28 April 1999 */ /* copyright 1987-1990 Phil Andrews, Pittsburgh Supercomputing Center */ # include # include # include # include # include # include "defs.h" #define byte_size 8 #define out_ln(instr) {out_string(instr); fb();} #define APPENDED_MARKER -123 /* appended text coming */ /* module for PostScript specific functions, note that we expect the device resolution is pxl_per_in, set by the calling program. All dimensions are expected to come in terms of device pixels */ static int ng_fix; /* do we need a newgen-style fix ? */ static int ng_skip = 1; /* if ng_fix skip these many lines in font desc. */ static int ncar_file; /* is it a brain-damaged NCAR file ? */ static int use_colours; /* for a colour printer */ #define word_size (sizeof(int) * byte_size) static int pxl_per_in; static char string_buffer[max_str + 1]; static int str_index; static int clip_set; /* make indices one and two point to the same font for compatibility */ static char *ps_def_font[] = {"Times-Roman", "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", "Symbol" }; #define max_ps_font (sizeof ps_def_font / (sizeof ps_def_font[0])) /* store these pointers to allow lookups into the CGM data structures */ static struct one_opt *popt; /* the command line options, in only */ static struct mf_d_struct *pc1; /* the class 1 elements, in only */ static struct pic_d_struct *pc2; /* the class 2 elements, in only */ static struct control_struct *pc3; /* the class 3 elements, in only */ static struct attrib_struct *pc5; /* the class 5 elements, in only */ static struct info_struct *dptr; /* device info, in and out */ /* For hex strings. */ static int hex_char[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; static int old_l_type; /* line type presently set */ static int old_l_width; /* line width presently set */ static float old_r, old_g, old_b; /* colour presently set */ static int state_level; static struct rgbi_struct old_back_col; /* the background colour used */ /* macro to convert from r, g, b to grey_scale, NTSC standard */ #define col_grey(r, g, b) (1.0 - (0.3 * r + 0.59 * g + 0.11 * b)) /* postscript globals */ static int ps_started_show = 0, ps_h, ps_v, def_dofont = 0; static int ps_xscale = 1, ps_yscale = 1; static char *ps_name[max_chars] = { "Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Upsilon", "Phi", "Psi", "Omega", "ff", "fi", "fl", "ffi", "ffl", "vari", "varj", "p1", "p2", "p3", "p4", "p5", "p6", "p7", "fbeta", "ae", "oe", "slo", "capae", "capoe", "capslo", "p8", "exclam", "dblq1", "splat", "dollar", "percent", "ampersand", "apost", "lparen", "rparen", "star", "plus", "comma", "minus", "dot", "slash", "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "colon", "semicolon", "upexclam", "equals", "upquest", "quest", "atsign", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "lsqparen", "dblq2", "rsqparen", "caret", "hidot", "p10", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "shorthyphen", "longhyphen", "p11", "twiddles", "dotdot" }; /* PROCEDURE DECLARATIONS */ static flush_string ( ); static l_dofont ( ); static send_string ( char *in_string, int str_l ); /* general colour setting routine */ static void set_colour(cptr) struct rgbi_struct *cptr; { float r, g, b; char buffer[max_str]; if (pc2->c_s_mode == i_c_mode) { /* indexed */ r = pc5->ctab[cptr->ind * 3]; g = pc5->ctab[cptr->ind * 3 + 1]; b = pc5->ctab[cptr->ind * 3 + 2]; } else if (pc2->c_s_mode == d_c_mode) { /* direct colour */ r = cptr->red; g = cptr->green; b = cptr->blue; } if ((fabs(r - old_r) + fabs(g - old_g) + fabs(b - old_b)) > 0.001) { sprintf(buffer, "%.4f %.4f %.4f setrgbcolor ", r, g, b); out_string(buffer); old_r = r; old_g = g; old_b = b; } return; } /* set it to something we can see */ static void set_complement(cptr) struct rgbi_struct *cptr; /* presumably background colour */ { float r, g, b; char buffer[max_str]; r = cptr->red; g = cptr->green; b = cptr->blue; /* now get the complement colour */ r = 1.0 - r; g = 1.0 - g; b = 1.0 - b; if ((fabs(r - old_r) + fabs(g - old_g) + fabs(b - old_b)) > 0.001) { sprintf(buffer, "%.4f %.4f %.4f setrgbcolor ", r, g, b); out_string(buffer); old_r = r; old_g = g; old_b = b; } return; } /* set the line type and width */ static void set_l_type(l_type, line_width) int line_width; enum line_enum l_type; { int dash_size, dot_size; if (line_width <= 0) line_width = 1; if ((int) l_type != old_l_type) { old_l_type = (int) l_type; dash_size = 20 * line_width; /* guess */ dot_size = dash_size / 4; /* guess */ if (dot_size <= 0) dot_size = 1; if (dash_size <= dot_size) dash_size = 4 * dot_size; switch (l_type) { case solid_l: out_string("[] 0 sd "); break; case dash: outc('['); outint(dash_size); outint(dot_size); out_string("] 0 sd "); break; case dot_l: outc('['); outint(dot_size); out_string("] 0 sd "); break; case dash_dot: outc('['); outint(dash_size); outint(dot_size); outint(dot_size); outint(dot_size); out_string("] 0 sd "); break; case dash_d_d: outc('['); outint(dash_size); outint(dot_size); outint(dot_size); outint(dot_size); outint(dot_size); outint(dot_size); out_string("] 0 sd "); break; default: fprintf(stderr, "unknown line type [%d]!\n", l_type); } } if (line_width != old_l_width) { outint(line_width); out_string("sl "); old_l_width = line_width; } return; } /* write adobe style header and set up the printer */ ps_begin(comment, file_name, prog_name) char *comment, *file_name, *prog_name; { long time(), now; char *ctime(), out_date[40]; int slen; static char buffer[max_str]; ncar_file = 0; /* benefit of the doubt */ ++state_level; if (state_level > 0) return(1); /* already done everything */ pxl_per_in = dptr->pxl_in; /* might have been changed */ ng_fix = (pxl_per_in == 400); /* for now */ def_dofont = 0; out_ln("%!PS-Adobe-1.0"); out_string("%%DocumentFonts: "); out_ln(ps_def_font[0]); out_string("%%Title: "); out_ln(file_name); out_string("%%Creator: "); out_ln(prog_name); now = time(0); strcpy(out_date, ctime(&now)); slen = strlen(out_date); *(out_date + ((slen) ? slen - 1 : 0) ) = 0; /* eliminate ctrl-j */ out_string("%%CreationDate: "); out_ln(out_date); /* set the bounding box equal to the page size */ out_string("%%BoundingBox: "); outint(0); outint(0); outint(((int) (72 * dptr->x_size))); outint(((int) (72 * dptr->y_size))); fb(); out_ln("%%EndComments"); out_ln("save"); /* save introductory state */ /* get the scaling right (1 unit = 1 pixel), PS default = 72 points/in */ outint(72); outint(pxl_per_in); out_ln("div dup scale % scale co-ordinate system"); /* handy abbreviations */ out_ln("/ln {lineto} def /mv {moveto} def /np {newpath} def /st {stroke} def"); out_ln("/s {show} def /cp {closepath} def /sd {setdash} def /sl {setlinewidth} def"); out_ln("/ch { dup stringwidth pop 2 div neg 0 rmoveto } def /mch {ch show} def"); out_ln("/rh { dup stringwidth pop neg 0 rmoveto } def /fl {fill} def"); /* that was the set of macros required for GPLOT, do GTEX now */ out_ln("/rp {show 1 0 rmoveto} def /rm {show -1 0 rmoveto} def /rpn {1 0 rmoveto} def"); out_ln("/rmn {-1 0 rmoveto} def /ah {av moveto} def /sf {findfont setfont} def"); out_ln("/mh {dup /av exch def moveto} def /tr {translate} def "); out_ln("/gs {gsave} def /gr {grestore} def "); /* set up a default font */ ps_font(0, 40); /* about 10 pts */ return(1); } /* do an adobe trailer */ ps_end(pages_done) int pages_done; { fb(); --state_level; if (state_level >= 0) return(1); out_ln("restore"); /* restore introductory state */ out_ln("%%Trailer"); out_string("%%Pages: "); outint(pages_done); fb(); return(1); } /* start the page */ ps_bpage(pic_name, xoffset, yoffset, rotation, rb, gb, bb, page_no, xsize, ysize) char *pic_name; float rotation; /* how much to rotate the page */ int xoffset, yoffset; /* offset in pixels */ int page_no; /* page number */ float rb, gb, bb; /* background colour values */ int xsize, ysize; { int max_x, max_y; char buffer[max_str]; clip_set = 0; old_back_col.red = rb; old_back_col.green = gb; old_back_col.blue = bb; old_back_col.ind = 0; old_r = old_g = old_b = -1.0; /* to ensure a colour set */ out_string("save "); /* save the introductory state */ /* handle translation and/or rotation */ if (xoffset || yoffset) { outint(xoffset); outint(yoffset); out_string("tr "); } if (rotation != 0.0) { sprintf(buffer, "%.4f rotate ", rotation); out_string(buffer); } /* set the background colour, if dark */ if (((fabs(rb) + fabs(gb) + fabs(bb)) / 3.0) < 0.95) { max_x = pxl_per_in * dptr->x_size; max_y = pxl_per_in * dptr->y_size; sprintf(buffer, "np %d %d mv %d %d ln %d %d ln %d %d ln ", 0, 0, max_x, 0, max_x, max_y, 0, max_y); out_string(buffer); set_colour(&old_back_col); out_string("cp fill "); } old_l_type = -1; old_l_width = -1; return(1); } /* end the page */ ps_epage(no_copies) { if (ps_started_show) flush_string(); if (clip_set) { clip_set = 0; } if (state_level == 0) { if (no_copies > 1) { out_string("/#copies "); outint(no_copies); out_ln("def"); } out_ln("showpage restore"); } else out_ln("restore"); return(1); } /* Metafile description */ ps_mfdescrip(char_ptr) char *char_ptr; { #define NCAR_FLAG_SIZE 4 static char ncar_flag[NCAR_FLAG_SIZE + 1] = "NCAR"; int i; if (char_ptr) { for (i=0; (itext_colour); if ((x != APPENDED_MARKER) || (y != APPENDED_MARKER) || ncar_file) { out_string("gs "); outint(x); outint(y); } else out_string("xs ys "); out_string("tr "); /* translate origin */ out_string("0 0 mv "); /* go to the origin */ buffer_len = strlen(buffer); /* first establish defaults */ ctheta1 = stheta2 = 1.0; stheta1 = ctheta2 = 0.0; /* now make the calls */ angle_str(&ctheta1, &stheta1, pc5->c_orient.y_base, pc5->c_orient.x_base); angle_str(&ctheta2, &stheta2, pc5->c_orient.y_up, pc5->c_orient.x_up); /* do we need a transformation */ need_transform = (ctheta1 != 1.0) || (stheta2 != 1.0) || (stheta1 != 0.0) || (ctheta2 != 0.0); if (need_transform) { det = ctheta1 * stheta2 - ctheta2 * stheta1; if (det == 0.0) det = 1.0; /* safety */ sprintf(trans_buffer, "[%.4f %.4f %.4f %.4f 0 0] concat ", stheta2 / det, -ctheta2 / det, -stheta1 / det, ctheta1 / det); out_string(trans_buffer); } /* now output the string */ switch (pc5->text_path) { case right : send_string(buffer, buffer_len); out_string("s "); break; case left : cptr = buffer + buffer_len; for (i=0; (ic_height); out_string("mv "); send_string(cptr++, 1); out_string("s "); } break; case down : cptr = buffer; for (i=0; ic_height); out_string("mv "); send_string(cptr++, 1); out_string("s "); } break; default : fprintf(stderr, "illegal value (%d) for path\n", pc5->text_path); break; } if (final || ncar_file) out_string("gr "); else out_string("currentpoint /ys exch def /xs exch def "); /* mark our place */ return(1); } /* actually output a string */ static send_string ( char *in_string, int str_l ) { int i; static char ps_string[4 * max_str + 1] = {'('}; char *c_ptr, *ps_ptr; if (str_l > max_str) str_l = max_str; c_ptr = in_string; ps_ptr = ps_string + 1; for (i=0; ic_width / width; r_height = dptr->c_height / width; /* which one is bigger ? */ r_scale = (r_height > r_width) ? r_height : r_width; out_string("gs "); /* save the graphics state */ if (r_scale > 1.0) { outc('/'); out_string(ps_def_font[pc5->t_f_index]); out_string(" findfont "); outint((int) (dptr->c_height / r_scale)); out_string("scalefont setfont "); } /* set the clipping path (simpleminded for now */ out_string("np "); outint(x); outint(y); out_string("mv "); outint(x + width); outint(y); out_string("ln "); outint(x + width); outint(y + height); out_string("ln "); outint(x); outint(y + height); out_string("ln cp clip "); /* pass it to the regular text handler */ ps_text(x, y, final, buffer); out_string("gr np "); /* for safety */ return(1); } /* appended text */ ps_app_text(final, buffer) enum boolean final; char *buffer; { ps_text(APPENDED_MARKER, APPENDED_MARKER, final, buffer); return(1); } /* handle clipping */ /* set the clipping rectangle */ ps_cliprect(int_coords, float_coords) int *int_coords; float *float_coords; /* two corner points */ { /* set the clipping path (simpleminded for now */ if (clip_set) { out_string("initclip "); } else clip_set = 1; out_string("np "); outint(int_coords[0]); outint(int_coords[1]); out_string("mv "); outint(int_coords[2]); outint(int_coords[1]); out_string("ln "); outint(int_coords[2]); outint(int_coords[3]); out_string("ln "); outint(int_coords[0]); outint(int_coords[3]); out_string("ln cp clip "); return(1); } /* set the clipping indicator */ ps_clipindic(clip_ind) int clip_ind; { if (!clip_ind && clip_set) { out_string("initclip "); clip_set = 0; } return(1); } /* plot a set of lines */ ps_pline(no_pairs, x1_ptr, y1_ptr) int no_pairs, *x1_ptr, *y1_ptr; { int i; if ( no_pairs <= 1 ) return(1); set_l_type(pc5->line_type, pc5->line_width.i); if ((ncar_file) && (!use_colours)) set_complement(&old_back_col); else set_colour(&pc5->line_colour); out_string("np "); outint(x1_ptr[0]); outint(y1_ptr[0]); out_string("mv "); for (i=1;iline_type, pc5->line_width.i); if ((ncar_file) && (!use_colours)) set_complement(&old_back_col); else set_colour(&pc5->line_colour); for (i=0; i < no_pairs ; i+=2) { out_string("np "); outint(x1_ptr[i]); outint(y1_ptr[i]); out_string("mv "); outint(x1_ptr[i+1]); outint(y1_ptr[i+1]); out_string("ln st "); } return(1); } /* put up a series of markers, characters are set at bottom left corner */ ps_pmarker(no_pairs, x1_ptr, y1_ptr) int no_pairs, *x1_ptr, *y1_ptr; { int i, x_adjust = 0, y_adjust = 0; if ((ncar_file) && (!use_colours)) set_complement(&old_back_col); else set_colour(&pc5->mk_colour); out_string("gs "); if (pc5->mk_type == 1) ps_font(0, 1); /* a dot */ else ps_font(0, pc5->mk_size.i); switch (pc5->mk_type) { case 1 : y_adjust = - 0.05 * pc5->mk_size.i; break; case 2 : y_adjust = -0.28 * pc5->mk_size.i; break; case 3 : y_adjust = -0.45 * pc5->mk_size.i; break; case 4 : y_adjust = -0.23 * pc5->mk_size.i; break; case 5 : y_adjust = -0.23 * pc5->mk_size.i; break; default: fprintf(stderr, "illegal marker type ! = %d\n", (int) pc5->mk_type); y_adjust = pc5->mk_size.i / 2; } for (i=0;imk_type]); out_string(") mch "); } out_string("gr "); return(1); } /* set the character height */ ps_cheight(size) int size; { ps_font(pc5->t_f_index, size); return(1); } /* set a font */ ps_font(index, size) int index, size; { char buffer[max_str]; if (size <= 0) size = 40; sprintf(buffer, "/%s ", ps_def_font[index]); out_string(buffer); out_string("findfont "); outint(size); out_string("scalefont setfont "); dptr->c_height = dptr->c_width = size; return(1); } /* do a polygon */ ps_pgon(no_pairs, x1_ptr, y1_ptr) int no_pairs, *x1_ptr, *y1_ptr; { int i, want_edge; if ( no_pairs <= 1 ) return(1); want_edge = (pc5->edge_vis == on) || (pc5->int_style == hollow); out_string("np "); outint(x1_ptr[0]); outint(y1_ptr[0]); out_string("mv "); for (i=1;iint_style) { case hollow : if (want_edge) out_string("cp ");break; case empty : if (want_edge) out_string("cp ");break; /* don't try to fill these */ case pattern : if (want_edge) out_string("cp ");break; /* no pattern fill yet */ case hatch : if (want_edge) out_string("cp ");break; /* no hatch fill yet */ case solid_i : set_colour(&pc5->fill_colour); if (want_edge) out_string("cp gs fill gr "); else out_string("cp fill "); break; } /* may want visible edge */ if (want_edge){ set_l_type(pc5->edge_type, pc5->edge_width.i); if (pc5->edge_vis == on) set_colour(&pc5->edge_colour); else set_colour(&pc5->fill_colour); out_string("st "); } return(1); } /* do a polyset */ ps_pset(no_pairs, x1_ptr, y1_ptr, edge_ptr) int no_pairs, *x1_ptr, *y1_ptr; char *edge_ptr; { int i, want_edge, old_x, old_y, line_on; if ( no_pairs <= 1 ) return(1); want_edge = (pc5->edge_vis == on) || (pc5->int_style == hollow); /* first do the interior fill */ out_string("np "); outint(x1_ptr[0]); outint(y1_ptr[0]); out_string("mv "); for (i=1; i<=no_pairs; ++i) { /* must end correctly */ if ((edge_ptr[i-1] > 1) || (i==no_pairs)) { /* end of path */ out_string("cp "); if (iint_style) { case hollow : break; case empty : out_string("np "); break; /* don't try to fill these */ case pattern : /* no pattern fill yet */ case hatch : /* no hatch fill yet */ case solid_i : set_colour(&pc5->fill_colour); /* NOTE ! eofill has no implicit newpath */ out_string("eofill np "); break; } /* may want visible edge */ if (want_edge) { set_l_type(pc5->edge_type, pc5->edge_width.i); if (pc5->edge_vis == on) set_colour(&pc5->edge_colour); else set_colour(&pc5->fill_colour); outint(old_x = x1_ptr[0]); outint(old_y = y1_ptr[0]); out_string("mv "); line_on = 0; i = 0; while (ic_s_mode; /* start with this, may change */ switch (c_s_mode) { case d_c_mode: c_size = 3 * col_prec; break; case i_c_mode: c_size = col_prec; break; default: fprintf(stderr, "illegal colour selection mode ! (%d)\n", (int) c_s_mode); return(2); } /* now get the row size in bytes allowing for rounding */ true_size = row_size = (nx * c_size + byte_size - 1) / byte_size; /* check */ old_size = row_size = (row_size % 2) ? row_size + 1 : row_size; /* round up */ /* expand a compressed raster */ if (rep_mode == 0) { new_ptr = allocate_mem(ny * row_size, 1); if (!new_ptr) return(2); (void) c_expand(dat_ptr, nx, ny, row_size, c_size, new_ptr); dat_ptr = new_ptr; /* carry on as before */ } /* for now we assume that postscript can handle grey-scale arrays only thus have to convert from a colour array to a grey scale. Postscript allows 1, 2, 4 or 8 bits per pixel to specify the grey value */ /* if the colour precision is 1 and the mode is indexed, then we will pass (almost) straight thru since the data is basically boolean */ if ((c_s_mode != i_c_mode) || (col_prec > 1)) { /* need to massage */ /* work out how many bits we will have in a pixel */ /* for now ask for 8 */ bits_sample = 8; components = (use_colours) ? 3 : 1; true_size = (nx * bits_sample*components + byte_size - 1) / byte_size; row_size = (true_size % 2) ? true_size + 1 : true_size; grey_ptr = allocate_mem(ny * row_size, 1); grey_array(dat_ptr, nx, ny, grey_ptr, c_s_mode, col_prec, pc5->ctab, bits_sample, old_size, row_size, components); dat_ptr = grey_ptr; } else { /* this is our fastest case, assume want speed rather than accuracy */ bits_sample = 1; /* have to check if we have reversed colour */ reverse_colour = col_grey(pc5->ctab[0], pc5->ctab[1], pc5->ctab[2]) > col_grey(pc5->ctab[3], pc5->ctab[4], pc5->ctab[5]); } /* now confident we have packed list 1, 2, 4 or 8 precision cell array */ /* but we may have to expand/shrink/rotate/skew, try to do it all in array */ out_string("gs "); /* save the present state */ tx = cp[0]; ty = cp[1]; a = cr[0] - tx; b = cr[1] - ty; c = cq[0] - cr[0]; d = cq[1] - cr[1]; sprintf(buffer, "[%d %d %d %d %d %d] concat ", a, b, c, d, tx, ty); out_string(buffer); sprintf(buffer, "/str %d string def ", true_size); out_ln(buffer); max_val = (1 << bits_sample) - 1; outint(nx); outint(ny); outint(bits_sample); sprintf(buffer, "[%d %d %d %d %d %d]", nx, 0, 0, ny, 0, 0); out_string(buffer); if (use_colours) { out_ln("{currentfile str readhexstring pop} false "); outint(components); out_ln("colorimage"); } else out_ln("{currentfile str readhexstring pop} image"); for (i=0; i> 4]); outc(hex_char[outb & 15]); } if (row_size > true_size) ++dat_ptr; /* skip padding byte */ } fb(); /* put end of line here */ out_string("gr "); if (new_ptr) free(new_ptr); if (grey_ptr) free(grey_ptr); return(1); } /* set a rectangle */ ps_rectangle(x_1, y_1, x2, y2) int x_1, x2, y_1, y2; { int want_edge; want_edge = (pc5->edge_vis == on) || (pc5->int_style == hollow); out_string("np "); outint(x_1); outint(y_1); out_string("mv "); outint(x_1); outint(y2); out_string("ln "); outint(x2); outint(y2); out_string("ln "); outint(x2); outint(y_1); out_string("ln "); switch (pc5->int_style) { case hollow : if (want_edge) out_string("cp ");break; case empty : if (want_edge) out_string("cp ");break; /* don't try to fill these */ case pattern : if (want_edge) out_string("cp ");break; /* no pattern fill yet */ case hatch : if (want_edge) out_string("cp ");break; /* no hatch fill yet */ case solid_i : set_colour(&pc5->fill_colour); if (want_edge) out_string("cp gs fill gr "); else out_string("cp fill "); break; } /* may want visible edge */ if (want_edge){ set_l_type(pc5->edge_type, pc5->edge_width.i); if (pc5->edge_vis == on) set_colour(&pc5->edge_colour); else set_colour(&pc5->fill_colour); out_string("st "); } return(1); } /* set a Circle */ ps_circle(x, y, r) int x, y, r; { float d0, d1; int want_edge; want_edge = (pc5->edge_vis == on) || (pc5->int_style == hollow); out_string("np "); outint(x); outint(y); outint(r); outint(0); outint(360); out_string("arc "); switch (pc5->int_style) { case hollow : case empty : break; /* don't try to fill these */ case pattern : /* no pattern fill yet */ case hatch : /* no hatch fill yet */ case solid_i : set_colour(&pc5->fill_colour); if (want_edge) out_string("cp gs fill gr "); else out_string("cp fill "); break; } /* may want visible edge */ if (want_edge){ set_l_type(pc5->edge_type, pc5->edge_width.i); if (pc5->edge_vis == on) set_colour(&pc5->edge_colour); else set_colour(&pc5->fill_colour); out_string("st "); } return(1); } /* set an arc, we get the positions of 1st pt, intermediate pt, end pt */ /* see utils.c for details */ ps_c3(pt_ptr) int *pt_ptr; { int xc, yc, r; /* circle centre and radius */ float deg[3]; /* starting and ending degrees (0 at top) */ double theta[3]; extern get_c_info(); /* utils.c */ float theta0, theta2; if (!get_c_info(pt_ptr, &xc, &yc, &r, theta, deg)) return(2); /* now figure out which direction */ if ((deg[0] <= deg[1]) && (deg[1] <= deg[2])) { theta0 = deg[0]; theta2 = deg[2]; } else { theta0 = deg[2]; theta2 = deg[0]; } out_string("np "); outint(xc); outint(yc); outint(r); outint((int) theta0); outint((int) theta2); out_string("arc st "); return(1); } /* set a closed arc, get the positions of 1st pt, intermdiate pt, end pt */ ps_c3_close(pt_ptr, chord) int *pt_ptr; enum boolean chord; { int xc, yc, r; /* circle centre and radius */ float deg[3]; /* starting and ending degrees (0 at top) */ double theta[3]; extern get_c_info(); /* utils.c */ get_c_info(pt_ptr, &xc, &yc, &r, theta, deg); out_string("np "); outint(xc); outint(yc); outint(r); outint((int) deg[0] + 90); outint((int) deg[2] + 90); out_string("arc "); /* now the closing part */ if (chord) { /* close with a chord */ out_string("cp st "); } else { /* close like a pie */ outint(xc); outint(yc); out_string("ln cp st "); } return(1); } /* set an arc, ends specified by vectors */ ps_c_centre(x, y, vec_array, r) int x, y, *vec_array, r; { float deg0, deg1; double theta; extern get_angle(); /* utils.c */ char buffer[max_str]; get_angle(vec_array, °0, &theta); get_angle(vec_array + 2, °1, &theta); out_string("np "); outint(x); outint(y); outint(r); sprintf(buffer, "%.4f ", deg0); out_string(buffer); sprintf(buffer, "%.4f ", deg1); out_string(buffer); out_string("arc st "); return(1); } /* set an arc, ends specified by vectors, but close it */ ps_c_c_close(x, y, vec_array, r, chord) int x, y, *vec_array, r; enum boolean chord; { float deg0, deg1; double theta; extern get_angle(); /* utils.c */ get_angle(vec_array, °0, &theta); get_angle(vec_array + 2, °1, &theta); out_string("np "); outint(x); outint(y); outint(r); outint((int) deg0 + 90); outint((int) deg1 + 90); out_string("arc "); /* now the closing part */ if (chord) { /* close with a chord */ out_string("cp st "); } else { /* close like a pie */ outint(x); outint(y); out_string("ln cp st "); } return(1); } /* first the basic UIS ellipse routine */ static do_ellipse(x, y, r, deg0, deg1) int x, y, r; /* position of centre and radius */ float *deg0, *deg1; /* beginning and ending degrees (start at top) */ { return(1); } /* set an ellipse, centre and two endpoints */ ps_ellipse(pt_array) int *pt_array; { return(1); } /* set an elliptical arc, centre, two endpoints, vectors for ends */ ps_ell_arc(pt_array, vec_array) int *pt_array, *vec_array; { return(1); } /* set an elliptical arc, close it */ ps_e_a_close(pt_array, vec_array, chord) int *pt_array, *vec_array; enum boolean chord; { return(1); } /* the TeX setting routines */ ps_s_font(font_no) int font_no; { char buffer[max_str]; if (ps_started_show) flush_string(); sprintf(buffer, "/TF%d sf ", font_no); out_string(buffer); return(1); } /* set a rule */ ps_s_rule(h, v, w_pxl, h_pxl) int h, v, w_pxl, h_pxl; { char buffer[max_str]; v += (h_pxl/2.0); /* postscript uses the center of the line */ if (ps_started_show) flush_string(); sprintf(buffer, "gs newpath %d %d moveto %d %d rlineto %d\ setlinewidth stroke gr ", h, v, w_pxl, 0, h_pxl); out_string(buffer); return(1); } /* end the font definition */ ps_e_font(font_no) int font_no; { char buffer[max_str]; out_string("/.notdef [.24 0 0 0 0 1 0 0 <>] def "); out_string("end end "); /* eliminated unique id, caused problems */ sprintf(buffer, "/TF%d exch definefont pop ", font_no); out_string(buffer); return(1); } /* set both the absolute vertical and horizontal positions */ ps_abs_both(hpos, vpos) int hpos, vpos; { char buffer[max_str]; if (ps_started_show) flush_string(); sprintf(buffer, "%d %d mh ", hpos, vpos); out_string(buffer); ps_h = hpos; ps_v = vpos; return(1); } /* set the absolute horizontal position */ ps_abs_h(pos) int pos; { char buffer[max_str]; if (ps_started_show) flush_string(); sprintf(buffer, "%d ah ", pos); out_string(buffer); ps_h = pos; return(1); } /* set the absolute vertical position */ ps_abs_v(pos) int pos; { char buffer[max_str]; if (ps_started_show) flush_string(); sprintf(buffer, "\n%d %d moveto /av %d def ", ps_h, pos, pos); out_string(buffer); ps_v = pos; return(1); } /* move horizontally, relatively */ ps_rel_h(shift) int shift; { char buffer[max_str]; if (ps_started_show) { send_string(string_buffer, str_index); ps_started_show = 0; str_index = 0; if (shift == 1) out_string("rp "); else if (shift == -1 ) out_string("rm "); else { sprintf(buffer, "s %d 0 rmoveto ", shift); out_string(buffer); } } else { sprintf(buffer, "%d 0 rmoveto ", shift); out_string(buffer); } return(1); } /* set a char */ ps_s_char(char_no) int char_no; { if (!ps_started_show) { str_index = 0; ps_started_show = 1; } if (str_index < max_str) string_buffer[str_index++] = char_no; return(1); } /* flush the string buffer */ static flush_string ( ) { ps_started_show = 0; if (str_index > 0) { send_string(string_buffer, str_index); str_index = 0; out_string("s "); } return(1); } /* start a postscript font definition */ ps_st_font(font_no, finfo) int font_no; struct font *finfo; { #define wanted_char(flag, char_no) \ ((flag[char_no / word_size] >> (char_no % word_size)) & 1) char buffer[max_str]; int i = 0, j = 0; if (!def_dofont) l_dofont(); /* load the dofont definition */ out_ln("dofont "); sprintf(buffer, "/imagemaskmatrix [%d 0 0 -%d 0 0] def ", ps_xscale, ps_yscale); out_ln(buffer); sprintf(buffer, "/FontMatrix [%d 0 0 %d 0 0] def Encoding ", ps_xscale, ps_yscale); out_ln(buffer); for (i=0; iwant_flag, i)) { sprintf(buffer, "dup %d /%s put ", i, ps_name[i]); out_string(buffer); ++j; } } sprintf(buffer, "pop /CharData %d dict def CharData begin ", max_chars); out_ln(buffer); return(1); } /* make a postscript character definition */ ps_dev_char(in_ptr, w_bytes, height, width, char_no, tfm_width, pxl_width, char_array, bytes_found, h_dots, v_dots) unsigned char *in_ptr; char *char_array; int w_bytes, height, char_no, width, tfm_width,pxl_width, *bytes_found, h_dots, v_dots; { int i, no_bytes = 0; unsigned char *cur_ptr; if ( (height == 0) || (width == 0) ) /* invisible, or illegal */ return(2); if (ng_fix) height += ng_skip; sprintf(char_array, "/%s[%d %d %d %d %d %d %d %d %d <", ps_name[char_no], pxl_width, h_dots, - (v_dots + height), width + h_dots, -v_dots, width, height, -h_dots, -v_dots); if (ng_fix) height -= ng_skip; no_bytes += strlen(char_array); cur_ptr = (unsigned char *) in_ptr; if (ng_fix) for (i = 0; i> 4) & 15]; char_array[no_bytes++] = hex_char[*cur_ptr & 15]; ++cur_ptr; } sprintf(char_array + no_bytes, ">]\ndef "); no_bytes += 6; *bytes_found += height * w_bytes; return(no_bytes); } /* suspend things gracefully */ ps_suspend() { if (ps_started_show) flush_string(); out_string(" save "); return(1); } /* and start things up again */ ps_restart() { out_string(" restore "); return(1); } /* load the dofont defintion */ static l_dofont() { out_ln("/dofont {"); out_ln("9 dict dup begin % allocate dictionary"); fb(); out_ln("/FontType 3 def % user defined font"); fb(); out_ln("/FontBBox [0 0 0 0] def % no assumptions yet"); fb(); out_ln("/Encoding 128 array def"); out_ln("0 1 127 {Encoding exch /.notdef put} for"); fb(); out_ln("/BuildChar"); out_ln("{ 0 begin"); out_ln(" /char exch def"); out_ln(" /fontdict exch def"); out_ln(" /charname fontdict /Encoding get char get def"); out_ln(" "); out_ln(" /charinfo fontdict /CharData get charname"); out_ln(" get def"); out_ln(" /wx charinfo 0 get def"); out_ln(" /charbbox charinfo 1 4 getinterval def"); out_ln(" wx 0 charbbox aload pop setcachedevice "); out_ln(" charinfo 5 get charinfo 6 get true"); fb(); out_ln(" fontdict /imagemaskmatrix get"); out_ln(" dup 4 charinfo 7 get put"); out_ln(" dup 5 charinfo 8 get put"); fb(); out_ln(" charinfo 9 1 getinterval cvx"); out_ln(" imagemask"); out_ln("end"); out_ln("} def"); fb(); out_ln("/BuildChar load 0 6 dict put"); out_ln("} def"); def_dofont = 1; return(1); } /* this is the routine that sets everything up */ /* the initialising routine for the postscript module */ void ps_setup(opt, dev_info, c1, c2, c3, c5, delim, mfdesc, pdesc, mfctrl, gprim, attr, escfun, extfun, ctrl, pargc, argv) struct one_opt *opt; /* the command line options, in only */ struct info_struct *dev_info; /* device info to fill out, out only */ struct mf_d_struct *c1; /* the class 1 elements, in only */ struct pic_d_struct *c2; /* the class 2 elements, in only */ struct control_struct *c3; /* the class 3 elements, in only */ struct attrib_struct *c5; /* the class 5 elements, in only */ int (*delim[])(); /* delimiter functions */ int (*mfdesc[])(); /* metafile descriptor functions */ int (*pdesc[])(); /* page descriptor functions */ int (*mfctrl[])(); /* controller functions */ int (*gprim[])(); /* graphical primitives */ int (*attr[])(); /* the attribute functions */ int (*escfun[])(); /* the escape functions */ int (*extfun[])(); /* the external functions */ int (*ctrl[])(); /* controller functions */ int *pargc; /* pointer to argc */ char **argv; /* the main argv */ { #define dev_length 20 char dev_name[dev_length + 1], buffer[dev_length + 1]; /* store the command line argument pointer */ popt = opt; /* store the device info pointer */ dptr = dev_info; /* and the cgm data strucures */ pc1 = c1; pc2 = c2; pc3 = c3; pc5 = c5; /* fill out the device info structure */ dev_info->pxl_in = 300.0; dev_info->ypxl_in = 300.0; dev_info->x_size = 8.0; dev_info->y_size = 10.9; dev_info->x_offset = 0.25; dev_info->y_offset = 0.25; dev_info->c_height = 10 * dev_info->pxl_in / 72; /* 10 pt */ dev_info->c_width = 10 * dev_info->pxl_in / 72; /* 10 pt */ dev_info->d_l_width = 3; dev_info->d_e_width = 3; dev_info->d_m_size = dev_info->c_height; /* marker size */ strcpy(dev_info->out_name, ".PS"); dev_info->capability = port_land | arb_rot | arb_trans | h_center | brk_ok | stroke_text | char_text | string_text | can_clip; dev_info->rec_size = 80; /* now fill out the function pointer arrays for CGM */ /* the delimiter functions */ delim[(int) B_Mf] = ps_begin; delim[(int) E_Mf] = ps_end; delim[(int) B_Pic_Body] = ps_bpage; delim[(int) E_Pic] = ps_epage; /* the Metafile Descriptor elements */ mfdesc[(int) MfDescrip] = ps_mfdescrip; /* the control elements */ mfctrl[(int) ClipRect] = ps_cliprect; mfctrl[(int) ClipIndic] = ps_clipindic; /* the graphical primitives */ gprim[(int) PolyLine] = ps_pline; gprim[(int) Dis_Poly] = ps_dpline; gprim[(int) PolyMarker] = ps_pmarker; gprim[(int) Text] = ps_text; gprim[(int) Rex_Text] = ps_rex_text; gprim[(int) App_Text] = ps_app_text; gprim[(int) Polygon] = ps_pgon; gprim[(int) Poly_Set] = ps_pset; gprim[(int) Cell_Array] = ps_carray; gprim[(int) Rectangle] = ps_rectangle; gprim[(int) Cgm_Circle] = ps_circle; gprim[(int) Circ_3] = ps_c3; gprim[(int) Circ_3_Close] = ps_c3_close; gprim[(int) Circ_Centre] = ps_c_centre; gprim[(int) Circ_C_Close] = ps_c_c_close; /* finish later gprim[(int) Ellipse] = ps_ellipse; gprim[(int) Ellip_Arc] = ps_ell_arc; gprim[(int) El_Arc_Close] = ps_e_a_close; */ /* the attributes */ attr[(int) CHeight] = ps_cheight; attr[(int) TAlign] = ps_t_align; /* checking for colour postscript option */ if (opt[(int) device].set) strncpy(dev_name, opt[(int) device].val.str, dev_length); dev_name[dev_length - 1] = 0; /* safety */ use_colours = (dev_name[2] == 'c') || (dev_name[2] == 'C'); state_level = -1; /* just starting */ return; } /* the following function optimises our TeX implementation and is unnecessary for CGM support only */ void ps_gtex_setup(opt, gtex_calls) /* function pointers, out only */ struct one_opt *opt; /* the command line options, in only */ int (*gtex_calls[])(); { /* assign TeX-specific functions */ gtex_calls[(int) S_Font] = ps_s_font; gtex_calls[(int) Suspend] = ps_suspend; gtex_calls[(int) Restart] = ps_restart; gtex_calls[(int) S_Rule] = ps_s_rule; gtex_calls[(int) S_Abs_Both] = ps_abs_both; gtex_calls[(int) S_Abs_H] = ps_abs_h; gtex_calls[(int) S_Abs_V] = ps_abs_v; gtex_calls[(int) M_Rel_H] = ps_rel_h; gtex_calls[(int) S_Char] = ps_s_char; gtex_calls[(int) St_Font] = ps_st_font; gtex_calls[(int) M_Dev_Char] = ps_dev_char; gtex_calls[(int) E_Font] = ps_e_font; return; }