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

plsym.c

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

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