/* cgmgen.c 28 April 1999 */ /* Notes- CGM metafile states: 0=uninitialized, or after 'end metafile' 1= after 'begin metafile' or 'end picture' 2= after 'begin picture' 3= after 'begin picture body' Coordinate transformation: The scaling and shift factors are set by setscale. The world coordinate minima and maxima (wcd_*) may be set by SETWCD and are used by setscale, which may reset the world coordinate limits if their aspect ratio does not match that of the display. If setscale changes the limits, it will select new values in such a way that a square region of the display will span a world coordinate region with the same aspect ratio as those of the world coordinate limits set using SETWCD. The _scale and _shift values are used in the coordinate-to-pixel conversion expressions which follow immediately. wcd_ values are the x and y limits of the world coordinate system, in terms of which the user gives coordinates. pxl_vdc is the number of pixels per VDC unit (in the x direction). Clipping: Polygons, polylines, and polymarkers are clipped to the boundary defined by the world coordinate rectangle (wcd_ values; see below). This clipping can be disabled and re_enabled by calling the clip_off and clip_on routines in cgm_clip.c . The start point of text is likewise clipped; this means that a text string written from left to right might trail off the right edge of the screen, but cannot enter the screen from the left edge (assuming default text attributes). Cell arrays are not currently clipped; their boundaries are just pushed back to the wcd_ borders. In general all this clipping is redundant since the device driver usually clips also, but some errors can arise (because coordinates go outside the VDC extent) if it is turned off. */ /* This module recognizes what type of machine it's on by the presence of the symbol VMS, unix, CRAY, or ardent. The following makes the machine assignment less ambiguous. */ # include #if ( unix && ( !CRAY && !ardent && !__hpux ) ) #define USE_UNIX #endif #ifdef _IBMR2 #include #include #endif #ifdef VMS #include descrip #include stdio #endif #ifdef CRAY #include #include #include #endif #ifdef USE_UNIX #include #include #endif #ifdef ardent #include #include #endif #ifdef __hpux #include #include #endif /* Include defs needed to comply with the GPlot driver interface */ #include "defs.h" /* Include defs files that allow linkage to Fortran on various systems */ #ifdef USE_UNIX #include "unix_defs.h" #endif #ifdef CRAY #include "unicos_defs.h" #endif #ifdef ardent #include "unicos_defs.h" /* these are also appropriate on Ardent Titan */ #endif #ifdef _IBMR2 /* include nothing */ #endif #ifdef __hpux /* include nothing */ #endif /* clipping and text emulation facilities */ #include "cgm_clip.h" #include "cgm_textem.h" /* Default GPlot device driver name, and associated storage. */ #define devnamlen 20 static char devnam[devnamlen]= "cgmb"; /* CGM metafile states. */ int cgmstate=0; /* Page number */ static int pgnum= 0; /* Storage for picture name */ #define maxpicnamelength 256 static char picture_name[maxpicnamelength]; /* will initially be nulls, which is correct */ /* Structures which maintain the CGM state */ static struct mf_d_struct glbl1; /* the class 1 elements */ static struct pic_d_struct glbl2,dflt2; /* the class 2 elements */ static struct control_struct glbl3,dflt3; /* the class 3 elements */ static struct attrib_struct glbl5,dflt5; /* the class 5 elements */ /* The arrays of function pointers, filled in externally by the device initialisation routine */ static int (*delim[Delim_Size])(); /* delimiter functions */ static int (*mfdesc[MfDesc_Size])(); /* metafile descriptor functions */ static int (*pdesc[PDesc_Size])(); /* page descriptor functions */ static int (*mfctrl[Control_Size])(); /* mf control functions */ static int (*gprim[GPrim_Size])(); /* graphical primitives */ static int (*attr[Att_Size])(); /* the attribute functions */ static int (*escfun[Esc_Size])(); /* the escape functions */ static int (*extfun[Ext_Size])(); /* the external functions */ static int (*ctrl[Delim_Size])(); /* external controller functions */ /* Device driver attribute storage */ static struct info_struct dev_info; /* Storage for simulated command line options (global so debugging option will extend to driver) */ static struct one_opt cmd_opt[opt_size]; /* Abbreviation for debugging option */ #define debugmode cmd_opt[(int)debug].val.i /* Set up interface to Fortran character string descriptors */ #ifdef VMS typedef struct dsc$descriptor_s *string_descriptor; #define STRINGLENGTH /* nothing */ #define DEFSTRINGLENGTH /* nothing */ #endif #ifdef CRAY typedef _fcd string_descriptor; #define STRINGLENGTH /* nothing */ #define INTSTRINGLENGTH /* nothing */ #define DEFSTRINGLENGTH /* nothing */ #endif #ifdef USE_UNIX typedef char *string_descriptor; #define STRINGLENGTH ,stringlength #define INTSTRINGLENGTH , int stringlength #define DEFSTRINGLENGTH int stringlength; #endif #ifdef _IBMR2 typedef char *string_descriptor; #define STRINGLENGTH ,stringlength #define INTSTRINGLENGTH , int stringlength #define DEFSTRINGLENGTH int stringlength; #endif #ifdef ardent typedef struct { char *addr; int length; } *string_descriptor; #define STRINGLENGTH /* nothing */ #define INTSTRINGLENGTH /* nothing */ #define DEFSTRINGLENGTH /* nothing */ #endif #ifdef __hpux typedef char *string_descriptor; #define STRINGLENGTH ,stringlength #define INTSTRINGLENGTH , int stringlength #define DEFSTRINGLENGTH int stringlength; #endif /* Some useful macros */ #define mcr_min(val1,val2) ( (val1)<(val2) ? (val1) : (val2) ) #define mcr_max(val1,val2) ( (val1)>(val2) ? (val1) : (val2) ) #define mcr_bound(val,vmin,vmax) ( mcr_max( vmin, mcr_min( val, vmax ) ) ) #define float_to_byte(fval) ((unsigned char)((int)((fval)*255.0)) % 256) /* Definition of default data storage space, and associated vars */ #define defbufsize 1024 unsigned char data_default[defbufsize], *databuf= data_default; static unsigned int datasize= defbufsize; /* Row buffer size to be used by WQCADC */ #define rowsize 1024 /* Define various constants */ #define maxcgmstr 257 #define mask_1_bit 1 #define mask_2_bits 3 #define mask_4_bits 15 #define mask_5_bits 31 #define mask_7_bits 127 #define mask_8_bits 255 #define mask_15_bits 32767 #define mask_16_bits 65535 #define byte_size 8 /* This flag gets set to true if output is to stdout. */ static int pipe_flag= 0; /* Storage for coord-to-pixel conversion factors and window and clip limits. */ static float xpxl_scale, ypxl_scale, xpxl_shift, ypxl_shift, pxl_vdc=1.0; static float wcd_xmin=0.0, wcd_xmax=1.0, wcd_ymin=0.0, wcd_ymax=1.0; /* Storage for world coordinate limits requested via SETWCD (equal * to the wcd_ values only if the device is square). */ static float req_xmin=0.0, req_xmax=1.0, req_ymin=0.0, req_ymax=1.0; /* Macros to check the existence of a function pointer, and invoke it if found. gbl_ret holds the return code. */ static int gbl_ret; #define check_do(group,op) if ( group[(int) op] ) \ gbl_ret= ( *group[(int) op] ) /* Macro to assign an error return value based on a driver return code */ #define err_chk( ierr ) switch (gbl_ret) { \ case 0: error("Driver error, exiting."); break; \ case 2: ierr= 1; break; \ default:; } /* Byte ordering information: Note that this may be machine dependent! */ /* The packword macro puts a CGM word into a char array in CGM order */ #define packword(word,pbyte) { *pbyte++=(word)>>8; *pbyte++=(word); } /* Macro and associated storage to pack a CGM 32-bit fixed-point value */ static unsigned int fxwrd1, fxwrd2; #define packfix(fval,pbyte) \ if (fval>=0.0) \ if (fval<32768.0) { fxwrd1= (int)fval; fxwrd2= (int)((fval-fxwrd1)*65536.0);}\ else {fxwrd1= mask_15_bits; fxwrd2= mask_16_bits;} \ else if (fval>=-32768.0) { fxwrd1= (((int)(-fval+.99999)) ^ mask_16_bits)+1; \ fxwrd2= (int)((fval + ((int)(-fval+.99999)))*65536.0);} \ else {fxwrd1= 1 << 15; fxwrd2= 0;}; \ packword(fxwrd1,pbyte); packword(fxwrd2,pbyte); /* Macros to implement packing of data for arbitrary precision cell arrays */ /* Add an arbitrary precision color value, byte aligned or not */ /* in should be an unsigned integer at least precision bits long */ /* ptr points to unsigned chars, initially zero filled */ #define mcr_ptcv(ptr, precision, in, bit) switch (precision){ \ case 32: *ptr++ = ( in & (mask_8_bits << 24) ) >> 24; \ case 24: *ptr++ = ( in & (mask_8_bits << 16) ) >> 16; \ case 16: *ptr++ = ( in & (mask_8_bits << 8) ) >> 8; \ case 8: *ptr++ = ( in & mask_8_bits ); break; \ case 4: *ptr = *ptr | ((in & mask_4_bits) << (4-bit)); bit= bit+4; \ if (bit == 8) { bit = 0; ++ptr; }; break; \ case 2: *ptr = *ptr | ((in & mask_2_bits) << (6-bit)); bit= bit+2; \ if (bit == 8) { bit = 0; ++ptr; }; break; \ case 1: *ptr = *ptr | ((in & mask_1_bit) << (7-bit)); bit= bit+1; \ if (bit == 8) { bit = 0; ++ptr; }; }; /* Add a 2-octet integer, byte aligned or not */ /* in should be an unsigned integer of at least 16 bits precision*/ /* ptr points to unsigned chars, initially zero filled */ #define mcr_ptei(ptr,in,bit) switch (bit) { \ case 0: *ptr++= (in >> 8) & mask_8_bits; \ *ptr++= in & mask_8_bits; break; \ case 1: *ptr= *ptr | ((in >> 9) & mask_8_bits); ptr++; \ *ptr++= (in >> 1) & mask_8_bits; *ptr= (in << 7) & mask_8_bits; break; \ case 2: *ptr= *ptr | ((in >> 10) & mask_8_bits); ptr++; \ *ptr++= (in >> 2) & mask_8_bits; *ptr= (in << 6) & mask_8_bits; break; \ case 3: *ptr= *ptr | ((in >> 11) & mask_8_bits); ptr++; \ *ptr++= (in >> 3) & mask_8_bits; *ptr= (in << 5) & mask_8_bits; break; \ case 4: *ptr= *ptr | ((in >> 12) & mask_8_bits); ptr++; \ *ptr++= (in >> 4) & mask_8_bits; *ptr= (in << 4) & mask_8_bits; break; \ case 5: *ptr= *ptr | ((in >> 13) & mask_8_bits); ptr++; \ *ptr++= (in >> 5) & mask_8_bits; *ptr= (in << 3) & mask_8_bits; break; \ case 6: *ptr= *ptr | ((in >> 14) & mask_8_bits); ptr++; \ *ptr++= (in >> 6) & mask_8_bits; *ptr= (in << 2) & mask_8_bits; break; \ case 7: *ptr= *ptr | ((in >> 15) & mask_8_bits); ptr++; \ *ptr++= (in >> 7) & mask_8_bits; *ptr= (in << 1) & mask_8_bits; }; /* PROCEDURE DECLARATIONS */ static int cgmfree ( char *ptr ); void csetdev ( char *name, int *ierr ); static unsigned int ibufsz ( int *image, int *nxdim, int *nydim, int *prec, int *mode ); static unsigned int pbufsz ( unsigned char *image, int *nxdim, int *nydim, int *prec, int *mode ); void stcpnm ( char *picname, int *ierr ); void wrbegp ( int *ierr ); void wrbgpb ( int *ierr ); void wrcopn ( char *fname, int *ierr ); void wrendp ( int *ierr ); void wrtcla ( int *image, int *nxdim, int *nydim, float *xp, float *yp, float *xq, float *yq, float *xr, float *yr, int *ierr ); void wrtend ( int *ierr ); void wrtopn ( string_descriptor fnamedesc, int *ierr INTSTRINGLENGTH ); void wrttxt ( char *txtstr, float *x, float *y, int *ierr ); /* Get an arbitrary precision color value, byte aligned or not */ /* ptr should point to an unsigned char */ #define mcr_gtcv(ptr, precision, out, bit) out = 0; switch (precision){ \ case 32: out = *ptr++; \ case 24: out = (out << byte_size) | (*ptr++ & 255); \ case 16: out = (out << byte_size) | (*ptr++ & 255); \ case 8: out = (out << byte_size) | (*ptr++ & 255); break; \ case 4: out= ( (*ptr >> (4-bit)) & 15 ); bit= bit + 4; \ if (bit == 8) { bit = 0; ++ptr; }; break; \ case 2: out= ( (*ptr >> (6-bit)) & 3 ); bit= bit + 2; \ if (bit == 8) { bit = 0; ++ptr; }; break; \ case 1: out= ( (*ptr >> (7-bit)) & 1 ); bit= bit + 1; \ if (bit == 8) { bit = 0; ++ptr; }; } \ igtmem(psz) /* This routine returns a pointer to available memory; it is included for the benefit of FORTRAN calling programs. */ int *psz; { if (debugmode) fprintf(stderr," IGTMEM: allocating %d bytes.\n",*psz); return((int) malloc( (unsigned int) *psz )); } ifrmem(pmem) /* This routine frees previously allocated memory based on a pointer; it is included for the benefit of FORTRAN calling programs. */ char **pmem; { if (debugmode) fprintf(stderr," IFRMEM: freeing memory.\n"); return(cgmfree(*pmem)); } static int cgmfree ( char *ptr ) /* This is a portable version of the 'free' routine */ { #ifdef VMS return( free(ptr) ); #else (void) free(ptr); return(0); #endif } static void error(errstr) char *errstr; /* This routine prints an error message in a portable way */ { #ifdef VMS perror(errstr); #else fprintf(stderr,errstr); fprintf(stderr,"\n"); #endif (void) exit(2); } /* This routine converts an x world coordinate to a device (integer) coordinate. */ static int x_rescale(val) float val; { return( (int) xpxl_scale*( val + xpxl_shift ) ); } /* This routine converts an y world coordinate to a device (integer) coordinate. */ static int y_rescale(val) float val; { return( (int) ypxl_scale*( val + ypxl_shift ) ); } /* This routine converts an x world coordinate to a device (integer) coordinate, restricting the result to within the clipping boundaries. */ static int xpxl(val) float val; { return( x_rescale( mcr_bound( val, wcd_xmin, wcd_xmax ) ) ); } /* This routine converts a y world coordinate to a device (integer) coordinate, restricting the result to within the clipping boundaries. */ static int ypxl(val) float val; { return( y_rescale( mcr_bound( val, wcd_ymin, wcd_ymax ) ) ); } /* This routine checks to see if sufficient data buffer memory is available, allocating more as necessary. */ static void checkbufsize(newsize) unsigned int newsize; { char msgbuf[256]; if ( newsize > datasize ) { if (debugmode) fprintf(stderr, " checkbufsize: expanding data buffer to %d chars.\n", newsize); if (databuf == data_default) { if ( ( databuf= (unsigned char *) malloc( (unsigned int)newsize ) ) == 0 ) { (void) sprintf(msgbuf, " CHECKBUFSIZE: Error allocating %d chars of data buffer memory; exiting.", newsize); error(msgbuf); } } else { if ( ( databuf= (unsigned char *) realloc( databuf, (unsigned int)newsize ) ) == 0 ) { (void) sprintf(msgbuf, " CHECKBUFSIZE: Error increasing data buffer memory to %d chars; exiting.", newsize); error(msgbuf); } }; datasize= newsize; }; } void wrtimg(image,nxdim,nydim,fnamedesc STRINGLENGTH) int *image,*nxdim,*nydim; char *fnamedesc; DEFSTRINGLENGTH /* This section of code is intended to write an integer array into a CGM metafile Cell Array, with all the appropriate trimmings. The integers in image are to be between 0 and 255; the dimensions of image are *nxdim and *nydim. */ { int tierr; float one= 1.0, zero= 0.0; if (debugmode) { fprintf(stderr," wrtimg: \n"); fprintf(stderr," nxdim: %d, nydim: %d \n",*nxdim,*nydim); fprintf(stderr," image: %d %d %d %d ...\n", *image,*(image+1),*(image+2),*(image+3)); }; wrtopn(fnamedesc,&tierr STRINGLENGTH ); wrbegp(&tierr); wrbgpb(&tierr); wrtcla(image,nxdim,nydim,&zero,&one,&one,&zero,&one,&one,&tierr); wrendp(&tierr); wrtend(&tierr); } static char *getstring(strdesc STRINGLENGTH) string_descriptor strdesc; DEFSTRINGLENGTH /* This routine finds a string in the supplied descriptor */ { static char stringcopy[maxcgmstr]="\0"; int ichar; #ifdef VMS if (strdesc->dsc$b_class != DSC$K_CLASS_S) { fprintf(stderr, " Wrong descriptor class in GETSTRING: %d\n", strdesc->dsc$b_class); stringcopy[0]= '\0'; }; if (strdesc->dsc$w_length >= maxcgmstr) { fprintf(stderr," Long string truncated in GETSTRING.\n"); (void) strncpy(stringcopy, strdesc->dsc$a_pointer,maxcgmstr-1); stringcopy[maxcgmstr-1]='\0'; } else { (void) strncpy(stringcopy, strdesc->dsc$a_pointer,strdesc->dsc$w_length); stringcopy[strdesc->dsc$w_length]='\0'; }; #endif #ifdef CRAY /* Note that the Cray version of this routine truncates trailing blanks */ if ( _fcdlen(strdesc) >= maxcgmstr ) { fprintf(stderr," Long string truncated in GETSTRING.\n"); (void) strncpy(stringcopy,_fcdtocp(strdesc),maxcgmstr-1); stringcopy[maxcgmstr-1]='\0'; } else { strncpy(stringcopy,_fcdtocp(strdesc),_fcdlen(strdesc)); stringcopy[_fcdlen(strdesc)]= '\0'; }; for (ichar= strlen(stringcopy)-1;(stringcopy[ichar]==' ')&&(ichar>=0); ichar--) stringcopy[ichar]= '\0'; #endif #ifdef USE_UNIX /* For this version of getstring, the macro STRINGLENGTH translates to * ",stringlength", which should contain the string length. Note that * this version truncates trailing blanks. */ if (stringlength >= maxcgmstr) { fprintf(stderr," Long string truncated in GETSTRING.\n"); (void) strncpy(stringcopy,strdesc,maxcgmstr-1); stringcopy[maxcgmstr-1]='\0'; } else { strncpy(stringcopy,strdesc,stringlength); stringcopy[stringlength]= '\0'; }; for (ichar= strlen(stringcopy)-1;(stringcopy[ichar]==' ')&&(ichar>=0); ichar--) stringcopy[ichar]= '\0'; #endif #ifdef _IBMR2 /* For this version of getstring, the macro STRINGLENGTH translates to * ",stringlength", which should contain the string length. Note that * this version truncates trailing blanks. */ if (stringlength >= maxcgmstr) { fprintf(stderr," Long string truncated in GETSTRING.\n"); (void) strncpy(stringcopy,strdesc,maxcgmstr-1); stringcopy[maxcgmstr-1]='\0'; } else { strncpy(stringcopy,strdesc,stringlength); stringcopy[stringlength]= '\0'; }; for (ichar= strlen(stringcopy)-1;(stringcopy[ichar]==' ')&&(ichar>=0); ichar--) stringcopy[ichar]= '\0'; #endif #ifdef ardent if ( strdesc->length >= maxcgmstr ) { fprintf(stderr," Long string truncated in GETSTRING.\n"); (void) strncpy(stringcopy,strdesc->addr,maxcgmstr-1); stringcopy[maxcgmstr-1]= '\0'; } else { (void) strcpy(stringcopy,strdesc->addr); stringcopy[strdesc->length]= '\0'; }; #endif #ifdef __hpux /* For this version of getstring, the macro STRINGLENGTH translates to * ",stringlength", which should contain the string length. Note that * this version truncates trailing blanks. */ if (stringlength >= maxcgmstr) { fprintf(stderr," Long string truncated in GETSTRING.\n"); (void) strncpy(stringcopy,strdesc,maxcgmstr-1); stringcopy[maxcgmstr-1]='\0'; } else { strncpy(stringcopy,strdesc,stringlength); stringcopy[stringlength]= '\0'; }; for (ichar= strlen(stringcopy)-1;(stringcopy[ichar]==' ')&&(ichar>=0); ichar--) stringcopy[ichar]= '\0'; #endif if (debugmode) fprintf(stderr," getstring: returning <%s>.\n", stringcopy); return(stringcopy); } static int devinit(fname) char *fname; /* This routine initializes the device driver interface. It does so by simulating the environment provided by gplot.c in the GPlot software. */ { extern int parse_cline(), dev_setup(), consult_device(), open_output_file(); int save_debug; /* Some booleans */ int to_screen, /* device is writing to screen */ do_list; /* listing is to be generated */ /* String to hold device default filename */ static char def_name[max_str]= ""; /* String to hold simulated command line */ char cmd_line[max_str]; /* Simulated argv, argc */ int argc; static char arg1[]= "gplot", arg2[max_str], arg3[max_str], arg4[max_str], arg5[max_str], *argv[]= { arg1, arg2, arg3, arg4, arg5 }; if (debugmode) fprintf(stderr,"devinit: fname=<%s>.\n",fname); /* Fill out the command line, and argv */ #ifdef VMS if (pipe_flag) { sprintf(cmd_line,"gpt/nindex/dev=%s dummy",devnam); sprintf(arg2,"/nindex"); sprintf(arg3,"/dev=%s",devnam); sprintf(arg4,"dummy"); arg5[0]= '\0'; argc= 4; } else { sprintf(cmd_line,"gpt/dev=%s dummy",devnam); sprintf(arg2,"/dev=%s",devnam); sprintf(arg3,"dummy"); arg4[0]= '\0'; arg5[0]= '\0'; argc= 3; } #else if (pipe_flag) { /* turn off block index generation */ sprintf(cmd_line,"gplot -N -d%s dummy %s",devnam,fname); sprintf(arg2,"-N"); sprintf(arg3,"-d%s",devnam); sprintf(arg4,"dummy"); sprintf(arg5,"%s",fname); argc= 5; } else { sprintf(cmd_line,"gplot -d%s dummy %s",devnam,fname); sprintf(arg2,"-d%s",devnam); sprintf(arg3,"dummy"); sprintf(arg4,"%s",fname); arg5[0]= '\0'; argc= 4; } #endif /* Parse the 'command line', initializing options. This will turn debugging off if it is on, so save and reset it. */ save_debug= debugmode; if ( !parse_cline(cmd_line, argc, argv, &to_screen, &do_list, &dev_info, cmd_opt) ) error("devinit: simulated command line didn't parse."); debugmode= save_debug; /* Initialize the output device */ if ( !dev_setup(cmd_opt, &dev_info, &glbl1, &glbl2, &glbl3, &glbl5, delim, mfdesc, pdesc, mfctrl, gprim, attr, escfun, extfun, ctrl, &argc, argv) ) error("devinit: device initialization failed."); consult_device(cmd_opt, &dev_info); /* Install text emulator if device can't handle all types of text */ if ( !( (dev_info.capability & stroke_text) && (dev_info.capability & char_text) && (dev_info.capability & string_text) ) ) gprim[(int)Text]= textem_create( attr, gprim, &dev_info, &glbl2, &glbl5 ); /* Open the output file (default name may be set by driver). */ if ( cmd_opt[(int) out_name].set ) strncpy(def_name, cmd_opt[(int) out_name].val.str,max_str); else { #ifdef VMS strncpy(def_name, dev_info.out_name, max_str); #endif }; if ( !open_output_file(fname, def_name, do_list, &dev_info) ) error("devinit: unable to open output file"); /* All possible errors have already been processed. */ return(1); } static void set_extents() /* This routine sets the VDC extent appropriately for the aspect ratio of the device. The world coordinate boundaries are then set appropriately to that VDC extent. */ { int i; if (debugmode) fprintf(stderr," set_extents:\n"); /* Reset VDC extent to defaults, which are square. */ for (i=0; i<4; i++) { glbl2.vdc_extent.i[i]= dflt2.vdc_extent.i[i]; glbl2.vdc_extent.r[i]= dflt2.vdc_extent.r[i]; } /* Adjust the VDC extent for current device size. */ if ( dev_info.x_size >= dev_info.y_size ) { if ( glbl1.vdc_type == vdc_int) { glbl2.vdc_extent.i[2]= glbl2.vdc_extent.i[0] + ( dev_info.x_size/dev_info.y_size ) * ( glbl2.vdc_extent.i[2]-glbl2.vdc_extent.i[0] ); glbl2.vdc_extent.r[2]= glbl2.vdc_extent.i[2] / pxl_vdc; } else { glbl2.vdc_extent.r[2]= glbl2.vdc_extent.r[0] + ( dev_info.x_size/dev_info.y_size ) * ( glbl2.vdc_extent.r[2]-glbl2.vdc_extent.r[0] ); glbl2.vdc_extent.i[2]= glbl2.vdc_extent.r[2] * pxl_vdc; } } else { if ( glbl1.vdc_type == vdc_int) { glbl2.vdc_extent.i[3]= glbl2.vdc_extent.i[1] + ( dev_info.y_size/dev_info.x_size ) * ( glbl2.vdc_extent.i[3]-glbl2.vdc_extent.i[1] ); glbl2.vdc_extent.r[3]= glbl2.vdc_extent.i[3] / pxl_vdc; } else { glbl2.vdc_extent.r[3]= glbl2.vdc_extent.r[1] + ( dev_info.y_size/dev_info.x_size ) * ( glbl2.vdc_extent.r[3]-glbl2.vdc_extent.r[1] ); glbl2.vdc_extent.i[3]= glbl2.vdc_extent.r[3] * pxl_vdc; } } /* If CGM state is appropriate, inform driver of change. If it is * not, it should pick it up when the next begin picture occurs. */ if (cgmstate==2) check_do( pdesc, vdcExtent)( glbl2.vdc_extent.i, glbl2.vdc_extent.r ); /* Set world coordinate extents appropriate for VDC extent. This is * computed from the req_ global extents, based on the assumption * that those values are appropriate if the display is square. */ if (dev_info.x_size >= dev_info.y_size) { wcd_xmin= req_xmin; wcd_xmax= req_xmin + (dev_info.x_size/dev_info.y_size)*(req_xmax-req_xmin); wcd_ymin= req_ymin; wcd_ymax= req_ymax; } else { wcd_xmin= req_xmin; wcd_xmax= req_xmax; wcd_ymin= req_ymin; wcd_ymax= req_ymin + (dev_info.y_size/dev_info.x_size)*(req_ymax-req_ymin); } } static void setscale() /* This routine sets the scaling factors used to convert floating point coords to pxl integers. It does so by finding a region of the same aspect ratio as the VDC extent within the device output field, placing the region such that the lower left corner corresponds with the lower left corner of the device output field, and taking appropriate ratios. This is done separately for the four possible relative aspect ratios of the device and VDC extent. The goal is to come up with a factor that will map the coordinate range given by the wcd_ limits to exactly fill the device pixel range in the direction that the VDC extent fits most snugly into the device display area. */ { float vdcxsiz, vdcysiz; int devxpxl, devypxl; if (debugmode) fprintf(stderr," setscale: setting scale.\n"); devxpxl= dev_info.pxl_in * dev_info.x_size; devypxl= dev_info.ypxl_in * dev_info.y_size; if (glbl1.vdc_type == vdc_int) { vdcxsiz= glbl2.vdc_extent.i[2] - glbl2.vdc_extent.i[0]; vdcysiz= glbl2.vdc_extent.i[3] - glbl2.vdc_extent.i[1]; } else { vdcxsiz= glbl2.vdc_extent.r[2] - glbl2.vdc_extent.r[0]; vdcysiz= glbl2.vdc_extent.r[3] - glbl2.vdc_extent.r[1]; }; if ( (dev_info.x_size/dev_info.y_size) <= (vdcxsiz/vdcysiz) ) { /* It touches both edges in the x direction */ xpxl_scale= devxpxl / (wcd_xmax-wcd_xmin); xpxl_shift= -wcd_xmin; ypxl_scale= (dev_info.x_size/dev_info.y_size)* (vdcysiz/vdcxsiz)*devypxl / (wcd_ymax-wcd_ymin); ypxl_shift= -wcd_ymin; } else { /* It touches both edges in the y direction */ xpxl_scale= (dev_info.y_size/dev_info.x_size)* (vdcxsiz/vdcysiz)*devxpxl / (wcd_xmax-wcd_xmin); xpxl_shift= -wcd_xmin; ypxl_scale= devypxl / (wcd_ymax-wcd_ymin); ypxl_shift= -wcd_ymin; }; pxl_vdc= (float)xpxl_scale * (wcd_xmax-wcd_xmin)/vdcxsiz; } void setwcd(xmin,ymin,xmax,ymax,ierr) float *xmin, *ymin, *xmax, *ymax; int *ierr; /* SETWCD sets the minimum and maximum boundaries of the world coordinate system. */ { if (debugmode) fprintf(stderr, "SETWCD: x range %f to %f\n y range %f to %f\n", *xmin, *xmax, *ymin, *ymax); if (*xmin == *xmax) { fprintf(stderr, "SETWCD - Warning!\n"); fprintf(stderr, " XMIN=XMAX; call ignored.\n"); fprintf(stderr, " XMIN = %f\n",*xmin); fprintf(stderr, " XMAX = %f\n",*xmax); *ierr= 1; return; } if (*ymin == *ymax) { fprintf(stderr, "SETWCD - Warning!\n"); fprintf(stderr, " YMIN=YMAX; call ignored.\n"); fprintf(stderr, " YMIN = %f\n",*ymin); fprintf(stderr, " YMAX = %f\n",*ymax); *ierr= 1; return; } req_xmin= *xmin; req_ymin= *ymin; req_xmax= *xmax; req_ymax= *ymax; /* If the system has been initialized, rescale now. If not, the new values will be used when the system is initialized. */ if ( cgmstate != 0 ) { set_extents(); /* to transfer req_ values to wcd_ variables */ setscale(); } } void tgldbg(ierr) int *ierr; /* This routine toggles debugging, turning it on if it is off and vice versa. */ { /* This message printed if debugging is being turned off */ if (debugmode) fprintf(stderr," tgldbg: debugging off\n"); debugmode= !debugmode; /* This message printed if debugging is being turned on */ if (debugmode) fprintf(stderr," tgldbg: debugging on\n"); } void setdev(dev,ierr STRINGLENGTH) string_descriptor dev; int *ierr; DEFSTRINGLENGTH /* This routine sets the output device. */ { char *name; name= getstring(dev STRINGLENGTH); if (debugmode) fprintf(stderr," setdev: setting device to %s\n",name); if (cgmstate!=0) { fprintf(stderr, " CGM in wrong state for SETDEV; call ignored.\n"); *ierr= 1; return; } csetdev(name,ierr); } void csetdev ( char *name, int *ierr ) { /* This routine sets the output device. */ if (debugmode) fprintf(stderr," csetdev: device set to %s\n",name); strncpy(devnam,name,devnamlen); } void wrtopn ( string_descriptor fnamedesc, int *ierr INTSTRINGLENGTH ) { /* This section of code opens a CGM metafile for writing, and writes a begin metafile command followed by a metafile version command. The 'state' variable is set appropriately. */ char *getstring(),*fname; fname= getstring(fnamedesc STRINGLENGTH); if (fname == 0 || strlen(fname) == 0) { fprintf(stderr, " Bad fname in call to WRTOPN; using default\n"); fname= "image"; }; if (debugmode) fprintf(stderr," wrtopn: fname: %s\n",fname); if (cgmstate!=0) { fprintf(stderr, " CGM in wrong state for WRTOPN; call ignored.\n"); *ierr= 1; return; } wrcopn(fname,ierr); } void wrcopn ( char *fname, int *ierr ) { /* This section of code opens a CGM metafile for writing, and writes a begin metafile command followed by a metafile version command. The 'state' variable is set appropriately. This version differs from wrtopn in that the file name is taken as a C character string rather than a fortran descriptor. If the file name given is "-", output will be directed to stdout. */ extern s_defaults(), rs_defaults(); static int element_list[2]= {-1, 1}; #ifdef VMS static char stdout_equiv_string[]= "SYS$OUTPUT:"; #else static char stdout_equiv_string[]= ""; #endif if (fname == 0 || strlen(fname) == 0) { fprintf(stderr, " Bad fname in call to WRCOPN; using default\n"); fname= "image"; }; if (debugmode) fprintf(stderr," wrcopn: fname: %s\n",fname); if (cgmstate!=0) { fprintf(stderr, " CGM in wrong state for WRCOPN; call ignored.\n"); *ierr= 1; return; } /* The following implements the convention that an fname of '-' means the output should go to stdout. Unfortunately the signal that must be sent to the underlieing GPlot software to accomplish this is operating system dependent. The dependency is accomodated by the ifdef at the top of this routine. We also set a flag to properly handle PSC CGM index block generation when writing to stdout. */ if ( !strncmp( fname, "-", 1 ) ) { fname= stdout_equiv_string; pipe_flag= 1; } else pipe_flag= 0; /* We must initialize the CGM attribute structs and the device. Unfortunately they are interdependent, so we make a partial set of definitions, then call the routines again to get everything straightened out. */ /* Set up the default attributes (and the global color table) */ s_defaults(&glbl1,&dflt2,&dflt3,&dflt5,&glbl5,1.0); /* Set global attributes equal to default attributes */ rs_defaults(&glbl1, &glbl2, &glbl3, &glbl5, &dflt2, &dflt3, &dflt5, 1.0 ); /* Initialize the device */ if ( !devinit(fname) ) error("Unable to initialize device; exiting."); /* Set the coordinate scaling factors */ set_extents(); setscale(); /* Reinitialize the default attributes (and the global color table) */ s_defaults(&glbl1,&dflt2,&dflt3,&dflt5,&glbl5,pxl_vdc); /* Reset global attributes equal to default attributes */ rs_defaults(&glbl1, &glbl2, &glbl3, &glbl5, &dflt2, &dflt3, &dflt5, pxl_vdc ); /* Reset the extents to undo change to VDC extent by rs_defaults */ set_extents(); /* Write begin metafile, metafile version, metafile descriptor, and metafile element list elements. */ check_do( delim, B_Mf )(fname,"CGMGEN","CGMGEN"); err_chk( *ierr ); check_do( mfdesc, MfVersion )(1); err_chk( *ierr ); check_do( mfdesc, MfDescrip)("PSC CGM 3.0"); err_chk( *ierr ); check_do( mfdesc, MfElList)(1, element_list); err_chk( *ierr ); cgmstate= 1; } void wrmxci(maxclrindx,ierr) int *maxclrindx,*ierr; /* This routine writes a 'max color index' command to the default metafile, if the cgm state is appropriate. */ { float *clrptr, *tblend; char msgbuf[256]; if (debugmode) fprintf(stderr," wrmxci: max color index= %d\n", *maxclrindx); if (cgmstate!=1) { fprintf(stderr, " CGM in wrong state for WRMXCI; call ignored.\n"); *ierr= 1; return; } /* If the global and default color tables are not this big, reallocate them so that they will be. The new memory locations above the previously-set color indices are initialized to zeros. */ if (*maxclrindx > glbl1.max_c_index) { glbl5.ctab= (float *) realloc( (char *)glbl5.ctab, 3 * sizeof(float) * (*maxclrindx+1) ); if (!glbl5.ctab) { sprintf(msgbuf, "Error increasing color table size to 3 * %d floats; exiting\n", *maxclrindx+1); error(msgbuf); } dflt5.ctab= (float *) realloc( (char *)dflt5.ctab, 3 * sizeof(float) * (*maxclrindx+1) ); if (!glbl5.ctab) { sprintf(msgbuf, "Error increasing default color table size to 3 * %d floats; exiting\n", *maxclrindx+1); error(msgbuf); } tblend= glbl5.ctab + 3 * (*maxclrindx+1); for ( clrptr= glbl5.ctab + 3 * (glbl1.max_c_index+1); clrptr < tblend; clrptr++ ) *clrptr= 0.0; tblend= dflt5.ctab + 3 * (*maxclrindx+1); for ( clrptr= dflt5.ctab + 3 * (glbl1.max_c_index+1); clrptr < tblend; clrptr++ ) *clrptr= 0.0; } /* Set the new max index, and (possibly) make the driver call. */ glbl1.max_c_index= *maxclrindx; check_do( mfdesc, MaxCInd )(*maxclrindx); err_chk( *ierr ); } void wrbegp ( int *ierr ) { /* This routine writes a 'begin picture' command to the default metafile, setting the CGM state appropriately. */ extern rs_defaults(); if (debugmode) fprintf(stderr," wrbegp\n"); if (cgmstate!=1) { fprintf(stderr, " CGM in wrong state for WRBEGP; call ignored.\n"); *ierr= 1; return; } /* Reset the coordinate scaling factors */ setscale(); /* Reset all defaults */ rs_defaults(&glbl1, &glbl2, &glbl3, &glbl5, &dflt2, &dflt3, &dflt5, pxl_vdc ); /* Write begin picture element. */ check_do( delim, B_Pic )(picture_name); err_chk( *ierr ); set_extents(); cgmstate= 2; /* The driver call may change device size (as window resizes * are detected by the driver), so reset vdc and world * coordinate extents. */ set_extents(); } void stpcnm(picnamedesc,ierr STRINGLENGTH) string_descriptor picnamedesc; int *ierr; DEFSTRINGLENGTH /* This routine allows the user to set the picture name from Fortran */ { char *getstring(),*picname; picname= getstring(picnamedesc STRINGLENGTH); if (picname == 0 || strlen(picname) == 0) { fprintf(stderr, " Bad picname in call to STPCNM; name not changed\n"); *ierr= 1; }; if (debugmode) fprintf(stderr," stpcnm: picname: %s\n",picname); stcpnm(picname,ierr); } void stcpnm ( char *picname, int *ierr ) { /* This routine allows the user to set the picture name from C */ if (picname == 0 || strlen(picname) == 0) { fprintf(stderr, " Bad picname in call to STCPNM; name not changed\n"); *ierr= 1; }; if (debugmode) fprintf(stderr," stcpnm: picname: %s\n",picname); strncpy( picture_name, picname, maxpicnamelength - 1 ); } void wrbgpb ( int *ierr ) { /* This routine writes a 'begin picture body' command to the default metafile, setting the CGM state appropriately. */ if (debugmode) fprintf(stderr," wrbgpb\n"); if (cgmstate!=2) { fprintf(stderr, " CGM in wrong state for WRBGPB; call ignored.\n"); *ierr= 1; return; } /* Increment the page number */ pgnum++; /* Reset the coordinate scaling factors, just in case the driver * changed some values since the begin_picture call. */ setscale(); check_do( delim, B_Pic_Body )("", 0, 0, 0.0, glbl2.back_col.red, glbl2.back_col.green, glbl2.back_col.blue, pgnum, (int)(dev_info.pxl_in * dev_info.x_size), (int)(dev_info.ypxl_in * dev_info.y_size)); err_chk( *ierr ); cgmstate= 3; } void wrendp ( int *ierr ) { /* This routine writes an 'end picture' command to the default metafile, setting the CGM state appropriately. */ if (debugmode) fprintf(stderr," wrendp\n"); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRENDP; call ignored.\n"); *ierr= 1; return; } check_do( delim, E_Pic )(1); err_chk( *ierr ); cgmstate= 1; } void wrtend ( int *ierr ) { /* This routine writes an 'end metafile' command to the default metafile, flushing buffers and setting the CGM state appropriately. */ extern close_up(); if (debugmode) fprintf(stderr," wrtend\n"); if (cgmstate!=1) { fprintf(stderr, " CGM in wrong state for WRTEND; call ignored.\n"); *ierr= 1; return; } check_do( delim, E_Mf )(pgnum); err_chk( *ierr ); close_up(0); cgmstate= 0; } void wrtcla ( int *image, int *nxdim, int *nydim, float *xp, float *yp, float *xq, float *yq, float *xr, float *yr, int *ierr ) { /* This routine writes a CGM cell array, if the CGM state is appropriate. The color index values are assumed to be integers between 0 and 255 inclusive. The dimensions are *nxdim and *nydim respectively, and (*xp,*yp) and (*xq,*yq) are the *real number* coordinates (between 0.0 and 1.0 inclusive) of the starting and ending corners of the area into which the cell array is mapped. The first scan line is to be written along the vector from (*xp,*yp) to (*xr,*yr). */ unsigned char *bufcpy; int *imagecopy, odd_row_flag, p[2], q[2], r[2]; unsigned int ibyte, jbyte, tot_buf_sz; if (debugmode) fprintf(stderr," wrtcla: nxdim= %d; nydim= %d\n", *nxdim,*nydim); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTCLA; call ignored.\n"); *ierr= 1; return; } if (glbl2.c_s_mode != i_c_mode) { fprintf(stderr, " Color mode not indexed in WRTCLA; call ignored.\n"); *ierr= 1; return; } p[0]= xpxl(*xp); p[1]= ypxl(*yp); q[0]= xpxl(*xq); q[1]= ypxl(*yq); r[0]= xpxl(*xr); r[1]= ypxl(*yr); odd_row_flag= ( *nxdim % 2 != 0 ); if (odd_row_flag) tot_buf_sz= (1+*nxdim)*(*nydim); else tot_buf_sz= (*nxdim)*(*nydim); checkbufsize(tot_buf_sz); bufcpy= databuf; imagecopy= image; for (jbyte=0; jbyte<*nydim; jbyte++) { for (ibyte=0; ibyte<*nxdim; ibyte++) *bufcpy++= *imagecopy++; if (odd_row_flag) *bufcpy++= 0; }; check_do( gprim, Cell_Array ) (p,q,r,*nxdim,*nydim,8,databuf,1,tot_buf_sz); err_chk( *ierr ); } void wrgcla(image,nxdim,nydim,xp,yp,xq,yq,xr,yr,prec,mode,ierr) int *nxdim,*nydim,*image,*prec,*mode,*ierr; float *xp,*yp,*xq,*yq,*xr,*yr; /* This routine writes a general CGM indexed color cell array, if the CGM state is appropriate. The color index values are assumed to be integers between 0 and 2**(*prec) - 1 inclusive. The dimensions are *nxdim and *nydim respectively, and (*xp,*yp) and (*xq,*yq) are the *real number* coordinates (between 0.0 and 1.0 inclusive) of the starting and ending corners of the area into which the cell array is mapped. The first scan line is to be written along the vector from (*xp,*yp) to (*xr,*yr). */ { unsigned char *bufcpy, *obufcpy; unsigned int tot_buf_sz, *imagecopy, inow, ilast, lrun, ibufsz(); int ibyte, jbyte, bit, p[2], q[2], r[2]; extern int em_cell_array(); if (debugmode) fprintf(stderr," wrgcla: nxdim= %d; nydim= %d\n", *nxdim,*nydim); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRGCLA; call ignored.\n"); *ierr= 1; return; } if (glbl2.c_s_mode != i_c_mode) { fprintf(stderr, " Color mode not indexed in WRGCLA; call ignored.\n"); *ierr= 1; return; } if ((*mode<0) || (*mode>1)) { fprintf(stderr, " Invalid cell rep. mode in WRGCLA; call ignored.\n"); *ierr= 1; return; } if ((*prec!=8) && (*prec!=1) && (*prec!=2) && (*prec!=4) && (*prec!=16) && (*prec!=24) && (*prec!=32)) { fprintf(stderr, " Invalid precision in WRGCLA; call ignored.\n"); *ierr= 1; return; } p[0]= xpxl(*xp); p[1]= ypxl(*yp); q[0]= xpxl(*xq); q[1]= ypxl(*yq); r[0]= xpxl(*xr); r[1]= ypxl(*yr); /* Get enough memory to hold the cell array plus header */ tot_buf_sz= ibufsz(image,nxdim,nydim,prec,mode); checkbufsize(tot_buf_sz); bufcpy= databuf; for(ibyte=0; ibyte1)) { fprintf(stderr, " Invalid cell rep. mode in WRPCLA; call ignored.\n"); *ierr= 1; return; } if ((*prec!=8) && (*prec!=1) && (*prec!=2) && (*prec!=4) && (*prec!=16) && (*prec!=24) && (*prec!=32)) { fprintf(stderr, " Invalid precision in WRPCLA; call ignored.\n"); *ierr= 1; return; } p[0]= xpxl(*xp); p[1]= ypxl(*yp); q[0]= xpxl(*xq); q[1]= ypxl(*yq); r[0]= xpxl(*xr); r[1]= ypxl(*yr); /* Get enough memory to hold the cell array plus header */ tot_buf_sz= pbufsz(image,nxdim,nydim,prec,mode); checkbufsize(tot_buf_sz); bufcpy= databuf; for(ibyte=0; ibyte= trigger_size) { tot_buf_sz= tot_buf_sz + size_increment; oldbuf= databuf; checkbufsize(tot_buf_sz); trigger_size= tot_buf_sz - max_row_size; bufcpy= bufcpy - oldbuf + databuf; }; }; /* Write the cell array element */ check_do( gprim, Cell_Array ) (p,q,r,*nxdim,*nydim,8,databuf,0,ldata); else gbl_ret= em_cell_array (p,q,r,*nxdim,*nydim,8,databuf,0,ldata); err_chk( *ierr ); } void wqcadc(nxdim,nydim,xp,yp,xq,yq,xr,yr,ierr) int *nxdim,*nydim,*ierr; float *xp,*yp,*xq,*yq,*xr,*yr; /* This routine writes a CGM cell array, in direct color form, if the CGM state is appropriate. The color values are assumed to lie between 0.0 and 1.0. The dimensions are *nxdim and *nydim respectively, and (*xmn,*ymn) and (*xmx,*ymx) are the *real number* coordinates (between 0.0 and 1.0 inclusive) of the starting and ending corners of the area into which the cell array is mapped. To save buffer space, the actual data is obtained by calling qclarw nydim times. The description of qclarw should be as follows: qclarw(rrow,grow,brow,nxdim,nydim,iy) int *nxdim,*nydim,*iy; float *rrow,*grow,*brow; On return each pointer should point to a pointer to a buffer nxdim floats long, containing the iy'th of nydim rows. iy runs from 1 to nydim, and calls will be made in ascending order. qclarw should return 0 if successful, as per the CGMGEN return code convention. */ { unsigned char *bufcpy,*oldbuf,rnow,gnow,bnow,rlast,glast,blast; float rrow[rowsize],grow[rowsize],brow[rowsize],*rcpy,*gcpy,*bcpy; int lrun, lrow, iy, max_row_size, size_increment, p[2], q[2], r[2]; unsigned int tot_buf_sz, trigger_size, ldata; unsigned int ibyte, jbyte; if (debugmode) fprintf(stderr," wqcadc: nxdim= %d; nydim= %d\n", *nxdim,*nydim); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WQCADC; call ignored.\n"); *ierr= 1; return; } if (glbl2.c_s_mode != d_c_mode) { fprintf(stderr, " Color mode not direct in WQCADC; call ignored.\n"); *ierr= 1; return; } if (*nxdim > rowsize) { fprintf(stderr, " Row length too long in WQCADC; call ignored.\n"); *ierr= 1; return; } /* Set cell array boundary coordinates */ p[0]= xpxl(*xp); p[1]= ypxl(*yp); q[0]= xpxl(*xq); q[1]= ypxl(*yq); r[0]= xpxl(*xr); r[1]= ypxl(*yr); /* Assume a 50% compression; we'll add more space later if needed. We'll ask for more when there isn't enough space for a full row left. An exception is made for very small cell arrays. Each increment is to be 1/2 the original size. */ max_row_size= ( *nxdim % 2 != 0 ) ? 5 * (*nxdim) * 1 : 5 * (*nxdim); tot_buf_sz= 0.5* ( 3*(*nxdim)*(*nydim) ); if (tot_buf_sz < (2 * max_row_size)) { tot_buf_sz= (*nydim) * max_row_size; trigger_size= tot_buf_sz; /* never expand buffer */ } else trigger_size= tot_buf_sz - max_row_size; size_increment= tot_buf_sz / 2 ; checkbufsize(tot_buf_sz); bufcpy= databuf; ldata= 0; for (jbyte=0; jbyte++<*nydim;) { iy= (int) jbyte; /* This section is commented out to avoid an undefined symbol error on loading. To use qclarw, you must uncomment this section. ----------------------------------------------------------------- */ /* if ( (*ierr= qclarw(rrow,grow,brow,nxdim,nydim,&iy)) != 0 ) { fprintf(stderr, "QCLARW reported error code %d on row %d", *ierr,jbyte); fprintf(stderr," command not executed.\n"); return; }; */ /* ------------------------------------------------------------------ Here ends the section that must be uncommented to use qclarw. */ rcpy= rrow; gcpy= grow; bcpy= brow; rlast= float_to_byte(*rcpy); glast= float_to_byte(*gcpy); blast= float_to_byte(*bcpy); lrun= 1; lrow= 0; for (ibyte=0; ibyte++<*nxdim;) { if ((ibyte<*nxdim)||(jbyte<*nydim)) { rnow= float_to_byte(*++rcpy); gnow= float_to_byte(*++gcpy); bnow= float_to_byte(*++bcpy); }; if ((rnow==rlast)&&(gnow==glast)&&(bnow==blast) &&(ibyte<*nxdim)) lrun++; else { packword(lrun,bufcpy); *bufcpy++= rlast; *bufcpy++= glast; *bufcpy++= blast; lrow= lrow+5; lrun= 1; rlast= rnow; glast= gnow; blast= bnow; }; }; if ( lrow % 2 ) { *bufcpy++= 0; lrow++; }; ldata= ldata +lrow; if (ldata >= trigger_size) { tot_buf_sz= tot_buf_sz + size_increment; oldbuf= databuf; checkbufsize(tot_buf_sz); trigger_size= tot_buf_sz - max_row_size; bufcpy= bufcpy - oldbuf + databuf; }; }; /* Write the cell array element */ check_do( gprim, Cell_Array ) (p,q,r,*nxdim,*nydim,8,databuf,0,ldata); err_chk( *ierr ); } void wrctbl(rarray,garray,barray,iclr,nclrs,ierr) int *iclr,*nclrs,*ierr; float *rarray,*garray,*barray; /* This routine writes a CGM color table command, if the CGM state is appropriate. The color table entries are assumed to have values between 0.0 and 1.0 . */ { int i; float *rcopy, *gcopy, *bcopy, *target; if (debugmode) fprintf(stderr," wrctbl: nclrs= %d\n",*nclrs); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRCTBL; call ignored.\n"); *ierr= 1; return; } /* Set the global color table to the given values */ rcopy= rarray; gcopy= garray; bcopy= barray; target= glbl5.ctab + 3*(*iclr); for (i=0; i<*nclrs; i++) { *target++= *rcopy++; *target++= *gcopy++; *target++= *bcopy++; }; /* Send the device the color table info */ check_do( attr, ColTab )(*iclr,*nclrs,glbl5.ctab); err_chk( *ierr ); } void wrftxt(textdesc,x,y,ierr STRINGLENGTH) string_descriptor textdesc; int *ierr; float *x,*y; DEFSTRINGLENGTH /* This routine writes a CGM text command from a Fortran text string, by parsing the string and calling WRTTXT with the result. */ { char *getstring(),*txtstr; txtstr= getstring(textdesc STRINGLENGTH); if (debugmode) fprintf(stderr, " wrftxt: x= %e, y= %e\n text= <%s>\n",*x,*y,txtstr); wrttxt(txtstr,x,y,ierr); } void wrttxt ( char *txtstr, float *x, float *y, int *ierr ) { /* This routine writes a CGM text command, if the CGM state is appropriate. This is a 'final' text command. */ int *pix, *piy; if (debugmode) fprintf(stderr, " wrttxt: x= %e, y= %e\n text= <%s>\n",*x,*y,txtstr); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTTXT; call ignored.\n"); *ierr= 1; return; } if ( clip_markers( 1, x, y, wcd_xmin, wcd_xmax, wcd_ymin, wcd_ymax, x_rescale, y_rescale, &pix, &piy ) ) { check_do( gprim, Text )(*pix,*piy,on,txtstr); err_chk( *ierr ); } } void wtxtpr(prec,ierr) int *ierr; int *prec; /* This routine writes a CGM text precision command, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr," wtxtpr: precision= %d.\n",*prec); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WTXTPR; call ignored.\n"); *ierr= 1; return; } if ((*prec<0)||(*prec>2)) { fprintf(stderr, " Invalid text precision (%d) in WTXTPR; call ignored.\n", *prec); *ierr= 1; return; } glbl5.t_prec= (enum txt_enum) *prec; check_do( attr, TPrec )(glbl5.t_prec); err_chk( *ierr ); } void wrtxts(height,ierr) int *ierr; float *height; /* This routine writes a CGM character height command, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr," wrtxts: height= %e.\n",*height); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTXTS; call ignored.\n"); *ierr= 1; return; } glbl5.c_height= (int)( xpxl_scale*( *height ) ); check_do( attr, CHeight )(glbl5.c_height); err_chk( *ierr ); } void wrtxte(factor,ierr) int *ierr; float *factor; /* This routine writes a CGM character expansion factor command, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr," wrtxte: factor= %f.\n",*factor); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTXTE; call ignored.\n"); *ierr= 1; return; } if (*factor<0.0) { fprintf(stderr, " Invalid character expansion factor (%f) in WRTXTE; call ignored.\n", *factor); *ierr= 1; return; } glbl5.c_exp_fac= *factor; check_do( attr, CExpFac )(glbl5.c_exp_fac); err_chk( *ierr ); } void wtxtsp(spacing,ierr) int *ierr; float *spacing; /* This routine writes a CGM character expansion factor command, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr," wtxtsp: spacing= %f.\n",*spacing); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WTXTSP; call ignored.\n"); *ierr= 1; return; } glbl5.c_space= *spacing; check_do( attr, CSpace )(glbl5.c_space); err_chk( *ierr ); } void wrtxtf(font,ierr) int *font; int *ierr; /* This routine writes a CGM text font command, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr," wrtxtf: font= %d.\n",*font); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTXTF; call ignored.\n"); *ierr= 1; return; } if (*font<1) { fprintf(stderr, " Invalid text font (%d) in WRTXTF; call ignored.\n", *font); *ierr= 1; return; } glbl5.t_f_index= *font; check_do( attr, TFIndex )(glbl5.t_f_index); err_chk( *ierr ); } void wrtxtp(path,ierr) int *ierr; int *path; /* This routine writes a CGM text path command, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr," wrtxtp: path= %d.\n",*path); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTXTP; call ignored.\n"); *ierr= 1; return; } if ((*path<0)||(*path>3)) { fprintf(stderr, " Invalid text path (%d) in WRTXTP; call ignored.\n", *path); *ierr= 1; return; } glbl5.text_path= (enum path_enum) *path; check_do( attr, TPath )(glbl5.text_path); err_chk( *ierr ); } void wrtxto(xu,yu,xb,yb,ierr) int *ierr; float *xu, *yu, *xb, *yb; /* This routine writes a CGM character orientation command, if the CGM state is appropriate. *xu and *yu are the floating-point magnitudes of the x and y components of the character up vector; *xb and *yb are for the character base vector. Only the ratios of the components matter; absolute magnitudes are irrelevant. */ { if (debugmode) fprintf(stderr," wrtxto: up= (%f,%f); base=(%f,%f).\n", *xu,*yu,*xb,*yb); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTXTO; call ignored.\n"); *ierr= 1; return; } /* 0.01 is chosen as an arbitrary scale factor */ glbl5.c_orient.x_up= (int)( 0.01 * *xu * dev_info.x_size * dev_info.pxl_in ); glbl5.c_orient.y_up= (int)( 0.01 * *yu * dev_info.y_size * dev_info.ypxl_in ); glbl5.c_orient.x_base= (int)( 0.01 * *xb * dev_info.x_size * dev_info.pxl_in ); glbl5.c_orient.y_base= (int)( 0.01 * *yb * dev_info.y_size * dev_info.ypxl_in ); check_do( attr, COrient ) ( glbl5.c_orient.x_up, glbl5.c_orient.y_up, glbl5.c_orient.x_base, glbl5.c_orient.y_base ); err_chk( *ierr ); } void wrtxta(hor,ver,cont_hor,cont_ver,ierr) int *ierr; int *hor,*ver; float *cont_hor,*cont_ver; /* This routine writes a CGM text alignment command, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr, " wrtxta: hor= %d, ver= %d, cont_hor= %f, cont_ver= %f.\n", *hor,*ver,*cont_hor,*cont_ver); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTXTA; call ignored.\n"); *ierr= 1; return; } if ((*hor<0)||(*hor>4)) { fprintf(stderr, " Invalid horizontal alignment (%d) in WRTXTA; call ignored.\n", *hor); *ierr= 1; return; } if ((*ver<0)||(*ver>6)) { fprintf(stderr, " Invalid vertical alignment (%d) in WRTXTA; call ignored.\n", *ver); *ierr= 1; return; } glbl5.text_align.hor= (enum hor_align) *hor; glbl5.text_align.ver= (enum ver_align) *ver; glbl5.text_align.cont_hor= *cont_hor; glbl5.text_align.cont_ver= *cont_ver; check_do( attr, TAlign ) ( glbl5.text_align.hor, glbl5.text_align.ver, glbl5.text_align.cont_hor, glbl5.text_align.cont_ver ); err_chk( *ierr ); } void wrtxtc(icolor,ierr) int *icolor,*ierr; /* This routine writes a CGM text color command, if the CGM state is appropriate. */ { float *clrptr; if (debugmode) fprintf(stderr," wrtxtc: icolor= %d.\n",*icolor); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRTXTC; call ignored.\n"); *ierr= 1; return; } if (glbl2.c_s_mode != i_c_mode) { fprintf(stderr, " Color mode not indexed in WRTXTC; call ignored.\n"); *ierr= 1; return; } clrptr= glbl5.ctab + 3*(*icolor); glbl5.text_colour.red= *clrptr++; glbl5.text_colour.green= *clrptr++; glbl5.text_colour.blue= *clrptr; glbl5.text_colour.ind= *icolor; check_do( attr, TColour ) ( glbl5.text_colour.red, glbl5.text_colour.green, glbl5.text_colour.blue, glbl5.text_colour.ind ); err_chk( *ierr ); } void wtxtdc(red,green,blue,ierr) int *ierr; float *red,*green,*blue; /* This routine writes a CGM text color command in direct color form, if the CGM state is appropriate. The color values are assumed to lie between 0.0 and 1.0 */ { if (debugmode) fprintf(stderr," wtxtdc: red=%e; green=%e; blue=%e.\n", *red,*green,*blue); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WTXTDC; call ignored.\n"); *ierr= 1; return; } if (glbl2.c_s_mode != d_c_mode) { fprintf(stderr, " Color mode not direct in WTXTDC; call ignored.\n"); *ierr= 1; return; } /* The index is set to -1 below to make it demonstrably invalid, a GPlot convention. */ glbl5.text_colour.red= *red; glbl5.text_colour.green= *green; glbl5.text_colour.blue= *blue; glbl5.text_colour.ind= -1; check_do( attr, TColour ) ( glbl5.text_colour.red, glbl5.text_colour.green, glbl5.text_colour.blue, glbl5.text_colour.ind ); err_chk( *ierr ); } void wrplin(xarray,yarray,npts,ierr) int *npts,*ierr; float *xarray,*yarray; /* This routine writes a CGM polyline command, if the CGM state is appropriate. */ { int count, *xbuf, *ybuf, *lengths, iplin; if (debugmode) fprintf(stderr," wrplin: npts= %d\n",*npts); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRPLIN; call ignored.\n"); *ierr= 1; return; } /* Copy rescaled coords into buffer. count<0 implies an error. */ count= clip_lines( *npts, xarray, yarray, wcd_xmin, wcd_xmax, wcd_ymin, wcd_ymax, x_rescale, y_rescale, &xbuf, &ybuf, &lengths ); if (count<0) { *ierr= 2; return; } /* Clipping can produce many polylines from one, so we must now do * potentially many calls to the renderer's polyline routine. */ for (iplin=0; iplin= 3) { /* ignore polygons clipped away */ check_do( gprim, Polygon )( *lengths, xbuf, ybuf ); else gbl_ret= em_pgon( *lengths, xbuf, ybuf ); err_chk( *ierr ); } xbuf += *lengths; ybuf += *lengths; lengths++; } } void wrpgnc(icolor,ierr) int *icolor,*ierr; /* This routine writes a CGM fill color command, if the CGM state is appropriate. */ { float *clrptr; if (debugmode) fprintf(stderr," wrpgnc: icolor= %d\n",*icolor); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRPGNC; call ignored.\n"); *ierr= 1; return; } if (glbl2.c_s_mode != i_c_mode) { fprintf(stderr, " Color mode not indexed in WRPGNC; call ignored.\n"); *ierr= 1; return; } clrptr= glbl5.ctab + 3*(*icolor); glbl5.fill_colour.red= *clrptr++; glbl5.fill_colour.green= *clrptr++; glbl5.fill_colour.blue= *clrptr; glbl5.fill_colour.ind= *icolor; check_do( attr, FillColour ) ( glbl5.fill_colour.red, glbl5.fill_colour.green, glbl5.fill_colour.blue, glbl5.fill_colour.ind ); err_chk( *ierr ); } void wpgndc(red,green,blue,ierr) int *ierr; float *red,*green,*blue; /* This routine writes a CGM polygon color command in direct color form, if the CGM state is appropriate. The color values are assumed to lie between 0.0 and 1.0 */ { if (debugmode) fprintf(stderr," wpgndc: red=%e; green=%e; blue=%e.\n", *red,*green,*blue); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WPGNDC; call ignored.\n"); *ierr= 1; return; } if (glbl2.c_s_mode != d_c_mode) { fprintf(stderr, " Color mode not direct in WPGNDC; call ignored.\n"); *ierr= 1; return; } /* The index is set to -1 below to make it demonstrably invalid, a GPlot convention. */ glbl5.fill_colour.red= *red; glbl5.fill_colour.green= *green; glbl5.fill_colour.blue= *blue; glbl5.fill_colour.ind= -1; check_do( attr, FillColour ) ( glbl5.fill_colour.red, glbl5.fill_colour.green, glbl5.fill_colour.blue, glbl5.fill_colour.ind ); err_chk( *ierr ); } void wristl(style,ierr) int *style, *ierr; /* This routine writes a CGM interior style element, if the CGM state is appropriate. */ { if (debugmode) fprintf(stderr," wristl: style= %d.\n",*style); if (cgmstate!=3) { fprintf(stderr, " CGM in wrong state for WRISTL; call ignored.\n"); *ierr= 1; return; } glbl5.int_style= (enum is_enum) *style; check_do( attr, IntStyle )( glbl5.int_style ); err_chk( *ierr ); } void wrtcsm(imode,ierr) int *imode,*ierr; /* This routine writes a CGM color selection mode command, if the CGM state is appropriate. The color_sel_mode flag is set appropriately. */ { if (debugmode) fprintf(stderr," wrtcsm: imode= %d.\n",*imode); if (cgmstate!=2) { fprintf(stderr, " CGM in wrong state for WRTCSM; call ignored.\n"); *ierr= 1; return; } if ((*imode!=0) && (*imode!=1)) { fprintf(stderr, " Color_sel_mode must be 0 or 1 in WRTCSM; call ignored.\n"); *ierr= 1; return; } glbl2.c_s_mode= (enum cs_enum) *imode; check_do( pdesc, ColSelMode )( glbl2.c_s_mode ); err_chk( *ierr ); } void wrbgdc(red,green,blue,ierr) int *ierr; float *red,*green,*blue; /* This routine writes a CGM background color command, if the CGM state is appropriate. The color_sel_mode flag is set appropriately. */ { int ir, ig, ib; if (debugmode) fprintf(stderr," wrbgdc: red=%e; green=%e; blue=%e.\n", *red,*green,*blue); if (cgmstate!=2) { fprintf(stderr, " CGM in wrong state for WRBGDC; call ignored.\n"); *ierr= 1; return; } ir= (int) ((*red) * glbl1.c_v_extent.max[0] + (1.0-(*red)) * glbl1.c_v_extent.min[0]); ig= (int) ((*green) * glbl1.c_v_extent.max[1] + (1.0-(*green)) * glbl1.c_v_extent.min[1]); ib= (int) ((*blue) * glbl1.c_v_extent.max[2] + (1.0-(*blue)) * glbl1.c_v_extent.min[2]); glbl2.back_col.red= *red; glbl2.back_col.green= *green; glbl2.back_col.blue= *blue; /* Set the index zero entry of the color table to the given color */ *(glbl5.ctab)= *red; *(glbl5.ctab+1)= *green; *(glbl5.ctab+2)= *blue; check_do( pdesc, BackCol )( ir, ig, ib ); err_chk( *ierr ); }