PLplot: xfig.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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
36 void plD_dispatch_init_xfig( PLDispatchTable *pdt );
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
73 void plD_dispatch_init_xfig( PLDispatchTable *pdt )
74 {
75 #ifndef ENABLE_DYNDRIVERS
76 pdt->pl_MenuStr = "Xfig file";
77 pdt->pl_DevName = "xfig";
78 #endif
79 pdt->pl_type = plDevType_FileOriented;
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
575 pldummy_xfig()
576 {
577 return 0;
578 }
579
580 #endif // PLD_xfig