• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

pstex.c

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

Generated on Wed Oct 12 2011 20:42:23 for PLplot by  doxygen 1.7.1