rsalz@uunet.UU.NET (Rich Salz) (10/07/87)
Submitted-by: steinmetz!sbcs!nyfca1!chan (Douglas Chan)
Posting-number: Volume 11, Issue 99
Archive-name: graphedit/part03
[ Note the /tmp/catshar, and the way that "draw.c" is split into two
files. Douglas did a nice packing jobs on this submission. --r$ ]
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Contents: draw.c.shar2 /tmp/catshar
echo x - draw.c.shar2
sed 's/^@//' > "draw.c.shar2" <<'@//E*O*F draw.c.shar2//'
/* create segment for the text sample if it is not there */
if ( !(dlist=ge_display_list(GE_CHAR_SAMPLE)) ) {
make_new_seg(GE_CHAR_SAMPLE);
dlist=ge_display_list(GE_CHAR_SAMPLE);
ge_graph(GE_CHAR_SAMPLE, GE_MOVE, TEXTX, TEXTY);
ge_graph(GE_CHAR_SAMPLE, GE_TEXT, (float)((int)text_sample), 0.);
} /* if */
/* change font of text sample and draw sample */
dlist->attr.font=value;
attr_changed = 1;
ge_draw(GE_CHAR_SAMPLE);
} /* do_change_font */
/*****************************************************************************
do_change_charsize is the notify procedure of the slider for character
size. It will create the text sample if it is not there and update the
size of the test sample according to the value of the slider.
*****************************************************************************/
do_change_charsize(item, value, event)
Panel_item item;
int value;
Event *event;
{
struct list *dlist;
/* create segment for text sample if it is not there */
if ( !(dlist=ge_display_list(GE_CHAR_SAMPLE)) ) {
make_new_seg(GE_CHAR_SAMPLE);
dlist=ge_display_list(GE_CHAR_SAMPLE);
ge_graph(GE_CHAR_SAMPLE, GE_MOVE, TEXTX, TEXTY);
ge_graph(GE_CHAR_SAMPLE, GE_TEXT, (float)((int)text_sample), 0.);
}
/* change character size of text sample and draw sample */
dlist->attr.charsize=value;
attr_changed = 1;
ge_draw(GE_CHAR_SAMPLE);
} /* do_change_charsize */
/*****************************************************************************
do_change_linestyle is the notify procedure of the linestyle choice.
It will create the line sample if it is not there and update the line
style of the line sample according to the value chosen.
*****************************************************************************/
/* define coordinates of line sample */
#define LINEX 80.
#define LINEY 370.
do_change_linestyle(item, value, event)
Panel_item item;
int value;
Event *event;
{
struct list *dlist;
/* create segment for line sample if it is not there */
if ( !(dlist=ge_display_list(GE_LINE_SAMPLE)) ) {
make_new_seg(GE_LINE_SAMPLE);
dlist=ge_display_list(GE_LINE_SAMPLE);
ge_graph(GE_LINE_SAMPLE, GE_MOVE, LINEX, LINEY);
ge_graph(GE_LINE_SAMPLE, GE_LINE, LINEX+60., LINEY);
}
/* update line style of line sample and draw sample */
dlist->attr.linestyle=value;
attr_changed = 1;
ge_draw(GE_LINE_SAMPLE);
} /* do_change_linestyle */
/*****************************************************************************
do_change_linewidth is the notify procedure of the slider for line widths.
It will create the line sample if it is not there and update the line
width of the line sample according to the value of the slider.
*****************************************************************************/
do_change_linewidth(item, value, event)
Panel_item item;
int value;
Event *event;
{
struct list *dlist;
/* create segment for the line sample if necessary */
if ( !(dlist=ge_display_list(GE_LINE_SAMPLE)) ) {
make_new_seg(GE_LINE_SAMPLE);
dlist=ge_display_list(GE_LINE_SAMPLE);
ge_graph(GE_LINE_SAMPLE, GE_MOVE, LINEX, LINEY);
ge_graph(GE_LINE_SAMPLE, GE_LINE, LINEX+60., LINEY);
} /* if */
/* update line width of line sample and draw sample */
dlist->attr.linewidth=value;
attr_changed = 1;
ge_draw(GE_LINE_SAMPLE);
} /* do_change_linewidth */
/*****************************************************************************
do_break is used to break a segment into segments with one primitive
in each segment. It scans the display list of the segment looking for
instructions such as GE_MOVE and GE_POLYGON which imply the beginning
of a primitive and create a new segment for it.
*****************************************************************************/
do_break()
{
int segnam;
struct list *dlist;
struct list_item *ptr;
struct attr attr;
int fill;
do_message("");
/* ask for number of segment to break */
do_usage("Select segment","","");
if ( ! (segnam=ge_pick()) ) {
do_usage("","","");
do_message("No segment selected.");
return;
} /* if */
do_usage("","","");
/* delete segment from view surface */
dlist = ge_display_list(segnam);
attr = dlist->attr;
attr.drawn = 0;
dlist->attr.deleted=1;
ge_draw(segnam);
if ( ptr=dlist->d_list ) {
ptr=ptr->next;
segopen = FALSE;
fill = 0;
/* scan the display list to create the new segments */
do {
switch ( ptr->instr ) {
/* create new segment at GE_MOVE and GE_PLOT */
case GE_MOVE:
case GE_PLOT:
if ( segopen )
ge_draw(opensegment);
make_new_seg(0);
curr_dlist->attr=attr;
break;
case GE_POLYGON:
/* create new segment at GE_POLYGON */
if ( segopen )
ge_draw(opensegment);
make_new_seg(0);
curr_dlist->attr=attr;
case GE_CIRCLE:
case GE_ELLIPSE:
/* set up the proper fill instruction for polygon, circle
and ellipse */
if (fill) {
ge_graph(opensegment, GE_FILL, (float)fill, 0.);
fill = 0;
}
break;
/* no special action for these instructions */
case GE_LINE:
case GE_POLYLINE:
case GE_TEXT:
case GE_CONT:
case GE_ARC:
case GE_ARCEXT:
break;
/* save the fill instruction value, which will be used by
the next polygon, circle or ellipse */
case GE_FILL:
fill = (int)ptr->x;
break;
/* save any change of attributes, which will be used as the
initial attributes of the next created segment */
case GE_SETCOLOR:
attr.color=(int)ptr->x;
break;
case GE_SETTYPELINE:
attr.linestyle=(int)ptr->x;
break;
case GE_SETLINEWIDTH:
attr.linewidth=(int)ptr->x;
break;
case GE_SETFONT:
attr.font=(int)ptr->x;
break;
case GE_SETCHARSIZE:
attr.charsize=(int)ptr->x;
break;
/* check that all possible instructions are properly handled */
default:
fprintf(stderr,
"Internal Error-Action for instruction %d missing.\n",
ptr->instr);
break;
} /* switch */
/* add instruction to the current segment */
ge_graph(opensegment, ptr->instr, ptr->x, ptr->y);
ptr=ptr->next;
} while (ptr != dlist->d_list->next);
} /* if */
/* draw the last segment created */
ge_draw(opensegment);
/* delete the old segment */
ge_delete_segment(segnam);
segopen = FALSE;
/* repeat if the continous option is on */
if ( panel_get_value(cycle_cont) ) do_break();
} /* do_break */
/*****************************************************************************
ge_newscale is used to determine the scaling factor for radius of circles
or character size of text when a segment is joined to another segment.
Input
sx1, sy1 - x,y scale of segment to be joined
sx2, sy2 - x,y scale of segment joining to the first segment
Output
Return the scaling factor determined.
*****************************************************************************/
float ge_newscale(sx1, sy1, sx2, sy2)
float sx1, sy1, sx2, sy2;
{
return (sqrt((double)
((sx2 * sx2 + sy2 * sy2)/
(sx1 * sx1 + sy1 * sy1))));
} /* ge_newscale */
/*****************************************************************************
do_join is used to join a number of segments to form one segment. It will
ask the user to pick the first segment. The display list of all the following
segments picked will be appended to the display list of the first segment
after any apporpiate changes. It will finish when the user do not pick any
segment or pick the first segment.
*****************************************************************************/
do_join()
{
int segnam, firstsegment;
struct list *dlist, *first_dlist;
struct list_item *ptr;
struct attr attr;
float sina, cosa;
/* ask the user to pick the first segment */
do_message("");
do_usage("First segment","","");
if ( ! (firstsegment=ge_pick()) ) {
/* abort if no segment picked */
do_usage("","","");
do_message("No segment selected.");
return;
} /* if */
/* get the display list of the first segment */
segopen = FALSE;
first_dlist = ge_display_list(firstsegment);
curr_dlist = first_dlist;
attr = first_dlist->attr;
/* update attr according to display list of first segment
to obtain attributes at the end of the display list */
if ( ptr=first_dlist->d_list ) {
ptr=ptr->next;
do {
switch ( ptr->instr ) {
case GE_SETCOLOR:
attr.color = (int) ptr->x;
break;
case GE_SETTYPELINE:
attr.linestyle = (int) ptr->x;
break;
case GE_SETLINEWIDTH:
attr.linewidth = (int) ptr->x;
break;
case GE_SETFONT:
attr.font = (int) ptr->x;
break;
case GE_SETCHARSIZE:
attr.charsize = (int) ptr->x;
break;
default: break;
} /* switch */
ptr=ptr->next;
} while ( ptr != first_dlist->d_list->next );
} /* if */
/* ask user to pick a number of segments to join */
do_message("Select first or no segment when done.");
do_usage("Select segment", "", "");
/* join until user pick no/first segment */
while (((segnam=ge_pick()) && (segnam != firstsegment))) {
float newscale;
dlist = ge_display_list(segnam);
newscale=ge_newscale(dlist->attr.sx, dlist->attr.sy, attr.sx, attr.sy);
/* change character size of new segment according to the difference
in scale between the two segments */
dlist->attr.charsize = (float)dlist->attr.charsize / newscale;
/* change attributes of the first segment to the initial attributes
of the joining segment */
if ( dlist->attr.color != attr.color ) {
ge_graph(firstsegment, GE_SETCOLOR, (float)dlist->attr.color, 0.);
attr.color = dlist->attr.color;
}
if ( dlist->attr.linestyle != attr.linestyle ) {
ge_graph(firstsegment, GE_SETTYPELINE, (float)dlist->attr.linestyle, 0.);
attr.linestyle = dlist->attr.linestyle;
}
if ( dlist->attr.linewidth != attr.linewidth ) {
ge_graph(firstsegment, GE_SETLINEWIDTH, (float)dlist->attr.linewidth, 0.);
attr.linewidth = dlist->attr.linewidth;
}
if ( dlist->attr.font != attr.font ) {
ge_graph(firstsegment, GE_SETFONT, (float)dlist->attr.font, 0.);
attr.font = dlist->attr.font;
}
if ( dlist->attr.charsize != attr.charsize ) {
ge_graph(firstsegment, GE_SETCHARSIZE, (float)dlist->attr.charsize, 0.);
attr.charsize = dlist->attr.charsize;
}
sina = sin((double)dlist->attr.ang);
cosa = cos((double)dlist->attr.ang);
/* append the display list of the joining segment to the display list
of the first segment */
if ( ptr=dlist->d_list ) {
ptr=ptr->next;
do {
float nx, ny, wx, wy;
/* add item to segment */
switch ( ptr->instr ) {
case GE_MOVE:
case GE_LINE:
case GE_PLOT:
case GE_POLYLINE:
case GE_POLYGON:
case GE_CONT:
/* transform point to world coordinate */
wx = dlist->attr.sx * cosa * ptr->x -
dlist->attr.sy * sina * ptr->y + dlist->attr.tx;
wy = dlist->attr.sx * sina * ptr->x +
dlist->attr.sy * cosa * ptr->y + dlist->attr.ty;
unxform(wx,wy,&nx,&ny);
break;
case GE_CIRCLE:
case GE_ARCEXT:
/* the radius has to be scaled according to the difference
in scale */
nx = ptr->x / newscale;
ny = ptr->y;
break;
case GE_ELLIPSE:
/* scale height and width of ellipse according to the
difference in scale */
nx = ptr->x * dlist->attr.sx / attr.sx;
ny = ptr->y * dlist->attr.sy / attr.sy;
break;
case GE_ARC:
/* change starting and ending angle of arc according to
the difference in rotation */
nx = ptr->x + dlist->attr.ang - attr.ang;
ny = ptr->y + dlist->attr.ang - attr.ang;
break;
case GE_TEXT:
case GE_FILL:
/* nothing has to be changed */
nx = ptr->x; ny = ptr->y;
break;
/* update current attribute of first segment */
case GE_SETCOLOR:
attr.color = (int) ptr->x;
nx = ptr->x; ny = ptr->y;
break;
case GE_SETTYPELINE:
attr.linestyle = (int) ptr->x;
nx = ptr->x; ny = ptr->y;
break;
case GE_SETLINEWIDTH:
attr.linewidth = (int) ptr->x;
nx = ptr->x; ny = ptr->y;
break;
case GE_SETFONT:
attr.font = (int) ptr->x;
nx = ptr->x; ny = ptr->y;
break;
case GE_SETCHARSIZE:
/* character size has to be scaled according to difference
in scale */
ptr->x /= newscale;
attr.charsize = (int) ptr->x;
nx = ptr->x; ny = ptr->y;
break;
/* check that all instuctions are properly handled */
default:
fprintf(stderr,
"Internal Error-Action for instruction %d missing.\n",
ptr->instr);
break;
} /* switch */
/* add instruction to first segment */
ge_graph(firstsegment, ptr->instr, nx, ny);
ptr=ptr->next;
} while ( ptr != dlist->d_list->next );
} /* if */
/* delete the segment */
dlist->attr.deleted = 1;
ge_draw(segnam);
ge_delete_segment(segnam);
/* redraw first segment */
ge_draw(firstsegment);
} /* while */
do_message("");
do_usage("","","");
} /* do_join */
/*****************************************************************************
do_clear will ask for confirmation of the clear and delete all
segments (except the samples) from the display list and the view
surface upon confirmation.
*****************************************************************************/
do_clear()
{
int i, tmp;
extern int ge_seglist;
extern struct list ge_open[];
do_message("");
if (!(wmgr_confirm(basefd,"Press the left mouse button to confirm Clear. To cancel, press the right mouse button now."))) {
/* clear is cancelled */
do_message("Cancelled.");
return;
} /* if */
/* scan the segment list to delete all segments */
for ( i=ge_seglist; i; i=tmp ) {
tmp = ge_open[i].next;
/* samples are excluded */
if ( ge_open[i].segno >= GE_MIN_SEG ) {
/* remove segment from display */
ge_open[i].attr.deleted=1;
ge_draw(ge_open[i].segno);
/* remove segment from segment list */
ge_delete_segment(ge_open[i].segno);
} /* if */
} /* for */
segopen=FALSE;
} /* do_clear */
/*****************************************************************************
do_copy_segment is used to make a copy of a segment. It will ask the
user to pick a segment, create a new segment and copy the display list of
the old segment to the new segment, and ask the user to move the new
segment to its proper position.
*****************************************************************************/
do_copy_segment()
{
int segnam, butnum;
float tx0, ty0, tx, ty, x, y, wx, wy;
struct list *dlist,*newdlist;
struct list_item *ptr;
/* ask for number of segment to copy */
do_message("");
do_usage("Select segment","","");
if (segnam=ge_pick() ) {
ge_locator(-1, &butnum, &wx, &wy);
/* create new segment */
make_new_seg(0);
segopen=FALSE;
/* copy display list and attributes to new segment */
dlist = ge_display_list(segnam);
newdlist = ge_display_list(opensegment);
newdlist->attr = dlist->attr;
newdlist->attr.drawn = 0;
if ( ptr=dlist->d_list ) {
ptr=ptr->next;
do {
ge_graph(opensegment, ptr->instr, ptr->x, ptr->y);
ptr=ptr->next;
} while ( ptr != dlist->d_list->next );
}
/* draw new segment */
ge_draw(opensegment);
/* ask to user to move the new segment */
tx0 = newdlist->attr.tx; ty0 = newdlist->attr.ty;
do_message("Move the new segment to its location.");
do_usage("", "", "Done");
do {
float tx, ty;
/* determine amount of movement */
ge_locator(-1,&butnum, &x, &y);
tx = x-wx;
ty = y-wy;
ge_align(&tx,&ty);
dlist->attr.tx = tx0 + tx;
dlist->attr.ty = ty0 + ty;
/* redraw both segments */
ge_redisplay(newdlist);
ge_redisplay(dlist);
} while ( butnum != 3 );
segopen = FALSE;
do_message("");
}
else {
do_message("No segment selected.");
}
do_usage("","","");
/* repeat if the continous option is on */
if ( segnam && panel_get_value(cycle_cont) )
do_copy_segment();
} /* do_copy_segment */
/*****************************************************************************
do_open_file is used to open a file with its name in the file name
field on the control pad. It will check whether the file name is
typed in and ask the user to confirm if the file already exist.
Output
Return stream of opened file if the open is successful, and 0 otherwise.
*****************************************************************************/
FILE *do_open_file()
{
char *string;
FILE *file;
/* get file name in file field on control pad */
string=(char *)panel_get_value(text_filen);
/* check for empty file name */
if ( string[0] == '\0' ) {
do_message("Empty file name.");
return(0);
}
/* ask user to confirm if file exist */
if ( !(access(string, F_OK) || wmgr_confirm(basefd,"Press the left mouse button to remove file. To cancel, press the right mouse button now.")) ) {
do_message("Cancelled.");
return(0);
}
/* try to open the file */
if ( !(file=fopen(string, "w+")) ) {
do_message("Cannot open file.");
return(0);
}
return(file);
} /* do_open_file */
/*****************************************************************************
do_save_seg will ask the user to pick a segment to save and save
it in the file indicated in the file field on the control pad.
*****************************************************************************/
do_save_seg()
{
extern int errno;
FILE *onfile;
int segno;
/* ask the user to pick a segment */
do_message("");
do_usage("Select segment","","");
if ( (segno=ge_pick()) < GE_MIN_SEG ) {
do_usage("","","");
do_message("No segment selected.");
return;
}
do_usage("","","");
/* try to open file */
if ( !(onfile=do_open_file()) ) {
/* abort if file cannot be openned */
return;
}
/* write segment to file */
ps_write_seg(onfile,segno);
/* close file */
fclose(onfile);
do_message("Segment saved.");
} /* do_save_seg */
/*****************************************************************************
do_restore will load a segment from the file indicated in the file
field on the control pad.
*****************************************************************************/
do_restore_seg()
{
char *string;
extern int errno;
FILE *onfile;
/* get file name from file field on control pad */
string=(char *)panel_get_value(text_filen);
/* try to open file */
if (!(onfile=fopen(string, "r"))) {
do_message("Cannot open file.");
return;
}
/* load segment */
if ( ! ps_load(onfile) ) {
do_message("Segment loaded.");
}
else {
do_message("File is not a saved segment.");
}
/* close file */
fclose(onfile);
segopen = FALSE;
} /* do_restore_seg */
/*****************************************************************************
do_save_pic will save the picture in the file indicated in the file
field on the control pad. It will run the optimize routine to optimize
the display list if the optimize option is on.
*****************************************************************************/
do_save_pic()
{
FILE *onfile;
extern Panel_item cycle_optm;
/* try to open file in the file field */
if ( !(onfile=do_open_file()) ) {
return;
}
/* run the optimize routine to optimize the display list if
the optimize option is on */
if ( (int)panel_get_value(cycle_optm) ) {
optimize();
}
/* save the picture */
ps_write(onfile);
/* close the file */
fclose(onfile);
do_message("Saved.");
} /* do_save_pic */
/*****************************************************************************
do_restore_pic will load the picture from the file indicated in the
file name field on the control pad.
*****************************************************************************/
do_restore_pic()
{
char *string;
extern int errno;
FILE *onfile;
/* get the file indicated in the file field */
string=(char *)panel_get_value(text_filen);
if (!(onfile=fopen(string, "r"))) {
do_message("Cannot open file.");
return;
}
/* load picture */
if ( ! ps_load(onfile) ) {
do_message("Picture loaded.");
segopen = FALSE;
}
else {
do_message("File is not a saved picture.");
}
/* close file */
fclose(onfile);
} /* do_restore_pic */
/*****************************************************************************
do_raster will write the pixrect image of whole/part of the picture on
the already opened onfile. It will remove the samples and grid from
the view surface and refresh the view surface before getting the
pixrect image.
Input
onfile - opened stream for writing
*****************************************************************************/
do_raster(onfile)
FILE *onfile;
{
float xmin, ymin, xmax, ymax;
int butnum,i;
extern Panel_item cycle_raster;
/* display list of samples */
struct {
int deleted;
struct list *dlist;
} samples[4];
/* segments which should be invisible on the raster file */
static int sampleseg[] = {GE_COLOR_SAMPLE,GE_LINE_SAMPLE,
GE_CHAR_SAMPLE, GE_GRID};
/* set region to dump */
xmin=0.; ymin=0.;
if ( (int)panel_get_value(cycle_raster) ) {
/* ask for region to dump when raster option is on */
do_usage("Reset corner","","Done");
do {
xmax=xmin;
ymax=ymin;
ge_locator(6, &butnum, &xmax, &ymax);
if ( butnum == 1 ) {
/* reset corner */
xmin=xmax;
ymin=ymax;
}
} while ( butnum != 3 );
do_usage("","","");
}
else {
/* dump the whole view surface */
xmax=GE_WIN_X;
ymax=GE_WIN_Y;
}
/* remove the samples from the view surface */
for ( i=0; i<4; i++ ) {
if ( (samples[i].dlist = ge_display_list(sampleseg[i])) &&
! (samples[i].deleted = samples[i].dlist->attr.deleted)){
samples[i].dlist->attr.deleted = 1;
ge_draw(sampleseg[i]);
} /* if */
} /* for */
/* refresh the screen */
ge_refresh();
/* dump the region to onfile */
core_write(onfile, xmin, ymin, xmax, ymax);
/* redraw the samples and grid */
for ( i=0; i<4; i++ ) {
if ( samples[i].dlist && (!samples[i].deleted) ) {
samples[i].dlist->attr.deleted = 0;
ge_draw(sampleseg[i]);
} /* if */
} /* for */
} /* do_raster */
/*****************************************************************************
do_output will write the picture in the format specified by the
output format option to the file indicated in the file field on the
control pad. It will try to open the file, and then call the
corresponding routine to write the picture.
*****************************************************************************/
do_output()
{
extern Panel_item cycle_output;
int format;
FILE *onfile;
FILE savestdout;
do_message("");
/* open the file indicated in the file field on the control pad */
if ( !(onfile=do_open_file()) ) {
return;
} /* if */
/* get the format from the output format option */
format=(int)panel_get_value(cycle_output);
switch ( format ) {
case 0:
/* raster file */
do_raster(onfile);
break;
case 1:
/* pic */
pic_write(onfile);
fclose(onfile);
break;
case 2:
/* plot */
/* make onfile the standard output file so that the plot library will
write to onfile */
savestdout = *stdout;
*stdout = *onfile;
plt_write();
/* reset standard output */
*stdout=savestdout;
break;
} /* switch */
do_message("Written");
} /* do_output */
/*****************************************************************************
do_global_scale will scale and move the whole picture within a rectangular
region specified by the user.
*****************************************************************************/
do_global_scale()
{
float xmin, ymin, xmax, ymax;
float tmp, sx, sy, tx, ty;
int butnum,i;
/* ask for the region to scale to */
do_message("");
do_usage("Reset corner","Cancel","Done");
xmin=0.; ymin=0.;
do {
xmax=xmin;
ymax=ymin;
ge_locator(6, &butnum, &xmax, &ymax);
if ( butnum == 1 ) {
/* reset corner */
xmin=xmax;
ymin=ymax;
}
if ( butnum == 2 ) {
/* cancel scale */
do_usage("","","");
do_message("Cancelled.");
return;
}
} while ( butnum != 3 );
do_usage("","","");
/* get lower left corner in (xmin,ymin) and upper right corner in
(xmax,ymax) */
if ( xmin > xmax ) {
tmp=xmin;
xmin=xmax;
xmax=tmp;
}
if ( ymin > ymax ) {
tmp=ymin;
ymin=ymax;
ymax=tmp;
}
/* determine the scale and movement */
sx = (xmax - xmin)/GE_WIN_X;
sy = (ymax - ymin)/GE_WIN_Y;
tx = xmin;
ty = ymin;
/* scan the segment list to scale all segments except the
samples */
for ( i=ge_seglist; i; i=ge_open[i].next ) {
if ( ge_open[i].segno >= GE_MIN_SEG ) {
float sina, cosa, nx, ny;
sina=sin((double)ge_open[i].attr.ang);
cosa=cos((double)ge_open[i].attr.ang);
/* determine the new translate value, scaling at (0,0)
in world coordinate */
nx = (-ge_open[i].attr.tx*cosa - ge_open[i].attr.ty*sina)/
ge_open[i].attr.sx;
ny = (-ge_open[i].attr.ty*cosa + ge_open[i].attr.tx*sina)/
ge_open[i].attr.sy;
ge_open[i].attr.tx += nx*cosa*ge_open[i].attr.sx*(1-sx) -
ny*sina*ge_open[i].attr.sy*(1-sy) + tx;
ge_open[i].attr.ty += nx*sina*ge_open[i].attr.sx*(1-sx) +
ny*cosa*ge_open[i].attr.sy*(1-sy) + ty;
/* determine the new scale factor */
ge_open[i].attr.sx *= sx;
ge_open[i].attr.sy *= sy;
/* redraw segment */
ge_redisplay(&(ge_open[i]));
} /* if */
} /* for */
} /* do_global_scale */
@//E*O*F draw.c.shar2//
chmod u=rw,g=r,o=r draw.c.shar2
echo x - /tmp/catshar
sed 's/^@//' > "/tmp/catshar" <<'@//E*O*F /tmp/catshar//'
#!/bin/csh
#
# This script combine draw.c.shar1 and draw.c.shar2 together
if ( -f draw.c.shar1 && -f draw.c.shar2 ) then
echo 'Reconstruct draw.c from draw.c.shar1 and draw.c.shar2...'
cat draw.c.shar1 draw.c.shar2 >> draw.c
/bin/rm -f draw.c.shar1 draw.c.shar2
endif
exit 0
@//E*O*F /tmp/catshar//
chmod u=rwx,g=rx,o=rx /tmp/catshar
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 <<\!!!
1013 3155 28120 draw.c.shar2
9 38 275 catshar
1022 3193 28395 total
!!!
wc draw.c.shar2 /tmp/catshar | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
/tmp/catshar
/bin/rm -f /tmp/catshar
exit 0