rsalz@uunet.UU.NET (Rich Salz) (10/07/87)
Submitted-by: steinmetz!sbcs!nyfca1!chan (Douglas Chan) Posting-number: Volume 11, Issue 100 Archive-name: graphedit/part04 # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Contents: core.c echo x - core.c sed 's/^@//' > "core.c" <<'@//E*O*F core.c//' static char SccsId[] = "@(#)core.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. *****************************************************************************/ /***************************************************************************** SunCore Interface ================= This file contains a package of routines used by graphedit as interface to SunCore, which is used to maintain the display on the view surface and to obtain mouse input from the view surface. *****************************************************************************/ #include <usercore.h> #include <math.h> #include <stdio.h> #include "display.h" #include "suntool/sunview.h" #include "suntool/panel.h" /* something from demolib.h */ struct vwsurf *get_view_surface(/* (struct vwsurf *), argv */); struct vwsurf *get_surface(/* (struct vwsurf *), argv */); static struct vwsurf Core_vwsurf; struct vwsurf *our_surface = &Core_vwsurf; /* our view surface */ /* pixrect device handlers */ static int cg1dd(); static int gp1dd(); static int cg2dd(); static int cg4dd(); /* only on Sun 3.2 and latter */ static int cgpixwindd(); static int pixwindd(); static int gp1pixwindd(); #define MAPSIZE 256 #define GE_TMPSEG 100000 /* The following two level mapping of colors can actually be reduced to one level */ /* entries in colormap used */ static int colortable[] = { 0, 1, 20, 40, 63 , 85, 105, 127, 147, 167, 191, 253, 254, 255 }; /* mapping between graphedit colors from 0-11 to colors in colortable */ static int clrmap[] = { 1,2,3,4,5,6,7,8,9,10,11,13}; /* color table values for b/w screens */ static float redlist[MAPSIZE], grnlist[MAPSIZE], blulist[MAPSIZE]; /* 1 2 3 4 5 6 7 8 9 10 11 12 */ static float redtex[] = {0.,.7334,.7922,.6667,.7765,.6589,.6589,.2667,.5334,.0314,.0235,.0157,0.,.0}; static float grntex[] = {0.,.5334,.1922,.5334,.0667,.1922,.0667,.5334,.5334,.0667,.0667,.0667,0.,.2667 }; static float blutex[] = {0.,.4001,.0000,.4001,.4001,.0000,.4001,.4001,.4001,.4001,.4001,.4001,0.,.3882}; /* color table values for color screens */ static float credtex[]= {1.,.95,.9,.8,.75,.7,.6,.5,.4,.3,.2,.1,1.,0.}; static float cgrntex[]= {1.,.95,.9,.8,.75,.7,.6,.5,.4,.3,.2,.1,1.,0.}; static float cblutex[]= {1.,.95,.9,.8,.75,.7,.6,.5,.4,.3,.2,.1,1.,0.}; /***************************************************************************** set_up_core will create the view surface, initialize the input devices, and setup the color table. *****************************************************************************/ set_up_core(argv) char *argv[]; { int colorflag,i; float white=1.0; static char default_cood[]="301,0,851,650,512,836,64,64,0"; static char *ptrs[]={default_cood, (char *)0}; /* start up SunCore */ if ( initialize_core(DYNAMICC, SYNCHRONOUS, TWOD)) exit(0); /* get what device the view surface will be created on */ get_view_surface(our_surface,argv); /* create a new window if view surface will be created in suntools */ if ( (our_surface->dd == pixwindd) || (our_surface->dd == cgpixwindd) || (our_surface->dd == gp1pixwindd) ) { our_surface->flags=1; } /* actually create the view surface */ our_surface->ptr = ptrs; our_surface->cmapsize = MAPSIZE; our_surface->cmapname[0] = '\0'; if (initialize_view_surface( our_surface, FALSE)) exit(0); /* initailize the input devices */ initialize_device( BUTTON, 1); initialize_device( BUTTON, 2); initialize_device( BUTTON, 3); initialize_device( LOCATOR, 1); initialize_device( PICK, 1); set_echo_position( LOCATOR, 1, 0., 0.); set_echo_surface( LOCATOR, 1, our_surface); set_echo_surface( PICK, 1, our_surface); set_pick(1,0.01); set_echo( PICK, 1,1); /* initailize view surface */ set_window(0.,GE_WIN_X,0.,GE_WIN_Y); set_viewport_2( 0.,1.,0., .75); /* init viewing transform */ set_window_clipping(FALSE); set_output_clipping(TRUE); select_view_surface(our_surface); set_image_transformation_type(XFORM2); set_primitive_attributes( &PRIMATTS); set_charprecision(CHARACTER); /* check whether view surface is on color device */ if((our_surface->dd == cg1dd) || (our_surface->dd == cgpixwindd) || (our_surface->dd == cg2dd) || (our_surface->dd == gp1dd) || (our_surface->dd == cg4dd) || (our_surface->dd == gp1pixwindd)) colorflag=TRUE; else colorflag=FALSE; if(!colorflag) { /* colormap for b/w device */ for (i=0;i<14;i++) { redlist[colortable[i]]=redtex[i]; grnlist[colortable[i]]=grntex[i]; blulist[colortable[i]]=blutex[i]; } } else { /* colormap for color device */ for (i=0;i<14;i++) { redlist[colortable[i]]=credtex[i]; grnlist[colortable[i]]=cgrntex[i]; blulist[colortable[i]]=cblutex[i]; } set_line_index(colortable[13]); set_text_index(colortable[13]); } /* if */ /* setup the color map */ define_color_indices(our_surface,0,MAPSIZE-1,redlist,grnlist,blulist); /* create the crosshair used by ge_locator */ ge_crosshair(); } /* set_up_core */ /***************************************************************************** ge_crosshair will create the crosshair used by ge_locator. *****************************************************************************/ #define CROSSHAIRSZ 2.5 /* size of crosshair */ ge_crosshair() { create_retained_segment(GE_CROSSHAIR); set_segment_visibility(GE_CROSSHAIR,0); move_abs_2(0., -CROSSHAIRSZ); line_abs_2(0., CROSSHAIRSZ); move_abs_2(-CROSSHAIRSZ, 0.); line_abs_2(CROSSHAIRSZ, 0.); close_retained_segment(); } /* ge_crosshair */ /***************************************************************************** do_exit will terminate the SunCore view surface. *****************************************************************************/ do_exit() { terminate_device( LOCATOR, 1); deselect_view_surface(our_surface); terminate_view_surface(our_surface); terminate_core(); } /* do_exit */ /***************************************************************************** ge_locator will read the mouse input within the view surface. It behaves differently according to echo. Input echo - if negative, read the current status of the mouse and return immediately otherwise, return the status of the mouse when any of the buttons is hit The mouse input will be echoed according to the value of abs(echo) as how the locator in Suncore is echoed: 0 - no echo 1 - pointing finger 2 - line connecting from (x,y) to mouse location 3 - line connecting from (x,y) to x coordinate of mouse 4 - line connecting from (x,y) to y coordinate of mouse 5 - line connecting from (x,y) to x or y coordinate of mouse, whichever is further 6 - a box with (x,y) as one corner and mouse location the other corner x,y - world coordinate used by echo Output butnum - number of button hit, 0 if no button was hit x,y - world coordinate of mouse location *****************************************************************************/ ge_locator(echo, butnum, x, y) int *butnum, echo; float *x, *y; { float nx, ny; int wait_int; /* how long (in ms) to wait */ /* decide how long to wait */ if ( echo<0 ) { echo = - echo; wait_int=20; } else wait_int=100000000; /* set the echo reference position */ if ( echo > 1 ) { map_world_to_ndc_2( *x, *y, &nx, &ny ); set_echo_position(LOCATOR, 1, nx, ny); } if ( (echo == 1) && (wait_int > 1000) ) { /* put cross hair at location read because the location may not be the position of the pointing finger */ set_echo(LOCATOR, 1, 0); await_any_button_get_locator_2(200,1,butnum, &nx, &ny); set_segment_image_transformation_2(GE_CROSSHAIR,1.,1.,0.,nx,ny); set_segment_visibility(GE_CROSSHAIR,1); while ( !(*butnum) ) { await_any_button_get_locator_2(200,1,butnum, &nx, &ny); set_segment_image_transformation_2(GE_CROSSHAIR,1.,1.,0.,nx,ny); } /* while */ set_segment_visibility(GE_CROSSHAIR,0); } else { /* specify the echo and read locator input */ set_echo(LOCATOR, 1, echo); await_any_button_get_locator_2(wait_int,1, butnum, &nx, &ny); } /* map normal device coordinate back to world coordinate */ map_ndc_to_world_2(nx, ny, x, y); } /* ge_locator */ /***************************************************************************** ge_tmp_new is used to create a temporary segment to echo a number of lines drawn. Input x,y - world coordinate to start at attr - attributes of current segment *****************************************************************************/ ge_tmp_new(x,y,attr) float x,y; struct attr attr; { /* set attributes */ set_linestyle(attr.linestyle); set_linewidth((float)attr.linewidth/5.); /* create temporary segment */ create_retained_segment(GE_TMPSEG); /* move to starting point */ move_abs_2(x,y); } /* ge_tmp_new */ /***************************************************************************** ge_tmp_line is used to continue echo of a number of lines. Input x,y - world coordinate to draw a line to *****************************************************************************/ ge_tmp_line(x,y) float x,y; { line_abs_2(x,y); } /* ge_tmp_line */ /***************************************************************************** ge_tmp_delete will delete the temporary segment created. *****************************************************************************/ ge_tmp_delete() { close_retained_segment(GE_TMPSEG); delete_retained_segment(GE_TMPSEG); } /* ge_tmp_delete */ /***************************************************************************** ge_flush will flush all previous mouse input. *****************************************************************************/ ge_flush() { int butnum; float x,y; do { await_any_button_get_locator_2(0,1, &butnum, &x, &y); } while ( butnum ); } /* ge_flush */ /***************************************************************************** ge_pick is used to pick a segment. It will flush previous input and wait for the user to pick a segment. Output Return number of segment picked. *****************************************************************************/ ge_pick() { int segno; int pickid; /* flush previous input */ ge_flush(); /* pick segment */ await_pick(1000000000, 1, &segno, &pickid); return(segno); } /* ge_pick */ /***************************************************************************** ge_draw will update the display of a segment on the view surface. If the segment is marked deleted, the segment will be make invisible on the display. If the segment has been drawn, the old image on the view surface will be erased. To minimize the time between the old image is erased and the new image is drawn, the new image is first drawn in an invisible temporary segment. The old image is then deleted and the new temporary segment renamed to be the segment. Input segno - number of segment to draw *****************************************************************************/ /* map graphedit linestyle to SunCore linestyle */ static int linestyle_menu[]= {SOLID,DOTTED,DASHED,DOTDASHED}; /* map graphedit font to SunCore font */ static int font_menu[]= {STICK,ROMAN,GREEK,SCRIPT,OLDENGLISH}; /* table to adjust width of font in SunCore so that they will have proportional width with fonts in PostScript */ static float charwidthfactor[] = { 1.28, 1.54, 1.42, 1.49, 1.48 }; static int segmentfont, segmentcharsize; /* ge_setchar will set the character size according to the graphedit character size and font */ #define ge_setchar(size,font) set_charsize((size)/charwidthfactor[(font)],(size)/1.5) ge_draw(segno) int segno; { struct list *seginfo, *ge_display_list(); struct list_item *ptr; static struct list_item closeinstr={GE_CLOSE, 0.,0.,NULL}; float tx,ty; /* abort if the display list of the segment cannot be found or is empty */ if ( !((seginfo=ge_display_list(segno)) && (ptr=seginfo->d_list)) ) return; /* set the initial attributes of the segment */ segmentfont = seginfo->attr.font; segmentcharsize = seginfo->attr.charsize; set_fill_index(colortable[clrmap[seginfo->attr.color]]); set_linestyle(linestyle_menu[seginfo->attr.linestyle]); set_linewidth((float)seginfo->attr.linewidth/5.); ge_setchar((float)seginfo->attr.charsize,seginfo->attr.font); set_font(font_menu[seginfo->attr.font]); /* create an invisible temporary segment*/ create_retained_segment(GE_TMPSEG); set_segment_visibility(GE_TMPSEG,0); /* scan the display list of the segment to draw the image */ ptr=ptr->next; do { ge_exec(ptr); ptr=ptr->next; } while ( ptr != seginfo->d_list->next ); /* close the segment */ ge_exec(&closeinstr); /* make user segments detectable and sample segment undetectable */ if ( segno >= GE_MIN_SEG ) { set_segment_detectability(GE_TMPSEG, segno); } else { set_segment_detectability(GE_TMPSEG, 0); } /* close the temporary segment */ close_retained_segment(GE_TMPSEG); /* set the transformation of the segment */ map_world_to_ndc_2(seginfo->attr.tx, seginfo->attr.ty, &tx, &ty); set_segment_image_transformation_2(GE_TMPSEG, seginfo->attr.sx, seginfo->attr.sy, seginfo->attr.ang, tx, ty); /* delete the old image if the segment has been drawn before */ if ( seginfo->attr.drawn ) delete_retained_segment(segno); /* make the temporary segment visible */ set_segment_visibility(GE_TMPSEG,!seginfo->attr.deleted); /* rename the temporary segment to be the segment */ rename_retained_segment(GE_TMPSEG, segno); seginfo->attr.drawn=1; } /* ge_draw */ /***************************************************************************** ge_draw_ellipse will draw a ellipse will a number of lines. The equation of the ellipse is 2 2 x y --- + --- = 1 2 2 a b Input a, b - parameter in equation fill - how the ellipse should be filled/bordered *****************************************************************************/ #define LINEPERCIRCLE 20 /* number of lines to form a circle */ ge_draw_ellipse(a,b,fill) float a,b; int fill; { float i; float oldsin, oldcos; float tmpsin, tmpcos; float intv; float ang; int count; float xbuff[LINEPERCIRCLE+1], ybuff[LINEPERCIRCLE+1]; intv=2.*PI/LINEPERCIRCLE; ang=0.; count=1; xbuff[0]=a*(oldcos=cos((double)ang)); ybuff[0]=b*(oldsin=sin((double)ang)); for (ang=intv; !(ang>(2.1*PI)); ang+=intv) { xbuff[count]=a*(-oldcos+(tmpcos=cos((double)ang))); ybuff[count++]=b*(-oldsin+(tmpsin=sin((double)ang))); oldcos=tmpcos; oldsin=tmpsin; } /* for */ if ( (fill==GE_FILLONLY) || (fill==GE_FILLBORDER) ) { /* fill region */ polygon_rel_2(xbuff,ybuff,count); move_rel_2(-xbuff[0], -ybuff[0]); } /* if */ if ( (fill==GE_BORDERONLY) || (fill==GE_FILLBORDER) ) { /* draw border */ move_rel_2(xbuff[0],ybuff[0]); polyline_rel_2(&(xbuff[1]),&(ybuff[1]),count-1); } /* if */ } /* ge_draw_ellipse */ /***************************************************************************** ge_draw_arc will draw an arc with center at current point, from ang1 to ang2 with radius radius. Input ang1 - from angle, 0 <= ang1 <= 2PI ang2 - to angle, 0 <= ang2 <= 2PI radius - radius of arc *****************************************************************************/ ge_draw_arc(ang1,ang2,radius) float ang1,ang2,radius; { float intv, ang; float oldsin, oldcos, tmpsin, tmpcos; int count; float xbuff[LINEPERCIRCLE+1], ybuff[LINEPERCIRCLE+1]; /* ensure that ang1 < ang2 */ if ( ang1 > ang2 ) { ang1 -= 2*PI; } /* determine the interval */ intv=2.*PI/LINEPERCIRCLE; if ((ang2-ang1) < (3*intv) ) { /* a minimum of three lines are drawn for the arc */ intv = (ang2-ang1)/3; } /* the first point */ ang=ang1; count=1; xbuff[0]=radius*(oldcos=cos((double)ang)); ybuff[0]=radius*(oldsin=sin((double)ang)); /* determine the following points */ for (ang += intv; ang < ang2; ang+=intv) { xbuff[count]=radius*(-oldcos+(tmpcos=cos((double)ang))); ybuff[count++]=radius*(-oldsin+(tmpsin=sin((double)ang))); oldcos=tmpcos; oldsin=tmpsin; } /* the last point */ xbuff[count]=radius*(-oldcos+(cos((double)ang2))); ybuff[count++]=radius*(-oldsin+(sin((double)ang2))); /* draw the arc */ move_rel_2(xbuff[0],ybuff[0]); polyline_rel_2(&(xbuff[1]),&(ybuff[1]),count-1); } /* ge_draw_arc */ /***************************************************************************** ge_exec will execute an instruction on a display list. Input ptr - pointer to the instruction *****************************************************************************/ ge_exec(ptr) struct list_item *ptr; { static float xbuff[512], ybuff[512]; static int lastinstr=0; static int n=0; static int fill=0; /* execute last polyline/polygon instruction if instruction indicates end of the last instruction */ if ( lastinstr && ptr->instr != GE_CONT ) { switch ( lastinstr ) { case GE_POLYLINE : polyline_abs_2(xbuff,ybuff,n); break; case GE_POLYGON : { /* do not draw if there are less than 3 points */ if ( n < 3 ) { fill=0; break; } if ( (fill==GE_FILLONLY) || (fill==GE_FILLBORDER) ) { /* fill region */ polygon_abs_2(xbuff,ybuff,n); } if ( (fill==GE_BORDERONLY) || (fill==GE_FILLBORDER) ) { /* draw border */ move_abs_2(xbuff[n-1],ybuff[n-1]); polyline_abs_2(xbuff,ybuff,n); } fill=0; break; } /* GE_POLYGON */ default: ; } /* switch */ lastinstr = n = 0; } /* if */ /* execute new instruction */ switch ( ptr->instr) { /* instructions with single coordinate */ case GE_MOVE: move_abs_2(ptr->x,ptr->y); break; case GE_LINE: line_abs_2(ptr->x,ptr->y); break; case GE_PLOT: move_abs_2(ptr->x,ptr->y); line_rel_2(0.,0.); break; case GE_TEXT: text((char *)((int)ptr->x)); break; case GE_FILL: fill=(int)ptr->x; 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 */ xbuff[n] = ptr->x; ybuff[n++]= ptr->y; break; case GE_CIRCLE: ge_draw_ellipse(ptr->x,ptr->x,fill); fill = 0; break; case GE_ELLIPSE: ge_draw_ellipse(ptr->x,ptr->y,fill); fill = 0; break; case GE_ARC: /* save the angles */ xbuff[0]=ptr->x; ybuff[0]=ptr->y; break; case GE_ARCEXT: ge_draw_arc(xbuff[0],ybuff[0],ptr->x); break; /* change the attributes of the segment */ case GE_SETCOLOR: set_fill_index(colortable[clrmap[(int)ptr->x]]); break; case GE_SETTYPELINE: set_linestyle(linestyle_menu[(int)ptr->x]); break; case GE_SETLINEWIDTH: set_linewidth(ptr->x/5.); break; case GE_SETCHARSIZE: ge_setchar(ptr->x,segmentfont); segmentcharsize = (int) ptr->x; break; case GE_SETFONT: set_font(font_menu[(int)ptr->x]); segmentfont = (int)ptr->x; ge_setchar(segmentcharsize, segmentfont); break; case GE_CLOSE: break; default : /* check that all instructions are handled properly */ fprintf(stderr, "Internal Error-Action for instruction %d missing.\n", ptr->instr); break; } /* switch */ } /* ge_exec */ /***************************************************************************** ge_redisplay will redraw the segment will any new transformation. *****************************************************************************/ ge_redisplay(seginfo) struct list *seginfo; { float tx, ty; /* translation should be in ndc */ map_world_to_ndc_2(seginfo->attr.tx, seginfo->attr.ty, &tx, &ty); /* will redraw the segment */ set_segment_image_transformation_2(seginfo->segno, seginfo->attr.sx, seginfo->attr.sy, seginfo->attr.ang,tx,ty); } /* ge_redisplay */ /***************************************************************************** core_write will write the pixrect image of a region on the view surface as a rasterfile on file. Input file - opened stream to write to xmin, ymin - coordinate of a corner of region in world coordinate xmax, ymax - coordinate of diagonal corner of region in world coordinate *****************************************************************************/ core_write(file, xmin, ymin, xmax, ymax) FILE *file; float xmin, ymin, xmax, ymax; { struct suncore_raster raster; float nx1, ny1, nx2, ny2, tmp; /* empty colormap structure for raster_to_file */ static struct { int type; int nbytes; char *data; } color_map = { 0, 0, 0 }; /* convert coordinates to ndc coordinates */ map_world_to_ndc_2(xmin, ymin, &nx1, &ny1); map_world_to_ndc_2(xmax, ymax, &nx2, &ny2); /* make (nx1,ny1) the lower left corner and (nx2,ny2) the upper right corner */ if ( nx2 < nx1 ) { tmp = nx1; nx1 = nx2; nx2 = tmp; } if ( ny2 < ny1 ) { tmp = ny1; ny1 = ny2; ny2 = tmp; } /* allocate memory for the pixrect image */ size_raster(our_surface, nx1, nx2, ny1, ny2, &raster); allocate_raster(&raster); /* get the pixrect image */ get_raster(our_surface, nx1, nx2, ny1, ny2, 0, 0, &raster); /* write pixrect image as raster file */ raster_to_file(&raster, &color_map, file->_file, 1); /* free memory */ free_raster(&raster); } /* core_write */ /***************************************************************************** ge_refresh will refresh the view surface. *****************************************************************************/ ge_refresh() { new_frame(); } /* ge_refresh */ @//E*O*F core.c// chmod u=r,g=r,o=r core.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 <<\!!! 843 2410 23387 core.c !!! wc core.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