PLplot: pstex.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
pstex.c
Go to the documentation of this file.
1 // $Id$
2 //
3 // PLplot pstex (Postscript/LaTeX) device driver.
4 //
5
6 #include "plDevs.h"
7
8 #ifdef PLD_pstex
9
10 #include "plplotP.h"
11 #include "drivers.h"
12 #include "ps.h"
13
14 // Device info
15 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_pstex =
16 "pstex:Combined Postscript/LaTeX files:0:pstex:41:pstex\n";
17
18 //--------------------------------------------------------------------------
19 // plD_init_pstex()
20 //
21 // Initialize device.
22 //--------------------------------------------------------------------------
23
24
25 static void parse_str( const char *str, char *dest );
26 static void proc_str( PLStream *pls, EscText *args );
27 static int color = 1;
28
29 static DrvOpt pstex_options[] = { { "color", DRV_INT, &color,
30 "Color Postscript/LaTeX (color=1|0)" },
31 { NULL, DRV_INT, NULL, NULL} };
32
33 void plD_dispatch_init_pstex( PLDispatchTable *pdt )
34 {
35 #ifndef ENABLE_DYNDRIVERS
36 pdt->pl_MenuStr = "Combined Postscript/LaTeX files";
37 pdt->pl_DevName = "pstex";
38 #endif
39 pdt->pl_type = plDevType_FileOriented;
40 pdt->pl_seq = 41;
41 pdt->pl_init = (plD_init_fp) plD_init_pstex;
42 pdt->pl_line = (plD_line_fp) plD_line_ps;
43 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_ps;
44 pdt->pl_eop = (plD_eop_fp) plD_eop_ps;
45 pdt->pl_bop = (plD_bop_fp) plD_bop_pstex;
46 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_pstex;
47 pdt->pl_state = (plD_state_fp) plD_state_ps;
48 pdt->pl_esc = (plD_esc_fp) plD_esc_pstex;
49 }
50
51 void
52 plD_init_pstex( PLStream *pls )
53 {
54 char *ofile;
55 size_t len;
56 PSDev *dev;
57 FILE *fp;
58
59 plParseDrvOpts( pstex_options );
60 if ( color )
61 plD_init_psc( pls ); // init color postscript driver
62 else
63 plD_init_psm( pls ); // init monochrome postscript driver
64
65 dev = (PSDev *) pls->dev;
66
67 pls->dev_text = 1; // want to draw text
68 pls->dev_unicode = 0; // don't want unicode
69
70 // open latex output file
71 len = strlen( pls->FileName ) + 3;
72 ofile = (char *) malloc( sizeof ( char ) * len );
73 snprintf( ofile, len, "%s_t", pls->FileName );
74 fp = fopen( ofile, "w" );
75 free( ofile );
76 dev->fp = fp;
77
78 fprintf( fp, "\\begin{picture}(0,0)(0,0)%%\n" );
79 fprintf( fp, "\\includegraphics[scale=1.,clip]{%s}%%\n", pls->FileName );
80 fprintf( fp, "\\end{picture}%%\n" );
81 // fprintf(fp,"\\setlength{\\unitlength}{%fbp}%%\n", 72./25.4/pls->xpmm);
82 fprintf( fp, "\\setlength{\\unitlength}{%fbp}%%\n", 1.0 / ENLARGE );
83 fprintf( fp, "\\begingroup\\makeatletter\\ifx\\SetFigFont\\undefined%%\n" );
84 fprintf( fp, "\\gdef\\SetFigFont#1#2#3#4#5{%%\n" );
85 fprintf( fp, "\\reset@font\\fontsize{#1}{#2pt}%%\n" );
86 fprintf( fp, "\\fontfamily{#3}\\fontseries{#4}\\fontshape{#5}%%\n" );
87 fprintf( fp, "\\selectfont}%%\n" );
88 fprintf( fp, "\\fi\\endgroup%%\n" );
89
90 dev->cur_pos = ftell( fp );
91 fprintf( fp, "\\begin{picture}(xxxxxx,xxxxxx)(xxxxxx,xxxxxx)%%\n" );
92 }
93
94 void
95 plD_esc_pstex( PLStream *pls, PLINT op, void *ptr )
96 {
97 switch ( op )
98 {
99 case PLESC_HAS_TEXT:
100 proc_str( pls, ptr );
101 break;
102 default:
103 plD_esc_ps( pls, op, ptr );
104 }
105 }
106
107 void
108 plD_bop_pstex( PLStream *pls )
109 {
110 plD_bop_ps( pls );
111 plGetFam( pls );
112 }
113
114 void
115 plD_tidy_pstex( PLStream *pls )
116 {
117 PSDev *dev = (PSDev *) pls->dev;
118 PLFLT scale;
119 FILE *fp;
120
121 plD_tidy_ps( pls );
122
123 scale = pls->xpmm * 25.4 / 72.;
124
125 fp = dev->fp;
126 fprintf( fp, "\\end{picture}\n" );
127
128 fseek( fp, dev->cur_pos, SEEK_SET );
129 fprintf( fp, "\\begin{picture}(%d,%d)(%d,%d)%%\n%%",
130 ROUND( ( dev->urx - dev->llx ) * scale ),
131 ROUND( ( dev->ury - dev->lly ) * scale ),
132 ROUND( ( dev->llx - XOFFSET ) * scale ),
133 ROUND( ( dev->lly - YOFFSET ) * scale ) );
134
135 plCloseFile( pls );
136 }
137
138 void
139 proc_str( PLStream *pls, EscText *args )
140 {
141 PLFLT *t = args->xform;
142 PLFLT a1, alpha, ft_ht, angle;
143 char cptr[256], jst, ref;
144 PSDev *dev = (PSDev *) pls->dev;
145 PLINT clxmin, clxmax, clymin, clymax;
146 FILE *fp;
147
148 fp = dev->fp;
149
150 // font height
151 ft_ht = 1.6 * pls->chrht * 72.0 / 25.4; /* ft_ht in points. ht is in mm */
152
153 // calculate baseline text angle
154 angle = ( (PLFLT) ( ORIENTATION - 1 ) + pls->diorot ) * 90.;
155 a1 = acos( t[0] ) * 180. / PI;
156 if ( t[2] > 0. )
157 alpha = a1 - angle - 90.;
158 else
159 alpha = 360. - a1 - angle - 90.;
160
161 // parse string for format (escape) characters
162 parse_str( args->string, cptr );
163
164 //
165 // Reference point (center baseline of string, not latex character reference point).
166 // If base = 0, it is aligned with the center of the text box
167 // If base = 1, it is aligned with the baseline of the text box
168 // If base = 2, it is aligned with the top of the text box
169 // Currently plplot only uses base=0
170 //
171
172 if ( args->base == 2 ) // not supported by plplot
173 ref = 't';
174 else if ( args->base == 1 )
175 ref = 'b';
176 else
177 ref = 'c';
178
179 //
180 // Text justification. Left, center and right justification, which
181 // are the more common options, are supported; variable justification is
182 // only approximate, based on plplot computation of it's string lenght
183 //
184
185 if ( args->just == 0.5 )
186 jst = 'c';
187 else if ( args->just == 1. )
188 jst = 'r';
189 else
190 {
191 jst = 'l';
192 args->x = args->refx; // use hints provided by plplot
193 args->y = args->refy;
194 }
195
196 // apply transformations
197 difilt( &args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax );
198
199 // check clip limits. For now, only the reference point of the string is checked;
200 // but the the whole string should be checked -- using a postscript construct
201 // such as gsave/clip/grestore. This method can also be applied to the xfig and
202 // pstex drivers. Zoom side effect: the font size must be adjusted!
203
204 if ( args->x < clxmin || args->x > clxmax || args->y < clymin || args->y > clymax )
205 return;
206
207 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
208 &( args->x ), &( args->y ) );
209
210 #ifdef DEBUG
211 fprintf( fp, "\\put(%d,%d){\\circle{10}}\n",
212 args->x, args->y );
213 #endif
214
215 fprintf( fp, "\\put(%d,%d){\\rotatebox{%.1f}{\\makebox(0,0)[%c%c]{\\SetFigFont{%.1f}{12}",
216 args->x, args->y, alpha, jst, ref, ft_ht );
217
218 //
219 // font family, serie and shape. Currently not supported by plplot
220 //
221 // Use current font instead:
222 // 1: Normal font (latex document default font)
223 // 2: Roman font
224 // 3: Italic font (most probably latex slanted)
225 // 4: Script font (latex sans serif)
226 //
227
228 switch ( pls->cfont )
229 {
230 case ( 1 ): fprintf( fp, "{\\familydefault}" ); break;
231 case ( 2 ): fprintf( fp, "{\\rmdefault}" ); break;
232 case ( 3 ): fprintf( fp, "{\\itdefault}" ); break;
233 case ( 4 ): fprintf( fp, "{\\sfdefault}" ); break;
234 default: fprintf( fp, "{\\familydefault}" );
235 }
236
237 fprintf( fp, "{\\mddefault}{\\updefault}\n" );
238
239 // font color.
240
241 if ( color )
242 fprintf( fp, "\\special{ps: %.3f %.3f %.3f setrgbcolor}{",
243 pls->curcolor.r / 255., pls->curcolor.g / 255., pls->curcolor.b / 255. );
244 else
245 fprintf( fp, "\\special{ps: 0 0 0 setrgbcolor}{" );
246
247 fprintf( fp, "%% Your text follows:\n" );
248 fprintf( fp, "%s\n", cptr );
249 fprintf( fp, "}}}}" );
250
251 //
252 // keep ps driver happy -- needed for background and orientation.
253 // arghhh! can't calculate it, as I only have the string reference
254 // point, not its extent!
255 // Quick (and final?) *hack*, ASSUME that no more than a char height
256 // extents after/before the string reference point.
257 //
258
259 dev->llx = MIN( dev->llx, args->x - ft_ht * 25.4 / 72. * pls->xpmm );
260 dev->lly = MIN( dev->lly, args->y - ft_ht * 25.4 / 72. * pls->ypmm );
261 dev->urx = MAX( dev->urx, args->x + ft_ht * 25.4 / 72. * pls->xpmm );
262 dev->ury = MAX( dev->ury, args->y + ft_ht * 25.4 / 72. * pls->ypmm );
263 }
264
265 void
266 parse_str( const char *str, char *dest )
267 {
268 int n, opened = 0, raised = 0, overline = 0, underline = 0, fontset = 0, math = 0;
269 char *tp = dest, c, esc;
270 char greek[] = "abgGdDezyhHiklLmncCopPrsStuUfFxqQwW";
271 char *mathgreek[] = { "alpha", "beta", "gamma", "Gamma", "delta", "Delta",
272 "epsilon", "zeta", "eta", "theta", "Theta", "iota",
273 "kappa", "lambda", "Lambda", "mu", "nu", "xi", "Xi",
274 "o", "pi", "Pi", "rho", "sigma", "Sigma","tau",
275 "upsilon", "Upsilon", "phi", "Phi", "chi",
276 "psi", "Psi", "omega", "Omega" };
277
278 plgesc( &esc );
279
280 while ( *str )
281 {
282 if ( *str != esc )
283 {
284 *tp++ = *str++;
285 continue;
286 }
287 str++;
288
289 switch ( *str++ )
290 {
291 case 'u': // up one level
292 if ( raised < 0 )
293 {
294 *tp++ = '}';
295 opened--;
296 }
297 else
298 {
299 n = sprintf( tp, "\\raisebox{%.2fex}{", 0.6 );
300 tp += n; opened++;
301 }
302 raised++;
303 break;
304
305 case 'd': // down one level
306 if ( raised > 0 )
307 {
308 *tp++ = '}';
309 opened--;
310 }
311 else
312 {
313 n = sprintf( tp, "\\raisebox{%.2fex}{", -0.6 );
314 tp += n; opened++;
315 }
316 raised--;
317 break;
318
319 case 'b': // backspace
320 n = sprintf( tp, "\\hspace{-1em}" );
321 tp += n;
322 break;
323
324 case '+': // toggles overline mode. Side effect, enter math mode.
325 if ( overline )
326 {
327 if ( --math )
328 *tp++ = '}';
329 else
330 {
331 n = sprintf( tp, "}$" );
332 tp += n;
333 }
334 overline--; opened--;
335 }
336 else
337 {
338 if ( !math )
339 *tp++ = '$';
340
341 n = sprintf( tp, "\\overline{" );
342 tp += n; overline++; opened++; math++;
343 }
344 break;
345
346 case '-': // toggles underline mode. Side effect, enter math mode.
347 if ( underline )
348 {
349 if ( --math )
350 *tp++ = '}';
351 else
352 {
353 n = sprintf( tp, "}$" );
354 tp += n;
355 }
356 underline--; opened--;
357 }
358 else
359 {
360 if ( !math )
361 *tp++ = '$';
362
363 n = sprintf( tp, "\\underline{" );
364 tp += n; underline++; opened++; math++;
365 }
366 break;
367
368 case 'g': // greek letter corresponding to roman letter x
369 c = *str++;
370 n = plP_strpos( greek, c );
371 if ( n != -1 )
372 {
373 if ( !math )
374 *tp++ = '$';
375
376 *tp++ = '\\';
377 strcpy( tp, mathgreek[n] );
378 if ( isupper( c ) )
379 *tp = toupper( *tp );
380 tp += strlen( mathgreek[n] );
381 if ( !math )
382 *tp++ = '$';
383 }
384 else
385 *tp++ = c;
386
387 break;
388
389 case '(': // Hershey symbol number (nnn) (any number of digits) FIXME ???
390 plwarn( "'g(...)' text escape sequence not processed." );
391 while ( *str++ != ')' )
392 ;
393 break;
394
395 case 'f': // switch font
396
397 switch ( *str++ )
398 {
399 case 'n': // Normal
400 while ( fontset-- )
401 {
402 *tp++ = '}';
403 opened--;
404 }
405
406 if ( math )
407 {
408 *tp++ = '$';
409 math = 0;
410 }
411
412 n = sprintf( tp, "\\normalfont " );
413 tp += n;
414 break;
415
416 case 'r': // Roman
417 if ( math )
418 n = sprintf( tp, "\\mathrm{" );
419 else
420 n = sprintf( tp, "\\textrm{" );
421
422 tp += n; opened++; fontset++;
423 break;
424
425 case 'i': // Italic
426 if ( math )
427 n = sprintf( tp, "\\mathit{" );
428 else
429 n = sprintf( tp, "\\textit{" );
430
431 tp += n; opened++; fontset++;
432 break;
433
434 case 's': // Script. Don't, use sans serif
435 if ( math )
436 n = sprintf( tp, "\\mathsf{" );
437 else
438 n = sprintf( tp, "\\textsf{" );
439
440 tp += n; opened++; fontset++;
441 break;
442 }
443
444 default:
445 if ( *str == esc )
446 *tp++ = esc;
447 }
448 }
449
450 while ( opened-- )
451 *tp++ = '}';
452 *tp = '\0';
453 }
454
455 #else
456 int
457 pldummy_pstex()
458 {
459 return 0;
460 }
461
462 #endif // PLD_pstexdev