1/* Hello, Emacs, this is -*-C-*- */
2
3/* GNUPLOT - texdraw.trm */
4
5/*[
6 * Copyright 1990 - 1993, 1998, 2004, 2018
7 *
8 * Permission to use, copy, and distribute this software and its
9 * documentation for any purpose with or without fee is hereby granted,
10 * provided that the above copyright notice appear in all copies and
11 * that both that copyright notice and this permission notice appear
12 * in supporting documentation.
13 *
14 * Permission to modify the software is granted, but not the right to
15 * distribute the complete modified source code.  Modifications are to
16 * be distributed as patches to the released version.  Permission to
17 * distribute binaries produced by compiling modified sources is granted,
18 * provided you
19 *   1. distribute the corresponding source modifications from the
20 *    released version in the form of a patch file along with the binaries,
21 *   2. add special version identification to distinguish your version
22 *    in addition to the base release version number,
23 *   3. provide your name and address as the primary contact for the
24 *    support of your modified version, and
25 *   4. retain our contact information in regard to use of the base
26 *    software.
27 * Permission to distribute the released version of the source code along
28 * with corresponding source modifications in the form of a patch file is
29 * granted with same provisions 2 through 4 for binary distributions.
30 *
31 * This software is provided "as is" without express or implied warranty
32 * to the extent permitted by applicable law.
33]*/
34
35/*
36 * This file is included by ../term.c.
37 *
38 * This terminal driver supports:
39 *   The TEXDRAW macros for LaTeX.
40 *
41 * AUTHORS
42 *   Khun Yee Fung. Modified from eepic.trm.
43 *   clipper@csd.uwo.ca
44 *   January 20, 1992
45 *
46 *   Bastian Maerkisch
47 *
48 * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
49 *
50 */
51
52/*
53 *  This file contains the texdraw terminal driver, intended for use with the
54 *  texdraw macro package for LaTeX. This is an alternative to the
55 *  latex driver. You need texdraw.sty, and texdraw.tex in the texdraw package.
56 *
57 */
58#include "driver.h"
59
60#ifdef TERM_REGISTER
61register_term(texdraw)
62#endif
63
64#ifdef TERM_PROTO
65TERM_PUBLIC void TEXDRAW_init(void);
66TERM_PUBLIC void TEXDRAW_options(void);
67TERM_PUBLIC void TEXDRAW_graphics(void);
68TERM_PUBLIC void TEXDRAW_text(void);
69TERM_PUBLIC void TEXDRAW_reset(void);
70TERM_PUBLIC void TEXDRAW_linetype(int linetype);
71TERM_PUBLIC void TEXDRAW_dashtype(int dt, t_dashtype *custom_dash_pattern);
72TERM_PUBLIC void TEXDRAW_linewidth(double linewidth);
73TERM_PUBLIC void TEXDRAW_move(unsigned int x, unsigned int y);
74TERM_PUBLIC void TEXDRAW_pointsize(double size);
75TERM_PUBLIC void TEXDRAW_point(unsigned int x, unsigned int y, int number);
76TERM_PUBLIC void TEXDRAW_vector(unsigned int ux, unsigned int uy);
77TERM_PUBLIC void TEXDRAW_arrow(unsigned int sx, unsigned int sy,
78				unsigned int ex, unsigned int ey,
79				int head);
80TERM_PUBLIC void TEXDRAW_put_text(unsigned int x, unsigned int y, const char str[]);
81TERM_PUBLIC int TEXDRAW_justify_text(enum JUSTIFY mode);
82TERM_PUBLIC int TEXDRAW_text_angle(int ang);
83TERM_PUBLIC void TEXDRAW_set_color(t_colorspec *colorspec);
84TERM_PUBLIC int TEXDRAW_make_palette(t_sm_palette *);
85TERM_PUBLIC void TEXDRAW_set_color(t_colorspec *);
86TERM_PUBLIC void TEXDRAW_fillbox(int style,
87					unsigned int x1, unsigned int y1,
88					unsigned int width, unsigned int height);
89TERM_PUBLIC void TEXDRAW_filled_polygon(int points, gpiPoint *corners);
90
91#define TEXDRAW_PTS_PER_INCH (72.27)
92/* resolution of printer we expect to use */
93#define DOTS_PER_INCH (300)
94/* dot size in pt */
95#define TEXDRAW_UNIT (TEXDRAW_PTS_PER_INCH/DOTS_PER_INCH)
96
97/* 5 inches wide by 3 inches high (default) */
98#define TEXDRAW_XMAX (5*DOTS_PER_INCH)
99#define TEXDRAW_YMAX (3*DOTS_PER_INCH)
100
101#define TEXDRAW_HTIC (5*DOTS_PER_INCH/72)	/* (5./TEXDRAW_UNIT) */
102#define TEXDRAW_VTIC (5*DOTS_PER_INCH/72)	/* (5./TEXDRAW_UNIT) */
103#define TEXDRAW_HCHAR (DOTS_PER_INCH*53/10/72)	/* (5.3/TEXDRAW_UNIT) */
104#define TEXDRAW_VCHAR (DOTS_PER_INCH*11/72)	/* (11./TEXDRAW_UNIT) */
105
106#define GOT_TEXDRAW_PROTO
107#endif
108
109#ifndef TERM_PROTO_ONLY
110#ifdef TERM_BODY
111
112/* terminate any line in progress */
113static void TEXDRAW_endline(void);
114
115/* determine gray level according to fillstyle */
116static double TEXDRAW_fill_gray(int style);
117
118static unsigned int TEXDRAW_posx;
119static unsigned int TEXDRAW_posy;
120static enum JUSTIFY TEXDRAW_justify = LEFT;
121static enum JUSTIFY TEXDRAW_last_justify = LEFT;
122static int TEXDRAW_angle = 0;
123static float TEXDRAW_scalefactor = 0.2409;
124static double TEXDRAW_xscale = 1.0, TEXDRAW_yscale = 1.0;
125
126/* for DOTS point style */
127#define TEXDRAW_TINY_DOT "\\htext{$\\cdot$}"
128
129/* POINTS */
130#define TEXDRAW_POINT_TYPES 15	/* we supply more point types */
131
132static const char * TEXDRAW_points[TEXDRAW_POINT_TYPES] = {
133    "\\htext{%s$+$}",
134    "\\htext{%s$\\times$}",
135    "\\htext{%s$\\ast$}",
136    "\\rmove(0 -8)\\htext{%s$\\Box$}",
137    "\\htext{%s$\\blacksquare$}",
138    "\\htext{%s$\\circ$}",
139    "\\htext{%s$\\bullet$}",
140    "\\htext{%s$\\triangle$}",
141    "\\htext{%s$\\blacktriangle$}",
142    "\\htext{%s$\\triangledown$}",
143    "\\htext{%s$\\blacktriangledown$}",
144    "\\htext{%s$\\lozenge$}",
145    "\\htext{%s$\\blacklozenge$}",
146    "\\htext{%s$\\heartsuit$}",
147    "\\htext{%s$\\spadesuit$}",
148};
149
150/* LINES */
151#define TEXDRAW_NUMLINES 5	/* number of linetypes below */
152static const int TEXDRAW_lines[] = {
153    2,				/* -2 border */
154    1,				/* -1 axes   */
155    2,				/*  0 solid  */
156    2,				/*  1 solid  */
157    2,				/*  2 solid  */
158};
159
160#define TEXDRAW_NUMPAT 5
161static const int TEXDRAW_dashpat[][6] = {
162    { 10, 6, 0, 0, 0, 0 },
163    {  4, 8, 0, 0, 0, 0 },
164    { 10, 6, 4, 6, 0, 0 },
165    { 10, 6, 4, 6, 4, 6 },
166};
167
168/* The line type selected most recently */
169static int TEXDRAW_last_type = 0;
170/* current line type */
171static int TEXDRAW_type;
172/* are we in the middle of a line */
173static TBOOLEAN TEXDRAW_inline = FALSE;
174/* number of points in line so far */
175static int TEXDRAW_linecount = 0;
176/* max value for linecount */
177#define TEXDRAW_LINEMAX 5
178/* linewidth scale factor */
179static double TEXDRAW_lw;
180static double TEXDRAW_last_lw;
181/* dashtype */
182static int TEXDRAW_dt;
183
184/* ARROWS */
185static char TEXDRAW_arrow_type;
186static int TEXDRAW_arrow_length;
187static int TEXDRAW_arrow_width;
188
189/* GRAY LEVEL */
190static double TEXDRAW_gray;
191static double TEXDRAW_last_gray;
192
193/* OPTIONS */
194static TBOOLEAN TEXDRAW_standalone = FALSE;
195static TBOOLEAN TEXDRAW_rounded = TRUE;
196static TBOOLEAN TEXDRAW_colortext = FALSE;
197static TBOOLEAN TEXDRAW_psarrows = TRUE;
198static TBOOLEAN TEXDRAW_texpoints = TRUE;
199static size_units TEXDRAW_explicit_units = INCHES;
200static double TEXDRAW_size_x = 5.;
201static double TEXDRAW_size_y = 3.;
202static double TEXDRAW_lw_scale = 1.;
203static double TEXDRAW_ps = 1.;
204static double TEXDRAW_background = 1.;
205
206/* option names */
207enum TEXDRAW_id { TEXDRAW_DEFAULT,
208	TEXDRAW_SIZE,
209	TEXDRAW_STANDALONE, TEXDRAW_INPUT,
210	TEXDRAW_BLACKTEXT, TEXDRAW_COLORTEXT,
211	TEXDRAW_ROUNDED, TEXDRAW_BUTT,
212	TEXDRAW_LINEWIDTH, TEXDRAW_POINTSCALE,
213	TEXDRAW_PSARROWS, TEXDRAW_GPARROWS,
214	TEXDRAW_TEXPOINTS, TEXDRAW_GPPOINTS,
215	TEXDRAW_BACKGROUND,
216	TEXDRAW_OTHER };
217
218static struct gen_table TEXDRAW_opts[] =
219{
220    { "def$ault", TEXDRAW_DEFAULT },
221    { "size", TEXDRAW_SIZE },
222    { "stand$alone", TEXDRAW_STANDALONE },
223    { "inp$ut", TEXDRAW_INPUT },
224    { "b$lacktext", TEXDRAW_BLACKTEXT },
225    { "colort$ext", TEXDRAW_COLORTEXT },
226    { "colourt$ext", TEXDRAW_COLORTEXT },
227    { "round$ed", TEXDRAW_ROUNDED },
228    { "butt", TEXDRAW_BUTT },
229    { "backg$round", TEXDRAW_BACKGROUND },
230    { "lw", TEXDRAW_LINEWIDTH },
231    { "linew$idth", TEXDRAW_LINEWIDTH },
232    { "points$cale", TEXDRAW_POINTSCALE },
233    { "ps", TEXDRAW_POINTSCALE },
234    { "psarrows", TEXDRAW_PSARROWS },
235    { "gparrows", TEXDRAW_GPARROWS },
236    { "texpoints", TEXDRAW_TEXPOINTS },
237    { "gppoints", TEXDRAW_GPPOINTS },
238    { NULL, TEXDRAW_OTHER }
239};
240
241
242TERM_PUBLIC void
243TEXDRAW_options()
244{
245    char size_str[80] = "";
246    int bg;
247
248    while (!END_OF_COMMAND) {
249	switch ((enum TEXDRAW_id) lookup_table(&TEXDRAW_opts[0], c_token)) {
250	case TEXDRAW_DEFAULT:
251	    TEXDRAW_standalone = FALSE;
252	    TEXDRAW_rounded = TRUE;
253	    TEXDRAW_colortext = TRUE;
254	    TEXDRAW_psarrows = TRUE;
255	    TEXDRAW_texpoints = TRUE;
256	    TEXDRAW_lw_scale = TEXDRAW_ps = 1.;
257	    TEXDRAW_background = 1.;
258	    TEXDRAW_size_x = 5 ;
259	    TEXDRAW_size_y = 3.;
260	    term->xmax = TEXDRAW_size_x * DOTS_PER_INCH;
261	    term->ymax = TEXDRAW_size_y * DOTS_PER_INCH;
262	    term->v_char = TEXDRAW_VCHAR;
263	    term->v_tic = TEXDRAW_VTIC;
264	    break;
265	case TEXDRAW_SIZE: {
266	    float width, height;
267
268	    c_token++;
269	    TEXDRAW_explicit_units = parse_term_size(&width, &height, INCHES);
270	    TEXDRAW_size_x = width / gp_resolution;
271	    TEXDRAW_size_y = height / gp_resolution;
272	    term->xmax = TEXDRAW_size_x * DOTS_PER_INCH;
273	    term->ymax = TEXDRAW_size_y * DOTS_PER_INCH;
274	    term->v_char = TEXDRAW_VCHAR;
275	    term->v_tic = TEXDRAW_VTIC;
276	    break;
277	}
278	case TEXDRAW_STANDALONE:
279	    TEXDRAW_standalone = TRUE;
280	    c_token++;
281	    break;
282	case TEXDRAW_INPUT:
283	    TEXDRAW_standalone = FALSE;
284	    c_token++;
285	    break;
286	case TEXDRAW_COLORTEXT:
287	    TEXDRAW_colortext = TRUE;
288	    c_token++;
289	    break;
290	case TEXDRAW_BLACKTEXT:
291	    TEXDRAW_colortext = FALSE;
292	    c_token++;
293	    break;
294	case TEXDRAW_BUTT:
295	    TEXDRAW_rounded = FALSE;
296	    c_token++;
297	    break;
298	case TEXDRAW_ROUNDED:
299	    TEXDRAW_rounded = TRUE;
300	    c_token++;
301	    break;
302	case TEXDRAW_LINEWIDTH:
303	    c_token++;
304	    TEXDRAW_lw_scale = real_expression();
305	    if (TEXDRAW_lw_scale < 0.0)
306		TEXDRAW_lw_scale = 1.0;
307	    break;
308	case TEXDRAW_POINTSCALE:
309	    c_token++;
310	    TEXDRAW_ps = real_expression();
311	    if (TEXDRAW_ps < 0.0)
312		TEXDRAW_ps = 1.0;
313	    break;
314	case TEXDRAW_BACKGROUND: {
315	    int background;
316	    int red, green, blue;
317
318	    c_token++;
319	    background = parse_color_name();
320	    red   = (double)((background >> 16) & 0xff);
321	    green = (double)((background >>  8) & 0xff);
322	    blue  = (double)( background        & 0xff);
323	    TEXDRAW_background = (red * 0.30 + green * 0.59 + blue * 0.11) / 255;
324	    break;
325	}
326	case TEXDRAW_GPARROWS:
327	    c_token++;
328	    TEXDRAW_psarrows = FALSE;
329	    break;
330	case TEXDRAW_PSARROWS:
331	    c_token++;
332	    TEXDRAW_psarrows = TRUE;
333	    break;
334	case TEXDRAW_GPPOINTS:
335	    c_token++;
336	    TEXDRAW_texpoints = FALSE;
337	    break;
338	case TEXDRAW_TEXPOINTS:
339	    c_token++;
340	    TEXDRAW_texpoints = TRUE;
341	    break;
342	default:
343	    int_error(c_token, "Unknown terminal option");
344	}
345    }
346
347    if (TEXDRAW_explicit_units == INCHES)
348	snprintf(size_str, sizeof(size_str), "size %.2fin, %.2fin", TEXDRAW_size_x, TEXDRAW_size_y);
349    else if (TEXDRAW_explicit_units == CM)
350	snprintf(size_str, sizeof(size_str), "size %.2fcm, %.2fcm", TEXDRAW_size_x * 2.54, TEXDRAW_size_y * 2.54);
351
352    // update terminal option string
353    bg = TEXDRAW_background * 255;
354    snprintf(term_options, MAX_LINE_LEN + 1,
355	"%s linewidth %.1f pointscale %.1f %stext "
356	"background \"#%02x%02x%02x\" "
357	"%sarrows %spoints %s",
358	TEXDRAW_rounded ? "rounded" : "butt",
359	TEXDRAW_lw_scale, TEXDRAW_ps,
360	TEXDRAW_colortext ? "color" : "black",
361	bg, bg, bg,
362	TEXDRAW_psarrows ? "ps" : "gp",
363	TEXDRAW_texpoints ? "tex" : "gp",
364	TEXDRAW_standalone ? "standalone" : "input");
365}
366
367
368TERM_PUBLIC void
369TEXDRAW_init()
370{
371    fputs("%% GNUPLOT: LaTeX using TEXDRAW macros\n", gpoutfile);
372    if (TEXDRAW_standalone) {
373	fputs(
374"\\documentclass[a4paper,10pt]{article}\n"\
375"\\usepackage{texdraw}\n"\
376"\\usepackage{latexsym}\n"\
377"\\usepackage{amssymb}\n"\
378"\\usepackage{xcolor}\n"
379"\\begin{document}\n",
380	    gpoutfile);
381    }
382}
383
384
385TERM_PUBLIC void
386TEXDRAW_graphics()
387{
388    static char tdg1[] = "\
389\\btexdraw\n\
390\\ifx\\pathDEFINED\\relax\\else\\let\\pathDEFINED\\relax\n\
391 \\def\\QtGfr{\\ifx (\\TGre \\let\\YhetT\\cpath\\else\\let\\YhetT\\relax\\fi\\YhetT}\n\
392 \\def\\path (#1 #2){\\move (#1 #2)\\futurelet\\TGre\\QtGfr}\n\
393 \\def\\cpath (#1 #2){\\lvec (#1 #2)\\futurelet\\TGre\\QtGfr}\n\
394\\fi\n\
395\\drawdim pt\n\
396\\setunitscale %2.2f\n\
397\\linewd %d\n\
398\\textref h:L v:C\n\
399\\writeps{%d setlinecap} \\writeps{%d setlinejoin}\n";
400
401    if (TEXDRAW_standalone)
402	fputs("\\begin{figure}\n", gpoutfile);
403    fprintf(gpoutfile, tdg1,
404	    TEXDRAW_scalefactor,
405	    TEXDRAW_lines[2],
406	    TEXDRAW_rounded ? 1 : 0, TEXDRAW_rounded ? 1 : 0
407	   );
408
409    if (TEXDRAW_background == 1.) {
410	/* enforce bounding box */
411	fprintf(gpoutfile, "\\move (0 0) \\rmove (%d %d)\n",
412		    term->xmax, term->ymax);
413    } else {
414	fprintf(gpoutfile, "\\move (0 0) \\rlvec (%d 0) \\rlvec (0 %d) \\rlvec (%d 0) \\ifill f:%0.2f\n",
415		    term->xmax, term->ymax, -term->xmax,
416		    TEXDRAW_background);
417    }
418
419    TEXDRAW_last_type = 0;
420    TEXDRAW_type = 0;
421    TEXDRAW_posx = TEXDRAW_posy = 0;
422    TEXDRAW_lw = TEXDRAW_last_lw = 1.;
423    TEXDRAW_gray = TEXDRAW_last_gray = 0.;
424    TEXDRAW_arrow_type = 0;
425    TEXDRAW_arrow_length = -1;
426    TEXDRAW_arrow_width = -1;
427    TEXDRAW_justify = TEXDRAW_last_justify = LEFT;
428}
429
430
431TERM_PUBLIC void
432TEXDRAW_text()
433{
434    TEXDRAW_endline();
435    // fputs("\\drawbb\n", gpoutfile);
436    fputs("\\etexdraw\n", gpoutfile);
437    if (TEXDRAW_standalone)
438	fputs("\\end{figure}\n\n", gpoutfile);
439}
440
441
442TERM_PUBLIC void
443TEXDRAW_reset()
444{
445    TEXDRAW_endline();
446    TEXDRAW_posx = TEXDRAW_posy = 0;
447
448    if (TEXDRAW_standalone)
449	fputs("\\end{document}\n", gpoutfile);
450}
451
452
453TERM_PUBLIC void
454TEXDRAW_linetype(int linetype)
455{
456    TEXDRAW_endline();
457
458    if (linetype >= TEXDRAW_NUMLINES - 2)
459	linetype %= (TEXDRAW_NUMLINES - 2);
460
461    TEXDRAW_type = linetype > -2 ? linetype : LT_BLACK;
462
463    if (linetype == LT_AXIS)
464	TEXDRAW_dashtype(DASHTYPE_AXIS, NULL);
465    else
466	TEXDRAW_dashtype(DASHTYPE_SOLID, NULL);
467}
468
469
470TERM_PUBLIC void
471TEXDRAW_dashtype(int dt, t_dashtype *custom_dash_pattern)
472{
473    TEXDRAW_endline();
474
475    if (dt == DASHTYPE_SOLID) {
476	dt = 0;
477    } else if (dt == DASHTYPE_AXIS) {
478	dt = 2;
479    } else if (dt > 0) {
480	dt %= TEXDRAW_NUMPAT;
481    }
482
483    if (dt == TEXDRAW_dt)
484	return;
485
486    if (dt == 0) {
487	fputs("\\lpatt ()\n", gpoutfile);
488	TEXDRAW_dt = 0;
489    } else if (dt > 0) {
490	int i;
491
492	fputs("\\lpatt (", gpoutfile);
493	for (i = 0; i < 6; i++) {
494	    if (TEXDRAW_dashpat[dt - 1][i] == 0)
495		break;
496	    fprintf(gpoutfile, "%d ", (int) (TEXDRAW_dashpat[dt - 1][i] * TEXDRAW_lw));
497	}
498	fputs(")\n", gpoutfile);
499	TEXDRAW_dt = dt;
500    } else if (dt == DASHTYPE_CUSTOM) {
501	/* not supported (yet) */
502    }
503}
504
505
506
507TERM_PUBLIC void
508TEXDRAW_linewidth(double linewidth)
509{
510    TEXDRAW_lw = linewidth * TEXDRAW_lw_scale;
511}
512
513
514TERM_PUBLIC void
515TEXDRAW_move(unsigned int x, unsigned int y)
516{
517    TEXDRAW_endline();
518
519    TEXDRAW_posx = x;
520    TEXDRAW_posy = y;
521}
522
523
524TERM_PUBLIC void
525TEXDRAW_pointsize(double size)
526{
527    // We can only scale gnuplot's native point types
528    term_pointsize = (size >= 0 ? size * TEXDRAW_ps : 1);
529}
530
531
532TERM_PUBLIC void
533TEXDRAW_point(unsigned int x, unsigned int y, int number)
534{
535    char colorstr[80] = "";
536
537    TEXDRAW_move(x, y);
538
539    if (!TEXDRAW_texpoints) {
540	do_point(x, y, number);
541	return;
542    }
543
544    /* Print the character defined by 'number'; number < 0 means
545     * to use a dot, otherwise one of the defined points. */
546    fprintf(gpoutfile, "\\move (%d %d)\n",
547	    (int) ((double) x * TEXDRAW_xscale),
548	    (int) ((double) y * TEXDRAW_yscale));
549    if (TEXDRAW_last_justify != CENTRE) {
550	fprintf(gpoutfile, "\\textref h:C v:C ");
551	TEXDRAW_last_justify = CENTRE;
552    }
553    if (TEXDRAW_colortext && TEXDRAW_gray != 0)
554	snprintf(colorstr, sizeof(colorstr), "\\color{black!%d!}", 100 - (int) (TEXDRAW_gray * 100));
555    if (number < 0) {
556	fprintf(gpoutfile, "%s\n", TEXDRAW_TINY_DOT);
557    } else {
558	fprintf(gpoutfile, TEXDRAW_points[number % TEXDRAW_POINT_TYPES], colorstr);
559	fputc('\n', gpoutfile);
560    }
561}
562
563
564TERM_PUBLIC void
565TEXDRAW_vector(unsigned int ux, unsigned int uy)
566{
567    if (!TEXDRAW_inline) {
568	TEXDRAW_inline = TRUE;
569
570	/* Start a new line. This depends on line type */
571	if ((TEXDRAW_type != TEXDRAW_last_type) || (TEXDRAW_last_lw != TEXDRAW_lw)) {
572	    if (TEXDRAW_lines[TEXDRAW_type + 2] * TEXDRAW_lw != TEXDRAW_lines[TEXDRAW_last_type + 2] * TEXDRAW_last_lw)
573		fprintf(gpoutfile, "\\linewd %d\n",
574			(int) (TEXDRAW_lines[TEXDRAW_type + 2] * TEXDRAW_lw + 0.5));
575	    TEXDRAW_last_type = TEXDRAW_type;
576	    TEXDRAW_last_lw = TEXDRAW_lw;
577	}
578	if (TEXDRAW_gray != TEXDRAW_last_gray) {
579		fprintf(gpoutfile, "\\setgray %0.2f\n", TEXDRAW_gray);
580		TEXDRAW_last_gray = TEXDRAW_gray;
581	}
582	fprintf(gpoutfile, "\\path (%d %d)",
583		(int) ((double) TEXDRAW_posx * TEXDRAW_xscale),
584		(int) ((double) TEXDRAW_posy * TEXDRAW_yscale));
585	TEXDRAW_linecount = 1;
586    } else {
587	/* Even though we are in middle of a path,
588	 * we may want to start a new path command.
589	 * If they are too long then latex will choke.
590	 */
591	if (TEXDRAW_linecount++ >= TEXDRAW_LINEMAX) {
592	    fputs("\n\\cpath ", gpoutfile);
593	    TEXDRAW_linecount = 1;
594	}
595    }
596    fprintf(gpoutfile, "(%d %d)",
597	    (int) ((double) ux * TEXDRAW_xscale),
598	    (int) ((double) uy * TEXDRAW_yscale));
599    TEXDRAW_posx = ux;
600    TEXDRAW_posy = uy;
601}
602
603
604static void
605TEXDRAW_endline()
606{
607    if (TEXDRAW_inline) {
608	putc('\n', gpoutfile);
609	TEXDRAW_inline = FALSE;
610    }
611}
612
613
614TERM_PUBLIC void
615TEXDRAW_arrow(
616    unsigned int sx, unsigned int sy,
617    unsigned int ex, unsigned int ey,
618    int head)
619{
620    char text;
621    char type = 'T'; // empty triangle
622    // These are the default arrow sizes:
623    int tiplen = (0.16 * 72 / TEXDRAW_scalefactor + 0.5);
624    int width = (0.08 * 72 / TEXDRAW_scalefactor + 0.5);
625
626    // Texdraw cannot only draw vector heads, fall back to built-in code.
627    if (!TEXDRAW_psarrows || (head & HEADS_ONLY)) {
628	do_arrow(sx, sy, ex, ey, head);
629	return;
630    }
631
632    switch (curr_arrow_headfilled) {
633	case AS_NOFILL:
634	    type = 'V'; // open V-shape
635	    break;
636	case AS_FILLED:
637	case AS_NOBORDER:
638	    type = 'F'; // filled triangle
639	    break;
640	case AS_EMPTY:
641	    type = 'W'; // white filled triangle
642	    break;
643    }
644
645    if (curr_arrow_headlength > 0) {
646	width  = sin(curr_arrow_headangle * DEG2RAD) * curr_arrow_headlength;
647	tiplen = cos(curr_arrow_headangle * DEG2RAD) * curr_arrow_headlength;
648	if ((curr_arrow_headbackangle - curr_arrow_headangle) <= 15)
649	    type = 'V'; // open V-shape
650    }
651
652    if (TEXDRAW_arrow_type != type) {
653	fprintf(gpoutfile, "\\arrowheadtype t:%c\n", type);
654	TEXDRAW_arrow_type = type;
655    }
656    if ((TEXDRAW_arrow_length != tiplen) || (TEXDRAW_arrow_width != width)) {
657	fprintf(gpoutfile, "\\arrowheadsize l:%d w:%d\n", tiplen, width);
658	TEXDRAW_arrow_length = tiplen;
659	TEXDRAW_arrow_width = width;
660    }
661
662    if ((head & BOTH_HEADS) != 0)
663	text = 'a';	// line with arrow
664    else
665	text = 'l';	// simple line
666
667    if ((head & END_HEAD) != 0 || (head & BOTH_HEADS) == 0) {
668	fprintf(gpoutfile, "\\move (%d %d)\\%cvec (%d %d)\n",
669	    (int) ((double) sx * TEXDRAW_xscale),
670	    (int) ((double) sy * TEXDRAW_yscale),
671	    text,
672	    (int) ((double) ex * TEXDRAW_xscale),
673	    (int) ((double) ey * TEXDRAW_yscale));
674    }
675    /* draw back-heads by drawing an arrow in the opposite direction */
676    if ((head & BACKHEAD) != 0) {
677	fprintf(gpoutfile, "\\move (%d %d)\\%cvec (%d %d)\n",
678	    (int) ((double) ex * TEXDRAW_xscale),
679	    (int) ((double) ey * TEXDRAW_yscale),
680	    text,
681	    (int) ((double) sx * TEXDRAW_xscale),
682	    (int) ((double) sy * TEXDRAW_yscale));
683    }
684
685    TEXDRAW_posx = ex;
686    TEXDRAW_posy = ey;
687}
688
689
690TERM_PUBLIC void
691TEXDRAW_put_text(unsigned int x, unsigned int y, const char str[])
692{
693    char colorstr[80] = "";
694    TEXDRAW_endline();
695
696    fprintf(gpoutfile, "\\move (%d %d)",
697	    (int) ((double) x * TEXDRAW_xscale),
698	    (int) ((double) y * TEXDRAW_yscale));
699
700    if (TEXDRAW_last_justify != TEXDRAW_justify) {
701	TEXDRAW_last_justify = TEXDRAW_justify;
702	if (TEXDRAW_justify == LEFT)
703	    fputs("\\textref h:L v:C ", gpoutfile);
704	else if (TEXDRAW_justify == CENTRE)
705	    fputs("\\textref h:C v:C ", gpoutfile);
706	else if (TEXDRAW_justify == RIGHT)
707	    fputs("\\textref h:R v:C ", gpoutfile);
708    }
709
710    if (TEXDRAW_colortext && TEXDRAW_gray != 0)
711	snprintf(colorstr, sizeof(colorstr), "\\color{black!%d!}", 100 - (int) (TEXDRAW_gray * 100));
712    if (TEXDRAW_angle == 0)
713	fprintf(gpoutfile, "\\htext{%s%s}\n", colorstr, str);
714    else if(TEXDRAW_angle == 90)
715	fprintf(gpoutfile, "\\vtext{%s%s}\n", colorstr, str);
716    else
717	fprintf(gpoutfile, "\\rtext td:%d {%s%s}\n", TEXDRAW_angle, colorstr, str);
718}
719
720
721TERM_PUBLIC int
722TEXDRAW_justify_text(enum JUSTIFY mode)
723{
724    TEXDRAW_justify = mode;
725    return (TRUE);
726}
727
728
729TERM_PUBLIC int
730TEXDRAW_text_angle(int ang)
731{
732    while (ang < 0) ang += 360;
733    ang %= 360;
734    TEXDRAW_angle = ang;
735    return (TRUE);
736}
737
738
739TERM_PUBLIC int
740TEXDRAW_make_palette(t_sm_palette *palette)
741{
742    return 0;  /* claim continuous colors */
743}
744
745
746TERM_PUBLIC void
747TEXDRAW_set_color(t_colorspec *colorspec)
748{
749    /* Users can choose any color as long as it is black.
750       Enables dash patterns. */
751    switch (colorspec->type) {
752    case TC_FRAC:
753	TEXDRAW_gray = colorspec->value;
754	break;
755    case TC_RGB: {
756	int red, green, blue;
757
758	red   = (colorspec->lt >> 16) & 0xff;
759	green = (colorspec->lt >>  8) & 0xff;
760	blue  = (colorspec->lt      ) & 0xff;
761	TEXDRAW_gray = (red * 0.30 + green * 0.59 + blue * 0.11) / 255;
762	break;
763    }
764    case TC_LT:
765	/* any line type is black for now */
766	TEXDRAW_gray = 0.;
767	break;
768    default:
769	break;
770    }
771}
772
773
774static double
775TEXDRAW_fill_gray(int style)
776{
777    double gray = TEXDRAW_gray;
778    int pattern = style >> 4;
779    int frac = style >> 4;
780    static const double TEXDRAW_pat_gray[4] = {
781	1.0, 0.5, 0.8, 0.0
782    };
783
784    switch (style & 0x0f) {
785    case FS_SOLID:
786    case FS_TRANSPARENT_SOLID:
787	if (frac < 100)
788	    gray *= frac / 100.;
789	break;
790    case FS_PATTERN:
791    case FS_TRANSPARENT_PATTERN:
792	gray = TEXDRAW_pat_gray[pattern % 4];
793	break;
794    case FS_EMPTY:
795	gray = 1.0;
796	break;
797    case FS_DEFAULT:
798    default:
799	break;
800    }
801    return gray;
802}
803
804
805TERM_PUBLIC void
806TEXDRAW_fillbox(int style,
807		unsigned int x1, unsigned int y1,
808		unsigned int width, unsigned int height)
809{
810    double gray;
811
812    TEXDRAW_endline();
813    gray = TEXDRAW_fill_gray(style);
814
815    // outline box using relative moves
816    fprintf(gpoutfile, "\\move (%d %d)", x1, y1);
817    fprintf(gpoutfile, "\\rlvec (%d %d)", width, 0);
818    fprintf(gpoutfile, "\\rlvec (%d %d)", 0, height);
819    fprintf(gpoutfile, "\\rlvec (%d %d)", -width, 0);
820    // the polygon is closed automatically by fill
821    fprintf(gpoutfile, "\\ifill f:%0.2f\n", gray);
822}
823
824
825TERM_PUBLIC void
826TEXDRAW_filled_polygon(int points, gpiPoint *corners)
827{
828    double gray;
829    int i;
830
831    TEXDRAW_endline();
832    gray = TEXDRAW_fill_gray(corners->style);
833
834    // outline polygon
835    fprintf(gpoutfile, "\\move (%d %d)", corners[0].x, corners[0].y);
836    for (i = 1; i < points; i++)
837	fprintf(gpoutfile, "\\lvec (%d %d)", corners[i].x, corners[i].y);
838    // fill polygon
839    fprintf(gpoutfile, "\\ifill f:%0.2f\n", gray);
840}
841
842#endif /* TERM_BODY */
843
844#ifdef TERM_TABLE
845
846TERM_TABLE_START(texdraw_driver)
847    "texdraw",
848    "LaTeX texdraw environment",
849    TEXDRAW_XMAX, TEXDRAW_YMAX, TEXDRAW_VCHAR, TEXDRAW_HCHAR,
850    TEXDRAW_VTIC, TEXDRAW_HTIC, TEXDRAW_options, TEXDRAW_init, TEXDRAW_reset,
851    TEXDRAW_text, null_scale, TEXDRAW_graphics, TEXDRAW_move, TEXDRAW_vector,
852    TEXDRAW_linetype, TEXDRAW_put_text, TEXDRAW_text_angle,
853    TEXDRAW_justify_text, TEXDRAW_point, TEXDRAW_arrow, set_font_null,
854    TEXDRAW_pointsize,
855    TERM_IS_LATEX | TERM_LINEWIDTH | TERM_POINTSCALE | TERM_MONOCHROME,
856    0 /*suspend*/, 0 /*resume*/,
857    TEXDRAW_fillbox,
858    TEXDRAW_linewidth,
859#ifdef USE_MOUSE
860    0, 0, 0, 0, 0,
861#endif
862    TEXDRAW_make_palette, 0,
863    TEXDRAW_set_color,
864    TEXDRAW_filled_polygon,
865    0, /* image */
866    0, 0, 0, /* enhanced text */
867    0, /* layer */
868    0, /* path */
869    0.0, /* scale (unused) */
870    0, /* hypertext */
871    0,
872    0,
873    TEXDRAW_dashtype
874TERM_TABLE_END(texdraw_driver)
875
876#undef LAST_TERM
877#define LAST_TERM texdraw_driver
878
879#endif /* TERM_TABLE */
880
881#endif /* TERM_PROTO_ONLY */
882
883#ifdef TERM_HELP
884START_HELP(texdraw)
885"1 texdraw",
886"?commands set terminal texdraw",
887"?set terminal texdraw",
888"?set term texdraw",
889"?terminal texdraw",
890"?term texdraw",
891"?texdraw",
892" The `texdraw` terminal driver supports the (La)TeX texdraw environment.  It is",
893" intended for use with the texdraw package,",
894" see https://www.ctan.org/tex-archive/graphics/texdraw/ .",
895"",
896"       set terminal texdraw",
897"                      {size <XX>{unit},<YY>{unit}}",
898"                      {standalone | input}",
899"                      {blacktext | colortext | colourtext}",
900"                      {linewidth <lw>} {rounded | butt}",
901"                      {pointscale <ps>}",
902"                      {psarrows | gparrows} {texpoints | gppoints}",
903"                      {background <rgbcolor>}",
904"",
905" Note: Graphics are in grayscale only. Text is always black. Boxes and polygons",
906" are filled using solid gray levels only. Patterns are not available.",
907"",
908" Points, among other things, are drawn using the LaTeX commands \"\\Diamond\" and",
909" \"\\Box\".  These commands no longer belong to the LaTeX2e core; they are included",
910" in the latexsym package, which is part of the base distribution and thus part",
911" of any LaTeX implementation.  Please do not forget to use this package.",
912" Other point types use symbols from the amssymb package. For compatibility with",
913" plain TeX you need to specify the `gppoints` option.",
914"",
915" `standalone` produces a LaTeX file with possibly multiple plots, ready",
916" to be compiled.  The default is `input` to produce a TeX file which can",
917" be included.",
918"",
919" `blacktext` forces all text to be written in black. `colortext` enables",
920" \"colored\" text. The default is `blacktext` and \"color\" means grayscale",
921" really.",
922"",
923" `rounded` sets line caps and line joins to be rounded; `butt` sets butt",
924" caps and mitered joins and is the default.",
925"",
926" `linewidth` and `pointscale` scale the width of lines and the size of point",
927" symbols, respectively. `pointscale`only applies to `gppoints`.",
928"",
929" `psarrows` draws `arrow`s using TeXdraw commands which are shorter but do not",
930" offer all options. `gparrows` selects drawing drawing arrows using gnuplot's",
931" own routine for full functionality instead.  Similarly, `texpoints`, and ",
932" `gppoints` select LaTeX symbols or gnuplot's point drawing routines."
933END_HELP(texdraw)
934#endif /* TERM_HELP */
935