rsalz@uunet.UU.NET (Rich Salz) (10/07/87)
Submitted-by: steinmetz!sbcs!nyfca1!chan (Douglas Chan) Posting-number: Volume 11, Issue 101 Archive-name: graphedit/part05 # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Contents: display.c ps.c pic.c plot.c echo x - display.c sed 's/^@//' > "display.c" <<'@//E*O*F display.c//' static char SccsId[] = "@(#)display.c 1.1 6/8/87 Copyright 1987 SBCS-chan"; /***************************************************************************** (c) Copyright 1987 Lap-Tak Chan Computer Science Department State University of New York at Stony Brook Stony Brook, NY 11794 This software and its documentation may be used, copied, and distributed, provided that this legend appear in all copies and that it is not copied or distributed for a profit. No representations is made about the suitability of this software for any purpose. It is provided "as is" with no support and no express or implied warranty. *****************************************************************************/ /***************************************************************************** Display List ============ The display list is used to maintain the data structure used to store the segments internally. Each segment has a display list, which consists of its segment number, attributes, and a instruction list. Each instruction is composed of an instruction with two arguments. The display list is initialized with ge_init_display. A segment is opened with ge_new_segment. Output primitives are drawn with ge_graph which will appending them to the instruction list of the segment. ge_delete_segment will delete the segment and free the memory allocated to the segment to the internal free lists. ge_display_list will return a pointer to the display list of a segment. The display list maintains a list of segments, which is a simple linked list of segment blocks taken from a fixed array. Unused segment blocks in the array are linked on a free list. Each segment block stores a pointer to the node of the object, the current position of the segment and a instruction list of the segment. The instruction list is stored as a circular queue of display items. Each display item consists of a display instruction and a coordinate. A hash table should be used to reference the segments instead of a search on the segment list. *****************************************************************************/ #include "display.h" #define GE_DITEM_SIZE 50 /* number of items to obtain from calloc when free list is empty */ struct list ge_open[GE_OPENMAX+1]; /* array of display lists */ static struct list_item *ge_dfree=0; /* free list for display instructions */ static int ge_dsfree; /* free list for segment blocks */ int ge_seglist; /* list of segment blocks */ /* instruction to indicate close of segment */ static struct list_item closeinstr; /***************************************************************************** Display items have to be allocated and freed frequently. The C allocation routines alloc, calloc and free is not efficient. To increase the efficiency, a list of free display items is maintained. Requests for display item are allocated from the free list. When the free list is empty, a number of display items is obtained with calloc and linked to the free list. ge_get_item will return a display item which is not in use. It obtains the display item from the free list. When the free list is empty, it get a number of display item from the system with calloc and link them to the free list. *****************************************************************************/ struct list_item *ge_get_item() { struct list_item *tmp; int count; /* free list is empty */ if ( ! ge_dfree ) { /* get space for list items */ tmp = (struct list_item *)calloc(GE_DITEM_SIZE,sizeof(struct list_item)); /* link blocks on free list */ for(count=1;count < GE_DITEM_SIZE;count++) tmp[count].next = &(tmp[count-1]); ge_dfree = &(tmp[GE_DITEM_SIZE-1]); } /* get item from free list */ tmp=ge_dfree; ge_dfree=tmp->next; return (tmp); } /***************************************************************************** ge_free_item will release a display item to the free list. *****************************************************************************/ ge_free_item(ptr) struct list_item *ptr; { ptr->next = ge_dfree; ge_dfree = ptr; } /***************************************************************************** ge_init_display initializes the display list. It links the segment blocks on the array to form a free list. *****************************************************************************/ ge_init_display() { int i; /* link segment blocks to form free list */ for(i=0;i<GE_OPENMAX-1;i++) ge_open[i].next = i + 1; ge_dsfree=1; /* empty segment list */ ge_seglist=0; closeinstr.instr=GE_CLOSE; } /***************************************************************************** ge_index searches for the display list of a segment. input segno : segment number output ge_index returns pointer to display list if found *****************************************************************************/ int ge_index(segno) int segno; { int i; for ( i=ge_seglist; i && ge_open[i].segno != segno; i=ge_open[i].next ); if ( ge_open[i].segno == segno ){ return (i); } else { return(-1); } } /***************************************************************************** ge_new_segment is called to create a new segment. input tree : pointer to node of object *****************************************************************************/ ge_new_segment(segno) int segno; { int pos; /* remove segment from free list */ pos=ge_dsfree; ge_dsfree=ge_open[pos].next; /* add segment to segment list */ ge_open[pos].next = ge_seglist; ge_seglist = pos; /* initialize content of list */ ge_open[pos].d_list = 0; ge_open[pos].segno = segno; } /***************************************************************************** ge_graph will add an output primitive to the display list of a segment. input segno : segment number instr : display instruction of output primitive (polygon, line, move, etc) x,y : coordinate of display *****************************************************************************/ ge_graph(segno,instr,x,y) int segno, instr; float x,y; { int pos; struct list_item *ptr; /* get display list of segment */ if ( (pos = ge_index(segno))>=0 ) { /* get display item */ ptr = ge_get_item(); /* store instruction and coordinate in item */ ptr->instr=instr; ptr->x=x; ptr->y=y; /* add instruction to display list */ if ( ge_open[pos].d_list ) { ptr->next = ge_open[pos].d_list->next; ge_open[pos].d_list->next = ptr; } else ptr->next = ptr; ge_open[pos].d_list = ptr; } } /* ge_graph */ /***************************************************************************** ge_delete_segment is called to delete a segment from the display list. input segno : segment number *****************************************************************************/ ge_delete_segment(segno) int segno; { int pos,tmpseg; struct list_item *ptr,*tmp; /* search for display list of segment */ if ( pos=ge_index(segno) ) { /* delete segment block from list of segments */ if ( pos == ge_seglist ) { /* segment at beginning of list */ ge_seglist = ge_open[pos].next; } else { for (tmpseg=ge_seglist; (ge_open[tmpseg].next != pos); tmpseg=ge_open[tmpseg].next) ; ge_open[tmpseg].next = ge_open[pos].next; } /* free display list of segment */ if ( ge_open[pos].d_list ) { /* make the display list a simple linked list */ ptr=ge_open[pos].d_list->next; ge_open[pos].d_list->next = 0; /* free items along the list */ for ( ; ptr; ptr=tmp ) { tmp=ptr->next; ge_free_item(ptr); } } /* if */ /* add segment block to free list */ ge_open[pos].next = ge_dsfree; ge_dsfree = pos; } /* if */ } /* ge_delete_segment */ /***************************************************************************** ge_display_list will get the display list of a segment. Input segno - number of segment Output Return pointer to display list of segment, 0 if segment is not found. *****************************************************************************/ struct list *ge_display_list(segno) int segno; { int pos; if ((pos=ge_index(segno)) >= 0) { return(&(ge_open[pos])); } else return(0); } /* ge_display_list */ @//E*O*F display.c// chmod u=r,g=r,o=r display.c echo x - ps.c sed 's/^@//' > "ps.c" <<'@//E*O*F ps.c//' static char SccsId[] = "@(#)ps.c 1.2 6/8/87 Copyright 1987 SBCS-chan"; /***************************************************************************** (c) Copyright 1987 Lap-Tak Chan Computer Science Department State University of New York at Stony Brook Stony Brook, NY 11794 This software and its documentation may be used, copied, and distributed, provided that this legend appear in all copies and that it is not copied or distributed for a profit. No representations is made about the suitability of this software for any purpose. It is provided "as is" with no support and no express or implied warranty. *****************************************************************************/ /***************************************************************************** PostScript Interface ==================== This file contains the PostScript interface routines of graphedit which can write the display lists in PostScript and rebuild the display lists from the written PostScript. *****************************************************************************/ #include "display.h" #include <usercore.h> #include <stdio.h> #include <string.h> #define DEGPERRAD 180./PI #define PSHEADER "ps.head" /* name of the header file */ static FILE *writefile; static char pshead[80]; struct list *ge_display_list(); /***************************************************************************** ps_init do the necessary initialization before writing segments to the output file. It will copy the header file as the beginning of the output file, and define how the graphedit coordinate system will be put on 8.5 x 11 paper according to save_attr. *****************************************************************************/ ps_init() { float sx, sy, tx, ty; FILE *header; char buf[512]; extern struct saveattr save_attr; float width, height; /* copy header to output file */ if ( ! (header=fopen(pshead, "r"))) { fprintf(writefile, "%% Header file %s should be included here\n",pshead); } else { /* copy the header file to the output file */ while ( fgets(buf, 512, header) ) { fputs(buf, writefile); } /* close the header file */ fclose(header); } if ( save_attr.rotate ) { /* rotate picture */ width = save_attr.height; height = save_attr.width; /* determine the scale, height and width of picture */ sx=save_attr.height*7.2/GE_WIN_X; sy=save_attr.width*7.2/GE_WIN_Y; switch ( save_attr.fix ) { case 1: sx=sy; width=GE_WIN_X/GE_WIN_Y*height; break; case 2: sy=sx; height=GE_WIN_Y/GE_WIN_X*width; break; } /* switch */ /* determine the offset necessary */ if ( save_attr.center ) { tx = (55./width-0.5)*GE_WIN_X; ty = (-42.5/height-0.5)*GE_WIN_Y; } else { tx = ((110.-save_attr.offb)/width-1.)*GE_WIN_X; ty = ((-save_attr.offa)/height-1.)*GE_WIN_Y; } fprintf(writefile, "90. rotate "); } else { width = save_attr.width; height = save_attr.height; /* determine the scale, height and width of the picture */ sx=save_attr.width*7.2/GE_WIN_X; sy=save_attr.height*7.2/GE_WIN_Y; switch (save_attr.fix) { case 1: sy=sx; height=GE_WIN_Y/GE_WIN_X*width; break; case 2: sx=sy; width=GE_WIN_X/GE_WIN_Y*height; break; } /* switch */ /* determine the offset necessary */ if ( save_attr.center ) { tx = (42.5/width-0.5)*GE_WIN_X; ty = (55./height-0.5)*GE_WIN_Y; } else { tx = save_attr.offa/width*GE_WIN_X; ty = ((110.-save_attr.offb)/height-1.)*GE_WIN_Y; } } /* define the graphedit coordinate system */ fprintf(writefile, "%f %f scale %f %f translate\n", sx, sy, tx,ty); /* header which will be used to find the real beginning of the saved segments */ fprintf(writefile, "%% graphedit.save v%s\n", GE_VERSION); } /* ps_init */ /***************************************************************************** ps_done just do whatever necessary after saving all these segments. *****************************************************************************/ ps_done() { FILE *tail; char buf[512]; fprintf(writefile, "GE_TERM\n"); } /* ps_done */ /***************************************************************************** ps_setfont will generate the change of font in PostScript. *****************************************************************************/ ps_setfont(font) int font; { fprintf(writefile, "%d GE_SET_FONT\n", font); } /* ps_setfont */ /***************************************************************************** ps_setlinestyle will generate the change of line style in PostScript. *****************************************************************************/ ps_setlinestyle(type) int type; { fprintf(writefile, "%d GE_SET_LINESTYLE\n", type); } /* ps_setlinestyle */ /***************************************************************************** ps_draw_seg will draw a segment in PostScript according to its display list. Input list - display list of segment *****************************************************************************/ ps_draw_seg(list) struct list *list; { struct list_item *ptr; static struct list_item closeinstr={GE_CLOSE, 0., 0., NULL}; /* abort if the display list of the segment is empty */ if ( !(ptr=list->d_list) ) return; /* set the transformation of the segment */ fprintf(writefile, "GE_NEW_SEG\n%f %f GE_TRANSLATE\n%f GE_ROTATE\n%f %f GE_SCALE\n", list->attr.tx, list->attr.ty, list->attr.ang * DEGPERRAD, list->attr.sx, list->attr.sy); /* set the attribtes of the segment */ fprintf(writefile, "%d GE_SET_COLOR\n", list->attr.color); fprintf(writefile, "%d GE_SET_LINEWIDTH\n", list->attr.linewidth); fprintf(writefile, "%d GE_SET_CHARSIZE\n", list->attr.charsize); ps_setlinestyle(list->attr.linestyle); ps_setfont(list->attr.font); /* scan the display list and execute the instructions to draw the primitives */ ptr=ptr->next; do { ps_exec(ptr); ptr=ptr->next; } while ( ptr != list->d_list->next ); /* close the segment */ ps_exec(&closeinstr); fprintf(writefile, "GE_END_SEG\n"); } /* ps_draw_seg */ /***************************************************************************** ps_exec will execute an instruction and draw it in PostScript. Input ptr - pointer to instruction *****************************************************************************/ ps_exec(ptr) struct list_item *ptr; { static float xbuff[512], ybuff[512]; static int lastinstr=0; static int n=0; int i; /* execute last polyline/polygon instruction if instruction indicates end of the last instruction */ if ( lastinstr && ptr->instr != GE_CONT ) { switch ( lastinstr ) { case GE_POLYLINE : fprintf(writefile, "%.4f %.4f GE_POLYLINE\n", xbuff[0], ybuff[0]); for (i=1; i<n; i++) { fprintf(writefile, "%.4f %.4f GE_CONT\n", xbuff[i], ybuff[i]); } fprintf(writefile, "GE_END\n"); break; case GE_POLYGON: fprintf(writefile, "%.4f %.4f GE_POLYGON\n", xbuff[0], ybuff[0]); for (i=1; i<n; i++) { fprintf(writefile, "%.4f %.4f GE_CONT\n", xbuff[i], ybuff[i]); } fprintf(writefile, "GE_END\n"); break; default: ; } lastinstr = n = 0; } /* execute new instruction */ switch (ptr->instr) { /* instructions with single coordinate */ case GE_MOVE: fprintf(writefile, "%.4f %.4f GE_MOVE\n", ptr->x, ptr->y); break; case GE_LINE: fprintf(writefile, "%.4f %.4f GE_LINE\n", ptr->x, ptr->y); break; case GE_ELLIPSE: fprintf(writefile, "%.4f %.4f GE_ELLIPSE\n", ptr->x, ptr->y); break; case GE_ARC: fprintf(writefile, "%.4f %.4f GE_ARC\n", ptr->x, ptr->y); break; case GE_ARCEXT: fprintf(writefile, "%.4f GE_ARCEXT\n", ptr->x); break; case GE_CIRCLE: fprintf(writefile, "%.4f GE_CIRCLE\n", ptr->x); break; /* instruction with two or more coordinates */ case GE_POLYLINE: case GE_POLYGON: /* store instruction */ lastinstr=ptr->instr; case GE_CONT: /* save coordinate of polyline/polygon */ xbuff[n] = ptr->x; ybuff[n++] = ptr->y; break; case GE_TEXT: fprintf(writefile, "(%s) GE_TEXT\n", (char *)((int)ptr->x)); break; case GE_SETCOLOR: fprintf(writefile, "%d GE_SET_COLOR\n", (int)ptr->x); break; case GE_SETTYPELINE: fprintf(writefile, "%d GE_SET_LINESTYLE\n", (int)ptr->x); break; case GE_SETLINEWIDTH: fprintf(writefile, "%d GE_SET_LINEWIDTH\n", (int)ptr->x); break; case GE_SETFONT: fprintf(writefile, "%d GE_SET_FONT\n", (int)ptr->x); break; case GE_SETCHARSIZE: fprintf(writefile, "%d GE_SET_CHARSIZE\n", (int)ptr->x); break; case GE_FILL: fprintf(writefile, "%d GE_FILL\n", (int)ptr->x); break; case GE_CLOSE: /* do nothing */ break; default : /* check that all instructions are properly handled */ fprintf(stderr, "Internal Error-Action for instruction %d missing.\n", ptr->instr); break; } /* switch */ } /* ps_exec */ /***************************************************************************** ps_write will write the picture as a complete PostScrip program in the already opened outfile. It will copy a header file to outfile, scan the segment list and write every segment (except the sample segments) in PostScript. The directory where the header file is located will be defined by the environment GELIB. If GELIB is not defined, GE_DEFAULTLIB will be used. Input outfile - opened output stream to write on *****************************************************************************/ ps_write(outfile) FILE *outfile; { extern int ge_seglist; extern struct list ge_open[]; int i; char *libdir; /* save it so that ps_exec will be able to access it */ writefile=outfile; /* generate the name for the header file */ if ( !(libdir = (char *)getenv("GELIB")) ) libdir=GE_DEFAULTLIB; (void)strcpy(pshead,libdir); (void)strcat(pshead,"/"); (void)strcat(pshead,PSHEADER); /* initialize */ ps_init(); /* scan the segment list and write every user segment */ for ( i=ge_seglist; i; i=ge_open[i].next ) { if ( ge_open[i].segno >= GE_MIN_SEG && (! ge_open[i].attr.deleted) ) { ps_draw_seg(&(ge_open[i])); } /* if */ } /* for */ ps_done(); } /* ps_write */ /***************************************************************************** ps_write_seg will write one segment in PostScript to outfile. The output file is not a complete PostScrip program and thus cannot be printed. Input outfile - opened output stream to write on segno - segment to write *****************************************************************************/ ps_write_seg(outfile, segno) FILE *outfile; int segno; { struct list *list; writefile=outfile; /* get display list of segment */ list=ge_display_list(segno); /* write header */ fprintf(writefile, "%% graphedit.save v%s\n", GE_VERSION); /* write segment in PostScript */ ps_draw_seg(list); } /* ps_write_seg */ /***************************************************************************** ps_load will rebuild the display list of the segments written in infile. It will scan the file for the mark of the beginning of data. Then it will read and process each line until the mark for the end of data is encountered. Input infile - opened input stread to read from *****************************************************************************/ ps_load(infile) FILE *infile; { char inbuf[512]; /* skip header until mark of beginning of data */ for (; (fgets(inbuf,512,infile)) && (strncmp(inbuf, "% graphedit.save",16));); if ( inbuf[0] != '%' ) { /* abort if header cannot be found */ return(1); } /* read and process each line in infile until the instruction GE_TERM marking the end of the file is encountered */ while ( (fgets(inbuf,512,infile) && (strcmp(inbuf,"GE_TERM")) )) { /* process line */ ps_read(inbuf); } /* while */ return(0); } /* ps_load */ /***************************************************************************** ps_cmd2instr will return the instruction for a command in the PostScript input. Input command - command in PostScript Output Return internal instruction corresponding to the command. *****************************************************************************/ ps_cmd2instr(command) char *command; { struct cmdinstr { char *cmd; int instr; } ; /* a map of command to instruction */ static struct cmdinstr cmdinstr[] = { { "GE_SET_FONT", GE_SETFONT }, { "GE_SET_LINESTYLE", GE_SETTYPELINE }, { "GE_SET_COLOR", GE_SETCOLOR }, { "GE_SET_LINEWIDTH", GE_SETLINEWIDTH}, { "GE_NEW_SEG", GE_NEW }, { "GE_END_SEG", GE_CLOSE }, { "GE_TRANSLATE", GE_TRANSLATE }, { "GE_ROTATE", GE_ROTATE }, { "GE_SCALE", GE_SCALE }, { "GE_MOVE", GE_MOVE }, { "GE_LINE", GE_LINE }, { "GE_POLYLINE", GE_POLYLINE }, { "GE_POLYGON", GE_POLYGON }, { "GE_TEXT", GE_TEXT }, { "GE_CIRCLE", GE_CIRCLE }, { "GE_ELLIPSE", GE_ELLIPSE }, { "GE_CONT", GE_CONT }, { "GE_SET_CHARSIZE", GE_SETCHARSIZE }, { "GE_FILL", GE_FILL }, { "GE_ARC", GE_ARC }, { "GE_ARCEXT", GE_ARCEXT}, { "", 0 } }; int i; /* scan for the location of the command in the map */ for ( i=0; cmdinstr[i].instr && strcmp(cmdinstr[i].cmd, command); i++ ); /* return instruction for command */ return(cmdinstr[i].instr); } /* ps_cmd2instr */ /***************************************************************************** ps_read will process a command in a line of input. Each command may be composed of 1 to 3 fields. The last field corresponds to an attribute or instruction while the others are parameters to the commands. Input inbuf - input buffer containing a line of input from the input file *****************************************************************************/ ps_read(inbuf) char *inbuf; { static int ps_segno; static struct list *seginfo; char buf1[80], buf2[80], buf3[80], *command; int fields, instr, inexec; float x,y; /* handle GE_TEXT */ if ( inbuf[0] == '(' ) { char *ptr; /* get the end of the text string */ if ( ptr=(char *)rindex(inbuf,')') ) { *ptr='\0'; strcpy((ptr=(char *)malloc(strlen(inbuf))),&(inbuf[1])); ge_graph(ps_segno, GE_TEXT, (float)((int)ptr),0.); } return; } /* separate the command into up to three fields */ if ( !(fields=sscanf(inbuf, "%s%s%s", buf1, buf2, buf3)) ) { return; } /* command is the last field */ switch ( fields ) { case 1: command=buf1; break; case 2: command=buf2; break; case 3: command=buf3; break; default: break; } /* switch */ /* get instruction corresponding to command */ if ( instr=ps_cmd2instr(command) ) { switch ( instr ) { /* instructions with two parameters */ case GE_MOVE: case GE_LINE: case GE_POLYLINE: case GE_POLYGON: case GE_CONT: case GE_ELLIPSE: case GE_ARC: sscanf(buf1,"%f",&x); sscanf(buf2,"%f",&y); ge_graph(ps_segno, instr, x, y); inexec=1; break; /* instructions with one parameter */ case GE_CIRCLE: case GE_ARCEXT: case GE_FILL: sscanf(buf1, "%f",&x); ge_graph(ps_segno, instr, x, 0.); inexec=1; break; /* initial attributes or change of attributes */ case GE_SETCOLOR: case GE_SETTYPELINE: case GE_SETLINEWIDTH: case GE_SETFONT: case GE_SETCHARSIZE: sscanf(buf1,"%f",&x); if ( ! inexec ) /* set initial attribues */ switch (instr) { case GE_SETCOLOR: seginfo->attr.color = (int)x; break; case GE_SETTYPELINE: seginfo->attr.linestyle = (int)x; break; case GE_SETLINEWIDTH: seginfo->attr.linewidth = (int)x; break; case GE_SETFONT: seginfo->attr.font = (int) x; break; case GE_SETCHARSIZE: seginfo->attr.charsize = (int) x; } else { /* change attribute */ ge_graph(ps_segno, instr, x, 0.); } break; /* trnasformations */ case GE_TRANSLATE: sscanf(buf1,"%f",&(seginfo->attr.tx)); sscanf(buf2,"%f",&(seginfo->attr.ty)); break; case GE_ROTATE: sscanf(buf1,"%f",&(seginfo->attr.ang)); seginfo->attr.ang /= DEGPERRAD; break; case GE_SCALE: sscanf(buf1,"%f",&(seginfo->attr.sx)); sscanf(buf2,"%f",&(seginfo->attr.sy)); break; /* start new segment */ case GE_NEW: /* create new segment */ ps_segno=make_new_seg(0); seginfo=(struct list *)ge_display_list(ps_segno); inexec=0; break; /* close segment */ case GE_CLOSE: seginfo=0; /* draw segment */ ge_draw(ps_segno); break; default: /* check that all instructions are properly handled */ fprintf(stderr, "Internal Error-Action for instruction %d missing.\n", instr); break; } /* switch */ } /* if */ } /* ps_read */ @//E*O*F ps.c// chmod u=r,g=r,o=r ps.c echo x - pic.c sed 's/^@//' > "pic.c" <<'@//E*O*F pic.c//' static char SccsId[] = "@(#)pic.c 1.1 6/8/87 Copyright 1987 SBCS-chan"; /***************************************************************************** (c) Copyright 1987 Lap-Tak Chan Computer Science Department State University of New York at Stony Brook Stony Brook, NY 11794 This software and its documentation may be used, copied, and distributed, provided that this legend appear in all copies and that it is not copied or distributed for a profit. No representations is made about the suitability of this software for any purpose. It is provided "as is" with no support and no express or implied warranty. *****************************************************************************/ /***************************************************************************** Pic Output ========== This file contains routines which write the diagram in format suitable as input to pic(1), which is a picture drawing preprocessor to troff. *****************************************************************************/ #include "display.h" #include <stdio.h> #include <string.h> #include <math.h> #define DEGPERRAD 180./PI static FILE *writefile; /* file to write diagram to */ struct list *ge_display_list(); static struct attr pic_attr; /* current attributes used for current segment */ static float sina, cosa; static float pic_rms; /* root mean square of x and y scale of current segment */ /* mapping of graphedit fonts to troff fonts */ static char *pic_font[]= { "R", "R", "S", "I", "B" }; /***************************************************************************** pic_init will do the necessary initialization for the writing. *****************************************************************************/ pic_init() { float sx, sy; FILE *header; char buf[512]; extern struct saveattr save_attr; /* indicate beginning of pic input */ fprintf(writefile, ".PS %.2f\n", save_attr.width/10.); /* to make pic using full graphedit coordinates */ fprintf(writefile, "move to (%.4f,%.4f)\n", GE_WIN_X, GE_WIN_Y); } /* pic_init */ /***************************************************************************** pic_done do anything necessary to clean up after the writing. *****************************************************************************/ pic_done() { FILE *tail; char buf[512]; /* indicate end of pic input */ fprintf(writefile, ".PE\n"); } /* pic_done */ /***************************************************************************** pic_xform transforms a coordinate of the current segment to the world coordiante. Input ix, iy - coordinate in space of current segment Output ox, oy - corresponding world coordinate of (ix,iy) according to transformatio of current segment. *****************************************************************************/ pic_xform(ix, iy, ox, oy) float ix, iy, *ox, *oy; { *ox = cosa * ix * pic_attr.sx - sina * iy * pic_attr.sy + pic_attr.tx; *oy = sina * ix * pic_attr.sx + cosa * iy * pic_attr.sy + pic_attr.ty; } /* pic_xform */ /***************************************************************************** pic_charsize set a new character size in pic. The actual character size is determined from the character size of the current segment, the width of the picture, and the scale of the current segment. *****************************************************************************/ pic_charsize() { float charsize; charsize = pic_attr.charsize * pic_rms * save_attr.width / 42.; return((int)charsize); } /* pic_charsize */ /***************************************************************************** pic_linestyle set a new line style according to the line style of the current segment. *****************************************************************************/ pic_linestyle() { /* mapping of graphedit line style to pic line style */ static char *pic_style[] = { 0, "dotted 3", "dashed 6", "dashed 2" }; if ( pic_style[pic_attr.linestyle] ) fprintf(writefile, " %s", pic_style[pic_attr.linestyle]); } /* pic_linestyle */ /***************************************************************************** pic_linewidth determine the line width in pic according to the line width of the current segment. Output Return the line width determined. *****************************************************************************/ pic_linewidth() { /* this formula may need adjustment */ return ((pic_attr.linewidth)*12+2); } /* pic_linewidth */ /* set the line width in pic */ #define pic_set_linewidth() fprintf(writefile,".ps %d\n",\ pic_linewidth()) /***************************************************************************** pic_sim_ellipse will simulate the drawing of an ellipse by dividing the ellipse into a number of segments and draw each segment with an arc. This is necessary because pic cannot draw rotated ellipse. Coordinates of points on the ellipse are determined by transformation of points on a circle at (0,0) with radius 1. Input currx, curry - current world cordinate a,b - half of width and height of ellipse *****************************************************************************/ pic_sim_ellipse(currx, curry, a, b) float currx, curry, a, b; { #define PLT_CIRINT 20 /* number of segments to divide into */ #define PLT_CIRSIZE PLT_CIRINT*2+1 /* size of array necessary */ static int pic_mdl_make = 0; static float pic_cir_x[PLT_CIRSIZE]; static float pic_cir_y[PLT_CIRSIZE]; extern float ge_radius(); /* from misc.c */ float radius; /* radius of arc */ float x1, y1, x2, y2, x3, y3; /* start, mid and end points of arc */ int i; /* put the coordinates of points on a circle with center at (0,0) and radius 1 in pic_cir_x and pic_cir_y at the first time */ if ( ! pic_mdl_make ) { int count; float intv; intv = PI / PLT_CIRINT; for (count=0; count < PLT_CIRSIZE; count ++ ) { pic_cir_x[count]=cos(intv*count); pic_cir_y[count]=sin(intv*count); } /* for */ pic_mdl_make = 1; } /* if */ /* determine the world coordinate of the first point and move there */ pic_xform(pic_cir_x[0]*a, pic_cir_y[0]*b, &x3, &y3); fprintf(writefile, "move to (%.4f,%.4f)\n", x3+currx-pic_attr.tx, y3+curry-pic_attr.ty); /* draw the arcs */ for ( i=0; i<PLT_CIRSIZE-1; i+=2 ) { /* make the end point of the last arc the start point */ x1=x3; y1=y3; /* determine the world coordinate of the mid point and the end point */ pic_xform(pic_cir_x[i+1]*a,pic_cir_y[i+1]*b, &x2, &y2); pic_xform(pic_cir_x[i+2]*a,pic_cir_y[i+2]*b, &x3, &y3); /* determine the radius of the arc passing the start, mid and end points */ radius = ge_radius(x1,y1,x2,y2,x3,y3); /* draw the arc */ fprintf(writefile, "arc to (%.4f,%.4f) radius %.4f\n", x3+currx-pic_attr.tx, y3+curry-pic_attr.ty, radius); } /* draw ellipse */ } /* pic_sim_ellipse */ /***************************************************************************** pic_sim_arc will simulate an arc which is not a real arc after transformation of the current segment with a number of small arcs. Input currx, curry - center of arc in world coordinate ang1 - start angle in radian, 0 <= ang1 <= 2*PI ang2 - end angle in radian, 0 <= ang2 < = 2*PI arcradius - radius of arc *****************************************************************************/ pic_sim_arc(currx, curry, ang1, ang2, arcradius) float currx, curry, ang1, ang2, arcradius; { /* draw arc from smalll arcs */ float intv, radius; extern float ge_radius(); int count; float x1,y1,x2,y2,x3,y3,ang; /* ensure ang1 < ang2 */ if ( ang1 > ang2 ) ang1 -= 2*PI; /* determine number of segmnets to divide into with a minimum of 3 */ intv = PI / PLT_CIRINT; count = (int)((ang2-ang1)/(2*intv)); if ( count < 3 ) count = 3; intv = (ang2-ang1)/(count*2); /* determine the world coordinate of the first point and move there */ pic_xform(cos(ang1)*radius,sin(ang1)*arcradius,&x3,&y3); fprintf(writefile, "move to (%.4f,%.4f)\n", x3+currx-pic_attr.tx,y3+curry-pic_attr.ty); /* draw the arcs */ for ( ang = ang1; ang< (ang2-2*intv); ang += 2*intv) { /* make the end point of the last arc the start point */ x1=x3; y1=y3; /* determine the world coordinate of the mid point and the end point */ pic_xform(cos(ang+intv)*arcradius, sin(ang+intv)*arcradius, &x2, &y2); pic_xform(cos(ang+2*intv)*arcradius, sin(ang+2*intv)*arcradius, &x3, &y3); /* determine the radius of the arc passing the start, mid and end point */ radius=ge_radius(x1,y1,x2,y2,x3,y3); /* draw the arc */ fprintf(writefile, "arc to (%.4f,%.4f) radius %.4f\n", x3+currx-pic_attr.tx, y3+curry-pic_attr.ty, radius); } /* for */ } /* draw arcs */ /***************************************************************************** plt_exec will execute an instruction. Input ptr - pointer to instruction *****************************************************************************/ pic_exec(ptr) struct list_item *ptr; { static float xbuff[512], ybuff[512]; static int lastinstr=0; static int n=0; /* number of points in polygon/polyline */ static float currx, curry; /* current point */ int i; /* execute last polyline/polygon instruction if instruction indicates end of the last instruction */ if ( lastinstr && ptr->instr != GE_CONT ) { switch ( lastinstr ) { case GE_POLYLINE : /* draw polyline */ for (i=0; i<n; i++) { fprintf(writefile, "line to (%.4f,%.4f)", xbuff[i], ybuff[i]); pic_linestyle(); /* specify line style */ fprintf(writefile, "\n"); } /* for */ /* move to new current point */ currx = xbuff[n-1]; curry = ybuff[n-1]; break; case GE_POLYGON: /* draw polygon */ fprintf(writefile, "move to (%.4f,%.4f)\n", xbuff[0], ybuff[0]); for (i=1; i<n; i++) { fprintf(writefile, "line to (%.4f,%.4f)", xbuff[i], ybuff[i]); pic_linestyle(); /* specify line style */ fprintf(writefile, "\n"); } /* for */ /* draw last line */ fprintf(writefile, "line to (%.4f,%.4f)", xbuff[0], ybuff[0]); pic_linestyle(); fprintf(writefile, "\n"); /* update current position */ currx = xbuff[0]; curry = ybuff[0]; break; default: ; } lastinstr = n = 0; } /* execute new instruction */ switch (ptr->instr) { /* instructions with single coordinate */ case GE_MOVE: /* move */ pic_xform(ptr->x, ptr->y, &currx, &curry); fprintf(writefile, "move to (%.4f,%.4f)\n", currx, curry); break; case GE_LINE: /* line */ pic_xform(ptr->x, ptr->y, &currx, &curry); fprintf(writefile, "line to (%.4f,%.4f)", currx, curry); pic_linestyle(); /* specify line style */ fprintf(writefile, "\n"); break; case GE_CIRCLE: { float radius; if ( pic_attr.sx == pic_attr.sy ) { /* draw a circle if it is a circle after transformation */ fprintf(writefile, "circle radius %.4f at (%.4f,%.4f)\n", ptr->x*pic_attr.sx, currx, curry); } else { if ( pic_attr.ang == 0. ) { /* draw ellipse if rotation is 0 */ fprintf(writefile, "ellipse at (%.4f, %.4f) ht %.4f wid %.4f\n", currx, curry, ptr->x*pic_attr.sy*2, ptr->x*pic_attr.sx*2); } else { /* simulate the ellipse */ pic_sim_ellipse(currx,curry,ptr->x,ptr->x); } } } break; case GE_ELLIPSE: { float radius; if ( pic_attr.ang == 0. ) { /* draw ellipse if there is no rotation */ fprintf(writefile, "ellipse at (%.4f, %.4f) ht %.4f wid %.4f\n", currx, curry, ptr->y*pic_attr.sy*2, ptr->x*pic_attr.sx*2); } else { /* simulate the ellipse */ pic_sim_ellipse(currx,curry,ptr->x,ptr->y); } } break; case GE_ARC: case GE_ARCEXT: { static float ang1, ang2; if ( ptr->instr == GE_ARC ) { ang1 = ptr->x; ang2 = ptr->y; } else { if ( pic_attr.sx == pic_attr.sy ) { /* draw arc */ float x1,y1,x2,y2; pic_xform(cos(ang1)*ptr->x,sin(ang1)*ptr->x,&x1,&y1); pic_xform(cos(ang2)*ptr->x,sin(ang2)*ptr->x,&x2,&y2); fprintf(writefile, "arc from (%.4f,%.4f) to (%.4f,%.4f) radius %.4f\n", x1+currx-pic_attr.tx,y1+curry-pic_attr.ty, x2+currx-pic_attr.tx,y2+curry-pic_attr.ty, ptr->x*pic_attr.sx); } else { /* simulate the arc */ pic_sim_arc(currx,curry,ang1,ang2,ptr->x); } } } /* GE_ARC, GE_ARCEXT */ break; /* instruction with two or more coordinates */ case GE_POLYLINE: case GE_POLYGON: lastinstr=ptr->instr; /* store instruction */ case GE_CONT: /* save coordinate of polyline/polygon */ pic_xform(ptr->x, ptr->y, &xbuff[n], &ybuff[n]); n++; break; case GE_TEXT: /* draw text */ fprintf(writefile, ".ft %s\n.ps %d\n\"%s\" ljust at (%.4f,%.4f)\n.ps %d\n", pic_font[pic_attr.font], pic_charsize(), (char *)((int)ptr->x), currx, curry, pic_linewidth()); break; case GE_SETTYPELINE: /* update line style */ pic_attr.linestyle = (int)ptr->x; break; case GE_SETLINEWIDTH: /* update line width */ pic_attr.linewidth = (int)ptr->x; pic_set_linewidth(); break; case GE_SETFONT: /* update font */ pic_attr.font = (int)ptr->x; break; case GE_SETCHARSIZE: /* update character size */ pic_attr.charsize = (int)ptr->x; break; /* ignore these instructions */ case GE_SETCOLOR: case GE_FILL: case GE_CLOSE: break; /* check whether all insturctions are properly handled */ default : fprintf(stderr, "Internal Error-Action for instruction %d missing.\n", ptr->instr); break; } /* switch */ } /* pic_exec */ /***************************************************************************** pic_draw_seg will draw a segment according to its display list. It just setup the attributes, and scan and execute the instructions on the instruction list. Input list - display list of segment *****************************************************************************/ pic_draw_seg(list) struct list *list; { struct list_item *ptr; /* instruction to indicate end of segment */ static struct list_item closeinstr={GE_CLOSE, 0., 0., NULL}; /* ignore segment if the instruction list is empty */ if ( !(ptr=list->d_list) ) return; /* setup the initial attributes */ pic_attr=list->attr; pic_rms = sqrt((double)((pic_attr.sx*pic_attr.sx+ pic_attr.sy*pic_attr.sy)/2)); sina = (double)sin((double)pic_attr.ang); cosa = (double)cos((double)pic_attr.ang); /* initialize the line width */ pic_set_linewidth(); /* point at beginning of instruction list */ ptr=ptr->next; /* scan instruction list */ do { /* execution instruction */ pic_exec(ptr); ptr=ptr->next; } while ( ptr != list->d_list->next ); /* end of segment */ pic_exec(&closeinstr); } /* pic_draw_seg */ /***************************************************************************** pic_write will write the diagram in pic. It scans the segment list and write every user segment not deleted. Input outfile - opened output stream *****************************************************************************/ pic_write(outfile) FILE *outfile; { extern int ge_seglist; extern struct list ge_open[]; int i; writefile=outfile; /* initialize pic */ pic_init(); /* scan the segment list */ for ( i=ge_seglist; i; i=ge_open[i].next ) { /* write undeleted user segment */ if ( ge_open[i].segno >= GE_MIN_SEG && (! ge_open[i].attr.deleted) ) { pic_draw_seg(&(ge_open[i])); } /* if */ } /* for */ /* terminate pic */ pic_done(); } /* pic_write */ @//E*O*F pic.c// chmod u=r,g=r,o=r pic.c echo x - plot.c sed 's/^@//' > "plot.c" <<'@//E*O*F plot.c//' static char SccsId[] = "@(#)plot.c 1.1 6/8/87 Copyright 1987 SBCS-achan"; /***************************************************************************** (c) Copyright 1987 Lap-Tak Chan Computer Science Department State University of New York at Stony Brook Stony Brook, NY 11794 This software and its documentation may be used, copied, and distributed, provided that this legend appear in all copies and that it is not copied or distributed for a profit. No representations is made about the suitability of this software for any purpose. It is provided "as is" with no support and no express or implied warranty. *****************************************************************************/ /***************************************************************************** Plot Output =========== This file contains routines which write the diagram in plot(5) format. The output file is actually written by routines in the plot(3) library. Filters for many graphic display terminal, laser printers, plotters and even regular terminals are available for files in plot(5) format. *****************************************************************************/ #include "display.h" #include <stdio.h> #include <math.h> /* scale used to maintain significance of coordinates when floating point coordinates are convert to integer coordinates */ #define SCALE 10 static double sina, cosa; /* sin and cos of rotation of current segment */ /* mapping of graphedit line styles to plot line styles */ static char *plt_linestyle[] = { "solid", "dotted", "shortdashed", "dotdashed" }; static struct attr curr_attr; /* attributes of current segment */ /* from display.c */ extern int ge_seglist; /* segment list */ extern struct list ge_open[]; /* display list of segments */ /***************************************************************************** plt_write will write the diagram with routines in plot(3). It scans the segment list and write every user segment not deleted. *****************************************************************************/ plt_write() { int i; /* initialize plot and define the coordiante space */ openpl(); space(0,0,(int)GE_WIN_X*SCALE, (int)GE_WIN_Y*SCALE); /* scan the segment list */ for ( i=ge_seglist; i; i=ge_open[i].next ) { /* write undeleted user segment */ if ( ge_open[i].segno >= GE_MIN_SEG && (! ge_open[i].attr.deleted) ) { plt_draw_seg(&(ge_open[i])); } /* if */ } /* for */ /* close plot */ closepl(); } /* plt_write */ /***************************************************************************** plt_draw_seg will draw a segment according to its display list. It just setup the attributes, and scan and execute the instructions on the instruction list. Input list - display list of segment *****************************************************************************/ plt_draw_seg(list) struct list *list; { struct list_item *ptr; /* instruction to indicate end of segment */ static struct list_item closeinstr={GE_CLOSE, 0., 0., NULL}; /* ignore segment if the instruction list is empty */ if ( !(ptr=list->d_list) ) return; /* setup the initial attributes */ curr_attr = list->attr; /* initialize the line style */ linemod(plt_linestyle[curr_attr.linestyle]); sina = (double)sin((double)curr_attr.ang); cosa = (double)cos((double)curr_attr.ang); /* point to beginning of instruction list */ ptr=ptr->next; /* scan instruction list */ do { /* execution instruction */ plt_exec(ptr); ptr=ptr->next; } while ( ptr !=list->d_list->next ); /* end of segment */ plt_exec(&closeinstr); } /* plt_draw_seg */ /***************************************************************************** plt_xform will transform a coordinate of the current segment to world coordinate and adjust its significance. Input fx, fy - coordinate in coordinate system of current segment Output ix, iy - world coordinate *****************************************************************************/ plt_xform(fx,fy,ix,iy) float fx, fy; int *ix, *iy; { float x, y; /* transform coordinate */ x = cosa * fx * curr_attr.sx - sina * fy * curr_attr.sy + curr_attr.tx; y = sina * fx * curr_attr.sx + cosa * fy * curr_attr.sy + curr_attr.ty; /* adjust significance */ *ix = (int)(x * SCALE + 0.5); *iy = (int)(y * SCALE + 0.5); } /* plt_xform */ /***************************************************************************** plt_sim_ellipse will simulate the drawing of an ellipse by dividing the ellipse into a number of segments and draw each segment with an arc. This is necessary because plot(3) cannot draw ellipse. Coordinates of points on the ellipse are determined by transformation of points on a circle at (0,0) with radius 1. Input xcur, ycur - current world coordinate a,b - half of width and height of ellipse *****************************************************************************/ plt_sim_ellipse(xcur, ycur, a, b) int xcur, ycur; float a, b; { #define PLT_CIRINT 20 /* number of segments to divide into */ #define PLT_CIRSIZE PLT_CIRINT*2+1 /* size of array necessary */ static int plt_mdl_make = 0; static float plt_cir_x[PLT_CIRSIZE]; static float plt_cir_y[PLT_CIRSIZE]; extern float ge_radius2(); /* from misc.c */ float radius; /* radius of arc */ int x1, y1, x2, y2, x3, y3; float x,y; int i; /* put the coordinates of points on a circle with center at (0,0) and radius 1 in plt_cir_x and plt_cir_y at the first time */ if ( ! plt_mdl_make ) { int count; float intv; intv = PI / PLT_CIRINT; for (count=0; count < PLT_CIRSIZE; count ++ ) { plt_cir_x[count]=cos(intv*count); plt_cir_y[count]=sin(intv*count); } plt_mdl_make = 1; } /* if */ /* determine the world coordinate of the first point */ plt_xform(plt_cir_x[0]*a, plt_cir_y[0]*b, &x3, &y3); /* draw the arcs */ for ( i=0; i<PLT_CIRSIZE-1; i+=2 ) { /* make the end point of the last arc the start point */ x1=x3; y1=y3; /* determine the world coordinate of the mid point and the end point */ plt_xform(plt_cir_x[i+1]*a,plt_cir_y[i+1]*b, &x2, &y2); plt_xform(plt_cir_x[i+2]*a,plt_cir_y[i+2]*b, &x3, &y3); /* determine the center of the arc passing the start point, midpoint and end point */ (void) ge_radius2((float)x1,(float)y1,(float)x2,(float)y2, (float)x3,(float)y3,&x,&y); /* draw the arc */ arc((int)(x+xcur-curr_attr.tx*SCALE),(int)(y+ycur-curr_attr.ty*SCALE), (int)(x1+xcur-curr_attr.tx*SCALE),(int)(y1+ycur-curr_attr.ty*SCALE), (int)(x3+xcur-curr_attr.tx*SCALE),(int)(y3+ycur-curr_attr.ty*SCALE)); } /* for */ } /* plt_sim_ellipse */ /***************************************************************************** plt_sim_arc will simulate an arc which is not a real arc after transformation of the current segment with a number of small arcs. Input cx, cy - center of arc in world coordinate ang1 - start angle in radian, 0 <= ang1 <= 2*PI ang2 - end angle in radian, 0 <= ang2 <= 2*PI arcradius - radius of arc *****************************************************************************/ plt_sim_arc(cx,cy,ang1,ang2,arcradius) int cx,cy; float ang1,ang2,arcradius; { float intv, radius; extern float ge_radius2(); int count; int x1,y1,x2,y2,x3,y3; /* start, mid and end point of small arc */ float ang,x,y; intv = PI / PLT_CIRINT; /* ensure ang1 is less than ang2 */ if ( ang1 > ang2 ) ang1 -= 2*PI; /* determine how many small arcs it will be divided into, the minimum is 3 */ count = (int)((ang2-ang1)/(2*intv)); if ( count < 3 ) count = 3; intv = (ang2-ang1)/(count*2); /* transform the first point */ plt_xform(cos(ang1)*arcradius,sin(ang1)*arcradius,&x3,&y3); /* draw the arcs */ for ( ang = ang1; ang< (ang2-2*intv); ang += 2*intv) { /* make end point of last arc the start point */ x1=x3; y1=y3; /* transform mid point */ plt_xform(cos(ang+intv)*arcradius, sin(ang+intv)*arcradius, &x2, &y2); /* transform end point */ plt_xform(cos(ang+2*intv)*arcradius, sin(ang+2*intv)*arcradius, &x3, &y3); /* determine radius of arc */ (void)ge_radius2((float)x1,(float)y1,(float)x2,(float)y2, (float)x3,(float)y3,&x,&y); /* draw small arc */ arc((int)(x+cx-curr_attr.tx*SCALE+0.5), (int)(y+cy-curr_attr.ty*SCALE+0.5), (int)(x1+cx-curr_attr.tx*SCALE), (int)(y1+cy-curr_attr.ty*SCALE), (int)(x3+cx-curr_attr.tx*SCALE), (int)(y3+cy-curr_attr.ty*SCALE)); } /* for */ } /* plt_sim_arc */ /***************************************************************************** plt_exec will execute an instruction. It call routines in plot(3) to actually do the drawing. Input ptr - pointer to instruction *****************************************************************************/ plt_exec(ptr) struct list_item *ptr; { static int xbuff[512], ybuff[512]; static int lastinstr=0; static int n=0; /* number of points in polygon/polyline */ static int xcur, ycur; /* current point */ int i; /* check whether the list of points for polygon/polyline end */ if ( lastinstr && ptr->instr !=GE_CONT ) { switch ( lastinstr ) { case GE_POLYLINE: /* draw polyline */ move (xcur, ycur); for (i=0; i<n; i++) { cont(xbuff[i], ybuff[i]); } xcur=xbuff[n-1]; ycur=ybuff[n-1]; break; case GE_POLYGON: /* draw polygon */ move(xbuff[0],ybuff[0]); for ( i=1; i<n; i++ ) { cont(xbuff[i], ybuff[i]); } cont(xbuff[0],ybuff[0]); xcur=xbuff[0]; ycur=ybuff[0]; break; } /* switch */ lastinstr = n = 0; } /* if */ switch (ptr->instr) { case GE_MOVE: plt_xform(ptr->x, ptr->y, &xcur, &ycur); move(xcur, ycur); break; case GE_LINE: { int tmpx, tmpy; plt_xform(ptr->x, ptr->y, &tmpx, &tmpy); line(xcur, ycur, tmpx, tmpy); xcur=tmpx; ycur=tmpy; } break; case GE_CIRCLE: if ( curr_attr.sx == curr_attr.sy ) { /* draw it as a circle if it is still a circle after transformation of current segment */ int radius; radius = (int)(ptr->x*SCALE+0.5); circle(xcur,ycur,radius); } else { plt_sim_ellipse(xcur,ycur,ptr->x,ptr->x); } break; case GE_ELLIPSE: /* draw ellipse */ plt_sim_ellipse(xcur,ycur,ptr->x,ptr->y); break; case GE_ARC: case GE_ARCEXT: { static float ang1, ang2; if ( ptr->instr == GE_ARC ) { /* save angles of arc */ ang1 = ptr->x; ang2 = ptr->y; } /* GE_ARC */ else { if ( curr_attr.sx == curr_attr.sy ) { /* draw arc as one arc if it is a real arc after transformation of current segment */ int x1,y1,x2,y2; /* transform start point and end point of arc */ plt_xform(cos(ang1)*ptr->x,sin(ang1)*ptr->x,&x1,&y1); plt_xform(cos(ang2)*ptr->x,sin(ang2)*ptr->x,&x2,&y2); /* draw arc */ arc(xcur,ycur, (int)(x1+xcur-curr_attr.tx*SCALE), (int)(y1+ycur-curr_attr.ty*SCALE), (int)(x2+xcur-curr_attr.tx*SCALE), (int)(y2+ycur-curr_attr.ty*SCALE)); } else { /* draw 'arc' with a number of small arcs */ plt_sim_arc(xcur,ycur,ang1,ang2,ptr->x); } } /* GE_ARCEXT */ } /* case GE_ARC, GE_ARCEXT */ break; case GE_POLYLINE: case GE_POLYGON: lastinstr=ptr->instr; case GE_CONT: plt_xform(ptr->x, ptr->y, &xbuff[n], &ybuff[n]); n++; break; case GE_SETTYPELINE: /* change the line style */ linemod(plt_linestyle[(int)ptr->x]); break; case GE_TEXT: /* draw text */ label((char *)((int)ptr->x)); break; /* ignore these instructions */ case GE_SETCOLOR: case GE_SETFONT: case GE_SETCHARSIZE: case GE_SETLINEWIDTH: case GE_FILL: case GE_CLOSE: break; /* check that all instructions are handled properly */ default: fprintf(stderr, "Internal Error-Action for instruction %d missing.\n", ptr->instr); break; } /* switch */ } /* plt_exec */ @//E*O*F plot.c// chmod u=r,g=r,o=r plot.c echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 314 1039 8695 display.c 689 1901 18053 ps.c 579 1887 16700 pic.c 464 1461 12850 plot.c 2046 6288 56298 total !!! wc display.c ps.c pic.c plot.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0