PLplot
5.10.0
|
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