PLplot  5.10.0
xfig.c
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines