1740 lines
44 KiB
C
1740 lines
44 KiB
C
/* $Id: plctrl.c,v 1.3 2005/03/18 20:32:41 eli Exp $
|
|
|
|
Misc. control routines, like begin, end, exit, change graphics/text
|
|
mode, change color. Includes some spillage from plcore.c. If you
|
|
don't know where it should go, put it here.
|
|
*/
|
|
|
|
#define DEBUG
|
|
|
|
#define NEED_PLDEBUG
|
|
#include "plplotP.h"
|
|
#ifdef macintosh
|
|
#include "mac.h"
|
|
/* for plMacLibOpen prototype; used in plLibOpen */
|
|
#endif
|
|
|
|
#ifdef DJGPP /* dos386/djgpp */
|
|
#ifdef __unix
|
|
#undef __unix
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __unix
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
/* Static functions */
|
|
|
|
/* Used by any external init code to suggest a path */
|
|
MZ_DLLEXPORT
|
|
char* plplotLibDir = 0;
|
|
|
|
static void
|
|
color_set(PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, char *name );
|
|
|
|
static void
|
|
strcat_delim(char *dirspec);
|
|
|
|
static int
|
|
(*exit_handler) (char *errormsg);
|
|
|
|
static void
|
|
plcmap0_def(int imin, int imax);
|
|
|
|
static void
|
|
plcmap1_def(void);
|
|
|
|
static PLFLT
|
|
value(double n1, double n2, double hue);
|
|
|
|
/* An additional hardwired location for lib files. */
|
|
/* I have no plans to change these again, ever. */
|
|
|
|
#if defined(DJGPP)
|
|
#ifndef PLLIBDEV
|
|
#define PLLIBDEV "c:/plplot/lib"
|
|
#endif
|
|
|
|
#elif defined(MSDOS)
|
|
#ifndef PLLIBDEV
|
|
#define PLLIBDEV "c:\\plplot\\lib"
|
|
#endif
|
|
|
|
#else
|
|
|
|
/* Anything else is assumed to be Unix */
|
|
|
|
#ifndef PLLIBDEV
|
|
#define PLLIBDEV "/usr/local/plplot/lib"
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* Routines that deal with colors & color maps.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plcol0()
|
|
*
|
|
* Set color, map 0. Argument is integer between 0 and plsc->ncol0.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
MZ_DLLEXPORT
|
|
void
|
|
c_plcol0(PLINT icol0)
|
|
{
|
|
if (plsc->level < 1) {
|
|
plabort("plcol0: Please call plinit first");
|
|
return;
|
|
}
|
|
if (icol0 < 0 || icol0 >= plsc->ncol0) {
|
|
char buffer[256];
|
|
sprintf(buffer, "plcol0: Invalid color map entry: %d", (int) icol0);
|
|
plabort(buffer);
|
|
return;
|
|
}
|
|
|
|
plsc->icol0 = icol0;
|
|
plsc->curcolor.r = plsc->cmap0[icol0].r;
|
|
plsc->curcolor.g = plsc->cmap0[icol0].g;
|
|
plsc->curcolor.b = plsc->cmap0[icol0].b;
|
|
|
|
plsc->curcmap = 0;
|
|
plP_state(PLSTATE_COLOR0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plcol1()
|
|
*
|
|
* Set color, map 1. Argument is a float between 0. and 1.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plcol1(PLFLT col1)
|
|
{
|
|
PLINT icol1;
|
|
|
|
if (plsc->level < 1) {
|
|
plabort("plcol1: Please call plinit first");
|
|
return;
|
|
}
|
|
if (col1 < 0 || col1 > 1) {
|
|
char buffer[256];
|
|
sprintf(buffer, "plcol1: Invalid color map position: %f", (PLFLT) col1);
|
|
plabort(buffer);
|
|
return;
|
|
}
|
|
|
|
icol1 = col1 * plsc->ncol1;
|
|
icol1 = MIN(icol1, plsc->ncol1-1);
|
|
|
|
plsc->icol1 = icol1;
|
|
plsc->curcolor.r = plsc->cmap1[plsc->icol1].r;
|
|
plsc->curcolor.g = plsc->cmap1[plsc->icol1].g;
|
|
plsc->curcolor.b = plsc->cmap1[plsc->icol1].b;
|
|
|
|
plsc->curcmap = 1;
|
|
plP_state(PLSTATE_COLOR1);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscolbg()
|
|
*
|
|
* Set the background color (cmap0[0]) by 8 bit RGB value
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
MZ_DLLEXPORT
|
|
void
|
|
c_plscolbg(PLINT r, PLINT g, PLINT b)
|
|
{
|
|
plscol0(0, r, g, b);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plgcolbg()
|
|
*
|
|
* Returns the background color (cmap0[0]) by 8 bit RGB value
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plgcolbg(PLINT *r, PLINT *g, PLINT *b)
|
|
{
|
|
plgcol0(0, r, g, b);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscol0()
|
|
*
|
|
* Set a given color from color map 0 by 8 bit RGB value
|
|
* Does not result in any additional cells to be allocated.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
MZ_DLLEXPORT
|
|
void
|
|
c_plscol0(PLINT icol0, PLINT r, PLINT g, PLINT b)
|
|
{
|
|
if (plsc->cmap0 == NULL)
|
|
plscmap0n(0);
|
|
|
|
if (icol0 < 0 || icol0 >= plsc->ncol0) {
|
|
char buffer[256];
|
|
sprintf(buffer, "plscol0: Illegal color table value: %d", (int) icol0);
|
|
plabort(buffer);
|
|
return;
|
|
}
|
|
if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
|
|
char buffer[256];
|
|
sprintf(buffer, "plscol0: Invalid RGB color: %d, %d, %d",
|
|
(int) r, (int) g, (int) b);
|
|
plabort(buffer);
|
|
return;
|
|
}
|
|
|
|
plsc->cmap0[icol0].r = r;
|
|
plsc->cmap0[icol0].g = g;
|
|
plsc->cmap0[icol0].b = b;
|
|
|
|
if (plsc->level > 0)
|
|
plP_state(PLSTATE_CMAP0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plgcol0()
|
|
*
|
|
* Returns 8 bit RGB values for given color from color map 0
|
|
* Values are negative if an invalid color id is given
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plgcol0(PLINT icol0, PLINT *r, PLINT *g, PLINT *b)
|
|
{
|
|
if (plsc->cmap0 == NULL)
|
|
plscmap0n(0);
|
|
|
|
*r = -1;
|
|
*g = -1;
|
|
*b = -1;
|
|
|
|
if (icol0 < 0 || icol0 > plsc->ncol0) {
|
|
char buffer[256];
|
|
sprintf(buffer, "plgcol0: Invalid color index: %d", (int) icol0);
|
|
plabort(buffer);
|
|
return;
|
|
}
|
|
|
|
*r = plsc->cmap0[icol0].r;
|
|
*g = plsc->cmap0[icol0].g;
|
|
*b = plsc->cmap0[icol0].b;
|
|
|
|
return;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscmap0()
|
|
*
|
|
* Set color map 0 colors by 8 bit RGB values. This sets the entire color
|
|
* map -- only as many colors as specified will be allocated.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plscmap0(PLINT *r, PLINT *g, PLINT *b, PLINT ncol0)
|
|
{
|
|
int i;
|
|
|
|
plscmap0n(ncol0);
|
|
|
|
for (i = 0; i < plsc->ncol0; i++) {
|
|
if ((r[i] < 0 || r[i] > 255) ||
|
|
(g[i] < 0 || g[i] > 255) ||
|
|
(b[i] < 0 || b[i] > 255)) {
|
|
|
|
char buffer[256];
|
|
sprintf(buffer, "plscmap0: Invalid RGB color: %d, %d, %d",
|
|
(int) r[i], (int) g[i], (int) b[i]);
|
|
plabort(buffer);
|
|
return;
|
|
}
|
|
|
|
plsc->cmap0[i].r = r[i];
|
|
plsc->cmap0[i].g = g[i];
|
|
plsc->cmap0[i].b = b[i];
|
|
}
|
|
|
|
if (plsc->level > 0)
|
|
plP_state(PLSTATE_CMAP0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscmap1()
|
|
*
|
|
* Set color map 1 colors by 8 bit RGB values
|
|
* This also sets the number of colors.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plscmap1(PLINT *r, PLINT *g, PLINT *b, PLINT ncol1)
|
|
{
|
|
int i;
|
|
|
|
plscmap1n(ncol1);
|
|
|
|
for (i = 0; i < plsc->ncol1; i++) {
|
|
if ((r[i] < 0 || r[i] > 255) ||
|
|
(g[i] < 0 || g[i] > 255) ||
|
|
(b[i] < 0 || b[i] > 255)) {
|
|
|
|
char buffer[256];
|
|
sprintf(buffer, "plscmap1: Invalid RGB color: %d, %d, %d",
|
|
(int) r[i], (int) g[i], (int) b[i]);
|
|
plabort(buffer);
|
|
return;
|
|
}
|
|
plsc->cmap1[i].r = r[i];
|
|
plsc->cmap1[i].g = g[i];
|
|
plsc->cmap1[i].b = b[i];
|
|
}
|
|
|
|
if (plsc->level > 0)
|
|
plP_state(PLSTATE_CMAP1);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscmap1l()
|
|
*
|
|
* Set color map 1 colors using a piece-wise linear relationship between
|
|
* position in the color map (from 0 to 1) and position in HLS or RGB color
|
|
* space. May be called at any time.
|
|
*
|
|
* The idea here is to specify a number of control points that specify the
|
|
* mapping between HLS (or RGB or CMY) and palette 1 value. Between these
|
|
* points, linear interpolation is used. By mapping position in the color
|
|
* map to function value, this gives a smooth variation of color with
|
|
* intensity. Any number of control points may be specified, located at
|
|
* arbitrary positions (intensities), although typically 2 - 4 are enough.
|
|
* Another way of stating this is that we are traversing a given number of
|
|
* lines through HLS (or RGB) space as we move through cmap 1 entries. The
|
|
* control points at the minimum and maximum intensity (0 and 1) must
|
|
* always be specified. By adding more control points you can get more
|
|
* variation. One good technique for plotting functions that vary about
|
|
* some expected average is to use an additional 2 control points in the
|
|
* center (intensity ~= 0.5) that are the same color as the background
|
|
* (typically white for paper output, black for crt), and same hue as the
|
|
* boundary control points. This allows the highs and lows to be very
|
|
* easily distinguished.
|
|
*
|
|
* Each control point must specify the position in cmap 1 as well as three
|
|
* coordinates in HLS or RGB space. The first point MUST correspond to
|
|
* position = 0, and the last to position = 1.
|
|
*
|
|
* The hue is interpolated around the "front" of the color wheel
|
|
* (red<->green<->blue<->red) unless the "rev" flag is set, in which case
|
|
* interpolation proceeds around the back (reverse) side. Specifying
|
|
* rev=NULL is equivalent to setting rev[]=0 for every control point.
|
|
*
|
|
* Bounds on RGB coordinates:
|
|
* R,G,B [0, 1] magnitude
|
|
*
|
|
* Bounds on HLS coordinates:
|
|
* hue [0, 360] degrees
|
|
* lightness [0, 1] magnitude
|
|
* saturation [0, 1] magnitude
|
|
*
|
|
* The inputs are:
|
|
* itype 0: HLS, 1: RGB
|
|
* npts number of control points
|
|
* pos[] position for each control point
|
|
* coord1[] first coordinate for each control point
|
|
* coord2[] second coordinate for each control point
|
|
* coord3[] third coordinate for each control point
|
|
* rev[] reverse flag for each control point
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
MZ_DLLEXPORT
|
|
void
|
|
c_plscmap1l(PLINT itype, PLINT npts, PLFLT *pos,
|
|
PLFLT *coord1, PLFLT *coord2, PLFLT *coord3, PLINT *rev)
|
|
{
|
|
int n;
|
|
PLFLT h, l, s, r, g, b;
|
|
|
|
if (npts < 2) {
|
|
plabort("plscmap1l: Must specify at least two control points");
|
|
return;
|
|
}
|
|
|
|
if ( (pos[0] != 0) || (pos[npts-1] != 1)) {
|
|
plabort("plscmap1l: First, last control points must lie on boundary");
|
|
return;
|
|
}
|
|
|
|
if ( npts > PL_MAX_CMAP1CP ) {
|
|
plabort("plscmap1l: exceeded maximum number of control points");
|
|
return;
|
|
}
|
|
|
|
/* Allocate if not done yet */
|
|
|
|
if (plsc->cmap1 == NULL)
|
|
plscmap1n(0);
|
|
|
|
/* Save control points */
|
|
|
|
plsc->ncp1 = npts;
|
|
|
|
for (n = 0; n < npts; n++) {
|
|
|
|
if (itype == 0) {
|
|
h = coord1[n];
|
|
l = coord2[n];
|
|
s = coord3[n];
|
|
}
|
|
else {
|
|
r = coord1[n];
|
|
g = coord2[n];
|
|
b = coord3[n];
|
|
plRGB_HLS(r, g, b, &h, &l, &s);
|
|
}
|
|
|
|
plsc->cmap1cp[n].h = h;
|
|
plsc->cmap1cp[n].l = l;
|
|
plsc->cmap1cp[n].s = s;
|
|
plsc->cmap1cp[n].p = pos[n];
|
|
|
|
if (rev == NULL)
|
|
plsc->cmap1cp[n].rev = 0;
|
|
else
|
|
plsc->cmap1cp[n].rev = rev[n];
|
|
}
|
|
|
|
/* Calculate and set color map */
|
|
|
|
plcmap1_calc();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plcmap1_calc()
|
|
*
|
|
* Bin up cmap 1 space and assign colors to make inverse mapping easy.
|
|
* Always do interpolation in HLS space.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plcmap1_calc(void)
|
|
{
|
|
int i, n;
|
|
PLFLT delta, dp, dh, dl, ds;
|
|
PLFLT h, l, s, p, r, g, b;
|
|
|
|
/* Loop over all control point pairs */
|
|
|
|
for (n = 0; n < plsc->ncp1-1; n++) {
|
|
|
|
if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n+1].p )
|
|
continue;
|
|
|
|
/* Differences in p, h, l, s between ctrl pts */
|
|
|
|
dp = plsc->cmap1cp[n+1].p - plsc->cmap1cp[n].p;
|
|
dh = plsc->cmap1cp[n+1].h - plsc->cmap1cp[n].h;
|
|
dl = plsc->cmap1cp[n+1].l - plsc->cmap1cp[n].l;
|
|
ds = plsc->cmap1cp[n+1].s - plsc->cmap1cp[n].s;
|
|
|
|
/* Adjust dh if we are to go around "the back side" */
|
|
|
|
if (plsc->cmap1cp[n].rev)
|
|
dh = (dh > 0) ? dh-360 : dh+360;
|
|
|
|
/* Loop over all color cells. Only interested in cells located (in */
|
|
/* cmap1 space) between n_th and n+1_th control points */
|
|
|
|
for (i = 0; i < plsc->ncol1; i++) {
|
|
p = (double) i / (plsc->ncol1 - 1.0);
|
|
if ( (p < plsc->cmap1cp[n].p) ||
|
|
(p > plsc->cmap1cp[n+1].p) )
|
|
continue;
|
|
|
|
/* Interpolate based on position of color cell in cmap1 space */
|
|
|
|
delta = (p - plsc->cmap1cp[n].p) / dp;
|
|
|
|
/* Linearly interpolate to get color cell h, l, s values */
|
|
|
|
h = plsc->cmap1cp[n].h + dh * delta;
|
|
l = plsc->cmap1cp[n].l + dl * delta;
|
|
s = plsc->cmap1cp[n].s + ds * delta;
|
|
|
|
while (h >= 360.)
|
|
h -= 360.;
|
|
|
|
while (h < 0.)
|
|
h += 360.;
|
|
|
|
plHLS_RGB(h, l, s, &r, &g, &b);
|
|
|
|
plsc->cmap1[i].r = MAX(0, MIN(255, (int) (256. * r)));
|
|
plsc->cmap1[i].g = MAX(0, MIN(255, (int) (256. * g)));
|
|
plsc->cmap1[i].b = MAX(0, MIN(255, (int) (256. * b)));
|
|
}
|
|
}
|
|
|
|
if (plsc->level > 0)
|
|
plP_state(PLSTATE_CMAP1);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscmap0n()
|
|
*
|
|
* Set number of colors in cmap 0, (re-)allocate cmap 0, and fill with
|
|
* default values for those colors not previously allocated (and less
|
|
* than index 15, after that you just get grey).
|
|
*
|
|
* The driver is not guaranteed to support all of these.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plscmap0n(PLINT ncol0)
|
|
{
|
|
int ncol, size, imin, imax;
|
|
|
|
/* No change */
|
|
|
|
if (ncol0 > 0 && plsc->ncol0 == ncol0)
|
|
return;
|
|
|
|
/* Handle all possible startup conditions */
|
|
|
|
if (plsc->ncol0 <= 0 && ncol0 <= 0)
|
|
ncol = 16;
|
|
else if (ncol0 <= 0)
|
|
ncol = plsc->ncol0;
|
|
else
|
|
ncol = ncol0;
|
|
|
|
imax = ncol-1;
|
|
size = ncol * sizeof(PLColor);
|
|
|
|
/* Allocate the space */
|
|
|
|
if (plsc->cmap0 == NULL) {
|
|
plsc->cmap0 = (PLColor *) calloc(1, size);
|
|
imin = 0;
|
|
}
|
|
else {
|
|
plsc->cmap0 = (PLColor *) realloc(plsc->cmap0, size);
|
|
imin = plsc->ncol0;
|
|
}
|
|
|
|
/* Fill in default entries */
|
|
|
|
plsc->ncol0 = ncol;
|
|
plcmap0_def(imin, imax);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscmap1n()
|
|
*
|
|
* Set number of colors in cmap 1, (re-)allocate cmap 1, and set default
|
|
* values if this is the first allocation.
|
|
*
|
|
* Note that the driver is allowed to disregard this number.
|
|
* In particular, most use fewer than we use internally.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
MZ_DLLEXPORT
|
|
void
|
|
c_plscmap1n(PLINT ncol1)
|
|
{
|
|
int ncol, size;
|
|
|
|
/* No change */
|
|
|
|
if (ncol1 > 0 && plsc->ncol1 == ncol1)
|
|
return;
|
|
|
|
/* Handle all possible startup conditions */
|
|
|
|
if (plsc->ncol1 <= 0 && ncol1 <= 0)
|
|
ncol = 128;
|
|
else if (ncol1 <= 0)
|
|
ncol = plsc->ncol1;
|
|
else
|
|
ncol = ncol1;
|
|
|
|
size = ncol * sizeof(PLColor);
|
|
|
|
/* Allocate the space */
|
|
|
|
if (plsc->ncol1 > 0)
|
|
plsc->cmap1 = (PLColor *) realloc(plsc->cmap1, size);
|
|
else
|
|
plsc->cmap1 = (PLColor *) calloc(ncol, sizeof(PLColor));
|
|
|
|
/* Fill in default entries */
|
|
|
|
plsc->ncol1 = ncol;
|
|
if (plsc->ncp1 == 0)
|
|
plcmap1_def();
|
|
else
|
|
plcmap1_calc();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* color_set()
|
|
*
|
|
* Initializes color table entry by RGB values.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
color_set(PLINT i, U_CHAR r, U_CHAR g, U_CHAR b, char *name )
|
|
{
|
|
plsc->cmap0[i].r = r;
|
|
plsc->cmap0[i].g = g;
|
|
plsc->cmap0[i].b = b;
|
|
plsc->cmap0[i].name = name;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plcmap0_def()
|
|
*
|
|
* Initializes specified color map 0 color entry to its default.
|
|
*
|
|
* Initial RGB values for color map 0 taken from X11R6
|
|
* (XFree86-3.3.6) X-windows
|
|
* rgb.txt file, and may not accurately represent the described colors on
|
|
* all systems.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
#define color_def(i, r, g, b, n) \
|
|
if (i >= imin && i <= imax) color_set(i, r, g, b, n);
|
|
|
|
static void
|
|
plcmap0_def(int imin, int imax)
|
|
{
|
|
int i;
|
|
|
|
color_def(0, 0, 0, 0, "black" ); /* black */
|
|
color_def(1, 255, 0, 0, "red"); /* red */
|
|
color_def(2, 255, 255, 0, "yellow" ); /* yellow */
|
|
color_def(3, 0, 255, 0, "green" ); /* green */
|
|
color_def(4, 127, 255, 212, "aquamarine" ); /* aquamarine */
|
|
color_def(5, 255, 192, 203, "pink" ); /* pink */
|
|
color_def(6, 245, 222, 179, "wheat" ); /* wheat */
|
|
color_def(7, 190, 190, 190, "grey" ); /* grey */
|
|
color_def(8, 165, 42, 42, "brown" ); /* brown */
|
|
color_def(9, 0, 0, 255, "blue" ); /* blue */
|
|
color_def(10, 138, 43, 226, "BlueViolet" ); /* Blue Violet */
|
|
color_def(11, 0, 255, 255, "cyan" ); /* cyan */
|
|
color_def(12, 64, 224, 208, "turquoise" ); /* turquoise */
|
|
color_def(13, 255, 0, 255, "magenta" ); /* magenta */
|
|
color_def(14, 250, 128, 114, "salmon" ); /* salmon */
|
|
color_def(15, 255, 255, 255, "white" ); /* white */
|
|
|
|
/* Any others are just arbitrarily set */
|
|
|
|
for (i = 16; i <= imax; i++)
|
|
color_def(i, 255, 0, 0, "red"); /* red */
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plcmap1_def()
|
|
*
|
|
* Initializes color map 1.
|
|
*
|
|
* The default initialization uses 6 control points in HLS space, the inner
|
|
* ones being very close to one of the vertices of the HLS double cone. The
|
|
* vertex used (black or white) is chosen to be the closer to the background
|
|
* color. The 6 points were chosen over the older 4 points in order to make
|
|
* weaker structures more easily visible, and give more control through the
|
|
* palette editor. If you don't like these settings.. change them!
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
plcmap1_def(void)
|
|
{
|
|
PLFLT i[6], h[6], l[6], s[6], midpt = 0., vertex = 0.;
|
|
|
|
/* Positions of control points */
|
|
|
|
i[0] = 0; /* left boundary */
|
|
i[1] = 0.44; /* a little left of center */
|
|
i[2] = 0.50; /* at center */
|
|
i[3] = 0.50; /* at center */
|
|
i[4] = 0.56; /* a little right of center */
|
|
i[5] = 1; /* right boundary */
|
|
|
|
/* For center control points, pick black or white, whichever is closer to bg */
|
|
/* Be carefult to pick just short of top or bottom else hue info is lost */
|
|
|
|
if (plsc->cmap0 != NULL)
|
|
vertex = ((PLFLT) plsc->cmap0[0].r +
|
|
(PLFLT) plsc->cmap0[0].g +
|
|
(PLFLT) plsc->cmap0[0].b) / 3. / 255.;
|
|
|
|
if (vertex < 0.5) {
|
|
vertex = 0.01;
|
|
midpt = 0.10;
|
|
} else {
|
|
vertex = 0.99;
|
|
midpt = 0.90;
|
|
}
|
|
|
|
/* Set hue */
|
|
|
|
h[0] = 260; /* low: blue-violet */
|
|
h[1] = 260; /* only change as we go over vertex */
|
|
h[2] = 260; /* only change as we go over vertex */
|
|
h[3] = 0; /* high: red */
|
|
h[4] = 0; /* high: red */
|
|
h[5] = 0; /* keep fixed */
|
|
|
|
/* Set lightness */
|
|
|
|
l[0] = 0.5; /* low */
|
|
l[1] = midpt; /* midpoint value */
|
|
l[2] = vertex; /* bg */
|
|
l[3] = vertex; /* bg */
|
|
l[4] = midpt; /* midpoint value */
|
|
l[5] = 0.5; /* high */
|
|
|
|
/* Set saturation -- keep at maximum */
|
|
|
|
s[0] = 1;
|
|
s[1] = 1;
|
|
s[2] = 1;
|
|
s[3] = 1;
|
|
s[4] = 1;
|
|
s[5] = 1;
|
|
|
|
c_plscmap1l(0, 6, i, h, l, s, NULL);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plscolor()
|
|
*
|
|
* Used to globally turn color output on/off
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plscolor(PLINT color)
|
|
{
|
|
plsc->colorset = 1;
|
|
plsc->color = color;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plrgb()
|
|
*
|
|
* Set line color by red, green, blue from 0. to 1.
|
|
* Do NOT use this. Only retained for backward compatibility
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plrgb(PLFLT r, PLFLT g, PLFLT b)
|
|
{
|
|
if (plsc->level < 1) {
|
|
plabort("plrgb: Please call plinit first");
|
|
return;
|
|
}
|
|
|
|
plsc->icol0 = PL_RGB_COLOR;
|
|
plsc->curcolor.r = MAX(0, MIN(255, (int) (256. * r)));
|
|
plsc->curcolor.g = MAX(0, MIN(255, (int) (256. * g)));
|
|
plsc->curcolor.b = MAX(0, MIN(255, (int) (256. * b)));
|
|
|
|
plsc->curcmap = 0;
|
|
plP_state(PLSTATE_COLOR0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plrgb1()
|
|
*
|
|
* Set line color by 8 bit RGB values.
|
|
* Do NOT use this. Only retained for backward compatibility
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plrgb1(PLINT r, PLINT g, PLINT b)
|
|
{
|
|
if (plsc->level < 1) {
|
|
plabort("plrgb1: Please call plinit first");
|
|
return;
|
|
}
|
|
if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
|
|
plabort("plrgb1: Invalid color");
|
|
return;
|
|
}
|
|
|
|
plsc->icol0 = PL_RGB_COLOR;
|
|
plsc->curcolor.r = r;
|
|
plsc->curcolor.g = g;
|
|
plsc->curcolor.b = b;
|
|
|
|
plsc->curcmap = 0;
|
|
plP_state(PLSTATE_COLOR0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plhls()
|
|
*
|
|
* Set current color by hue, lightness, and saturation.
|
|
* Convert hls color coordinates to rgb, then call plrgb.
|
|
* Do NOT use this. Only retained for backward compatibility
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plhls(PLFLT h, PLFLT l, PLFLT s)
|
|
{
|
|
PLFLT r, g, b;
|
|
|
|
plHLS_RGB(h, l, s, &r, &g, &b);
|
|
plrgb(r, g, b);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void value()
|
|
*
|
|
* Auxiliary function used by plHLS_RGB().
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
static PLFLT
|
|
value(double n1, double n2, double hue)
|
|
{
|
|
PLFLT val;
|
|
|
|
while (hue >= 360.)
|
|
hue -= 360.;
|
|
while (hue < 0.)
|
|
hue += 360.;
|
|
|
|
if (hue < 60.)
|
|
val = n1 + (n2 - n1) * hue / 60.;
|
|
else if (hue < 180.)
|
|
val = n2;
|
|
else if (hue < 240.)
|
|
val = n1 + (n2 - n1) * (240. - hue) / 60.;
|
|
else
|
|
val = n1;
|
|
|
|
return (val);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plHLS_RGB()
|
|
*
|
|
* Convert HLS color to RGB color.
|
|
* Bounds on HLS (input):
|
|
* hue [0., 360.] degrees
|
|
* lightness [0., 1.] magnitude
|
|
* saturation [0., 1.] magnitude
|
|
*
|
|
* Hue is always mapped onto the interval [0., 360.] regardless of input.
|
|
* Bounds on RGB (output) is always [0., 1.]. Convert to RGB color values
|
|
* by multiplying by 2**nbits (nbits typically 8).
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plHLS_RGB(PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b)
|
|
{
|
|
PLFLT m1, m2;
|
|
|
|
if (l <= .5)
|
|
m2 = l * (s + 1.);
|
|
else
|
|
m2 = l + s - l * s;
|
|
|
|
m1 = 2 * l - m2;
|
|
|
|
*p_r = value(m1, m2, h + 120.);
|
|
*p_g = value(m1, m2, h);
|
|
*p_b = value(m1, m2, h - 120.);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plRGB_HLS()
|
|
*
|
|
* Convert RGB color to HLS color.
|
|
* Bounds on RGB (input) is always [0., 1.].
|
|
* Bounds on HLS (output):
|
|
* hue [0., 360.] degrees
|
|
* lightness [0., 1.] magnitude
|
|
* saturation [0., 1.] magnitude
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plRGB_HLS(PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s)
|
|
{
|
|
PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
|
|
|
|
rgb_min = MIN( r, MIN( g, b ));
|
|
rgb_max = MAX( r, MAX( g, b ));
|
|
|
|
l = (rgb_min+rgb_max) / 2.0;
|
|
|
|
if (rgb_min == rgb_max) {
|
|
s = 0;
|
|
h = 0;
|
|
}
|
|
else {
|
|
d = rgb_max - rgb_min;
|
|
if (l < 0.5)
|
|
s = 0.5 * d / l;
|
|
else
|
|
s = 0.5* d / (1.-l);
|
|
|
|
rc = (rgb_max-r) / d;
|
|
gc = (rgb_max-g) / d;
|
|
bc = (rgb_max-b) / d;
|
|
|
|
if (r == rgb_max)
|
|
h = bc-gc;
|
|
else if (g == rgb_max)
|
|
h = rc-bc+2;
|
|
else
|
|
h = gc-rc-2;
|
|
|
|
h = h*60;
|
|
if (h < 0)
|
|
h = h+360;
|
|
else if (h >= 360)
|
|
h = h-360;
|
|
}
|
|
*p_h = h;
|
|
*p_l = l;
|
|
*p_s = s;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* A grab-bag of various control routines.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plwarn()
|
|
*
|
|
* A handy way to issue warnings, if need be.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plwarn(char *errormsg)
|
|
{
|
|
int was_gfx = 0;
|
|
|
|
if (plsc->graphx == 1) {
|
|
was_gfx = 1;
|
|
pltext();
|
|
}
|
|
|
|
fprintf(stderr, "\n*** PLPLOT WARNING ***\n");
|
|
if (*errormsg != '\0')
|
|
fprintf(stderr, "%s\n", errormsg);
|
|
|
|
if (was_gfx == 1)
|
|
plgra();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plabort()
|
|
*
|
|
* Much the same as plwarn(), but appends ", aborting operation" to the
|
|
* error message. Helps to keep source code uncluttered and provides a
|
|
* convention for error aborts.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plabort(char *errormsg)
|
|
{
|
|
if (plsc->errcode != NULL)
|
|
*(plsc->errcode) = 1;
|
|
|
|
if (plsc->errmsg != NULL) {
|
|
sprintf(plsc->errmsg, "\n*** PLPLOT ERROR ***\n");
|
|
if (*errormsg != '\0')
|
|
sprintf(plsc->errmsg, "%s, aborting operation\n", errormsg);
|
|
|
|
} else {
|
|
int was_gfx = 0;
|
|
|
|
if (plsc->graphx == 1) {
|
|
was_gfx = 1;
|
|
pltext();
|
|
}
|
|
|
|
fprintf(stderr, "\n*** PLPLOT ERROR ***\n");
|
|
if (*errormsg != '\0')
|
|
fprintf(stderr, "%s, aborting operation\n", errormsg);
|
|
|
|
if (was_gfx == 1)
|
|
plgra();
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plexit()
|
|
*
|
|
* In case of an abort this routine is called. It just prints out an error
|
|
* message and tries to clean up as much as possible. It's best to turn
|
|
* off pause and then restore previous setting before returning.
|
|
*
|
|
* If cleanup needs to be done in the main program, the user should write
|
|
* his/her own exit handler and pass it in via plsexit(). This function
|
|
* should should either call plend() before exiting, or simply return.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plexit(char *errormsg)
|
|
{
|
|
int status = 1;
|
|
|
|
if (exit_handler != NULL)
|
|
status = (*exit_handler)(errormsg);
|
|
|
|
plsc->nopause = 1;
|
|
if (*errormsg != '\0') {
|
|
fprintf(stderr, "\n*** PLPLOT ERROR ***\n");
|
|
fprintf(stderr, "%s\n", errormsg);
|
|
}
|
|
plend();
|
|
|
|
fprintf(stderr, "Program aborted\n");
|
|
exit(status);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plsexit()
|
|
*
|
|
* Sets an optional user exit handler.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plsexit(int (*handler) (char *))
|
|
{
|
|
exit_handler = handler;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plgra()
|
|
*
|
|
* Switches to graphics screen.
|
|
*
|
|
* Here and in pltext() it's a good idea to return silently if plinit()
|
|
* hasn't yet been called, since plwarn() calls pltext() and plgra(), and
|
|
* plwarn() may be called at any time.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_plgra(void)
|
|
{
|
|
if (plsc->level > 0)
|
|
plP_esc(PLESC_GRAPH, NULL);
|
|
}
|
|
|
|
void
|
|
c_plxormod(PLINT mode, PLINT *status) /* xor mode */
|
|
{
|
|
static int ostate = 0;
|
|
|
|
if (!plsc->dev_xor) {
|
|
*status = 0;
|
|
return;
|
|
}
|
|
|
|
if (plsc->level > 0) {
|
|
plP_esc(PLESC_XORMOD, &mode);
|
|
if (mode) {
|
|
ostate = plsc->plbuf_write;
|
|
plsc->plbuf_write = 0;
|
|
} else
|
|
plsc->plbuf_write = ostate;
|
|
}
|
|
*status = 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void pltext()
|
|
*
|
|
* Switches to text screen.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
c_pltext(void)
|
|
{
|
|
if (plsc->level > 0)
|
|
plP_esc(PLESC_TEXT, NULL);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void pl_cmd()
|
|
*
|
|
* Front-end to driver escape function.
|
|
* In principle this can be used to pass just about anything directly
|
|
* to the driver.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
pl_cmd(PLINT op, void *ptr)
|
|
{
|
|
plP_esc(op, ptr);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* char *plFindCommand
|
|
*
|
|
* Looks for the specified executable file. Search path:
|
|
* PLPLOT_BIN_ENV = $(PLPLOT_BIN)
|
|
* current directory
|
|
* PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
|
|
* BIN_DIR
|
|
*
|
|
* The caller must free the returned pointer (points to malloc'ed memory)
|
|
* when finished with it.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
char *
|
|
plFindCommand(char *fn)
|
|
{
|
|
char *fs = NULL, *dn;
|
|
|
|
/* PLPLOT_BIN_ENV = $(PLPLOT_BIN) */
|
|
|
|
#if defined(PLPLOT_BIN_ENV)
|
|
if ((dn = getenv(PLPLOT_BIN_ENV)) != NULL) {
|
|
plGetName(dn, "", fn, &fs);
|
|
if ( ! plFindName(fs))
|
|
return fs;
|
|
fprintf(stderr, PLPLOT_BIN_ENV"=\"%s\"\n", dn); /* what IS set? */
|
|
}
|
|
#endif /* PLPLOT_BIN_ENV */
|
|
|
|
/* Current directory */
|
|
|
|
plGetName(".", "", fn, &fs);
|
|
if ( ! plFindName(fs))
|
|
return fs;
|
|
|
|
/* PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin */
|
|
|
|
#if defined(PLPLOT_HOME_ENV)
|
|
if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
|
|
plGetName(dn, "bin", fn, &fs);
|
|
if ( ! plFindName(fs))
|
|
return fs;
|
|
fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
|
|
}
|
|
#endif /* PLPLOT_HOME_ENV */
|
|
|
|
/* BIN_DIR */
|
|
|
|
#if defined (BIN_DIR)
|
|
plGetName(BIN_DIR, "", fn, &fs);
|
|
if ( ! plFindName(fs))
|
|
return fs;
|
|
#endif
|
|
|
|
/* Crapped out */
|
|
|
|
free_mem(fs);
|
|
fprintf(stderr, "plFindCommand: cannot locate command: %s\n", fn);
|
|
#if defined (BIN_DIR)
|
|
fprintf(stderr, "bin dir=\"" BIN_DIR "\"\n" ); /* what WAS set? */
|
|
#endif /* BIN_DIR */
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* FILE *plLibOpen(fn)
|
|
*
|
|
* Return file pointer to lib file.
|
|
* Locations checked:
|
|
* PLPLOT_LIB_ENV = $(PLPLOT_LIB)
|
|
* current directory
|
|
* PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib
|
|
* DATA_DIR
|
|
* PLLIBDEV
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
FILE *
|
|
plLibOpen(char *fn)
|
|
{
|
|
FILE *ret = NULL;
|
|
|
|
PDFstrm *pdfs = plLibOpenPdfstrm(fn);
|
|
if (pdfs == NULL) {
|
|
return NULL;
|
|
}
|
|
if (pdfs->file != NULL) {
|
|
ret = pdfs->file;
|
|
pdfs->file = NULL;
|
|
}
|
|
pdf_close(pdfs);
|
|
return ret;
|
|
}
|
|
|
|
PDFstrm *
|
|
plLibOpenPdfstrm(char *fn)
|
|
{
|
|
PDFstrm *file;
|
|
char *fs = NULL, *dn = NULL;
|
|
|
|
/**** search PLPLOT_LIB_ENV = $(PLPLOT_LIB) ****/
|
|
|
|
#if defined(PLPLOT_LIB_ENV)
|
|
if ((dn = getenv(PLPLOT_LIB_ENV)) != NULL) {
|
|
plGetName(dn, "", fn, &fs);
|
|
|
|
if ((file = pdf_fopen(fs, "rb")) != NULL)
|
|
goto done;
|
|
|
|
fprintf(stderr, PLPLOT_LIB_ENV"=\"%s\"\n", dn); /* what IS set? */
|
|
}
|
|
#endif /* PLPLOT_LIB_ENV */
|
|
|
|
/**** search current directory ****/
|
|
|
|
if ((file = pdf_fopen(fn, "rb")) != NULL)
|
|
goto done;
|
|
|
|
/**** search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ****/
|
|
|
|
#if defined (PLPLOT_HOME_ENV)
|
|
if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
|
|
plGetName(dn, "lib", fn, &fs);
|
|
|
|
if ((file = pdf_fopen(fs, "rb")) != NULL)
|
|
goto done;
|
|
fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
|
|
}
|
|
#endif /* PLPLOT_HOME_ENV/lib */
|
|
|
|
/**** search installed location ****/
|
|
|
|
#if defined (DATA_DIR)
|
|
plGetName(DATA_DIR, "", fn, &fs);
|
|
|
|
if ((file = pdf_fopen(fs, "rb")) != NULL)
|
|
goto done;
|
|
#endif /* DATA_DIR */
|
|
|
|
/**** search hardwired location ****/
|
|
|
|
#ifdef PLLIBDEV
|
|
plGetName(PLLIBDEV, "", fn, &fs);
|
|
|
|
if ((file = pdf_fopen(fs, "rb")) != NULL)
|
|
goto done;
|
|
#endif /* PLLIBDEV */
|
|
|
|
#ifdef macintosh
|
|
file = plMacLibOpen(fn);
|
|
if (file != NULL)
|
|
goto done;
|
|
#endif /* macintosh */
|
|
|
|
if (plplotLibDir != NULL) {
|
|
plGetName(plplotLibDir, "", fn, &fs);
|
|
if ((file = pdf_fopen(fs, "rb")) != NULL)
|
|
goto done;
|
|
|
|
}
|
|
|
|
/**** not found, give up ****/
|
|
|
|
return NULL;
|
|
|
|
done:
|
|
free_mem(fs);
|
|
return (file);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* int plFindName
|
|
*
|
|
* Authors: Paul Dubois (LLNL), others?
|
|
* This function is in the public domain.
|
|
*
|
|
* Given a pathname, determine if it is a symbolic link. If so, continue
|
|
* searching to the ultimate terminus - there may be more than one link.
|
|
* Use the error value to determine when the terminus is reached, and to
|
|
* determine if the pathname really exists. Then stat it to determine
|
|
* whether it's executable. Return 0 for an executable, errno otherwise.
|
|
* Note that 'p' _must_ have at least one '/' character - it does by
|
|
* construction in this program. The contents of the array pointed to by
|
|
* 'p' are changed to the actual pathname if findname is successful.
|
|
*
|
|
* This function is only defined under Unix for now.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
#ifdef do_not_do // changed, this is unnessisary in this build anyway
|
|
int
|
|
plFindName(char *p)
|
|
{
|
|
int n;
|
|
char buf[1024], *cp;
|
|
extern int errno;
|
|
struct stat sbuf;
|
|
|
|
pldebug("plFindName", "Trying to find %s\n", p);
|
|
while ((n = readlink(p, buf, 1024)) > 0) {
|
|
pldebug("plFindName", "Readlink read %d chars at: %s\n", n, p);
|
|
if (buf[0] == '/') {
|
|
/* Link is an absolute path */
|
|
|
|
strncpy(p, buf, n);
|
|
p[n] = '\0';
|
|
pldebug("plFindName", "Link is absolute: %s\n", p);
|
|
}
|
|
else {
|
|
/* Link is relative to its directory; make it absolute */
|
|
|
|
cp = 1 + strrchr(p, '/');
|
|
strncpy(cp, buf, n);
|
|
cp[n] = '\0';
|
|
pldebug("plFindName",
|
|
"Link is relative: %s\n\tTotal path:%s\n", cp, p);
|
|
}
|
|
}
|
|
|
|
/* This macro not defined on the NEC SX-3 */
|
|
|
|
#ifdef SX
|
|
#define S_ISREG(mode) (mode & S_IFREG)
|
|
#endif
|
|
|
|
/* SGI machines return ENXIO instead of EINVAL Dubois 11/92 */
|
|
|
|
if (errno == EINVAL || errno == ENXIO) {
|
|
pldebug("plFindName", "%s may be the one...\n", p);
|
|
if ((stat(p, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) {
|
|
pldebug("plFindName", "%s is a regular file\n", p);
|
|
return (access(p, X_OK));
|
|
}
|
|
}
|
|
pldebug("plFindName", "%s found but is not executable\n", p);
|
|
return (errno ? errno : -1);
|
|
}
|
|
|
|
#else
|
|
int
|
|
plFindName(char *p)
|
|
{
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void plGetName()
|
|
*
|
|
* Gets search name for file by concatenating the dir, subdir, and file
|
|
* name, allocating memory as needed. The appropriate delimiter is added
|
|
* after the dir specification as necessary. The caller is responsible
|
|
* for freeing the malloc'ed memory.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plGetName(char *dir, char *subdir, char *filename, char **filespec)
|
|
{
|
|
int lfilespec;
|
|
|
|
/* Malloc space for filespec */
|
|
|
|
free_mem(*filespec);
|
|
lfilespec = 10;
|
|
lfilespec = strlen(dir) + strlen(subdir) + strlen(filename) + 10;
|
|
*filespec = (char *) malloc(lfilespec);
|
|
|
|
strcpy(*filespec, dir);
|
|
|
|
if (*subdir != '\0') {
|
|
strcat_delim(*filespec);
|
|
strcat(*filespec, subdir);
|
|
}
|
|
if (*filename != '\0') {
|
|
strcat_delim(*filespec);
|
|
strcat(*filespec, filename);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* void strcat_delim()
|
|
*
|
|
* Append path name deliminator if necessary (does not add one if one's
|
|
* there already, or if dealing with a colon-terminated device name).
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
strcat_delim(char *dirspec)
|
|
{
|
|
int ldirspec = strlen(dirspec);
|
|
#if defined (MSDOS)
|
|
if (dirspec[ldirspec-1] != '\\')
|
|
strcat(dirspec, "\\");
|
|
#elif defined (macintosh)
|
|
if (dirspec[ldirspec-1] != ':')
|
|
strcat(dirspec, ":");
|
|
#else /* unix is the default */
|
|
if (dirspec[ldirspec-1] != '/')
|
|
strcat(dirspec, "/");
|
|
#endif
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plcol_interp()
|
|
*
|
|
* Initializes device cmap 1 entry by interpolation from pls->cmap1
|
|
* entries. Returned PLColor is supposed to represent the i_th color
|
|
* out of a total of ncol colors in the current color scheme.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plcol_interp(PLStream *pls, PLColor *newcolor, int i, int ncol)
|
|
{
|
|
PLFLT x, delta;
|
|
int il, ir;
|
|
|
|
x = (double) (i * (pls->ncol1-1)) / (double) (ncol-1);
|
|
il = x;
|
|
ir = il + 1;
|
|
delta = x - il;
|
|
|
|
if (ir > pls->ncol1 || il < 0)
|
|
fprintf(stderr, "Invalid color\n");
|
|
|
|
else if (ir == pls->ncol1 || (delta == 0.)) {
|
|
newcolor->r = pls->cmap1[il].r;
|
|
newcolor->g = pls->cmap1[il].g;
|
|
newcolor->b = pls->cmap1[il].b;
|
|
}
|
|
else {
|
|
newcolor->r = (1.-delta) * pls->cmap1[il].r + delta * pls->cmap1[ir].r;
|
|
newcolor->g = (1.-delta) * pls->cmap1[il].g + delta * pls->cmap1[ir].g;
|
|
newcolor->b = (1.-delta) * pls->cmap1[il].b + delta * pls->cmap1[ir].b;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plOpenFile()
|
|
*
|
|
* Opens file for output, prompting if not set.
|
|
* Prints extra newline at end to make output look better in batch runs.
|
|
* A file name of "-" indicates output to stdout.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
#define MAX_NUM_TRIES 10
|
|
void
|
|
plOpenFile(PLStream *pls)
|
|
{
|
|
int i = 0, count = 0;
|
|
size_t len;
|
|
char line[256];
|
|
|
|
while (pls->OutFile == NULL) {
|
|
|
|
/* Setting pls->FileName = NULL forces creation of a new family member */
|
|
/* You should also free the memory associated with it if you do this */
|
|
|
|
if (pls->family && pls->BaseName != NULL)
|
|
plP_getmember(pls);
|
|
|
|
/* Prompt if filename still not known */
|
|
|
|
if (pls->FileName == NULL) {
|
|
do {
|
|
fprintf(stdout, "Enter graphics output file name: ");
|
|
fgets(line, sizeof(line), stdin);
|
|
len = strlen(line);
|
|
if (len)
|
|
len--;
|
|
line[len] = '\0'; /* strip new-line */
|
|
count++; /* count zero entries */
|
|
} while (!len && count < MAX_NUM_TRIES);
|
|
plP_sfnam(pls, line);
|
|
}
|
|
|
|
/* If name is "-", send to stdout */
|
|
|
|
if ( ! strcmp(pls->FileName, "-")) {
|
|
pls->OutFile = stdout;
|
|
pls->output_type = 1;
|
|
break;
|
|
}
|
|
|
|
/* Need this here again, for prompted family initialization */
|
|
|
|
if (pls->family && pls->BaseName != NULL)
|
|
plP_getmember(pls);
|
|
|
|
if (i++ > 10)
|
|
plexit("Too many tries.");
|
|
|
|
if ((pls->OutFile = fopen(pls->FileName, "wb+")) == NULL)
|
|
fprintf(stdout, "Can't open %s.\n", pls->FileName);
|
|
else
|
|
{
|
|
// fprintf(stderr, "Opened %s\n", pls->FileName);
|
|
// this is not needed
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plP_getmember()
|
|
*
|
|
* Sets up next file member name (in pls->FileName), but does not open it.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plP_getmember(PLStream *pls)
|
|
{
|
|
char tmp[256];
|
|
|
|
if (pls->FileName == NULL)
|
|
pls->FileName = (char *) malloc(10 + strlen(pls->BaseName));
|
|
|
|
sprintf(tmp, "%s.%%0%1ii", pls->BaseName, (int) pls->fflen);
|
|
sprintf(pls->FileName, tmp, pls->member);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plP_sfnam()
|
|
*
|
|
* Sets up file name & family stem name.
|
|
* Reserve some extra space (5 chars) to hold an optional member number.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plP_sfnam(PLStream *pls, const char *fnam)
|
|
{
|
|
pls->OutFile = NULL;
|
|
|
|
if (pls->FileName != NULL)
|
|
free((void *) pls->FileName);
|
|
|
|
pls->FileName = (char *) malloc(10 + strlen(fnam));
|
|
|
|
strcpy(pls->FileName, fnam);
|
|
|
|
if (pls->BaseName != NULL)
|
|
free((void *) pls->BaseName);
|
|
|
|
pls->BaseName = (char *) malloc(10 + strlen(fnam));
|
|
|
|
strcpy(pls->BaseName, fnam);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plFamInit()
|
|
*
|
|
* Initializes family file parameters.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plFamInit(PLStream *pls)
|
|
{
|
|
if (pls->family) {
|
|
pls->bytecnt = 0;
|
|
if ( ! pls->member)
|
|
pls->member = 1;
|
|
if ( ! pls->finc)
|
|
pls->finc = 1;
|
|
if ( ! pls->fflen)
|
|
pls->fflen = 1;
|
|
if ( ! pls->bytemax)
|
|
pls->bytemax = PL_FILESIZE_KB * 1000;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plGetFam()
|
|
*
|
|
* Starts new member file of family file set if necessary.
|
|
*
|
|
* Note each member file is a complete graphics file (can be printed
|
|
* individually), although 'plrender' will treat a family as a single
|
|
* logical file if given the family name instead of the member name.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plGetFam(PLStream *pls)
|
|
{
|
|
PLFLT xpmm_loc, ypmm_loc;
|
|
if (pls->family) {
|
|
if (pls->bytecnt > pls->bytemax || pls->famadv) {
|
|
plP_tidy();
|
|
pls->member += pls->finc;
|
|
pls->famadv = 0;
|
|
plP_init();
|
|
/* Apply compensating factor to original xpmm and ypmm so that
|
|
* character aspect ratio is preserved when overall aspect ratio
|
|
* is changed. */
|
|
plP_gpixmm(&xpmm_loc, &ypmm_loc);
|
|
plP_setpxl(xpmm_loc*plsc->caspfactor, ypmm_loc/plsc->caspfactor);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plRotPhy()
|
|
*
|
|
* Rotates physical coordinates if necessary for given orientation.
|
|
* Each time orient is incremented, the plot is rotated 90 deg clockwise.
|
|
* Note: this is now used only to rotate by 90 degrees for devices that
|
|
* expect portrait mode.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plRotPhy(PLINT orient, PLINT xmin, PLINT ymin, PLINT xmax, PLINT ymax,
|
|
int *px, int *py)
|
|
{
|
|
int x, y;
|
|
|
|
x = *px;
|
|
y = *py;
|
|
|
|
switch (orient%4) {
|
|
|
|
case 1:
|
|
*px = xmin + (y - ymin);
|
|
*py = ymin + (xmax - x);
|
|
break;
|
|
|
|
case 2:
|
|
*px = xmin + (xmax - x);
|
|
*py = ymin + (ymax - y);
|
|
break;
|
|
|
|
case 3:
|
|
*px = xmin + (ymax - y);
|
|
*py = ymin + (x - xmin);
|
|
break;
|
|
|
|
default:
|
|
break; /* do nothing */
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plAllocDev()
|
|
*
|
|
* Allocates a standard PLDev structure for device-specific data, stores
|
|
* the address in pls->dev, and returns the address as well.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
PLDev *
|
|
plAllocDev(PLStream *pls)
|
|
{
|
|
if (pls->dev != NULL)
|
|
free((void *) pls->dev);
|
|
|
|
pls->dev = calloc(1, (size_t) sizeof(PLDev));
|
|
if (pls->dev == NULL)
|
|
plexit("plAllocDev: cannot allocate memory\n");
|
|
|
|
return (PLDev *) pls->dev;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plGinInit()
|
|
*
|
|
* Just fills in the PLGraphicsIn with appropriate initial values.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
plGinInit(PLGraphicsIn *gin)
|
|
{
|
|
gin->type = 0;
|
|
gin->state = 0;
|
|
gin->keysym = 0;
|
|
gin->button = 0;
|
|
gin->string[0] = '\0';
|
|
gin->pX = gin->pY = -1;
|
|
gin->dX = gin->dY = 0.;
|
|
gin->wX = gin->wY = 0.;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plGetInt()
|
|
*
|
|
* Prompts human to input an integer in response to given message.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
PLINT
|
|
plGetInt(char *s)
|
|
{
|
|
int m;
|
|
int i = 0;
|
|
char line[256];
|
|
|
|
while (i++ < 10) {
|
|
fprintf(stdout, s);
|
|
fgets(line, sizeof(line), stdin);
|
|
#ifdef MSDOS
|
|
m = atoi(line);
|
|
return (m);
|
|
#else
|
|
if (sscanf(line, "%d", &m) == 1)
|
|
return (m);
|
|
fprintf(stdout, "No value or value out of range; please try again\n");
|
|
#endif
|
|
}
|
|
plexit("Too many tries.");
|
|
return (0);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plGetFlt()
|
|
*
|
|
* Prompts human to input a float in response to given message.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
PLFLT
|
|
plGetFlt(char *s)
|
|
{
|
|
PLFLT m;
|
|
double m1;
|
|
int i = 0;
|
|
char line[256];
|
|
|
|
while (i++ < 10) {
|
|
fprintf(stdout, s);
|
|
fgets(line, sizeof(line), stdin);
|
|
#ifdef MSDOS
|
|
m = atof(line);
|
|
return (m);
|
|
#else
|
|
if (sscanf(line, "%lf", &m1) == 1) {
|
|
m = (PLFLT) m1;
|
|
return (m);
|
|
}
|
|
fprintf(stdout, "No value or value out of range; please try again\n");
|
|
#endif
|
|
}
|
|
plexit("Too many tries.");
|
|
return (0.);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*\
|
|
* plstrdup()
|
|
*
|
|
* A replacement for strdup(), which isn't portable.
|
|
* Caller responsible for freeing the allocated memory.
|
|
\*--------------------------------------------------------------------------*/
|
|
|
|
char *
|
|
plstrdup(const char *src)
|
|
{
|
|
char *dest = (char *) malloc( (strlen(src) + 1) * sizeof(char) );
|
|
if (dest != NULL)
|
|
strcpy(dest, src);
|
|
else
|
|
plabort("Out of memory");
|
|
|
|
return dest;
|
|
}
|
|
|