Back to index

plt-scheme  4.2.1
plctrl.c
Go to the documentation of this file.
00001 /* $Id: plctrl.c,v 1.3 2005/03/18 20:32:41 eli Exp $
00002 
00003        Misc. control routines, like begin, end, exit, change graphics/text
00004        mode, change color.  Includes some spillage from plcore.c.  If you
00005        don't know where it should go, put it here.  
00006 */
00007 
00008 #define DEBUG
00009 
00010 #define NEED_PLDEBUG
00011 #include "plplotP.h"
00012 #ifdef macintosh
00013 #include "mac.h"
00014 /* for plMacLibOpen prototype; used in plLibOpen */
00015 #endif
00016 
00017 #ifdef DJGPP                /* dos386/djgpp */
00018 #ifdef __unix
00019 #undef __unix
00020 #endif
00021 #endif
00022 
00023 #ifdef __unix
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #ifdef HAVE_UNISTD_H
00027 #include <unistd.h>
00028 #endif
00029 #include <errno.h>
00030 #endif
00031 
00032 /* Static functions */
00033 
00034 /* Used by any external init code to suggest a path */
00035 MZ_DLLEXPORT
00036 char* plplotLibDir = 0;
00037 
00038 static void
00039 color_set(PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, char *name );
00040 
00041 static void
00042 strcat_delim(char *dirspec);
00043 
00044 static int
00045 (*exit_handler) (char *errormsg);
00046 
00047 static void
00048 plcmap0_def(int imin, int imax);
00049 
00050 static void
00051 plcmap1_def(void);
00052 
00053 static PLFLT
00054 value(double n1, double n2, double hue);
00055 
00056 /* An additional hardwired location for lib files. */
00057 /* I have no plans to change these again, ever. */
00058 
00059 #if defined(DJGPP)
00060 #ifndef PLLIBDEV
00061 #define PLLIBDEV "c:/plplot/lib"
00062 #endif
00063 
00064 #elif defined(MSDOS)
00065 #ifndef PLLIBDEV
00066 #define PLLIBDEV "c:\\plplot\\lib"
00067 #endif
00068 
00069 #else
00070 
00071 /* Anything else is assumed to be Unix */
00072 
00073 #ifndef PLLIBDEV
00074 #define PLLIBDEV "/usr/local/plplot/lib"
00075 #endif
00076 
00077 #endif
00078 
00079 /*--------------------------------------------------------------------------*\
00080  *  Routines that deal with colors & color maps.
00081 \*--------------------------------------------------------------------------*/
00082 
00083 /*--------------------------------------------------------------------------*\
00084  * plcol0()
00085  *
00086  * Set color, map 0.  Argument is integer between 0 and plsc->ncol0.
00087 \*--------------------------------------------------------------------------*/
00088 
00089 MZ_DLLEXPORT
00090 void
00091 c_plcol0(PLINT icol0)
00092 {
00093     if (plsc->level < 1) {
00094        plabort("plcol0: Please call plinit first");
00095        return;
00096     }
00097     if (icol0 < 0 || icol0 >= plsc->ncol0) {
00098        char buffer[256];
00099        sprintf(buffer, "plcol0: Invalid color map entry: %d", (int) icol0);
00100        plabort(buffer);
00101        return;
00102     }
00103 
00104     plsc->icol0 = icol0;
00105     plsc->curcolor.r = plsc->cmap0[icol0].r;
00106     plsc->curcolor.g = plsc->cmap0[icol0].g;
00107     plsc->curcolor.b = plsc->cmap0[icol0].b;
00108 
00109     plsc->curcmap = 0;
00110     plP_state(PLSTATE_COLOR0);
00111 }
00112 
00113 /*--------------------------------------------------------------------------*\
00114  * plcol1()
00115  *
00116  * Set color, map 1.  Argument is a float between 0. and 1.
00117 \*--------------------------------------------------------------------------*/
00118 
00119 void
00120 c_plcol1(PLFLT col1)
00121 {
00122     PLINT icol1;
00123 
00124     if (plsc->level < 1) {
00125        plabort("plcol1: Please call plinit first");
00126        return;
00127     }
00128     if (col1 < 0 || col1 > 1) {
00129        char buffer[256];
00130        sprintf(buffer, "plcol1: Invalid color map position: %f", (PLFLT) col1);
00131        plabort(buffer);
00132        return;
00133     }
00134 
00135     icol1 = col1 * plsc->ncol1;
00136     icol1 = MIN(icol1, plsc->ncol1-1);
00137 
00138     plsc->icol1 = icol1;
00139     plsc->curcolor.r = plsc->cmap1[plsc->icol1].r;
00140     plsc->curcolor.g = plsc->cmap1[plsc->icol1].g;
00141     plsc->curcolor.b = plsc->cmap1[plsc->icol1].b;
00142 
00143     plsc->curcmap = 1;
00144     plP_state(PLSTATE_COLOR1);
00145 }
00146 
00147 /*--------------------------------------------------------------------------*\
00148  * plscolbg()
00149  *
00150  * Set the background color (cmap0[0]) by 8 bit RGB value
00151 \*--------------------------------------------------------------------------*/
00152 
00153 MZ_DLLEXPORT
00154 void
00155 c_plscolbg(PLINT r, PLINT g, PLINT b)
00156 {
00157     plscol0(0, r, g, b);
00158 }
00159 
00160 /*--------------------------------------------------------------------------*\
00161  * plgcolbg()
00162  *
00163  * Returns the background color (cmap0[0]) by 8 bit RGB value
00164 \*--------------------------------------------------------------------------*/
00165 
00166 void
00167 c_plgcolbg(PLINT *r, PLINT *g, PLINT *b)
00168 {
00169     plgcol0(0, r, g, b);
00170 }
00171 
00172 /*--------------------------------------------------------------------------*\
00173  * plscol0()
00174  *
00175  * Set a given color from color map 0 by 8 bit RGB value
00176  * Does not result in any additional cells to be allocated.
00177 \*--------------------------------------------------------------------------*/
00178 
00179 MZ_DLLEXPORT
00180 void
00181 c_plscol0(PLINT icol0, PLINT r, PLINT g, PLINT b)
00182 {
00183     if (plsc->cmap0 == NULL)
00184        plscmap0n(0);
00185 
00186     if (icol0 < 0 || icol0 >= plsc->ncol0) {
00187        char buffer[256];
00188        sprintf(buffer, "plscol0: Illegal color table value: %d", (int) icol0);
00189        plabort(buffer);
00190        return;
00191     }
00192     if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
00193        char buffer[256];
00194        sprintf(buffer, "plscol0: Invalid RGB color: %d, %d, %d",
00195               (int) r, (int) g, (int) b);
00196        plabort(buffer);
00197        return;
00198     }
00199 
00200     plsc->cmap0[icol0].r = r;
00201     plsc->cmap0[icol0].g = g;
00202     plsc->cmap0[icol0].b = b;
00203 
00204     if (plsc->level > 0)
00205        plP_state(PLSTATE_CMAP0);
00206 }
00207 
00208 /*--------------------------------------------------------------------------*\
00209  * plgcol0()
00210  *
00211  * Returns 8 bit RGB values for given color from color map 0
00212  * Values are negative if an invalid color id is given
00213 \*--------------------------------------------------------------------------*/
00214 
00215 void
00216 c_plgcol0(PLINT icol0, PLINT *r, PLINT *g, PLINT *b)
00217 {
00218     if (plsc->cmap0 == NULL)
00219        plscmap0n(0);
00220 
00221     *r = -1;
00222     *g = -1;
00223     *b = -1;
00224 
00225     if (icol0 < 0 || icol0 > plsc->ncol0) {
00226        char buffer[256];
00227        sprintf(buffer, "plgcol0: Invalid color index: %d", (int) icol0);
00228        plabort(buffer);
00229        return;
00230     }
00231 
00232     *r = plsc->cmap0[icol0].r;
00233     *g = plsc->cmap0[icol0].g;
00234     *b = plsc->cmap0[icol0].b;
00235 
00236     return;
00237 }
00238 
00239 /*--------------------------------------------------------------------------*\
00240  * plscmap0()
00241  *
00242  * Set color map 0 colors by 8 bit RGB values.  This sets the entire color
00243  * map -- only as many colors as specified will be allocated.
00244 \*--------------------------------------------------------------------------*/
00245 
00246 void
00247 c_plscmap0(PLINT *r, PLINT *g, PLINT *b, PLINT ncol0)
00248 {
00249     int i;
00250 
00251     plscmap0n(ncol0);
00252 
00253     for (i = 0; i < plsc->ncol0; i++) {
00254        if ((r[i] < 0 || r[i] > 255) ||
00255            (g[i] < 0 || g[i] > 255) ||
00256            (b[i] < 0 || b[i] > 255)) {
00257 
00258            char buffer[256];
00259            sprintf(buffer, "plscmap0: Invalid RGB color: %d, %d, %d",
00260                   (int) r[i], (int) g[i], (int) b[i]);
00261            plabort(buffer);
00262            return;
00263        }
00264 
00265        plsc->cmap0[i].r = r[i];
00266        plsc->cmap0[i].g = g[i];
00267        plsc->cmap0[i].b = b[i];
00268     }
00269 
00270     if (plsc->level > 0)
00271        plP_state(PLSTATE_CMAP0);
00272 }
00273 
00274 /*--------------------------------------------------------------------------*\
00275  * plscmap1()
00276  *
00277  * Set color map 1 colors by 8 bit RGB values
00278  * This also sets the number of colors.
00279 \*--------------------------------------------------------------------------*/
00280 
00281 void
00282 c_plscmap1(PLINT *r, PLINT *g, PLINT *b, PLINT ncol1)
00283 {
00284     int i;
00285 
00286     plscmap1n(ncol1);
00287 
00288     for (i = 0; i < plsc->ncol1; i++) {
00289        if ((r[i] < 0 || r[i] > 255) ||
00290            (g[i] < 0 || g[i] > 255) ||
00291            (b[i] < 0 || b[i] > 255)) {
00292 
00293            char buffer[256];
00294            sprintf(buffer, "plscmap1: Invalid RGB color: %d, %d, %d",
00295                   (int) r[i], (int) g[i], (int) b[i]);
00296            plabort(buffer);
00297            return;
00298        }
00299        plsc->cmap1[i].r = r[i];
00300        plsc->cmap1[i].g = g[i];
00301        plsc->cmap1[i].b = b[i];
00302     }
00303 
00304     if (plsc->level > 0)
00305        plP_state(PLSTATE_CMAP1);
00306 }
00307 
00308 /*--------------------------------------------------------------------------*\
00309  * plscmap1l()
00310  *
00311  * Set color map 1 colors using a piece-wise linear relationship between
00312  * position in the color map (from 0 to 1) and position in HLS or RGB color
00313  * space.  May be called at any time.
00314  *
00315  * The idea here is to specify a number of control points that specify the
00316  * mapping between HLS (or RGB or CMY) and palette 1 value.  Between these
00317  * points, linear interpolation is used.  By mapping position in the color
00318  * map to function value, this gives a smooth variation of color with
00319  * intensity.  Any number of control points may be specified, located at
00320  * arbitrary positions (intensities), although typically 2 - 4 are enough.
00321  * Another way of stating this is that we are traversing a given number of
00322  * lines through HLS (or RGB) space as we move through cmap 1 entries.  The
00323  * control points at the minimum and maximum intensity (0 and 1) must
00324  * always be specified.  By adding more control points you can get more
00325  * variation.  One good technique for plotting functions that vary about
00326  * some expected average is to use an additional 2 control points in the
00327  * center (intensity ~= 0.5) that are the same color as the background
00328  * (typically white for paper output, black for crt), and same hue as the
00329  * boundary control points.  This allows the highs and lows to be very
00330  * easily distinguished.
00331  *
00332  * Each control point must specify the position in cmap 1 as well as three
00333  * coordinates in HLS or RGB space.  The first point MUST correspond to
00334  * position = 0, and the last to position = 1.  
00335  *
00336  * The hue is interpolated around the "front" of the color wheel
00337  * (red<->green<->blue<->red) unless the "rev" flag is set, in which case
00338  * interpolation proceeds around the back (reverse) side.  Specifying
00339  * rev=NULL is equivalent to setting rev[]=0 for every control point.
00340  *
00341  * Bounds on RGB coordinates:
00342  *     R,G,B         [0, 1]        magnitude
00343  *
00344  * Bounds on HLS coordinates:
00345  *     hue           [0, 360]      degrees
00346  *     lightness     [0, 1]        magnitude
00347  *     saturation    [0, 1]        magnitude
00348  *
00349  * The inputs are:
00350  *     itype         0: HLS, 1: RGB
00351  *     npts          number of control points
00352  *     pos[]         position for each control point
00353  *     coord1[]      first coordinate for each control point
00354  *     coord2[]      second coordinate for each control point
00355  *     coord3[]      third coordinate for each control point 
00356  *     rev[]         reverse flag for each control point
00357 \*--------------------------------------------------------------------------*/
00358 
00359 MZ_DLLEXPORT
00360 void
00361 c_plscmap1l(PLINT itype, PLINT npts, PLFLT *pos,
00362            PLFLT *coord1, PLFLT *coord2, PLFLT *coord3, PLINT *rev)
00363 {
00364     int n;
00365     PLFLT h, l, s, r, g, b;
00366 
00367     if (npts < 2) {
00368        plabort("plscmap1l: Must specify at least two control points");
00369        return;
00370     }
00371 
00372     if ( (pos[0] != 0) || (pos[npts-1] != 1)) {
00373        plabort("plscmap1l: First, last control points must lie on boundary");
00374        return;
00375     }
00376 
00377     if ( npts > PL_MAX_CMAP1CP ) {
00378        plabort("plscmap1l: exceeded maximum number of control points");
00379        return;
00380     }
00381 
00382 /* Allocate if not done yet */
00383 
00384     if (plsc->cmap1 == NULL)
00385        plscmap1n(0);
00386 
00387 /* Save control points */
00388 
00389     plsc->ncp1 = npts;
00390 
00391     for (n = 0; n < npts; n++) {
00392 
00393        if (itype == 0) {
00394            h = coord1[n];
00395            l = coord2[n];
00396            s = coord3[n];
00397        }
00398        else {
00399            r = coord1[n];
00400            g = coord2[n];
00401            b = coord3[n];
00402            plRGB_HLS(r, g, b, &h, &l, &s);
00403        }
00404 
00405        plsc->cmap1cp[n].h = h;
00406        plsc->cmap1cp[n].l = l;
00407        plsc->cmap1cp[n].s = s;
00408        plsc->cmap1cp[n].p = pos[n];
00409 
00410        if (rev == NULL)
00411            plsc->cmap1cp[n].rev = 0;
00412        else
00413            plsc->cmap1cp[n].rev = rev[n];
00414     }
00415 
00416 /* Calculate and set color map */
00417 
00418     plcmap1_calc();
00419 }
00420 
00421 /*--------------------------------------------------------------------------*\
00422  * plcmap1_calc()
00423  *
00424  * Bin up cmap 1 space and assign colors to make inverse mapping easy.
00425  * Always do interpolation in HLS space.
00426 \*--------------------------------------------------------------------------*/
00427 
00428 void
00429 plcmap1_calc(void)
00430 {
00431     int i, n;
00432     PLFLT delta, dp, dh, dl, ds;
00433     PLFLT h, l, s, p, r, g, b;
00434 
00435 /* Loop over all control point pairs */
00436 
00437     for (n = 0; n < plsc->ncp1-1; n++) {
00438 
00439        if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n+1].p )
00440            continue;
00441 
00442     /* Differences in p, h, l, s between ctrl pts */
00443 
00444        dp = plsc->cmap1cp[n+1].p - plsc->cmap1cp[n].p;
00445        dh = plsc->cmap1cp[n+1].h - plsc->cmap1cp[n].h;
00446        dl = plsc->cmap1cp[n+1].l - plsc->cmap1cp[n].l;
00447        ds = plsc->cmap1cp[n+1].s - plsc->cmap1cp[n].s;
00448 
00449     /* Adjust dh if we are to go around "the back side" */
00450 
00451        if (plsc->cmap1cp[n].rev)
00452            dh = (dh > 0) ? dh-360 : dh+360;
00453 
00454     /* Loop over all color cells.  Only interested in cells located (in */
00455     /* cmap1 space)  between n_th and n+1_th control points */
00456 
00457        for (i = 0; i < plsc->ncol1; i++) {
00458            p = (double) i / (plsc->ncol1 - 1.0);
00459            if ( (p < plsc->cmap1cp[n].p) ||
00460                (p > plsc->cmap1cp[n+1].p) )
00461               continue;
00462 
00463        /* Interpolate based on position of color cell in cmap1 space */
00464 
00465            delta = (p - plsc->cmap1cp[n].p) / dp;
00466 
00467        /* Linearly interpolate to get color cell h, l, s values */
00468 
00469            h = plsc->cmap1cp[n].h + dh * delta;
00470            l = plsc->cmap1cp[n].l + dl * delta;
00471            s = plsc->cmap1cp[n].s + ds * delta;
00472 
00473            while (h >= 360.)
00474               h -= 360.;
00475 
00476            while (h < 0.)
00477               h += 360.;
00478 
00479            plHLS_RGB(h, l, s, &r, &g, &b);
00480 
00481            plsc->cmap1[i].r = MAX(0, MIN(255, (int) (256. * r)));
00482            plsc->cmap1[i].g = MAX(0, MIN(255, (int) (256. * g)));
00483            plsc->cmap1[i].b = MAX(0, MIN(255, (int) (256. * b)));
00484        }
00485     }
00486 
00487     if (plsc->level > 0)
00488        plP_state(PLSTATE_CMAP1);
00489 }
00490 
00491 /*--------------------------------------------------------------------------*\
00492  * plscmap0n()
00493  *
00494  * Set number of colors in cmap 0, (re-)allocate cmap 0, and fill with
00495  * default values for those colors not previously allocated (and less
00496  * than index 15, after that you just get grey).
00497  *
00498  * The driver is not guaranteed to support all of these.
00499 \*--------------------------------------------------------------------------*/
00500 
00501 void
00502 c_plscmap0n(PLINT ncol0)
00503 {
00504     int ncol, size, imin, imax;
00505 
00506 /* No change */
00507 
00508     if (ncol0 > 0 && plsc->ncol0 == ncol0)
00509        return;
00510 
00511 /* Handle all possible startup conditions */
00512 
00513     if (plsc->ncol0 <= 0 && ncol0 <= 0)
00514        ncol = 16;
00515     else if (ncol0 <= 0)
00516        ncol = plsc->ncol0;
00517     else
00518         ncol = ncol0;
00519 
00520     imax = ncol-1;
00521     size = ncol * sizeof(PLColor);
00522 
00523 /* Allocate the space */
00524 
00525     if (plsc->cmap0 == NULL) {
00526        plsc->cmap0 = (PLColor *) calloc(1, size);
00527        imin = 0;
00528     }
00529     else {
00530        plsc->cmap0 = (PLColor *) realloc(plsc->cmap0, size);
00531        imin = plsc->ncol0;
00532     }
00533 
00534 /* Fill in default entries */
00535 
00536     plsc->ncol0 = ncol;
00537     plcmap0_def(imin, imax);
00538 }
00539 
00540 /*--------------------------------------------------------------------------*\
00541  * plscmap1n()
00542  *
00543  * Set number of colors in cmap 1, (re-)allocate cmap 1, and set default
00544  * values if this is the first allocation.
00545  *
00546  * Note that the driver is allowed to disregard this number.
00547  * In particular, most use fewer than we use internally.
00548 \*--------------------------------------------------------------------------*/
00549 
00550 MZ_DLLEXPORT
00551 void
00552 c_plscmap1n(PLINT ncol1)
00553 {
00554     int ncol, size;
00555 
00556 /* No change */
00557 
00558     if (ncol1 > 0 && plsc->ncol1 == ncol1)
00559        return;
00560 
00561 /* Handle all possible startup conditions */
00562 
00563     if (plsc->ncol1 <= 0 && ncol1 <= 0)
00564        ncol = 128;
00565     else if (ncol1 <= 0)
00566        ncol = plsc->ncol1;
00567     else
00568         ncol = ncol1;
00569 
00570     size = ncol * sizeof(PLColor);
00571 
00572 /* Allocate the space */
00573 
00574     if (plsc->ncol1 > 0) 
00575        plsc->cmap1 = (PLColor *) realloc(plsc->cmap1, size);
00576     else 
00577        plsc->cmap1 = (PLColor *) calloc(ncol, sizeof(PLColor));
00578 
00579 /* Fill in default entries */
00580 
00581     plsc->ncol1 = ncol;
00582     if (plsc->ncp1 == 0)
00583        plcmap1_def();
00584     else
00585        plcmap1_calc();
00586 }
00587 
00588 /*--------------------------------------------------------------------------*\
00589  * color_set()
00590  *
00591  * Initializes color table entry by RGB values.
00592 \*--------------------------------------------------------------------------*/
00593 
00594 static void
00595 color_set(PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, char *name )
00596 {
00597     plsc->cmap0[i].r = r;
00598     plsc->cmap0[i].g = g;
00599     plsc->cmap0[i].b = b;
00600     plsc->cmap0[i].name = name;
00601 }
00602 
00603 /*--------------------------------------------------------------------------*\
00604  * plcmap0_def()
00605  *
00606  * Initializes specified color map 0 color entry to its default.
00607  *
00608  * Initial RGB values for color map 0 taken from X11R6 
00609  * (XFree86-3.3.6) X-windows 
00610  * rgb.txt file, and may not accurately represent the described colors on 
00611  * all systems.
00612 \*--------------------------------------------------------------------------*/
00613 
00614 #define color_def(i, r, g, b, n) \
00615 if (i >= imin && i <= imax) color_set(i, r, g, b, n);
00616 
00617 static void
00618 plcmap0_def(int imin, int imax)
00619 {
00620     int i;
00621 
00622     color_def(0,    0,   0,   0, "black" );      /* black */
00623     color_def(1,  255,   0,   0, "red");  /* red */
00624     color_def(2,  255, 255,   0, "yellow" );     /* yellow */
00625     color_def(3,    0, 255,   0, "green" );      /* green */
00626     color_def(4,  127, 255, 212, "aquamarine" ); /* aquamarine */
00627     color_def(5,  255, 192, 203, "pink" );       /* pink */
00628     color_def(6,  245, 222, 179, "wheat" );      /* wheat */
00629     color_def(7,  190, 190, 190, "grey" );       /* grey */
00630     color_def(8,  165,  42,  42, "brown" );      /* brown */
00631     color_def(9,    0,   0, 255, "blue" );       /* blue */
00632     color_def(10, 138,  43, 226, "BlueViolet" ); /* Blue Violet */
00633     color_def(11,   0, 255, 255, "cyan" );       /* cyan */
00634     color_def(12,  64, 224, 208, "turquoise" );  /* turquoise */
00635     color_def(13, 255,   0, 255, "magenta" );    /* magenta */
00636     color_def(14, 250, 128, 114, "salmon" );     /* salmon */
00637     color_def(15, 255, 255, 255, "white" );      /* white */
00638 
00639 /* Any others are just arbitrarily set */
00640 
00641     for (i = 16; i <= imax; i++)
00642        color_def(i, 255, 0, 0, "red");    /* red */
00643 }
00644 
00645 /*--------------------------------------------------------------------------*\
00646  * plcmap1_def()
00647  *
00648  * Initializes color map 1.
00649  *
00650  * The default initialization uses 6 control points in HLS space, the inner
00651  * ones being very close to one of the vertices of the HLS double cone.  The
00652  * vertex used (black or white) is chosen to be the closer to the background
00653  * color.  The 6 points were chosen over the older 4 points in order to make 
00654  * weaker structures more easily visible, and give more control through the
00655  * palette editor.  If you don't like these settings.. change them!
00656 \*--------------------------------------------------------------------------*/
00657 
00658 static void
00659 plcmap1_def(void)
00660 {
00661     PLFLT i[6], h[6], l[6], s[6], midpt = 0., vertex = 0.;
00662 
00663 /* Positions of control points */
00664 
00665     i[0] = 0;        /* left boundary */
00666     i[1] = 0.44;     /* a little left of center */
00667     i[2] = 0.50;     /* at center */
00668     i[3] = 0.50;     /* at center */
00669     i[4] = 0.56;     /* a little right of center */
00670     i[5] = 1;        /* right boundary */
00671 
00672 /* For center control points, pick black or white, whichever is closer to bg */
00673 /* Be carefult to pick just short of top or bottom else hue info is lost */
00674 
00675     if (plsc->cmap0 != NULL)
00676        vertex = ((PLFLT) plsc->cmap0[0].r +
00677                 (PLFLT) plsc->cmap0[0].g +
00678                 (PLFLT) plsc->cmap0[0].b) / 3. / 255.;
00679 
00680     if (vertex < 0.5) {
00681        vertex = 0.01;
00682        midpt  = 0.10;
00683     } else {
00684        vertex = 0.99;
00685        midpt  = 0.90;
00686     }
00687 
00688 /* Set hue */
00689 
00690     h[0] = 260;             /* low: blue-violet */
00691     h[1] = 260;             /* only change as we go over vertex */
00692     h[2] = 260;             /* only change as we go over vertex */
00693     h[3] = 0;        /* high: red */
00694     h[4] = 0;        /* high: red */
00695     h[5] = 0;        /* keep fixed */
00696 
00697 /* Set lightness */
00698 
00699     l[0] = 0.5;             /* low */
00700     l[1] = midpt;    /* midpoint value */
00701     l[2] = vertex;   /* bg */
00702     l[3] = vertex;   /* bg */
00703     l[4] = midpt;    /* midpoint value */
00704     l[5] = 0.5;             /* high */
00705 
00706 /* Set saturation -- keep at maximum */
00707 
00708     s[0] = 1;
00709     s[1] = 1;
00710     s[2] = 1;
00711     s[3] = 1;
00712     s[4] = 1;
00713     s[5] = 1;
00714 
00715     c_plscmap1l(0, 6, i, h, l, s, NULL);
00716 }
00717 
00718 /*--------------------------------------------------------------------------*\
00719  * plscolor()
00720  *
00721  * Used to globally turn color output on/off
00722 \*--------------------------------------------------------------------------*/
00723 
00724 void
00725 c_plscolor(PLINT color)
00726 {
00727     plsc->colorset = 1;
00728     plsc->color = color;
00729 }
00730 
00731 /*--------------------------------------------------------------------------*\
00732  * plrgb()
00733  *
00734  * Set line color by red, green, blue from  0. to 1.
00735  * Do NOT use this.  Only retained for backward compatibility
00736 \*--------------------------------------------------------------------------*/
00737 
00738 void
00739 c_plrgb(PLFLT r, PLFLT g, PLFLT b)
00740 {
00741     if (plsc->level < 1) {
00742        plabort("plrgb: Please call plinit first");
00743        return;
00744     }
00745 
00746     plsc->icol0 = PL_RGB_COLOR;
00747     plsc->curcolor.r = MAX(0, MIN(255, (int) (256. * r)));
00748     plsc->curcolor.g = MAX(0, MIN(255, (int) (256. * g)));
00749     plsc->curcolor.b = MAX(0, MIN(255, (int) (256. * b)));
00750 
00751     plsc->curcmap = 0;
00752     plP_state(PLSTATE_COLOR0);
00753 }
00754 
00755 /*--------------------------------------------------------------------------*\
00756  * plrgb1()
00757  *
00758  * Set line color by 8 bit RGB values.
00759  * Do NOT use this.  Only retained for backward compatibility
00760 \*--------------------------------------------------------------------------*/
00761 
00762 void
00763 c_plrgb1(PLINT r, PLINT g, PLINT b)
00764 {
00765     if (plsc->level < 1) {
00766        plabort("plrgb1: Please call plinit first");
00767        return;
00768     }
00769     if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
00770        plabort("plrgb1: Invalid color");
00771        return;
00772     }
00773 
00774     plsc->icol0 = PL_RGB_COLOR;
00775     plsc->curcolor.r = r;
00776     plsc->curcolor.g = g;
00777     plsc->curcolor.b = b;
00778 
00779     plsc->curcmap = 0;
00780     plP_state(PLSTATE_COLOR0);
00781 }
00782 
00783 /*--------------------------------------------------------------------------*\
00784  * void plhls()
00785  *
00786  * Set current color by hue, lightness, and saturation.
00787  * Convert hls color coordinates to rgb, then call plrgb.
00788  * Do NOT use this.  Only retained for backward compatibility
00789 \*--------------------------------------------------------------------------*/
00790 
00791 void
00792 c_plhls(PLFLT h, PLFLT l, PLFLT s)
00793 {
00794     PLFLT r, g, b;
00795 
00796     plHLS_RGB(h, l, s, &r, &g, &b);
00797     plrgb(r, g, b);
00798 }
00799 
00800 /*--------------------------------------------------------------------------*\
00801  * void value()
00802  *
00803  * Auxiliary function used by plHLS_RGB().
00804 \*--------------------------------------------------------------------------*/
00805 
00806 static PLFLT
00807 value(double n1, double n2, double hue)
00808 {
00809     PLFLT val;
00810 
00811     while (hue >= 360.)
00812        hue -= 360.;
00813     while (hue < 0.)
00814        hue += 360.;
00815 
00816     if (hue < 60.)
00817        val = n1 + (n2 - n1) * hue / 60.;
00818     else if (hue < 180.)
00819        val = n2;
00820     else if (hue < 240.)
00821        val = n1 + (n2 - n1) * (240. - hue) / 60.;
00822     else
00823        val = n1;
00824 
00825     return (val);
00826 }
00827 
00828 /*--------------------------------------------------------------------------*\
00829  * void plHLS_RGB()
00830  *
00831  * Convert HLS color to RGB color.
00832  * Bounds on HLS (input):
00833  *     hue           [0., 360.]    degrees
00834  *     lightness     [0., 1.]      magnitude
00835  *     saturation    [0., 1.]      magnitude
00836  *
00837  * Hue is always mapped onto the interval [0., 360.] regardless of input.
00838  * Bounds on RGB (output) is always [0., 1.].  Convert to RGB color values
00839  * by multiplying by 2**nbits (nbits typically 8).
00840 \*--------------------------------------------------------------------------*/
00841 
00842 void
00843 plHLS_RGB(PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b)
00844 {
00845     PLFLT m1, m2;
00846 
00847     if (l <= .5)
00848        m2 = l * (s + 1.);
00849     else
00850        m2 = l + s - l * s;
00851 
00852     m1 = 2 * l - m2;
00853 
00854     *p_r = value(m1, m2, h + 120.);
00855     *p_g = value(m1, m2, h);
00856     *p_b = value(m1, m2, h - 120.);
00857 }
00858 
00859 /*--------------------------------------------------------------------------*\
00860  * void plRGB_HLS()
00861  *
00862  * Convert RGB color to HLS color.
00863  * Bounds on RGB (input) is always [0., 1.].  
00864  * Bounds on HLS (output):
00865  *     hue           [0., 360.]    degrees
00866  *     lightness     [0., 1.]      magnitude
00867  *     saturation    [0., 1.]      magnitude
00868 \*--------------------------------------------------------------------------*/
00869 
00870 void
00871 plRGB_HLS(PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s)
00872 {
00873     PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
00874 
00875     rgb_min = MIN( r, MIN( g, b ));
00876     rgb_max = MAX( r, MAX( g, b ));
00877 
00878     l = (rgb_min+rgb_max) / 2.0;
00879 
00880     if (rgb_min == rgb_max) {
00881        s = 0;
00882        h = 0;
00883     } 
00884     else {
00885        d = rgb_max - rgb_min;
00886        if (l < 0.5)
00887            s = 0.5 * d / l;
00888        else 
00889            s = 0.5* d / (1.-l);
00890 
00891        rc = (rgb_max-r) / d;
00892        gc = (rgb_max-g) / d;
00893        bc = (rgb_max-b) / d;
00894 
00895        if (r == rgb_max)
00896            h = bc-gc;
00897        else if (g == rgb_max)
00898            h = rc-bc+2;
00899        else
00900            h = gc-rc-2;
00901 
00902        h = h*60;
00903        if (h <  0)
00904            h = h+360;
00905        else if (h >= 360)
00906            h = h-360;
00907     }
00908     *p_h = h;
00909     *p_l = l;
00910     *p_s = s;
00911 }
00912 
00913 /*--------------------------------------------------------------------------*\
00914  * A grab-bag of various control routines.
00915 \*--------------------------------------------------------------------------*/
00916 
00917 /*--------------------------------------------------------------------------*\
00918  * void plwarn()
00919  *
00920  * A handy way to issue warnings, if need be.
00921 \*--------------------------------------------------------------------------*/
00922 
00923 void
00924 plwarn(char *errormsg)
00925 {
00926     int was_gfx = 0;
00927 
00928     if (plsc->graphx == 1) {
00929        was_gfx = 1;
00930        pltext();
00931     }
00932 
00933     fprintf(stderr, "\n*** PLPLOT WARNING ***\n");
00934     if (*errormsg != '\0')
00935        fprintf(stderr, "%s\n", errormsg);
00936 
00937     if (was_gfx == 1)
00938        plgra();
00939 }
00940 
00941 /*--------------------------------------------------------------------------*\
00942  * void plabort()
00943  *
00944  * Much the same as plwarn(), but appends ", aborting operation" to the
00945  * error message.  Helps to keep source code uncluttered and provides a
00946  * convention for error aborts.
00947 \*--------------------------------------------------------------------------*/
00948 
00949 void
00950 plabort(char *errormsg)
00951 {
00952     if (plsc->errcode != NULL)
00953        *(plsc->errcode) = 1;
00954 
00955     if (plsc->errmsg != NULL) {
00956        sprintf(plsc->errmsg, "\n*** PLPLOT ERROR ***\n");
00957        if (*errormsg != '\0')
00958            sprintf(plsc->errmsg, "%s, aborting operation\n", errormsg);
00959 
00960     } else {
00961        int was_gfx = 0;
00962 
00963        if (plsc->graphx == 1) {
00964            was_gfx = 1;
00965            pltext();
00966        }
00967 
00968        fprintf(stderr, "\n*** PLPLOT ERROR ***\n");
00969        if (*errormsg != '\0')
00970            fprintf(stderr, "%s, aborting operation\n", errormsg);
00971 
00972        if (was_gfx == 1)
00973            plgra();
00974     }
00975 }
00976 
00977 /*--------------------------------------------------------------------------*\
00978  * void plexit()
00979  *
00980  * In case of an abort this routine is called.  It just prints out an error
00981  * message and tries to clean up as much as possible.  It's best to turn
00982  * off pause and then restore previous setting before returning.
00983  *
00984  * If cleanup needs to be done in the main program, the user should write
00985  * his/her own exit handler and pass it in via plsexit().  This function
00986  * should should either call plend() before exiting, or simply return.
00987 \*--------------------------------------------------------------------------*/
00988 
00989 void
00990 plexit(char *errormsg)
00991 {
00992     int status = 1;
00993 
00994     if (exit_handler != NULL)
00995        status = (*exit_handler)(errormsg);
00996 
00997     plsc->nopause = 1;
00998     if (*errormsg != '\0') {
00999        fprintf(stderr, "\n*** PLPLOT ERROR ***\n");
01000        fprintf(stderr, "%s\n", errormsg);
01001     }
01002     plend();
01003 
01004     fprintf(stderr, "Program aborted\n");
01005     exit(status);
01006 }
01007 
01008 /*--------------------------------------------------------------------------*\
01009  * void plsexit()
01010  *
01011  * Sets an optional user exit handler.
01012 \*--------------------------------------------------------------------------*/
01013 
01014 void
01015 plsexit(int (*handler) (char *))
01016 {
01017     exit_handler = handler;
01018 }
01019 
01020 /*--------------------------------------------------------------------------*\
01021  * void plgra()
01022  *
01023  * Switches to graphics screen.  
01024  *
01025  * Here and in pltext() it's a good idea to return silently if plinit()
01026  * hasn't yet been called, since plwarn() calls pltext() and plgra(), and
01027  * plwarn() may be called at any time.
01028 \*--------------------------------------------------------------------------*/
01029 
01030 void
01031 c_plgra(void)
01032 {
01033     if (plsc->level > 0)
01034        plP_esc(PLESC_GRAPH, NULL);
01035 }
01036 
01037 void
01038 c_plxormod(PLINT mode, PLINT *status)     /* xor mode */
01039 {
01040   static int ostate = 0;
01041 
01042   if (!plsc->dev_xor) {
01043     *status = 0;
01044     return;
01045   }
01046 
01047   if (plsc->level > 0) {
01048     plP_esc(PLESC_XORMOD, &mode);
01049     if (mode) {
01050       ostate = plsc->plbuf_write;
01051       plsc->plbuf_write = 0;
01052     } else
01053       plsc->plbuf_write = ostate;
01054   } 
01055   *status = 1;
01056 }
01057 
01058 /*--------------------------------------------------------------------------*\
01059  * void pltext()
01060  *
01061  * Switches to text screen.
01062 \*--------------------------------------------------------------------------*/
01063 
01064 void
01065 c_pltext(void)
01066 {
01067     if (plsc->level > 0)
01068        plP_esc(PLESC_TEXT, NULL);
01069 }
01070 
01071 /*--------------------------------------------------------------------------*\
01072  * void pl_cmd()
01073  *
01074  * Front-end to driver escape function.
01075  * In principle this can be used to pass just about anything directly
01076  * to the driver.
01077 \*--------------------------------------------------------------------------*/
01078 
01079 void
01080 pl_cmd(PLINT op, void *ptr)
01081 {
01082     plP_esc(op, ptr);
01083 }
01084 
01085 /*--------------------------------------------------------------------------*\
01086  * char *plFindCommand
01087  *
01088  * Looks for the specified executable file.  Search path:
01089  *     PLPLOT_BIN_ENV = $(PLPLOT_BIN)
01090  *     current directory
01091  *     PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
01092  *     BIN_DIR
01093  *
01094  * The caller must free the returned pointer (points to malloc'ed memory)
01095  * when finished with it.
01096 \*--------------------------------------------------------------------------*/
01097 
01098 char *
01099 plFindCommand(char *fn)
01100 {
01101     char *fs = NULL, *dn;
01102 
01103 /* PLPLOT_BIN_ENV = $(PLPLOT_BIN) */
01104 
01105 #if defined(PLPLOT_BIN_ENV)
01106     if ((dn = getenv(PLPLOT_BIN_ENV)) != NULL) {
01107         plGetName(dn, "", fn, &fs);
01108         if ( ! plFindName(fs))
01109             return fs;
01110         fprintf(stderr, PLPLOT_BIN_ENV"=\"%s\"\n", dn); /* what IS set? */
01111     }
01112 #endif  /* PLPLOT_BIN_ENV */
01113 
01114 /* Current directory */
01115 
01116     plGetName(".", "", fn, &fs);
01117     if ( ! plFindName(fs))
01118        return fs;
01119 
01120 /* PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin */
01121 
01122 #if defined(PLPLOT_HOME_ENV)
01123     if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
01124         plGetName(dn, "bin", fn, &fs);
01125         if ( ! plFindName(fs))
01126             return fs;
01127         fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
01128     }
01129 #endif  /* PLPLOT_HOME_ENV */
01130 
01131 /* BIN_DIR */
01132 
01133 #if defined (BIN_DIR)
01134     plGetName(BIN_DIR, "", fn, &fs);
01135     if ( ! plFindName(fs))
01136        return fs;
01137 #endif
01138 
01139 /* Crapped out */
01140 
01141     free_mem(fs);
01142     fprintf(stderr, "plFindCommand: cannot locate command: %s\n", fn);
01143 #if defined (BIN_DIR)
01144     fprintf(stderr, "bin dir=\"" BIN_DIR "\"\n" );      /* what WAS set? */
01145 #endif  /* BIN_DIR */
01146     return NULL;
01147 }
01148 
01149 /*--------------------------------------------------------------------------*\
01150  * FILE *plLibOpen(fn)
01151  *
01152  * Return file pointer to lib file.
01153  * Locations checked:
01154  *     PLPLOT_LIB_ENV = $(PLPLOT_LIB)
01155  *     current directory
01156  *     PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib
01157  *     DATA_DIR
01158  *     PLLIBDEV
01159 \*--------------------------------------------------------------------------*/
01160 
01161 FILE *
01162 plLibOpen(char *fn)
01163 {
01164     FILE *ret = NULL;
01165     
01166     PDFstrm *pdfs = plLibOpenPdfstrm(fn);
01167     if (pdfs == NULL) {
01168         return NULL;
01169     }
01170     if (pdfs->file != NULL) {
01171         ret = pdfs->file;
01172        pdfs->file = NULL;
01173     }
01174     pdf_close(pdfs);
01175     return ret;
01176 }
01177 
01178 PDFstrm *
01179 plLibOpenPdfstrm(char *fn)
01180 {
01181     PDFstrm *file;
01182     char *fs = NULL, *dn = NULL;
01183 
01184 /****  search PLPLOT_LIB_ENV = $(PLPLOT_LIB)     ****/
01185 
01186 #if defined(PLPLOT_LIB_ENV)
01187     if ((dn = getenv(PLPLOT_LIB_ENV)) != NULL) {
01188         plGetName(dn, "", fn, &fs);
01189 
01190         if ((file = pdf_fopen(fs, "rb")) != NULL)
01191             goto done;
01192 
01193         fprintf(stderr, PLPLOT_LIB_ENV"=\"%s\"\n", dn); /* what IS set? */
01194     }
01195 #endif  /* PLPLOT_LIB_ENV */
01196 
01197 /****  search current directory    ****/
01198 
01199     if ((file = pdf_fopen(fn, "rb")) != NULL)
01200         goto done;
01201 
01202 /****  search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib  ****/
01203 
01204 #if defined (PLPLOT_HOME_ENV)
01205     if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
01206         plGetName(dn, "lib", fn, &fs);
01207 
01208         if ((file = pdf_fopen(fs, "rb")) != NULL)
01209             goto done;
01210         fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
01211     }
01212 #endif  /* PLPLOT_HOME_ENV/lib */
01213 
01214 /****  search installed location   ****/
01215 
01216 #if defined (DATA_DIR)
01217     plGetName(DATA_DIR, "", fn, &fs);
01218 
01219     if ((file = pdf_fopen(fs, "rb")) != NULL)
01220         goto done;
01221 #endif  /* DATA_DIR */
01222 
01223 /****  search hardwired location   ****/
01224 
01225 #ifdef PLLIBDEV
01226     plGetName(PLLIBDEV, "", fn, &fs);
01227 
01228     if ((file = pdf_fopen(fs, "rb")) != NULL)
01229        goto done;
01230 #endif /* PLLIBDEV */
01231 
01232 #ifdef macintosh
01233     file = plMacLibOpen(fn);
01234     if (file != NULL)
01235         goto done;
01236 #endif /* macintosh */
01237 
01238     if (plplotLibDir != NULL) {
01239        plGetName(plplotLibDir, "", fn, &fs);
01240        if ((file = pdf_fopen(fs, "rb")) != NULL)
01241            goto done;
01242 
01243     }
01244     
01245 /****  not found, give up   ****/
01246 
01247     return NULL;
01248 
01249  done:
01250     free_mem(fs);
01251     return (file);
01252 }
01253 
01254 /*--------------------------------------------------------------------------*\
01255  * int plFindName
01256  *
01257  * Authors: Paul Dubois (LLNL), others?
01258  * This function is in the public domain.
01259  *
01260  * Given a pathname, determine if it is a symbolic link.  If so, continue
01261  * searching to the ultimate terminus - there may be more than one link.
01262  * Use the error value to determine when the terminus is reached, and to
01263  * determine if the pathname really exists.  Then stat it to determine
01264  * whether it's executable.  Return 0 for an executable, errno otherwise.
01265  * Note that 'p' _must_ have at least one '/' character - it does by
01266  * construction in this program.  The contents of the array pointed to by
01267  * 'p' are changed to the actual pathname if findname is successful.
01268  *
01269  * This function is only defined under Unix for now.
01270 \*--------------------------------------------------------------------------*/
01271 
01272 #ifdef do_not_do // changed, this is unnessisary in this build anyway
01273 int 
01274 plFindName(char *p)
01275 {
01276     int n;
01277     char buf[1024], *cp;
01278     extern int errno;
01279     struct stat sbuf;
01280 
01281     pldebug("plFindName", "Trying to find %s\n", p);
01282     while ((n = readlink(p, buf, 1024)) > 0) {
01283        pldebug("plFindName", "Readlink read %d chars at: %s\n", n, p);
01284        if (buf[0] == '/') {
01285        /* Link is an absolute path */
01286 
01287            strncpy(p, buf, n);
01288            p[n] = '\0';
01289            pldebug("plFindName", "Link is absolute: %s\n", p);
01290        }
01291        else {
01292        /* Link is relative to its directory; make it absolute */
01293 
01294            cp = 1 + strrchr(p, '/');
01295            strncpy(cp, buf, n);
01296            cp[n] = '\0';
01297            pldebug("plFindName",
01298                   "Link is relative: %s\n\tTotal path:%s\n", cp, p);
01299        }
01300     }
01301 
01302 /* This macro not defined on the NEC SX-3 */
01303 
01304 #ifdef SX
01305 #define S_ISREG(mode)   (mode & S_IFREG)
01306 #endif
01307 
01308 /* SGI machines return ENXIO instead of EINVAL Dubois 11/92 */
01309 
01310     if (errno == EINVAL || errno == ENXIO) {
01311        pldebug("plFindName", "%s may be the one...\n", p);
01312        if ((stat(p, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) {
01313            pldebug("plFindName", "%s is a regular file\n", p);
01314            return (access(p, X_OK));
01315        }
01316     }
01317     pldebug("plFindName", "%s found but is not executable\n", p);
01318     return (errno ? errno : -1);
01319 }
01320 
01321 #else
01322 int 
01323 plFindName(char *p)
01324 {
01325     return 1;
01326 }
01327 #endif
01328 
01329 /*--------------------------------------------------------------------------*\
01330  * void plGetName()
01331  *
01332  * Gets search name for file by concatenating the dir, subdir, and file
01333  * name, allocating memory as needed.  The appropriate delimiter is added
01334  * after the dir specification as necessary.  The caller is responsible
01335  * for freeing the malloc'ed memory.
01336 \*--------------------------------------------------------------------------*/
01337 
01338 void
01339 plGetName(char *dir, char *subdir, char *filename, char **filespec)
01340 {
01341     int lfilespec;
01342 
01343 /* Malloc space for filespec */
01344 
01345     free_mem(*filespec);
01346     lfilespec = 10;
01347     lfilespec = strlen(dir) + strlen(subdir) + strlen(filename) + 10;
01348     *filespec = (char *) malloc(lfilespec);
01349 
01350     strcpy(*filespec, dir);
01351 
01352     if (*subdir != '\0') {
01353        strcat_delim(*filespec);
01354        strcat(*filespec, subdir);
01355     }
01356     if (*filename != '\0') {
01357        strcat_delim(*filespec);
01358        strcat(*filespec, filename);
01359     }
01360 }
01361 
01362 /*--------------------------------------------------------------------------*\
01363  * void strcat_delim()
01364  *
01365  * Append path name deliminator if necessary (does not add one if one's
01366  * there already, or if dealing with a colon-terminated device name).
01367 \*--------------------------------------------------------------------------*/
01368 
01369 static void
01370 strcat_delim(char *dirspec)
01371 {
01372     int ldirspec = strlen(dirspec);
01373 #if defined (MSDOS)
01374     if (dirspec[ldirspec-1] != '\\')
01375        strcat(dirspec, "\\");
01376 #elif defined (macintosh)
01377     if (dirspec[ldirspec-1] != ':')
01378         strcat(dirspec, ":");
01379 #else           /* unix is the default */
01380     if (dirspec[ldirspec-1] != '/')
01381        strcat(dirspec, "/");
01382 #endif
01383 }
01384 
01385 /*--------------------------------------------------------------------------*\
01386  * plcol_interp()
01387  *
01388  * Initializes device cmap 1 entry by interpolation from pls->cmap1
01389  * entries.  Returned PLColor is supposed to represent the i_th color
01390  * out of a total of ncol colors in the current color scheme.
01391 \*--------------------------------------------------------------------------*/
01392 
01393 void
01394 plcol_interp(PLStream *pls, PLColor *newcolor, int i, int ncol)
01395 {
01396     PLFLT x, delta;
01397     int il, ir;
01398 
01399     x = (double) (i * (pls->ncol1-1)) / (double) (ncol-1);
01400     il = x;
01401     ir = il + 1;
01402     delta = x - il;
01403 
01404     if (ir > pls->ncol1 || il < 0)
01405        fprintf(stderr, "Invalid color\n");
01406 
01407     else if (ir == pls->ncol1 || (delta == 0.)) {
01408        newcolor->r = pls->cmap1[il].r;
01409        newcolor->g = pls->cmap1[il].g;
01410        newcolor->b = pls->cmap1[il].b;
01411     }
01412     else {
01413        newcolor->r = (1.-delta) * pls->cmap1[il].r + delta * pls->cmap1[ir].r;
01414        newcolor->g = (1.-delta) * pls->cmap1[il].g + delta * pls->cmap1[ir].g;
01415        newcolor->b = (1.-delta) * pls->cmap1[il].b + delta * pls->cmap1[ir].b;
01416     }
01417 }
01418 
01419 /*--------------------------------------------------------------------------*\
01420  * plOpenFile()
01421  *
01422  * Opens file for output, prompting if not set.
01423  * Prints extra newline at end to make output look better in batch runs.
01424  * A file name of "-" indicates output to stdout.
01425 \*--------------------------------------------------------------------------*/
01426 
01427 #define MAX_NUM_TRIES       10
01428 void
01429 plOpenFile(PLStream *pls)
01430 {
01431     int i = 0, count = 0;
01432     size_t len;
01433     char line[256];
01434 
01435     while (pls->OutFile == NULL) {
01436 
01437 /* Setting pls->FileName = NULL forces creation of a new family member */
01438 /* You should also free the memory associated with it if you do this */
01439 
01440        if (pls->family && pls->BaseName != NULL)
01441            plP_getmember(pls);
01442 
01443 /* Prompt if filename still not known */
01444 
01445        if (pls->FileName == NULL) {
01446            do {
01447               fprintf(stdout, "Enter graphics output file name: ");
01448               fgets(line, sizeof(line), stdin);
01449               len = strlen(line);
01450               if (len)
01451                   len--;
01452               line[len] = '\0';    /* strip new-line */
01453               count++;             /* count zero entries */
01454            } while (!len && count < MAX_NUM_TRIES);
01455            plP_sfnam(pls, line);
01456        }
01457 
01458 /* If name is "-", send to stdout */
01459 
01460        if ( ! strcmp(pls->FileName, "-")) {
01461            pls->OutFile = stdout;
01462            pls->output_type = 1;
01463            break;
01464        }
01465 
01466 /* Need this here again, for prompted family initialization */
01467 
01468        if (pls->family && pls->BaseName != NULL) 
01469            plP_getmember(pls);
01470 
01471        if (i++ > 10)
01472            plexit("Too many tries.");
01473 
01474        if ((pls->OutFile = fopen(pls->FileName, "wb+")) == NULL) 
01475            fprintf(stdout, "Can't open %s.\n", pls->FileName);
01476        else
01477          {
01478 //         fprintf(stderr, "Opened %s\n", pls->FileName);
01479 //         this is not needed
01480          }
01481     }
01482 }
01483 
01484 /*--------------------------------------------------------------------------*\
01485  * plP_getmember()
01486  *
01487  * Sets up next file member name (in pls->FileName), but does not open it.
01488 \*--------------------------------------------------------------------------*/
01489 
01490 void
01491 plP_getmember(PLStream *pls)
01492 {
01493     char tmp[256];
01494 
01495     if (pls->FileName == NULL)
01496        pls->FileName = (char *) malloc(10 + strlen(pls->BaseName));
01497 
01498     sprintf(tmp, "%s.%%0%1ii", pls->BaseName, (int) pls->fflen);
01499     sprintf(pls->FileName, tmp, pls->member);
01500 }
01501 
01502 /*--------------------------------------------------------------------------*\
01503  * plP_sfnam()
01504  *
01505  * Sets up file name & family stem name.
01506  * Reserve some extra space (5 chars) to hold an optional member number.
01507 \*--------------------------------------------------------------------------*/
01508 
01509 void
01510 plP_sfnam(PLStream *pls, const char *fnam)
01511 {
01512     pls->OutFile = NULL;
01513 
01514     if (pls->FileName != NULL)
01515        free((void *) pls->FileName);
01516 
01517     pls->FileName = (char *) malloc(10 + strlen(fnam));
01518 
01519     strcpy(pls->FileName, fnam);
01520 
01521     if (pls->BaseName != NULL)
01522        free((void *) pls->BaseName);
01523 
01524     pls->BaseName = (char *) malloc(10 + strlen(fnam));
01525 
01526     strcpy(pls->BaseName, fnam);
01527 }
01528 
01529 /*--------------------------------------------------------------------------*\
01530  * plFamInit()
01531  *
01532  * Initializes family file parameters.
01533 \*--------------------------------------------------------------------------*/
01534 
01535 void
01536 plFamInit(PLStream *pls)
01537 {
01538     if (pls->family) {
01539        pls->bytecnt = 0;
01540        if ( ! pls->member)
01541            pls->member = 1;
01542        if ( ! pls->finc)
01543            pls->finc = 1;
01544        if ( ! pls->fflen)
01545            pls->fflen = 1;
01546        if ( ! pls->bytemax)
01547            pls->bytemax = PL_FILESIZE_KB * 1000;
01548     }
01549 }
01550 
01551 /*--------------------------------------------------------------------------*\
01552  * plGetFam()
01553  *
01554  * Starts new member file of family file set if necessary.
01555  *
01556  * Note each member file is a complete graphics file (can be printed
01557  * individually), although 'plrender' will treat a family as a single
01558  * logical file if given the family name instead of the member name.
01559 \*--------------------------------------------------------------------------*/
01560 
01561 void
01562 plGetFam(PLStream *pls)
01563 {
01564     PLFLT xpmm_loc, ypmm_loc;
01565     if (pls->family) {
01566        if (pls->bytecnt > pls->bytemax || pls->famadv) {
01567            plP_tidy();
01568            pls->member += pls->finc;
01569            pls->famadv = 0;
01570            plP_init();
01571           /* Apply compensating factor to original xpmm and ypmm so that 
01572            * character aspect ratio is preserved when overall aspect ratio
01573            * is changed. */
01574            plP_gpixmm(&xpmm_loc, &ypmm_loc);
01575            plP_setpxl(xpmm_loc*plsc->caspfactor, ypmm_loc/plsc->caspfactor); 
01576            return;
01577        }
01578     }
01579 }
01580 
01581 /*--------------------------------------------------------------------------*\
01582  * plRotPhy()
01583  *
01584  * Rotates physical coordinates if necessary for given orientation.
01585  * Each time orient is incremented, the plot is rotated 90 deg clockwise.
01586  * Note: this is now used only to rotate by 90 degrees for devices that
01587  * expect portrait mode.
01588 \*--------------------------------------------------------------------------*/
01589 
01590 void
01591 plRotPhy(PLINT orient, PLINT xmin, PLINT ymin, PLINT xmax, PLINT ymax,
01592         int *px, int *py)
01593 {
01594     int x, y;
01595 
01596     x = *px;
01597     y = *py;
01598 
01599     switch (orient%4) {
01600 
01601     case 1:
01602        *px = xmin + (y - ymin);
01603        *py = ymin + (xmax - x);
01604        break;
01605 
01606     case 2:
01607        *px = xmin + (xmax - x);
01608        *py = ymin + (ymax - y);
01609        break;
01610 
01611     case 3:
01612        *px = xmin + (ymax - y);
01613        *py = ymin + (x - xmin);
01614        break;
01615 
01616     default:
01617        break;               /* do nothing */
01618     }
01619 }
01620 
01621 /*--------------------------------------------------------------------------*\
01622  * plAllocDev()
01623  *
01624  * Allocates a standard PLDev structure for device-specific data, stores
01625  * the address in pls->dev, and returns the address as well.
01626 \*--------------------------------------------------------------------------*/
01627 
01628 PLDev *
01629 plAllocDev(PLStream *pls)
01630 {
01631     if (pls->dev != NULL)
01632        free((void *) pls->dev);
01633 
01634     pls->dev = calloc(1, (size_t) sizeof(PLDev));
01635     if (pls->dev == NULL)
01636        plexit("plAllocDev: cannot allocate memory\n");
01637 
01638     return (PLDev *) pls->dev;
01639 }
01640 
01641 /*--------------------------------------------------------------------------*\
01642  * plGinInit()
01643  *
01644  * Just fills in the PLGraphicsIn with appropriate initial values.
01645 \*--------------------------------------------------------------------------*/
01646 
01647 void
01648 plGinInit(PLGraphicsIn *gin)
01649 {
01650     gin->type = 0;
01651     gin->state = 0;
01652     gin->keysym = 0;
01653     gin->button = 0;
01654     gin->string[0] = '\0';
01655     gin->pX = gin->pY = -1;
01656     gin->dX = gin->dY = 0.;
01657     gin->wX = gin->wY = 0.;
01658 }
01659 
01660 /*--------------------------------------------------------------------------*\
01661  * plGetInt()
01662  *
01663  * Prompts human to input an integer in response to given message.
01664 \*--------------------------------------------------------------------------*/
01665 
01666 PLINT
01667 plGetInt(char *s)
01668 {
01669     int m;
01670     int i = 0;
01671     char line[256];
01672 
01673     while (i++ < 10) {
01674        fprintf(stdout, s);
01675        fgets(line, sizeof(line), stdin);
01676 #ifdef MSDOS
01677        m = atoi(line);
01678        return (m);
01679 #else
01680        if (sscanf(line, "%d", &m) == 1)
01681            return (m);
01682        fprintf(stdout, "No value or value out of range; please try again\n");
01683 #endif
01684     }
01685     plexit("Too many tries.");
01686     return (0);
01687 }
01688 
01689 /*--------------------------------------------------------------------------*\
01690  * plGetFlt()
01691  *
01692  * Prompts human to input a float in response to given message.
01693 \*--------------------------------------------------------------------------*/
01694 
01695 PLFLT
01696 plGetFlt(char *s)
01697 {
01698     PLFLT m;
01699     double m1;
01700     int i = 0;
01701     char line[256];
01702 
01703     while (i++ < 10) {
01704        fprintf(stdout, s);
01705        fgets(line, sizeof(line), stdin);
01706 #ifdef MSDOS
01707        m = atof(line);
01708        return (m);
01709 #else
01710        if (sscanf(line, "%lf", &m1) == 1) {
01711            m = (PLFLT) m1;
01712            return (m);
01713        }
01714        fprintf(stdout, "No value or value out of range; please try again\n");
01715 #endif
01716     }
01717     plexit("Too many tries.");
01718     return (0.);
01719 }
01720 
01721 /*--------------------------------------------------------------------------*\
01722  * plstrdup()
01723  *
01724  * A replacement for strdup(), which isn't portable.
01725  * Caller responsible for freeing the allocated memory.
01726 \*--------------------------------------------------------------------------*/
01727 
01728 char *
01729 plstrdup(const char *src)
01730 {
01731     char *dest = (char *) malloc( (strlen(src) + 1) * sizeof(char) );
01732     if (dest != NULL)
01733        strcpy(dest, src);
01734     else
01735        plabort("Out of memory");
01736 
01737     return dest;
01738 }
01739