/* Hello, Emacs, this is -*-C-*- * $Id: latex.trm,v 1.37 2010/09/15 23:46:20 sfeam Exp $ * */ /* GNUPLOT - latex.trm */ /*[ * Copyright 1990 - 1993, 1998, 2004 * * 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 complete modified source code. Modifications are to * be distributed as patches to the released version. Permission to * distribute binaries produced by compiling modified sources is granted, * provided you * 1. distribute the corresponding source modifications from the * released version in the form of a patch file along with the binaries, * 2. add special version identification to distinguish your version * in addition to the base release version number, * 3. provide your name and address as the primary contact for the * support of your modified version, and * 4. retain our contact information in regard to use of the base * software. * Permission to distribute the released version of the source code along * with corresponding source modifications in the form of a patch file is * granted with same provisions 2 through 4 for binary distributions. * * This software is provided "as is" without express or implied warranty * to the extent permitted by applicable law. ]*/ /* * 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 (gnuplot-info@lists.sourceforge.net). * */ /* modified to optimize use of \rule for long lines */ /* TLDC: modified to have nice line types */ /* 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) */ /* Since it took me a little while to figure out what is happening, * I may as well write it down. * There are three length scales of interest: inches, points * and dots. inches are obvious. points are the usual typesetting * thing (ie approx 72 points per inch). This driver works in * units of dots, which corresponds to pixels on a 300 DPI printer. * We do a \setlength{unitlength}{...pt} to make teX work in * terms of dots. The ... is called LATEX_UNIT in here. * The reason I had to get involved in all of this is because * font size (in pts) was not being scaled up by DOTS_PER_POINT * - drd, Sept 1996 */ /* E A Merritt Feb 2007 - change sequence of point types to match * PostScript and other terminals. Uses symbols from amssymb package. */ /* T.Sefzick Oct 2009 - rotate text when option 'rotated' is given. * needs graphics or graphicx package. */ #include "driver.h" #ifdef TERM_REGISTER register_term(latex) #ifdef EMTEX register_term(emtex) #endif #endif #ifdef TERM_PROTO TERM_PUBLIC void LATEX_options __PROTO((void)); TERM_PUBLIC void LATEX_init __PROTO((void)); TERM_PUBLIC void LATEX_graphics __PROTO((void)); TERM_PUBLIC void LATEX_text __PROTO((void)); TERM_PUBLIC void LATEX_put_text __PROTO((unsigned int x, unsigned int y, const char str[])); TERM_PUBLIC void LATEX_linetype __PROTO((int linetype)); TERM_PUBLIC void LATEX_move __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void LATEX_point __PROTO((unsigned int x, unsigned int y, int number)); TERM_PUBLIC void LATEX_vector __PROTO((unsigned int ux, unsigned int uy)); TERM_PUBLIC void LATEX_arrow __PROTO((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head)); TERM_PUBLIC int LATEX_justify_text __PROTO((enum JUSTIFY mode)); TERM_PUBLIC int LATEX_text_angle __PROTO((int ang)); TERM_PUBLIC void LATEX_reset __PROTO((void)); TERM_PUBLIC void LATEX_fillbox __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)); #ifdef EMTEX TERM_PUBLIC void EMTEX_init __PROTO((void)); TERM_PUBLIC void EMTEX_reset __PROTO((void)); TERM_PUBLIC void EMTEX_text __PROTO((void)); #endif #ifdef EEPIC TERM_PUBLIC void EEPIC_move __PROTO((unsigned int x, unsigned int y)); TERM_PUBLIC void EEPIC_vector __PROTO((unsigned int ux, unsigned int uy)); #endif #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 pts) */ #define LATEX_VTIC (5*DOTS_PER_INCH/72) /* (5 pts) */ #define LATEX_HCHAR (DOTS_PER_INCH*53/10/72) /* (5.3 pts) */ #define LATEX_VCHAR (DOTS_PER_INCH*11/72) /* (11 pts) */ #endif #ifndef TERM_PROTO_ONLY #ifdef TERM_BODY static int LATEX_posx; static int LATEX_posy; static int LATEX_fontsize = 10; static char LATEX_font[MAX_ID_LEN+1] = "doc"; static enum JUSTIFY latex_justify = LEFT; static int latex_angle = 0; static TBOOLEAN latex_rotate = FALSE; static TBOOLEAN latex_explicit_size = FALSE; static size_units latex_explicit_units = INCHES; /* 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 15 /* we supply more point types */ static const char GPFAR *GPFAR LATEX_points[] = { "\\makebox(0,0){$+$}", "\\makebox(0,0){$\\times$}", "\\makebox(0,0){$\\ast$}", "\\raisebox{-.8pt}{\\makebox(0,0){$\\Box$}}", "\\makebox(0,0){$\\blacksquare$}", "\\makebox(0,0){$\\circ$}", "\\makebox(0,0){$\\bullet$}", "\\makebox(0,0){$\\triangle$}", "\\makebox(0,0){$\\blacktriangle$}", "\\makebox(0,0){$\\triangledown$}", "\\makebox(0,0){$\\blacktriangledown$}", "\\makebox(0,0){$\\lozenge$}", "\\makebox(0,0){$\\blacklozenge$}", "\\makebox(0,0){$\\heartsuit$}", "\\makebox(0,0){$\\spadesuit$}", }; /* 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[] = { {0.4, 0.0}, /* thin solid line */ {0.4, 5.0}, /* thin dotted line */ {0.8, 0.0}, /* thick solid line */ {1.0, 5.0}, /* thick dotted line */ {1.2, 0.0}, /* Thick solid line */ {1.0, 10.0}, /* thick widely dotted line */ }; /* for drawing dotted and solid lines */ static void LATEX_dot_line __PROTO((int x1, int x2, int y1, int y2)); static void LATEX_solid_line __PROTO((int x1, int x2, int y1, int y2)); static void LATEX_rule __PROTO((int code, double x, double y, double width, double height)); static void LATEX_flushdot __PROTO((void)); #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 static TBOOLEAN emtex = FALSE; /* not currently using emtex */ static void EMTEX_solid_line __PROTO((int x1, int x2, int y1, int y2)); #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 */ }; /* figure out the best arrow */ static void best_latex_arrow __PROTO((int, int, int, int, int, int)); enum LATEX_id { LATEX_COURIER, LATEX_ROMAN, LATEX_DEFAULT, LATEX_SIZE, LATEX_ROTATE, LATEX_NOROTATE, LATEX_OTHER }; static struct gen_table LATEX_opts[] = { { "c$ourier", LATEX_COURIER }, { "r$oman", LATEX_ROMAN }, { "d$efault", LATEX_DEFAULT }, { "si$ze", LATEX_SIZE }, { "rot$ate", LATEX_ROTATE }, { "no$rotate", LATEX_NOROTATE }, { NULL, LATEX_OTHER } }; TERM_PUBLIC void LATEX_options() { latex_explicit_size = FALSE; while (!END_OF_COMMAND) { switch(lookup_table(&LATEX_opts[0],c_token)) { case LATEX_COURIER: strcpy(LATEX_font, "cmtt"); c_token++; break; case LATEX_ROMAN: strcpy(LATEX_font, "cmr"); c_token++; break; case LATEX_DEFAULT: strcpy(LATEX_font, "doc"); c_token++; break; case LATEX_SIZE: { float xmax_t = 5., ymax_t = 3.; c_token++; latex_explicit_size = TRUE; latex_explicit_units = parse_term_size(&xmax_t, &ymax_t, INCHES); term->xmax = xmax_t * DOTS_PER_INCH/72; term->ymax = ymax_t * DOTS_PER_INCH/72; break; } case LATEX_ROTATE: latex_rotate = TRUE; c_token++; break; case LATEX_NOROTATE: latex_rotate = FALSE; c_token++; break; case LATEX_OTHER: default: /* if isannumber? */ LATEX_fontsize = int_expression(); } } /* tell gnuplot core about char. sizes. Horizontal spacing * is about half the text pointsize */ term->v_char = (unsigned int) (LATEX_fontsize * DOTS_PER_INCH / 72); term->h_char = (unsigned int) (LATEX_fontsize * DOTS_PER_INCH / 144); if (strcmp(LATEX_font, "doc")==0) strncpy(term_options, "(document specific font)",MAX_LINE_LEN); else sprintf(term_options, "%s %d", LATEX_font[2] == 't' ? "courier" : "roman", LATEX_fontsize); if (latex_explicit_size) { if (latex_explicit_units == CM) sprintf(&(term_options[strlen(term_options)]), "size %.2fcm, %.2fcm ", 2.54*(float)term->xmax/(DOTS_PER_INCH), 2.54*(float)term->ymax/(DOTS_PER_INCH)); else sprintf(&(term_options[strlen(term_options)]), "size %.2fin, %.2fin ", (float)term->xmax/(DOTS_PER_INCH), (float)term->ymax/(DOTS_PER_INCH)); } if (latex_rotate) { sprintf(&(term_options[strlen(term_options)]), " rotate"); } else { sprintf(&(term_options[strlen(term_options)]), " norotate"); } } TERM_PUBLIC void LATEX_init() { #ifdef EMTEX emtex = FALSE; #endif LATEX_posx = LATEX_posy = 0; fprintf(gpoutfile, "\ %% GNUPLOT: LaTeX picture\n\ \\setlength{\\unitlength}{%fpt}\n\ \\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n", LATEX_UNIT); LATEX_linetype(LT_AXIS); LATEX_size = 0; } TERM_PUBLIC void LATEX_graphics() { int xscale, yscale; /* set size of canvas */ if (!latex_explicit_size) { term->xmax = LATEX_XMAX; term->ymax = LATEX_YMAX; } /* bounding box */ xscale = xsize * term->xmax; yscale = ysize * term->ymax; fprintf(gpoutfile, "\\begin{picture}(%d,%d)(0,0)\n", xscale, yscale); if (strcmp(LATEX_font, "doc") != 0) { fprintf(gpoutfile, "\ \\font\\gnuplot=%s10 at %dpt\n\ \\gnuplot\n", LATEX_font, LATEX_fontsize); } } TERM_PUBLIC void LATEX_text() { LATEX_flushrule(); LATEX_flushdot(); fputs("\\end{picture}\n", gpoutfile); LATEX_posx = LATEX_posy = 0; /* current position */ LATEX_moved = TRUE; /* pen is up after move */ } TERM_PUBLIC void LATEX_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(gpoutfile, "\\sbox{\\plotpoint}{\\rule[%.3fpt]{%.3fpt}{%.3fpt}}%%\n", -size / 2, size, size); #ifdef EMTEX if (emtex) /* change line width */ fprintf(gpoutfile, "\\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 */ } TERM_PUBLIC void LATEX_move(unsigned int x, unsigned int y) { LATEX_flushdot(); LATEX_posx = x; LATEX_posy = y; LATEX_moved = TRUE; /* reset */ } TERM_PUBLIC void LATEX_point(unsigned int x, unsigned int y, int number) { LATEX_move(x, y); /* Print the character defined by 'number'; number < 0 means to use a dot, otherwise one of the defined points. */ fprintf(gpoutfile, "\\put(%d,%d){%s}\n", x, y, (number < 0 ? LATEX_TINY_DOT : LATEX_points[number % LATEX_POINT_TYPES])); } TERM_PUBLIC void LATEX_vector(unsigned int ux, unsigned int 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(int x1, int x2, int y1, int 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(gpoutfile, "\\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 = GPMIN(ABS(dx), (0.25 + 1.0 / ABS(slope)) * LATEX_dotsize); offset = sign(dy) * GPMIN(LATEX_dotsize, ABS(dy)); dy = dy - offset; length = x * LATEX_UNIT; inc = (x == ABS(dx) ? 1 : GPMAX(1, ABS(dy) / TINY_STEP + 0.5)); if (inc == 1) { fprintf(gpoutfile, "\\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(gpoutfile, "\\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(gpoutfile, "\\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 = GPMIN(ABS(dy), (0.25 + ABS(slope)) * LATEX_dotsize); offset = sign(dx) * GPMIN(LATEX_dotsize, ABS(dx)); dx = dx - offset; length = y * LATEX_UNIT; inc = (y == ABS(dy) ? 1 : GPMAX(1, ABS(dx) / TINY_STEP + 0.5)); if (inc == 1) { fprintf(gpoutfile, "\\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(gpoutfile, "\\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(gpoutfile, "\\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( int code, /* how do we treat this rule? */ double x, double y, double width, double height) { static float lastx, lasty; static float lastw, lasth; static TBOOLEAN isvalid = 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 (isvalid && 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 (isvalid) { /* 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(gpoutfile, "\\put(%.1f,%.1f){%s}\n", lastx, lasty, LATEX_DOT); else fprintf(gpoutfile, "\\put(%.1f,%.1f){\\rule[%.3fpt]{%.3fpt}{%.3fpt}}\n", lastx, lasty, -LATEX_dotsize * LATEX_UNIT / 2, lastw * LATEX_UNIT, lasth * LATEX_UNIT); } if (flush) { isvalid = FALSE; } else { lastx = x; lasty = y; lastw = width; lasth = height; isvalid = TRUE; } } static void LATEX_dot_line(int x1, int x2, int y1, int y2) { static float LATEX_left; /* fraction of space left after last dot */ /* 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(gpoutfile, "\\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(gpoutfile, "\\put(%.2f,%.2f){%s}\n", lastx, lasty, LATEX_DOT); else if (numdots > 0) fprintf(gpoutfile, "\\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(gpoutfile, "\\put(%d,%d){%s}\n", LATEX_posx, LATEX_posy, LATEX_DOT); LATEX_needsdot = FALSE; } TERM_PUBLIC void LATEX_arrow( unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head) { best_latex_arrow(sx, sy, ex, ey, 1, head); LATEX_posx = ex; LATEX_posy = ey; } static void best_latex_arrow( int sx, int sy, int ex, int ey, /* start and end points */ int who, /* 1=LATEX, 2=EEPIC */ int 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(gpoutfile, "\\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(gpoutfile, "\\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(gpoutfile, "\\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(gpoutfile, "\\put(%d,%d){\\vector(%d,%d){0}}\n", ex, ey, bestslope->dx * sign(ex - sx), bestslope->dy * sign(ey - sy)); } } } TERM_PUBLIC void LATEX_put_text(unsigned int x, unsigned int y, const char str[]) { static const char *justify[] = { "[l]", "", "[r]" }; TBOOLEAN flag = FALSE; int i; /* ignore empty strings */ if (str[0] == NUL) return; if (!latex_rotate) for (flag = FALSE, i = 0; str[i] && !flag;) flag = (str[i++] == '\\') && (str[i++] == '\\'); fprintf(gpoutfile, "\\put(%d,%d)", x, y); if (latex_rotate && latex_angle) fprintf (gpoutfile, "{\\rotatebox{%d}", latex_angle); if ((str[0] == '{') || (str[0] == '[')) { fprintf(gpoutfile, "{\\makebox(0,0)%s}\n", str); } else if (flag) fprintf(gpoutfile, "{\\makebox(0,0)%s{\\shortstack{%s}}}\n", justify[latex_justify], str); else fprintf(gpoutfile, "{\\makebox(0,0)%s{%s}}\n", justify[latex_justify], str); if (latex_rotate && latex_angle) fprintf (gpoutfile, "}"); } TERM_PUBLIC int LATEX_justify_text(enum JUSTIFY mode) { latex_justify = mode; return (TRUE); } TERM_PUBLIC int LATEX_text_angle(int ang) { /* 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 is not used elsewhere, so we use it for 'real' text rotation using '\rotatebox' */ latex_angle = ang; return (TRUE); } TERM_PUBLIC void LATEX_reset() { LATEX_posx = LATEX_posy = 0; /* current position */ LATEX_moved = TRUE; /* pen is up after move */ } TERM_PUBLIC void LATEX_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height) { /* TODO: Something other than black/white */ if ((style & 0xf) == FS_EMPTY) return; if ((style & 0xf) == FS_SOLID && (style >> 4) < 50) return; if ((style & 0xf) == FS_PATTERN && ((style >> 4) & 1) == 0) return; fprintf(gpoutfile, "\\put(%d,%d){\\rule{%gpt}{%gpt}}\n", x1, y1, width*LATEX_UNIT, height*LATEX_UNIT); } #ifdef EMTEX TERM_PUBLIC void EMTEX_init() { emtex = TRUE; LATEX_posx = LATEX_posy = 0; fprintf(gpoutfile, "\ %% GNUPLOT: LaTeX picture with emtex specials\n\ \\setlength{\\unitlength}{%fpt}\n\ \\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n", LATEX_UNIT); LATEX_linetype(LT_AXIS); } TERM_PUBLIC void EMTEX_reset() { emtex = FALSE; LATEX_posx = LATEX_posy = 0; } TERM_PUBLIC void EMTEX_text() { fputs("\\end{picture}\n", gpoutfile); } static void EMTEX_solid_line(int x1, int x2, int y1, int y2) { /* emtex special solid line */ if (LATEX_moved) fprintf(gpoutfile, "\\put(%d,%d){\\special{em:moveto}}\n", x1, y1); if ((x1 != x2) || (y1 != y2)) fprintf(gpoutfile, "\\put(%d,%d){\\special{em:lineto}}\n", x2, y2); LATEX_posx = x2; LATEX_posy = y2; LATEX_moved = FALSE; } #endif /* EMTEX */ #endif /* TERM_BODY */ #endif /* TERM_PROTO_ONLY */ #ifdef TERM_TABLE TERM_TABLE_START(latex_driver) "latex", "LaTeX picture environment", LATEX_XMAX, LATEX_YMAX, LATEX_VCHAR, LATEX_HCHAR, LATEX_VTIC, LATEX_HTIC, LATEX_options, LATEX_init, LATEX_reset, LATEX_text, null_scale, LATEX_graphics, LATEX_move, LATEX_vector, LATEX_linetype, LATEX_put_text, LATEX_text_angle, LATEX_justify_text, LATEX_point, LATEX_arrow, set_font_null, NULL, /* pointsize */ TERM_IS_LATEX, /* flags */ NULL, NULL, /* suspend, resume */ LATEX_fillbox, NULL, /* linewidth */ #ifdef USE_MOUSE NULL, NULL, NULL, NULL, NULL, #endif NULL /* Color stuff */ TERM_TABLE_END(latex_driver) #undef LAST_TERM #define LAST_TERM latex_driver #ifdef EMTEX TERM_TABLE_START(emtex_driver) "emtex", "LaTeX picture environment with emTeX specials", LATEX_XMAX, LATEX_YMAX, LATEX_VCHAR, LATEX_HCHAR, LATEX_VTIC, LATEX_HTIC, LATEX_options, EMTEX_init, EMTEX_reset, EMTEX_text, null_scale, LATEX_graphics, LATEX_move, LATEX_vector, LATEX_linetype, LATEX_put_text, LATEX_text_angle, LATEX_justify_text, LATEX_point, LATEX_arrow, set_font_null, NULL, TERM_IS_LATEX TERM_TABLE_END(emtex_driver) #undef LAST_TERM #define LAST_TERM emtex_driver #endif /* EMTEX */ #endif /* TERM_TABLE */ #ifdef TERM_HELP START_HELP(latex) "1 latex", "?commands set terminal emtex", "?set terminal emtex", "?set term emtex", "?terminal emtex", "?term emtex", "?emtex", "?commands set terminal latex", "?set terminal latex", "?set term latex", "?terminal latex", "?term latex", "?latex", " Syntax:", " set terminal {latex | emtex} {default | {courier|roman} {}}", " {size {unit}, {unit}} {rotate | norotate}", "", " By default the plot will inherit font settings from the embedding document.", " You have the option of forcing either Courier (cmtt) or Roman (cmr) fonts", " instead. In this case you may also specify a fontsize.", " Unless your driver is capable of building fonts at any size (e.g. dvips),", " stick to the standard 10, 11 and 12 point sizes.", "", " METAFONT users beware: METAFONT does not like odd sizes.", "", " All drivers for LaTeX offer a special way of controlling text positioning:", " If any text string begins with '{', you also need to include a '}' at the", " end of the text, and the whole text will be centered both horizontally and", " vertically. If the text string begins with '[', you need to follow this with", " a position specification (up to two out of t,b,l,r), ']{', the text itself,", " and finally '}'. The text itself may be anything LaTeX can typeset as an", " LR-box. '\\rule{}{}'s may help for best positioning.", "", " Points, among other things, are drawn using the LaTeX commands \"\\Diamond\" and", " \"\\Box\". These commands no longer belong to the LaTeX2e core; they are included", " in the latexsym package, which is part of the base distribution and thus part", " of any LaTeX implementation. Please do not forget to use this package.", " Other point types use symbols from the amssymb package.", "", " The default size for the plot is 5 inches by 3 inches. The `size` option", " changes this to whatever the user requests. By default the X and Y sizes", " are taken to be in inches, but other units are possible (currently only cm).", "", " If 'rotate' is specified, rotated text, especially a rotated y-axis label,", " is possible (the packages graphics or graphicx are needed). The 'stacked'", " y-axis label mechanism is then deactivated.", "", " Examples:", " About label positioning:", " Use gnuplot defaults (mostly sensible, but sometimes not really best):", " set title '\\LaTeX\\ -- $ \\gamma $'", " Force centering both horizontally and vertically:", " set label '{\\LaTeX\\ -- $ \\gamma $}' at 0,0", " Specify own positioning (top here):", " set xlabel '[t]{\\LaTeX\\ -- $ \\gamma $}'", " The other label -- account for long ticlabels:", " set ylabel '[r]{\\LaTeX\\ -- $ \\gamma $\\rule{7mm}{0pt}}'" END_HELP(latex) #endif /* TERM_TABLE */