plt - Software for 2D Plots 2.5
(13,147 bytes)
/* file: lw.c Paul Albrecht July 1987
Last revised: 7 November 2002
PostScript driver for plt
Copyright (C) Paul Albrecht 1988
Recent changes (by George Moody, george@mit.edu):
23 February 2001: added color support including the X11R6 color database
30 March 2001: added LN, CN, RN, label concatenation
11 April 2001: general cleanup
10 May 2001: replaced old elabel() with implementation from xw.c
7 November 2002: corrected axis title placement when using log axes
_______________________________________________________________________________
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
You may contact the maintainer by e-mail (george@mit.edu) or postal mail
(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software,
please visit PhysioNet (http://www.physionet.org/).
_______________________________________________________________________________
The plotting space for PostScript output is always the same number (300*2) of
units per inch, so that the line width and font shapes are not changed in size
if the plot is compressed in one dimension. This code needs the prolog file
plt.pro, which defines the PostScript procedures used here. For example,
paths are defined with M (move) and N (next) and stroked with L (line) or F
(filled region); M, N, L, and F are not PostScript primitives, but are
defined by plt.pro.
*/
#include "plt.h"
#include "rgb.h" /* color definitions from X11R6 */
/* Prototypes of functions defined in this module */
void openpl(void);
void closepl(void);
void erase(void);
void space(Ptype x0, Ptype y0, Ptype x1, Ptype y1);
void label(char *lbl);
void move(Ptype x, Ptype y);
void line(Ptype x0, Ptype y0, Ptype x1, Ptype y1);
void cont(Ptype x, Ptype y);
void plabel(char *lbl, Ptype x, Ptype y, char *just, double angle);
void alabel(char *what, char *lbl, Ptype x, Ptype y);
void elabel(char *what, char *base, char *exp, Ptype x, Ptype y);
void strsize(char *str, Ptype *xsize, Ptype *ysize, double angle);
void scatterplot(PltPtr plt, Ptype x, Ptype y, Ptype yneg, Ptype ypos);
void PolyDef(Ptype x, Ptype y, Const what);
void special(int what, PtrUnion arg0, PtrUnion arg1);
static void sendstring(char *s);
static void flushpath(void);
static void PTERMInit();
static void setfont();
static void linewidth();
static void linemod();
static void setgray();
static void setcolor();
static void PTERMInit(char *pterm);
static void setfont(char *name, double ps);
static void linewidth(double lw);
static void linemod(char *lm);
static void setgray(double grey);
static void setcolor(char *color);
#define MAXPATH 1475 /* Laser Writer can't handle 1500 */
static Ptype oldx, oldy;
static long npath;
void openpl(void)
{
npath = 0;
}
void closepl(void)
{
flushpath();
fflush(stdout);
}
void erase(void)
{
/* This space intentionally left void :-) */
}
void space(Ptype x0, Ptype y0, Ptype x1, Ptype y1)
{
printf("%.5lg %.5lg %.5lg %.5lg %.5lg ",
fscl, xorig, yorig, xorig+xdim, yorig+ydim);
printf("%ld %ld %ld %ld WDEF\n", (long)x0, (long)y0, (long)x1, (long)y1);
setfont(DEFAULT_FONT, (double)DEFAULT_PS);
}
void label(char *lbl)
{
sendstring(lbl);
printf(" show\n");
npath = 0;
}
void move(Ptype x, Ptype y)
{
flushpath();
printf("%ld %ld M\n", (long)x, (long)y);
oldx = x;
oldy = y;
npath = 1;
}
void line(Ptype x0, Ptype y0, Ptype x1, Ptype y1)
{
move(x1, y1);
printf("%ld %ld L\n", (long)(x0-oldx), (long)(y0-oldy));
npath = 0;
}
void cont(Ptype x, Ptype y)
{
if (npath == 0)
err(YES, "Called cont() before move()");
if (npath == MAXPATH-1) {
printf("%ld %ld L\n%ld %ld M\n",
(long)(x-oldx), (long)(y-oldy), (long)x, (long)y);
npath = 1;
}
else {
printf("%ld %ld N\n", (long)(x-oldx), (long)(y-oldy));
npath++;
}
oldx = x;
oldy = y;
}
static void sendstring(char *s)
{
char c;
flushpath();
putchar('(');
while (c = *s++) {
if ((c == ')') || (c == '(') || (c == '\\'))
putchar('\\');
if ((c > 0176) || (c <040)) {
putchar('\\');
putchar(((c>>6)&07)+'0');
putchar(((c>>3)&07)+'0');
putchar((c&07)+'0');
}
else putchar(c);
}
putchar(')');
npath = 0;
}
static void flushpath(void)
{
if (npath > 1) {
printf("0 0 L\n");
npath = 0;
}
}
static struct {
char *just;
short pos;
} *j, jtypes[] = { "LB", 0, "LC", 1, "LT", 2, "CT", 3, "RT", 4, "RC", 5,
"RB", 6, "CB", 7, "CC", 8, "LN", 9, "CN",10, "RN", 11 };
void plabel(char *lbl, Ptype x, Ptype y, char *just, double angle)
{
static char jtmp[3];
if (lbl[0] == 0)
return;
for (j=jtypes; j < ENDP(jtypes) ; j++) {
if (strcmp(j->just,just) == 0)
break;
}
if (j == ENDP(jtypes)) {
err(NO, "Unknown mode `%s' in plabel(%s,...)", just, lbl);
}
else {
sendstring(lbl);
printf(" %ld %ld %ld %.5lg T\n",
(long)x, (long)y, (long)(j->pos), angle);
}
}
static Ptype xax_off, yax_off, xax_roff, yax_roff;
void alabel(char *what, char *lbl, Ptype x, Ptype y)
{
sendstring(lbl);
if (strcmp(what, "YT") == 0)
x -= yax_off;
else if (strcmp(what, "YTR") == 0)
x += yax_roff;
else if (strcmp(what, "XT") == 0)
y -= xax_off;
else if (strcmp(what, "XTR") == 0)
y += xax_roff;
printf(" %ld %ld %s\n", (long)x, (long)y, what);
}
static double prev_ps = -1;
static char fontcode[4] = "t";
void elabel(char *what, char *base, char *exponent, Ptype x, Ptype y)
{
static Ptype xsize, ysize;
Ptype off;
char *font_name = StringSave(fontcode);
double base_ps = prev_ps, exp_ps = prev_ps*0.8;
strsize(base, &xsize, &ysize, 0.0);
off = xsize;
setfont(font_name, exp_ps);
strsize(exponent, &xsize, &ysize, 0.0);
off += xsize;
if (strcmp(what,"XE") == 0) {
x += chwd/3;
plabel(exponent, x+off/2, y, "RT", 0.0);
setfont(font_name, base_ps);
plabel(base, x-off/2, y-chht/3, "LT", 0.0);
xax_off = 3*chht/2;
}
else if (strcmp(what,"YE") == 0) {
x -= chwd/3;
setfont(font_name, base_ps);
plabel(base, x-off, y-chht/3, "LB", 0.0);
setfont(font_name, exp_ps);
plabel(exponent, x, y+(chht+3)/6, "RB", 0.0);
if (off > yax_off)
yax_off = off;
setfont(font_name, base_ps);
}
else if (strcmp(what,"XER") == 0) {
x += chwd/3;
plabel(exponent, x+off/2, y+3*chht/4, "RB", 0.0);
setfont(font_name, base_ps);
plabel(base, x-off/2, y+chht/4, "LB", 0.0);
xax_roff = 3*chht/2;
}
else if (strcmp(what,"YER") == 0) {
x += chwd/2;
plabel(exponent, x+off, y+(chht+3)/6, "RB", 0.0);
setfont(font_name, base_ps);
plabel(base, x, y-chht/3, "LB", 0.0);
if (off > yax_roff)
yax_roff = off;
}
else
err(YES, "Bad call: elabel(%s,...)", what);
}
/* For the PostScript driver, there is no proper string size function --
this one gives an approximate size that is usable for determining
line spacing but not much more. The code downloaded in plt.pro uses
the PostScript rendering engine to get accurate string sizes for
centering and concatenating strings, but these are not reported back
to plt. */
void strsize(char *str, Ptype *xsize, Ptype *ysize, double angle)
{
short len;
if (fabs(angle) < 1 ) {
*xsize = chwd * strlen(str);
*ysize = chht;
}
else if (fabs(angle-90) < 1) {
*xsize = chht;
*ysize = chwd * strlen(str);
}
else
err(NO, "Bad angle %.5lg in for strsize(%s,...)", angle, str);
}
void scatterplot(PltPtr plt, Ptype x, Ptype y, Ptype yneg, Ptype ypos)
{
static char lbl[2];
flushpath();
yneg -= y;
ypos -= y;
if (plt->symbol)
printf("%d %ld %ld %ld %ld SY\n", (int)(plt->pc-'0'),
(long)yneg, (long)ypos, (long)x, (long)y);
else {
lbl[0] = plt->pc;
sendstring(lbl);
printf(" %ld %ld %ld %ld SP\n",
(long)yneg, (long)ypos, (long)x, (long)y);
}
}
void PolyDef(Ptype x, Ptype y, Const what)
{
int fill;
fill = -1;
switch (what) {
case CMOVE:
move(x, y);
break;
case CBBCONT:
case CCONT:
cont(x, y);
break;
case CFILL:
case CFILLI:
cont(x, y);
fill = 0;
break;
case CSTROKE:
cont(x, y); /* flow through */
case COSTROKE:
flushpath();
break;
case CBBFILL:
case CBBFILLI:
cont(x, y);
fill = 1;
break;
default:
err(YES, "Bad PolyDef() code %d", what);
}
if (fill >= 0) {
printf("%d F\n", fill);
npath = 0;
}
if (npath == MAXPATH)
fprintf(stderr, "Polygon path exceeds %d sections", MAXPATH);
}
void special(int what, PtrUnion arg0, PtrUnion arg1)
{
switch (what) {
case SETPTERM:
PTERMInit(arg0.c);
break;
case SETLINEWIDTH:
linewidth(*arg0.d);
break;
case SETLINEMODE:
linemod(arg0.c);
break;
case SETCOLOR: /* added 23 Feb 2001 GBM */
setcolor(arg0.c);
break;
case SETFONT:
setfont(arg0.c, *arg1.d);
break;
case SETGRAY:
flushpath(); /* flow through */
case SETGRAYD:
setgray(*arg0.d);
break;
}
}
static void PTERMInit(char *pterm)
{
double f1, f2, f3, f4, f5;
short n;
char ptmp[50];
if (pterm == 0) {
ptmp[0] = 0;
n = 1;
}
else
n = sscanf(pterm, "%s%lf%lf%lf%lf%lf", ptmp, &f1, &f2, &f3, &f4, &f5);
PTERMLookup(ptmp, "lw"); /* defines p */
if (fscl == DEFAULT)
fscl = (n > 1) ? f1 : 0.85;
if (xdim == DEFAULT)
xdim = (n > 2) ? f2 : p->xinches;
if (ydim == DEFAULT)
ydim = (n > 3) ? f3 : p->yinches;
if (xorig == DEFAULT)
xorig = (n > 4) ? f4 : 0.5*(8.25-xdim) + 0.25;
if (yorig == DEFAULT)
yorig = (n > 5) ? f5 : 0.67*(11-ydim);
default_ps = DEFAULT_PS;
xinch = yinch = 300*2;
p->xinches = xdim;
p->yinches = ydim;
p->xfull = p->xsquare = xdim * xinch;
p->yfull = ydim * yinch;
p->ch = chht = 1.1*chhtscl*fscl*default_ps/72.0*yinch + 0.5;
p->cw = chwd = 0.5*chwdscl*fscl*default_ps/72.0*xinch + 0.5;
}
static struct {
char *name;
char *code;
} *f, fonts[] = {
"Helvetica", "h",
"Helvetica-Bold", "hb",
"Helvetica-Oblique", "ho",
"Helvetica-BoldOblique", "hbo",
"Helvetica-BoldOblique", "hob",
"Courier", "c",
"Courier-Bold", "cb",
"Courier-Oblique", "co",
"Courier-BoldOblique", "cbo",
"Courier-BoldOblique", "cob",
"Times-Roman", "t",
"Times-Roman", "tr",
"Times-Italic", "ti",
"Times-Bold", "tb",
"Times-BoldItalic", "tbi",
"Times-BoldItalic", "tib", "Symbol", "s",
NULL, NULL };
static char *prev_lm="";
static void setfont(char *name, double ps)
{
static char *prev_name;
short n = 0;
char *fontname = name;
while (*fontname && n < 3) {
fontcode[n++] = *(fontname++) | 040;
while (*fontname && *(fontname++) != '-');
}
fontcode[n] = 0;
for (f = fonts; f->code != NULL && strcmp(fontcode, f->code) != 0; f++)
;
if (f->code == NULL) {
err(NO, "Unknown font: %s -- Using: %s", name, DEFAULT_FONT);
f->name = DEFAULT_FONT;
}
if (ps < 0 ) {
err(NO, "Bad font size: %.5lg -- Using %g", ps, DEFAULT_PS);
ps = DEFAULT_PS;
}
if (prev_ps != ps || prev_name != f->name) {
printf("/%s %.5lg SF\n", prev_name=f->name, prev_ps=ps);
if (*prev_lm != 0 && strcmp(prev_lm,"solid") != 0)
printf("%s setdash\n", prev_lm);
}
}
static void linewidth(double lw)
{
static double prev_lw = -1;
if (lw < 0) {
err(NO, "Bad line width: %.5lg", lw);
lw = 2;
}
if (prev_lw != lw)
printf("%.5lg LW\n", prev_lw = lw);
}
static void linemod(char *lm)
{
flushpath();
if (strcmp(prev_lm,lm))
printf("%s setdash\n", prev_lm=lm);
}
static int ored=-1, ogreen=-1, oblue=-1;
static void setgray(double grey)
{
if (grey < 0 || grey > 1) {
err(NO, "Bad grey value: %.5lg", grey);
grey = 0;
}
else if (ored >= 0) {
char greystring[8];
sprintf(greystring, "grey%02d", (int)(grey*100.0));
setcolor(greystring);
}
else
printf("%.5lg setgray\n", grey);
}
/* Added 23 February 2001 GBM */
static void setcolor(char *color)
{
int i, red, green, blue;
if (color == NULL)
red = green = blue = 0;
else if (*color == '#')
sscanf(color, "#%2x%2x%2x", &red, &green, &blue);
else {
for (i = 0; i < NCOLORS; i++) {
if (strcasecmp(color, colortab[i].name) == 0) {
red = colortab[i].red;
green = colortab[i].green;
blue = colortab[i].blue;
break;
}
}
if (i >= NCOLORS)
red = green = blue = 0;
}
if (red != ored || green != ogreen || blue != oblue) {
ored = red; ogreen = green; oblue = blue;
printf("%g %g %g setrgbcolor\n", red/255.0, green/255.0, blue/255.0);
}
}