/* $Id: plsym.c,v 1.2 2005/03/17 21:39:21 eli Exp $ Point, symbol, and string plotting routines. Also font management code. See the description of plLibOpen() for the search path used in finding the font files. */ #define NEED_PLDEBUG #include "plplotP.h" #include #include /* Declarations */ static short int *fntlkup; static short int *fntindx; static signed char *fntbffr; static short int numberfonts, numberchars; static short int indxleng; static short fontloaded = 0; /* moved to plstr.h, plsc->cfont static PLINT font = 1; current font */ #define PLMAXSTR 300 #define STLEN 250 static char font_types[] = "nris"; static char greek[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw"; static short symbol_buffer[PLMAXSTR]; static signed char xygrid[STLEN]; /* Static function prototypes */ static void pldeco(short int **sym, PLINT *length, const char *text); 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); static PLINT plcvec(PLINT ch, signed char **xygr); static void plhrsh(PLINT ch, PLINT x, PLINT y); /*--------------------------------------------------------------------------*\ * void plsym() * * Plots array y against x for n points using Hershey symbol "code". \*--------------------------------------------------------------------------*/ void c_plsym(PLINT n, PLFLT *x, PLFLT *y, PLINT code) { PLINT i; if (plsc->level < 3) { plabort("plsym: Please set up window first"); return; } if (code < 0) { plabort("plsym: Invalid code"); return; } for (i = 0; i < n; i++) plhrsh(code, plP_wcpcx(x[i]), plP_wcpcy(y[i])); } /*--------------------------------------------------------------------------*\ * void plpoin() * * Plots array y against x for n points using ASCII code "code". * * code=-1 means try to just draw a point. Right now it's just a move and * a draw at the same place. Not ideal, since a sufficiently intelligent * output device may optimize it away, or there may be faster ways of * doing it. This is OK for now, though, and offers a 4X speedup over * drawing a Hershey font "point" (which is actually diamond shaped and * therefore takes 4 strokes to draw). \*--------------------------------------------------------------------------*/ MZ_DLLEXPORT void c_plpoin(PLINT n, PLFLT *x, PLFLT *y, PLINT code) { PLINT i, sym, ifont = plsc->cfont; if (plsc->level < 3) { plabort("plpoin: Please set up window first"); return; } if (code < -1 || code > 127) { plabort("plpoin: Invalid code"); return; } if (code == -1) { for (i = 0; i < n; i++) pljoin(x[i], y[i], x[i], y[i]); } else { if (ifont > numberfonts) ifont = 1; sym = *(fntlkup + (ifont - 1) * numberchars + code); for (i = 0; i < n; i++) plhrsh(sym, plP_wcpcx(x[i]), plP_wcpcy(y[i])); } } /*--------------------------------------------------------------------------*\ * void plpoin3(n, x, y, z, code) * * Draws a series of points in 3 space. Setup similar to plline3(). \*--------------------------------------------------------------------------*/ void c_plpoin3(PLINT n, PLFLT *x, PLFLT *y, PLFLT *z, PLINT code) { PLINT i, sym, ifont = plsc->cfont; PLFLT u, v; PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale; if (plsc->level < 3) { plabort("plpoin3: Please set up window first"); return; } if (code < -1 || code > 127) { plabort("plpoin3: Invalid code"); return; } plP_gdom(&xmin, &xmax, &ymin, &ymax); plP_grange(&zscale, &zmin, &zmax); if (code == -1) { for (i = 0; i < n; i++) { if(x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax && z[i] >= zmin && z[i] <= zmax) { u = plP_wcpcx(plP_w3wcx( x[i], y[i], z[i] )); v = plP_wcpcy(plP_w3wcy( x[i], y[i], z[i] )); plP_movphy(u,v); plP_draphy(u,v); } } } else { if (ifont > numberfonts) ifont = 1; sym = *(fntlkup + (ifont - 1) * numberchars + code); for( i=0; i < n; i++ ) { if(x[i] >= xmin && x[i] <= xmax && y[i] >= ymin && y[i] <= ymax && z[i] >= zmin && z[i] <= zmax) { u = plP_wcpcx(plP_w3wcx( x[i], y[i], z[i] )); v = plP_wcpcy(plP_w3wcy( x[i], y[i], z[i] )); plhrsh(sym, u, v); } } } return; } /*--------------------------------------------------------------------------*\ * void plhrsh() * * Writes the Hershey symbol "ch" centred at the physical coordinate (x,y). \*--------------------------------------------------------------------------*/ static void plhrsh(PLINT ch, PLINT x, PLINT y) { PLINT cx, cy, k, penup, style; signed char *vxygrid = 0; PLFLT scale, xscale, yscale; PLINT llx[STLEN], lly[STLEN], l = 0; penup = 1; scale = 0.05 * plsc->symht; if ( ! plcvec(ch, &vxygrid)) { plP_movphy(x, y); return; } /* Line style must be continuous */ style = plsc->nms; plsc->nms = 0; /* Compute how many physical pixels correspond to a character pixel */ xscale = scale * plsc->xpmm; yscale = scale * plsc->ypmm; k = 4; for (;;) { cx = vxygrid[k++]; cy = vxygrid[k++]; if (cx == 64 && cy == 64) { if (l) { plP_draphy_poly(llx, lly, l); l = 0; } plP_movphy(x, y); plsc->nms = style; return; } else if (cx == 64 && cy == 0) penup = 1; else { if (penup == 1) { if (l) { plP_draphy_poly(llx, lly, l); l = 0; } llx[l] = ROUND(x+ xscale * cx); lly[l++] = ROUND(y + yscale * cy); plP_movphy(llx[l-1], lly[l-1]); penup = 0; } else { llx[l] = ROUND(x+ xscale * cx); lly[l++] = ROUND(y + yscale * cy); } } } } /*--------------------------------------------------------------------------*\ * void plarrows() * * simple arrow plotter * copyright 1993 Wesley Ebisuzaki * * an arrow is defined by its location (x, y) and its direction (u, v) * * inputs: * u[i], v[i] arrow's horizontal and vertical projection * x[i], y[i] arrow's location (world coordinates) * n number of arrows to draw * scale > 0 scaling factor for arrows * 0 default scaling factor * < 0 default scaling factor * (-scale) * dx, dy distance between arrows * used when calculating the default arrow scaling * so that arrows don't overlap * \*--------------------------------------------------------------------------*/ #define SCALE0 2.0 /* definition of original arrow: 2 line segments */ static PLFLT arrow_x[4] = {0.5, -0.5, -0.27, -0.5}; static PLFLT arrow_y[4] = {0.0, 0.0, 0.0, 0.20}; void plarrows(PLFLT *u, PLFLT *v, PLFLT *x, PLFLT *y, PLINT n, PLFLT scale, PLFLT dx, PLFLT dy) { PLFLT uu, vv; PLINT i, j; PLINT px0, py0, dpx, dpy; PLINT a_x[4], a_y[4]; PLFLT max_u, max_v; double t; if (n <= 0) return; if (scale <= 0.0) { /* automatic scaling */ /* find max / min values of data */ max_u = u[0]; max_v = v[0]; for (i = 1; i < n; i++) { t = fabs((double) u[i]); max_u = t > max_u ? t : max_u; t = fabs((double) v[i]); max_v = t > max_v ? t : max_v; } /* measure distance in grid boxs */ max_u = max_u / fabs( (double) dx); max_v = max_v / fabs( (double) dy); t = (max_u > max_v ? max_u : max_v); t = SCALE0 / t; if (scale < 0) { scale = -scale * t; } else { scale = t; } } pldebug("plarrows", "scale factor=%lf n=%d\n", scale,n); for (i = 0; i < n; i++) { uu = scale * u[i]; vv = scale * v[i]; if (uu == 0.0 && uu == 0.0) continue; /* conversion to physical coordinates */ px0 = plP_wcpcx(x[i]); py0 = plP_wcpcy(y[i]); pldebug("plarrows", "%f %f %d %d\n",x[i],y[i],px0,py0); dpx = plP_wcpcx(x[i] + 0.5*uu) - px0; dpy = plP_wcpcy(y[i] + 0.5*vv) - py0; /* transform arrow -> a */ for (j = 0; j < 4; j++) { a_x[j] = arrow_x[j] * dpx - arrow_y[j] * dpy + px0; a_y[j] = arrow_x[j] * dpy + arrow_y[j] * dpx + py0; } /* draw the arrow */ plP_movphy(a_x[0], a_y[0]); plP_draphy(a_x[1], a_y[1]); plP_movphy(a_x[2], a_y[2]); plP_draphy(a_x[3], a_y[3]); } } /*--------------------------------------------------------------------------*\ * void pllab() * * Simple routine for labelling graphs. \*--------------------------------------------------------------------------*/ MZ_DLLEXPORT void c_pllab(const char *xlabel, const char *ylabel, const char *tlabel) { if (plsc->level < 2) { plabort("pllab: Please set up viewport first"); return; } plmtex("t", (PLFLT) 2.0, (PLFLT) 0.5, (PLFLT) 0.5, tlabel); plmtex("b", (PLFLT) 3.2, (PLFLT) 0.5, (PLFLT) 0.5, xlabel); plmtex("l", (PLFLT) 5.0, (PLFLT) 0.5, (PLFLT) 0.5, ylabel); } /*--------------------------------------------------------------------------*\ * void plmtex() * * Prints out "text" at specified position relative to viewport * (may be inside or outside) * * side String which is one of the following: * B or b : Bottom of viewport * T or t : Top of viewport * BV or bv : Bottom of viewport, vertical text * TV or tv : Top of viewport, vertical text * L or l : Left of viewport * R or r : Right of viewport * LV or lv : Left of viewport, vertical text * RV or rv : Right of viewport, vertical text * * disp Displacement from specified edge of viewport, measured outwards from * the viewport in units of the current character height. The * centerlines of the characters are aligned with the specified * position. * * pos Position of the reference point of the string relative to the * viewport edge, ranging from 0.0 (left-hand edge) to 1.0 (right-hand * edge) * * just Justification of string relative to reference point * just = 0.0 => left hand edge of string is at reference * just = 1.0 => right hand edge of string is at reference * just = 0.5 => center of string is at reference \*--------------------------------------------------------------------------*/ void c_plmtex(const char *side, PLFLT disp, PLFLT pos, PLFLT just, const char *text) { PLINT clpxmi, clpxma, clpymi, clpyma; PLINT vert, refx, refy, x, y; PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, xform[4]; PLFLT chrdef, chrht; PLFLT dispx, dispy; if (plsc->level < 2) { plabort("plmtex: Please set up viewport first"); return; } /* Open clip limits to subpage limits */ plP_gclp(&clpxmi, &clpxma, &clpymi, &clpyma); /* get and store current clip limits */ plP_sclp(plsc->sppxmi, plsc->sppxma, plsc->sppymi, plsc->sppyma); if (plP_stindex(side, "BV") != -1 || plP_stindex(side, "bv") != -1) { vert = 1; xdv = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos; ydv = plsc->vpdymi; dispx = 0; dispy = -disp; } else if (plP_stindex(side, "TV") != -1 || plP_stindex(side, "tv") != -1) { vert = 1; xdv = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos; ydv = plsc->vpdyma; dispx = 0; dispy = disp; } else if (plP_stsearch(side, 'b')) { vert = 0; xdv = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos; ydv = plsc->vpdymi; dispx = 0; dispy = -disp; } else if (plP_stsearch(side, 't')) { vert = 0; xdv = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos; ydv = plsc->vpdyma; dispx = 0; dispy = disp; } else if (plP_stindex(side, "LV") != -1 || plP_stindex(side, "lv") != -1) { vert = 0; xdv = plsc->vpdxmi; ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos; dispx = -disp; dispy = 0; } else if (plP_stindex(side, "RV") != -1 || plP_stindex(side, "rv") != -1) { vert = 0; xdv = plsc->vpdxma; ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos; dispx = disp; dispy = 0; } else if (plP_stsearch(side, 'l')) { vert = 1; xdv = plsc->vpdxmi; ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos; dispx = -disp; dispy = 0; } else if (plP_stsearch(side, 'r')) { vert = 1; xdv = plsc->vpdxma; ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos; dispx = disp; dispy = 0; } else { plP_sclp(clpxmi, clpxma, clpymi, clpyma); /* restore initial clip limits */ return; } /* Transformation matrix */ if (vert != 0) { xform[0] = 0.0; xform[1] = -1.0; xform[2] = 1.0; xform[3] = 0.0; } else { xform[0] = 1.0; xform[1] = 0.0; xform[2] = 0.0; xform[3] = 1.0; } /* Convert to physical units (mm) and compute shifts */ plgchr(&chrdef, &chrht); shift = (just == 0.0) ? 0.0 : plstrl(text) * just; xmm = plP_dcmmx(xdv) + dispx * chrht; ymm = plP_dcmmy(ydv) + dispy * chrht; refxmm = xmm - shift * xform[0]; refymm = ymm - shift * xform[2]; /* Convert to device units (pixels) and call text plotter */ x = plP_mmpcx(xmm); y = plP_mmpcy(ymm); refx = plP_mmpcx(refxmm); refy = plP_mmpcy(refymm); plP_text(0, just, xform, x, y, refx, refy, text); plP_sclp(clpxmi, clpxma, clpymi, clpyma); /* restore clip limits */ } /*--------------------------------------------------------------------------*\ * void plptex() * * Prints out "text" at world cooordinate (wx,wy). The text may be * at any angle "angle" relative to the horizontal. The parameter * "just" adjusts the horizontal justification of the string: * just = 0.0 => left hand edge of string is at (wx,wy) * just = 1.0 => right hand edge of string is at (wx,wy) * just = 0.5 => center of string is at (wx,wy) etc. \*--------------------------------------------------------------------------*/ MZ_DLLEXPORT void c_plptex(PLFLT wx, PLFLT wy, PLFLT dx, PLFLT dy, PLFLT just, const char *text) { PLINT x, y, refx, refy; PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, cc, ss; PLFLT xform[4], diag; PLFLT chrdef, chrht; PLFLT dispx, dispy; if (plsc->level < 3) { plabort("plptex: Please set up window first"); return; } if (dx == 0.0 && dy == 0.0) { dx = 1.0; dy = 0.0; } cc = plsc->wmxscl * dx; ss = plsc->wmyscl * dy; diag = sqrt(cc * cc + ss * ss); cc /= diag; ss /= diag; xform[0] = cc; xform[1] = -ss; xform[2] = ss; xform[3] = cc; xdv = plP_wcdcx(wx); ydv = plP_wcdcy(wy); dispx = 0.; dispy = 0.; /* Convert to physical units (mm) and compute shifts */ plgchr(&chrdef, &chrht); shift = (just == 0.0) ? 0.0 : plstrl(text) * just; xmm = plP_dcmmx(xdv) + dispx * chrht; ymm = plP_dcmmy(ydv) + dispy * chrht; refxmm = xmm - shift * xform[0]; refymm = ymm - shift * xform[2]; x = plP_mmpcx(xmm); y = plP_mmpcy(ymm); refx = plP_mmpcx(refxmm); refy = plP_mmpcy(refymm); plP_text(0, just, xform, x, y, refx, refy, text); } /*--------------------------------------------------------------------------*\ * void plstr() * * Prints out a "string" at reference position with physical coordinates * (refx,refy). The coordinates of the vectors defining the string are * passed through the linear mapping defined by the 2 x 2 matrix xform() * before being plotted. The reference position is at the left-hand edge of * the string. If base = 1, it is aligned with the baseline of the string. * If base = 0, it is aligned with the center of the character box. * * Note, all calculations are done in terms of millimetres. These are scaled * as necessary before plotting the string on the page. \*--------------------------------------------------------------------------*/ void plstr(PLINT base, PLFLT *xform, PLINT refx, PLINT refy, const char *string) { short int *symbol; signed char *vxygrid = 0; PLINT ch, i, length, level = 0, style, oline = 0, uline = 0; PLFLT width = 0., xorg = 0., yorg = 0., def, ht, dscale, scale; plgchr(&def, &ht); dscale = 0.05 * ht; scale = dscale; /* Line style must be continuous */ style = plsc->nms; plsc->nms = 0; pldeco(&symbol, &length, string); for (i = 0; i < length; i++) { ch = symbol[i]; if (ch == -1) { /* super-script */ level++; yorg += 16.0 * scale; scale = dscale * pow(0.75, (double) ABS(level)); } else if (ch == -2) { /* sub-script */ level--; scale = dscale * pow(0.75, (double) ABS(level)); yorg -= 16.0 * scale; } else if (ch == -3) /* back-char */ xorg -= width * scale; else if (ch == -4) /* toogle overline */ oline = !oline; else if (ch == -5) /* toogle underline */ uline = !uline; else { if (plcvec(ch, &vxygrid)) plchar(vxygrid, xform, base, oline, uline, refx, refy, scale, plsc->xpmm, plsc->ypmm, &xorg, &yorg, &width); } } plsc->nms = style; } /*--------------------------------------------------------------------------*\ * plchar() * * Plots out a given stroke font character. \*--------------------------------------------------------------------------*/ static void plchar(signed char *vxygrid, 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) { PLINT xbase, ybase, ydisp, lx, ly, cx, cy; PLINT k, penup; PLFLT x, y; PLINT llx[STLEN], lly[STLEN], l = 0; xbase = vxygrid[2]; *p_width = vxygrid[3] - xbase; if (base == 0) { ybase = 0; ydisp = vxygrid[0]; } else { ybase = vxygrid[0]; ydisp = 0; } k = 4; penup = 1; for (;;) { cx = vxygrid[k++]; cy = vxygrid[k++]; if (cx == 64 && cy == 64) { if (l) { plP_draphy_poly(llx, lly, l); l = 0; } break; } if (cx == 64 && cy == 0) { if (l) { plP_draphy_poly(llx, lly, l); l = 0; } penup = 1; } else { x = *p_xorg + (cx - xbase) * scale; y = *p_yorg + (cy - ybase) * scale; lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y)); ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y)); if (penup == 1) { if (l) { plP_draphy_poly(llx, lly, l); l = 0; } llx[l] = lx; lly[l++] = ly; /* store 1st point ! */ plP_movphy(lx, ly); penup = 0; } else { llx[l] = lx; lly[l++] = ly; } } } if (oline) { x = *p_xorg; y = *p_yorg + (30 + ydisp) * scale; lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y)); ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y)); plP_movphy(lx, ly); x = *p_xorg + *p_width * scale; lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y)); ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y)); plP_draphy(lx, ly); } if (uline) { x = *p_xorg; y = *p_yorg + (-5 + ydisp) * scale; lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y)); ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y)); plP_movphy(lx, ly); x = *p_xorg + *p_width * scale; lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y)); ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y)); plP_draphy(lx, ly); } *p_xorg = *p_xorg + *p_width * scale; } /*--------------------------------------------------------------------------*\ * PLFLT plstrl() * * Computes the length of a string in mm, including escape sequences. \*--------------------------------------------------------------------------*/ PLFLT plstrl(const char *string) { short int *symbol; signed char *vxygrid = 0; PLINT ch, i, length, level = 0; PLFLT width = 0., xorg = 0., dscale, scale, def, ht; plgchr(&def, &ht); dscale = 0.05 * ht; scale = dscale; pldeco(&symbol, &length, string); for (i = 0; i < length; i++) { ch = symbol[i]; if (ch == -1) { level++; scale = dscale * pow(0.75, (double) ABS(level)); } else if (ch == -2) { level--; scale = dscale * pow(0.75, (double) ABS(level)); } else if (ch == -3) xorg -= width * scale; else if (ch == -4 || ch == -5); else { if (plcvec(ch, &vxygrid)) { width = vxygrid[3] - vxygrid[2]; xorg += width * scale; } } } return (PLFLT) xorg; } /*--------------------------------------------------------------------------*\ * PLINT plcvec() * * Gets the character digitisation of Hershey table entry "char". * Returns 1 if there is a valid entry. \*--------------------------------------------------------------------------*/ static PLINT plcvec(PLINT ch, signed char **xygr) { PLINT k = 0, ib; signed char x, y; ch--; if (ch < 0 || ch >= indxleng) return (PLINT) 0; ib = fntindx[ch] - 2; if (ib == -2) return (PLINT) 0; do { ib++; x = fntbffr[2 * ib]; y = fntbffr[2 * ib + 1]; xygrid[k++] = x; xygrid[k++] = y; } while ((x != 64 || y != 64) && k <= (STLEN - 2)); if (k == (STLEN-1)) { /* This is bad if we get here */ xygrid[k] = 64; xygrid[k] = 64; } *xygr = xygrid; return (PLINT) 1; } /*--------------------------------------------------------------------------*\ * void pldeco() * * Decode a character string, and return an array of float integer symbol * numbers. This routine is responsible for interpreting all escape sequences. * At present the following escape sequences are defined (the letter following * the may be either upper or lower case): * * u : up one level (returns -1) * d : down one level (returns -2) * b : backspace (returns -3) * + : toggles overline mode (returns -4) * - : toggles underline mode (returns -5) * : * gx : greek letter corresponding to roman letter x * fn : switch to Normal font * fr : switch to Roman font * fi : switch to Italic font * fs : switch to Script font * (nnn) : Hershey symbol number nnn (any number of digits) * * The escape character defaults to '#', but can be changed to any of * [!#$%&*@^~] via a call to plsesc. \*--------------------------------------------------------------------------*/ static void pldeco(short int **symbol, PLINT *length, const char *text) { PLINT ch, ifont = plsc->cfont, ig, j = 0, lentxt = strlen(text); char test, esc; short int *sym = symbol_buffer; /* Initialize parameters. */ *length = 0; *symbol = symbol_buffer; plgesc(&esc); if (ifont > numberfonts) ifont = 1; /* Get next character; treat non-printing characters as spaces. */ while (j < lentxt) { if (*length >= PLMAXSTR) return; test = text[j++]; ch = test; if (ch < 0 || ch > 175) ch = 32; /* Test for escape sequence (#) */ if (ch == esc && (lentxt - j) >= 1) { test = text[j++]; if (test == esc) sym[(*length)++] = *(fntlkup + (ifont - 1) * numberchars + ch); else if (test == 'u' || test == 'U') sym[(*length)++] = -1; else if (test == 'd' || test == 'D') sym[(*length)++] = -2; else if (test == 'b' || test == 'B') sym[(*length)++] = -3; else if (test == '+') sym[(*length)++] = -4; else if (test == '-') sym[(*length)++] = -5; else if (test == '(') { sym[*length] = 0; while ('0' <= text[j] && text[j] <= '9') { sym[*length] = sym[*length] * 10 + text[j] - '0'; j++; } (*length)++; if (text[j] == ')') j++; } else if (test == 'f' || test == 'F') { test = text[j++]; ifont = 1 + plP_strpos(font_types, isupper(test) ? tolower(test) : test); if (ifont == 0 || ifont > numberfonts) ifont = 1; } else if (test == 'g' || test == 'G') { test = text[j++]; ig = plP_strpos(greek, test) + 1; sym[(*length)++] = *(fntlkup + (ifont - 1) * numberchars + 127 + ig); } else { ; } } else { /* Decode character. */ /* >>PC<< removed increment from following expression to fix */ /* compiler bug */ sym[(*length)] = *(fntlkup + (ifont - 1) * numberchars + ch); (*length)++; } } } /*--------------------------------------------------------------------------*\ * PLINT plP_strpos() * * Searches string str for first occurence of character chr. If found * the position of the character in the string is returned (the first * character has position 0). If the character is not found a -1 is * returned. \*--------------------------------------------------------------------------*/ PLINT plP_strpos(char *str, int chr) { char *temp; if ((temp = strchr(str, chr))) return (PLINT) (temp - str); else return (PLINT) -1; } /*--------------------------------------------------------------------------*\ * PLINT plP_stindex() * * Similar to strpos, but searches for occurence of string str2. \*--------------------------------------------------------------------------*/ PLINT plP_stindex(const char *str1, const char *str2) { PLINT base, str1ind, str2ind; for (base = 0; *(str1 + base) != '\0'; base++) { for (str1ind = base, str2ind = 0; *(str2 + str2ind) != '\0' && *(str2 + str2ind) == *(str1 + str1ind); str1ind++, str2ind++) ; if (*(str2 + str2ind) == '\0') return (PLINT) base; } return (PLINT) -1; /* search failed */ } /*--------------------------------------------------------------------------*\ * PLINT plP_stsearch() * * Searches string str for character chr (case insensitive). \*--------------------------------------------------------------------------*/ PLINT plP_stsearch(const char *str, int chr) { if (strchr(str, chr)) return (PLINT) 1; else if (strchr(str, toupper(chr))) return (PLINT) 1; else return (PLINT) 0; } /*--------------------------------------------------------------------------*\ * void c_plfont(ifont) * * Sets the global font flag to 'ifont'. \*--------------------------------------------------------------------------*/ void c_plfont(PLINT ifont) { if (plsc->level < 1) { plabort("plfont: Please call plinit first"); return; } if (ifont < 1 || ifont > 4) { plabort("plfont: Invalid font"); return; } plsc->cfont = ifont; } /*--------------------------------------------------------------------------*\ * void plfntld(fnt) * * Loads either the standard or extended font. \*--------------------------------------------------------------------------*/ void plfntld(PLINT fnt) { static PLINT charset; short bffrleng; PDFstrm *pdfs; if (fontloaded && (charset == fnt)) return; plfontrel(); fontloaded = 1; charset = fnt; if (fnt) pdfs = plLibOpenPdfstrm(PL_XFONT); else pdfs = plLibOpenPdfstrm(PL_SFONT); if (pdfs == NULL) plexit("Unable to open or allocate memory for font file"); /* Read fntlkup[] */ pdf_rd_2bytes(pdfs, (U_SHORT *) &bffrleng); numberfonts = bffrleng / 256; numberchars = bffrleng & 0xff; bffrleng = numberfonts * numberchars; fntlkup = (short int *) malloc(bffrleng * sizeof(short int)); if ( ! fntlkup) plexit("plfntld: Out of memory while allocating font buffer."); pdf_rd_2nbytes(pdfs, (U_SHORT *) fntlkup, bffrleng); /* Read fntindx[] */ pdf_rd_2bytes(pdfs, (U_SHORT *) &indxleng); fntindx = (short int *) malloc(indxleng * sizeof(short int)); if ( ! fntindx) plexit("plfntld: Out of memory while allocating font buffer."); pdf_rd_2nbytes(pdfs, (U_SHORT *) fntindx, indxleng); /* Read fntbffr[] */ /* Since this is an array of char, there are no endian problems */ pdf_rd_2bytes(pdfs, (U_SHORT *) &bffrleng); fntbffr = (signed char *) malloc(2 * bffrleng * sizeof(signed char)); if ( ! fntbffr) plexit("plfntld: Out of memory while allocating font buffer."); #if PLPLOT_USE_TCL_CHANNELS pdf_rdx(fntbffr, sizeof(signed char)*(2 * bffrleng), pdfs); #else if ( (2 * bffrleng) != fread((void *) fntbffr, (size_t) sizeof(signed char), (size_t) (2 * bffrleng), pdfs->file) ) { plexit("plfntld: Failed to read into font buffer."); } #endif /* Done */ pdf_close(pdfs); } /*--------------------------------------------------------------------------*\ * void plfontrel() * * Release memory for fonts. \*--------------------------------------------------------------------------*/ void plfontrel(void) { if (fontloaded) { free_mem(fntindx) free_mem(fntbffr) free_mem(fntlkup) fontloaded = 0; } }