PLplot: plsym.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plsym.c
Go to the documentation of this file.
1 // $Id: plsym.c 11973 2011-10-17 21:16:39Z andrewross $
2 //
3 // Point, symbol, and string plotting routines.
4 // Also font management code. See the description of plLibOpen() for
5 // the search path used in finding the font files.
6 //
7 // Copyright (C) 1992 Geoffrey Furnish
8 // Copyright (C) 1993, 1994, 1995, 2000, 2001, 2002 Maurice LeBrun
9 // Copyright (C) 2000-2010 Alan W. Irwin
10 // Copyright (C) 2001, 2003, 2004 Rafael Laboissiere
11 // Copyright (C) 2002 Vincent Darley
12 // Copyright (C) 2004 Andrew Ross
13 // Copyright (C) 2007 Hazen Babcock
14 //
15 // This file is part of PLplot.
16 //
17 // PLplot is free software; you can redistribute it and/or modify
18 // it under the terms of the GNU Library General Public License as published
19 // by the Free Software Foundation; either version 2 of the License, or
20 // (at your option) any later version.
21 //
22 // PLplot is distributed in the hope that it will be useful,
23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 // GNU Library General Public License for more details.
26 //
27 // You should have received a copy of the GNU Library General Public License
28 // along with PLplot; if not, write to the Free Software
29 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 //
31
36
37 #ifndef __PLSYM_H__
38 #define __PLSYM_H__
39
40 #include "plplotP.h"
41 #include <float.h>
42 #include <ctype.h>
43 #include "plhershey-unicode.h"
44
45 // Declarations
46
47 static short int *fntlkup;
48 static short int *fntindx;
49 static signed char *fntbffr;
50 static short int numberfonts, numberchars;
51 static short int indxleng;
52
53 static short fontloaded = 0;
54 // moved to plstr.h, plsc->cfont static PLINT font = 1; current font
55
56 #define PLMAXSTR 300
57 #define STLEN 250
58
59 static const char font_types[] = "nris";
60
61 static short symbol_buffer[PLMAXSTR];
62 static signed char xygrid[STLEN];
63
64 int hershey2unicode( int in );
65
66 // Static function prototypes
67
68 static void
69 pldeco( short int **sym, PLINT *length, const char *text );
70
71 static void
72 plchar( signed char *xygrid, PLFLT *xform, PLINT base, PLINT oline, PLINT uline,
73 PLINT refx, PLINT refy, PLFLT scale, PLFLT xpmm, PLFLT ypmm,
74 PLFLT *p_xorg, PLFLT *p_yorg, PLFLT *p_width );
75
76 static PLINT
77 plcvec( PLINT ch, signed char **xygr );
78
79 static void
80 plhrsh( PLINT ch, PLINT x, PLINT y );
81
82 static void
83 plhrsh2( PLINT ch, PLINT x, PLINT y );
84
85 //--------------------------------------------------------------------------
100 //--------------------------------------------------------------------------
101
102 void
103 c_plstring( PLINT n, const PLFLT *x, const PLFLT *y, const char *string )
104 {
105 PLINT i;
106 for ( i = 0; i < n; i++ )
107 {
108 c_plptex( x[i], y[i], 1., 0., 0.5, string );
109 }
110 }
111
112 //--------------------------------------------------------------------------
120 //--------------------------------------------------------------------------
121
122 void
123 c_plsym( PLINT n, const PLFLT *x, const PLFLT *y, PLINT code )
124 {
125 PLINT i;
126 PLFLT xt, yt;
127
128 if ( plsc->level < 3 )
129 {
130 plabort( "plsym: Please set up window first" );
131 return;
132 }
133 if ( code < 0 )
134 {
135 plabort( "plsym: Invalid code" );
136 return;
137 }
138
139 for ( i = 0; i < n; i++ )
140 {
141 TRANSFORM( x[i], y[i], &xt, &yt );
142 plhrsh( code, plP_wcpcx( xt ), plP_wcpcy( yt ) );
143 }
144 }
145
146 //--------------------------------------------------------------------------
164 //--------------------------------------------------------------------------
165
166 void
167 c_plpoin( PLINT n, const PLFLT *x, const PLFLT *y, PLINT code )
168 {
169 PLINT i, sym, ifont = plsc->cfont;
170 PLFLT xt, yt;
171
172 if ( plsc->level < 3 )
173 {
174 plabort( "plpoin: Please set up window first" );
175 return;
176 }
177 if ( code < -1 || code > 127 )
178 {
179 plabort( "plpoin: Invalid code" );
180 return;
181 }
182
183 if ( code == -1 )
184 {
185 for ( i = 0; i < n; i++ )
186 {
187 TRANSFORM( x[i], y[i], &xt, &yt );
188 pljoin( xt, yt, xt, yt );
189 }
190 }
191 else
192 {
193 if ( ifont > numberfonts )
194 ifont = 1;
195 sym = *( fntlkup + ( ifont - 1 ) * numberchars + code );
196 // One-time diagnostic output.
197 // fprintf(stdout, "plploin code, sym = %d, %d\n", code, sym);
198
199 for ( i = 0; i < n; i++ )
200 {
201 TRANSFORM( x[i], y[i], &xt, &yt );
202 plhrsh( sym, plP_wcpcx( xt ), plP_wcpcy( yt ) );
203 }
204 }
205 }
206
207 //--------------------------------------------------------------------------
227 //--------------------------------------------------------------------------
228
229 void
230 c_plpoin3( PLINT n, const PLFLT *x, const PLFLT *y, const PLFLT *z, PLINT code )
231 {
232 PLINT i, sym, ifont = plsc->cfont;
233 PLFLT u, v;
234 PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
235
236 if ( plsc->level < 3 )
237 {
238 plabort( "plpoin3: Please set up window first" );
239 return;
240 }
241 if ( code < -1 || code > 127 )
242 {
243 plabort( "plpoin3: Invalid code" );
244 return;
245 }
246
247 plP_gdom( &xmin, &xmax, &ymin, &ymax );
248 plP_grange( &zscale, &zmin, &zmax );
249
250 if ( code == -1 )
251 {
252 for ( i = 0; i < n; i++ )
253 {
254 if ( x[i] >= xmin && x[i] <= xmax &&
255 y[i] >= ymin && y[i] <= ymax &&
256 z[i] >= zmin && z[i] <= zmax )
257 {
258 u = plP_wcpcx( plP_w3wcx( x[i], y[i], z[i] ) );
259 v = plP_wcpcy( plP_w3wcy( x[i], y[i], z[i] ) );
260 plP_movphy( (PLINT) u, (PLINT) v );
261 plP_draphy( (PLINT) u, (PLINT) v );
262 }
263 }
264 }
265 else
266 {
267 if ( ifont > numberfonts )
268 ifont = 1;
269 sym = *( fntlkup + ( ifont - 1 ) * numberchars + code );
270
271 for ( i = 0; i < n; i++ )
272 {
273 if ( x[i] >= xmin && x[i] <= xmax &&
274 y[i] >= ymin && y[i] <= ymax &&
275 z[i] >= zmin && z[i] <= zmax )
276 {
277 u = plP_wcpcx( plP_w3wcx( x[i], y[i], z[i] ) );
278 v = plP_wcpcy( plP_w3wcy( x[i], y[i], z[i] ) );
279 plhrsh( sym, (PLINT) u, (PLINT) v );
280 }
281 }
282 }
283 }
284
285 //--------------------------------------------------------------------------
303 //--------------------------------------------------------------------------
304
305 void
306 c_plstring3( PLINT n, const PLFLT *x, const PLFLT *y, const PLFLT *z, const char * string )
307 {
308 PLINT i;
309 PLFLT u, v;
310 PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
311
312 if ( plsc->level < 3 )
313 {
314 plabort( "plstring3: Please set up window first" );
315 return;
316 }
317
318 plP_gdom( &xmin, &xmax, &ymin, &ymax );
319 plP_grange( &zscale, &zmin, &zmax );
320
321 for ( i = 0; i < n; i++ )
322 {
323 if ( x[i] >= xmin && x[i] <= xmax &&
324 y[i] >= ymin && y[i] <= ymax &&
325 z[i] >= zmin && z[i] <= zmax )
326 {
327 u = plP_w3wcx( x[i], y[i], z[i] );
328 v = plP_w3wcy( x[i], y[i], z[i] );
329 c_plptex( u, v, 1., 0., 0.5, string );
330 }
331 }
332 }
333
334 //--------------------------------------------------------------------------
335 // static void plhrsh(PLINT ch, PLINT x, PLINT y)
336 // PLINT ch - hershey code to plot
337 // PLINT x - device-world x coordinate of hershey character
338 // PLINT y - device-world y coordinate of hershey character
339 //
340 // Writes the Hershey symbol "ch" centred at the physical coordinate (x,y).
341 // This function is now just a "spoof" front end to the old plhersh,
342 // which has now been renamed to plhrsh2(). All this function does is
343 // decide whether or not we should render natively as unicode, and then
344 // convert between hershey and unicode.
345 //
346 // If the function KNOWS there isn't a unicode equivalent, then it will
347 // try to render it as a hershey font. Understandably, this might make
348 // testing out the unicode functions a little tricky, so if you want
349 // to disable this behaviour, recompile with PL_TEST_FOR_MISSING_GLYPHS
350 // defined.
351 //--------------------------------------------------------------------------
352
353 static void
354 plhrsh( PLINT ch, PLINT x, PLINT y )
355 {
356 EscText args;
357 int idx;
358 PLUNICODE unicode_char;
359
360 // Check to see if the device understands unicode and wants to draw
361 // symbols.
362 //
363 if ( ( plsc->dev_text ) && ( plsc->dev_unicode ) && ( !plsc->dev_hrshsym ) )
364 {
365 idx = plhershey2unicode( ch ); // Get the index in the lookup table
366 unicode_char = hershey_to_unicode_lookup_table[idx].Unicode;
367
368 //
369 // Test to see if there is a defined unicode glyph for this hershey code;
370 // if there isn't, then we pass the glyph to plhersh, and have it
371 // rendered the old fashioned way.
372 // Otherwise, we let the driver render it as unicode
373 //
374
375 if ( ( unicode_char == 0 ) || ( idx == -1 ) )
376 {
377 #ifndef PL_TEST_FOR_MISSING_GLYPHS
378 plhrsh2( ch, x, y );
379 #endif
380 }
381 else
382 {
383 PLUNICODE plhrsh_unicode_buffer[3], fci;
384 PLFLT xform[] = { 1.0, 0.0, 0.0, 1.0 };
385 char esc;
386 args.unicode_char = unicode_char;
387 args.font_face = hershey_to_unicode_lookup_table[idx].Font;
388 // Comment out to fix problem with ps, psttf drivers
389 //args.base = 1;
390 args.base = 0;
391 args.just = .5;
392 args.xform = 0;
393 args.x = x;
394 args.y = y;
395 args.string = NULL; // Since we are using unicode, we want this to be NULL
396 // "array method"
397 plgesc( &esc );
398 args.xform = xform;
399 args.unicode_array_len = 1;
400 plhrsh_unicode_buffer[0] = unicode_char;
401 // watch out for escape character and unescape it by appending
402 // one extra.
403 if ( unicode_char == (PLUNICODE) esc )
404 {
405 args.unicode_array_len = 2;
406 plhrsh_unicode_buffer[1] = unicode_char;
407 }
408
409 // No need to change font back since only one character.
410 args.unicode_array = &plhrsh_unicode_buffer[0]; // Get address of the unicode buffer (even though it is currently static)
411
412 plsc->original_chrht = plsc->chrht;
413 plsc->original_chrdef = plsc->chrdef;
414 plsc->chrht = plsc->symht;
415 plsc->chrdef = plsc->symdef;
416
417 if ( plsc->alt_unicode )
418 {
419 plgfci( &fci );
420 args.n_fci = fci;
421 args.n_char = unicode_char;
422 plP_esc( PLESC_BEGIN_TEXT, &args );
423 plP_esc( PLESC_TEXT_CHAR, &args );
424 plP_esc( PLESC_END_TEXT, &args );
425 }
426 else
427 {
428 plP_esc( PLESC_HAS_TEXT, &args );
429 }
430
431 plsc->chrht = plsc->original_chrht;
432 plsc->chrdef = plsc->original_chrdef;
433 }
434 }
435 else
436 {
437 plhrsh2( ch, x, y );
438 }
439 }
440
441 //--------------------------------------------------------------------------
442 // void plhrsh2()
443 //
444 // Writes the Hershey symbol "ch" centred at the physical coordinate (x,y).
445 //--------------------------------------------------------------------------
446
447 static void
448 plhrsh2( PLINT ch, PLINT x, PLINT y )
449 {
450 PLINT cx, cy, k, penup, style;
451 signed char *vxygrid = 0;
452 PLFLT scale, xscale, yscale;
453 PLINT llx[STLEN], lly[STLEN], l = 0;
454
455 penup = 1;
456 scale = 0.05 * plsc->symht;
457
458 if ( !plcvec( ch, &vxygrid ) )
459 {
460 plP_movphy( x, y );
461 return;
462 }
463
464 // Line style must be continuous
465
466 style = plsc->nms;
467 plsc->nms = 0;
468
469 // Compute how many physical pixels correspond to a character pixel
470
471 xscale = scale * plsc->xpmm;
472 yscale = scale * plsc->ypmm;
473
474 k = 4;
475 for (;; )
476 {
477 cx = vxygrid[k++];
478 cy = vxygrid[k++];
479 if ( cx == 64 && cy == 64 )
480 {
481 if ( l )
482 {
483 plP_draphy_poly( llx, lly, l );
484 l = 0;
485 }
486 plP_movphy( x, y );
487 plsc->nms = style;
488 return;
489 }
490 else if ( cx == 64 && cy == 0 )
491 penup = 1;
492 else
493 {
494 if ( penup == 1 )
495 {
496 if ( l )
497 {
498 plP_draphy_poly( llx, lly, l );
499 l = 0;
500 }
501 llx[l] = ROUND( x + xscale * cx );
502 lly[l++] = ROUND( y + yscale * cy );
503 plP_movphy( llx[l - 1], lly[l - 1] );
504 penup = 0;
505 }
506 else
507 {
508 llx[l] = ROUND( x + xscale * cx );
509 lly[l++] = ROUND( y + yscale * cy );
510 }
511 }
512 }
513 }
514
515 //--------------------------------------------------------------------------
516 // void pllab()
517 //
518 // Simple routine for labelling graphs.
519 //--------------------------------------------------------------------------
520
521 void
522 c_pllab( const char *xlabel, const char *ylabel, const char *tlabel )
523 {
524 if ( plsc->level < 2 )
525 {
526 plabort( "pllab: Please set up viewport first" );
527 return;
528 }
529
530 plmtex( "t", (PLFLT) 2.0, (PLFLT) 0.5, (PLFLT) 0.5, tlabel );
531 plmtex( "b", (PLFLT) 3.2, (PLFLT) 0.5, (PLFLT) 0.5, xlabel );
532 plmtex( "l", (PLFLT) 5.0, (PLFLT) 0.5, (PLFLT) 0.5, ylabel );
533 }
534
535 //--------------------------------------------------------------------------
536 // void plmtex()
537 //
538 // Prints out "text" at specified position relative to viewport
539 // (may be inside or outside)
540 //
541 // side String which is one of the following:
542 // B or b : Bottom of viewport
543 // T or t : Top of viewport
544 // BV or bv : Bottom of viewport, vertical text
545 // TV or tv : Top of viewport, vertical text
546 // L or l : Left of viewport
547 // R or r : Right of viewport
548 // LV or lv : Left of viewport, vertical text
549 // RV or rv : Right of viewport, vertical text
550 //
551 // disp Displacement from specified edge of viewport, measured outwards from
552 // the viewport in units of the current character height. The
553 // centerlines of the characters are aligned with the specified
554 // position.
555 //
556 // pos Position of the reference point of the string relative to the
557 // viewport edge, ranging from 0.0 (left-hand edge) to 1.0 (right-hand
558 // edge)
559 //
560 // just Justification of string relative to reference point
561 // just = 0.0 => left hand edge of string is at reference
562 // just = 1.0 => right hand edge of string is at reference
563 // just = 0.5 => center of string is at reference
564 //--------------------------------------------------------------------------
565
566 void
567 c_plmtex( const char *side, PLFLT disp, PLFLT pos, PLFLT just,
568 const char *text )
569 {
570 PLINT clpxmi, clpxma, clpymi, clpyma;
571 PLINT vert, refx, refy, x, y;
572 PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, xform[4];
573 PLFLT chrdef, chrht;
574 PLFLT dispx, dispy;
575
576 if ( plsc->level < 2 )
577 {
578 plabort( "plmtex: Please set up viewport first" );
579 return;
580 }
581
582 // Open clip limits to subpage limits
583
584 plP_gclp( &clpxmi, &clpxma, &clpymi, &clpyma ); // get and store current clip limits
585 plP_sclp( plsc->sppxmi, plsc->sppxma, plsc->sppymi, plsc->sppyma );
586
587 if ( plP_stindex( side, "BV" ) != -1 || plP_stindex( side, "bv" ) != -1 )
588 {
589 vert = 1;
590 xdv = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
591 ydv = plsc->vpdymi;
592 dispx = 0;
593 dispy = -disp;
594 }
595 else if ( plP_stindex( side, "TV" ) != -1 || plP_stindex( side, "tv" ) != -1 )
596 {
597 vert = 1;
598 xdv = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
599 ydv = plsc->vpdyma;
600 dispx = 0;
601 dispy = disp;
602 }
603 else if ( plP_stsearch( side, 'b' ) )
604 {
605 vert = 0;
606 xdv = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
607 ydv = plsc->vpdymi;
608 dispx = 0;
609 dispy = -disp;
610 }
611 else if ( plP_stsearch( side, 't' ) )
612 {
613 vert = 0;
614 xdv = plsc->vpdxmi + ( plsc->vpdxma - plsc->vpdxmi ) * pos;
615 ydv = plsc->vpdyma;
616 dispx = 0;
617 dispy = disp;
618 }
619 else if ( plP_stindex( side, "LV" ) != -1 || plP_stindex( side, "lv" ) != -1 )
620 {
621 vert = 0;
622 xdv = plsc->vpdxmi;
623 ydv = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
624 dispx = -disp;
625 dispy = 0;
626 }
627 else if ( plP_stindex( side, "RV" ) != -1 || plP_stindex( side, "rv" ) != -1 )
628 {
629 vert = 0;
630 xdv = plsc->vpdxma;
631 ydv = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
632 dispx = disp;
633 dispy = 0;
634 }
635 else if ( plP_stsearch( side, 'l' ) )
636 {
637 vert = 1;
638 xdv = plsc->vpdxmi;
639 ydv = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
640 dispx = -disp;
641 dispy = 0;
642 }
643 else if ( plP_stsearch( side, 'r' ) )
644 {
645 vert = 1;
646 xdv = plsc->vpdxma;
647 ydv = plsc->vpdymi + ( plsc->vpdyma - plsc->vpdymi ) * pos;
648 dispx = disp;
649 dispy = 0;
650 }
651 else
652 {
653 plP_sclp( clpxmi, clpxma, clpymi, clpyma ); // restore initial clip limits
654 return;
655 }
656
657 // Transformation matrix
658
659 if ( vert != 0 )
660 {
661 xform[0] = 0.0;
662 xform[1] = -1.0;
663 xform[2] = 1.0;
664 xform[3] = 0.0;
665 }
666 else
667 {
668 xform[0] = 1.0;
669 xform[1] = 0.0;
670 xform[2] = 0.0;
671 xform[3] = 1.0;
672 }
673
674 // Convert to physical units (mm) and compute shifts
675
676 plgchr( &chrdef, &chrht );
677 shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
678
679 xmm = plP_dcmmx( xdv ) + dispx * chrht;
680 ymm = plP_dcmmy( ydv ) + dispy * chrht;
681 refxmm = xmm - shift * xform[0];
682 refymm = ymm - shift * xform[2];
683
684 // Convert to device units (pixels) and call text plotter
685
686 x = plP_mmpcx( xmm );
687 y = plP_mmpcy( ymm );
688 refx = plP_mmpcx( refxmm );
689 refy = plP_mmpcy( refymm );
690
691 plP_text( 0, just, xform, x, y, refx, refy, text );
692 plP_sclp( clpxmi, clpxma, clpymi, clpyma ); // restore clip limits
693 }
694
695 //--------------------------------------------------------------------------
696 // void plptex()
697 //
698 // Prints out "text" at world cooordinate (wx,wy). The text may be
699 // at any angle "angle" relative to the horizontal. The parameter
700 // "just" adjusts the horizontal justification of the string:
701 // just = 0.0 => left hand edge of string is at (wx,wy)
702 // just = 1.0 => right hand edge of string is at (wx,wy)
703 // just = 0.5 => center of string is at (wx,wy) etc.
704 //--------------------------------------------------------------------------
705
706 void
707 c_plptex( PLFLT wx, PLFLT wy, PLFLT dx, PLFLT dy, PLFLT just, const char *text )
708 {
709 PLINT x, y, refx, refy;
710 PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, cc, ss;
711 PLFLT xform[4], diag;
712 PLFLT chrdef, chrht;
713 PLFLT dispx, dispy;
714 PLFLT wxt, wyt, dxt, dyt;
715
716 if ( plsc->level < 3 )
717 {
718 plabort( "plptex: Please set up window first" );
719 return;
720 }
721
722 // Transform both the origin and offset values
723 TRANSFORM( wx, wy, &wxt, &wyt );
724 TRANSFORM( wx + dx, wy + dy, &dxt, &dyt );
725 dxt = dxt - wxt;
726 dyt = dyt - wyt;
727 if ( dxt == 0.0 && dyt == 0.0 )
728 {
729 dxt = 1.0;
730 dyt = 0.0;
731 }
732
733 cc = plsc->wmxscl * dxt;
734 ss = plsc->wmyscl * dyt;
735 diag = sqrt( cc * cc + ss * ss );
736 cc /= diag;
737 ss /= diag;
738
739 xform[0] = cc;
740 xform[1] = -ss;
741 xform[2] = ss;
742 xform[3] = cc;
743
744 xdv = plP_wcdcx( wxt );
745 ydv = plP_wcdcy( wyt );
746
747 dispx = 0.;
748 dispy = 0.;
749
750 // Convert to physical units (mm) and compute shifts
751
752 plgchr( &chrdef, &chrht );
753 shift = ( just == 0.0 ) ? 0.0 : plstrl( text ) * just;
754
755 xmm = plP_dcmmx( xdv ) + dispx * chrht;
756 ymm = plP_dcmmy( ydv ) + dispy * chrht;
757 refxmm = xmm - shift * xform[0];
758 refymm = ymm - shift * xform[2];
759
760 x = plP_mmpcx( xmm );
761 y = plP_mmpcy( ymm );
762 refx = plP_mmpcx( refxmm );
763 refy = plP_mmpcy( refymm );
764
765 plP_text( 0, just, xform, x, y, refx, refy, text );
766 }
767
768 //--------------------------------------------------------------------------
769 // void plstr()
770 //
771 // Prints out a "string" at reference position with physical coordinates
772 // (refx,refy). The coordinates of the vectors defining the string are
773 // passed through the linear mapping defined by the 2 x 2 matrix xform()
774 // before being plotted. The reference position is at the left-hand edge of
775 // the string. If base = 1, it is aligned with the baseline of the string.
776 // If base = 0, it is aligned with the center of the character box.
777 //
778 // Note, all calculations are done in terms of millimetres. These are scaled
779 // as necessary before plotting the string on the page.
780 //--------------------------------------------------------------------------
781
782 void
783 plstr( PLINT base, PLFLT *xform, PLINT refx, PLINT refy, const char *string )
784 {
785 short int *symbol;
786 signed char *vxygrid = 0;
787
788 PLINT ch, i, length, level = 0, style, oline = 0, uline = 0;
789 PLFLT width = 0., xorg = 0., yorg = 0., def, ht, dscale, scale;
790 PLFLT old_sscale, sscale, old_soffset, soffset;
791
792 plgchr( &def, &ht );
793 dscale = 0.05 * ht;
794 scale = dscale;
795
796 // Line style must be continuous
797
798 style = plsc->nms;
799 plsc->nms = 0;
800
801 pldeco( &symbol, &length, string );
802
803 for ( i = 0; i < length; i++ )
804 {
805 ch = symbol[i];
806 if ( ch == -1 ) // superscript
807 {
808 plP_script_scale( TRUE, &level,
809 &old_sscale, &sscale, &old_soffset, &soffset );
810 yorg = 16.0 * dscale * soffset;
811 scale = dscale * sscale;
812 }
813 else if ( ch == -2 ) // subscript
814 {
815 plP_script_scale( FALSE, &level,
816 &old_sscale, &sscale, &old_soffset, &soffset );
817 yorg = -16.0 * dscale * soffset;
818 scale = dscale * sscale;
819 }
820 else if ( ch == -3 ) // back-char
821 xorg -= width * scale;
822 else if ( ch == -4 ) // toogle overline
823 oline = !oline;
824 else if ( ch == -5 ) // toogle underline
825 uline = !uline;
826 else
827 {
828 if ( plcvec( ch, &vxygrid ) )
829 plchar( vxygrid, xform, base, oline, uline, refx, refy, scale,
830 plsc->xpmm, plsc->ypmm, &xorg, &yorg, &width );
831 }
832 }
833 plsc->nms = style;
834 }
835
836 //--------------------------------------------------------------------------
837 // plchar()
838 //
839 // Plots out a given stroke font character.
840 //--------------------------------------------------------------------------
841
842 static void
843 plchar( signed char *vxygrid, PLFLT *xform, PLINT base, PLINT oline, PLINT uline,
844 PLINT refx, PLINT refy, PLFLT scale, PLFLT xpmm, PLFLT ypmm,
845 PLFLT *p_xorg, PLFLT *p_yorg, PLFLT *p_width )
846 {
847 PLINT xbase, ybase, ydisp, lx, ly, cx, cy;
848 PLINT k, penup;
849 PLFLT x, y;
850 PLINT llx[STLEN], lly[STLEN], l = 0;
851
852 xbase = vxygrid[2];
853 *p_width = vxygrid[3] - xbase;
854 if ( base == 0 )
855 {
856 ybase = 0;
857 ydisp = vxygrid[0];
858 }
859 else
860 {
861 ybase = vxygrid[0];
862 ydisp = 0;
863 }
864 k = 4;
865 penup = 1;
866
867 for (;; )
868 {
869 cx = vxygrid[k++];
870 cy = vxygrid[k++];
871 if ( cx == 64 && cy == 64 )
872 {
873 if ( l )
874 {
875 plP_draphy_poly( llx, lly, l );
876 l = 0;
877 }
878 break;
879 }
880 if ( cx == 64 && cy == 0 )
881 {
882 if ( l )
883 {
884 plP_draphy_poly( llx, lly, l );
885 l = 0;
886 }
887 penup = 1;
888 }
889 else
890 {
891 x = *p_xorg + ( cx - xbase ) * scale;
892 y = *p_yorg + ( cy - ybase ) * scale;
893 lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
894 ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
895 if ( penup == 1 )
896 {
897 if ( l )
898 {
899 plP_draphy_poly( llx, lly, l );
900 l = 0;
901 }
902 llx[l] = lx;
903 lly[l++] = ly; // store 1st point !
904 plP_movphy( lx, ly );
905 penup = 0;
906 }
907 else
908 {
909 llx[l] = lx;
910 lly[l++] = ly;
911 }
912 }
913 }
914
915 if ( oline )
916 {
917 x = *p_xorg;
918 y = *p_yorg + ( 30 + ydisp ) * scale;
919 lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
920 ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
921 plP_movphy( lx, ly );
922 x = *p_xorg + *p_width * scale;
923 lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
924 ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
925 plP_draphy( lx, ly );
926 }
927 if ( uline )
928 {
929 x = *p_xorg;
930 y = *p_yorg + ( -5 + ydisp ) * scale;
931 lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
932 ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
933 plP_movphy( lx, ly );
934 x = *p_xorg + *p_width * scale;
935 lx = refx + ROUND( xpmm * ( xform[0] * x + xform[1] * y ) );
936 ly = refy + ROUND( ypmm * ( xform[2] * x + xform[3] * y ) );
937 plP_draphy( lx, ly );
938 }
939 *p_xorg = *p_xorg + *p_width * scale;
940 }
941
942 //--------------------------------------------------------------------------
943 // PLFLT plstrl()
944 //
945 // Computes the length of a string in mm, including escape sequences.
946 //--------------------------------------------------------------------------
947
948 PLFLT
949 plstrl( const char *string )
950 {
951 short int *symbol;
952 signed char *vxygrid = 0;
953 PLINT ch, i, length, level = 0;
954 PLFLT width = 0., xorg = 0., dscale, scale, def, ht;
955
956 // If the driver will compute string lengths for us then we ask
957 // it do so by setting get_string_length flag. When this is set
958 // the driver will set the string_length variable instead of
959 // actually rendering the string.
960 //
961 // TODO:
962 // Is plmtex the best string diplay routine to use?
963 // Will this work for buffered plots?
964
965 if ( plsc->has_string_length )
966 {
967 plsc->get_string_length = 1;
968 c_plmtex( "t", 0.0, 0.0, 0.0, string );
969 plsc->get_string_length = 0;
970 return (PLFLT) plsc->string_length;
971 }
972
973
974 plgchr( &def, &ht );
975 dscale = 0.05 * ht;
976 scale = dscale;
977 pldeco( &symbol, &length, string );
978
979 for ( i = 0; i < length; i++ )
980 {
981 ch = symbol[i];
982 if ( ch == -1 )
983 {
984 level++;
985 scale = dscale * pow( 0.75, (double) ABS( level ) );
986 }
987 else if ( ch == -2 )
988 {
989 level--;
990 scale = dscale * pow( 0.75, (double) ABS( level ) );
991 }
992 else if ( ch == -3 )
993 xorg -= width * scale;
994 else if ( ch == -4 || ch == -5 )
995 ;
996 else
997 {
998 if ( plcvec( ch, &vxygrid ) )
999 {
1000 width = vxygrid[3] - vxygrid[2];
1001 xorg += width * scale;
1002 }
1003 }
1004 }
1005 return (PLFLT) xorg;
1006 }
1007
1008 //--------------------------------------------------------------------------
1009 // PLINT plcvec()
1010 //
1011 // Gets the character digitisation of Hershey table entry "char".
1012 // Returns 1 if there is a valid entry.
1013 //--------------------------------------------------------------------------
1014
1015 static PLINT
1016 plcvec( PLINT ch, signed char **xygr )
1017 {
1018 PLINT k = 0, ib;
1019 signed char x, y;
1020
1021 ch--;
1022 if ( ch < 0 || ch >= indxleng )
1023 return (PLINT) 0;
1024 ib = fntindx[ch] - 2;
1025 if ( ib == -2 )
1026 return (PLINT) 0;
1027
1028 do
1029 {
1030 ib++;
1031 x = fntbffr[2 * ib];
1032 y = fntbffr[2 * ib + 1];
1033 xygrid[k++] = x;
1034 xygrid[k++] = y;
1035 } while ( ( x != 64 || y != 64 ) && k <= ( STLEN - 2 ) );
1036
1037 if ( k == ( STLEN - 1 ) )
1038 {
1039 // This is bad if we get here
1040 xygrid[k] = 64;
1041 xygrid[k] = 64;
1042 }
1043
1044 *xygr = xygrid;
1045 return (PLINT) 1;
1046 }
1047
1048 //--------------------------------------------------------------------------
1049 // void pldeco()
1050 //
1051 // Decode a character string, and return an array of float integer symbol
1052 // numbers. This routine is responsible for interpreting all escape sequences.
1053 // At present the following escape sequences are defined (the letter following
1054 // the <esc> may be either upper or lower case):
1055 //
1056 // <esc>u : up one level (returns -1)
1057 // <esc>d : down one level (returns -2)
1058 // <esc>b : backspace (returns -3)
1059 // <esc>+ : toggles overline mode (returns -4)
1060 // <esc>- : toggles underline mode (returns -5)
1061 // <esc><esc> : <esc>
1062 // <esc>gx : greek letter corresponding to roman letter x
1063 // <esc>fn : switch to Normal font
1064 // <esc>fr : switch to Roman font
1065 // <esc>fi : switch to Italic font
1066 // <esc>fs : switch to Script font
1067 // <esc>(nnn) : Hershey symbol number nnn (any number of digits)
1068 //
1069 // The escape character defaults to '#', but can be changed to any of
1070 // [!#$%&*@^~] via a call to plsesc.
1071 //--------------------------------------------------------------------------
1072
1073 static void
1074 pldeco( short int **symbol, PLINT *length, const char *text )
1075 {
1076 PLINT ch, ifont = plsc->cfont, ig, j = 0, lentxt = (PLINT) strlen( text );
1077 char test, esc;
1078 short int *sym = symbol_buffer;
1079
1080 // Initialize parameters.
1081
1082 *length = 0;
1083 *symbol = symbol_buffer;
1084 plgesc( &esc );
1085 if ( ifont > numberfonts )
1086 ifont = 1;
1087
1088 // Get next character; treat non-printing characters as spaces.
1089
1090 while ( j < lentxt )
1091 {
1092 if ( *length >= PLMAXSTR )
1093 return;
1094 test = text[j++];
1095 ch = test;
1096 if ( ch < 0 || ch > 175 )
1097 ch = 32;
1098
1099 // Test for escape sequence (#)
1100
1101 if ( ch == esc && ( lentxt - j ) >= 1 )
1102 {
1103 test = text[j++];
1104 if ( test == esc )
1105 sym[( *length )++] = *( fntlkup + ( ifont - 1 ) * numberchars + ch );
1106
1107 else if ( test == 'u' || test == 'U' )
1108 sym[( *length )++] = -1;
1109
1110 else if ( test == 'd' || test == 'D' )
1111 sym[( *length )++] = -2;
1112
1113 else if ( test == 'b' || test == 'B' )
1114 sym[( *length )++] = -3;
1115
1116 else if ( test == '+' )
1117 sym[( *length )++] = -4;
1118
1119 else if ( test == '-' )
1120 sym[( *length )++] = -5;
1121
1122 else if ( test == '(' )
1123 {
1124 sym[*length] = 0;
1125 while ( '0' <= text[j] && text[j] <= '9' )
1126 {
1127 sym[*length] = (short) ( (int) sym[*length] * 10 + text[j] - '0' );
1128 j++;
1129 }
1130 ( *length )++;
1131 if ( text[j] == ')' )
1132 j++;
1133 }
1134 else if ( test == 'f' || test == 'F' )
1135 {
1136 test = text[j++];
1137 ifont = 1 + plP_strpos( font_types,
1138 isupper( test ) ? tolower( test ) : test );
1139 if ( ifont == 0 || ifont > numberfonts )
1140 ifont = 1;
1141 }
1142 else if ( test == 'g' || test == 'G' )
1143 {
1144 test = text[j++];
1145 ig = plP_strpos( plP_greek_mnemonic, test ) + 1;
1146 // This accesses the Hershey glyphs using the same
1147 // "ascii" index as plpoin. So the order of the Greek
1148 // glyphs in this case depends on the subhersh[0-3]
1149 // indices in fonts/font11.c which for lower-case epsilon,
1150 // theta, and phi substitutes (684, 685, and 686) for
1151 // (631, 634, and 647) in the compact case and (2184,
1152 // 2185, and 2186) for (2131, 2134, and 2147) in the
1153 // extended case.
1154 sym[( *length )++] =
1155 *( fntlkup + ( ifont - 1 ) * numberchars + 127 + ig );
1156 }
1157 else
1158 {
1159 ;
1160 }
1161 }
1162 else
1163 {
1164 // Decode character.
1165 // >>PC<< removed increment from following expression to fix
1166 // compiler bug
1167
1168 sym[( *length )] = *( fntlkup + ( ifont - 1 ) * numberchars + ch );
1169 ( *length )++;
1170 }
1171 }
1172 }
1173
1174 //--------------------------------------------------------------------------
1175 // PLINT plP_strpos()
1176 //
1177 // Searches string str for first occurence of character chr. If found
1178 // the position of the character in the string is returned (the first
1179 // character has position 0). If the character is not found a -1 is
1180 // returned.
1181 //--------------------------------------------------------------------------
1182
1183 PLINT
1184 plP_strpos( const char *str, int chr )
1185 {
1186 char *temp;
1187
1188 if ( ( temp = strchr( str, chr ) ) )
1189 return (PLINT) ( temp - str );
1190 else
1191 return (PLINT) -1;
1192 }
1193
1194 //--------------------------------------------------------------------------
1195 // PLINT plP_stindex()
1196 //
1197 // Similar to strpos, but searches for occurence of string str2.
1198 //--------------------------------------------------------------------------
1199
1200 PLINT
1201 plP_stindex( const char *str1, const char *str2 )
1202 {
1203 PLINT base, str1ind, str2ind;
1204
1205 for ( base = 0; *( str1 + base ) != '\0'; base++ )
1206 {
1207 for ( str1ind = base, str2ind = 0; *( str2 + str2ind ) != '\0' &&
1208 *( str2 + str2ind ) == *( str1 + str1ind ); str1ind++, str2ind++ )
1209 ;
1210
1211 if ( *( str2 + str2ind ) == '\0' )
1212 return (PLINT) base;
1213 }
1214 return (PLINT) -1; // search failed
1215 }
1216
1217 //--------------------------------------------------------------------------
1218 // PLBOOL plP_stsearch()
1219 //
1220 // Searches string str for character chr (case insensitive).
1221 //--------------------------------------------------------------------------
1222
1223 PLBOOL
1224 plP_stsearch( const char *str, int chr )
1225 {
1226 if ( strchr( str, chr ) )
1227 return TRUE;
1228 else if ( strchr( str, toupper( chr ) ) )
1229 return TRUE;
1230 else
1231 return FALSE;
1232 }
1233
1234 //--------------------------------------------------------------------------
1268
1269 void
1270 plP_script_scale( PLBOOL ifupper, PLINT *level,
1271 PLFLT *old_scale, PLFLT *scale,
1272 PLFLT *old_offset, PLFLT *offset )
1273 {
1274 if ( *level == 0 )
1275 {
1276 *old_scale = 1.;
1277 *old_offset = 0.;
1278 }
1279 else
1280 {
1281 *old_scale = *scale;
1282 *old_offset = *offset;
1283 }
1284 if ( ( *level >= 0 && ifupper ) || ( *level <= 0 && !ifupper ) )
1285 {
1286 // If superscript of subscript moves further away from centerline....
1287 *scale = 0.75 * *old_scale;
1288 *offset = *old_offset + *old_scale;
1289 }
1290 else
1291 {
1292 // If superscript of subscript moves closer to centerline....
1293 *scale = *old_scale / 0.75;
1294 *offset = *old_offset - *scale;
1295 }
1296 if ( ifupper )
1297 ( *level )++;
1298 else
1299 ( *level )--;
1300 }
1301
1302 //--------------------------------------------------------------------------
1303 // void c_plfont(ifont)
1304 //
1305 // Sets the global font flag to 'ifont'.
1306 //--------------------------------------------------------------------------
1307
1308 void
1309 c_plfont( PLINT ifont )
1310 {
1311 PLUNICODE fci = PL_FCI_MARK;
1312 if ( plsc->level < 1 )
1313 {
1314 plabort( "plfont: Please call plinit first" );
1315 return;
1316 }
1317 if ( ifont < 1 || ifont > 4 )
1318 {
1319 plabort( "plfont: Invalid font" );
1320 return;
1321 }
1322
1323 plsc->cfont = ifont;
1324
1325 // Provide some degree of forward compatibility if dealing with
1326 // unicode font. But better procedure is to call plsfci directly rather
1327 // than using this lame Hershey font interface.
1328 //
1329 switch ( ifont )
1330 {
1331 case 1:
1332 // normal = (medium, upright, sans serif)
1333 plP_hex2fci( PL_FCI_SANS, PL_FCI_FAMILY, &fci );
1334 plsfci( fci );
1335 break;
1336 // roman = (medium, upright, serif)
1337 case 2:
1338 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
1339 plsfci( fci );
1340 break;
1341 // italic = (medium, italic, serif)
1342 case 3:
1343 plP_hex2fci( PL_FCI_ITALIC, PL_FCI_STYLE, &fci );
1344 plP_hex2fci( PL_FCI_SERIF, PL_FCI_FAMILY, &fci );
1345 plsfci( fci );
1346 break;
1347 // script = (medium, upright, script)
1348 case 4:
1349 plP_hex2fci( PL_FCI_SCRIPT, PL_FCI_FAMILY, &fci );
1350 plsfci( fci );
1351 break;
1352 }
1353 }
1354
1355 //--------------------------------------------------------------------------
1356 // void plfntld(fnt)
1357 //
1358 // Loads either the standard or extended font.
1359 //--------------------------------------------------------------------------
1360
1361 void
1362 plfntld( PLINT fnt )
1363 {
1364 static PLINT charset;
1365 short bffrleng;
1366 PDFstrm *pdfs;
1367
1368 if ( fontloaded && ( charset == fnt ) )
1369 return;
1370
1371 plfontrel();
1372 fontloaded = 1;
1373 charset = fnt;
1374
1375 if ( fnt )
1376 pdfs = plLibOpenPdfstrm( PL_XFONT );
1377 else
1378 pdfs = plLibOpenPdfstrm( PL_SFONT );
1379
1380 if ( pdfs == NULL )
1381 plexit( "Unable to either (1) open/find or (2) allocate memory for the font file" );
1382
1383 // Read fntlkup[]
1384
1385 pdf_rd_2bytes( pdfs, (U_SHORT *) &bffrleng );
1386 numberfonts = bffrleng / 256;
1387 numberchars = bffrleng & 0xff;
1388 bffrleng = (short) ( numberfonts * numberchars );
1389 fntlkup = (short int *) malloc( (size_t) bffrleng * sizeof ( short int ) );
1390 if ( !fntlkup )
1391 plexit( "plfntld: Out of memory while allocating font buffer." );
1392
1393 pdf_rd_2nbytes( pdfs, (U_SHORT *) fntlkup, bffrleng );
1394
1395 // Read fntindx[]
1396
1397 pdf_rd_2bytes( pdfs, (U_SHORT *) &indxleng );
1398 fntindx = (short int *) malloc( (size_t) indxleng * sizeof ( short int ) );
1399 if ( !fntindx )
1400 plexit( "plfntld: Out of memory while allocating font buffer." );
1401
1402 pdf_rd_2nbytes( pdfs, (U_SHORT *) fntindx, indxleng );
1403
1404 // Read fntbffr[]
1405 // Since this is an array of char, there are no endian problems
1406
1407 pdf_rd_2bytes( pdfs, (U_SHORT *) &bffrleng );
1408 fntbffr = (signed char *) malloc( 2 * (size_t) bffrleng * sizeof ( signed char ) );
1409 if ( !fntbffr )
1410 plexit( "plfntld: Out of memory while allocating font buffer." );
1411
1412 #if PLPLOT_USE_TCL_CHANNELS
1413 pdf_rdx( fntbffr, sizeof ( signed char ) * (size_t) ( 2 * bffrleng ), pdfs );
1414 #else
1415 plio_fread( (void *) fntbffr, (size_t) sizeof ( signed char ),
1416 (size_t) ( 2 * bffrleng ), pdfs->file );
1417 #endif
1418
1419 // Done
1420
1421 pdf_close( pdfs );
1422 }
1423
1424 //--------------------------------------------------------------------------
1425 // void plfontrel()
1426 //
1427 // Release memory for fonts.
1428 //--------------------------------------------------------------------------
1429
1430 void
1431 plfontrel( void )
1432 {
1433 if ( fontloaded )
1434 {
1435 free_mem( fntindx )
1436 free_mem( fntbffr )
1437 free_mem( fntlkup )
1438 fontloaded = 0;
1439 }
1440 }
1441
1442 //--------------------------------------------------------------------------
1443 // int plhershey2unicode ( int in )
1444 //
1445 // Function searches for in, the input hershey code, in a lookup table and
1446 // returns the corresponding index in that table.
1447 // Using this index you can work out the unicode equivalent as well as
1448 // the closest approximate to the font-face. If the returned index is
1449 // -1 then no match was possible.
1450 //
1451 // Two versions of the function exist, a simple linear search version,
1452 // and a more complex, but significantly faster, binary search version.
1453 // If there seem to be problems with the binary search method, the brain-dead
1454 // linear search can be enabled by defining SIMPLE_BUT_SAFE_HERSHEY_LOOKUP
1455 // at compile time.
1456 //--------------------------------------------------------------------------
1457
1458 int plhershey2unicode( int in )
1459 {
1460 #ifdef SIMPLE_BUT_SAFE_HERSHEY_LOOKUP
1461 int ret = -1;
1462 int i;
1463
1464 for ( i = 0; ( i < number_of_entries_in_hershey_to_unicode_table ) && ( ret == -1 ); i++ )
1465 {
1466 if ( hershey_to_unicode_lookup_table[i].Hershey == in )
1467 ret = i;
1468 }
1469
1470 return ( ret );
1471
1472 #else
1473
1474 int jlo = -1, jmid, jhi = number_of_entries_in_hershey_to_unicode_table;
1475 while ( jhi - jlo > 1 )
1476 {
1477 // Note that although jlo or jhi can be just outside valid
1478 // range (see initialization above) because of while condition
1479 // jlo < jmid < jhi and jmid must be in valid range.
1480 //
1481 jmid = ( jlo + jhi ) / 2;
1482 // convert hershey_to_unicode_lookup_table[jmid].Hershey to signed
1483 // integer since we don't loose information - the number range
1484 // is from 1 and 2932 at the moment
1485 if ( in > (int) ( hershey_to_unicode_lookup_table[jmid].Hershey ) )
1486 jlo = jmid;
1487 else if ( in < (int) ( hershey_to_unicode_lookup_table[jmid].Hershey ) )
1488 jhi = jmid;
1489 else
1490 // We have found it!
1491 // in == hershey_to_unicode_lookup_table[jmid].Hershey
1492 //
1493 return ( jmid );
1494 }
1495 // jlo is invalid or it is valid and in > hershey_to_unicode_lookup_table[jlo].Hershey.
1496 // jhi is invalid or it is valid and in < hershey_to_unicode_lookup_table[jhi].Hershey.
1497 // All these conditions together imply in cannot be found in
1498 // hershey_to_unicode_lookup_table[j].Hershey, for all j.
1499 //
1500 return ( -1 );
1501 #endif
1502 }
1503
1504 //--------------------------------------------------------------------------
1505 // char *
1506 // plP_FCI2FontName ( PLUNICODE fci,
1507 // const FCI_to_FontName_Table lookup[], const int nlookup)
1508 //
1509 // Function takes an input FCI (font characterization integer) index,
1510 // looks through the lookup table (which must be sorted by PLUNICODE fci),
1511 // then returns the corresponding pointer to a valid font name. If the FCI
1512 // index is not present the returned value is NULL.
1513 //--------------------------------------------------------------------------
1514
1515 const char *
1516 plP_FCI2FontName( PLUNICODE fci,
1517 const FCI_to_FontName_Table lookup[], const int nlookup )
1518 {
1519 int jlo = -1, jmid, jhi = nlookup;
1520 while ( jhi - jlo > 1 )
1521 {
1522 // Note that although jlo or jhi can be just outside valid
1523 // range (see initialization above) because of while condition
1524 // jlo < jmid < jhi and jmid must be in valid range.
1525 //
1526 jmid = ( jlo + jhi ) / 2;
1527 if ( fci > lookup[jmid].fci )
1528 jlo = jmid;
1529 else if ( fci < lookup[jmid].fci )
1530 jhi = jmid;
1531 else
1532 // We have found it!
1533 // fci == lookup[jmid].fci
1534 //
1535 return (const char *) ( lookup[jmid].pfont );
1536 }
1537 // jlo is invalid or it is valid and fci > lookup[jlo].Unicode.
1538 // jhi is invalid or it is valid and fci < lookup[jhi].Unicode.
1539 // All these conditions together imply fci index cannot be found in lookup.
1540 // Mark lookup failure with NULL pointer.
1541 //
1542 return ( NULL );
1543 }
1544
1545 //--------------------------------------------------------------------------
1546 // void plmtex3()
1547 //
1548 // This is the 3d equivalent of plmtex(). It prints out "text" at specified
1549 // position relative to viewport (may be inside or outside)
1550 //
1551 // side String contains one or more of the following characters
1552 // x,y,z : Specify which axis is to be labeled
1553 // p,s : Label the "primary" or the "secondary" axis. The "primary" axis
1554 // being somewhat arbitrary, but basically it is the one that you'd
1555 // expect to labeled in a 3d graph of standard orientation. Example:
1556 // for z this would be the left hand axis.
1557 // v : draw the text perpendicular to the axis.
1558 //
1559 // disp Displacement from specified edge of axis, measured outwards from
1560 // the axis in units of the current character height. The
1561 // centerlines of the characters are aligned with the specified
1562 // position.
1563 //
1564 // pos Position of the reference point of the string relative to the
1565 // axis ends, ranging from 0.0 (left-hand end) to 1.0 (right-hand
1566 // end)
1567 //
1568 // just Justification of string relative to reference point
1569 // just = 0.0 => left hand edge of string is at reference
1570 // just = 1.0 => right hand edge of string is at reference
1571 // just = 0.5 => center of string is at reference
1572 //
1573 // All calculations are done in physical coordinates.
1574 //
1575 //--------------------------------------------------------------------------
1576
1577 void
1578 c_plmtex3( const char *side, PLFLT disp, PLFLT pos, PLFLT just, const char *text )
1579 {
1580 // local storage
1581 PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
1582 PLFLT chrdef, chrht;
1583
1584 // calculated
1585 PLFLT xpc, ypc, xrefpc, yrefpc;
1586 PLFLT epx1 = 0.0, epy1 = 0.0, epx2 = 0.0, epy2 = 0.0, epx3 = 0.0, epy3 = 0.0;
1587 PLFLT dispx, dispy, xform[4];
1588 PLFLT shift, theta, temp;
1589
1590 // check that the plotting environment is set up
1591 if ( plsc->level < 3 )
1592 {
1593 plabort( "plmtex3: Please set up window first" );
1594 return;
1595 }
1596
1597 // get plotting environment information
1598 plP_gdom( &xmin, &xmax, &ymin, &ymax );
1599 plP_grange( &zscale, &zmin, &zmax );
1600 plgchr( &chrdef, &chrht );
1601
1602 // handle x/y axises
1603 if ( ( plP_stindex( side, "x" ) != -1 ) || ( plP_stindex( side, "y" ) != -1 ) )
1604 {
1605 // get the locations of the end points of the relevant axis
1606
1607 // x axis label
1608 if ( plP_stindex( side, "x" ) != -1 )
1609 {
1610 // primary
1611 if ( plP_stindex( side, "p" ) != -1 )
1612 {
1613 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
1614 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
1615 epx2 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
1616 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
1617 }
1618 else
1619 {
1620 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
1621 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
1622 epx2 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
1623 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
1624 }
1625 }
1626 else
1627 {
1628 if ( plP_stindex( side, "p" ) != -1 )
1629 {
1630 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
1631 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
1632 epx2 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
1633 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
1634 }
1635 else
1636 {
1637 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
1638 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
1639 epx2 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
1640 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
1641 }
1642 }
1643
1644 // text always goes from left to right
1645 if ( epx1 > epx2 )
1646 {
1647 temp = epx1;
1648 epx1 = epx2;
1649 epx2 = temp;
1650 temp = epy1;
1651 epy1 = epy2;
1652 epy2 = temp;
1653 // recalculate position assuming the user specified
1654 // it in the min -> max direction of the axis.
1655 pos = 1.0 - pos;
1656 }
1657
1658 // calculate location of text center point
1659
1660 // 1. calculate the angle of the axis we are to
1661 // draw the text on relative to the horizontal
1662
1663 if ( ( epx2 - epx1 ) != 0.0 )
1664 {
1665 theta = atan( ( epy2 - epy1 ) / ( epx2 - epx1 ) );
1666 }
1667 else
1668 {
1669 if ( epy2 > epy1 )
1670 {
1671 theta = 0.5 * PI;
1672 }
1673 else
1674 {
1675 theta = -0.5 * PI;
1676 }
1677 }
1678
1679 // 2. calculate the perpendicular vector
1680
1681 dispy = disp * chrht;
1682
1683 // 3. calculate x & y center points
1684
1685 xpc = pos * ( epx2 - epx1 ) + epx1;
1686 ypc = pos * ( epy2 - epy1 ) + epy1;
1687
1688 // 4. compute reference point
1689 // It appears that drivers that cannot handle text justification
1690 // use this as the starting point of the string.
1691 // Calculations must be done in millimeters for this part
1692 // so we convert to mm, do the calculation and convert back.
1693 // The calculation is also dependent of the orientation
1694 // (perpendicular or parallel) of the text.
1695
1696 xpc = plP_dcmmx( plP_pcdcx( (PLINT) xpc ) );
1697 ypc = plP_dcmmy( plP_pcdcy( (PLINT) ypc ) ) - dispy;
1698
1699 shift = plstrl( text ) * just;
1700
1701 if ( plP_stindex( side, "v" ) != -1 )
1702 {
1703 xrefpc = xpc;
1704 yrefpc = ypc - shift;
1705 }
1706 else
1707 {
1708 xrefpc = xpc - cos( theta ) * shift;
1709 yrefpc = ypc - sin( theta ) * shift;
1710 }
1711
1712 xpc = plP_mmpcx( xpc );
1713 ypc = plP_mmpcy( ypc );
1714 xrefpc = plP_mmpcx( xrefpc );
1715 yrefpc = plP_mmpcy( yrefpc );
1716
1717 // 5. compute transform matrix & draw text
1718
1719 // perpendicular, rotate 90 degrees & shear
1720
1721 if ( plP_stindex( side, "v" ) != -1 )
1722 {
1723 xform[0] = 0.0;
1724 xform[1] = -cos( theta );
1725 xform[2] = 1.0;
1726 xform[3] = -sin( theta );
1727 plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
1728 }
1729
1730 // parallel, rotate & shear by angle
1731 else
1732 {
1733 xform[0] = cos( theta );
1734 xform[1] = 0.0;
1735 xform[2] = sin( theta );
1736 xform[3] = 1.0;
1737
1738 plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
1739 }
1740 }
1741
1742 // handle z axises
1743 if ( plP_stindex( side, "z" ) != -1 )
1744 {
1745 // Find the left most of the 4 z axis options for "primary"
1746 // Also find the location of frontmost point in the graph,
1747 // which will be needed to calculate at what angle to shear
1748 // the text.
1749
1750 if ( plP_stindex( side, "p" ) != -1 )
1751 {
1752 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
1753 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
1754 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmax ) );
1755 epx3 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
1756 epy3 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
1757
1758 if ( plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) ) < epx1 )
1759 {
1760 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
1761 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
1762 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmax ) );
1763 epx3 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
1764 epy3 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
1765 }
1766
1767 if ( plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) ) < epx1 )
1768 {
1769 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
1770 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
1771 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmax ) );
1772 epx3 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
1773 epy3 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
1774 }
1775
1776 if ( plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) ) < epx1 )
1777 {
1778 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
1779 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
1780 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmax ) );
1781 epx3 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
1782 epy3 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
1783 }
1784 }
1785
1786 // find the right most of the 4 z axis options for "primary"
1787 if ( plP_stindex( side, "s" ) != -1 )
1788 {
1789 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
1790 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
1791 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmax ) );
1792 epx3 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
1793 epy3 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
1794
1795 if ( plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) ) > epx1 )
1796 {
1797 epx1 = plP_wcpcx( plP_w3wcx( xmin, ymax, zmin ) );
1798 epy1 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmin ) );
1799 epy2 = plP_wcpcy( plP_w3wcy( xmin, ymax, zmax ) );
1800 epx3 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
1801 epy3 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
1802 }
1803
1804 if ( plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) ) > epx1 )
1805 {
1806 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
1807 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
1808 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmax ) );
1809 epx3 = plP_wcpcx( plP_w3wcx( xmin, ymin, zmin ) );
1810 epy3 = plP_wcpcy( plP_w3wcy( xmin, ymin, zmin ) );
1811 }
1812
1813 if ( plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) ) > epx1 )
1814 {
1815 epx1 = plP_wcpcx( plP_w3wcx( xmax, ymax, zmin ) );
1816 epy1 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmin ) );
1817 epy2 = plP_wcpcy( plP_w3wcy( xmax, ymax, zmax ) );
1818 epx3 = plP_wcpcx( plP_w3wcx( xmax, ymin, zmin ) );
1819 epy3 = plP_wcpcy( plP_w3wcy( xmax, ymin, zmin ) );
1820 }
1821 }
1822
1823 // Calculate location of text center point.
1824 // This is very similiar for the z axis.
1825
1826 // primary and secondary have to be handled separately here
1827
1828 if ( plP_stindex( side, "p" ) != -1 )
1829 {
1830 // 1. Calculate the angle of the axis we are to
1831 // draw the text on relative to the horizontal.
1832
1833 if ( ( epx3 - epx1 ) != 0.0 )
1834 {
1835 theta = atan( ( epy3 - epy1 ) / ( epx3 - epx1 ) );
1836 }
1837 else
1838 {
1839 if ( epy3 > epy1 )
1840 {
1841 theta = 0.5 * PI;
1842 }
1843 else
1844 {
1845 theta = -0.5 * PI;
1846 }
1847 }
1848
1849 // 2. Calculate the perpendicular vector.
1850
1851 dispx = -cos( theta ) * disp * chrht;
1852 dispy = -sin( theta ) * disp * chrht;
1853 }
1854 else
1855 {
1856 if ( ( epx1 - epx3 ) != 0.0 )
1857 {
1858 theta = -atan( ( epy3 - epy1 ) / ( epx1 - epx3 ) );
1859 }
1860 else
1861 {
1862 if ( epy3 > epy1 )
1863 {
1864 theta = -0.5 * PI;
1865 }
1866 else
1867 {
1868 theta = 0.5 * PI;
1869 }
1870 }
1871
1872 dispx = cos( theta ) * disp * chrht;
1873 dispy = sin( theta ) * disp * chrht;
1874 }
1875
1876 // 3. Calculate x & y center points.
1877
1878 xpc = epx1;
1879 ypc = pos * ( epy2 - epy1 ) + epy1;
1880
1881 // 4. Compute the reference point.
1882
1883 xpc = plP_dcmmx( plP_pcdcx( (PLINT) xpc ) ) + dispx;
1884 ypc = plP_dcmmy( plP_pcdcy( (PLINT) ypc ) ) + dispy;
1885
1886 shift = plstrl( text ) * just;
1887
1888 if ( plP_stindex( side, "v" ) != -1 )
1889 {
1890 xrefpc = xpc - cos( theta ) * shift;
1891 yrefpc = ypc - sin( theta ) * shift;
1892 }
1893 else
1894 {
1895 xrefpc = xpc;
1896 yrefpc = ypc - shift;
1897 }
1898
1899 xpc = plP_mmpcx( xpc );
1900 ypc = plP_mmpcy( ypc );
1901 xrefpc = plP_mmpcx( xrefpc );
1902 yrefpc = plP_mmpcy( yrefpc );
1903
1904 // 5. Compute transform matrix & draw text.
1905
1906 if ( plP_stindex( side, "v" ) != -1 )
1907 {
1908 xform[0] = cos( theta );
1909 xform[1] = 0.0;
1910 xform[2] = sin( theta );
1911 xform[3] = 1.0;
1912
1913 plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
1914 }
1915
1916 else
1917 {
1918 xform[0] = 0.0;
1919 xform[1] = -cos( theta );
1920 xform[2] = 1.0;
1921 xform[3] = -sin( theta );
1922
1923 plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
1924 }
1925 }
1926 }
1927
1928 //--------------------------------------------------------------------------
1929 // void plptex3()
1930 //
1931 // Prints out "text" at world cooordinate (wx,wy,wz).
1932 //
1933 // The text is drawn parallel to the line between (wx,wy,wz) and
1934 // (wx+dx,wy+dy,wz+dz).
1935 //
1936 // The text is sheared so that it is "vertically" parallel to the
1937 // line between (wx,wy,wz) and (wx+sx, wy+sy, wz+sz). If sx=sy=sz=0 then
1938 // the text is simply rotated to parallel to the baseline.
1939 //
1940 // "just" adjusts the horizontal justification of the string:
1941 // just = 0.0 => left hand edge of string is at (wx,wy)
1942 // just = 1.0 => right hand edge of string is at (wx,wy)
1943 // just = 0.5 => center of string is at (wx,wy) etc.
1944 //
1945 // Calculations are done in physical coordinates.
1946 //
1947 //--------------------------------------------------------------------------
1948
1949 void
1950 c_plptex3( PLFLT wx, PLFLT wy, PLFLT wz, PLFLT dx, PLFLT dy, PLFLT dz,
1951 PLFLT sx, PLFLT sy, PLFLT sz, PLFLT just, const char *text )
1952 {
1953 PLFLT xpc, ypc, xrefpc, yrefpc, xdpc, ydpc, xspc, yspc, ld, ls, cp, shift;
1954 PLFLT x_o, y_o, z_o, x_dx, y_dy, z_dz;
1955 PLFLT theta, phi, stride, xform[6], affineL[6], cosphi;
1956
1957 // check that the plotting environment is set up
1958 if ( plsc->level < 3 )
1959 {
1960 plabort( "plptex3: Please set up window first" );
1961 return;
1962 }
1963
1964 // compute text x,y location in physical coordinates
1965 xpc = plP_wcpcx( plP_w3wcx( wx, wy, wz ) );
1966 ypc = plP_wcpcy( plP_w3wcy( wx, wy, wz ) );
1967
1968 // determine angle to rotate text in the x-y plane
1969 xdpc = plP_wcpcx( plP_w3wcx( wx + dx, wy + dy, wz + dz ) );
1970 ydpc = plP_wcpcy( plP_w3wcy( wx + dx, wy + dy, wz + dz ) );
1971 theta = atan2( ydpc - ypc, xdpc - xpc );
1972
1973 // Determine angle to shear text in the x-y plane. This is a little
1974 // messy, but basically the idea is:
1975 //
1976 // Compute the dot product of the vector d and the vector s to
1977 // determine the angle between them (acos(t) = d . s / |d| |s|).
1978 // Then because acos will return a number from 0.0 to PI, i.e.
1979 // only in quadrants 1 or 2, compute the cross product of the
1980 // two vectors. If this is negative then the angle is adjusted
1981 // 0.0 to -PI.
1982
1983 if ( ( sx == 0.0 ) && ( sy == 0.0 ) && ( sz == 0.0 ) )
1984 {
1985 phi = 0.0;
1986 }
1987 else
1988 {
1989 xspc = plP_wcpcx( plP_w3wcx( wx + sx, wy + sy, wz + sz ) );
1990 yspc = plP_wcpcy( plP_w3wcy( wx + sx, wy + sy, wz + sz ) );
1991 ld = sqrt( ( xpc - xdpc ) * ( xpc - xdpc ) + ( ypc - ydpc ) * ( ypc - ydpc ) );
1992 ls = sqrt( ( xpc - xspc ) * ( xpc - xspc ) + ( ypc - yspc ) * ( ypc - yspc ) );
1993 phi = acos( ( ( xdpc - xpc ) * ( xspc - xpc ) + ( ydpc - ypc ) * ( yspc - ypc ) ) / ( ld * ls ) );
1994 cp = ( xdpc - xpc ) * ( yspc - ypc ) - ( ydpc - ypc ) * ( xspc - xpc );
1995 if ( cp < 0.0 )
1996 {
1997 phi = -phi;
1998 }
1999 phi = 0.5 * PI - phi;
2000 }
2001
2002 // Determine how to adjust the "stride" of the text to make it
2003 // appear that it is going into (or out of) the page. Basically
2004 // scale the x baseline of the text by the normalized length of
2005 // the d vector projected into the x-y plane.
2006 x_o = plP_w3wcx( wx, wy, wz );
2007 y_o = plP_w3wcy( wx, wy, wz );
2008 z_o = plP_w3wcz( wx, wy, wz );
2009 x_dx = x_o - plP_w3wcx( wx + dx, wy + dy, wz + dz );
2010 y_dy = y_o - plP_w3wcy( wx + dx, wy + dy, wz + dz );
2011 z_dz = z_o - plP_w3wcz( wx + dx, wy + dy, wz + dz );
2012
2013 stride = sqrt( x_dx * x_dx + y_dy * y_dy );
2014 stride = stride / sqrt( x_dx * x_dx + y_dy * y_dy + z_dz * z_dz );
2015
2016 // compute the reference point
2017 xpc = plP_dcmmx( plP_pcdcx( (PLINT) xpc ) );
2018 ypc = plP_dcmmy( plP_pcdcy( (PLINT) ypc ) );
2019
2020 shift = plstrl( text ) * just;
2021 xrefpc = xpc - cos( theta ) * shift * stride;
2022 yrefpc = ypc - sin( theta ) * shift * stride;
2023
2024 xpc = plP_mmpcx( xpc );
2025 ypc = plP_mmpcy( ypc );
2026 xrefpc = plP_mmpcx( xrefpc );
2027 yrefpc = plP_mmpcy( yrefpc );
2028
2029 // compute the transform
2030 // This affine transformation corresponds to transforming from old
2031 // coordinates to new coordinates by rotating axes, y shearing
2032 // or (y skewing), and scaling.
2033 // Comment out the explicit xform calculations because we use
2034 // the affine utilities for that calculation instead.
2035 //
2036 // xform[0] = cos( theta ) * stride;
2037 // xform[1] = cos( theta ) * sin( phi ) - sin( theta ) * cos( phi );
2038 // xform[2] = sin( theta ) * stride;
2039 // xform[3] = sin( theta ) * sin( phi ) + cos( theta ) * cos( phi );
2040 //
2041 plP_affine_rotate( xform, 180. * theta / PI );
2042 plP_affine_yskew( affineL, -180. * phi / PI );
2043 plP_affine_multiply( xform, affineL, xform );
2044 cosphi = cos( phi );
2045 if ( fabs( cosphi ) > 1.e-300 )
2046 plP_affine_scale( affineL, 1. / stride, 1. / cosphi );
2047 else
2048 plP_affine_scale( affineL, 1. / stride, 1.e300 );
2049 plP_affine_multiply( xform, affineL, xform );
2050
2051 plP_text( 0, just, xform, (PLINT) xpc, (PLINT) ypc, (PLINT) xrefpc, (PLINT) yrefpc, text );
2052 }
2053
2054 //--------------------------------------------------------------------------
2055 // void plsfont()
2056 //
2057 // Set the family, style and weight of the current font.
2058 // This is a user-friendly front-end to plsfci.
2059 // Note: A negative value signifies that this element should not be changed.
2060 //--------------------------------------------------------------------------
2061 void
2062 c_plsfont( PLINT family, PLINT style, PLINT weight )
2063 {
2064 PLUNICODE fci;
2065
2066 plgfci( &fci );
2067
2068 if ( family >= 0 )
2069 {
2070 // Bounds checking assumes symbol is last font
2071 if ( family > PL_FCI_SYMBOL )
2072 plwarn( "plsfont: Value for family is out of range" );
2073 else
2074 plP_hex2fci( (unsigned char) family, PL_FCI_FAMILY, &fci );
2075 }
2076
2077 if ( style >= 0 )
2078 {
2079 // Bounds checking assumes oblique is last style
2080 if ( style > PL_FCI_OBLIQUE )
2081 plwarn( "plsfont: Value for style is out of range" );
2082 else
2083 plP_hex2fci( (unsigned char) style, PL_FCI_STYLE, &fci );
2084 }
2085
2086 if ( weight >= 0 )
2087 {
2088 // Bounds checking assumes bold is last weight
2089 if ( weight > PL_FCI_BOLD )
2090 plwarn( "plsfont: Value for weight is out of range" );
2091 else
2092 plP_hex2fci( (unsigned char) weight, PL_FCI_WEIGHT, &fci );
2093 }
2094
2095 plsfci( fci );
2096 }
2097
2098 //--------------------------------------------------------------------------
2099 // void plgfont()
2100 //
2101 // Get the family, style and weight of the current font.
2102 // This is a user-friendly front-end to plgfci.
2103 // Note: A NULL pointer signifies that this value should not be returned.
2104 //--------------------------------------------------------------------------
2105 void
2106 c_plgfont( PLINT *p_family, PLINT *p_style, PLINT *p_weight )
2107 {
2108 PLUNICODE fci;
2109 unsigned char val;
2110
2111 plgfci( &fci );
2112
2113 if ( p_family )
2114 {
2115 plP_fci2hex( fci, &val, PL_FCI_FAMILY );
2116 *p_family = (PLINT) val;
2117 }
2118
2119 if ( p_style )
2120 {
2121 plP_fci2hex( fci, &val, PL_FCI_STYLE );
2122 *p_style = (PLINT) val;
2123 }
2124
2125 if ( p_weight )
2126 {
2127 plP_fci2hex( fci, &val, PL_FCI_WEIGHT );
2128 *p_weight = (PLINT) val;
2129 }
2130 }
2131
2132
2133 #undef PLSYM_H
2134 #endif