home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CICA 1995 May
/
cica_0595_4.zip
/
cica_0595_4
/
UTIL
/
GPT34SRC
/
TERM
/
LATEX.TRM
< prev
next >
Wrap
Text File
|
1993-05-11
|
21KB
|
707 lines
/*
* $Id: latex.trm%v 3.38.2.125 1993/05/05 00:13:05 woo Exp woo $
*
*/
/* GNUPLOT - latex.trm */
/*
* Copyright (C) 1990 - 1993
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the modified code. Modifications are to be distributed
* as patches to released version.
*
* This software is provided "as is" without express or implied warranty.
*
* This file is included by ../term.c.
*
* This terminal driver supports:
* LaTeX pictures (latex).
* LaTeX pictures with emTeX specials (emtex).
*
* AUTHORS
* David Kotz, Russell Lang
*
* send your comments or suggestions to (info-gnuplot@dartmouth.edu).
*
*/
/* modified to optimize use of \rule for long lines */
/* the following LATEX driver has been modified by
Russell Lang, eln272v@monu1.cc.monash.oz from the
GnuTeX 1.3 driver by David Kotz, David.Kotz@Dartmouth.edu.
Since then it has been further extended by David Kotz.
EmTeX driver by Russell Lang. */
/* 9 Dec 1992 LATEX_put_text rewritten to handle \\ newlines
Daniel S. Lewart (d-lewart@uiuc.edu) */
#define TINY_STEP 0.5 /* tiny steps for high quality lines */
#define LATEX_PTS_PER_INCH (72.27)
#define DOTS_PER_INCH (300) /* resolution of printer we expect to use */
#define LATEX_UNIT (LATEX_PTS_PER_INCH/DOTS_PER_INCH) /* dot size in pt */
/* 5 inches wide by 3 inches high (default) */
#define LATEX_XMAX (5*DOTS_PER_INCH) /* (LATEX_PTS_PER_INCH/LATEX_UNIT*5.0) */
#define LATEX_YMAX (3*DOTS_PER_INCH) /* (LATEX_PTS_PER_INCH/LATEX_UNIT*3.0) */
#define LATEX_HTIC (5*DOTS_PER_INCH/72) /* (5./LATEX_UNIT) */
#define LATEX_VTIC (5*DOTS_PER_INCH/72) /* (5./LATEX_UNIT) */
#define LATEX_HCHAR (DOTS_PER_INCH*53/10/72) /* (5.3/LATEX_UNIT) */
#define LATEX_VCHAR (DOTS_PER_INCH*11/72) /* (11./LATEX_UNIT) */
static int LATEX_posx;
static int LATEX_posy;
int LATEX_fontsize = 10;
char LATEX_font[MAX_ID_LEN+1] = "cmr";
static enum JUSTIFY latex_justify=LEFT;
static int latex_angle=0;
/* Default line-drawing character */
/* the definition of plotpoint varies with linetype */
#define LATEX_DOT "\\usebox{\\plotpoint}"
#define LATEX_TINY_DOT "\\rule{1pt}{1pt}" /* for dots plot style */
/* POINTS */
#define LATEX_POINT_TYPES 12 /* we supply more point types */
static char GPFAR * GPFAR LATEX_points[] = {
"\\raisebox{-.8pt}{\\makebox(0,0){$\\Diamond$}}",
"\\makebox(0,0){$+$}",
"\\raisebox{-.8pt}{\\makebox(0,0){$\\Box$}}",
"\\makebox(0,0){$\\times$}",
"\\makebox(0,0){$\\triangle$}",
"\\makebox(0,0){$\\star$}",
"\\circle{12}", "\\circle{18}", "\\circle{24}",
"\\circle*{12}", "\\circle*{18}", "\\circle*{24}"
};
/* LINES */
static float LATEX_size = 0; /* current thick of line in points */
static float LATEX_dotspace = 0; /* current dotspace of line in points */
#define LATEX_LINE_TYPES 6 /* number of line types below */
#define LATEX_THIN_LINE 0 /* the thinnest solid line type */
static struct {
float size; /* size of dot, or thick of line in points */
float dotspace; /* inter-dot space in points; 0 for lines */
} GPFAR LATEX_lines[] = {
{1.0, 0.0}, /* Thick solid line */
{.35, 0.0}, /* thin solid line */
{.6, 0.0}, /* thick solid line */
{.5, 3.0}, /* dotted line */
{.5, 7.0}, /* widely dotted line */
{.5, 11.0} /* really widely dotted line */
};
/* for drawing dotted and solid lines */
static void LATEX_dot_line();
static void LATEX_solid_line();
static void LATEX_rule();
static void LATEX_flushdot();
#define LATEX_flushrule() LATEX_rule(2, 0.,0.,0.,0.) /* flush old rule */
static TBOOLEAN LATEX_moved = TRUE; /* pen is up after move */
static float LATEX_dotsize; /* size of LATEX_DOT in units */
static TBOOLEAN LATEX_needsdot = FALSE;/* does dotted line need termination? */
#ifdef EMTEX
TBOOLEAN emtex=FALSE; /* not currently using emtex */
static void EMTEX_solid_line();
#endif
/* ARROWS */
/* the set of non-vertical/non-horizontal LaTeX vector slopes */
/* except negatives - they are handled specially */
static struct vslope {
int dx, dy;
} GPFAR LATEX_slopes[] = {
{1,1}, {1,2}, {1,3}, {1,4},
{2,1}, {2,3},
{3,1}, {3,2}, {3,4},
{4,1}, {4,3},
{0,0} /* terminator */
};
static void best_latex_arrow(); /* figure out the best arrow */
LATEX_options()
{
extern struct value *const_express();
extern double real();
if (!END_OF_COMMAND) {
if (almost_equals(c_token,"c$ourier")) {
strcpy(LATEX_font,"cmtt");
c_token++;
}
else if (almost_equals(c_token,"r$oman")) {
strcpy(LATEX_font,"cmr");
c_token++;
}
else if (almost_equals(c_token,"d$efault")) {
strcpy(LATEX_font,"cmr");
LATEX_fontsize = 10;
c_token++;
}
}
if (!END_OF_COMMAND) {
struct value a;
LATEX_fontsize = (int)real(const_express(&a));
term_tbl[term].v_char = (unsigned int)(LATEX_fontsize);
term_tbl[term].h_char = (unsigned int)(LATEX_fontsize);
}
sprintf(term_options,"%s %d point", LATEX_font ? "courier" : "roman",
LATEX_fontsize);
}
LATEX_init()
{
#ifdef EMTEX
emtex = FALSE;
#endif
LATEX_posx = LATEX_posy = 0;
fprintf(outfile, "%% GNUPLOT: LaTeX picture\n");
fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
fprintf(outfile,
"\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
LATEX_linetype(-1);
LATEX_size =0;
}
LATEX_scale(xs, ys)
double xs, ys; /* scaling factors */
{
register struct termentry *t = &term_tbl[term];
/* we change the table for use in graphics.c and LATEX_graphics */
t->xmax = (unsigned int)(LATEX_XMAX * xs);
t->ymax = (unsigned int)(LATEX_YMAX * ys);
return(TRUE);
}
LATEX_graphics()
{
register struct termentry *t = &term_tbl[term];
fprintf(outfile, "\\begin{picture}(%d,%d)(0,0)\n", t->xmax, t->ymax);
fprintf(outfile, "\\font\\gnuplot=%s10 at %dpt\n", LATEX_font, LATEX_fontsize);
fprintf(outfile, "\\gnuplot\n");
}
LATEX_text()
{
LATEX_flushrule();
LATEX_flushdot();
fprintf(outfile, "\\end{picture}\n");
LATEX_posx = LATEX_posy = 0; /* current position */
LATEX_moved = TRUE; /* pen is up after move */
}
LATEX_linetype(linetype)
int linetype;
{
float size;
if (linetype >= LATEX_LINE_TYPES)
linetype %= LATEX_LINE_TYPES;
#ifdef EMTEX
if (!emtex)
#endif
LATEX_flushrule();
LATEX_flushdot();
/* Find the new desired line thickness. */
/* negative linetypes (for axes) use a thin line */
/* only relevant for drawing axes/border in 3d */
size = (linetype >= 0 ? LATEX_lines[linetype].size
: LATEX_lines[LATEX_THIN_LINE].size);
/* If different from current size, redefine \plotpoint */
if (size != LATEX_size) {
fprintf(outfile,
"\\sbox{\\plotpoint}{\\rule[%.3fpt]{%.3fpt}{%.3fpt}}%%\n",
-size/2, size, size);
#ifdef EMTEX
if (emtex) /* change line width */
fprintf(outfile, "\\special{em:linewidth %.1fpt}%%\n", size);
#endif
}
LATEX_size = size;
LATEX_dotsize = size / LATEX_UNIT;
LATEX_dotspace = (linetype >= 0) ? LATEX_lines[linetype].dotspace : 0;
LATEX_moved = TRUE; /* reset */
}
LATEX_move(x,y)
unsigned int x,y;
{
LATEX_flushdot();
LATEX_posx = x;
LATEX_posy = y;
LATEX_moved = TRUE; /* reset */
}
LATEX_point(x,y, number) /* version of line_and_point */
unsigned int x,y;
int number; /* type of point */
{
LATEX_move(x,y);
/* Print the character defined by 'number'; number < 0 means
to use a dot, otherwise one of the defined points. */
fprintf(outfile, "\\put(%d,%d){%s}\n", x, y,
(number < 0 ? LATEX_TINY_DOT
: LATEX_points[number % LATEX_POINT_TYPES]));
}
LATEX_vector(ux,uy)
unsigned int ux,uy;
{
if (LATEX_dotspace == 0.0) {
/* solid line */
#ifdef EMTEX
if (emtex)
EMTEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
else
#endif
LATEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
} else
/* dotted line */
LATEX_dot_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
LATEX_posx = ux;
LATEX_posy = uy;
}
static void
LATEX_solid_line(x1,x2, y1,y2)
int x1,x2, y1,y2;
{
float slope;
int inc;
float dx,dy,x,y;
float offset,length;
int code; /* possibly combine with previous rule */
/* we draw a solid line using the current line thickness (size) */
/* we do it with lots of \\rules */
if (x1 == x2 && y1 == y2) { /* zero-length line - just a dot */
if (LATEX_moved) {
LATEX_flushrule();
/* plot a dot */
fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
}
} else {
code = (LATEX_moved ? 0 : 1); /* no combine after move */
LATEX_moved = FALSE;
if (x1 == x2) /* vertical line - special case */
LATEX_rule(code, (double)x1, (double)y1,
LATEX_dotsize, (double)y2-y1);
else if (y1 == y2) /* horizontal line - special case */
LATEX_rule(code, (double)x1, (double)y1, (double)x2-x1,
LATEX_dotsize);
else {
dx = (float)x2-x1;
dy = (float)y2-y1;
slope = dy/dx;
if (abs(slope) <= 1.0) {
/* longer than high */
x = min(abs(dx),(0.25+1.0/abs(slope))*LATEX_dotsize);
offset = sign(dy)*min(LATEX_dotsize,abs(dy));
dy = dy - offset;
length = x*LATEX_UNIT;
inc = (x == abs(dx) ? 1 : max(1,abs(dy)/TINY_STEP+0.5));
if (inc == 1) {
fprintf(outfile,"\\put(%u,%.2f){\\rule{%.3fpt}{%.3fpt}}\n",
(x2>=x1? x1 : x2), ((float)y1+y2-LATEX_dotsize)/2,
length, LATEX_dotsize*LATEX_UNIT);
} else {
dy = dy/inc;
dx = (dx-sign(dx)*x)/(inc-1);
fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
(dx>=0.0? (float)x1 : x1-x),
(float)y1-(abs(dy)-offset)/2,
dx, dy, inc, length, abs(dy)*LATEX_UNIT);
}
/* done with one section, now smooth it */
x = x/2;
dx = sign(dx) * x;
dx = (float)x2 - x1 - dx;
dy = (float)y2 - y1;
fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
(dx>=0.0? (float)x1 : x1-x), (float)y1-LATEX_dotsize/2,
dx, dy, x*LATEX_UNIT, LATEX_dotsize*LATEX_UNIT);
LATEX_moved = TRUE;
} else {
/* higher than long */
y = min(abs(dy),(0.25+abs(slope))*LATEX_dotsize);
offset = sign(dx)*min(LATEX_dotsize,abs(dx));
dx = dx - offset;
length = y*LATEX_UNIT;
inc = (y == abs(dy) ? 1 : max(1,abs(dx)/TINY_STEP+0.5));
if (inc == 1) {
fprintf(outfile,"\\put(%.2f,%u){\\rule{%.3fpt}{%.3fpt}}\n",
((float)x1+x2-LATEX_dotsize)/2, (y2>=y1? y1 : y2),
LATEX_dotsize*LATEX_UNIT, length);
} else {
dx = dx/inc;
dy = (dy-sign(dy)*y)/(inc-1);
fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
(float)x1-(abs(dx)-offset)/2,
(dy>=0? (float)y1 : y1-y),
dx, dy, inc, abs(dx)*LATEX_UNIT, length);
}
/* done with one section, now smooth it */
y = y/2;
dx = (float)x2 - x1;
dy = sign(dy) * y;
dy = (float)y2 - y1 - dy;
fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
(float)x1-LATEX_dotsize/2, (dy>=0.0? (float)y1 : y1-y),
dx, dy, LATEX_dotsize*LATEX_UNIT, y*LATEX_UNIT);
LATEX_moved = TRUE;
}
}
}
}
/* Draw a \rule. Width or height may be negative; we can correct.
* The rule is never output immediately. The previous rule is output
* as-is if code is 0, and the previous rule is
* combined with the current rule (if possible) if code is 1.
* The previous rule is output, and the new one ignored, if code is 2.
*/
static void
LATEX_rule(code, x,y, width, height)
int code; /* how do we treat this rule? */
double x, y;
double width;
double height;
{
static float lastx, lasty;
static float lastw, lasth;
static TBOOLEAN valid = FALSE; /* is 'last' data valid? */
TBOOLEAN combine = (code == 1);
TBOOLEAN flush = (code == 2);
if (!flush)
if (width == 0 || height == 0)
return; /* ignore this rule */
if (valid && combine) {
/* try to combine new rule with old rule */
if ((int)lastx == (int)x && lastw == width) { /* vertical rule */
if (lasth * height >= 0) { /* same sign */
lasth += height;
return;
}
} else if ((int)lasty == (int)y && lasth == height){ /* horiz rule */
if (lastw * width >= 0) { /* same sign */
lastw += width;
return;
}
}
/* oh well, output last and remember the new one */
}
if (valid) {
/* output the rule */
if (lastw < 0) {
lastx += lastw;
lastw = -lastw;
}
if (lasth < 0) {
lasty += lasth;
lasth = -lasth;
}
/* if very small use canned dot */
if (lastw < LATEX_dotsize || lasth < LATEX_dotsize)
fprintf(outfile, "\\put(%.1f,%.1f){%s}\n",
lastx, lasty, LATEX_DOT);
else
fprintf(outfile, "\\put(%.1f,%.1f){\\rule[%.3fpt]{%.3fpt}{%.3fpt}}\n",
lastx, lasty, -LATEX_dotsize*LATEX_UNIT/2,
lastw*LATEX_UNIT, lasth*LATEX_UNIT);
}
if (flush) {
valid = FALSE;
} else {
lastx = x; lasty = y;
lastw = width; lasth = height;
valid = TRUE;
}
}
static void
LATEX_dot_line(x1,x2, y1,y2)
int x1,x2, y1,y2;
{
static float LATEX_left; /* fraction of space left after last dot */
#ifndef AMIGA_AC_5
extern double sqrt();
#endif
/* we draw a dotted line using the current dot spacing */
if (LATEX_moved)
LATEX_left = 1.0; /* reset after a move */
/* zero-length line? */
if (x1 == x2 && y1 == y2) {
if (LATEX_moved)
/* plot a dot */
fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
} else {
float dotspace = LATEX_dotspace / LATEX_UNIT;
float x,y; /* current position */
float xinc, yinc; /* increments */
float slope; /* slope of line */
float lastx = -1; /* last x point plotted */
float lasty = -1; /* last y point plotted */
int numdots = 0; /* number of dots in this section */
/* first, figure out increments for x and y */
if (x2 == x1) {
xinc = 0.0;
yinc = (y2-y1>0)?dotspace:-dotspace;
} else {
slope = ((float)y2-y1)/((float)x2-x1);
xinc = dotspace / sqrt(1 + slope*slope) * sign(x2-x1);
yinc = slope * xinc;
}
/* now draw the dotted line */
/* we take into account where we last placed a dot */
for (x=x1 + xinc*(1-LATEX_left), y=y1 + yinc*(1-LATEX_left);
(x2-x)*xinc >= 0 && (y2-y)*yinc >= 0; /* same sign or zero */
lastx = x, x += xinc,
lasty = y, y += yinc)
numdots++;
if (numdots == 1)
fprintf(outfile, "\\put(%.2f,%.2f){%s}\n",
lastx, lasty, LATEX_DOT);
else
fprintf(outfile, "\\multiput(%u,%u)(%.3f,%.3f){%u}{%s}\n",
x1, y1, xinc, yinc, numdots, LATEX_DOT);
/* how much is left over, as a fraction of dotspace? */
if (xinc != 0.0) /* xinc must be nonzero */
if (lastx >= 0)
LATEX_left = abs(x2 - lastx) / abs(xinc);
else
LATEX_left += abs(x2-x1) / abs(xinc);
else
if (lasty >= 0)
LATEX_left = abs(y2 - lasty) / abs(yinc);
else
LATEX_left += abs(y2-y1) / abs(yinc);
}
LATEX_needsdot = (LATEX_left > 0);
LATEX_moved = FALSE;
}
static void
LATEX_flushdot()
{
if (LATEX_needsdot)
fprintf(outfile, "\\put(%d,%d){%s}\n",
LATEX_posx, LATEX_posy, LATEX_DOT);
LATEX_needsdot = FALSE;
}
LATEX_arrow(sx,sy, ex,ey, head)
int sx,sy, ex,ey;
TBOOLEAN head;
{
best_latex_arrow(sx,sy, ex,ey, 1, head);
LATEX_posx = ex;
LATEX_posy = ey;
}
static void best_latex_arrow(sx,sy, ex,ey, who, head)
int sx,sy, ex,ey; /* start and end points */
int who; /* 1=LATEX, 2=EEPIC */
TBOOLEAN head;
{
int dx = ex - sx;
int dy = ey - sy;
float m; /* slope of line */
float arrowslope; /* slope of arrow */
float minerror = 0; /* best-case error */
struct vslope *slope; /* one of the slopes */
struct vslope *bestslope; /* the slope with min error */
/* We try to draw a real arrow (ie, \vector). If we can't get
* a slope that is close, we draw a bent arrow.
*/
if (dx == 0) {
/* vertical arrow */
fprintf(outfile, "\\put(%d,%d){\\%s(0,%d){%d}}\n",
sx, sy, head ? "vector":"line",
sign(ey-sy), abs(ey-sy));
} else if (dy == 0) {
/* horizontal arrow */
fprintf(outfile, "\\put(%d,%d){\\%s(%d,0){%d}}\n",
sx, sy, head ? "vector":"line",
sign(ex-sx), abs(ex-sx));
} else {
/* Slanted arrow. We'll give it a try.
* we try to find the closest-slope arrowhead.
*/
bestslope = NULL;
minerror = 0; /* to shut up turbo C */
m = abs((float)dy/dx); /* the slope we want */
for (slope = LATEX_slopes; slope->dx != 0.0; slope++) {
/* find the slope of the arrow */
arrowslope = (float) slope->dy / slope->dx;
if (bestslope == NULL || abs(m-arrowslope) < minerror) {
minerror = abs(m-arrowslope);
bestslope = slope;
}
}
/* now we have the best slope arrow */
/* maybe it's exactly the right slope! */
if (minerror == 0.0) /* unlikely but possible */
fprintf(outfile, "\\put(%d,%d){\\%s(%d,%d){%d}}\n",
sx, sy, head ? "vector" : "line",
bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy),
abs(ex-sx));
else {
/* we draw the line the usual way, with thin lines */
#ifdef EMTEX
if (emtex) {
LATEX_linetype(LATEX_THIN_LINE);
EMTEX_solid_line(sx,ex,sy,ey);
} else
#endif
if (who == 1) {
LATEX_linetype(LATEX_THIN_LINE);
LATEX_solid_line(sx,ex,sy,ey);
}
#ifdef EEPIC
else {
EEPIC_move(sx,sy);
EEPIC_vector(ex,ey);
}
#endif /* EEPIC */
/* and then draw an arrowhead (a short vector) there */
if (head)
fprintf(outfile, "\\put(%d,%d){\\vector(%d,%d){0}}\n",
ex, ey,
bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy));
}
}
}
LATEX_put_text(x, y, str)
int x,y; /* reference point of string */
char str[]; /* the text */
{
static char *justify[] = { "[l]", "", "[r]" };
int flag,i;
/* ignore empty strings */
if (str[0] == '\0')
return(0);
for (flag=FALSE,i=0; str[i] && !flag;)
flag = (str[i++] == '\\') && (str[i++] == '\\');
fprintf(outfile, "\\put(%d,%d)", x, y);
if (flag)
fprintf(outfile, "{\\makebox(0,0)%s{\\shortstack{%s}}}\n",
justify[latex_justify], str);
else
fprintf(outfile, "{\\makebox(0,0)%s{%s}}\n",
justify[latex_justify], str);
}
int LATEX_justify_text(mode)
enum JUSTIFY mode;
{
latex_justify = mode;
return (TRUE);
}
int LATEX_text_angle(angle)
int angle;
{
/* we can't really write text vertically, but this will
put the ylabel centred at the left of the plot, and
then we'll make a \shortstack */
latex_angle = angle;
return (TRUE);
}
LATEX_reset()
{
LATEX_posx = LATEX_posy = 0; /* current position */
LATEX_moved = TRUE; /* pen is up after move */
}
#ifdef EMTEX
EMTEX_init()
{
emtex=TRUE;
LATEX_posx = LATEX_posy = 0;
fprintf(outfile, "%% GNUPLOT: LaTeX picture with emtex specials\n");
fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
fprintf(outfile,
"\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
LATEX_linetype(-1);
}
EMTEX_reset()
{
emtex=FALSE;
LATEX_posx = LATEX_posy = 0;
}
EMTEX_text()
{
fprintf(outfile, "\\end{picture}\n");
}
static void
EMTEX_solid_line(x1,x2, y1,y2)
int x1,x2, y1,y2;
{
/* emtex special solid line */
if (LATEX_moved)
fprintf(outfile, "\\put(%d,%d){\\special{em:moveto}}\n", x1, y1);
if ( (x1!=x2) || (y1!=y2) )
fprintf(outfile, "\\put(%d,%d){\\special{em:lineto}}\n", x2, y2);
LATEX_posx = x2;
LATEX_posy = y2;
LATEX_moved = FALSE;
}
#endif /* EMTEX */