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