PLplot
5.10.0
|
00001 // PLplot pstex (Postscript/LaTeX) device driver. 00002 // 00003 00004 #include "plDevs.h" 00005 00006 #ifdef PLD_pstex 00007 00008 #include "plplotP.h" 00009 #include "drivers.h" 00010 #include "ps.h" 00011 00012 // Device info 00013 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_pstex = 00014 "pstex:Combined Postscript/LaTeX files:0:pstex:41:pstex\n"; 00015 00016 //-------------------------------------------------------------------------- 00017 // plD_init_pstex() 00018 // 00019 // Initialize device. 00020 //-------------------------------------------------------------------------- 00021 00022 00023 static void parse_str( const char *str, char *dest ); 00024 static void proc_str( PLStream *pls, EscText *args ); 00025 static int color = 1; 00026 00027 static DrvOpt pstex_options[] = { { "color", DRV_INT, &color, 00028 "Color Postscript/LaTeX (color=1|0)" }, 00029 { NULL, DRV_INT, NULL, NULL} }; 00030 00031 void plD_dispatch_init_pstex( PLDispatchTable *pdt ) 00032 { 00033 #ifndef ENABLE_DYNDRIVERS 00034 pdt->pl_MenuStr = "Combined Postscript/LaTeX files"; 00035 pdt->pl_DevName = "pstex"; 00036 #endif 00037 pdt->pl_type = plDevType_FileOriented; 00038 pdt->pl_seq = 41; 00039 pdt->pl_init = (plD_init_fp) plD_init_pstex; 00040 pdt->pl_line = (plD_line_fp) plD_line_ps; 00041 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_ps; 00042 pdt->pl_eop = (plD_eop_fp) plD_eop_ps; 00043 pdt->pl_bop = (plD_bop_fp) plD_bop_pstex; 00044 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_pstex; 00045 pdt->pl_state = (plD_state_fp) plD_state_ps; 00046 pdt->pl_esc = (plD_esc_fp) plD_esc_pstex; 00047 } 00048 00049 void 00050 plD_init_pstex( PLStream *pls ) 00051 { 00052 char *ofile; 00053 size_t len; 00054 PSDev *dev; 00055 FILE *fp; 00056 00057 plParseDrvOpts( pstex_options ); 00058 if ( color ) 00059 plD_init_psc( pls ); // init color postscript driver 00060 else 00061 plD_init_psm( pls ); // init monochrome postscript driver 00062 00063 dev = (PSDev *) pls->dev; 00064 00065 pls->dev_text = 1; // want to draw text 00066 pls->dev_unicode = 0; // don't want unicode 00067 00068 // open latex output file 00069 len = strlen( pls->FileName ) + 3; 00070 ofile = (char *) malloc( sizeof ( char ) * len ); 00071 snprintf( ofile, len, "%s_t", pls->FileName ); 00072 fp = fopen( ofile, "w" ); 00073 free( ofile ); 00074 dev->fp = fp; 00075 00076 fprintf( fp, "\\begin{picture}(0,0)(0,0)%%\n" ); 00077 fprintf( fp, "\\includegraphics[scale=1.,clip]{%s}%%\n", pls->FileName ); 00078 fprintf( fp, "\\end{picture}%%\n" ); 00079 // fprintf(fp,"\\setlength{\\unitlength}{%fbp}%%\n", 72./25.4/pls->xpmm); 00080 fprintf( fp, "\\setlength{\\unitlength}{%fbp}%%\n", 1.0 / ENLARGE ); 00081 fprintf( fp, "\\begingroup\\makeatletter\\ifx\\SetFigFont\\undefined%%\n" ); 00082 fprintf( fp, "\\gdef\\SetFigFont#1#2#3#4#5{%%\n" ); 00083 fprintf( fp, "\\reset@font\\fontsize{#1}{#2pt}%%\n" ); 00084 fprintf( fp, "\\fontfamily{#3}\\fontseries{#4}\\fontshape{#5}%%\n" ); 00085 fprintf( fp, "\\selectfont}%%\n" ); 00086 fprintf( fp, "\\fi\\endgroup%%\n" ); 00087 00088 dev->cur_pos = ftell( fp ); 00089 fprintf( fp, "\\begin{picture}(xxxxxx,xxxxxx)(xxxxxx,xxxxxx)%%\n" ); 00090 } 00091 00092 void 00093 plD_esc_pstex( PLStream *pls, PLINT op, void *ptr ) 00094 { 00095 switch ( op ) 00096 { 00097 case PLESC_HAS_TEXT: 00098 proc_str( pls, ptr ); 00099 break; 00100 default: 00101 plD_esc_ps( pls, op, ptr ); 00102 } 00103 } 00104 00105 void 00106 plD_bop_pstex( PLStream *pls ) 00107 { 00108 plD_bop_ps( pls ); 00109 plGetFam( pls ); 00110 } 00111 00112 void 00113 plD_tidy_pstex( PLStream *pls ) 00114 { 00115 PSDev *dev = (PSDev *) pls->dev; 00116 PLFLT scale; 00117 FILE *fp; 00118 00119 plD_tidy_ps( pls ); 00120 00121 scale = pls->xpmm * 25.4 / 72.; 00122 00123 fp = dev->fp; 00124 fprintf( fp, "\\end{picture}\n" ); 00125 00126 fseek( fp, dev->cur_pos, SEEK_SET ); 00127 fprintf( fp, "\\begin{picture}(%d,%d)(%d,%d)%%\n%%", 00128 ROUND( ( dev->urx - dev->llx ) * scale ), 00129 ROUND( ( dev->ury - dev->lly ) * scale ), 00130 ROUND( ( dev->llx - XOFFSET ) * scale ), 00131 ROUND( ( dev->lly - YOFFSET ) * scale ) ); 00132 00133 plCloseFile( pls ); 00134 } 00135 00136 void 00137 proc_str( PLStream *pls, EscText *args ) 00138 { 00139 PLFLT *t = args->xform; 00140 PLFLT a1, alpha, ft_ht, angle; 00141 char cptr[256], jst, ref; 00142 PSDev *dev = (PSDev *) pls->dev; 00143 PLINT clxmin, clxmax, clymin, clymax; 00144 FILE *fp; 00145 00146 fp = dev->fp; 00147 00148 // font height 00149 ft_ht = 1.6 * pls->chrht * 72.0 / 25.4; /* ft_ht in points. ht is in mm */ 00150 00151 // calculate baseline text angle 00152 angle = ( (PLFLT) ( ORIENTATION - 1 ) + pls->diorot ) * 90.; 00153 a1 = acos( t[0] ) * 180. / PI; 00154 if ( t[2] > 0. ) 00155 alpha = a1 - angle - 90.; 00156 else 00157 alpha = 360. - a1 - angle - 90.; 00158 00159 // parse string for format (escape) characters 00160 parse_str( args->string, cptr ); 00161 00162 // 00163 // Reference point (center baseline of string, not latex character reference point). 00164 // If base = 0, it is aligned with the center of the text box 00165 // If base = 1, it is aligned with the baseline of the text box 00166 // If base = 2, it is aligned with the top of the text box 00167 // Currently plplot only uses base=0 00168 // 00169 00170 if ( args->base == 2 ) // not supported by plplot 00171 ref = 't'; 00172 else if ( args->base == 1 ) 00173 ref = 'b'; 00174 else 00175 ref = 'c'; 00176 00177 // 00178 // Text justification. Left, center and right justification, which 00179 // are the more common options, are supported; variable justification is 00180 // only approximate, based on plplot computation of it's string lenght 00181 // 00182 00183 if ( args->just == 0.5 ) 00184 jst = 'c'; 00185 else if ( args->just == 1. ) 00186 jst = 'r'; 00187 else 00188 { 00189 jst = 'l'; 00190 args->x = args->refx; // use hints provided by plplot 00191 args->y = args->refy; 00192 } 00193 00194 // apply transformations 00195 difilt( &args->x, &args->y, 1, &clxmin, &clxmax, &clymin, &clymax ); 00196 00197 // check clip limits. For now, only the reference point of the string is checked; 00198 // but the the whole string should be checked -- using a postscript construct 00199 // such as gsave/clip/grestore. This method can also be applied to the xfig and 00200 // pstex drivers. Zoom side effect: the font size must be adjusted! 00201 00202 if ( args->x < clxmin || args->x > clxmax || args->y < clymin || args->y > clymax ) 00203 return; 00204 00205 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, 00206 &( args->x ), &( args->y ) ); 00207 00208 #ifdef DEBUG 00209 fprintf( fp, "\\put(%d,%d){\\circle{10}}\n", 00210 args->x, args->y ); 00211 #endif 00212 00213 fprintf( fp, "\\put(%d,%d){\\rotatebox{%.1f}{\\makebox(0,0)[%c%c]{\\SetFigFont{%.1f}{12}", 00214 args->x, args->y, alpha, jst, ref, ft_ht ); 00215 00216 // 00217 // font family, serie and shape. Currently not supported by plplot 00218 // 00219 // Use current font instead: 00220 // 1: Normal font (latex document default font) 00221 // 2: Roman font 00222 // 3: Italic font (most probably latex slanted) 00223 // 4: Script font (latex sans serif) 00224 // 00225 00226 switch ( pls->cfont ) 00227 { 00228 case ( 1 ): fprintf( fp, "{\\familydefault}" ); break; 00229 case ( 2 ): fprintf( fp, "{\\rmdefault}" ); break; 00230 case ( 3 ): fprintf( fp, "{\\itdefault}" ); break; 00231 case ( 4 ): fprintf( fp, "{\\sfdefault}" ); break; 00232 default: fprintf( fp, "{\\familydefault}" ); 00233 } 00234 00235 fprintf( fp, "{\\mddefault}{\\updefault}\n" ); 00236 00237 // font color. 00238 00239 if ( color ) 00240 fprintf( fp, "\\special{ps: %.3f %.3f %.3f setrgbcolor}{", 00241 pls->curcolor.r / 255., pls->curcolor.g / 255., pls->curcolor.b / 255. ); 00242 else 00243 fprintf( fp, "\\special{ps: 0 0 0 setrgbcolor}{" ); 00244 00245 fprintf( fp, "%% Your text follows:\n" ); 00246 fprintf( fp, "%s\n", cptr ); 00247 fprintf( fp, "}}}}" ); 00248 00249 // 00250 // keep ps driver happy -- needed for background and orientation. 00251 // arghhh! can't calculate it, as I only have the string reference 00252 // point, not its extent! 00253 // Quick (and final?) *hack*, ASSUME that no more than a char height 00254 // extents after/before the string reference point. 00255 // 00256 00257 dev->llx = MIN( dev->llx, args->x - ft_ht * 25.4 / 72. * pls->xpmm ); 00258 dev->lly = MIN( dev->lly, args->y - ft_ht * 25.4 / 72. * pls->ypmm ); 00259 dev->urx = MAX( dev->urx, args->x + ft_ht * 25.4 / 72. * pls->xpmm ); 00260 dev->ury = MAX( dev->ury, args->y + ft_ht * 25.4 / 72. * pls->ypmm ); 00261 } 00262 00263 void 00264 parse_str( const char *str, char *dest ) 00265 { 00266 int n, opened = 0, raised = 0, overline = 0, underline = 0, fontset = 0, math = 0; 00267 char *tp = dest, c, esc; 00268 char greek[] = "abgGdDezyhHiklLmncCopPrsStuUfFxqQwW"; 00269 char *mathgreek[] = { "alpha", "beta", "gamma", "Gamma", "delta", "Delta", 00270 "epsilon", "zeta", "eta", "theta", "Theta", "iota", 00271 "kappa", "lambda", "Lambda", "mu", "nu", "xi", "Xi", 00272 "o", "pi", "Pi", "rho", "sigma", "Sigma","tau", 00273 "upsilon", "Upsilon", "phi", "Phi", "chi", 00274 "psi", "Psi", "omega", "Omega" }; 00275 00276 plgesc( &esc ); 00277 00278 while ( *str ) 00279 { 00280 if ( *str != esc ) 00281 { 00282 *tp++ = *str++; 00283 continue; 00284 } 00285 str++; 00286 00287 switch ( *str++ ) 00288 { 00289 case 'u': // up one level 00290 if ( raised < 0 ) 00291 { 00292 *tp++ = '}'; 00293 opened--; 00294 } 00295 else 00296 { 00297 n = sprintf( tp, "\\raisebox{%.2fex}{", 0.6 ); 00298 tp += n; opened++; 00299 } 00300 raised++; 00301 break; 00302 00303 case 'd': // down one level 00304 if ( raised > 0 ) 00305 { 00306 *tp++ = '}'; 00307 opened--; 00308 } 00309 else 00310 { 00311 n = sprintf( tp, "\\raisebox{%.2fex}{", -0.6 ); 00312 tp += n; opened++; 00313 } 00314 raised--; 00315 break; 00316 00317 case 'b': // backspace 00318 n = sprintf( tp, "\\hspace{-1em}" ); 00319 tp += n; 00320 break; 00321 00322 case '+': // toggles overline mode. Side effect, enter math mode. 00323 if ( overline ) 00324 { 00325 if ( --math ) 00326 *tp++ = '}'; 00327 else 00328 { 00329 n = sprintf( tp, "}$" ); 00330 tp += n; 00331 } 00332 overline--; opened--; 00333 } 00334 else 00335 { 00336 if ( !math ) 00337 *tp++ = '$'; 00338 00339 n = sprintf( tp, "\\overline{" ); 00340 tp += n; overline++; opened++; math++; 00341 } 00342 break; 00343 00344 case '-': // toggles underline mode. Side effect, enter math mode. 00345 if ( underline ) 00346 { 00347 if ( --math ) 00348 *tp++ = '}'; 00349 else 00350 { 00351 n = sprintf( tp, "}$" ); 00352 tp += n; 00353 } 00354 underline--; opened--; 00355 } 00356 else 00357 { 00358 if ( !math ) 00359 *tp++ = '$'; 00360 00361 n = sprintf( tp, "\\underline{" ); 00362 tp += n; underline++; opened++; math++; 00363 } 00364 break; 00365 00366 case 'g': // greek letter corresponding to roman letter x 00367 c = *str++; 00368 n = plP_strpos( greek, c ); 00369 if ( n != -1 ) 00370 { 00371 if ( !math ) 00372 *tp++ = '$'; 00373 00374 *tp++ = '\\'; 00375 strcpy( tp, mathgreek[n] ); 00376 if ( isupper( c ) ) 00377 *tp = toupper( *tp ); 00378 tp += strlen( mathgreek[n] ); 00379 if ( !math ) 00380 *tp++ = '$'; 00381 } 00382 else 00383 *tp++ = c; 00384 00385 break; 00386 00387 case '(': // Hershey symbol number (nnn) (any number of digits) FIXME ??? 00388 plwarn( "'g(...)' text escape sequence not processed." ); 00389 while ( *str++ != ')' ) 00390 ; 00391 break; 00392 00393 case 'f': // switch font 00394 00395 switch ( *str++ ) 00396 { 00397 case 'n': // Normal 00398 while ( fontset-- ) 00399 { 00400 *tp++ = '}'; 00401 opened--; 00402 } 00403 00404 if ( math ) 00405 { 00406 *tp++ = '$'; 00407 math = 0; 00408 } 00409 00410 n = sprintf( tp, "\\normalfont " ); 00411 tp += n; 00412 break; 00413 00414 case 'r': // Roman 00415 if ( math ) 00416 n = sprintf( tp, "\\mathrm{" ); 00417 else 00418 n = sprintf( tp, "\\textrm{" ); 00419 00420 tp += n; opened++; fontset++; 00421 break; 00422 00423 case 'i': // Italic 00424 if ( math ) 00425 n = sprintf( tp, "\\mathit{" ); 00426 else 00427 n = sprintf( tp, "\\textit{" ); 00428 00429 tp += n; opened++; fontset++; 00430 break; 00431 00432 case 's': // Script. Don't, use sans serif 00433 if ( math ) 00434 n = sprintf( tp, "\\mathsf{" ); 00435 else 00436 n = sprintf( tp, "\\textsf{" ); 00437 00438 tp += n; opened++; fontset++; 00439 break; 00440 } 00441 00442 default: 00443 if ( *str == esc ) 00444 *tp++ = esc; 00445 } 00446 } 00447 00448 while ( opened-- ) 00449 *tp++ = '}'; 00450 *tp = '\0'; 00451 } 00452 00453 #else 00454 int 00455 pldummy_pstex() 00456 { 00457 return 0; 00458 } 00459 00460 #endif // PLD_pstexdev