PLplot  5.10.0
pstex.c
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines