Back to index

plt-scheme  4.2.1
plsym.c
Go to the documentation of this file.
00001 /* $Id: plsym.c,v 1.2 2005/03/17 21:39:21 eli Exp $
00002 
00003        Point, symbol, and string plotting routines.
00004        Also font management code.  See the description of plLibOpen() for
00005        the search path used in finding the font files.
00006 */
00007 
00008 #define NEED_PLDEBUG
00009 #include "plplotP.h"
00010 #include <float.h>
00011 #include <ctype.h>
00012 
00013 /* Declarations */
00014 
00015 static short int *fntlkup;
00016 static short int *fntindx;
00017 static signed char *fntbffr;
00018 static short int numberfonts, numberchars;
00019 static short int indxleng;
00020 
00021 static short fontloaded = 0;
00022 /* moved to plstr.h, plsc->cfont  static PLINT font = 1;  current font */
00023 
00024 #define PLMAXSTR     300
00025 #define STLEN        250
00026 
00027 static char font_types[] = "nris";
00028 static char greek[] = "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw";
00029 
00030 static short symbol_buffer[PLMAXSTR];
00031 static signed char xygrid[STLEN];
00032 
00033 /* Static function prototypes */
00034 
00035 static void
00036 pldeco(short int **sym, PLINT *length, const char *text);
00037 
00038 static void
00039 plchar(signed char *xygrid, PLFLT *xform, PLINT base, PLINT oline, PLINT uline,
00040        PLINT refx, PLINT refy, PLFLT scale, PLFLT xpmm, PLFLT ypmm,
00041        PLFLT *p_xorg, PLFLT *p_yorg, PLFLT *p_width);
00042 
00043 static PLINT
00044 plcvec(PLINT ch, signed char **xygr);
00045 
00046 static void
00047 plhrsh(PLINT ch, PLINT x, PLINT y);
00048 
00049 /*--------------------------------------------------------------------------*\
00050  * void plsym()
00051  *
00052  * Plots array y against x for n points using Hershey symbol "code".
00053 \*--------------------------------------------------------------------------*/
00054 
00055 void
00056 c_plsym(PLINT n, PLFLT *x, PLFLT *y, PLINT code)
00057 {
00058     PLINT i;
00059 
00060     if (plsc->level < 3) {
00061        plabort("plsym: Please set up window first");
00062        return;
00063     }
00064     if (code < 0) {
00065        plabort("plsym: Invalid code");
00066        return;
00067     }
00068 
00069     for (i = 0; i < n; i++)
00070        plhrsh(code, plP_wcpcx(x[i]), plP_wcpcy(y[i]));
00071 }
00072 
00073 /*--------------------------------------------------------------------------*\
00074  * void plpoin()
00075  *
00076  * Plots array y against x for n points using ASCII code "code".
00077  *
00078  * code=-1 means try to just draw a point.  Right now it's just a move and
00079  * a draw at the same place.  Not ideal, since a sufficiently intelligent
00080  * output device may optimize it away, or there may be faster ways of
00081  * doing it.  This is OK for now, though, and offers a 4X speedup over
00082  * drawing a Hershey font "point" (which is actually diamond shaped and
00083  * therefore takes 4 strokes to draw).
00084 \*--------------------------------------------------------------------------*/
00085 
00086 MZ_DLLEXPORT
00087 void
00088 c_plpoin(PLINT n, PLFLT *x, PLFLT *y, PLINT code)
00089 {
00090     PLINT i, sym, ifont = plsc->cfont;
00091 
00092     if (plsc->level < 3) {
00093        plabort("plpoin: Please set up window first");
00094        return;
00095     }
00096     if (code < -1 || code > 127) {
00097        plabort("plpoin: Invalid code");
00098        return;
00099     }
00100 
00101     if (code == -1) {
00102        for (i = 0; i < n; i++)
00103            pljoin(x[i], y[i], x[i], y[i]);
00104     }
00105     else {
00106         if (ifont > numberfonts)
00107            ifont = 1;
00108        sym = *(fntlkup + (ifont - 1) * numberchars + code);
00109 
00110        for (i = 0; i < n; i++)
00111            plhrsh(sym, plP_wcpcx(x[i]), plP_wcpcy(y[i]));
00112     }
00113 }
00114 
00115 /*--------------------------------------------------------------------------*\
00116  * void plpoin3(n, x, y, z, code)
00117  *
00118  * Draws a series of points in 3 space.  Setup similar to plline3().
00119 \*--------------------------------------------------------------------------*/
00120 
00121 void
00122 c_plpoin3(PLINT n, PLFLT *x, PLFLT *y, PLFLT *z, PLINT code)
00123 {
00124     PLINT i, sym, ifont = plsc->cfont;
00125     PLFLT u, v;
00126     PLFLT xmin, xmax, ymin, ymax, zmin, zmax, zscale;
00127 
00128     if (plsc->level < 3) {
00129        plabort("plpoin3: Please set up window first");
00130        return;
00131     }
00132     if (code < -1 || code > 127) {
00133        plabort("plpoin3: Invalid code");
00134        return;
00135     }
00136 
00137     plP_gdom(&xmin, &xmax, &ymin, &ymax);
00138     plP_grange(&zscale, &zmin, &zmax);
00139 
00140     if (code == -1) {
00141        for (i = 0; i < n; i++) {
00142          if(x[i] >= xmin && x[i] <= xmax &&
00143             y[i] >= ymin && y[i] <= ymax &&
00144             z[i] >= zmin && z[i] <= zmax) {
00145            u = plP_wcpcx(plP_w3wcx( x[i], y[i], z[i] ));
00146            v = plP_wcpcy(plP_w3wcy( x[i], y[i], z[i] ));
00147            plP_movphy(u,v);
00148            plP_draphy(u,v);
00149          }
00150        }
00151     }
00152     else {
00153         if (ifont > numberfonts)
00154            ifont = 1;
00155        sym = *(fntlkup + (ifont - 1) * numberchars + code);
00156 
00157        for( i=0; i < n; i++ ) {
00158          if(x[i] >= xmin && x[i] <= xmax &&
00159             y[i] >= ymin && y[i] <= ymax &&
00160             z[i] >= zmin && z[i] <= zmax) {
00161            u = plP_wcpcx(plP_w3wcx( x[i], y[i], z[i] ));
00162            v = plP_wcpcy(plP_w3wcy( x[i], y[i], z[i] ));
00163            plhrsh(sym, u, v);
00164          }
00165        }
00166     }
00167     return;
00168 }
00169 
00170 /*--------------------------------------------------------------------------*\
00171  * void plhrsh()
00172  *
00173  * Writes the Hershey symbol "ch" centred at the physical coordinate (x,y).
00174 \*--------------------------------------------------------------------------*/
00175 
00176 static void
00177 plhrsh(PLINT ch, PLINT x, PLINT y)
00178 {
00179     PLINT cx, cy, k, penup, style;
00180     signed char *vxygrid = 0;
00181     PLFLT scale, xscale, yscale;
00182     PLINT llx[STLEN], lly[STLEN], l = 0;
00183 
00184     penup = 1;
00185     scale = 0.05 * plsc->symht;
00186 
00187     if ( ! plcvec(ch, &vxygrid)) {
00188        plP_movphy(x, y);
00189        return;
00190     }
00191 
00192 /* Line style must be continuous */
00193 
00194     style = plsc->nms;
00195     plsc->nms = 0;
00196 
00197 /* Compute how many physical pixels correspond to a character pixel */
00198 
00199     xscale = scale * plsc->xpmm;
00200     yscale = scale * plsc->ypmm;
00201 
00202     k = 4;
00203     for (;;) {
00204        cx = vxygrid[k++];
00205        cy = vxygrid[k++];
00206        if (cx == 64 && cy == 64) {
00207          if (l) {
00208            plP_draphy_poly(llx, lly, l);
00209            l = 0;
00210          }
00211          plP_movphy(x, y);
00212          plsc->nms = style;
00213          return;
00214        }
00215        else if (cx == 64 && cy == 0)
00216            penup = 1;
00217        else {
00218            if (penup == 1) {
00219              if (l) {
00220               plP_draphy_poly(llx, lly, l);
00221               l = 0;
00222             }
00223              llx[l] = ROUND(x+ xscale * cx);
00224             lly[l++] = ROUND(y + yscale * cy);
00225              plP_movphy(llx[l-1], lly[l-1]);
00226             penup = 0;
00227            }
00228            else {
00229              llx[l] = ROUND(x+ xscale * cx);
00230              lly[l++] = ROUND(y + yscale * cy);
00231            }
00232        }
00233     }
00234 }
00235 
00236 /*--------------------------------------------------------------------------*\
00237  * void plarrows()
00238  *
00239  * simple arrow plotter
00240  * copyright 1993 Wesley Ebisuzaki
00241  *
00242  * an arrow is defined by its location (x, y) and its direction (u, v)
00243  *
00244  * inputs:
00245  *   u[i], v[i]      arrow's horizontal and vertical projection
00246  *   x[i], y[i]      arrow's location (world coordinates)
00247  *   n               number of arrows to draw
00248  *   scale           > 0  scaling factor for arrows
00249  *                   0    default scaling factor
00250  *                   < 0  default scaling factor * (-scale)
00251  *   dx, dy          distance between arrows
00252  *                   used when calculating the default arrow scaling
00253  *                   so that arrows don't overlap
00254  *
00255 \*--------------------------------------------------------------------------*/
00256 
00257 #define SCALE0 2.0
00258 
00259 /* definition of original arrow: 2 line segments */
00260 
00261 static PLFLT arrow_x[4] = {0.5, -0.5, -0.27, -0.5};
00262 static PLFLT arrow_y[4] = {0.0, 0.0, 0.0, 0.20};
00263 
00264 void 
00265 plarrows(PLFLT *u, PLFLT *v, PLFLT *x, PLFLT *y, PLINT n,
00266         PLFLT scale, PLFLT dx, PLFLT dy) 
00267 {
00268     PLFLT uu, vv;
00269     PLINT i, j;
00270     PLINT px0, py0, dpx, dpy;
00271     PLINT a_x[4], a_y[4];
00272     PLFLT max_u, max_v;
00273     double t;
00274 
00275     if (n <= 0) return;
00276 
00277     if (scale <= 0.0) {
00278 
00279     /* automatic scaling */
00280     /* find max / min values of data */
00281 
00282        max_u = u[0];
00283        max_v = v[0];
00284        for (i = 1; i < n; i++) {
00285            t = fabs((double) u[i]);
00286            max_u = t > max_u ? t : max_u;
00287            t = fabs((double) v[i]);
00288            max_v = t > max_v ? t : max_v;
00289        }
00290 
00291     /* measure distance in grid boxs */
00292 
00293        max_u = max_u / fabs( (double) dx);
00294        max_v = max_v / fabs( (double) dy);
00295 
00296        t = (max_u > max_v ? max_u : max_v);
00297        t = SCALE0 / t;
00298        if (scale < 0) {
00299            scale = -scale * t;
00300        }
00301        else {
00302            scale = t;
00303        }
00304     }
00305     pldebug("plarrows", "scale factor=%lf n=%d\n", scale,n);
00306 
00307     for (i = 0; i < n; i++) {
00308        uu = scale * u[i];
00309        vv = scale * v[i];
00310        if (uu == 0.0 && uu == 0.0) continue;
00311 
00312     /* conversion to physical coordinates */
00313 
00314        px0 = plP_wcpcx(x[i]);
00315        py0 = plP_wcpcy(y[i]);
00316 
00317        pldebug("plarrows", "%f %f %d %d\n",x[i],y[i],px0,py0);
00318 
00319        dpx = plP_wcpcx(x[i] + 0.5*uu) - px0;
00320        dpy = plP_wcpcy(y[i] + 0.5*vv) - py0;
00321 
00322     /* transform arrow -> a */
00323 
00324        for (j = 0; j < 4; j++) {
00325            a_x[j] = arrow_x[j] * dpx -
00326               arrow_y[j] * dpy + px0;
00327            a_y[j] = arrow_x[j] * dpy +
00328               arrow_y[j] * dpx + py0;
00329        }
00330 
00331     /* draw the arrow */
00332 
00333        plP_movphy(a_x[0], a_y[0]);
00334        plP_draphy(a_x[1], a_y[1]);
00335        plP_movphy(a_x[2], a_y[2]);
00336        plP_draphy(a_x[3], a_y[3]);
00337     }
00338 }
00339 
00340 /*--------------------------------------------------------------------------*\
00341  * void pllab()
00342  *
00343  * Simple routine for labelling graphs.
00344 \*--------------------------------------------------------------------------*/
00345 
00346 MZ_DLLEXPORT
00347 void
00348 c_pllab(const char *xlabel, const char *ylabel, const char *tlabel)
00349 {
00350     if (plsc->level < 2) {
00351        plabort("pllab: Please set up viewport first");
00352        return;
00353     }
00354 
00355     plmtex("t", (PLFLT) 2.0, (PLFLT) 0.5, (PLFLT) 0.5, tlabel);
00356     plmtex("b", (PLFLT) 3.2, (PLFLT) 0.5, (PLFLT) 0.5, xlabel);
00357     plmtex("l", (PLFLT) 5.0, (PLFLT) 0.5, (PLFLT) 0.5, ylabel);
00358 }
00359 
00360 /*--------------------------------------------------------------------------*\
00361  * void plmtex()
00362  *
00363  * Prints out "text" at specified position relative to viewport
00364  * (may be inside or outside)
00365  *
00366  * side       String which is one of the following:
00367  *     B or b  :  Bottom of viewport
00368  *     T or t  :  Top of viewport
00369  *     BV or bv : Bottom of viewport, vertical text
00370  *     TV or tv : Top of viewport, vertical text
00371  *     L or l  :  Left of viewport
00372  *     R or r  :  Right of viewport
00373  *     LV or lv : Left of viewport, vertical text
00374  *     RV or rv : Right of viewport, vertical text
00375  *
00376  * disp Displacement from specified edge of viewport, measured outwards from
00377  *     the viewport in units of the current character height. The
00378  *     centerlines of the characters are aligned with the specified
00379  *     position.
00380  *
00381  * pos Position of the reference point of the string relative to the
00382  *     viewport edge, ranging from 0.0 (left-hand edge) to 1.0 (right-hand
00383  *     edge)
00384  *
00385  * just       Justification of string relative to reference point
00386  *     just = 0.0 => left hand edge of string is at reference
00387  *     just = 1.0 => right hand edge of string is at reference
00388  *     just = 0.5 => center of string is at reference
00389 \*--------------------------------------------------------------------------*/
00390 
00391 void
00392 c_plmtex(const char *side, PLFLT disp, PLFLT pos, PLFLT just,
00393         const char *text)
00394 {
00395     PLINT clpxmi, clpxma, clpymi, clpyma;
00396     PLINT vert, refx, refy, x, y;
00397     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, xform[4];
00398     PLFLT chrdef, chrht;
00399     PLFLT dispx, dispy;
00400 
00401     if (plsc->level < 2) {
00402        plabort("plmtex: Please set up viewport first");
00403        return;
00404     }
00405 
00406 /* Open clip limits to subpage limits */
00407 
00408     plP_gclp(&clpxmi, &clpxma, &clpymi, &clpyma); /* get and store current clip limits */
00409     plP_sclp(plsc->sppxmi, plsc->sppxma, plsc->sppymi, plsc->sppyma);
00410 
00411     if (plP_stindex(side, "BV") != -1 || plP_stindex(side, "bv") != -1) {
00412        vert = 1;
00413        xdv  = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos;
00414        ydv  = plsc->vpdymi;
00415        dispx = 0;
00416        dispy = -disp;
00417     }
00418     else if (plP_stindex(side, "TV") != -1 || plP_stindex(side, "tv") != -1) {
00419        vert = 1;
00420        xdv  = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos;
00421        ydv  = plsc->vpdyma;
00422        dispx = 0;
00423        dispy = disp;
00424     }
00425     else if (plP_stsearch(side, 'b')) {
00426        vert = 0;
00427        xdv = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos;
00428        ydv = plsc->vpdymi;
00429        dispx = 0;
00430        dispy = -disp;
00431 
00432     } else if (plP_stsearch(side, 't')) {
00433        vert = 0;
00434        xdv = plsc->vpdxmi + (plsc->vpdxma - plsc->vpdxmi) * pos;
00435        ydv = plsc->vpdyma;
00436        dispx = 0;
00437        dispy = disp;
00438 
00439     } else if (plP_stindex(side, "LV") != -1 || plP_stindex(side, "lv") != -1) {
00440        vert = 0;
00441        xdv = plsc->vpdxmi;
00442        ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos;
00443        dispx = -disp;
00444        dispy = 0;
00445 
00446     } else if (plP_stindex(side, "RV") != -1 || plP_stindex(side, "rv") != -1) {
00447        vert = 0;
00448        xdv = plsc->vpdxma;
00449        ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos;
00450        dispx = disp;
00451        dispy = 0;
00452 
00453     } else if (plP_stsearch(side, 'l')) {
00454        vert = 1;
00455        xdv = plsc->vpdxmi;
00456        ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos;
00457        dispx = -disp;
00458        dispy = 0;
00459 
00460     } else if (plP_stsearch(side, 'r')) {
00461        vert = 1;
00462        xdv = plsc->vpdxma;
00463        ydv = plsc->vpdymi + (plsc->vpdyma - plsc->vpdymi) * pos;
00464        dispx = disp;
00465        dispy = 0;
00466 
00467     } else {
00468        plP_sclp(clpxmi, clpxma, clpymi, clpyma); /* restore initial clip limits */
00469        return;
00470     }
00471 
00472 /* Transformation matrix */
00473 
00474     if (vert != 0) {
00475        xform[0] = 0.0;
00476        xform[1] = -1.0;
00477        xform[2] = 1.0;
00478        xform[3] = 0.0;
00479     } else {
00480        xform[0] = 1.0;
00481        xform[1] = 0.0;
00482        xform[2] = 0.0;
00483        xform[3] = 1.0;
00484     }
00485 
00486 /* Convert to physical units (mm) and compute shifts */
00487 
00488     plgchr(&chrdef, &chrht);
00489     shift = (just == 0.0) ? 0.0 : plstrl(text) * just;
00490 
00491     xmm = plP_dcmmx(xdv) + dispx * chrht;
00492     ymm = plP_dcmmy(ydv) + dispy * chrht;
00493     refxmm = xmm - shift * xform[0];
00494     refymm = ymm - shift * xform[2];
00495 
00496 /* Convert to device units (pixels) and call text plotter */
00497 
00498     x = plP_mmpcx(xmm);
00499     y = plP_mmpcy(ymm);
00500     refx = plP_mmpcx(refxmm);
00501     refy = plP_mmpcy(refymm);
00502 
00503     plP_text(0, just, xform, x, y, refx, refy, text);
00504     plP_sclp(clpxmi, clpxma, clpymi, clpyma); /* restore clip limits */
00505 }
00506 
00507 /*--------------------------------------------------------------------------*\
00508  * void plptex()
00509  *
00510  * Prints out "text" at world cooordinate (wx,wy). The text may be
00511  * at any angle "angle" relative to the horizontal. The parameter
00512  * "just" adjusts the horizontal justification of the string:
00513  *     just = 0.0 => left hand edge of string is at (wx,wy)
00514  *     just = 1.0 => right hand edge of string is at (wx,wy)
00515  *     just = 0.5 => center of string is at (wx,wy) etc.
00516 \*--------------------------------------------------------------------------*/
00517 
00518 MZ_DLLEXPORT
00519 void
00520 c_plptex(PLFLT wx, PLFLT wy, PLFLT dx, PLFLT dy, PLFLT just, const char *text)
00521 {
00522     PLINT x, y, refx, refy;
00523     PLFLT xdv, ydv, xmm, ymm, refxmm, refymm, shift, cc, ss;
00524     PLFLT xform[4], diag;
00525     PLFLT chrdef, chrht;
00526     PLFLT dispx, dispy;
00527 
00528     if (plsc->level < 3) {
00529        plabort("plptex: Please set up window first");
00530        return;
00531     }
00532 
00533     if (dx == 0.0 && dy == 0.0) {
00534        dx = 1.0;
00535        dy = 0.0;
00536     }
00537     cc = plsc->wmxscl * dx;
00538     ss = plsc->wmyscl * dy;
00539     diag = sqrt(cc * cc + ss * ss);
00540     cc /= diag;
00541     ss /= diag;
00542 
00543     xform[0] = cc;
00544     xform[1] = -ss;
00545     xform[2] = ss;
00546     xform[3] = cc;
00547 
00548     xdv = plP_wcdcx(wx);
00549     ydv = plP_wcdcy(wy);
00550 
00551     dispx = 0.;
00552     dispy = 0.;
00553 
00554 /* Convert to physical units (mm) and compute shifts */
00555 
00556     plgchr(&chrdef, &chrht);
00557     shift = (just == 0.0) ? 0.0 : plstrl(text) * just;
00558 
00559     xmm = plP_dcmmx(xdv) + dispx * chrht;
00560     ymm = plP_dcmmy(ydv) + dispy * chrht;
00561     refxmm = xmm - shift * xform[0];
00562     refymm = ymm - shift * xform[2];
00563 
00564     x = plP_mmpcx(xmm);
00565     y = plP_mmpcy(ymm);
00566     refx = plP_mmpcx(refxmm);
00567     refy = plP_mmpcy(refymm);
00568 
00569     plP_text(0, just, xform, x, y, refx, refy, text);      
00570 }
00571 
00572 /*--------------------------------------------------------------------------*\
00573  * void plstr()
00574  *
00575  * Prints out a "string" at reference position with physical coordinates
00576  * (refx,refy). The coordinates of the vectors defining the string are
00577  * passed through the linear mapping defined by the 2 x 2 matrix xform()
00578  * before being plotted.  The reference position is at the left-hand edge of
00579  * the string. If base = 1, it is aligned with the baseline of the string.
00580  * If base = 0, it is aligned with the center of the character box.
00581  *
00582  * Note, all calculations are done in terms of millimetres. These are scaled
00583  * as necessary before plotting the string on the page.
00584 \*--------------------------------------------------------------------------*/
00585 
00586 void
00587 plstr(PLINT base, PLFLT *xform, PLINT refx, PLINT refy, const char *string)
00588 {
00589     short int *symbol;
00590     signed char *vxygrid = 0;
00591     
00592     PLINT ch, i, length, level = 0, style, oline = 0, uline = 0;
00593     PLFLT width = 0., xorg = 0., yorg = 0., def, ht, dscale, scale;
00594 
00595     plgchr(&def, &ht);
00596     dscale = 0.05 * ht;
00597     scale = dscale;
00598 
00599 /* Line style must be continuous */
00600 
00601     style = plsc->nms;
00602     plsc->nms = 0;
00603 
00604     pldeco(&symbol, &length, string);
00605 
00606     for (i = 0; i < length; i++) {
00607        ch = symbol[i];
00608        if (ch == -1) { /* super-script */
00609            level++;
00610            yorg += 16.0 * scale;
00611            scale = dscale * pow(0.75, (double) ABS(level));
00612        }
00613        else if (ch == -2) { /* sub-script */
00614            level--; 
00615            scale = dscale * pow(0.75, (double) ABS(level));
00616            yorg -= 16.0 * scale;
00617        }
00618        else if (ch == -3) /* back-char */
00619            xorg -= width * scale;
00620        else if (ch == -4) /* toogle overline */
00621            oline = !oline; 
00622        else if (ch == -5)  /* toogle underline */
00623            uline = !uline;
00624        else {
00625            if (plcvec(ch, &vxygrid))
00626               plchar(vxygrid, xform, base, oline, uline, refx, refy, scale,
00627                      plsc->xpmm, plsc->ypmm, &xorg, &yorg, &width);
00628        }
00629     }
00630     plsc->nms = style;
00631 }
00632 
00633 /*--------------------------------------------------------------------------*\
00634  * plchar()
00635  *
00636  * Plots out a given stroke font character.
00637 \*--------------------------------------------------------------------------*/
00638 
00639 static void
00640 plchar(signed char *vxygrid, PLFLT *xform, PLINT base, PLINT oline, PLINT uline,
00641        PLINT refx, PLINT refy, PLFLT scale, PLFLT xpmm, PLFLT ypmm,
00642        PLFLT *p_xorg, PLFLT *p_yorg, PLFLT *p_width)
00643 {
00644     PLINT xbase, ybase, ydisp, lx, ly, cx, cy;
00645     PLINT k, penup;
00646     PLFLT x, y;
00647     PLINT llx[STLEN], lly[STLEN], l = 0;
00648 
00649     xbase = vxygrid[2];
00650     *p_width = vxygrid[3] - xbase;
00651     if (base == 0) {
00652        ybase = 0;
00653        ydisp = vxygrid[0];
00654     }
00655     else {
00656        ybase = vxygrid[0];
00657        ydisp = 0;
00658     }
00659     k = 4;
00660     penup = 1;
00661 
00662     for (;;) {
00663        cx = vxygrid[k++];
00664        cy = vxygrid[k++];
00665        if (cx == 64 && cy == 64) {
00666          if (l) {
00667            plP_draphy_poly(llx, lly, l);
00668            l = 0;
00669          }
00670          break;
00671        }
00672        if (cx == 64 && cy == 0) {
00673          if (l) {
00674            plP_draphy_poly(llx, lly, l);
00675            l = 0;
00676          }
00677          penup = 1;
00678        }
00679        else {
00680            x = *p_xorg + (cx - xbase) * scale;
00681            y = *p_yorg + (cy - ybase) * scale;
00682            lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y));
00683            ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y));
00684            if (penup == 1) {
00685              if (l) {
00686               plP_draphy_poly(llx, lly, l);
00687               l = 0;
00688              }
00689              llx[l] = lx;
00690              lly[l++] = ly; /* store 1st point ! */
00691              plP_movphy(lx, ly);
00692              penup = 0;
00693            }
00694            else {
00695              llx[l] = lx;
00696              lly[l++] = ly;
00697            }
00698        }
00699     }
00700 
00701     if (oline) {
00702        x = *p_xorg;
00703        y = *p_yorg + (30 + ydisp) * scale;
00704        lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y));
00705        ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y));
00706        plP_movphy(lx, ly);
00707        x = *p_xorg + *p_width * scale;
00708        lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y));
00709        ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y));
00710        plP_draphy(lx, ly);
00711     }
00712     if (uline) {
00713        x = *p_xorg;
00714        y = *p_yorg + (-5 + ydisp) * scale;
00715        lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y));
00716        ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y));
00717        plP_movphy(lx, ly);
00718        x = *p_xorg + *p_width * scale;
00719        lx = refx + ROUND(xpmm * (xform[0] * x + xform[1] * y));
00720        ly = refy + ROUND(ypmm * (xform[2] * x + xform[3] * y));
00721        plP_draphy(lx, ly);
00722     }
00723     *p_xorg = *p_xorg + *p_width * scale;
00724 }
00725 
00726 /*--------------------------------------------------------------------------*\
00727  * PLFLT plstrl()
00728  *
00729  * Computes the length of a string in mm, including escape sequences.
00730 \*--------------------------------------------------------------------------*/
00731 
00732 PLFLT
00733 plstrl(const char *string)
00734 {
00735     short int *symbol;
00736     signed char *vxygrid = 0;
00737     PLINT ch, i, length, level = 0;
00738     PLFLT width = 0., xorg = 0., dscale, scale, def, ht;
00739 
00740     plgchr(&def, &ht);
00741     dscale = 0.05 * ht;
00742     scale = dscale;
00743     pldeco(&symbol, &length, string);
00744 
00745     for (i = 0; i < length; i++) {
00746        ch = symbol[i];
00747        if (ch == -1) {
00748            level++;
00749            scale = dscale * pow(0.75, (double) ABS(level));
00750        }
00751        else if (ch == -2) {
00752            level--;
00753            scale = dscale * pow(0.75, (double) ABS(level));
00754        }
00755        else if (ch == -3)
00756            xorg -= width * scale;
00757        else if (ch == -4 || ch == -5);
00758        else {
00759            if (plcvec(ch, &vxygrid)) {
00760               width = vxygrid[3] - vxygrid[2];
00761               xorg += width * scale;
00762            }
00763        }
00764     }
00765     return (PLFLT) xorg;
00766 }
00767 
00768 /*--------------------------------------------------------------------------*\
00769  * PLINT plcvec()
00770  *
00771  * Gets the character digitisation of Hershey table entry "char".
00772  * Returns 1 if there is a valid entry.
00773 \*--------------------------------------------------------------------------*/
00774 
00775 static PLINT
00776 plcvec(PLINT ch, signed char **xygr)
00777 {
00778     PLINT k = 0, ib;
00779     signed char x, y;
00780 
00781     ch--;
00782     if (ch < 0 || ch >= indxleng)
00783        return (PLINT) 0;
00784     ib = fntindx[ch] - 2;
00785     if (ib == -2)
00786        return (PLINT) 0;
00787 
00788     do {
00789        ib++;
00790        x = fntbffr[2 * ib];
00791        y = fntbffr[2 * ib + 1];
00792        xygrid[k++] = x;
00793        xygrid[k++] = y;
00794     } while ((x != 64 || y != 64) && k <= (STLEN - 2));
00795 
00796     if (k == (STLEN-1)) {
00797        /* This is bad if we get here */
00798        xygrid[k] = 64;
00799        xygrid[k] = 64;
00800     }
00801     
00802     *xygr = xygrid;
00803     return (PLINT) 1;
00804 }
00805 
00806 /*--------------------------------------------------------------------------*\
00807  * void pldeco()
00808  *
00809  * Decode a character string, and return an array of float integer symbol
00810  * numbers. This routine is responsible for interpreting all escape sequences.
00811  * At present the following escape sequences are defined (the letter following
00812  * the <esc> may be either upper or lower case):
00813  *
00814  * <esc>u     : up one level (returns -1)
00815  * <esc>d     : down one level (returns -2)
00816  * <esc>b     : backspace (returns -3)
00817  * <esc>+     : toggles overline mode (returns -4)
00818  * <esc>-     : toggles underline mode (returns -5)
00819  * <esc><esc> : <esc>
00820  * <esc>gx    : greek letter corresponding to roman letter x
00821  * <esc>fn    : switch to Normal font
00822  * <esc>fr    : switch to Roman font
00823  * <esc>fi    : switch to Italic font
00824  * <esc>fs    : switch to Script font
00825  * <esc>(nnn) : Hershey symbol number nnn (any number of digits)
00826  *
00827  * The escape character defaults to '#', but can be changed to any of
00828  * [!#$%&*@^~] via a call to plsesc.
00829 \*--------------------------------------------------------------------------*/
00830 
00831 static void
00832 pldeco(short int **symbol, PLINT *length, const char *text)
00833 {
00834     PLINT ch, ifont = plsc->cfont, ig, j = 0, lentxt = strlen(text);
00835     char test, esc;
00836     short int *sym = symbol_buffer;
00837 
00838 /* Initialize parameters. */
00839 
00840     *length = 0;
00841     *symbol = symbol_buffer;
00842     plgesc(&esc);
00843     if (ifont > numberfonts)
00844        ifont = 1;
00845 
00846 /* Get next character; treat non-printing characters as spaces. */
00847 
00848     while (j < lentxt) {
00849        if (*length >= PLMAXSTR)
00850            return;
00851        test = text[j++];
00852        ch = test;
00853        if (ch < 0 || ch > 175)
00854            ch = 32;
00855 
00856     /* Test for escape sequence (#) */
00857 
00858        if (ch == esc && (lentxt - j) >= 1) {
00859            test = text[j++];
00860            if (test == esc)
00861               sym[(*length)++] = *(fntlkup + (ifont - 1) * numberchars + ch);
00862 
00863            else if (test == 'u' || test == 'U')
00864               sym[(*length)++] = -1;
00865 
00866            else if (test == 'd' || test == 'D')
00867               sym[(*length)++] = -2;
00868 
00869            else if (test == 'b' || test == 'B')
00870               sym[(*length)++] = -3;
00871 
00872            else if (test == '+')
00873               sym[(*length)++] = -4;
00874 
00875            else if (test == '-')
00876               sym[(*length)++] = -5;
00877 
00878            else if (test == '(') {
00879               sym[*length] = 0;
00880               while ('0' <= text[j] && text[j] <= '9') {
00881                   sym[*length] = sym[*length] * 10 + text[j] - '0';
00882                   j++;
00883               }
00884               (*length)++;
00885               if (text[j] == ')')
00886                   j++;
00887            }
00888            else if (test == 'f' || test == 'F') {
00889               test = text[j++];
00890               ifont = 1 + plP_strpos(font_types,
00891                                    isupper(test) ? tolower(test) : test);
00892               if (ifont == 0 || ifont > numberfonts)
00893                   ifont = 1;
00894            }
00895            else if (test == 'g' || test == 'G') {
00896               test = text[j++];
00897               ig = plP_strpos(greek, test) + 1;
00898               sym[(*length)++] = 
00899                   *(fntlkup + (ifont - 1) * numberchars + 127 + ig);
00900            }
00901            else {
00902               ;
00903            }
00904        }
00905        else {
00906 
00907        /* Decode character. */
00908        /* >>PC<< removed increment from following expression to fix */
00909        /* compiler bug */ 
00910 
00911            sym[(*length)] = *(fntlkup + (ifont - 1) * numberchars + ch);
00912            (*length)++;
00913        }
00914     }
00915 }
00916 
00917 /*--------------------------------------------------------------------------*\
00918  * PLINT plP_strpos()
00919  *
00920  * Searches string str for first occurence of character chr.  If found
00921  * the position of the character in the string is returned (the first
00922  * character has position 0).  If the character is not found a -1 is
00923  * returned.
00924 \*--------------------------------------------------------------------------*/
00925 
00926 PLINT
00927 plP_strpos(char *str, int chr)
00928 {
00929     char *temp;
00930 
00931     if ((temp = strchr(str, chr)))
00932        return (PLINT) (temp - str);
00933     else
00934        return (PLINT) -1;
00935 }
00936 
00937 /*--------------------------------------------------------------------------*\
00938  * PLINT plP_stindex()
00939  *
00940  * Similar to strpos, but searches for occurence of string str2.
00941 \*--------------------------------------------------------------------------*/
00942 
00943 PLINT
00944 plP_stindex(const char *str1, const char *str2)
00945 {
00946     PLINT base, str1ind, str2ind;
00947 
00948     for (base = 0; *(str1 + base) != '\0'; base++) {
00949        for (str1ind = base, str2ind = 0; *(str2 + str2ind) != '\0' &&
00950             *(str2 + str2ind) == *(str1 + str1ind); str1ind++, str2ind++)
00951            ;
00952 
00953        if (*(str2 + str2ind) == '\0')
00954            return (PLINT) base;
00955     }
00956     return (PLINT) -1;             /* search failed */
00957 }
00958 
00959 /*--------------------------------------------------------------------------*\
00960  * PLINT plP_stsearch()
00961  *
00962  * Searches string str for character chr (case insensitive).
00963 \*--------------------------------------------------------------------------*/
00964 
00965 PLINT
00966 plP_stsearch(const char *str, int chr)
00967 {
00968     if (strchr(str, chr))
00969        return (PLINT) 1;
00970     else if (strchr(str, toupper(chr)))
00971        return (PLINT) 1;
00972     else
00973        return (PLINT) 0;
00974 }
00975 
00976 /*--------------------------------------------------------------------------*\
00977  * void c_plfont(ifont)
00978  *
00979  * Sets the global font flag to 'ifont'.
00980 \*--------------------------------------------------------------------------*/
00981 
00982 void
00983 c_plfont(PLINT ifont)
00984 {
00985     if (plsc->level < 1) {
00986        plabort("plfont: Please call plinit first");
00987        return;
00988     }
00989     if (ifont < 1 || ifont > 4) {
00990        plabort("plfont: Invalid font");
00991        return;
00992     }
00993 
00994     plsc->cfont = ifont;
00995 }
00996 
00997 /*--------------------------------------------------------------------------*\
00998  * void plfntld(fnt)
00999  *
01000  * Loads either the standard or extended font.
01001 \*--------------------------------------------------------------------------*/
01002 
01003 void
01004 plfntld(PLINT fnt)
01005 {
01006     static PLINT charset;
01007     short bffrleng;
01008     PDFstrm *pdfs;
01009 
01010     if (fontloaded && (charset == fnt))
01011        return;
01012 
01013     plfontrel();
01014     fontloaded = 1;
01015     charset = fnt;
01016 
01017     if (fnt)
01018        pdfs = plLibOpenPdfstrm(PL_XFONT);
01019     else
01020        pdfs = plLibOpenPdfstrm(PL_SFONT);
01021 
01022     if (pdfs == NULL)
01023        plexit("Unable to open or allocate memory for font file");
01024 
01025 /* Read fntlkup[] */
01026 
01027     pdf_rd_2bytes(pdfs, (U_SHORT *) &bffrleng);
01028     numberfonts = bffrleng / 256;
01029     numberchars = bffrleng & 0xff;
01030     bffrleng = numberfonts * numberchars;
01031     fntlkup = (short int *) malloc(bffrleng * sizeof(short int));
01032     if ( ! fntlkup)
01033        plexit("plfntld: Out of memory while allocating font buffer.");
01034 
01035     pdf_rd_2nbytes(pdfs, (U_SHORT *) fntlkup, bffrleng);
01036 
01037 /* Read fntindx[] */
01038 
01039     pdf_rd_2bytes(pdfs, (U_SHORT *) &indxleng);
01040     fntindx = (short int *) malloc(indxleng * sizeof(short int));
01041     if ( ! fntindx)
01042        plexit("plfntld: Out of memory while allocating font buffer.");
01043 
01044     pdf_rd_2nbytes(pdfs, (U_SHORT *) fntindx, indxleng);
01045 
01046 /* Read fntbffr[] */
01047 /* Since this is an array of char, there are no endian problems */
01048 
01049     pdf_rd_2bytes(pdfs, (U_SHORT *) &bffrleng);
01050     fntbffr = (signed char *) malloc(2 * bffrleng * sizeof(signed char));
01051     if ( ! fntbffr)
01052        plexit("plfntld: Out of memory while allocating font buffer.");
01053 
01054 #if PLPLOT_USE_TCL_CHANNELS
01055     pdf_rdx(fntbffr, sizeof(signed char)*(2 * bffrleng), pdfs);
01056 #else
01057     fread((void *) fntbffr, (size_t) sizeof(signed char),
01058          (size_t) (2 * bffrleng), pdfs->file);
01059 #endif
01060 
01061 /* Done */
01062 
01063     pdf_close(pdfs);
01064 }
01065 
01066 /*--------------------------------------------------------------------------*\
01067  * void plfontrel()
01068  *
01069  * Release memory for fonts.
01070 \*--------------------------------------------------------------------------*/
01071 
01072 void
01073 plfontrel(void)
01074 {
01075     if (fontloaded) {
01076        free_mem(fntindx)
01077        free_mem(fntbffr)
01078        free_mem(fntlkup)
01079        fontloaded = 0;
01080     }
01081 }