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