Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / latex.trm
diff --git a/term/latex.trm b/term/latex.trm
new file mode 100644 (file)
index 0000000..2913cd5
--- /dev/null
@@ -0,0 +1,940 @@
+/* Hello, Emacs, this is -*-C-*-
+ * $Id: latex.trm,v 1.30.2.2 2007/05/27 05:15:28 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
+ */
+
+#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));
+
+#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_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 12   /* we supply more point types */
+
+static const 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[] =
+
+{
+    {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_OTHER };
+
+static struct gen_table LATEX_opts[] =
+{
+    { "c$ourier", LATEX_COURIER },
+    { "r$oman", LATEX_ROMAN },
+    { "d$efault", LATEX_DEFAULT },
+    { "si$ze", LATEX_SIZE },
+    { NULL, LATEX_OTHER }
+};
+
+
+TERM_PUBLIC void
+LATEX_options()
+{
+    struct value a;
+    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_OTHER:
+       default:
+           /* if isannumber? */
+           LATEX_fontsize = (int) real(const_express(&a));
+       }
+    }
+
+    /* 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));
+    }
+
+}
+
+
+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]" };
+    int flag, i;
+
+    /* ignore empty strings */
+    if (str[0] == NUL)
+       return;
+
+    for (flag = FALSE, i = 0; str[i] && !flag;)
+       flag = (str[i++] == '\\') && (str[i++] == '\\');
+
+    fprintf(gpoutfile, "\\put(%d,%d)", x, y);
+    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);
+}
+
+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 = (ang ? 1 : 0);
+    return (TRUE);
+}
+
+TERM_PUBLIC void
+LATEX_reset()
+{
+    LATEX_posx = LATEX_posy = 0;       /* current position */
+    LATEX_moved = TRUE;                /* pen is up after move */
+}
+
+
+#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
+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
+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} {<fontsize>}}",
+"                    {size <XX>{unit}, <YY>{unit}}",
+"",
+" 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.",
+"",
+" 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).",
+"",
+" 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 */