PLplot 5.9.6
plsym.c
00001 /* $Id$
00002  *
00003  *      Point, symbol, and string plotting routines.
00004  *      Also font management code.  See the description of plLibOpen() for
00005  *      the search path used in finding the font files.
00006  *
00007  * Copyright (C) 1992  Geoffrey Furnish
00008  * Copyright (C) 1993, 1994, 1995, 2000, 2001, 2002  Maurice LeBrun
00009  * Copyright (C) 2000, 2002, 2004, 2005  Alan W. Irwin
00010  * Copyright (C) 2001, 2003, 2004  Rafael Laboissiere
00011  * Copyright (C) 2002  Vincent Darley
00012  * Copyright (C) 2004  Andrew Ross
00013  * Copyright (C) 2007  Hazen Babcock
00014  *
00015  * This file is part of PLplot.
00016  *
00017  * PLplot is free software; you can redistribute it and/or modify
00018  * it under the terms of the GNU General Library Public License as published
00019  * by the Free Software Foundation; either version 2 of the License, or
00020  * (at your option) any later version.
00021  *
00022  * PLplot is distributed in the hope that it will be useful,
00023  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00024  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025  * GNU Library General Public License for more details.
00026  *
00027  * You should have received a copy of the GNU Library General Public License
00028  * along with PLplot; if not, write to the Free Software
00029  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00030  */
00031 
00032 #ifndef __PLSYM_H__
00033 #define __PLSYM_H__
00034 
00035 #include "plplotP.h"
00036 #include <float.h>
00037 #include <ctype.h>
00038 #include "plhershey-unicode.h"
00039 
00040 /* Declarations */
00041 
00042 static short int   *fntlkup;
00043 static short int   *fntindx;
00044 static signed char *fntbffr;
00045 static short int   numberfonts, numberchars;
00046 static short int   indxleng;
00047 
00048 static short       fontloaded = 0;
00049 /* moved to plstr.h, plsc->cfont  static PLINT font = 1;  current font */
00050 
00051 #define PLMAXSTR    300
00052 #define STLEN       250
00053 
00054 static const char  font_types[] = "nris";
00055 
00056 static short       symbol_buffer[PLMAXSTR];
00057 static signed char xygrid[STLEN];
00058 
00059 int hershey2unicode( int in );
00060 
00061 /* Static function prototypes */
00062 
00063 static void
00064 pldeco( short int **sym, PLINT *length, const char *text );
00065 
00066 static void
00067 plchar( signed char *xygrid, PLFLT *xform, PLINT base, PLINT oline, PLINT uline,
00068         PLINT refx, PLINT refy, PLFLT scale, PLFLT xpmm, PLFLT ypmm,
00069         PLFLT *p_xorg, PLFLT *p_yorg, PLFLT *p_width );
00070 
00071 static PLINT
00072 plcvec( PLINT ch, signed char **xygr );
00073 
00074 static void
00075 plhrsh( PLINT ch, PLINT x, PLINT y );
00076 
00077 static void
00078 plhrsh2( PLINT ch, PLINT x, PLINT y );
00079 
00080 /*--------------------------------------------------------------------------*\
00081  * void plsym()
00082  *
00083  * Plots array y against x for n points using Hershey symbol "code".
00084  \*--------------------------------------------------------------------------*/
00085 
00086 void
00087 c_plsym( PLINT n, PLFLT *x, PLFLT *y, PLINT code )
00088 {
00089     PLINT i;
00090     PLFLT xt, yt;
00091 
00092     if ( plsc->level < 3 )
00093     {
00094         plabort( "plsym: Please set up window first" );
00095         return;
00096     }
00097     if ( code < 0 )
00098     {
00099         plabort( "plsym: Invalid code" );
00100         return;
00101     }
00102 
00103     for ( i = 0; i < n; i++ )
00104     {
00105         TRANSFORM( x[i], y[i], &xt, &yt );
00106         plhrsh( code, plP_wcpcx( xt ), plP_wcpcy( yt ) );
00107     }
00108 }
00109 
00110 /*--------------------------------------------------------------------------*\
00111  * void plpoin()
00112  *
00113  * Plots array y against x for n points using ASCII code "code".
00114  *
00115  * code=-1 means try to just draw a point.  Right now it's just a move and
00116  * a draw at the same place.  Not ideal, since a sufficiently intelligent
00117  * output device may optimize it away, or there may be faster ways of
00118  * doing it.  This is OK for now, though, and offers a 4X speedup over
00119  * drawing a Hershey font "point" (which is actually diamond shaped and
00120  * therefore takes 4 strokes to draw).
00121  \*--------------------------------------------------------------------------*/
00122 
00123 void
00124 c_plpoin( PLINT n, PLFLT *x, PLFLT *y, PLINT code )
00125 {
00126     PLINT i, sym, ifont = plsc->cfont;
00127     PLFLT xt, yt;
00128 
00129     if ( plsc->level < 3 )
00130     {
00131         plabort( "plpoin: Please set up window first" );
00132         return;
00133     }
00134     if ( code < -1 || code > 127 )
00135     {
00136         plabort( "plpoin: Invalid code" );
00137         return;
00138     }
00139 
00140     if ( code == -1 )
00141     {
00142         for ( i = 0; i < n; i++ )
00143         {
00144             TRANSFORM( x[i], y[i], &xt, &yt );
00145             pljoin( xt, yt, xt, yt );
00146         }
00147     }
00148     else
00149     {
00150         if ( ifont > numberfonts )
00151             ifont = 1;
00152         sym = *( fntlkup + ( ifont - 1 ) * numberchars + code );
00153         // One-time diagnostic output.
00154         // fprintf(stdout, "plploin code, sym = %d, %d\n", code, sym);
00155 
00156         for ( i = 0; i < n; i++ )
00157         {
00158             TRANSFORM( x[i], y[i], &xt, &yt );
00159             plhrsh( sym, plP_wcpcx( xt ), plP_wcpcy( yt ) );
00160         }
00161     }
00162 }
00163 
00164 /*--------------------------------------------------------------------------*\
00165  * void plpoin3(n, x, y, z, code)
00166  *
00167  * Draws a series of points in 3 space.  Setup similar to plline3().
00168  \*--------------------------------------------------------------------------*/
00169 
00170 void
00171 c_plpoin3( PLINT n, PLFLT *x, PLFLT *y, PLFLT *z, PLINT code )
00172 {
00173     PLINT i, sym, ifont = plsc->cfont;
00174     PLFLT u, v;
00175     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00176 
00177     if ( plsc->level < 3 )
00178     {
00179         plabort( "plpoin3: Please set up window first" );
00180         return;
00181     }
00182     if ( code < -1 || code > 127 )
00183     {
00184         plabort( "plpoin3: Invalid code" );
00185         return;
00186     }
00187 
00188     plP_gdom( &xmin, &xmax, &ymin, &ymax );
00189     plP_grange( &zscale, &zmin, &zmax );
00190 
00191     if ( code == -1 )
00192     {
00193         for ( i = 0; i < n; i++ )
00194         {
00195             if ( x[i] >= xmin && x[i] <= xmax &&
00196                  y[i] >= ymin && y[i] <= ymax &&
00197                  z[i] >= zmin && z[i] <= zmax )
00198             {
00199                 u = plP_wcpcx( plP_w3wcx( x[i], y[i], z[i] ) );
00200                 v = plP_wcpcy( plP_w3wcy( x[i], y[i], z[i] ) );
00201                 plP_movphy( (PLINT) u, (PLINT) v );
00202                 plP_draphy( (PLINT) u, (PLINT) v );
00203             }
00204         }
00205     }
00206     else
00207     {
00208         if ( ifont > numberfonts )
00209             ifont = 1;
00210         sym = *( fntlkup + ( ifont - 1 ) * numberchars + code );
00211 
00212         for ( i = 0; i < n; i++ )
00213         {
00214             if ( x[i] >= xmin && x[i] <= xmax &&
00215                  y[i] >= ymin && y[i] <= ymax &&
00216                  z[i] >= zmin && z[i] <= zmax )
00217             {
00218                 u = plP_wcpcx( plP_w3wcx( x[i], y[i], z[i] ) );
00219                 v = plP_wcpcy( plP_w3wcy( x[i], y[i], z[i] ) );
00220                 plhrsh( sym, (PLINT) u, (PLINT) v );
00221             }
00222         }
00223     }
00224     return;
00225 }
00226 
00227 /*--------------------------------------------------------------------------*\
00228  * static void plhrsh(PLINT ch, PLINT x, PLINT y)
00229  *    PLINT ch - hershey code to plot
00230  *    PLINT x - device-world x coordinate of hershey character
00231  *    PLINT y - device-world y coordinate of hershey character
00232  *
00233  *  Writes the Hershey symbol "ch" centred at the physical coordinate (x,y).
00234  *  This function is now just a "spoof" front end to the old plhersh,
00235  *  which has now been renamed to plhrsh2(). All this function does is
00236  *  decide whether or not we should render natively as unicode, and then
00237  *  convert between hershey and unicode.
00238  *
00239  *  If the function KNOWS there isn't a unicode equivalent, then it will
00240  *  try to render it as a hershey font. Understandably, this might make
00241  *  testing out the unicode functions a little tricky, so if you want
00242  *  to disable this behaviour, recompile with PL_TEST_FOR_MISSING_GLYPHS
00243  *  defined.
00244  \*--------------------------------------------------------------------------*/
00245 
00246 static void
00247 plhrsh( PLINT ch, PLINT x, PLINT y )
00248 {
00249     EscText   args;
00250     int       idx;
00251     PLUNICODE unicode_char;
00252 
00253     /* Check to see if the device understands unicode and wants to draw
00254      * symbols.
00255      */
00256     if ( ( plsc->dev_text ) && ( plsc->dev_unicode ) && ( !plsc->dev_hrshsym ) )
00257     {
00258         idx          = plhershey2unicode( ch ); /* Get the index in the lookup table */
00259         unicode_char = hershey_to_unicode_lookup_table[idx].Unicode;
00260 
00261         /*
00262          *  Test to see if there is a defined unicode glyph for this hershey code;
00263          *  if there isn't, then we pass the glyph to plhersh, and have it
00264          *  rendered the old fashioned way.
00265          *  Otherwise, we let the driver render it as unicode
00266          */
00267 
00268         if ( ( unicode_char == 0 ) || ( idx == -1 ) )
00269         {
00270 #ifndef PL_TEST_FOR_MISSING_GLYPHS
00271             plhrsh2( ch, x, y );
00272 #endif
00273         }
00274         else
00275         {
00276             PLUNICODE plhrsh_unicode_buffer[3], fci;
00277             PLFLT     xform[] = { 1.0, 0.0, 0.0, 1.0 };
00278             char      esc;
00279             args.unicode_char = unicode_char;
00280             args.font_face    = hershey_to_unicode_lookup_table[idx].Font;
00281             /* Comment out to fix problem with ps, psttf drivers */
00282             /*args.base = 1;*/
00283             args.base   = 0;
00284             args.just   = .5;
00285             args.xform  = 0;
00286             args.x      = x;
00287             args.y      = y;
00288             args.string = NULL; /* Since we are using unicode, we want this to be NULL */
00289             /* "array method" */
00290             plgesc( &esc );
00291             args.xform               = xform;
00292             args.unicode_array_len   = 1;
00293             plhrsh_unicode_buffer[0] = unicode_char;
00294             /* watch out for escape character and unescape it by appending
00295              * one extra. */
00296             if ( unicode_char == esc )
00297             {
00298                 args.unicode_array_len   = 2;
00299                 plhrsh_unicode_buffer[1] = unicode_char;
00300             }
00301 
00302             /* No need to change font back since only one character. */
00303             args.unicode_array = &plhrsh_unicode_buffer[0]; /* Get address of the unicode buffer (even though it is currently static) */
00304 
00305             plsc->original_chrht  = plsc->chrht;
00306             plsc->original_chrdef = plsc->chrdef;
00307             plsc->chrht           = plsc->symht;
00308             plsc->chrdef          = plsc->symdef;
00309 
00310             if ( plsc->alt_unicode )
00311             {
00312                 plgfci( &fci );
00313                 args.n_fci  = fci;
00314                 args.n_char = unicode_char;
00315                 plP_esc( PLESC_BEGIN_TEXT, &args );
00316                 plP_esc( PLESC_TEXT_CHAR, &args );
00317                 plP_esc( PLESC_END_TEXT, &args );
00318             }
00319             else
00320             {
00321                 plP_esc( PLESC_HAS_TEXT, &args );
00322             }
00323 
00324             plsc->chrht  = plsc->original_chrht;
00325             plsc->chrdef = plsc->original_chrdef;
00326         }
00327     }
00328     else
00329     {
00330         plhrsh2( ch, x, y );
00331     }
00332 }
00333 
00334 /*--------------------------------------------------------------------------*\
00335  * void plhrsh2()
00336  *
00337  * Writes the Hershey symbol "ch" centred at the physical coordinate (x,y).
00338  \*--------------------------------------------------------------------------*/
00339 
00340 static void
00341 plhrsh2( PLINT ch, PLINT x, PLINT y )
00342 {
00343     PLINT       cx, cy, k, penup, style;
00344     signed char *vxygrid = 0;
00345     PLFLT       scale, xscale, yscale;
00346     PLINT       llx[STLEN], lly[STLEN], l = 0;
00347 
00348     penup = 1;
00349     scale = 0.05 * plsc->symht;
00350 
00351     if ( !plcvec( ch, &vxygrid ) )
00352     {
00353         plP_movphy( x, y );
00354         return;
00355     }
00356 
00357 /* Line style must be continuous */
00358 
00359     style     = plsc->nms;
00360     plsc->nms = 0;
00361 
00362 /* Compute how many physical pixels correspond to a character pixel */
00363 
00364     xscale = scale * plsc->xpmm;
00365     yscale = scale * plsc->ypmm;
00366 
00367     k = 4;
00368     for (;; )
00369     {
00370         cx = vxygrid[k++];
00371         cy = vxygrid[k++];
00372         if ( cx == 64 && cy == 64 )
00373         {
00374             if ( l )
00375             {
00376                 plP_draphy_poly( llx, lly, l );
00377                 l = 0;
00378             }
00379             plP_movphy( x, y );
00380             plsc->nms = style;
00381             return;
00382         }
00383         else if ( cx == 64 && cy == 0 )
00384             penup = 1;
00385         else
00386         {
00387             if ( penup == 1 )
00388             {
00389                 if ( l )
00390                 {
00391                     plP_draphy_poly( llx, lly, l );
00392                     l = 0;
00393                 }
00394                 llx[l]   = ROUND( x + xscale * cx );
00395                 lly[l++] = ROUND( y + yscale * cy );
00396                 plP_movphy( llx[l - 1], lly[l - 1] );
00397                 penup = 0;
00398             }
00399             else
00400             {
00401                 llx[l]   = ROUND( x + xscale * cx );
00402                 lly[l++] = ROUND( y + yscale * cy );
00403             }
00404         }
00405     }
00406 }
00407 
00408 /*--------------------------------------------------------------------------*\
00409  * void pllab()
00410  *
00411  * Simple routine for labelling graphs.
00412  \*--------------------------------------------------------------------------*/
00413 
00414 void
00415 c_pllab( const char *xlabel, const char *ylabel, const char *tlabel )
00416 {
00417     if ( plsc->level < 2 )
00418     {
00419         plabort( "pllab: Please set up viewport first" );
00420         return;
00421     }
00422 
00423     plmtex( "t", (PLFLT) 2.0, (PLFLT) 0.5, (PLFLT) 0.5, tlabel );
00424     plmtex( "b", (PLFLT) 3.2, (PLFLT) 0.5, (PLFLT) 0.5, xlabel );
00425     plmtex( "l", (PLFLT) 5.0, (PLFLT) 0.5, (PLFLT) 0.5, ylabel );
00426 }
00427 
00428 /*--------------------------------------------------------------------------*\
00429  * void plmtex()
00430  *
00431  * Prints out "text" at specified position relative to viewport
00432  * (may be inside or outside)
00433  *
00434  * side String which is one of the following:
00435  *  B or b  :  Bottom of viewport
00436  *  T or t  :  Top of viewport
00437  *  BV or bv : Bottom of viewport, vertical text
00438  *  TV or tv : Top of viewport, vertical text
00439  *  L or l  :  Left of viewport
00440  *  R or r  :  Right of viewport
00441  *  LV or lv : Left of viewport, vertical text
00442  *  RV or rv : Right of viewport, vertical text
00443  *
00444  * disp Displacement from specified edge of viewport, measured outwards from
00445  *  the viewport in units of the current character height. The
00446  *  centerlines of the characters are aligned with the specified
00447  *  position.
00448  *
00449  * pos  Position of the reference point of the string relative to the
00450  *  viewport edge, ranging from 0.0 (left-hand edge) to 1.0 (right-hand
00451  *  edge)
00452  *
00453  * just Justification of string relative to reference point
00454  *  just = 0.0 => left hand edge of string is at reference
00455  *  just = 1.0 => right hand edge of string is at reference
00456  *  just = 0.5 => center of string is at reference
00457  \*--------------------------------------------------------------------------*/
00458 
00459 void
00460 c_plmtex( const char *side, PLFLT disp, PLFLT pos, PLFLT just,
00461           const char *text )
00462 {
00463     PLINT clpxmi, clpxma, clpymi, clpyma;
00464     PLINT vert, refx, refy, x, y;
00465     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, xform[4];
00466     PLFLT chrdef, chrht;
00467     PLFLT dispx, dispy;
00468 
00469     if ( plsc->level < 2 )
00470     {
00471         plabort( "plmtex: Please set up viewport first" );
00472         return;
00473     }
00474 
00475 /* Open clip limits to subpage limits */
00476 
00477     plP_gclp( &clpxmi, &clpxma, &clpymi, &clpyma ); /* get and store current clip limits */
00478     plP_sclp( plsc->sppxmi, plsc->sppxma, plsc->sppymi, plsc->sppyma );
00479 
00480     if ( plP_stindex( side, "BV" ) != -1 || plP_stindex( side, "bv" ) != -1 )
00481     {
00482         vert  = 1;
00483         xdv   = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
00484         ydv   = plsc->vpdymi;
00485         dispx = 0;
00486         dispy = -disp;
00487     }
00488     else if ( plP_stindex( side, "TV" ) != -1 || plP_stindex( side, "tv" ) != -1 )
00489     {
00490         vert  = 1;
00491         xdv   = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
00492         ydv   = plsc->vpdyma;
00493         dispx = 0;
00494         dispy = disp;
00495     }
00496     else if ( plP_stsearch( side, 'b' ) )
00497     {
00498         vert  = 0;
00499         xdv   = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
00500         ydv   = plsc->vpdymi;
00501         dispx = 0;
00502         dispy = -disp;
00503     }
00504     else if ( plP_stsearch( side, 't' ) )
00505     {
00506         vert  = 0;
00507         xdv   = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
00508         ydv   = plsc->vpdyma;
00509         dispx = 0;
00510         dispy = disp;
00511     }
00512     else if ( plP_stindex( side, "LV" ) != -1 || plP_stindex( side, "lv" ) != -1 )
00513     {
00514         vert  = 0;
00515         xdv   = plsc->vpdxmi;
00516         ydv   = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
00517         dispx = -disp;
00518         dispy = 0;
00519     }
00520     else if ( plP_stindex( side, "RV" ) != -1 || plP_stindex( side, "rv" ) != -1 )
00521     {
00522         vert  = 0;
00523         xdv   = plsc->vpdxma;
00524         ydv   = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
00525         dispx = disp;
00526         dispy = 0;
00527     }
00528     else if ( plP_stsearch( side, 'l' ) )
00529     {
00530         vert  = 1;
00531         xdv   = plsc->vpdxmi;
00532         ydv   = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
00533         dispx = -disp;
00534         dispy = 0;
00535     }
00536     else if ( plP_stsearch( side, 'r' ) )
00537     {
00538         vert  = 1;
00539         xdv   = plsc->vpdxma;
00540         ydv   = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
00541         dispx = disp;
00542         dispy = 0;
00543     }
00544     else
00545     {
00546         plP_sclp( clpxmi, clpxma, clpymi, clpyma ); /* restore initial clip limits */
00547         return;
00548     }
00549 
00550 /* Transformation matrix */
00551 
00552     if ( vert != 0 )
00553     {
00554         xform[0] = 0.0;
00555         xform[1] = -1.0;
00556         xform[2] = 1.0;
00557         xform[3] = 0.0;
00558     }
00559     else
00560     {
00561         xform[0] = 1.0;
00562         xform[1] = 0.0;
00563         xform[2] = 0.0;
00564         xform[3] = 1.0;
00565     }
00566 
00567 /* Convert to physical units (mm) and compute shifts */
00568 
00569     plgchr( &chrdef, &chrht );
00570     shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
00571 
00572     xmm    = plP_dcmmx( xdv ) + dispx * chrht;
00573     ymm    = plP_dcmmy( ydv ) + dispy * chrht;
00574     refxmm = xmm - shift * xform[0];
00575     refymm = ymm - shift * xform[2];
00576 
00577 /* Convert to device units (pixels) and call text plotter */
00578 
00579     x    = plP_mmpcx( xmm );
00580     y    = plP_mmpcy( ymm );
00581     refx = plP_mmpcx( refxmm );
00582     refy = plP_mmpcy( refymm );
00583 
00584     plP_text( 0, just, xform, x, y, refx, refy, text );
00585     plP_sclp( clpxmi, clpxma, clpymi, clpyma ); /* restore clip limits */
00586 }
00587 
00588 /*--------------------------------------------------------------------------*\
00589  * void plptex()
00590  *
00591  * Prints out "text" at world cooordinate (wx,wy). The text may be
00592  * at any angle "angle" relative to the horizontal. The parameter
00593  * "just" adjusts the horizontal justification of the string:
00594  *  just = 0.0 => left hand edge of string is at (wx,wy)
00595  *  just = 1.0 => right hand edge of string is at (wx,wy)
00596  *  just = 0.5 => center of string is at (wx,wy) etc.
00597  \*--------------------------------------------------------------------------*/
00598 
00599 void
00600 c_plptex( PLFLT wx, PLFLT wy, PLFLT dx, PLFLT dy, PLFLT just, const char *text )
00601 {
00602     PLINT x, y, refx, refy;
00603     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, cc, ss;
00604     PLFLT xform[4], diag;
00605     PLFLT chrdef, chrht;
00606     PLFLT dispx, dispy;
00607     PLFLT wxt, wyt, dxt, dyt;
00608 
00609     if ( plsc->level < 3 )
00610     {
00611         plabort( "plptex: Please set up window first" );
00612         return;
00613     }
00614 
00615     /* Transform both the origin and offset values */
00616     TRANSFORM( wx, wy, &wxt, &wyt );
00617     TRANSFORM( wx + dx, wy + dy, &dxt, &dyt );
00618     dxt = dxt - wxt;
00619     dyt = dyt - wyt;
00620     if ( dxt == 0.0 && dyt == 0.0 )
00621     {
00622         dxt = 1.0;
00623         dyt = 0.0;
00624     }
00625 
00626     cc   = plsc->wmxscl * dxt;
00627     ss   = plsc->wmyscl * dyt;
00628     diag = sqrt( cc * cc + ss * ss );
00629     cc  /= diag;
00630     ss  /= diag;
00631 
00632     xform[0] = cc;
00633     xform[1] = -ss;
00634     xform[2] = ss;
00635     xform[3] = cc;
00636 
00637     xdv = plP_wcdcx( wxt );
00638     ydv = plP_wcdcy( wyt );
00639 
00640     dispx = 0.;
00641     dispy = 0.;
00642 
00643 /* Convert to physical units (mm) and compute shifts */
00644 
00645     plgchr( &chrdef, &chrht );
00646     shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
00647 
00648     xmm    = plP_dcmmx( xdv ) + dispx * chrht;
00649     ymm    = plP_dcmmy( ydv ) + dispy * chrht;
00650     refxmm = xmm - shift * xform[0];
00651     refymm = ymm - shift * xform[2];
00652 
00653     x    = plP_mmpcx( xmm );
00654     y    = plP_mmpcy( ymm );
00655     refx = plP_mmpcx( refxmm );
00656     refy = plP_mmpcy( refymm );
00657 
00658     plP_text( 0, just, xform, x, y, refx, refy, text );
00659 }
00660 
00661 /*--------------------------------------------------------------------------*\
00662  * void plstr()
00663  *
00664  * Prints out a "string" at reference position with physical coordinates
00665  * (refx,refy). The coordinates of the vectors defining the string are
00666  * passed through the linear mapping defined by the 2 x 2 matrix xform()
00667  * before being plotted.  The reference position is at the left-hand edge of
00668  * the string. If base = 1, it is aligned with the baseline of the string.
00669  * If base = 0, it is aligned with the center of the character box.
00670  *
00671  * Note, all calculations are done in terms of millimetres. These are scaled
00672  * as necessary before plotting the string on the page.
00673  \*--------------------------------------------------------------------------*/
00674 
00675 void
00676 plstr( PLINT base, PLFLT *xform, PLINT refx, PLINT refy, const char *string )
00677 {
00678     short int   *symbol;
00679     signed char *vxygrid = 0;
00680 
00681     PLINT       ch, i, length, level = 0, style, oline = 0, uline = 0;
00682     PLFLT       width = 0., xorg = 0., yorg = 0., def, ht, dscale, scale;
00683 
00684     plgchr( &def, &ht );
00685     dscale = 0.05 * ht;
00686     scale  = dscale;
00687 
00688 /* Line style must be continuous */
00689 
00690     style     = plsc->nms;
00691     plsc->nms = 0;
00692 
00693     pldeco( &symbol, &length, string );
00694 
00695     for ( i = 0; i < length; i++ )
00696     {
00697         ch = symbol[i];
00698         if ( ch == -1 )   /* super-script */
00699         {
00700             level++;
00701             yorg += 16.0 * scale;
00702             scale = dscale * pow( 0.75, (double) ABS( level ) );
00703         }
00704         else if ( ch == -2 )   /* sub-script */
00705         {
00706             level--;
00707             scale = dscale * pow( 0.75, (double) ABS( level ) );
00708             yorg -= 16.0 * scale;
00709         }
00710         else if ( ch == -3 ) /* back-char */
00711             xorg -= width * scale;
00712         else if ( ch == -4 ) /* toogle overline */
00713             oline = !oline;
00714         else if ( ch == -5 ) /* toogle underline */
00715             uline = !uline;
00716         else
00717         {
00718             if ( plcvec( ch, &vxygrid ) )
00719                 plchar( vxygrid, xform, base, oline, uline, refx, refy, scale,
00720                     plsc->xpmm, plsc->ypmm, &xorg, &yorg, &width );
00721         }
00722     }
00723     plsc->nms = style;
00724 }
00725 
00726 /*--------------------------------------------------------------------------*\
00727  * plchar()
00728  *
00729  * Plots out a given stroke font character.
00730  \*--------------------------------------------------------------------------*/
00731 
00732 static void
00733 plchar( signed char *vxygrid, PLFLT *xform, PLINT base, PLINT oline, PLINT uline,
00734         PLINT refx, PLINT refy, PLFLT scale, PLFLT xpmm, PLFLT ypmm,
00735         PLFLT *p_xorg, PLFLT *p_yorg, PLFLT *p_width )
00736 {
00737     PLINT xbase, ybase, ydisp, lx, ly, cx, cy;
00738     PLINT k, penup;
00739     PLFLT x, y;
00740     PLINT llx[STLEN], lly[STLEN], l = 0;
00741 
00742     xbase    = vxygrid[2];
00743     *p_width = vxygrid[3] - xbase;
00744     if ( base == 0 )
00745     {
00746         ybase = 0;
00747         ydisp = vxygrid[0];
00748     }
00749     else
00750     {
00751         ybase = vxygrid[0];
00752         ydisp = 0;
00753     }
00754     k     = 4;
00755     penup = 1;
00756 
00757     for (;; )
00758     {
00759         cx = vxygrid[k++];
00760         cy = vxygrid[k++];
00761         if ( cx == 64 && cy == 64 )
00762         {
00763             if ( l )
00764             {
00765                 plP_draphy_poly( llx, lly, l );
00766                 l = 0;
00767             }
00768             break;
00769         }
00770         if ( cx == 64 && cy == 0 )
00771         {
00772             if ( l )
00773             {
00774                 plP_draphy_poly( llx, lly, l );
00775                 l = 0;
00776             }
00777             penup = 1;
00778         }
00779         else
00780         {
00781             x  = *p_xorg + ( cx - xbase ) * scale;
00782             y  = *p_yorg + ( cy - ybase ) * scale;
00783             lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
00784             ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
00785             if ( penup == 1 )
00786             {
00787                 if ( l )
00788                 {
00789                     plP_draphy_poly( llx, lly, l );
00790                     l = 0;
00791                 }
00792                 llx[l]   = lx;
00793                 lly[l++] = ly; /* store 1st point ! */
00794                 plP_movphy( lx, ly );
00795                 penup = 0;
00796             }
00797             else
00798             {
00799                 llx[l]   = lx;
00800                 lly[l++] = ly;
00801             }
00802         }
00803     }
00804 
00805     if ( oline )
00806     {
00807         x  = *p_xorg;
00808         y  = *p_yorg + ( 30 + ydisp ) * scale;
00809         lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
00810         ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
00811         plP_movphy( lx, ly );
00812         x  = *p_xorg + *p_width * scale;
00813         lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
00814         ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
00815         plP_draphy( lx, ly );
00816     }
00817     if ( uline )
00818     {
00819         x  = *p_xorg;
00820         y  = *p_yorg + ( -5 + ydisp ) * scale;
00821         lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
00822         ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
00823         plP_movphy( lx, ly );
00824         x  = *p_xorg + *p_width * scale;
00825         lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
00826         ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
00827         plP_draphy( lx, ly );
00828     }
00829     *p_xorg = *p_xorg + *p_width * scale;
00830 }
00831 
00832 /*--------------------------------------------------------------------------*\
00833  * PLFLT plstrl()
00834  *
00835  * Computes the length of a string in mm, including escape sequences.
00836  \*--------------------------------------------------------------------------*/
00837 
00838 PLFLT
00839 plstrl( const char *string )
00840 {
00841     short int   *symbol;
00842     signed char *vxygrid = 0;
00843     PLINT       ch, i, length, level = 0;
00844     PLFLT       width = 0., xorg = 0., dscale, scale, def, ht;
00845 
00846     plgchr( &def, &ht );
00847     dscale = 0.05 * ht;
00848     scale  = dscale;
00849     pldeco( &symbol, &length, string );
00850 
00851     for ( i = 0; i < length; i++ )
00852     {
00853         ch = symbol[i];
00854         if ( ch == -1 )
00855         {
00856             level++;
00857             scale = dscale * pow( 0.75, (double) ABS( level ) );
00858         }
00859         else if ( ch == -2 )
00860         {
00861             level--;
00862             scale = dscale * pow( 0.75, (double) ABS( level ) );
00863         }
00864         else if ( ch == -3 )
00865             xorg -= width * scale;
00866         else if ( ch == -4 || ch == -5 )
00867             ;
00868         else
00869         {
00870             if ( plcvec( ch, &vxygrid ) )
00871             {
00872                 width = vxygrid[3] - vxygrid[2];
00873                 xorg += width * scale;
00874             }
00875         }
00876     }
00877     return (PLFLT) xorg;
00878 }
00879 
00880 /*--------------------------------------------------------------------------*\
00881  * PLINT plcvec()
00882  *
00883  * Gets the character digitisation of Hershey table entry "char".
00884  * Returns 1 if there is a valid entry.
00885  \*--------------------------------------------------------------------------*/
00886 
00887 static PLINT
00888 plcvec( PLINT ch, signed char **xygr )
00889 {
00890     PLINT       k = 0, ib;
00891     signed char x, y;
00892 
00893     ch--;
00894     if ( ch < 0 || ch >= indxleng )
00895         return (PLINT) 0;
00896     ib = fntindx[ch] - 2;
00897     if ( ib == -2 )
00898         return (PLINT) 0;
00899 
00900     do
00901     {
00902         ib++;
00903         x           = fntbffr[2 * ib];
00904         y           = fntbffr[2 * ib + 1];
00905         xygrid[k++] = x;
00906         xygrid[k++] = y;
00907     } while ( ( x != 64 || y != 64 ) && k <= ( STLEN - 2 ) );
00908 
00909     if ( k == ( STLEN - 1 ) )
00910     {
00911         /* This is bad if we get here */
00912         xygrid[k] = 64;
00913         xygrid[k] = 64;
00914     }
00915 
00916     *xygr = xygrid;
00917     return (PLINT) 1;
00918 }
00919 
00920 /*--------------------------------------------------------------------------*\
00921  * void pldeco()
00922  *
00923  * Decode a character string, and return an array of float integer symbol
00924  * numbers. This routine is responsible for interpreting all escape sequences.
00925  * At present the following escape sequences are defined (the letter following
00926  * the <esc> may be either upper or lower case):
00927  *
00928  * <esc>u   : up one level (returns -1)
00929  * <esc>d   : down one level (returns -2)
00930  * <esc>b   : backspace (returns -3)
00931  * <esc>+   : toggles overline mode (returns -4)
00932  * <esc>-   : toggles underline mode (returns -5)
00933  * <esc><esc>   : <esc>
00934  * <esc>gx  : greek letter corresponding to roman letter x
00935  * <esc>fn  : switch to Normal font
00936  * <esc>fr  : switch to Roman font
00937  * <esc>fi  : switch to Italic font
00938  * <esc>fs  : switch to Script font
00939  * <esc>(nnn)   : Hershey symbol number nnn (any number of digits)
00940  *
00941  * The escape character defaults to '#', but can be changed to any of
00942  * [!#$%&*@^~] via a call to plsesc.
00943  \*--------------------------------------------------------------------------*/
00944 
00945 static void
00946 pldeco( short int **symbol, PLINT *length, const char *text )
00947 {
00948     PLINT     ch, ifont = plsc->cfont, ig, j = 0, lentxt = strlen( text );
00949     char      test, esc;
00950     short int *sym = symbol_buffer;
00951 
00952 /* Initialize parameters. */
00953 
00954     *length = 0;
00955     *symbol = symbol_buffer;
00956     plgesc( &esc );
00957     if ( ifont > numberfonts )
00958         ifont = 1;
00959 
00960 /* Get next character; treat non-printing characters as spaces. */
00961 
00962     while ( j < lentxt )
00963     {
00964         if ( *length >= PLMAXSTR )
00965             return;
00966         test = text[j++];
00967         ch   = test;
00968         if ( ch < 0 || ch > 175 )
00969             ch = 32;
00970 
00971         /* Test for escape sequence (#) */
00972 
00973         if ( ch == esc && ( lentxt - j ) >= 1 )
00974         {
00975             test = text[j++];
00976             if ( test == esc )
00977                 sym[( *length )++] = *( fntlkup + ( ifont - 1 ) * numberchars + ch );
00978 
00979             else if ( test == 'u' || test == 'U' )
00980                 sym[( *length )++] = -1;
00981 
00982             else if ( test == 'd' || test == 'D' )
00983                 sym[( *length )++] = -2;
00984 
00985             else if ( test == 'b' || test == 'B' )
00986                 sym[( *length )++] = -3;
00987 
00988             else if ( test == '+' )
00989                 sym[( *length )++] = -4;
00990 
00991             else if ( test == '-' )
00992                 sym[( *length )++] = -5;
00993 
00994             else if ( test == '(' )
00995             {
00996                 sym[*length] = 0;
00997                 while ( '0' <= text[j] && text[j] <= '9' )
00998                 {
00999                     sym[*length] = sym[*length] * 10 + text[j] - '0';
01000                     j++;
01001                 }
01002                 ( *length )++;
01003                 if ( text[j] == ')' )
01004                     j++;
01005             }
01006             else if ( test == 'f' || test == 'F' )
01007             {
01008                 test  = text[j++];
01009                 ifont = 1 + plP_strpos( font_types,
01010                     isupper( test ) ? tolower( test ) : test );
01011                 if ( ifont == 0 || ifont > numberfonts )
01012                     ifont = 1;
01013             }
01014             else if ( test == 'g' || test == 'G' )
01015             {
01016                 test = text[j++];
01017                 ig   = plP_strpos( plP_greek_mnemonic, test ) + 1;
01018                 sym[( *length )++] =
01019                     *( fntlkup + ( ifont - 1 ) * numberchars + 127 + ig );
01020             }
01021             else
01022             {
01023                 ;
01024             }
01025         }
01026         else
01027         {
01028             /* Decode character. */
01029             /* >>PC<< removed increment from following expression to fix */
01030             /* compiler bug */
01031 
01032             sym[( *length )] = *( fntlkup + ( ifont - 1 ) * numberchars + ch );
01033             ( *length )++;
01034         }
01035     }
01036 }
01037 
01038 /*--------------------------------------------------------------------------*\
01039  * PLINT plP_strpos()
01040  *
01041  * Searches string str for first occurence of character chr.  If found
01042  * the position of the character in the string is returned (the first
01043  * character has position 0).  If the character is not found a -1 is
01044  * returned.
01045  \*--------------------------------------------------------------------------*/
01046 
01047 PLINT
01048 plP_strpos( const char *str, int chr )
01049 {
01050     char *temp;
01051 
01052     if ( ( temp = strchr( str, chr ) ) )
01053         return (PLINT) ( temp - str );
01054     else
01055         return (PLINT) -1;
01056 }
01057 
01058 /*--------------------------------------------------------------------------*\
01059  * PLINT plP_stindex()
01060  *
01061  * Similar to strpos, but searches for occurence of string str2.
01062  \*--------------------------------------------------------------------------*/
01063 
01064 PLINT
01065 plP_stindex( const char *str1, const char *str2 )
01066 {
01067     PLINT base, str1ind, str2ind;
01068 
01069     for ( base = 0; *( str1 + base ) != '\0'; base++ )
01070     {
01071         for ( str1ind = base, str2ind = 0; *( str2 + str2ind ) != '\0' &&
01072               *( str2 + str2ind ) == *( str1 + str1ind ); str1ind++, str2ind++ )
01073             ;
01074 
01075         if ( *( str2 + str2ind ) == '\0' )
01076             return (PLINT) base;
01077     }
01078     return (PLINT) -1;          /* search failed */
01079 }
01080 
01081 /*--------------------------------------------------------------------------*\
01082  * PLBOOL plP_stsearch()
01083  *
01084  * Searches string str for character chr (case insensitive).
01085  \*--------------------------------------------------------------------------*/
01086 
01087 PLBOOL
01088 plP_stsearch( const char *str, int chr )
01089 {
01090     if ( strchr( str, chr ) )
01091         return TRUE;
01092     else if ( strchr( str, toupper( chr ) ) )
01093         return TRUE;
01094     else
01095         return FALSE;
01096 }
01097 
01098 /*--------------------------------------------------------------------------*\
01099  * void c_plfont(ifont)
01100  *
01101  * Sets the global font flag to 'ifont'.
01102  \*--------------------------------------------------------------------------*/
01103 
01104 void
01105 c_plfont( PLINT ifont )
01106 {
01107     PLUNICODE fci = PL_FCI_MARK;
01108     if ( plsc->level < 1 )
01109     {
01110         plabort( "plfont: Please call plinit first" );
01111         return;
01112     }
01113     if ( ifont < 1 || ifont > 4 )
01114     {
01115         plabort( "plfont: Invalid font" );
01116         return;
01117     }
01118 
01119     plsc->cfont = ifont;
01120 
01121     /* Provide some degree of forward compatibility if dealing with
01122      * unicode font. But better procedure is to call plsfci directly rather
01123      * than using this lame Hershey font interface.
01124      */
01125     switch ( ifont )
01126     {
01127     case 1:
01128         /* normal = (medium, upright, sans serif) */
01129         plP_hex2fci( PL_FCI_SANS, PL_FCI_FAMILY, &fci );
01130         plsfci( fci );
01131         break;
01132     /* roman = (medium, upright, serif) */
01133     case 2:
01134         plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
01135         plsfci( fci );
01136         break;
01137     /* italic = (medium, italic, serif) */
01138     case 3:
01139         plP_hex2fci( PL_FCI_ITALIC, PL_FCI_STYLE, &fci );
01140         plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
01141         plsfci( fci );
01142         break;
01143     /* script = (medium, upright, script) */
01144     case 4:
01145         plP_hex2fci( PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci );
01146         plsfci( fci );
01147         break;
01148     }
01149 }
01150 
01151 /*--------------------------------------------------------------------------*\
01152  * void plfntld(fnt)
01153  *
01154  * Loads either the standard or extended font.
01155  \*--------------------------------------------------------------------------*/
01156 
01157 void
01158 plfntld( PLINT fnt )
01159 {
01160     static PLINT charset;
01161     short        bffrleng;
01162     PDFstrm      *pdfs;
01163 
01164     if ( fontloaded && ( charset == fnt ) )
01165         return;
01166 
01167     plfontrel();
01168     fontloaded = 1;
01169     charset    = fnt;
01170 
01171     if ( fnt )
01172         pdfs = plLibOpenPdfstrm( PL_XFONT );
01173     else
01174         pdfs = plLibOpenPdfstrm( PL_SFONT );
01175 
01176     if ( pdfs == NULL )
01177         plexit( "Unable to either (1) open/find or (2) allocate memory for the font file" );
01178 
01179 /* Read fntlkup[] */
01180 
01181     pdf_rd_2bytes( pdfs, (U_SHORT *) &bffrleng );
01182     numberfonts = bffrleng / 256;
01183     numberchars = bffrleng & 0xff;
01184     bffrleng    = numberfonts * numberchars;
01185     fntlkup     = (short int *) malloc( bffrleng * sizeof ( short int ) );
01186     if ( !fntlkup )
01187         plexit( "plfntld: Out of memory while allocating font buffer." );
01188 
01189     pdf_rd_2nbytes( pdfs, (U_SHORT *) fntlkup, bffrleng );
01190 
01191 /* Read fntindx[] */
01192 
01193     pdf_rd_2bytes( pdfs, (U_SHORT *) &indxleng );
01194     fntindx = (short int *) malloc( indxleng * sizeof ( short int ) );
01195     if ( !fntindx )
01196         plexit( "plfntld: Out of memory while allocating font buffer." );
01197 
01198     pdf_rd_2nbytes( pdfs, (U_SHORT *) fntindx, indxleng );
01199 
01200 /* Read fntbffr[] */
01201 /* Since this is an array of char, there are no endian problems */
01202 
01203     pdf_rd_2bytes( pdfs, (U_SHORT *) &bffrleng );
01204     fntbffr = (signed char *) malloc( 2 * bffrleng * sizeof ( signed char ) );
01205     if ( !fntbffr )
01206         plexit( "plfntld: Out of memory while allocating font buffer." );
01207 
01208 #if PLPLOT_USE_TCL_CHANNELS
01209     pdf_rdx( fntbffr, sizeof ( signed char ) * ( 2 * bffrleng ), pdfs );
01210 #else
01211     plio_fread( (void *) fntbffr, (size_t) sizeof ( signed char ),
01212         (size_t) ( 2 * bffrleng ), pdfs->file );
01213 #endif
01214 
01215 /* Done */
01216 
01217     pdf_close( pdfs );
01218 }
01219 
01220 /*--------------------------------------------------------------------------*\
01221  * void plfontrel()
01222  *
01223  * Release memory for fonts.
01224  \*--------------------------------------------------------------------------*/
01225 
01226 void
01227 plfontrel( void )
01228 {
01229     if ( fontloaded )
01230     {
01231         free_mem( fntindx )
01232         free_mem( fntbffr )
01233         free_mem( fntlkup )
01234         fontloaded = 0;
01235     }
01236 }
01237 
01238 /*--------------------------------------------------------------------------*\
01239  *  int plhershey2unicode ( int in )
01240  *
01241  *  Function searches for in, the input hershey code, in a lookup table and
01242  *  returns the corresponding index in that table.
01243  *  Using this index you can work out the unicode equivalent as well as
01244  *  the closest approximate to the font-face. If the returned index is
01245  *  -1 then no match was possible.
01246  *
01247  *  Two versions of the function exist, a simple linear search version,
01248  *  and a more complex, but significantly faster, binary search version.
01249  *  If there seem to be problems with the binary search method, the brain-dead
01250  *  linear search can be enabled by defining SIMPLE_BUT_SAFE_HERSHEY_LOOKUP
01251  *  at compile time.
01252  \*--------------------------------------------------------------------------*/
01253 
01254 int plhershey2unicode( int in )
01255 {
01256 #ifdef SIMPLE_BUT_SAFE_HERSHEY_LOOKUP
01257     int ret = -1;
01258     int i;
01259 
01260     for ( i = 0; ( i < number_of_entries_in_hershey_to_unicode_table ) && ( ret == -1 ); i++ )
01261     {
01262         if ( hershey_to_unicode_lookup_table[i].Hershey == in )
01263             ret = i;
01264     }
01265 
01266     return ( ret );
01267 
01268 #else
01269 
01270     int jlo = -1, jmid, jhi = number_of_entries_in_hershey_to_unicode_table;
01271     while ( jhi - jlo > 1 )
01272     {
01273         /* Note that although jlo or jhi can be just outside valid
01274          * range (see initialization above) because of while condition
01275          * jlo < jmid < jhi and jmid must be in valid range.
01276          */
01277         jmid = ( jlo + jhi ) / 2;
01278         /* convert hershey_to_unicode_lookup_table[jmid].Hershey to signed
01279          * integer since we don't loose information - the number range
01280          * is from 1 and 2932 at the moment */
01281         if ( in > (int) ( hershey_to_unicode_lookup_table[jmid].Hershey ) )
01282             jlo = jmid;
01283         else if ( in < (int) ( hershey_to_unicode_lookup_table[jmid].Hershey ) )
01284             jhi = jmid;
01285         else
01286             /* We have found it!
01287              * in == hershey_to_unicode_lookup_table[jmid].Hershey
01288              */
01289             return ( jmid );
01290     }
01291     /* jlo is invalid or it is valid and in > hershey_to_unicode_lookup_table[jlo].Hershey.
01292      * jhi is invalid or it is valid and in < hershey_to_unicode_lookup_table[jhi].Hershey.
01293      * All these conditions together imply in cannot be found in
01294      * hershey_to_unicode_lookup_table[j].Hershey, for all j.
01295      */
01296     return ( -1 );
01297 #endif
01298 }
01299 
01300 /*--------------------------------------------------------------------------*\
01301  *  char *
01302  *  plP_FCI2FontName ( PLUNICODE fci,
01303  *                     const FCI_to_FontName_Table lookup[], const int nlookup)
01304  *
01305  *  Function takes an input FCI (font characterization integer) index,
01306  *  looks through the lookup table (which must be sorted by PLUNICODE fci),
01307  *  then returns the corresponding pointer to a valid font name.  If the FCI
01308  *  index is not present the returned value is NULL.
01309  \*--------------------------------------------------------------------------*/
01310 
01311 char *
01312 plP_FCI2FontName( PLUNICODE fci,
01313                   const FCI_to_FontName_Table lookup[], const int nlookup )
01314 {
01315     int jlo = -1, jmid, jhi = nlookup;
01316     while ( jhi - jlo > 1 )
01317     {
01318         /* Note that although jlo or jhi can be just outside valid
01319          * range (see initialization above) because of while condition
01320          * jlo < jmid < jhi and jmid must be in valid range.
01321          */
01322         jmid = ( jlo + jhi ) / 2;
01323         if ( fci > lookup[jmid].fci )
01324             jlo = jmid;
01325         else if ( fci < lookup[jmid].fci )
01326             jhi = jmid;
01327         else
01328             /* We have found it!
01329              * fci == lookup[jmid].fci
01330              */
01331             return (char *) ( lookup[jmid].pfont );
01332     }
01333     /* jlo is invalid or it is valid and fci > lookup[jlo].Unicode.
01334      * jhi is invalid or it is valid and fci < lookup[jhi].Unicode.
01335      * All these conditions together imply fci index cannot be found in lookup.
01336      * Mark lookup failure with NULL pointer.
01337      */
01338     return ( NULL );
01339 }
01340 
01341 /*--------------------------------------------------------------------------*\
01342  * void plmtex3()
01343  *
01344  * This is the 3d equivalent of plmtex(). It prints out "text" at specified
01345  * position relative to viewport (may be inside or outside)
01346  *
01347  * side String contains one or more of the following characters
01348  *  x,y,z : Specify which axis is to be labeled
01349  *  p,s   : Label the "primary" or the "secondary" axis. The "primary" axis
01350  *            being somewhat arbitrary, but basically it is the one that you'd
01351  *            expect to labeled in a 3d graph of standard orientation. Example:
01352  *            for z this would be the left hand axis.
01353  *  v     : draw the text perpendicular to the axis.
01354  *
01355  * disp Displacement from specified edge of axis, measured outwards from
01356  *  the axis in units of the current character height. The
01357  *  centerlines of the characters are aligned with the specified
01358  *  position.
01359  *
01360  * pos  Position of the reference point of the string relative to the
01361  *  axis ends, ranging from 0.0 (left-hand end) to 1.0 (right-hand
01362  *  end)
01363  *
01364  * just Justification of string relative to reference point
01365  *  just = 0.0 => left hand edge of string is at reference
01366  *  just = 1.0 => right hand edge of string is at reference
01367  *  just = 0.5 => center of string is at reference
01368  *
01369  * All calculations are done in physical coordinates.
01370  *
01371  \*--------------------------------------------------------------------------*/
01372 
01373 void
01374 c_plmtex3( const char *side, PLFLT disp, PLFLT pos, PLFLT just, const char *text )
01375 {
01376     /* local storage */
01377     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
01378     PLFLT chrdef, chrht;
01379 
01380     /* calculated */
01381     PLFLT xpc, ypc, xrefpc, yrefpc;
01382     PLFLT epx1, epy1, epx2, epy2, epx3, epy3;
01383     PLFLT dispx, dispy, xform[4];
01384     PLFLT shift, theta, temp;
01385 
01386     /* check that the plotting environment is set up */
01387     if ( plsc->level < 3 )
01388     {
01389         plabort( "plmtex3: Please set up window first" );
01390         return;
01391     }
01392 
01393     /* get plotting environment information */
01394     plP_gdom( &xmin, &xmax, &ymin, &ymax );
01395     plP_grange( &zscale, &zmin, &zmax );
01396     plgchr( &chrdef, &chrht );
01397 
01398     /* handle x/y axises */
01399     if ( ( plP_stindex( side, "x" ) != -1 ) || ( plP_stindex( side, "y" ) != -1 ) )
01400     {
01401         /* get the locations of the end points of the relevant axis */
01402 
01403         /* x axis label */
01404         if ( plP_stindex( side, "x" ) != -1 )
01405         {
01406             /* primary */
01407             if ( plP_stindex( side, "p" ) != -1 )
01408             {
01409                 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
01410                 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
01411                 epx2 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
01412                 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
01413             }
01414             else
01415             {
01416                 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
01417                 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
01418                 epx2 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
01419                 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
01420             }
01421         }
01422         else
01423         {
01424             if ( plP_stindex( side, "p" ) != -1 )
01425             {
01426                 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
01427                 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
01428                 epx2 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
01429                 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
01430             }
01431             else
01432             {
01433                 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
01434                 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
01435                 epx2 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
01436                 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
01437             }
01438         }
01439 
01440         /* text always goes from left to right */
01441         if ( epx1 > epx2 )
01442         {
01443             temp = epx1;
01444             epx1 = epx2;
01445             epx2 = temp;
01446             temp = epy1;
01447             epy1 = epy2;
01448             epy2 = temp;
01449             /* recalculate position assuming the user specified
01450              * it in the min -> max direction of the axis. */
01451             pos = 1.0 - pos;
01452         }
01453 
01454         /* calculate location of text center point */
01455 
01456         /* 1. calculate the angle of the axis we are to
01457          * draw the text on relative to the horizontal */
01458 
01459         if ( ( epx2 - epx1 ) != 0.0 )
01460         {
01461             theta = atan( ( epy2 - epy1 ) / ( epx2 - epx1 ) );
01462         }
01463         else
01464         {
01465             if ( epy2 > epy1 )
01466             {
01467                 theta = 0.5 * PI;
01468             }
01469             else
01470             {
01471                 theta = -0.5 * PI;
01472             }
01473         }
01474 
01475         /* 2. calculate the perpendicular vector */
01476 
01477         dispy = disp * chrht;
01478 
01479         /* 3. calculate x & y center points */
01480 
01481         xpc = pos * ( epx2 - epx1 ) + epx1;
01482         ypc = pos * ( epy2 - epy1 ) + epy1;
01483 
01484         /* 4. compute reference point
01485          *  It appears that drivers that cannot handle text justification
01486          *   use this as the starting point of the string.
01487          *  Calculations must be done in millimeters for this part
01488          *   so we convert to mm, do the calculation and convert back.
01489          *  The calculation is also dependent of the orientation
01490          *   (perpendicular or parallel) of the text. */
01491 
01492         xpc = plP_dcmmx( plP_pcdcx( (PLINT) xpc ) );
01493         ypc = plP_dcmmy( plP_pcdcy( (PLINT) ypc ) ) - dispy;
01494 
01495         shift = plstrl( text ) * just;
01496 
01497         if ( plP_stindex( side, "v" ) != -1 )
01498         {
01499             xrefpc = xpc;
01500             yrefpc = ypc - shift;
01501         }
01502         else
01503         {
01504             xrefpc = xpc - cos( theta ) * shift;
01505             yrefpc = ypc - sin( theta ) * shift;
01506         }
01507 
01508         xpc    = plP_mmpcx( xpc );
01509         ypc    = plP_mmpcy( ypc );
01510         xrefpc = plP_mmpcx( xrefpc );
01511         yrefpc = plP_mmpcy( yrefpc );
01512 
01513         /* 5. compute transform matrix & draw text */
01514 
01515         /* perpendicular, rotate 90 degrees & shear */
01516 
01517         if ( plP_stindex( side, "v" ) != -1 )
01518         {
01519             xform[0] = 0.0;
01520             xform[1] = -cos( theta );
01521             xform[2] = 1.0;
01522             xform[3] = -sin( theta );
01523             plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
01524         }
01525 
01526         /* parallel, rotate & shear by angle */
01527         else
01528         {
01529             xform[0] = cos( theta );
01530             xform[1] = 0.0;
01531             xform[2] = sin( theta );
01532             xform[3] = 1.0;
01533 
01534             plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
01535         }
01536     }
01537 
01538     /* handle z axises */
01539     if ( plP_stindex( side, "z" ) != -1 )
01540     {
01541         /* Find the left most of the 4 z axis options for "primary"
01542          * Also find the location of frontmost point in the graph,
01543          *  which will be needed to calculate at what angle to shear
01544          *  the text. */
01545 
01546         if ( plP_stindex( side, "p" ) != -1 )
01547         {
01548             epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
01549             epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
01550             epy2 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmax ) );
01551             epx3 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
01552             epy3 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
01553 
01554             if ( plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) ) < epx1 )
01555             {
01556                 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
01557                 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
01558                 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmax ) );
01559                 epx3 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
01560                 epy3 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
01561             }
01562 
01563             if ( plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) ) < epx1 )
01564             {
01565                 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
01566                 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
01567                 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmax ) );
01568                 epx3 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
01569                 epy3 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
01570             }
01571 
01572             if ( plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) ) < epx1 )
01573             {
01574                 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
01575                 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
01576                 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmax ) );
01577                 epx3 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
01578                 epy3 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
01579             }
01580         }
01581 
01582         /* find the right most of the 4 z axis options for "primary" */
01583         if ( plP_stindex( side, "s" ) != -1 )
01584         {
01585             epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
01586             epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
01587             epy2 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmax ) );
01588             epx3 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
01589             epy3 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
01590 
01591             if ( plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) ) > epx1 )
01592             {
01593                 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
01594                 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
01595                 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmax ) );
01596                 epx3 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
01597                 epy3 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
01598             }
01599 
01600             if ( plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) ) > epx1 )
01601             {
01602                 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
01603                 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
01604                 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmax ) );
01605                 epx3 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
01606                 epy3 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
01607             }
01608 
01609             if ( plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) ) > epx1 )
01610             {
01611                 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
01612                 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
01613                 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmax ) );
01614                 epx3 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
01615                 epy3 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
01616             }
01617         }
01618 
01619         /* Calculate location of text center point.
01620          * This is very similiar for the z axis. */
01621 
01622         /* primary and secondary have to be handled separately here */
01623 
01624         if ( plP_stindex( side, "p" ) != -1 )
01625         {
01626             /* 1. Calculate the angle of the axis we are to
01627              * draw the text on relative to the horizontal. */
01628 
01629             if ( ( epx3 - epx1 ) != 0.0 )
01630             {
01631                 theta = atan( ( epy3 - epy1 ) / ( epx3 - epx1 ) );
01632             }
01633             else
01634             {
01635                 if ( epy3 > epy1 )
01636                 {
01637                     theta = 0.5 * PI;
01638                 }
01639                 else
01640                 {
01641                     theta = -0.5 * PI;
01642                 }
01643             }
01644 
01645             /* 2. Calculate the perpendicular vector. */
01646 
01647             dispx = -cos( theta ) * disp * chrht;
01648             dispy = -sin( theta ) * disp * chrht;
01649         }
01650         else
01651         {
01652             if ( ( epx1 - epx3 ) != 0.0 )
01653             {
01654                 theta = -atan( ( epy3 - epy1 ) / ( epx1 - epx3 ) );
01655             }
01656             else
01657             {
01658                 if ( epy3 > epy1 )
01659                 {
01660                     theta = -0.5 * PI;
01661                 }
01662                 else
01663                 {
01664                     theta = 0.5 * PI;
01665                 }
01666             }
01667 
01668             dispx = cos( theta ) * disp * chrht;
01669             dispy = sin( theta ) * disp * chrht;
01670         }
01671 
01672         /* 3. Calculate x & y center points. */
01673 
01674         xpc = epx1;
01675         ypc = pos * ( epy2 - epy1 ) + epy1;
01676 
01677         /* 4. Compute the reference point. */
01678 
01679         xpc = plP_dcmmx( plP_pcdcx( (PLINT) xpc ) ) + dispx;
01680         ypc = plP_dcmmy( plP_pcdcy( (PLINT) ypc ) ) + dispy;
01681 
01682         shift = plstrl( text ) * just;
01683 
01684         if ( plP_stindex( side, "v" ) != -1 )
01685         {
01686             xrefpc = xpc - cos( theta ) * shift;
01687             yrefpc = ypc - sin( theta ) * shift;
01688         }
01689         else
01690         {
01691             xrefpc = xpc;
01692             yrefpc = ypc - shift;
01693         }
01694 
01695         xpc    = plP_mmpcx( xpc );
01696         ypc    = plP_mmpcy( ypc );
01697         xrefpc = plP_mmpcx( xrefpc );
01698         yrefpc = plP_mmpcy( yrefpc );
01699 
01700         /* 5. Compute transform matrix & draw text. */
01701 
01702         if ( plP_stindex( side, "v" ) != -1 )
01703         {
01704             xform[0] = cos( theta );
01705             xform[1] = 0.0;
01706             xform[2] = sin( theta );
01707             xform[3] = 1.0;
01708 
01709             plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
01710         }
01711 
01712         else
01713         {
01714             xform[0] = 0.0;
01715             xform[1] = -cos( theta );
01716             xform[2] = 1.0;
01717             xform[3] = -sin( theta );
01718 
01719             plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
01720         }
01721     }
01722 }
01723 
01724 /*--------------------------------------------------------------------------*\
01725  * void plptex3()
01726  *
01727  * Prints out "text" at world cooordinate (wx,wy,wz).
01728  *
01729  * The text is drawn parallel to the line between (wx,wy,wz) and
01730  * (wx+dx,wy+dy,wz+dz).
01731  *
01732  * The text is sheared so that it is "vertically" parallel to the
01733  * line between (wx,wy,wz) and (wx+sx, wy+sy, wz+sz). If sx=sy=sz=0 then
01734  * the text is simply rotated to parallel to the baseline.
01735  *
01736  * "just" adjusts the horizontal justification of the string:
01737  *  just = 0.0 => left hand edge of string is at (wx,wy)
01738  *  just = 1.0 => right hand edge of string is at (wx,wy)
01739  *  just = 0.5 => center of string is at (wx,wy) etc.
01740  *
01741  * Calculations are done in physical coordinates.
01742  *
01743  \*--------------------------------------------------------------------------*/
01744 
01745 void
01746 c_plptex3( PLFLT wx, PLFLT wy, PLFLT wz, PLFLT dx, PLFLT dy, PLFLT dz,
01747            PLFLT sx, PLFLT sy, PLFLT sz, PLFLT just, const char *text )
01748 {
01749     PLFLT xpc, ypc, xrefpc, yrefpc, xdpc, ydpc, xspc, yspc, ld, ls, cp, shift;
01750     PLFLT x_o, y_o, z_o, x_dx, y_dy, z_dz;
01751     PLFLT theta, phi, stride, xform[6], affineL[6], cosphi;
01752 
01753     /* check that the plotting environment is set up */
01754     if ( plsc->level < 3 )
01755     {
01756         plabort( "plptex3: Please set up window first" );
01757         return;
01758     }
01759 
01760     /* compute text x,y location in physical coordinates */
01761     xpc = plP_wcpcx( plP_w3wcx( wx, wy, wz ) );
01762     ypc = plP_wcpcy( plP_w3wcy( wx, wy, wz ) );
01763 
01764     /* determine angle to rotate text in the x-y plane */
01765     xdpc  = plP_wcpcx( plP_w3wcx( wx + dx, wy + dy, wz + dz ) );
01766     ydpc  = plP_wcpcy( plP_w3wcy( wx + dx, wy + dy, wz + dz ) );
01767     theta = atan2( ydpc - ypc, xdpc - xpc );
01768 
01769     /* Determine angle to shear text in the x-y plane. This is a little
01770      * messy, but basically the idea is:
01771      *
01772      * Compute the dot product of the vector d and the vector s to
01773      * determine the angle between them (acos(t) = d . s / |d| |s|).
01774      * Then because acos will return a number from 0.0 to PI, i.e.
01775      * only in quadrants 1 or 2, compute the cross product of the
01776      * two vectors. If this is negative then the angle is adjusted
01777      * 0.0 to -PI. */
01778 
01779     if ( ( sx == 0.0 ) && ( sy == 0.0 ) && ( sz == 0.0 ) )
01780     {
01781         phi = 0.0;
01782     }
01783     else
01784     {
01785         xspc = plP_wcpcx( plP_w3wcx( wx + sx, wy + sy, wz + sz ) );
01786         yspc = plP_wcpcy( plP_w3wcy( wx + sx, wy + sy, wz + sz ) );
01787         ld   = sqrt( ( xpc - xdpc ) * ( xpc - xdpc ) + ( ypc - ydpc ) * ( ypc - ydpc ) );
01788         ls   = sqrt( ( xpc - xspc ) * ( xpc - xspc ) + ( ypc - yspc ) * ( ypc - yspc ) );
01789         phi  = acos( ( ( xdpc - xpc ) * ( xspc - xpc ) + ( ydpc - ypc ) * ( yspc - ypc ) ) / ( ld * ls ) );
01790         cp   = ( xdpc - xpc ) * ( yspc - ypc ) - ( ydpc - ypc ) * ( xspc - xpc );
01791         if ( cp < 0.0 )
01792         {
01793             phi = -phi;
01794         }
01795         phi = 0.5 * PI - phi;
01796     }
01797 
01798     /* Determine how to adjust the "stride" of the text to make it
01799      * appear that it is going into (or out of) the page. Basically
01800      * scale the x baseline of the text by the normalized length of
01801      * the d vector projected into the x-y plane. */
01802     x_o  = plP_w3wcx( wx, wy, wz );
01803     y_o  = plP_w3wcy( wx, wy, wz );
01804     z_o  = plP_w3wcz( wx, wy, wz );
01805     x_dx = x_o - plP_w3wcx( wx + dx, wy + dy, wz + dz );
01806     y_dy = y_o - plP_w3wcy( wx + dx, wy + dy, wz + dz );
01807     z_dz = z_o - plP_w3wcz( wx + dx, wy + dy, wz + dz );
01808 
01809     stride = sqrt( x_dx * x_dx + y_dy * y_dy );
01810     stride = stride / sqrt( x_dx * x_dx + y_dy * y_dy + z_dz * z_dz );
01811 
01812     /* compute the reference point */
01813     xpc = plP_dcmmx( plP_pcdcx( (PLINT) xpc ) );
01814     ypc = plP_dcmmy( plP_pcdcy( (PLINT) ypc ) );
01815 
01816     shift  = plstrl( text ) * just;
01817     xrefpc = xpc - cos( theta ) * shift * stride;
01818     yrefpc = ypc - sin( theta ) * shift * stride;
01819 
01820     xpc    = plP_mmpcx( xpc );
01821     ypc    = plP_mmpcy( ypc );
01822     xrefpc = plP_mmpcx( xrefpc );
01823     yrefpc = plP_mmpcy( yrefpc );
01824 
01825     /* compute the transform */
01826     /* This affine transformation corresponds to transforming from old
01827      * coordinates to new coordinates by rotating axes, y shearing
01828      * or (y skewing), and scaling.
01829      * Comment out the explicit xform calculations because we use
01830      * the affine utilities for that calculation instead. */
01831     /*
01832      * xform[0] = cos( theta ) * stride;
01833      * xform[1] = cos( theta ) * sin( phi ) - sin( theta ) * cos( phi );
01834      * xform[2] = sin( theta ) * stride;
01835      * xform[3] = sin( theta ) * sin( phi ) + cos( theta ) * cos( phi );
01836      */
01837     plP_affine_rotate( xform, 180. * theta / PI );
01838     plP_affine_yskew( affineL, -180. * phi / PI );
01839     plP_affine_multiply( xform, affineL, xform );
01840     cosphi = cos( phi );
01841     if ( fabs( cosphi ) > 1.e-300 )
01842         plP_affine_scale( affineL, 1. / stride, 1. / cosphi );
01843     else
01844         plP_affine_scale( affineL, 1. / stride, 1.e300 );
01845     plP_affine_multiply( xform, affineL, xform );
01846 
01847     plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
01848 }
01849 
01850 /*------------------------------------------------------------------------*\
01851  * void plsfont()
01852  *
01853  * Set the family, style and weight of the current font.
01854  * This is a user-friendly front-end to plsfci.
01855  * Note: A negative value signifies that this element should not be changed.
01856  \*------------------------------------------------------------------------*/
01857 void
01858 c_plsfont( PLINT family, PLINT style, PLINT weight )
01859 {
01860     PLUNICODE fci;
01861 
01862     plgfci( &fci );
01863 
01864     if ( family >= 0 )
01865     {
01866         /* Bounds checking assumes symbol is last font */
01867         if ( family > PL_FCI_SYMBOL )
01868             plwarn( "plsfont: Value for family is out of range" );
01869         else
01870             plP_hex2fci( (unsigned char) family, PL_FCI_FAMILY, &fci );
01871     }
01872 
01873     if ( style >= 0 )
01874     {
01875         /* Bounds checking assumes oblique is last style */
01876         if ( style > PL_FCI_OBLIQUE )
01877             plwarn( "plsfont: Value for style is out of range" );
01878         else
01879             plP_hex2fci( (unsigned char) style, PL_FCI_STYLE, &fci );
01880     }
01881 
01882     if ( weight >= 0 )
01883     {
01884         /* Bounds checking assumes bold is last weight */
01885         if ( weight > PL_FCI_BOLD )
01886             plwarn( "plsfont: Value for weight is out of range" );
01887         else
01888             plP_hex2fci( (unsigned char) weight, PL_FCI_WEIGHT, &fci );
01889     }
01890 
01891     plsfci( fci );
01892 }
01893 
01894 /*------------------------------------------------------------------------*\
01895  * void plgfont()
01896  *
01897  * Get the family, style and weight of the current font.
01898  * This is a user-friendly front-end to plgfci.
01899  * Note: A NULL pointer signifies that this value should not be returned.
01900  \*------------------------------------------------------------------------*/
01901 void
01902 c_plgfont( PLINT *p_family, PLINT *p_style, PLINT *p_weight )
01903 {
01904     PLUNICODE     fci;
01905     unsigned char val;
01906 
01907     plgfci( &fci );
01908 
01909     if ( p_family )
01910     {
01911         plP_fci2hex( fci, &val, PL_FCI_FAMILY );
01912         *p_family = (PLINT) val;
01913     }
01914 
01915     if ( p_style )
01916     {
01917         plP_fci2hex( fci, &val, PL_FCI_STYLE );
01918         *p_style = (PLINT) val;
01919     }
01920 
01921     if ( p_weight )
01922     {
01923         plP_fci2hex( fci, &val, PL_FCI_WEIGHT );
01924         *p_weight = (PLINT) val;
01925     }
01926 }
01927 
01928 
01929 #undef PLSYM_H
01930 #endif
 All Data Structures Files Functions