• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

xfig.c

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

Generated on Wed Oct 12 2011 20:42:23 for PLplot by  doxygen 1.7.1