Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / latex.trm
1 /* Hello, Emacs, this is -*-C-*-
2  * $Id: latex.trm,v 1.30.2.2 2007/05/27 05:15:28 sfeam Exp $
3  *
4  */
5
6 /* GNUPLOT - latex.trm */
7
8 /*[
9  * Copyright 1990 - 1993, 1998, 2004
10  *
11  * Permission to use, copy, and distribute this software and its
12  * documentation for any purpose with or without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and
14  * that both that copyright notice and this permission notice appear
15  * in supporting documentation.
16  *
17  * Permission to modify the software is granted, but not the right to
18  * distribute the complete modified source code.  Modifications are to
19  * be distributed as patches to the released version.  Permission to
20  * distribute binaries produced by compiling modified sources is granted,
21  * provided you
22  *   1. distribute the corresponding source modifications from the
23  *    released version in the form of a patch file along with the binaries,
24  *   2. add special version identification to distinguish your version
25  *    in addition to the base release version number,
26  *   3. provide your name and address as the primary contact for the
27  *    support of your modified version, and
28  *   4. retain our contact information in regard to use of the base
29  *    software.
30  * Permission to distribute the released version of the source code along
31  * with corresponding source modifications in the form of a patch file is
32  * granted with same provisions 2 through 4 for binary distributions.
33  *
34  * This software is provided "as is" without express or implied warranty
35  * to the extent permitted by applicable law.
36 ]*/
37
38 /*
39  * This file is included by ../term.c.
40  *
41  * This terminal driver supports:
42  *   LaTeX pictures (latex).
43  *   LaTeX pictures with emTeX specials (emtex).
44  *
45  * AUTHORS
46  *   David Kotz, Russell Lang
47  *
48  * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
49  *
50  */
51
52 /* modified to optimize use of \rule for long lines */
53 /* TLDC: modified to have nice line types */
54
55 /* the following LATEX driver has been modified by
56    Russell Lang, eln272v@monu1.cc.monash.oz from the
57    GnuTeX 1.3 driver by David Kotz, David.Kotz@Dartmouth.edu.
58    Since then it has been further extended by David Kotz.
59    EmTeX driver by Russell Lang. */
60
61 /*  9 Dec 1992  LATEX_put_text rewritten to handle \\ newlines
62                 Daniel S. Lewart (d-lewart@uiuc.edu) */
63
64 /* Since it took me a little while to figure out what is happening,
65  * I may as well write it down.
66  *  There are three length scales of interest: inches, points
67  * and dots. inches are obvious. points are the usual typesetting
68  * thing (ie approx 72 points per inch). This driver works in
69  * units of dots, which corresponds to pixels on a 300 DPI printer.
70  * We do a \setlength{unitlength}{...pt} to make teX work in
71  * terms of dots.  The ... is called LATEX_UNIT in here.
72  *   The reason I had to get involved in all of this is because
73  * font size (in pts) was not being scaled up by DOTS_PER_POINT
74  * - drd, Sept 1996
75  */
76
77 #include "driver.h"
78
79 #ifdef TERM_REGISTER
80 register_term(latex)
81 #ifdef EMTEX
82 register_term(emtex)
83 #endif
84 #endif
85
86 #ifdef TERM_PROTO
87 TERM_PUBLIC void LATEX_options __PROTO((void));
88 TERM_PUBLIC void LATEX_init __PROTO((void));
89 TERM_PUBLIC void LATEX_graphics __PROTO((void));
90 TERM_PUBLIC void LATEX_text __PROTO((void));
91 TERM_PUBLIC void LATEX_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
92 TERM_PUBLIC void LATEX_linetype __PROTO((int linetype));
93 TERM_PUBLIC void LATEX_move __PROTO((unsigned int x, unsigned int y));
94 TERM_PUBLIC void LATEX_point __PROTO((unsigned int x, unsigned int y, int number));
95 TERM_PUBLIC void LATEX_vector __PROTO((unsigned int ux, unsigned int uy));
96 TERM_PUBLIC void LATEX_arrow __PROTO((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head));
97 TERM_PUBLIC int LATEX_justify_text __PROTO((enum JUSTIFY mode));
98 TERM_PUBLIC int LATEX_text_angle __PROTO((int ang));
99 TERM_PUBLIC void LATEX_reset __PROTO((void));
100
101 #ifdef EMTEX
102 TERM_PUBLIC void EMTEX_init __PROTO((void));
103 TERM_PUBLIC void EMTEX_reset __PROTO((void));
104 TERM_PUBLIC void EMTEX_text __PROTO((void));
105 #endif
106
107 #ifdef EEPIC
108 TERM_PUBLIC void EEPIC_move __PROTO((unsigned int x, unsigned int y));
109 TERM_PUBLIC void EEPIC_vector __PROTO((unsigned int ux, unsigned int uy));
110 #endif
111
112 #define TINY_STEP 0.5           /* tiny steps for high quality lines */
113
114 #define LATEX_PTS_PER_INCH (72.27)
115 #define DOTS_PER_INCH (300)     /* resolution of printer we expect to use */
116 #define LATEX_UNIT (LATEX_PTS_PER_INCH/DOTS_PER_INCH)   /* dot size in pt */
117
118 /* 5 inches wide by 3 inches high (default) */
119 #define LATEX_XMAX (5*DOTS_PER_INCH)    /* (LATEX_PTS_PER_INCH/LATEX_UNIT*5.0) */
120 #define LATEX_YMAX (3*DOTS_PER_INCH)    /* (LATEX_PTS_PER_INCH/LATEX_UNIT*3.0) */
121
122 #define LATEX_HTIC (5*DOTS_PER_INCH/72)         /* (5 pts) */
123 #define LATEX_VTIC (5*DOTS_PER_INCH/72)         /* (5 pts) */
124 #define LATEX_HCHAR (DOTS_PER_INCH*53/10/72)    /* (5.3 pts) */
125 #define LATEX_VCHAR (DOTS_PER_INCH*11/72)       /* (11 pts) */
126 #endif
127
128
129 #ifndef TERM_PROTO_ONLY
130 #ifdef TERM_BODY
131
132 static int LATEX_posx;
133 static int LATEX_posy;
134 static int LATEX_fontsize = 10;
135 static char LATEX_font[MAX_ID_LEN+1] = "doc";
136 static enum JUSTIFY latex_justify = LEFT;
137 static int latex_angle = 0;
138
139 static TBOOLEAN latex_explicit_size = FALSE;
140 static size_units latex_explicit_units = INCHES;
141
142 /* Default line-drawing character */
143 /* the definition of plotpoint varies with linetype */
144 #define LATEX_DOT "\\usebox{\\plotpoint}"
145 #define LATEX_TINY_DOT "\\rule{1pt}{1pt}"       /* for dots plot style */
146
147 /* POINTS */
148 #define LATEX_POINT_TYPES 12    /* we supply more point types */
149
150 static const char GPFAR *GPFAR LATEX_points[] = {
151     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Diamond$}}",
152     "\\makebox(0,0){$+$}",
153     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Box$}}",
154     "\\makebox(0,0){$\\times$}",
155     "\\makebox(0,0){$\\triangle$}",
156     "\\makebox(0,0){$\\star$}",
157     "\\circle{12}", "\\circle{18}", "\\circle{24}",
158     "\\circle*{12}", "\\circle*{18}", "\\circle*{24}"
159 };
160
161 /* LINES */
162 static float LATEX_size = 0;    /* current thick of line in points */
163 static float LATEX_dotspace = 0;        /* current dotspace of line in points */
164 #define LATEX_LINE_TYPES 6      /* number of line types below */
165 #define LATEX_THIN_LINE 0       /* the thinnest solid line type */
166 static struct {
167     float size;                 /* size of dot, or thick of line in points */
168     float dotspace;             /* inter-dot space in points; 0 for lines */
169 } GPFAR LATEX_lines[] =
170
171 {
172     {0.4, 0.0},                 /* thin solid line */
173     {0.4, 5.0},                 /* thin dotted line */
174     {0.8, 0.0},                 /* thick solid line */
175     {1.0, 5.0},                 /* thick dotted line */
176     {1.2, 0.0},                 /* Thick solid line */
177     {1.0, 10.0},                /* thick widely dotted line */
178 };
179
180 /* for drawing dotted and solid lines */
181 static void LATEX_dot_line __PROTO((int x1, int x2, int y1, int y2));
182 static void LATEX_solid_line __PROTO((int x1, int x2, int y1, int y2));
183 static void LATEX_rule __PROTO((int code, double x, double y, double width, double height));
184 static void LATEX_flushdot __PROTO((void));
185 #define LATEX_flushrule() LATEX_rule(2, 0.,0.,0.,0.)    /* flush old rule */
186 static TBOOLEAN LATEX_moved = TRUE;     /* pen is up after move */
187 static float LATEX_dotsize;     /* size of LATEX_DOT in units */
188 static TBOOLEAN LATEX_needsdot = FALSE;         /* does dotted line need termination? */
189
190 #ifdef EMTEX
191 static TBOOLEAN emtex = FALSE;          /* not currently using emtex */
192 static void EMTEX_solid_line __PROTO((int x1, int x2, int y1, int y2));
193 #endif
194
195 /* ARROWS */
196 /* the set of non-vertical/non-horizontal LaTeX vector slopes */
197 /* except negatives - they are handled specially */
198 static struct vslope {
199     int dx, dy;
200 } GPFAR LATEX_slopes[] =
201
202 {
203     {1, 1},
204     {1, 2},
205     {1, 3},
206     {1, 4},
207     {2, 1},
208     {2, 3},
209     {3, 1},
210     {3, 2},
211     {3, 4},
212     {4, 1},
213     {4, 3},
214     {0, 0}                      /* terminator */
215 };
216
217 /* figure out the best arrow */
218 static void best_latex_arrow __PROTO((int, int, int, int, int, int));
219
220 enum LATEX_id { LATEX_COURIER, LATEX_ROMAN, LATEX_DEFAULT, LATEX_SIZE, LATEX_OTHER };
221
222 static struct gen_table LATEX_opts[] =
223 {
224     { "c$ourier", LATEX_COURIER },
225     { "r$oman", LATEX_ROMAN },
226     { "d$efault", LATEX_DEFAULT },
227     { "si$ze", LATEX_SIZE },
228     { NULL, LATEX_OTHER }
229 };
230
231
232 TERM_PUBLIC void
233 LATEX_options()
234 {
235     struct value a;
236     latex_explicit_size = FALSE;
237
238     while (!END_OF_COMMAND) {
239         switch(lookup_table(&LATEX_opts[0],c_token)) {
240         case LATEX_COURIER:
241             strcpy(LATEX_font, "cmtt");
242             c_token++;
243             break;
244         case LATEX_ROMAN:
245             strcpy(LATEX_font, "cmr");
246             c_token++;
247             break;
248         case LATEX_DEFAULT:
249             strcpy(LATEX_font, "doc");
250             c_token++;
251             break;
252         case LATEX_SIZE:
253             {
254             float xmax_t = 5., ymax_t = 3.;
255             c_token++;
256             latex_explicit_size = TRUE;
257             latex_explicit_units = parse_term_size(&xmax_t, &ymax_t, INCHES);
258             term->xmax = xmax_t * DOTS_PER_INCH/72;
259             term->ymax = ymax_t * DOTS_PER_INCH/72;
260             break;
261             }
262         case LATEX_OTHER:
263         default:
264             /* if isannumber? */
265             LATEX_fontsize = (int) real(const_express(&a));
266         }
267     }
268
269     /* tell gnuplot core about char. sizes. Horizontal spacing
270      * is about half the text pointsize
271      */
272     term->v_char = (unsigned int) (LATEX_fontsize * DOTS_PER_INCH / 72);
273     term->h_char = (unsigned int) (LATEX_fontsize * DOTS_PER_INCH / 144);
274
275     if (strcmp(LATEX_font, "doc")==0)
276         strncpy(term_options, "(document specific font)",MAX_LINE_LEN);
277     else
278         sprintf(term_options, "%s %d",
279                 LATEX_font[2] == 't' ? "courier" : "roman", LATEX_fontsize);
280
281     if (latex_explicit_size) {
282         if (latex_explicit_units == CM)
283             sprintf(&(term_options[strlen(term_options)]), "size %.2fcm, %.2fcm ",
284                 2.54*(float)term->xmax/(DOTS_PER_INCH),
285                 2.54*(float)term->ymax/(DOTS_PER_INCH));
286         else
287             sprintf(&(term_options[strlen(term_options)]), "size %.2fin, %.2fin ",
288                 (float)term->xmax/(DOTS_PER_INCH),
289                 (float)term->ymax/(DOTS_PER_INCH));
290     }
291
292 }
293
294
295 TERM_PUBLIC void
296 LATEX_init()
297 {
298 #ifdef EMTEX
299     emtex = FALSE;
300 #endif
301     LATEX_posx = LATEX_posy = 0;
302
303     fprintf(gpoutfile, "\
304 %% GNUPLOT: LaTeX picture\n\
305 \\setlength{\\unitlength}{%fpt}\n\
306 \\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n",
307             LATEX_UNIT);
308
309     LATEX_linetype(LT_AXIS);
310     LATEX_size = 0;
311 }
312
313 TERM_PUBLIC void
314 LATEX_graphics()
315 {
316     int xscale, yscale;
317
318     /* set size of canvas */
319     if (!latex_explicit_size) {
320         term->xmax = LATEX_XMAX;
321         term->ymax = LATEX_YMAX;
322     }
323
324     /* bounding box */
325     xscale = xsize * term->xmax;
326     yscale = ysize * term->ymax;
327
328     fprintf(gpoutfile, "\\begin{picture}(%d,%d)(0,0)\n", xscale, yscale);
329     if (strcmp(LATEX_font, "doc") != 0) {
330         fprintf(gpoutfile, "\
331 \\font\\gnuplot=%s10 at %dpt\n\
332 \\gnuplot\n",
333                 LATEX_font, LATEX_fontsize);
334     }
335 }
336
337
338 TERM_PUBLIC void
339 LATEX_text()
340 {
341     LATEX_flushrule();
342     LATEX_flushdot();
343     fputs("\\end{picture}\n", gpoutfile);
344     LATEX_posx = LATEX_posy = 0;        /* current position */
345     LATEX_moved = TRUE;         /* pen is up after move */
346 }
347
348 TERM_PUBLIC void
349 LATEX_linetype(int linetype)
350 {
351     float size;
352
353     if (linetype >= LATEX_LINE_TYPES)
354         linetype %= LATEX_LINE_TYPES;
355
356 #ifdef EMTEX
357     if (!emtex)
358 #endif
359         LATEX_flushrule();
360     LATEX_flushdot();
361
362     /* Find the new desired line thickness. */
363     /* negative linetypes (for axes) use a thin line */
364     /* only relevant for drawing axes/border in 3d */
365     size = (linetype >= 0 ? LATEX_lines[linetype].size
366             : LATEX_lines[LATEX_THIN_LINE].size);
367
368     /* If different from current size, redefine \plotpoint */
369     if (size != LATEX_size) {
370         fprintf(gpoutfile,
371                 "\\sbox{\\plotpoint}{\\rule[%.3fpt]{%.3fpt}{%.3fpt}}%%\n",
372                 -size / 2, size, size);
373 #ifdef EMTEX
374         if (emtex)              /* change line width */
375             fprintf(gpoutfile, "\\special{em:linewidth %.1fpt}%%\n", size);
376 #endif
377     }
378     LATEX_size = size;
379     LATEX_dotsize = size / LATEX_UNIT;
380     LATEX_dotspace = (linetype >= 0) ? LATEX_lines[linetype].dotspace : 0;
381     LATEX_moved = TRUE;         /* reset */
382 }
383
384 TERM_PUBLIC void
385 LATEX_move(unsigned int x, unsigned int y)
386 {
387     LATEX_flushdot();
388
389     LATEX_posx = x;
390     LATEX_posy = y;
391     LATEX_moved = TRUE;         /* reset */
392 }
393
394
395 TERM_PUBLIC void
396 LATEX_point(unsigned int x, unsigned int y, int number)
397 {
398     LATEX_move(x, y);
399
400     /* Print the character defined by 'number'; number < 0 means
401        to use a dot, otherwise one of the defined points. */
402     fprintf(gpoutfile, "\\put(%d,%d){%s}\n", x, y,
403             (number < 0 ? LATEX_TINY_DOT
404              : LATEX_points[number % LATEX_POINT_TYPES]));
405 }
406
407
408 TERM_PUBLIC void
409 LATEX_vector(unsigned int ux, unsigned int uy)
410 {
411     if (LATEX_dotspace == 0.0) {
412         /* solid line */
413 #ifdef EMTEX
414         if (emtex)
415             EMTEX_solid_line(LATEX_posx, (int) ux, LATEX_posy, (int) uy);
416         else
417 #endif
418             LATEX_solid_line(LATEX_posx, (int) ux, LATEX_posy, (int) uy);
419     } else
420         /* dotted line */
421         LATEX_dot_line(LATEX_posx, (int) ux, LATEX_posy, (int) uy);
422
423     LATEX_posx = ux;
424     LATEX_posy = uy;
425 }
426
427 static void
428 LATEX_solid_line(int x1, int x2, int y1, int y2)
429 {
430     float slope;
431     int inc;
432     float dx, dy, x, y;
433     float offset, length;
434     int code;                   /* possibly combine with previous rule */
435
436     /* we draw a solid line using the current line thickness (size) */
437     /* we do it with lots of \\rules */
438
439     if (x1 == x2 && y1 == y2) { /* zero-length line - just a dot */
440         if (LATEX_moved) {
441             LATEX_flushrule();
442             /* plot a dot */
443             fprintf(gpoutfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
444         }
445     } else {
446         code = (LATEX_moved ? 0 : 1);   /* no combine after move */
447         LATEX_moved = FALSE;
448         if (x1 == x2)           /* vertical line - special case */
449             LATEX_rule(code, (double) x1, (double) y1,
450                        LATEX_dotsize, (double) y2 - y1);
451         else if (y1 == y2)      /* horizontal line - special case */
452             LATEX_rule(code, (double) x1, (double) y1, (double) x2 - x1,
453                        LATEX_dotsize);
454         else {
455             dx = (float) x2 - x1;
456             dy = (float) y2 - y1;
457             slope = dy / dx;
458             if (ABS(slope) <= 1.0) {
459                 /* longer than high */
460                 x = GPMIN(ABS(dx), (0.25 + 1.0 / ABS(slope)) * LATEX_dotsize);
461                 offset = sign(dy) * GPMIN(LATEX_dotsize, ABS(dy));
462                 dy = dy - offset;
463                 length = x * LATEX_UNIT;
464                 inc = (x == ABS(dx) ? 1 : GPMAX(1, ABS(dy) / TINY_STEP + 0.5));
465                 if (inc == 1) {
466                     fprintf(gpoutfile, "\\put(%u,%.2f){\\rule{%.3fpt}{%.3fpt}}\n",
467                             (x2 >= x1 ? x1 : x2), ((float) y1 + y2 - LATEX_dotsize) / 2,
468                             length, LATEX_dotsize * LATEX_UNIT);
469                 } else {
470                     dy = dy / inc;
471                     dx = (dx - sign(dx) * x) / (inc - 1);
472                     fprintf(gpoutfile,
473                             "\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
474                             (dx >= 0.0 ? (float) x1 : x1 - x),
475                             (float) y1 - (ABS(dy) - offset) / 2,
476                             dx, dy, inc, length, ABS(dy) * LATEX_UNIT);
477                 }
478 /* done with one section, now smooth it */
479                 x = x / 2;
480                 dx = sign(dx) * x;
481                 dx = (float) x2 - x1 - dx;
482                 dy = (float) y2 - y1;
483                 fprintf(gpoutfile, "\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
484                         (dx >= 0.0 ? (float) x1 : x1 - x), (float) y1 - LATEX_dotsize / 2,
485                         dx, dy, x * LATEX_UNIT, LATEX_dotsize * LATEX_UNIT);
486                 LATEX_moved = TRUE;
487             } else {
488                 /* higher than long */
489                 y = GPMIN(ABS(dy), (0.25 + ABS(slope)) * LATEX_dotsize);
490                 offset = sign(dx) * GPMIN(LATEX_dotsize, ABS(dx));
491                 dx = dx - offset;
492                 length = y * LATEX_UNIT;
493                 inc = (y == ABS(dy) ? 1 : GPMAX(1, ABS(dx) / TINY_STEP + 0.5));
494                 if (inc == 1) {
495                     fprintf(gpoutfile, "\\put(%.2f,%u){\\rule{%.3fpt}{%.3fpt}}\n",
496                             ((float) x1 + x2 - LATEX_dotsize) / 2, (y2 >= y1 ? y1 : y2),
497                             LATEX_dotsize * LATEX_UNIT, length);
498                 } else {
499                     dx = dx / inc;
500                     dy = (dy - sign(dy) * y) / (inc - 1);
501                     fprintf(gpoutfile,
502                             "\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
503                             (float) x1 - (ABS(dx) - offset) / 2,
504                             (dy >= 0 ? (float) y1 : y1 - y),
505                             dx, dy, inc, ABS(dx) * LATEX_UNIT, length);
506                 }
507 /* done with one section, now smooth it */
508                 y = y / 2;
509                 dx = (float) x2 - x1;
510                 dy = sign(dy) * y;
511                 dy = (float) y2 - y1 - dy;
512                 fprintf(gpoutfile, "\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
513                         (float) x1 - LATEX_dotsize / 2, (dy >= 0.0 ? (float) y1 : y1 - y),
514                         dx, dy, LATEX_dotsize * LATEX_UNIT, y * LATEX_UNIT);
515                 LATEX_moved = TRUE;
516             }
517         }
518     }
519 }
520
521 /* Draw a \rule. Width or height may be negative; we can correct.
522  * The rule is never output immediately. The previous rule is output
523  * as-is if code is 0, and the previous rule is
524  * combined with the current rule (if possible) if code is 1.
525  * The previous rule is output, and the new one ignored, if code is 2.
526  */
527 static void
528 LATEX_rule(
529     int code,                   /* how do we treat this rule? */
530     double x, double y,
531     double width,
532     double height)
533 {
534     static float lastx, lasty;
535     static float lastw, lasth;
536     static TBOOLEAN isvalid = FALSE;    /* is 'last' data valid? */
537     TBOOLEAN combine = (code == 1);
538     TBOOLEAN flush = (code == 2);
539
540     if (!flush)
541         if (width == 0 || height == 0)
542             return;             /* ignore this rule */
543
544     if (isvalid && combine) {
545         /* try to combine new rule with old rule */
546         if ((int) lastx == (int) x && lastw == width) {         /* vertical rule */
547             if (lasth * height >= 0) {  /* same sign */
548                 lasth += height;
549                 return;
550             }
551         } else if ((int) lasty == (int) y && lasth == height) {         /* horiz rule */
552             if (lastw * width >= 0) {   /* same sign */
553                 lastw += width;
554                 return;
555             }
556         }
557         /* oh well, output last and remember the new one */
558     }
559     if (isvalid) {
560         /* output the rule */
561         if (lastw < 0) {
562             lastx += lastw;
563             lastw = -lastw;
564         }
565         if (lasth < 0) {
566             lasty += lasth;
567             lasth = -lasth;
568         }
569         /* if very small use canned dot */
570         if (lastw < LATEX_dotsize || lasth < LATEX_dotsize)
571             fprintf(gpoutfile, "\\put(%.1f,%.1f){%s}\n",
572                     lastx, lasty, LATEX_DOT);
573         else
574             fprintf(gpoutfile, "\\put(%.1f,%.1f){\\rule[%.3fpt]{%.3fpt}{%.3fpt}}\n",
575                     lastx, lasty, -LATEX_dotsize * LATEX_UNIT / 2,
576                     lastw * LATEX_UNIT, lasth * LATEX_UNIT);
577     }
578     if (flush) {
579         isvalid = FALSE;
580     } else {
581         lastx = x;
582         lasty = y;
583         lastw = width;
584         lasth = height;
585         isvalid = TRUE;
586     }
587 }
588
589 static void
590 LATEX_dot_line(int x1, int x2, int y1, int y2)
591 {
592     static float LATEX_left;    /* fraction of space left after last dot */
593
594     /* we draw a dotted line using the current dot spacing */
595
596     if (LATEX_moved)
597         LATEX_left = 1.0;       /* reset after a move */
598
599     /* zero-length line? */
600     if (x1 == x2 && y1 == y2) {
601         if (LATEX_moved)
602             /* plot a dot */
603             fprintf(gpoutfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
604     } else {
605         float dotspace = LATEX_dotspace / LATEX_UNIT;
606         float x, y;             /* current position */
607         float xinc, yinc;       /* increments */
608         float slope;            /* slope of line */
609         float lastx = -1;       /* last x point plotted */
610         float lasty = -1;       /* last y point plotted */
611         int numdots = 0;        /* number of dots in this section */
612
613         /* first, figure out increments for x and y */
614         if (x2 == x1) {
615             xinc = 0.0;
616             yinc = (y2 - y1 > 0) ? dotspace : -dotspace;
617         } else {
618             slope = ((float) y2 - y1) / ((float) x2 - x1);
619             xinc = dotspace / sqrt(1 + slope * slope) * sign(x2 - x1);
620             yinc = slope * xinc;
621         }
622
623         /* now draw the dotted line */
624         /* we take into account where we last placed a dot */
625         for (x = x1 + xinc * (1 - LATEX_left), y = y1 + yinc * (1 - LATEX_left);
626              (x2 - x) * xinc >= 0 && (y2 - y) * yinc >= 0;      /* same sign or zero */
627              lastx = x, x += xinc,
628              lasty = y, y += yinc)
629             numdots++;
630         if (numdots == 1)
631             fprintf(gpoutfile, "\\put(%.2f,%.2f){%s}\n",
632                     lastx, lasty, LATEX_DOT);
633         else if (numdots > 0)
634             fprintf(gpoutfile, "\\multiput(%u,%u)(%.3f,%.3f){%u}{%s}\n",
635                     x1, y1, xinc, yinc, numdots, LATEX_DOT);
636
637         /* how much is left over, as a fraction of dotspace? */
638         if (xinc != 0.0) {      /* xinc must be nonzero */
639             if (lastx >= 0)
640                 LATEX_left = ABS(x2 - lastx) / ABS(xinc);
641             else
642                 LATEX_left += ABS(x2 - x1) / ABS(xinc);
643         } else
644             if (lasty >= 0)
645                 LATEX_left = ABS(y2 - lasty) / ABS(yinc);
646             else
647                 LATEX_left += ABS(y2 - y1) / ABS(yinc);
648     }
649
650     LATEX_needsdot = (LATEX_left > 0);
651
652     LATEX_moved = FALSE;
653 }
654
655 static void
656 LATEX_flushdot()
657 {
658     if (LATEX_needsdot)
659         fprintf(gpoutfile, "\\put(%d,%d){%s}\n",
660                 LATEX_posx, LATEX_posy, LATEX_DOT);
661     LATEX_needsdot = FALSE;
662 }
663
664 TERM_PUBLIC void
665 LATEX_arrow(
666     unsigned int sx, unsigned int sy,
667     unsigned int ex, unsigned int ey,
668     int head)
669 {
670     best_latex_arrow(sx, sy, ex, ey, 1, head);
671
672     LATEX_posx = ex;
673     LATEX_posy = ey;
674 }
675
676 static void
677 best_latex_arrow(
678     int sx, int sy, int ex, int ey, /* start and end points */
679     int who,                    /* 1=LATEX, 2=EEPIC */
680     int head)
681 {
682     int dx = ex - sx;
683     int dy = ey - sy;
684     float m;                    /* slope of line */
685     float arrowslope;           /* slope of arrow */
686     float minerror = 0;         /* best-case error */
687     struct vslope *slope;       /* one of the slopes */
688     struct vslope *bestslope;   /* the slope with min error */
689
690     /* We try to draw a real arrow (ie, \vector). If we can't get
691        * a slope that is close, we draw a bent arrow.
692      */
693
694     if (dx == 0) {
695         /* vertical arrow */
696         fprintf(gpoutfile, "\\put(%d,%d){\\%s(0,%d){%d}}\n",
697                 sx, sy, head ? "vector" : "line",
698                 sign(ey - sy), ABS(ey - sy));
699     } else if (dy == 0) {
700         /* horizontal arrow */
701         fprintf(gpoutfile, "\\put(%d,%d){\\%s(%d,0){%d}}\n",
702                 sx, sy, head ? "vector" : "line",
703                 sign(ex - sx), ABS(ex - sx));
704     } else {
705         /* Slanted arrow. We'll give it a try.
706          * we try to find the closest-slope arrowhead.
707          */
708         bestslope = NULL;
709         minerror = 0;           /* to shut up turbo C */
710         m = ABS((float) dy / dx);       /* the slope we want */
711         for (slope = LATEX_slopes; slope->dx != 0.0; slope++) {
712             /* find the slope of the arrow */
713             arrowslope = (float) slope->dy / slope->dx;
714             if (bestslope == NULL || ABS(m - arrowslope) < minerror) {
715                 minerror = ABS(m - arrowslope);
716                 bestslope = slope;
717             }
718         }
719
720         /* now we have the best slope arrow */
721         /* maybe it's exactly the right slope! */
722         if (minerror == 0.0)    /* unlikely but possible */
723             fprintf(gpoutfile, "\\put(%d,%d){\\%s(%d,%d){%d}}\n",
724                     sx, sy, head ? "vector" : "line",
725                     bestslope->dx * sign(ex - sx), bestslope->dy * sign(ey - sy),
726                     ABS(ex - sx));
727         else {
728             /* we draw the line the usual way, with thin lines */
729 #ifdef EMTEX
730             if (emtex) {
731                 LATEX_linetype(LATEX_THIN_LINE);
732                 EMTEX_solid_line(sx, ex, sy, ey);
733             } else
734 #endif
735             if (who == 1) {
736                 LATEX_linetype(LATEX_THIN_LINE);
737                 LATEX_solid_line(sx, ex, sy, ey);
738             }
739 #ifdef EEPIC
740             else {
741                 EEPIC_move(sx, sy);
742                 EEPIC_vector(ex, ey);
743             }
744 #endif /* EEPIC */
745             /* and then draw an arrowhead (a short vector) there */
746             if (head)
747                 fprintf(gpoutfile, "\\put(%d,%d){\\vector(%d,%d){0}}\n",
748                         ex, ey,
749                         bestslope->dx * sign(ex - sx), bestslope->dy * sign(ey - sy));
750         }
751     }
752 }
753
754 TERM_PUBLIC void
755 LATEX_put_text(unsigned int x, unsigned int y, const char str[])
756 {
757     static const char *justify[] = { "[l]", "", "[r]" };
758     int flag, i;
759
760     /* ignore empty strings */
761     if (str[0] == NUL)
762         return;
763
764     for (flag = FALSE, i = 0; str[i] && !flag;)
765         flag = (str[i++] == '\\') && (str[i++] == '\\');
766
767     fprintf(gpoutfile, "\\put(%d,%d)", x, y);
768     if ((str[0] == '{') || (str[0] == '[')) {
769         fprintf(gpoutfile, "{\\makebox(0,0)%s}\n", str);
770     } else if (flag)
771         fprintf(gpoutfile, "{\\makebox(0,0)%s{\\shortstack{%s}}}\n",
772                 justify[latex_justify], str);
773     else
774         fprintf(gpoutfile, "{\\makebox(0,0)%s{%s}}\n",
775                 justify[latex_justify], str);
776 }
777
778 TERM_PUBLIC int
779 LATEX_justify_text(enum JUSTIFY mode)
780 {
781     latex_justify = mode;
782     return (TRUE);
783 }
784
785 TERM_PUBLIC int
786 LATEX_text_angle(int ang)
787 {
788     /* we can't really write text vertically, but this will
789        put the ylabel centred at the left of the plot, and
790        then we'll make a \shortstack */
791     latex_angle = (ang ? 1 : 0);
792     return (TRUE);
793 }
794
795 TERM_PUBLIC void
796 LATEX_reset()
797 {
798     LATEX_posx = LATEX_posy = 0;        /* current position */
799     LATEX_moved = TRUE;         /* pen is up after move */
800 }
801
802
803 #ifdef EMTEX
804
805 TERM_PUBLIC void
806 EMTEX_init()
807 {
808     emtex = TRUE;
809     LATEX_posx = LATEX_posy = 0;
810     fprintf(gpoutfile, "\
811 %% GNUPLOT: LaTeX picture with emtex specials\n\
812 \\setlength{\\unitlength}{%fpt}\n\
813 \\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n",
814             LATEX_UNIT);
815     LATEX_linetype(LT_AXIS);
816 }
817
818
819 TERM_PUBLIC void
820 EMTEX_reset()
821 {
822     emtex = FALSE;
823     LATEX_posx = LATEX_posy = 0;
824 }
825
826
827 TERM_PUBLIC void
828 EMTEX_text()
829 {
830     fputs("\\end{picture}\n", gpoutfile);
831 }
832
833
834 static void
835 EMTEX_solid_line(int x1, int x2, int y1, int y2)
836 {
837     /* emtex special solid line */
838     if (LATEX_moved)
839         fprintf(gpoutfile, "\\put(%d,%d){\\special{em:moveto}}\n", x1, y1);
840     if ((x1 != x2) || (y1 != y2))
841         fprintf(gpoutfile, "\\put(%d,%d){\\special{em:lineto}}\n", x2, y2);
842     LATEX_posx = x2;
843     LATEX_posy = y2;
844     LATEX_moved = FALSE;
845 }
846
847
848 #endif /* EMTEX */
849
850 #endif /* TERM_BODY */
851 #endif /* TERM_PROTO_ONLY */
852
853 #ifdef TERM_TABLE
854
855 TERM_TABLE_START(latex_driver)
856     "latex", "LaTeX picture environment",
857     LATEX_XMAX, LATEX_YMAX, LATEX_VCHAR, LATEX_HCHAR,
858     LATEX_VTIC, LATEX_HTIC, LATEX_options, LATEX_init, LATEX_reset,
859     LATEX_text, null_scale, LATEX_graphics, LATEX_move, LATEX_vector,
860     LATEX_linetype, LATEX_put_text, LATEX_text_angle,
861     LATEX_justify_text, LATEX_point, LATEX_arrow, set_font_null
862 TERM_TABLE_END(latex_driver)
863
864 #undef LAST_TERM
865 #define LAST_TERM latex_driver
866
867
868 #ifdef EMTEX
869 TERM_TABLE_START(emtex_driver)
870     "emtex", "LaTeX picture environment with emTeX specials",
871     LATEX_XMAX, LATEX_YMAX, LATEX_VCHAR, LATEX_HCHAR,
872     LATEX_VTIC, LATEX_HTIC, LATEX_options, EMTEX_init, EMTEX_reset,
873     EMTEX_text, null_scale, LATEX_graphics, LATEX_move, LATEX_vector,
874     LATEX_linetype, LATEX_put_text, LATEX_text_angle,
875     LATEX_justify_text, LATEX_point, LATEX_arrow, set_font_null
876 TERM_TABLE_END(emtex_driver)
877
878 #undef LAST_TERM
879 #define LAST_TERM emtex_driver
880
881 #endif /* EMTEX */
882 #endif /* TERM_TABLE */
883
884
885 #ifdef TERM_HELP
886 START_HELP(latex)
887 "1 latex",
888 "?commands set terminal emtex",
889 "?set terminal emtex",
890 "?set term emtex",
891 "?terminal emtex",
892 "?term emtex",
893 "?emtex",
894 "?commands set terminal latex",
895 "?set terminal latex",
896 "?set term latex",
897 "?terminal latex",
898 "?term latex",
899 "?latex",
900 " Syntax:",
901 "       set terminal {latex | emtex} {default | {courier|roman} {<fontsize>}}",
902 "                    {size <XX>{unit}, <YY>{unit}}",
903 "",
904 " By default the plot will inherit font settings from the embedding document.",
905 " You have the option of forcing either Courier (cmtt) or Roman (cmr) fonts",
906 " instead. In this case you may also specify a fontsize.",
907 " Unless your driver is capable of building fonts at any size (e.g. dvips),",
908 " stick to the standard 10, 11 and 12 point sizes.",
909 "",
910 " METAFONT users beware: METAFONT does not like odd sizes.",
911 "",
912 " All drivers for LaTeX offer a special way of controlling text positioning:",
913 " If any text string begins with '{', you also need to include a '}' at the",
914 " end of the text, and the whole text will be centered both horizontally and",
915 " vertically.  If the text string begins with '[', you need to follow this with",
916 " a position specification (up to two out of t,b,l,r), ']{', the text itself,",
917 " and finally '}'.  The text itself may be anything LaTeX can typeset as an",
918 " LR-box.  '\\rule{}{}'s may help for best positioning.",
919 "",
920 " Points, among other things, are drawn using the LaTeX commands \"\\Diamond\" and",
921 " \"\\Box\".  These commands no longer belong to the LaTeX2e core; they are included",
922 " in the latexsym package, which is part of the base distribution and thus part",
923 " of any LaTeX implementation.  Please do not forget to use this package.",
924 "",
925 " The default size for the plot is 5 inches by 3 inches. The `size` option",
926 " changes this to whatever the user requests. By default the X and Y sizes",
927 " are taken to be in inches, but other units are possible (currently only cm).",
928 "",
929 " Examples:",
930 " About label positioning:",
931 " Use gnuplot defaults (mostly sensible, but sometimes not really best):",
932 "        set title '\\LaTeX\\ -- $ \\gamma $'",
933 " Force centering both horizontally and vertically:",
934 "        set label '{\\LaTeX\\ -- $ \\gamma $}' at 0,0",
935 " Specify own positioning (top here):",
936 "        set xlabel '[t]{\\LaTeX\\ -- $ \\gamma $}'",
937 " The other label -- account for long ticlabels:",
938 "        set ylabel '[r]{\\LaTeX\\ -- $ \\gamma $\\rule{7mm}{0pt}}'"
939 END_HELP(latex)
940 #endif /* TERM_TABLE */