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