PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
xfig.c
Go to the documentation of this file.
1 // $Id: xfig.c 12626 2013-10-24 23:01:26Z andrewross $
2 //
3 // PLplot xfig device driver.
4 //
5 #include "plDevs.h"
6 
7 #ifdef PLD_xfig
8 
9 #include "plplotP.h"
10 #include "drivers.h"
11 
12 // Device info
13 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_xfig = "xfig:Fig file:0:xfig:31:xfig\n";
14 
15 typedef struct
16 {
17  PLINT xold, yold;
18 
19  PLINT xmin, xmax;
20  PLINT ymin, ymax;
21 
22  PLFLT xscale_dev, yscale_dev;
23 
24  int *buffptr, bufflen;
25  int count;
26  int curwid;
27  int curcol;
28  int firstline;
29  long cmap0_pos, cmap1_pos;
30  int cmap0_ncol, cmap1_ncol;
31  int offset, offset_inc;
32 } xfig_Dev;
33 
34 // Function prototypes
35 
37 
38 void plD_init_xfig( PLStream * );
39 void plD_line_xfig( PLStream *, short, short, short, short );
40 void plD_polyline_xfig( PLStream *, short *, short *, PLINT );
41 void plD_eop_xfig( PLStream * );
42 void plD_bop_xfig( PLStream * );
43 void plD_tidy_xfig( PLStream * );
44 void plD_state_xfig( PLStream *, PLINT );
45 void plD_esc_xfig( PLStream *, PLINT, void * );
46 
47 static void flushbuffer( PLStream * );
48 
49 // top level declarations
50 
51 #define FIGX 297 // portrait A4 mm
52 #define FIGY 210
53 #define DPI 1200
54 
55 // it looks like xfig-3.2.3c has a bug. A4 papersize is 297x210 mm,
56 // and at 1200 dpi this gives 14031x9921 dots. In a file saved from
57 // xfig, with a box of A4 size, the reported sizes are 13365x9450
58 
59 #define BSIZE 25
60 #define XFIG_COLBASE 33 // xfig first user color, plplot colormap0[0],
61  // the background color
62 
63 
64 static void stcmap0( PLStream * );
65 static void stcmap1( PLStream * );
66 static void proc_str( PLStream *, EscText * );
67 
68 static int text = 0;
69 
70 static DrvOpt xfig_options[] = { { "text", DRV_INT, &text, "Use Postscript text (text=1|0)" },
71  { NULL, DRV_INT, NULL, NULL } };
72 
74 {
75 #ifndef ENABLE_DYNDRIVERS
76  pdt->pl_MenuStr = "Xfig file";
77  pdt->pl_DevName = "xfig";
78 #endif
80  pdt->pl_seq = 31;
81  pdt->pl_init = (plD_init_fp) plD_init_xfig;
82  pdt->pl_line = (plD_line_fp) plD_line_xfig;
83  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_xfig;
84  pdt->pl_eop = (plD_eop_fp) plD_eop_xfig;
85  pdt->pl_bop = (plD_bop_fp) plD_bop_xfig;
86  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_xfig;
87  pdt->pl_state = (plD_state_fp) plD_state_xfig;
88  pdt->pl_esc = (plD_esc_fp) plD_esc_xfig;
89 }
90 
91 //--------------------------------------------------------------------------
92 // plD_init_xfig()
93 //
94 // Initialize device.
95 //--------------------------------------------------------------------------
96 
97 void
98 plD_init_xfig( PLStream *pls )
99 {
100  xfig_Dev *dev;
101 
102  plParseDrvOpts( xfig_options );
103  if ( text )
104  pls->dev_text = 1; // want to draw text
105 
106 // Initialize family file info
107 
108  plFamInit( pls );
109 
110 // Prompt for a file name if not already set
111 
112  plOpenFile( pls );
113 
114 // Allocate and initialize device-specific data
115 
116  if ( pls->dev != NULL )
117  free( (void *) pls->dev );
118 
119  pls->dev = calloc( 1, (size_t) sizeof ( xfig_Dev ) );
120 
121  if ( pls->dev == NULL )
122  plexit( "plD_init_xfig: cannot allocate memory\n" );
123 
124  dev = (xfig_Dev *) pls->dev;
125 
126  dev->curwid = pls->width < 1 ? 1 : (int) pls->width;
127  dev->firstline = 1;
128 
129  dev->xold = PL_UNDEFINED;
130  dev->yold = PL_UNDEFINED;
131  dev->xmin = 0;
132  dev->xmax = FIGX;
133  dev->ymin = 0;
134  dev->ymax = FIGY;
135  dev->xscale_dev = DPI / 25.4;
136  dev->yscale_dev = DPI / 25.4;
137  dev->offset_inc = dev->ymax * (PLINT) dev->yscale_dev;
138  dev->offset = -dev->offset_inc;
139  pls->dev_fill0 = 1; // Handle solid fills
140  if ( !pls->colorset )
141  pls->color = 1; // Is a color device
142 
143  plP_setpxl( dev->xscale_dev, dev->xscale_dev ); // dpmm -- dots per mm
144  plP_setphy( 0, (PLINT) ( FIGX * dev->xscale_dev ), 0, (PLINT) ( FIGY * dev->yscale_dev ) ); // physical dimension in mm
145 
146 // Write out header
147 
148  fprintf( pls->OutFile, "#FIG 3.2\n" );
149  fprintf( pls->OutFile, "Landscape\n" );
150  fprintf( pls->OutFile, "Center\n" );
151  fprintf( pls->OutFile, "Metric\n" );
152  fprintf( pls->OutFile, "A4\n" );
153  fprintf( pls->OutFile, "100.0\n" );
154  fprintf( pls->OutFile, "Single\n" );
155  fprintf( pls->OutFile, "-2\n" );
156  fprintf( pls->OutFile, "%d 2\n", DPI );
157 
158  // user defined colors, for colormap0
159  dev->cmap0_ncol = 2 * pls->ncol0; // allow for a maximum of 2x the default cmap0 entries
160  dev->cmap0_pos = ftell( pls->OutFile );
161  stcmap0( pls );
162 
163  // user defined colors, for colormap1
164  dev->cmap1_ncol = 2 * pls->ncol1; // allow for a maximum of 2x the default cmap1 entries
165  dev->cmap1_pos = ftell( pls->OutFile );
166  stcmap1( pls );
167 
168  dev->bufflen = 2 * BSIZE;
169  dev->buffptr = (int *) malloc( sizeof ( int ) * (size_t) ( dev->bufflen ) );
170  if ( dev->buffptr == NULL )
171  plexit( "plD_init_xfig: Out of memory!" );
172 }
173 
174 void
175 stcmap0( PLStream *pls )
176 {
177  xfig_Dev *dev;
178  long cur_pos;
179  int i;
180 
181  dev = (xfig_Dev *) pls->dev;
182 
183  if ( pls->ncol0 > dev->cmap0_ncol )
184  plwarn( "Too many colors for cmap0. Preallocate using command line '-ncol0 n.\n'" );
185 
186  cur_pos = ftell( pls->OutFile );
187 
188  if ( fseek( pls->OutFile, dev->cmap0_pos, SEEK_SET ) )
189  plexit( "Sorry, only file based output, no pipes.\n" );
190 
191  // fill the colormap
192  for ( i = 0; i < pls->ncol0; i++ )
193  fprintf( pls->OutFile, "0 %d #%.2x%.2x%.2x\n", i + XFIG_COLBASE,
194  pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b );
195 
196  // fill the nonspecified entries colormap
197  for ( i = pls->ncol0; i < dev->cmap0_ncol; i++ )
198  fprintf( pls->OutFile, "0 %d #000000\n", i + XFIG_COLBASE );
199 
200  if ( cur_pos != dev->cmap0_pos )
201  fseek( pls->OutFile, cur_pos, SEEK_SET );
202 }
203 
204 void
205 stcmap1( PLStream *pls )
206 {
207  xfig_Dev *dev;
208  long cur_pos;
209  int i;
210 
211  dev = (xfig_Dev *) pls->dev;
212 
213  if ( pls->ncol1 > dev->cmap1_ncol )
214  plwarn( "Too many colors for cmap1. Preallocate using command line '-ncol1 n.\n'" );
215 
216  cur_pos = ftell( pls->OutFile );
217 
218  if ( fseek( pls->OutFile, dev->cmap1_pos, SEEK_SET ) )
219  plexit( "Sorry, only file based output, no pipes.\n" );
220 
221  // fill the colormap
222  for ( i = 0; i < pls->ncol1; i++ )
223  fprintf( pls->OutFile, "0 %d #%.2x%.2x%.2x\n", i + XFIG_COLBASE + dev->cmap0_ncol,
224  pls->cmap1[i].r, pls->cmap1[i].g, pls->cmap1[i].b );
225 
226  // fill the nonspecified entries colormap
227  for ( i = pls->ncol1; i < dev->cmap1_ncol; i++ )
228  fprintf( pls->OutFile, "0 %d #000000\n", i + XFIG_COLBASE + dev->cmap0_ncol );
229 
230  if ( cur_pos != dev->cmap1_pos )
231  fseek( pls->OutFile, cur_pos, SEEK_SET );
232 }
233 
234 //--------------------------------------------------------------------------
235 // plD_line_xfig()
236 //
237 // Draw a line in the current color from (x1,y1) to (x2,y2).
238 //--------------------------------------------------------------------------
239 
240 void
241 plD_line_xfig( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
242 {
243  xfig_Dev *dev = (xfig_Dev *) pls->dev;
244  int x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
245  int *tempptr;
246  int count;
247 
248 // If starting point of this line is the same as the ending point of
249 // the previous line then don't raise the pen. (This really speeds up
250 // plotting and reduces the size of the file.
251 
252  if ( dev->firstline )
253  {
254  count = 0;
255  *( dev->buffptr + count++ ) = x1;
256  *( dev->buffptr + count++ ) = y1;
257  *( dev->buffptr + count++ ) = x2;
258  *( dev->buffptr + count++ ) = y2;
259  dev->firstline = 0;
260  }
261  else if ( x1 == dev->xold && y1 == dev->yold )
262  {
263  count = dev->count;
264  if ( count + 2 >= dev->bufflen )
265  {
266  dev->bufflen += 2 * BSIZE;
267  tempptr = (int *)
268  realloc( (void *) dev->buffptr, (size_t) ( dev->bufflen ) * sizeof ( int ) );
269  if ( tempptr == NULL )
270  {
271  free( (void *) dev->buffptr );
272  plexit( "plD_line_xfig: Out of memory!" );
273  }
274  dev->buffptr = tempptr;
275  }
276  *( dev->buffptr + count++ ) = x2;
277  *( dev->buffptr + count++ ) = y2;
278  }
279  else
280  {
281  flushbuffer( pls );
282  count = dev->count;
283  *( dev->buffptr + count++ ) = x1;
284  *( dev->buffptr + count++ ) = y1;
285  *( dev->buffptr + count++ ) = x2;
286  *( dev->buffptr + count++ ) = y2;
287  }
288  dev->count = count;
289  dev->xold = x2;
290  dev->yold = y2;
291 }
292 
293 //--------------------------------------------------------------------------
294 // plD_polyline_xfig()
295 //
296 // Draw a polyline in the current color.
297 //--------------------------------------------------------------------------
298 
299 void
300 plD_polyline_xfig( PLStream *pls, short *xa, short *ya, PLINT npts )
301 {
302  PLINT i;
303 
304  for ( i = 0; i < npts - 1; i++ )
305  plD_line_xfig( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] );
306 }
307 
308 //--------------------------------------------------------------------------
309 // plD_eop_xfig()
310 //
311 // End of page.
312 //--------------------------------------------------------------------------
313 
314 void
315 plD_eop_xfig( PLStream *pls )
316 {
317  xfig_Dev *dev = (xfig_Dev *) pls->dev;
318 
319  if ( !dev->firstline )
320  flushbuffer( pls );
321 }
322 
323 //--------------------------------------------------------------------------
324 // plD_bop_xfig()
325 //
326 // Set up for the next page.
327 // Advance to next family file if necessary (file output).
328 //--------------------------------------------------------------------------
329 
330 void
331 plD_bop_xfig( PLStream *pls )
332 {
333  xfig_Dev *dev;
334 
335  if ( !pls->termin )
336  plGetFam( pls );
337 
338  dev = (xfig_Dev *) pls->dev;
339 
340  dev->xold = PL_UNDEFINED;
341  dev->yold = PL_UNDEFINED;
342  dev->firstline = 1;
343 
344  pls->famadv = 1;
345  pls->page++;
346 
347  dev->offset += dev->offset_inc;
348  flushbuffer( pls );
349 
350  // create background FIXME -- sync with orientation in header and pls->diorot
351  dev->curcol = XFIG_COLBASE; // colormap entry 0, background
352  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 );
353  fprintf( pls->OutFile, "%d %d %d %d %d %d %d %d %d %d\n",
354  0, dev->offset,
355  0, (int) ( FIGY * dev->yscale_dev ) + dev->offset,
356  (int) ( FIGX * dev->xscale_dev ), (int) ( FIGY * dev->yscale_dev ) + dev->offset,
357  (int) ( FIGX * dev->xscale_dev ), dev->offset,
358  0, dev->offset );
359 }
360 
361 //--------------------------------------------------------------------------
362 // plD_tidy_xfig()
363 //
364 // Close graphics file or otherwise clean up.
365 //--------------------------------------------------------------------------
366 
367 void
368 plD_tidy_xfig( PLStream *pls )
369 {
370  xfig_Dev *dev = (xfig_Dev *) pls->dev;
371 
372  flushbuffer( pls );
373  free( (void *) dev->buffptr );
374  plCloseFile( pls );
375 }
376 
377 //--------------------------------------------------------------------------
378 // plD_state_xfig()
379 //
380 // Handle change in PLStream state (color, pen width, fill attribute, etc).
381 //--------------------------------------------------------------------------
382 
383 void
384 plD_state_xfig( PLStream *pls, PLINT op )
385 {
386  xfig_Dev *dev = (xfig_Dev *) pls->dev;
387 
388  switch ( op )
389  {
390  case PLSTATE_WIDTH:
391  flushbuffer( pls );
392  dev->firstline = 1;
393  dev->curwid = pls->width < 1 ? 1 : (int) pls->width;
394  break;
395 
396  case PLSTATE_COLOR0:
397  flushbuffer( pls );
398  dev->curcol = pls->icol0 + XFIG_COLBASE;
399  break;
400 
401  case PLSTATE_COLOR1:
402  flushbuffer( pls );
403  dev->curcol = pls->icol1 + XFIG_COLBASE + pls->ncol0;
404  break;
405 
406  case PLSTATE_CMAP0:
407  stcmap0( pls );
408  break;
409 
410  case PLSTATE_CMAP1:
411  stcmap1( pls );
412  break;
413  }
414 }
415 
416 //--------------------------------------------------------------------------
417 // plD_esc_xfig()
418 //
419 // Escape function.
420 // Preliminary fill support for colormap0
421 //--------------------------------------------------------------------------
422 
423 void
424 plD_esc_xfig( PLStream *pls, PLINT op, void *ptr )
425 {
426  xfig_Dev *dev = pls->dev;
427  int i, npts;
428 
429  switch ( op )
430  {
431  case PLESC_FILL:
432 
433  npts = pls->dev_npts;
434 
435  flushbuffer( pls );
436  fprintf( pls->OutFile, "2 1 0 1 %d %d 50 0 20 0.0 0 0 0 0 0 %d\n",
437  dev->curcol, dev->curcol, npts );
438 
439  for ( i = 0; i < npts; i++ )
440  fprintf( pls->OutFile, "%d %d ", pls->dev_x[i],
441  dev->offset + dev->ymax * (int) dev->xscale_dev - pls->dev_y[i] );
442 
443  fprintf( pls->OutFile, "\n" );
444  break;
445 
446  case PLESC_HAS_TEXT:
447  proc_str( pls, ptr );
448  break;
449  }
450 }
451 
452 //--------------------------------------------------------------------------
453 // Utility functions.
454 //--------------------------------------------------------------------------
455 
456 static void
457 flushbuffer( PLStream *pls )
458 {
459  xfig_Dev *dev = pls->dev;
460  int i = 0;
461 
462  if ( dev->count == 0 )
463  return;
464 
465  fprintf( pls->OutFile, "2 1 0 %d %d 0 50 0 -1 0.0 0 0 0 0 0 %d\n",
466  dev->curwid, dev->curcol, dev->count / 2 );
467  while ( i < dev->count )
468  {
469  fprintf( pls->OutFile, "%d %d ", *( dev->buffptr + i ),
470  dev->offset + dev->ymax * (int) dev->yscale_dev - *( dev->buffptr + i + 1 ) );
471  i += 2;
472  }
473  fprintf( pls->OutFile, "\n" );
474  dev->count = 0;
475 }
476 
477 void
478 proc_str( PLStream *pls, EscText *args )
479 {
480  PLFLT *t = args->xform;
481  PLFLT a1, alpha, ft_ht, angle, ref;
482  xfig_Dev *dev = (xfig_Dev *) pls->dev;
483  PLINT clxmin, clxmax, clymin, clymax;
484  int jst, font;
485 
486  // font height
487  ft_ht = pls->chrht * 72.0 / 25.4; // ft_ht in points. ht is in mm
488 
489  // calculate baseline text angle
490  angle = pls->diorot * 90.;
491  a1 = acos( t[0] ) * 180. / PI;
492  if ( t[2] > 0. )
493  alpha = a1 - angle;
494  else
495  alpha = 360. - a1 - angle;
496 
497  alpha = alpha * PI / 180.;
498 
499  // TODO: parse string for format (escape) characters
500  // parse_str(args->string, return_string);
501 
502  // apply transformations
503  difilt( &args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax );
504 
505  // check clip limits. For now, only the reference point of the string is checked;
506  // but the the whole string should be checked -- using a postscript construct
507  // such as gsave/clip/grestore. This method can also be applied to the xfig and
508  // pstex drivers. Zoom side effect: the font size must be adjusted!
509 
510  if ( args->x < clxmin || args->x > clxmax || args->y < clymin || args->y > clymax )
511  return;
512 
513  //
514  // Text justification. Left, center and right justification, which
515  // are the more common options, are supported; variable justification is
516  // only approximate, based on plplot computation of it's string lenght
517  //
518 
519  if ( args->just == 0.5 )
520  jst = 1; // center
521  else if ( args->just == 1. )
522  jst = 2; // right
523  else
524  {
525  jst = 0; // left
526  args->x = args->refx; // use hints provided by plplot
527  args->y = args->refy;
528  }
529 
530  //
531  // Reference point (center baseline of string, not latex character reference point).
532  // If base = 0, it is aligned with the center of the text box
533  // If base = 1, it is aligned with the baseline of the text box
534  // If base = 2, it is aligned with the top of the text box
535  // Currently plplot only uses base=0
536  // xfig use base=1
537  //
538 
539  if ( args->base == 2 ) // not supported by plplot
540  ref = -DPI / 72. * ft_ht / 2.; // half font height in xfig unities (1/1200 inches)
541  else if ( args->base == 1 )
542  ref = 0.;
543  else
544  ref = DPI / 72. * ft_ht / 2.;
545 
546  // rotate point in xfig is lower left corner, compensate
547  args->y = (PLINT) ( dev->offset + dev->ymax * (int) dev->xscale_dev - ( args->y - ref * cos( alpha ) ) );
548  args->x = (PLINT) ( args->x + ref * sin( alpha ) );
549 
550  //
551  // font family, serie and shape. Currently not supported by plplot
552  //
553  // Use Postscript Times
554  // 1: Normal font
555  // 2: Roman font
556  // 3: Italic font
557  // 4: sans serif
558  //
559 
560  switch ( pls->cfont )
561  {
562  case ( 1 ): font = 0; break;
563  case ( 2 ): font = 1; break;
564  case ( 3 ): font = 3; break;
565  case ( 4 ): font = 4; break;
566  default: font = 0;
567  }
568 
569  fprintf( pls->OutFile, "4 %d %d 50 0 %d %f %f 4 1 1 %d %d %s\\001\n",
570  jst, dev->curcol, font, 1.8 * ft_ht, alpha, args->x, args->y, args->string );
571 }
572 
573 #else
574 int
576 {
577  return 0;
578 }
579 
580 #endif // PLD_xfig