home *** CD-ROM | disk | FTP | other *** search
/ CICA 1995 May / cica_0595_4.zip / cica_0595_4 / UTIL / GPT34SRC / TERM / LATEX.TRM < prev    next >
Text File  |  1993-05-11  |  21KB  |  707 lines

  1. /*
  2.  * $Id: latex.trm%v 3.38.2.125 1993/05/05 00:13:05 woo Exp woo $
  3.  *
  4.  */
  5.  
  6. /* GNUPLOT - latex.trm */
  7. /*
  8.  * Copyright (C) 1990 - 1993   
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software  is provided "as is" without express or implied warranty.
  21.  * 
  22.  * This file is included by ../term.c.
  23.  *
  24.  * This terminal driver supports:
  25.  *   LaTeX pictures (latex).
  26.  *   LaTeX pictures with emTeX specials (emtex). 
  27.  *
  28.  * AUTHORS
  29.  *   David Kotz, Russell Lang
  30.  *
  31.  * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
  32.  * 
  33.  */
  34.  
  35. /* modified to optimize use of \rule for long lines */
  36.  
  37. /* the following LATEX driver has been modified by 
  38.    Russell Lang, eln272v@monu1.cc.monash.oz from the
  39.    GnuTeX 1.3 driver by David Kotz, David.Kotz@Dartmouth.edu.
  40.    Since then it has been further extended by David Kotz.
  41.    EmTeX driver by Russell Lang. */
  42.  
  43. /*  9 Dec 1992  LATEX_put_text rewritten to handle \\ newlines
  44.                 Daniel S. Lewart (d-lewart@uiuc.edu) */
  45.  
  46. #define TINY_STEP 0.5    /* tiny steps for high quality lines */
  47.  
  48. #define LATEX_PTS_PER_INCH (72.27)
  49. #define DOTS_PER_INCH (300)    /* resolution of printer we expect to use */
  50. #define LATEX_UNIT (LATEX_PTS_PER_INCH/DOTS_PER_INCH) /* dot size in pt */
  51.  
  52. /* 5 inches wide by 3 inches high (default) */
  53. #define LATEX_XMAX (5*DOTS_PER_INCH)  /* (LATEX_PTS_PER_INCH/LATEX_UNIT*5.0) */
  54. #define LATEX_YMAX (3*DOTS_PER_INCH)  /* (LATEX_PTS_PER_INCH/LATEX_UNIT*3.0) */
  55.  
  56. #define LATEX_HTIC (5*DOTS_PER_INCH/72)        /* (5./LATEX_UNIT) */
  57. #define LATEX_VTIC (5*DOTS_PER_INCH/72)        /* (5./LATEX_UNIT) */
  58. #define LATEX_HCHAR (DOTS_PER_INCH*53/10/72)    /* (5.3/LATEX_UNIT) */
  59. #define LATEX_VCHAR (DOTS_PER_INCH*11/72)    /* (11./LATEX_UNIT) */
  60.  
  61. static int LATEX_posx;
  62. static int LATEX_posy;
  63. int LATEX_fontsize = 10;
  64. char LATEX_font[MAX_ID_LEN+1] = "cmr";
  65. static enum JUSTIFY latex_justify=LEFT;
  66. static int latex_angle=0;
  67.  
  68. /* Default line-drawing character */
  69. /* the definition of plotpoint varies with linetype */
  70. #define LATEX_DOT "\\usebox{\\plotpoint}"
  71. #define LATEX_TINY_DOT "\\rule{1pt}{1pt}" /* for dots plot style */
  72.  
  73. /* POINTS */
  74. #define LATEX_POINT_TYPES 12    /* we supply more point types */
  75. static char GPFAR * GPFAR LATEX_points[] = {
  76.     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Diamond$}}",
  77.     "\\makebox(0,0){$+$}",
  78.     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Box$}}",
  79.     "\\makebox(0,0){$\\times$}",
  80.     "\\makebox(0,0){$\\triangle$}",
  81.     "\\makebox(0,0){$\\star$}",
  82.     "\\circle{12}", "\\circle{18}", "\\circle{24}",
  83.     "\\circle*{12}", "\\circle*{18}", "\\circle*{24}"
  84. };
  85.  
  86. /* LINES */
  87. static float LATEX_size = 0;    /* current thick of line in points */
  88. static float LATEX_dotspace = 0; /* current dotspace of line in points */
  89. #define LATEX_LINE_TYPES 6    /* number of line types below */
  90. #define LATEX_THIN_LINE 0    /* the thinnest solid line type */
  91. static struct {
  92.     float size;            /* size of dot, or thick of line in points */
  93.     float dotspace;            /* inter-dot space in points; 0 for lines */
  94. } GPFAR LATEX_lines[] = {
  95.     {1.0, 0.0},                /* Thick solid line */
  96.     {.35, 0.0},                /* thin solid line */
  97.     {.6, 0.0},                /* thick solid line */
  98.     {.5, 3.0},                /* dotted line */
  99.     {.5, 7.0},                /* widely dotted line */
  100.     {.5, 11.0}                /* really widely dotted line */
  101. };
  102. /* for drawing dotted and solid lines */
  103. static void LATEX_dot_line();
  104. static void LATEX_solid_line();
  105. static void LATEX_rule();
  106. static void LATEX_flushdot();
  107. #define LATEX_flushrule() LATEX_rule(2, 0.,0.,0.,0.) /* flush old rule */
  108. static TBOOLEAN LATEX_moved = TRUE;    /* pen is up after move */
  109. static float LATEX_dotsize;    /* size of LATEX_DOT in units */
  110. static TBOOLEAN LATEX_needsdot = FALSE;/* does dotted line need termination? */
  111.  
  112. #ifdef EMTEX
  113. TBOOLEAN emtex=FALSE; /* not currently using emtex */
  114. static void EMTEX_solid_line();
  115. #endif
  116.  
  117. /* ARROWS */
  118. /* the set of non-vertical/non-horizontal LaTeX vector slopes */
  119. /* except negatives - they are handled specially */
  120. static struct vslope {
  121.     int dx, dy;
  122. } GPFAR LATEX_slopes[] = {
  123.     {1,1}, {1,2}, {1,3}, {1,4},
  124.     {2,1}, {2,3},
  125.     {3,1}, {3,2}, {3,4},
  126.     {4,1}, {4,3},
  127.     {0,0}                    /* terminator */
  128. };
  129. static void best_latex_arrow(); /* figure out the best arrow */
  130.  
  131. LATEX_options()
  132. {
  133.     extern struct value *const_express();
  134.     extern double real();
  135.  
  136.     if (!END_OF_COMMAND) {
  137.         if (almost_equals(c_token,"c$ourier")) {
  138.             strcpy(LATEX_font,"cmtt");
  139.             c_token++;
  140.         }
  141.         else if (almost_equals(c_token,"r$oman")) {
  142.             strcpy(LATEX_font,"cmr");
  143.             c_token++;
  144.         }
  145.         else if (almost_equals(c_token,"d$efault")) {
  146.             strcpy(LATEX_font,"cmr");
  147.             LATEX_fontsize = 10;
  148.             c_token++;
  149.         }
  150.     }
  151.     
  152.     if (!END_OF_COMMAND) {
  153.         struct value a;
  154.         LATEX_fontsize = (int)real(const_express(&a));
  155.         term_tbl[term].v_char = (unsigned int)(LATEX_fontsize);
  156.         term_tbl[term].h_char = (unsigned int)(LATEX_fontsize);
  157.     }
  158.     sprintf(term_options,"%s %d point", LATEX_font ? "courier" : "roman",
  159.         LATEX_fontsize);
  160. }
  161.  
  162.  
  163. LATEX_init()
  164. {
  165. #ifdef EMTEX
  166.     emtex = FALSE;
  167. #endif
  168.     LATEX_posx = LATEX_posy = 0;
  169.     fprintf(outfile, "%% GNUPLOT: LaTeX picture\n");
  170.     fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
  171.     fprintf(outfile, 
  172.           "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
  173.     LATEX_linetype(-1);
  174.     LATEX_size =0;
  175. }
  176.  
  177.  
  178. LATEX_scale(xs, ys)
  179.     double xs, ys;            /* scaling factors */
  180. {
  181.     register struct termentry *t = &term_tbl[term];
  182.  
  183.     /* we change the table for use in graphics.c and LATEX_graphics */
  184.     t->xmax = (unsigned int)(LATEX_XMAX * xs);
  185.     t->ymax = (unsigned int)(LATEX_YMAX * ys);
  186.  
  187.     return(TRUE);
  188. }
  189.  
  190. LATEX_graphics()
  191. {
  192.     register struct termentry *t = &term_tbl[term];
  193.  
  194.     fprintf(outfile, "\\begin{picture}(%d,%d)(0,0)\n", t->xmax, t->ymax);
  195.     fprintf(outfile, "\\font\\gnuplot=%s10 at %dpt\n", LATEX_font, LATEX_fontsize);
  196.     fprintf(outfile, "\\gnuplot\n");
  197. }
  198.  
  199.  
  200. LATEX_text()
  201. {
  202.     LATEX_flushrule();
  203.     LATEX_flushdot();
  204.     fprintf(outfile, "\\end{picture}\n");
  205.     LATEX_posx = LATEX_posy = 0; /* current position */
  206.     LATEX_moved = TRUE;    /* pen is up after move */
  207. }
  208.  
  209. LATEX_linetype(linetype)
  210.     int linetype;
  211. {
  212.     float size;
  213.  
  214.     if (linetype >= LATEX_LINE_TYPES)
  215.      linetype %= LATEX_LINE_TYPES;
  216.  
  217. #ifdef EMTEX
  218.     if (!emtex)
  219. #endif
  220.     LATEX_flushrule();
  221.     LATEX_flushdot();
  222.  
  223.     /* Find the new desired line thickness. */
  224.     /* negative linetypes (for axes) use a thin line */
  225.     /* only relevant for drawing axes/border in 3d */
  226.     size = (linetype >= 0 ? LATEX_lines[linetype].size 
  227.           : LATEX_lines[LATEX_THIN_LINE].size);
  228.  
  229.     /* If different from current size, redefine \plotpoint */
  230.     if (size != LATEX_size) {
  231.        fprintf(outfile, 
  232.              "\\sbox{\\plotpoint}{\\rule[%.3fpt]{%.3fpt}{%.3fpt}}%%\n",
  233.              -size/2, size, size);
  234. #ifdef EMTEX
  235.         if (emtex)         /* change line width */
  236.         fprintf(outfile, "\\special{em:linewidth %.1fpt}%%\n", size);
  237. #endif
  238.     }
  239.     
  240.     LATEX_size = size;
  241.     LATEX_dotsize = size / LATEX_UNIT;
  242.     LATEX_dotspace = (linetype >= 0) ? LATEX_lines[linetype].dotspace : 0;
  243.     LATEX_moved = TRUE;            /* reset */
  244. }
  245.  
  246. LATEX_move(x,y)
  247.     unsigned int x,y;
  248. {
  249.     LATEX_flushdot();
  250.  
  251.     LATEX_posx = x;
  252.     LATEX_posy = y;
  253.     LATEX_moved = TRUE;            /* reset */
  254. }
  255.  
  256.  
  257. LATEX_point(x,y, number)        /* version of line_and_point */
  258.     unsigned int x,y;
  259.     int number;                /* type of point */
  260. {
  261.     LATEX_move(x,y);
  262.     
  263.     /* Print the character defined by 'number'; number < 0 means 
  264.       to use a dot, otherwise one of the defined points. */
  265.     fprintf(outfile, "\\put(%d,%d){%s}\n", x, y, 
  266.           (number < 0 ? LATEX_TINY_DOT
  267.            : LATEX_points[number % LATEX_POINT_TYPES]));
  268. }
  269.  
  270.  
  271. LATEX_vector(ux,uy)
  272.     unsigned int ux,uy;
  273. {
  274.     if (LATEX_dotspace == 0.0) {
  275.        /* solid line */
  276. #ifdef EMTEX
  277.        if (emtex)
  278.         EMTEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  279.        else
  280. #endif
  281.         LATEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  282.     } else
  283.      /* dotted line */
  284.      LATEX_dot_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  285.  
  286.     LATEX_posx = ux;
  287.     LATEX_posy = uy;
  288. }
  289.  
  290. static void
  291. LATEX_solid_line(x1,x2, y1,y2)
  292.     int x1,x2, y1,y2;
  293. {
  294.     float slope;
  295.     int inc;
  296.     float dx,dy,x,y;
  297.     float offset,length;
  298.     int code;                /* possibly combine with previous rule */
  299.  
  300.     /* we draw a solid line using the current line thickness (size) */
  301.     /* we do it with lots of \\rules */
  302.  
  303.     if (x1 == x2 && y1 == y2) { /* zero-length line - just a dot */
  304.        if (LATEX_moved) {
  305.           LATEX_flushrule();
  306.           /* plot a dot */
  307.           fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
  308.        }
  309.     } else {
  310.        code = (LATEX_moved ? 0 : 1); /* no combine after move */
  311.            LATEX_moved = FALSE;
  312.        if (x1 == x2)        /* vertical line - special case */
  313.         LATEX_rule(code, (double)x1, (double)y1,
  314.                LATEX_dotsize, (double)y2-y1);
  315.        else if (y1 == y2)    /* horizontal line - special case */
  316.         LATEX_rule(code, (double)x1, (double)y1, (double)x2-x1,
  317.                LATEX_dotsize);
  318.        else {
  319.           dx = (float)x2-x1;
  320.           dy = (float)y2-y1;
  321.           slope = dy/dx;
  322.           if (abs(slope) <= 1.0) {
  323.             /* longer than high */
  324.             x = min(abs(dx),(0.25+1.0/abs(slope))*LATEX_dotsize);
  325.             offset = sign(dy)*min(LATEX_dotsize,abs(dy));
  326.             dy = dy - offset;
  327.             length = x*LATEX_UNIT;
  328.             inc = (x == abs(dx) ? 1 : max(1,abs(dy)/TINY_STEP+0.5));
  329.             if (inc == 1) {
  330.               fprintf(outfile,"\\put(%u,%.2f){\\rule{%.3fpt}{%.3fpt}}\n",
  331.              (x2>=x1? x1 : x2), ((float)y1+y2-LATEX_dotsize)/2,
  332.              length, LATEX_dotsize*LATEX_UNIT);
  333.             } else {
  334.               dy = dy/inc;
  335.               dx = (dx-sign(dx)*x)/(inc-1);
  336. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
  337.                (dx>=0.0? (float)x1 : x1-x), 
  338.                (float)y1-(abs(dy)-offset)/2, 
  339.                dx, dy, inc, length, abs(dy)*LATEX_UNIT);
  340.             }
  341. /* done with one section, now smooth it */
  342.             x = x/2;
  343.             dx = sign(dx) * x;
  344.             dx = (float)x2 - x1 - dx;
  345.             dy = (float)y2 - y1;
  346. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
  347.              (dx>=0.0? (float)x1 : x1-x), (float)y1-LATEX_dotsize/2,
  348.              dx, dy, x*LATEX_UNIT, LATEX_dotsize*LATEX_UNIT);
  349.                 LATEX_moved = TRUE;
  350.           } else {
  351.             /* higher than long */
  352.             y = min(abs(dy),(0.25+abs(slope))*LATEX_dotsize);
  353.             offset = sign(dx)*min(LATEX_dotsize,abs(dx));
  354.             dx = dx - offset;
  355.             length = y*LATEX_UNIT;
  356.             inc = (y == abs(dy) ? 1 : max(1,abs(dx)/TINY_STEP+0.5));
  357.             if (inc == 1) {
  358.              fprintf(outfile,"\\put(%.2f,%u){\\rule{%.3fpt}{%.3fpt}}\n",
  359.              ((float)x1+x2-LATEX_dotsize)/2, (y2>=y1? y1 : y2),
  360.              LATEX_dotsize*LATEX_UNIT, length);
  361.             } else {
  362.               dx = dx/inc;
  363.               dy = (dy-sign(dy)*y)/(inc-1);
  364. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
  365.                (float)x1-(abs(dx)-offset)/2, 
  366.                (dy>=0? (float)y1 : y1-y), 
  367.                dx, dy, inc, abs(dx)*LATEX_UNIT, length);
  368.             }
  369. /* done with one section, now smooth it */
  370.             y = y/2;
  371.             dx = (float)x2 - x1;
  372.             dy = sign(dy) * y;
  373.             dy = (float)y2 - y1 - dy;
  374. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
  375.              (float)x1-LATEX_dotsize/2, (dy>=0.0? (float)y1 : y1-y),
  376.              dx, dy, LATEX_dotsize*LATEX_UNIT, y*LATEX_UNIT);
  377.                 LATEX_moved = TRUE;
  378.           }
  379.        }
  380.     }
  381. }
  382.  
  383. /* Draw a \rule. Width or height may be negative; we can correct.
  384.  * The rule is never output immediately. The previous rule is output
  385.  * as-is if code is 0, and the previous rule is
  386.  * combined with the current rule (if possible) if code is 1.
  387.  * The previous rule is output, and the new one ignored, if code is 2.
  388.  */
  389. static void
  390. LATEX_rule(code, x,y, width, height)
  391.     int code;                /* how do we treat this rule? */
  392.     double x, y;
  393.     double width;
  394.     double height;
  395. {  
  396.     static float lastx, lasty;
  397.     static float lastw, lasth;
  398.     static TBOOLEAN valid = FALSE; /* is 'last' data valid? */
  399.     TBOOLEAN combine = (code == 1);
  400.     TBOOLEAN flush = (code == 2);
  401.  
  402.     if (!flush)
  403.      if (width == 0 || height == 0)
  404.        return;            /* ignore this rule */
  405.  
  406.     if (valid && combine) {
  407.        /* try to combine new rule with old rule */
  408.        if ((int)lastx == (int)x && lastw == width) { /* vertical rule */
  409.           if (lasth * height >= 0) { /* same sign */
  410.              lasth += height;
  411.              return;
  412.           }
  413.        } else if ((int)lasty == (int)y && lasth == height){ /* horiz rule */
  414.           if (lastw * width >= 0) { /* same sign */
  415.              lastw += width;
  416.              return;
  417.           }
  418.        }
  419.        /* oh well, output last and remember the new one */
  420.     }
  421.  
  422.     if (valid) {
  423.        /* output the rule */
  424.        if (lastw < 0) {
  425.           lastx += lastw;
  426.           lastw = -lastw;
  427.        }
  428.        if (lasth < 0) {
  429.           lasty += lasth;
  430.           lasth = -lasth;
  431.        }
  432.  
  433.        /* if very small use canned dot */
  434.        if (lastw < LATEX_dotsize || lasth < LATEX_dotsize)
  435.         fprintf(outfile, "\\put(%.1f,%.1f){%s}\n",       
  436.                lastx, lasty, LATEX_DOT);
  437.        else
  438.         fprintf(outfile, "\\put(%.1f,%.1f){\\rule[%.3fpt]{%.3fpt}{%.3fpt}}\n",
  439.                lastx, lasty, -LATEX_dotsize*LATEX_UNIT/2,
  440.                lastw*LATEX_UNIT, lasth*LATEX_UNIT);
  441.     }
  442.     
  443.     if (flush) {
  444.        valid = FALSE;
  445.     } else {
  446.        lastx = x; lasty = y;
  447.        lastw = width; lasth = height;
  448.        valid = TRUE;
  449.     }
  450. }
  451.  
  452. static void
  453. LATEX_dot_line(x1,x2, y1,y2)
  454.     int x1,x2, y1,y2;
  455. {
  456.     static float LATEX_left;    /* fraction of space left after last dot */
  457. #ifndef AMIGA_AC_5
  458.     extern double sqrt();
  459. #endif
  460.     /* we draw a dotted line using the current dot spacing */
  461.  
  462.     if (LATEX_moved)
  463.      LATEX_left = 1.0;        /* reset after a move */
  464.  
  465.     /* zero-length line? */
  466.     if (x1 == x2 && y1 == y2) {
  467.        if (LATEX_moved)
  468.         /* plot a dot */
  469.         fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
  470.     } else {
  471.        float dotspace = LATEX_dotspace / LATEX_UNIT;
  472.        float x,y;            /* current position */
  473.        float xinc, yinc;    /* increments */
  474.        float slope;        /* slope of line */
  475.        float lastx = -1;    /* last x point plotted */
  476.        float lasty = -1;    /* last y point plotted */
  477.        int numdots = 0;    /* number of dots in this section */
  478.  
  479.        /* first, figure out increments for x and y */
  480.        if (x2 == x1) {
  481.           xinc = 0.0;
  482.           yinc = (y2-y1>0)?dotspace:-dotspace;
  483.        } else {
  484.           slope = ((float)y2-y1)/((float)x2-x1);
  485.           xinc = dotspace / sqrt(1 + slope*slope) * sign(x2-x1);
  486.           yinc = slope * xinc;
  487.        }
  488.        
  489.        /* now draw the dotted line */
  490.        /* we take into account where we last placed a dot */
  491.        for (x=x1 + xinc*(1-LATEX_left), y=y1 + yinc*(1-LATEX_left);
  492.            (x2-x)*xinc >= 0 && (y2-y)*yinc >= 0; /* same sign or zero */
  493.            lastx = x, x += xinc, 
  494.            lasty = y, y += yinc)
  495.         numdots++;
  496.        if (numdots == 1)
  497.         fprintf(outfile, "\\put(%.2f,%.2f){%s}\n",
  498.            lastx, lasty, LATEX_DOT);
  499.        else
  500.         fprintf(outfile, "\\multiput(%u,%u)(%.3f,%.3f){%u}{%s}\n",
  501.                x1, y1, xinc, yinc, numdots, LATEX_DOT);
  502.  
  503.        /* how much is left over, as a fraction of dotspace? */
  504.        if (xinc != 0.0)            /* xinc must be nonzero */
  505.         if (lastx >= 0)
  506.           LATEX_left = abs(x2 - lastx) / abs(xinc);
  507.         else
  508.           LATEX_left += abs(x2-x1) / abs(xinc);
  509.        else
  510.         if (lasty >= 0)
  511.           LATEX_left = abs(y2 - lasty) / abs(yinc);
  512.         else
  513.           LATEX_left += abs(y2-y1) / abs(yinc);
  514.     }
  515.  
  516.     LATEX_needsdot = (LATEX_left > 0);
  517.  
  518.     LATEX_moved = FALSE;
  519. }
  520.  
  521. static void
  522. LATEX_flushdot()
  523. {
  524.     if (LATEX_needsdot) 
  525.      fprintf(outfile, "\\put(%d,%d){%s}\n", 
  526.             LATEX_posx, LATEX_posy, LATEX_DOT);
  527.     LATEX_needsdot = FALSE;
  528. }
  529.  
  530. LATEX_arrow(sx,sy, ex,ey, head)
  531.     int sx,sy, ex,ey;
  532.     TBOOLEAN head;
  533. {
  534.     best_latex_arrow(sx,sy, ex,ey, 1, head);
  535.  
  536.     LATEX_posx = ex;
  537.     LATEX_posy = ey;
  538. }
  539.  
  540. static void best_latex_arrow(sx,sy, ex,ey, who, head)
  541.     int sx,sy, ex,ey;        /* start and end points */
  542.     int who;                /* 1=LATEX, 2=EEPIC */
  543.     TBOOLEAN head;
  544. {
  545.     int dx = ex - sx;
  546.     int dy = ey - sy;
  547.     float m;                /* slope of line */
  548.     float arrowslope;        /* slope of arrow */
  549.     float minerror = 0;        /* best-case error */
  550.     struct vslope *slope;    /* one of the slopes */
  551.     struct vslope *bestslope;    /* the slope with min error */
  552.  
  553.     /* We try to draw a real arrow (ie, \vector). If we can't get
  554.     * a slope that is close, we draw a bent arrow.
  555.     */
  556.  
  557.     if (dx == 0) {
  558.        /* vertical arrow */
  559.        fprintf(outfile, "\\put(%d,%d){\\%s(0,%d){%d}}\n",
  560.              sx, sy, head ? "vector":"line", 
  561.              sign(ey-sy), abs(ey-sy));
  562.     } else if (dy == 0) {
  563.        /* horizontal arrow */
  564.        fprintf(outfile, "\\put(%d,%d){\\%s(%d,0){%d}}\n",
  565.              sx, sy, head ? "vector":"line",
  566.              sign(ex-sx), abs(ex-sx));
  567.     } else {
  568.        /* Slanted arrow. We'll give it a try.
  569.         * we try to find the closest-slope arrowhead.
  570.         */
  571.        bestslope = NULL;
  572.        minerror = 0; /* to shut up turbo C */
  573.        m = abs((float)dy/dx); /* the slope we want */
  574.        for (slope = LATEX_slopes; slope->dx != 0.0; slope++) {
  575.           /* find the slope of the arrow */
  576.           arrowslope = (float) slope->dy / slope->dx;
  577.           if (bestslope == NULL || abs(m-arrowslope) < minerror) {
  578.              minerror = abs(m-arrowslope);
  579.              bestslope = slope;
  580.           }
  581.        }
  582.  
  583.        /* now we have the best slope arrow */
  584.        /* maybe it's exactly the right slope! */
  585.        if (minerror == 0.0)    /* unlikely but possible */
  586.         fprintf(outfile, "\\put(%d,%d){\\%s(%d,%d){%d}}\n",
  587.                sx, sy, head ? "vector" : "line",
  588.                bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy),
  589.                abs(ex-sx));
  590.        else {
  591.           /* we draw the line the usual way, with thin lines */
  592. #ifdef EMTEX
  593.           if (emtex) {
  594.              LATEX_linetype(LATEX_THIN_LINE);
  595.              EMTEX_solid_line(sx,ex,sy,ey);
  596.           } else 
  597. #endif
  598.             if (who == 1) {
  599.                LATEX_linetype(LATEX_THIN_LINE);
  600.                LATEX_solid_line(sx,ex,sy,ey);
  601.             }
  602. #ifdef EEPIC
  603.             else {
  604.                EEPIC_move(sx,sy);
  605.                EEPIC_vector(ex,ey);
  606.             }
  607. #endif /* EEPIC */
  608.           /* and then draw an arrowhead (a short vector) there */
  609.             if (head)
  610.                   fprintf(outfile, "\\put(%d,%d){\\vector(%d,%d){0}}\n",
  611.                 ex, ey, 
  612.                 bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy));
  613.        }
  614.     }
  615. }
  616.  
  617. LATEX_put_text(x, y, str)
  618.     int x,y;            /* reference point of string */
  619.     char str[];         /* the text */
  620. {
  621.     static char *justify[] = { "[l]", "", "[r]" };
  622.     int flag,i;
  623.  
  624.     /* ignore empty strings */
  625.     if (str[0] == '\0')
  626.         return(0);
  627.  
  628.     for (flag=FALSE,i=0; str[i] && !flag;)
  629.         flag = (str[i++] == '\\') && (str[i++] == '\\');
  630.  
  631.     fprintf(outfile, "\\put(%d,%d)", x, y);
  632.     if (flag)
  633.         fprintf(outfile, "{\\makebox(0,0)%s{\\shortstack{%s}}}\n",
  634.             justify[latex_justify], str);
  635.     else
  636.         fprintf(outfile, "{\\makebox(0,0)%s{%s}}\n",
  637.             justify[latex_justify], str);
  638. }
  639.  
  640. int LATEX_justify_text(mode)
  641.     enum JUSTIFY mode;
  642. {
  643.     latex_justify = mode;
  644.     return (TRUE);
  645. }
  646.  
  647. int LATEX_text_angle(angle)
  648.     int angle;
  649. {
  650.     /* we can't really write text vertically, but this will 
  651.       put the ylabel centred at the left of the plot, and
  652.       then we'll make a \shortstack */
  653.     latex_angle = angle;
  654.     return (TRUE);
  655. }
  656.  
  657. LATEX_reset()
  658. {
  659.     LATEX_posx = LATEX_posy = 0; /* current position */
  660.     LATEX_moved = TRUE;    /* pen is up after move */
  661. }
  662.  
  663.  
  664. #ifdef EMTEX
  665.  
  666. EMTEX_init()
  667. {
  668.     emtex=TRUE;
  669.     LATEX_posx = LATEX_posy = 0;
  670.     fprintf(outfile, "%% GNUPLOT: LaTeX picture with emtex specials\n");
  671.     fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
  672.     fprintf(outfile, 
  673.           "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
  674.     LATEX_linetype(-1);
  675. }
  676.  
  677.  
  678. EMTEX_reset()
  679. {
  680.     emtex=FALSE;
  681.     LATEX_posx = LATEX_posy = 0;
  682. }
  683.  
  684.  
  685. EMTEX_text()
  686. {
  687.     fprintf(outfile, "\\end{picture}\n");
  688. }
  689.  
  690.  
  691. static void
  692. EMTEX_solid_line(x1,x2, y1,y2)
  693.     int x1,x2, y1,y2;
  694. {
  695.     /* emtex special solid line */
  696.     if (LATEX_moved)
  697.         fprintf(outfile, "\\put(%d,%d){\\special{em:moveto}}\n", x1, y1);
  698.     if ( (x1!=x2) || (y1!=y2) )
  699.         fprintf(outfile, "\\put(%d,%d){\\special{em:lineto}}\n", x2, y2);
  700.     LATEX_posx = x2;
  701.     LATEX_posy = y2;
  702.     LATEX_moved = FALSE;
  703. }
  704.  
  705.  
  706. #endif /* EMTEX */
  707.