PLplot
5.10.0
|
00001 // PLplot xfig device driver. 00002 // 00003 #include "plDevs.h" 00004 00005 #ifdef PLD_xfig 00006 00007 #include "plplotP.h" 00008 #include "drivers.h" 00009 00010 // Device info 00011 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_xfig = "xfig:Fig file:0:xfig:31:xfig\n"; 00012 00013 typedef struct 00014 { 00015 PLINT xold, yold; 00016 00017 PLINT xmin, xmax; 00018 PLINT ymin, ymax; 00019 00020 PLFLT xscale_dev, yscale_dev; 00021 00022 int *buffptr, bufflen; 00023 int count; 00024 int curwid; 00025 int curcol; 00026 int firstline; 00027 long cmap0_pos, cmap1_pos; 00028 int cmap0_ncol, cmap1_ncol; 00029 int offset, offset_inc; 00030 } xfig_Dev; 00031 00032 // Function prototypes 00033 00034 void plD_dispatch_init_xfig( PLDispatchTable *pdt ); 00035 00036 void plD_init_xfig( PLStream * ); 00037 void plD_line_xfig( PLStream *, short, short, short, short ); 00038 void plD_polyline_xfig( PLStream *, short *, short *, PLINT ); 00039 void plD_eop_xfig( PLStream * ); 00040 void plD_bop_xfig( PLStream * ); 00041 void plD_tidy_xfig( PLStream * ); 00042 void plD_state_xfig( PLStream *, PLINT ); 00043 void plD_esc_xfig( PLStream *, PLINT, void * ); 00044 00045 static void flushbuffer( PLStream * ); 00046 00047 // top level declarations 00048 00049 #define FIGX 297 // portrait A4 mm 00050 #define FIGY 210 00051 #define DPI 1200 00052 00053 // it looks like xfig-3.2.3c has a bug. A4 papersize is 297x210 mm, 00054 // and at 1200 dpi this gives 14031x9921 dots. In a file saved from 00055 // xfig, with a box of A4 size, the reported sizes are 13365x9450 00056 00057 #define BSIZE 25 00058 #define XFIG_COLBASE 33 // xfig first user color, plplot colormap0[0], 00059 // the background color 00060 00061 00062 static void stcmap0( PLStream * ); 00063 static void stcmap1( PLStream * ); 00064 static void proc_str( PLStream *, EscText * ); 00065 00066 static int text = 0; 00067 00068 static DrvOpt xfig_options[] = { { "text", DRV_INT, &text, "Use Postscript text (text=1|0)" }, 00069 { NULL, DRV_INT, NULL, NULL } }; 00070 00071 void plD_dispatch_init_xfig( PLDispatchTable *pdt ) 00072 { 00073 #ifndef ENABLE_DYNDRIVERS 00074 pdt->pl_MenuStr = "Xfig file"; 00075 pdt->pl_DevName = "xfig"; 00076 #endif 00077 pdt->pl_type = plDevType_FileOriented; 00078 pdt->pl_seq = 31; 00079 pdt->pl_init = (plD_init_fp) plD_init_xfig; 00080 pdt->pl_line = (plD_line_fp) plD_line_xfig; 00081 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_xfig; 00082 pdt->pl_eop = (plD_eop_fp) plD_eop_xfig; 00083 pdt->pl_bop = (plD_bop_fp) plD_bop_xfig; 00084 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_xfig; 00085 pdt->pl_state = (plD_state_fp) plD_state_xfig; 00086 pdt->pl_esc = (plD_esc_fp) plD_esc_xfig; 00087 } 00088 00089 //-------------------------------------------------------------------------- 00090 // plD_init_xfig() 00091 // 00092 // Initialize device. 00093 //-------------------------------------------------------------------------- 00094 00095 void 00096 plD_init_xfig( PLStream *pls ) 00097 { 00098 xfig_Dev *dev; 00099 00100 plParseDrvOpts( xfig_options ); 00101 if ( text ) 00102 pls->dev_text = 1; // want to draw text 00103 00104 // Initialize family file info 00105 00106 plFamInit( pls ); 00107 00108 // Prompt for a file name if not already set 00109 00110 plOpenFile( pls ); 00111 00112 // Allocate and initialize device-specific data 00113 00114 if ( pls->dev != NULL ) 00115 free( (void *) pls->dev ); 00116 00117 pls->dev = calloc( 1, (size_t) sizeof ( xfig_Dev ) ); 00118 00119 if ( pls->dev == NULL ) 00120 plexit( "plD_init_xfig: cannot allocate memory\n" ); 00121 00122 dev = (xfig_Dev *) pls->dev; 00123 00124 dev->curwid = pls->width < 1 ? 1 : (int) pls->width; 00125 dev->firstline = 1; 00126 00127 dev->xold = PL_UNDEFINED; 00128 dev->yold = PL_UNDEFINED; 00129 dev->xmin = 0; 00130 dev->xmax = FIGX; 00131 dev->ymin = 0; 00132 dev->ymax = FIGY; 00133 dev->xscale_dev = DPI / 25.4; 00134 dev->yscale_dev = DPI / 25.4; 00135 dev->offset_inc = dev->ymax * (PLINT) dev->yscale_dev; 00136 dev->offset = -dev->offset_inc; 00137 pls->dev_fill0 = 1; // Handle solid fills 00138 if ( !pls->colorset ) 00139 pls->color = 1; // Is a color device 00140 00141 plP_setpxl( dev->xscale_dev, dev->xscale_dev ); // dpmm -- dots per mm 00142 plP_setphy( 0, (PLINT) ( FIGX * dev->xscale_dev ), 0, (PLINT) ( FIGY * dev->yscale_dev ) ); // physical dimension in mm 00143 00144 // Write out header 00145 00146 fprintf( pls->OutFile, "#FIG 3.2\n" ); 00147 fprintf( pls->OutFile, "Landscape\n" ); 00148 fprintf( pls->OutFile, "Center\n" ); 00149 fprintf( pls->OutFile, "Metric\n" ); 00150 fprintf( pls->OutFile, "A4\n" ); 00151 fprintf( pls->OutFile, "100.0\n" ); 00152 fprintf( pls->OutFile, "Single\n" ); 00153 fprintf( pls->OutFile, "-2\n" ); 00154 fprintf( pls->OutFile, "%d 2\n", DPI ); 00155 00156 // user defined colors, for colormap0 00157 dev->cmap0_ncol = 2 * pls->ncol0; // allow for a maximum of 2x the default cmap0 entries 00158 dev->cmap0_pos = ftell( pls->OutFile ); 00159 stcmap0( pls ); 00160 00161 // user defined colors, for colormap1 00162 dev->cmap1_ncol = 2 * pls->ncol1; // allow for a maximum of 2x the default cmap1 entries 00163 dev->cmap1_pos = ftell( pls->OutFile ); 00164 stcmap1( pls ); 00165 00166 dev->bufflen = 2 * BSIZE; 00167 dev->buffptr = (int *) malloc( sizeof ( int ) * (size_t) ( dev->bufflen ) ); 00168 if ( dev->buffptr == NULL ) 00169 plexit( "plD_init_xfig: Out of memory!" ); 00170 } 00171 00172 void 00173 stcmap0( PLStream *pls ) 00174 { 00175 xfig_Dev *dev; 00176 long cur_pos; 00177 int i; 00178 00179 dev = (xfig_Dev *) pls->dev; 00180 00181 if ( pls->ncol0 > dev->cmap0_ncol ) 00182 plwarn( "Too many colors for cmap0. Preallocate using command line '-ncol0 n.\n'" ); 00183 00184 cur_pos = ftell( pls->OutFile ); 00185 00186 if ( fseek( pls->OutFile, dev->cmap0_pos, SEEK_SET ) ) 00187 plexit( "Sorry, only file based output, no pipes.\n" ); 00188 00189 // fill the colormap 00190 for ( i = 0; i < pls->ncol0; i++ ) 00191 fprintf( pls->OutFile, "0 %d #%.2x%.2x%.2x\n", i + XFIG_COLBASE, 00192 pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b ); 00193 00194 // fill the nonspecified entries colormap 00195 for ( i = pls->ncol0; i < dev->cmap0_ncol; i++ ) 00196 fprintf( pls->OutFile, "0 %d #000000\n", i + XFIG_COLBASE ); 00197 00198 if ( cur_pos != dev->cmap0_pos ) 00199 fseek( pls->OutFile, cur_pos, SEEK_SET ); 00200 } 00201 00202 void 00203 stcmap1( PLStream *pls ) 00204 { 00205 xfig_Dev *dev; 00206 long cur_pos; 00207 int i; 00208 00209 dev = (xfig_Dev *) pls->dev; 00210 00211 if ( pls->ncol1 > dev->cmap1_ncol ) 00212 plwarn( "Too many colors for cmap1. Preallocate using command line '-ncol1 n.\n'" ); 00213 00214 cur_pos = ftell( pls->OutFile ); 00215 00216 if ( fseek( pls->OutFile, dev->cmap1_pos, SEEK_SET ) ) 00217 plexit( "Sorry, only file based output, no pipes.\n" ); 00218 00219 // fill the colormap 00220 for ( i = 0; i < pls->ncol1; i++ ) 00221 fprintf( pls->OutFile, "0 %d #%.2x%.2x%.2x\n", i + XFIG_COLBASE + dev->cmap0_ncol, 00222 pls->cmap1[i].r, pls->cmap1[i].g, pls->cmap1[i].b ); 00223 00224 // fill the nonspecified entries colormap 00225 for ( i = pls->ncol1; i < dev->cmap1_ncol; i++ ) 00226 fprintf( pls->OutFile, "0 %d #000000\n", i + XFIG_COLBASE + dev->cmap0_ncol ); 00227 00228 if ( cur_pos != dev->cmap1_pos ) 00229 fseek( pls->OutFile, cur_pos, SEEK_SET ); 00230 } 00231 00232 //-------------------------------------------------------------------------- 00233 // plD_line_xfig() 00234 // 00235 // Draw a line in the current color from (x1,y1) to (x2,y2). 00236 //-------------------------------------------------------------------------- 00237 00238 void 00239 plD_line_xfig( PLStream *pls, short x1a, short y1a, short x2a, short y2a ) 00240 { 00241 xfig_Dev *dev = (xfig_Dev *) pls->dev; 00242 int x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a; 00243 int *tempptr; 00244 int count; 00245 00246 // If starting point of this line is the same as the ending point of 00247 // the previous line then don't raise the pen. (This really speeds up 00248 // plotting and reduces the size of the file. 00249 00250 if ( dev->firstline ) 00251 { 00252 count = 0; 00253 *( dev->buffptr + count++ ) = x1; 00254 *( dev->buffptr + count++ ) = y1; 00255 *( dev->buffptr + count++ ) = x2; 00256 *( dev->buffptr + count++ ) = y2; 00257 dev->firstline = 0; 00258 } 00259 else if ( x1 == dev->xold && y1 == dev->yold ) 00260 { 00261 count = dev->count; 00262 if ( count + 2 >= dev->bufflen ) 00263 { 00264 dev->bufflen += 2 * BSIZE; 00265 tempptr = (int *) 00266 realloc( (void *) dev->buffptr, (size_t) ( dev->bufflen ) * sizeof ( int ) ); 00267 if ( tempptr == NULL ) 00268 { 00269 free( (void *) dev->buffptr ); 00270 plexit( "plD_line_xfig: Out of memory!" ); 00271 } 00272 dev->buffptr = tempptr; 00273 } 00274 *( dev->buffptr + count++ ) = x2; 00275 *( dev->buffptr + count++ ) = y2; 00276 } 00277 else 00278 { 00279 flushbuffer( pls ); 00280 count = dev->count; 00281 *( dev->buffptr + count++ ) = x1; 00282 *( dev->buffptr + count++ ) = y1; 00283 *( dev->buffptr + count++ ) = x2; 00284 *( dev->buffptr + count++ ) = y2; 00285 } 00286 dev->count = count; 00287 dev->xold = x2; 00288 dev->yold = y2; 00289 } 00290 00291 //-------------------------------------------------------------------------- 00292 // plD_polyline_xfig() 00293 // 00294 // Draw a polyline in the current color. 00295 //-------------------------------------------------------------------------- 00296 00297 void 00298 plD_polyline_xfig( PLStream *pls, short *xa, short *ya, PLINT npts ) 00299 { 00300 PLINT i; 00301 00302 for ( i = 0; i < npts - 1; i++ ) 00303 plD_line_xfig( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] ); 00304 } 00305 00306 //-------------------------------------------------------------------------- 00307 // plD_eop_xfig() 00308 // 00309 // End of page. 00310 //-------------------------------------------------------------------------- 00311 00312 void 00313 plD_eop_xfig( PLStream *pls ) 00314 { 00315 xfig_Dev *dev = (xfig_Dev *) pls->dev; 00316 00317 if ( !dev->firstline ) 00318 flushbuffer( pls ); 00319 } 00320 00321 //-------------------------------------------------------------------------- 00322 // plD_bop_xfig() 00323 // 00324 // Set up for the next page. 00325 // Advance to next family file if necessary (file output). 00326 //-------------------------------------------------------------------------- 00327 00328 void 00329 plD_bop_xfig( PLStream *pls ) 00330 { 00331 xfig_Dev *dev; 00332 00333 if ( !pls->termin ) 00334 plGetFam( pls ); 00335 00336 dev = (xfig_Dev *) pls->dev; 00337 00338 dev->xold = PL_UNDEFINED; 00339 dev->yold = PL_UNDEFINED; 00340 dev->firstline = 1; 00341 00342 pls->famadv = 1; 00343 pls->page++; 00344 00345 dev->offset += dev->offset_inc; 00346 flushbuffer( pls ); 00347 00348 // create background FIXME -- sync with orientation in header and pls->diorot 00349 dev->curcol = XFIG_COLBASE; // colormap entry 0, background 00350 fprintf( pls->OutFile, "2 1 0 1 %d %d 50 0 20 0.0 0 0 -1 0 0 5\n", dev->curcol, dev->curcol ); 00351 fprintf( pls->OutFile, "%d %d %d %d %d %d %d %d %d %d\n", 00352 0, dev->offset, 00353 0, (int) ( FIGY * dev->yscale_dev ) + dev->offset, 00354 (int) ( FIGX * dev->xscale_dev ), (int) ( FIGY * dev->yscale_dev ) + dev->offset, 00355 (int) ( FIGX * dev->xscale_dev ), dev->offset, 00356 0, dev->offset ); 00357 } 00358 00359 //-------------------------------------------------------------------------- 00360 // plD_tidy_xfig() 00361 // 00362 // Close graphics file or otherwise clean up. 00363 //-------------------------------------------------------------------------- 00364 00365 void 00366 plD_tidy_xfig( PLStream *pls ) 00367 { 00368 xfig_Dev *dev = (xfig_Dev *) pls->dev; 00369 00370 flushbuffer( pls ); 00371 free( (void *) dev->buffptr ); 00372 plCloseFile( pls ); 00373 } 00374 00375 //-------------------------------------------------------------------------- 00376 // plD_state_xfig() 00377 // 00378 // Handle change in PLStream state (color, pen width, fill attribute, etc). 00379 //-------------------------------------------------------------------------- 00380 00381 void 00382 plD_state_xfig( PLStream *pls, PLINT op ) 00383 { 00384 xfig_Dev *dev = (xfig_Dev *) pls->dev; 00385 00386 switch ( op ) 00387 { 00388 case PLSTATE_WIDTH: 00389 flushbuffer( pls ); 00390 dev->firstline = 1; 00391 dev->curwid = pls->width < 1 ? 1 : (int) pls->width; 00392 break; 00393 00394 case PLSTATE_COLOR0: 00395 flushbuffer( pls ); 00396 dev->curcol = pls->icol0 + XFIG_COLBASE; 00397 break; 00398 00399 case PLSTATE_COLOR1: 00400 flushbuffer( pls ); 00401 dev->curcol = pls->icol1 + XFIG_COLBASE + pls->ncol0; 00402 break; 00403 00404 case PLSTATE_CMAP0: 00405 stcmap0( pls ); 00406 break; 00407 00408 case PLSTATE_CMAP1: 00409 stcmap1( pls ); 00410 break; 00411 } 00412 } 00413 00414 //-------------------------------------------------------------------------- 00415 // plD_esc_xfig() 00416 // 00417 // Escape function. 00418 // Preliminary fill support for colormap0 00419 //-------------------------------------------------------------------------- 00420 00421 void 00422 plD_esc_xfig( PLStream *pls, PLINT op, void *ptr ) 00423 { 00424 xfig_Dev *dev = pls->dev; 00425 int i, npts; 00426 00427 switch ( op ) 00428 { 00429 case PLESC_FILL: 00430 00431 npts = pls->dev_npts; 00432 00433 flushbuffer( pls ); 00434 fprintf( pls->OutFile, "2 1 0 1 %d %d 50 0 20 0.0 0 0 0 0 0 %d\n", 00435 dev->curcol, dev->curcol, npts ); 00436 00437 for ( i = 0; i < npts; i++ ) 00438 fprintf( pls->OutFile, "%d %d ", pls->dev_x[i], 00439 dev->offset + dev->ymax * (int) dev->xscale_dev - pls->dev_y[i] ); 00440 00441 fprintf( pls->OutFile, "\n" ); 00442 break; 00443 00444 case PLESC_HAS_TEXT: 00445 proc_str( pls, ptr ); 00446 break; 00447 } 00448 } 00449 00450 //-------------------------------------------------------------------------- 00451 // Utility functions. 00452 //-------------------------------------------------------------------------- 00453 00454 static void 00455 flushbuffer( PLStream *pls ) 00456 { 00457 xfig_Dev *dev = pls->dev; 00458 int i = 0; 00459 00460 if ( dev->count == 0 ) 00461 return; 00462 00463 fprintf( pls->OutFile, "2 1 0 %d %d 0 50 0 -1 0.0 0 0 0 0 0 %d\n", 00464 dev->curwid, dev->curcol, dev->count / 2 ); 00465 while ( i < dev->count ) 00466 { 00467 fprintf( pls->OutFile, "%d %d ", *( dev->buffptr + i ), 00468 dev->offset + dev->ymax * (int) dev->yscale_dev - *( dev->buffptr + i + 1 ) ); 00469 i += 2; 00470 } 00471 fprintf( pls->OutFile, "\n" ); 00472 dev->count = 0; 00473 } 00474 00475 void 00476 proc_str( PLStream *pls, EscText *args ) 00477 { 00478 PLFLT *t = args->xform; 00479 PLFLT a1, alpha, ft_ht, angle, ref; 00480 xfig_Dev *dev = (xfig_Dev *) pls->dev; 00481 PLINT clxmin, clxmax, clymin, clymax; 00482 int jst, font; 00483 00484 // font height 00485 ft_ht = pls->chrht * 72.0 / 25.4; // ft_ht in points. ht is in mm 00486 00487 // calculate baseline text angle 00488 angle = pls->diorot * 90.; 00489 a1 = acos( t[0] ) * 180. / PI; 00490 if ( t[2] > 0. ) 00491 alpha = a1 - angle; 00492 else 00493 alpha = 360. - a1 - angle; 00494 00495 alpha = alpha * PI / 180.; 00496 00497 // TODO: parse string for format (escape) characters 00498 // parse_str(args->string, return_string); 00499 00500 // apply transformations 00501 difilt( &args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax ); 00502 00503 // check clip limits. For now, only the reference point of the string is checked; 00504 // but the the whole string should be checked -- using a postscript construct 00505 // such as gsave/clip/grestore. This method can also be applied to the xfig and 00506 // pstex drivers. Zoom side effect: the font size must be adjusted! 00507 00508 if ( args->x < clxmin || args->x > clxmax || args->y < clymin || args->y > clymax ) 00509 return; 00510 00511 // 00512 // Text justification. Left, center and right justification, which 00513 // are the more common options, are supported; variable justification is 00514 // only approximate, based on plplot computation of it's string lenght 00515 // 00516 00517 if ( args->just == 0.5 ) 00518 jst = 1; // center 00519 else if ( args->just == 1. ) 00520 jst = 2; // right 00521 else 00522 { 00523 jst = 0; // left 00524 args->x = args->refx; // use hints provided by plplot 00525 args->y = args->refy; 00526 } 00527 00528 // 00529 // Reference point (center baseline of string, not latex character reference point). 00530 // If base = 0, it is aligned with the center of the text box 00531 // If base = 1, it is aligned with the baseline of the text box 00532 // If base = 2, it is aligned with the top of the text box 00533 // Currently plplot only uses base=0 00534 // xfig use base=1 00535 // 00536 00537 if ( args->base == 2 ) // not supported by plplot 00538 ref = -DPI / 72. * ft_ht / 2.; // half font height in xfig unities (1/1200 inches) 00539 else if ( args->base == 1 ) 00540 ref = 0.; 00541 else 00542 ref = DPI / 72. * ft_ht / 2.; 00543 00544 // rotate point in xfig is lower left corner, compensate 00545 args->y = (PLINT) ( dev->offset + dev->ymax * (int) dev->xscale_dev - ( args->y - ref * cos( alpha ) ) ); 00546 args->x = (PLINT) ( args->x + ref * sin( alpha ) ); 00547 00548 // 00549 // font family, serie and shape. Currently not supported by plplot 00550 // 00551 // Use Postscript Times 00552 // 1: Normal font 00553 // 2: Roman font 00554 // 3: Italic font 00555 // 4: sans serif 00556 // 00557 00558 switch ( pls->cfont ) 00559 { 00560 case ( 1 ): font = 0; break; 00561 case ( 2 ): font = 1; break; 00562 case ( 3 ): font = 3; break; 00563 case ( 4 ): font = 4; break; 00564 default: font = 0; 00565 } 00566 00567 fprintf( pls->OutFile, "4 %d %d 50 0 %d %f %f 4 1 1 %d %d %s\\001\n", 00568 jst, dev->curcol, font, 1.8 * ft_ht, alpha, args->x, args->y, args->string ); 00569 } 00570 00571 #else 00572 int 00573 pldummy_xfig() 00574 { 00575 return 0; 00576 } 00577 00578 #endif // PLD_xfig