racket/src/plot/plplot/plsym.c
2011-02-03 17:42:33 -05:00

1085 lines
28 KiB
C

/* $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 <float.h>
#include <ctype.h>
/* 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 <esc> may be either upper or lower case):
*
* <esc>u : up one level (returns -1)
* <esc>d : down one level (returns -2)
* <esc>b : backspace (returns -3)
* <esc>+ : toggles overline mode (returns -4)
* <esc>- : toggles underline mode (returns -5)
* <esc><esc> : <esc>
* <esc>gx : greek letter corresponding to roman letter x
* <esc>fn : switch to Normal font
* <esc>fr : switch to Roman font
* <esc>fi : switch to Italic font
* <esc>fs : switch to Script font
* <esc>(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 occurrence 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 occurrence 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;
}
}