1/* GNUPLOT - context.trm */
2
3/*[
4 * Copyright (c) 2006-2011, Mojca Miklavec
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * - Redistributions of source code must retain the above copyright notice,
11 *   this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright notice,
13 *   this list of conditions and the following disclaimer in the documentation
14 *   and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27]*/
28
29/*
30 * AUTHORS:
31 *   Mojca Miklavec
32 *       <mojca.miklavec.lists at gmail.com>
33 *     - author of this file
34 *     - improvements to m-gnuplot.tex
35 *     - mp-gnuplot.mp - metapost macros to support gnuplot-specifics
36 *       inside ConTeXt
37 *
38 *   Hans Hagen (author of ConTeXt)
39 *        <pragma at wxs.nl>
40 *      - a lot of functionality added to ConTeXt to enable better support
41 *        of Gnuplot module, many bugs fixed
42 *      - author of the module m-gnuplot.tex to support inclusion of Gnuplot
43 *        graphics into ConTeXt
44 *      - constant support on the most tricky issues
45 *   Taco Hoekwater (developer of MetaPost, pdfTeX & LuaTeX)
46 *        <taco at elvenkind.com>
47 *      - some code of this file, many tricks, lots of bug fixes,
48 *        suggestions and testing
49 *      - Hans's right hand in ConTeXt development:
50 *        constant support on even more tricky issues
51 *
52 *   For questions, suggestions, comments, improvements please contact:
53 *     - Mojca Miklavec <mojca.miklavec.lists at gmail.com> or
54 *     - <gnuplot-context at googlegroups.com>
55 *     - http://wiki.contextgarden.net/Gnuplot
56 *
57 * With special thanks to:
58 * - Peter Münster (ctx) for the initiative
59 * - Renaud Aubin (ctx) for maintaining the first source code repository
60 * - Aditya Mahajan (ctx) for some tricky parts in m-gnuplot.tex
61 * - Timothée Lecomte & Ethan A Merritt (gnuplot) for many suggestion about improving this terminal
62 * - Bastian Märkisch (gnuplot) for code improvements
63 *
64 */
65
66/*
67 * GNUPLOT -- context.trm
68 *
69 * This driver creates a ConTeXt document with embded metapost (metafun)
70 * commands and is consequently used for creation of PDF documents.
71 *
72 * It is in a way similar to pslatex, but specialized for ConTeXt,
73 * where it can also be used in the following way:
74 *
75 * \usemodule[gnuplot]
76 *
77 * \starttext
78 * \title{Drawing nice graphs with \sc gnuplot}
79 * \startGNUPLOTscript{sin}
80 * plot sin(x) t '$\sin(x)$'
81 * \stopGNUPLOTscript
82 * \useGNUPLOTgraphic[sin]
83 * \stoptext
84 *
85 * For more information see http://wiki.contextgarden.net/Gnuplot
86 *
87 * Mostly based on:
88 * - default settings copied from LaTeX terminal (because I liked it)
89 * - path construction & drawing routines from MetaPost terminal
90 * - advanced functionality with reference to PostScript terminal
91 *
92 * Future plans:
93 * - most important
94 *   - different syntax for font switching
95 *   - improve support for (transparent) binary images
96 * - add missing functionality:
97 *   - improved support for palettes
98 *   - smooth shading in color bars
99 *   - gouraud shading (if it will be implemented in gnuplot)
100 *   - other color spaces
101 * - derive a better metapost terminal out of this one (to replace the old one)
102 */
103
104#include "driver.h"
105#include "pm3d.h"
106
107#ifdef TERM_REGISTER
108register_term(context)
109#endif
110
111#ifdef TERM_PROTO
112TERM_PUBLIC void CONTEXT_options(void);
113TERM_PUBLIC void CONTEXT_init(void);
114TERM_PUBLIC void CONTEXT_reset(void);
115TERM_PUBLIC void CONTEXT_text(void);
116TERM_PUBLIC void CONTEXT_graphics(void);
117TERM_PUBLIC void CONTEXT_move(unsigned int x, unsigned int y);
118TERM_PUBLIC void CONTEXT_vector(unsigned int x, unsigned int y);
119TERM_PUBLIC void CONTEXT_linetype(int lt);
120TERM_PUBLIC void CONTEXT_put_text(unsigned int x, unsigned int y, const char *str);
121
122TERM_PUBLIC  int CONTEXT_text_angle(int ang);
123TERM_PUBLIC  int CONTEXT_justify_text(enum JUSTIFY mode);
124TERM_PUBLIC void CONTEXT_point(unsigned int x, unsigned int y, int number);
125TERM_PUBLIC void CONTEXT_arrow(unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head);
126TERM_PUBLIC  int CONTEXT_set_font(const char *font); /* "font,size" */
127TERM_PUBLIC void CONTEXT_pointsize(double pointsize);
128TERM_PUBLIC void CONTEXT_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height); /* clear part of multiplot */
129TERM_PUBLIC void CONTEXT_fill(int style);
130TERM_PUBLIC void CONTEXT_linewidth(double linewidth);
131TERM_PUBLIC  int CONTEXT_make_palette(t_sm_palette *palette);
132/* TERM_PUBLIC void CONTEXT_previous_palette(void); do we need it? */
133TERM_PUBLIC void CONTEXT_set_color(t_colorspec *colorspec);
134TERM_PUBLIC void CONTEXT_filled_polygon(int points, gpiPoint *corners);
135TERM_PUBLIC void CONTEXT_image(unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor);
136
137/* Metapost < 1.750 can only deal with numbers between 2^{-16} and 2^12=4069 */
138/* scale is 1cm = 1000 units */
139
140#define CONTEXT_DPCM 1000
141#define CONTEXT_DPI (2.54 * CONTEXT_DPCM)
142/* default plot size will be 5in x 3in */
143#define CONTEXT_XSIZE_VALUE 5
144#define CONTEXT_YSIZE_VALUE 3
145#define CONTEXT_SIZE_UNIT INCHES
146#define CONTEXT_XMAX (CONTEXT_XSIZE_VALUE * CONTEXT_DPI)
147#define CONTEXT_YMAX (CONTEXT_YSIZE_VALUE * CONTEXT_DPI)
148/* default fontsize: 12pt */
149#define CONTEXT_FONTSIZE 12.0
150/* default height of char: 12pt by default */
151#define CONTEXT_VCHAR (CONTEXT_DPI * CONTEXT_FONTSIZE / 72.27)
152/* in ConTeXt 12pt LM font is the default;
153 * at that size digits are 5.8749847pt wide
154 * in LaTeX, which assumes 11pt, the ratio is 5.3/11, which is similar */
155#define CONTEXT_LM_H_TO_V_RATIO 0.4895
156#define CONTEXT_HCHAR (CONTEXT_LM_H_TO_V_RATIO * CONTEXT_VCHAR)
157/* default tic size: 3.5bp (chosen to suit the size of plot approximately)
158 * - in LaTeX it is 5bp
159 * - in TikZ it is 0.18cm (approximately 5.1bp)
160 * - in PostScript it is 3.15pt
161 * - MetaPost uses 5pt or 5bp
162 */
163#define CONTEXT_HTIC (3.5 * CONTEXT_DPI / 72)
164#define CONTEXT_VTIC CONTEXT_HTIC
165
166#endif /* TERM_PROTO */
167
168
169#ifndef TERM_PROTO_ONLY
170#ifdef TERM_BODY
171
172/*
173 * started counting when the code was included into CVS
174 *
175 * major number should change only in case of a complete rewrite or major incompatibility
176 * minor number should change for every new functionality
177 * patch number & date should change in every commit
178 */
179static const char CONTEXT_term_version[] = "1.0";
180static const char CONTEXT_term_patch[]   = "0";
181static const char CONTEXT_term_date[]    = "2011-11-05";
182
183static void CONTEXT_params_reset(void);
184
185static void CONTEXT_adjust_dimensions(void);
186static void CONTEXT_fontstring_parse(char *from_string, char *to_string, int to_size, double *fontsize);
187
188static void CONTEXT_startpath(void);
189static void CONTEXT_endpath(void);
190
191static void CONTEXT_write_palette(t_sm_palette *palette);
192static void CONTEXT_write_palette_gradient(gradient_struct *gradient, int cnt);
193
194/* Each number is divided by 100 (1/100th of a point is drawn) */
195
196static int CONTEXT_posx;
197static int CONTEXT_posy;
198/* remembers where we started the path:
199 * if we finish it in the same point, the path is closed with --cycle
200 *
201 * After I implemented this, the functionality has been added to gnuplot core
202 * and PostScript terminal uses it, but to be on the safe side,
203 * I prefer not to add last-minute patches which could potentially break something.
204 * (the code written here proved to be rather safe & working so far)
205 * In the next version the core functionality should be integrated & tested.
206 */
207static int CONTEXT_path_start_x;
208static int CONTEXT_path_start_y;
209/* fontname, fontsize */
210static char CONTEXT_font[MAX_ID_LEN+1] = "";
211static double CONTEXT_fontsize = CONTEXT_FONTSIZE;
212
213/* fontname,fontsize to be put next to font labels if needed */
214static char CONTEXT_font_explicit[2*MAX_ID_LEN+1] = "";
215/* this is only set to >0 if asked for explicitly (for example with set_font(",15")) */
216static double CONTEXT_fontsize_explicit = 0.0;
217
218/* the last pointsize used (it will only be changed if it becomes different) */
219static double CONTEXT_old_pointsize = 1.0;
220/* the last linewidth used (it will only be changed if it becomes different) */
221static double CONTEXT_old_linewidth = 1.0;
222/* the last linetype used (it will only be changed if it becomes different) */
223static int CONTEXT_old_linetype = -3;
224/* was the color changed explicitly? */
225static TBOOLEAN CONTEXT_color_changed = FALSE;
226
227/* the number of path nodes before a newline (doesn't really matter,
228 * could be set to 1000; check if any editors have problems with that) */
229#define CONTEXT_LINEMAX 4
230
231/* if we're inside a path (unfinished line) then path_count > 0
232 * (PDF has PDF_pathIsOpen) */
233static unsigned int CONTEXT_path_count = 0;
234/* this true/false switch is used to help distinguish dots from paths */
235static unsigned int CONTEXT_path_is_dot = 0;
236
237/* angle of text rotation */
238static int CONTEXT_ang = 0;
239/* left/middle/right text justification */
240static enum JUSTIFY CONTEXT_justify = LEFT;
241
242#ifdef OS2 /* same constants are defined in os2emx.h */
243enum LINEJOIN { LINEJOIN_MITER=LINEJOIN_MITRE, _LINEJOIN_ROUND=LINEJOIN_ROUND, _LINEJOIN_BEVEL=LINEJOIN_BEVEL };
244#else
245enum LINEJOIN { LINEJOIN_MITER, LINEJOIN_ROUND, LINEJOIN_BEVEL };
246#endif
247enum LINECAP  { LINECAP_BUTT, LINECAP_ROUND, LINECAP_SQUARE };
248
249/* whether points are drawn with metapost or typeset with TeX (easy configurable) */
250enum CONTEXT_POINTS { CONTEXT_POINTS_WITH_METAPOST, CONTEXT_POINTS_WITH_TEX };
251/* whether images are inline or written out as PNGs and included (in MKII only external work) */
252enum CONTEXT_IMAGES { CONTEXT_IMAGES_INLINE, CONTEXT_IMAGES_EXTERNAL };
253
254/* counts the number of graphics */
255static int   CONTEXT_counter = 0;
256/* counts the number of external PNG images */
257static int   CONTEXT_image_counter = 0;
258/* length of basename for storing image name (including path, excluding extension) */
259static int   CONTEXT_image_filename_length = 0;
260/* if name is a path, remember at which index basename starts */
261static int   CONTEXT_image_filename_start = 0;
262static char *CONTEXT_image_filename = NULL;
263/* whether images will be external or not */
264enum CONTEXT_IMAGES CONTEXT_images = CONTEXT_IMAGES_INLINE;
265
266/* Palette has to be stored for the usage in later plots */
267static t_sm_palette *CONTEXT_old_palette;
268
269/*********************/
270/* global parameters */
271/*********************/
272
273typedef struct CONTEXT_params_t {
274	double              xsize;               /* 5in    */
275	double              ysize;               /* 3in    */
276	size_units          unit;                /* INCHES */
277	TBOOLEAN            standalone;          /* false  */
278	TBOOLEAN            timestamp;           /* true   */
279	char               *header;              /* ""     */
280	TBOOLEAN            color;               /* true   */
281	TBOOLEAN            dashed;              /* true   */
282	enum LINEJOIN       linejoin;            /* MITER  */
283	enum LINECAP        linecap;             /* BUTT   */
284	double              scale_dashlength;    /* 1.0    */
285	double              scale_linewidth;     /* 1.0    */
286	double              scale_text;          /* 1.0    */
287	enum CONTEXT_POINTS points;              /* CONTEXT_POINTS_WITH_METAPOST */
288	enum CONTEXT_IMAGES images;              /* CONTEXT_IMAGES_INLINE */
289	char                font[MAX_ID_LEN+1];  /* ""     */
290	double              fontsize;            /* 12pt   */
291} CONTEXT_params_t;
292
293
294#define CONTEXT_PARAMS_DEFAULT { \
295	CONTEXT_XSIZE_VALUE,\
296	CONTEXT_YSIZE_VALUE,\
297	INCHES,\
298	FALSE,\
299	TRUE,\
300	NULL,\
301	TRUE,\
302	TRUE,\
303	LINEJOIN_MITER,\
304	LINECAP_BUTT,\
305	1.0,\
306	1.0,\
307	1.0,\
308	CONTEXT_POINTS_WITH_METAPOST,\
309	CONTEXT_IMAGES_INLINE,\
310	"",\
311	CONTEXT_FONTSIZE\
312}
313
314static CONTEXT_params_t CONTEXT_params = CONTEXT_PARAMS_DEFAULT;
315
316enum CONTEXT_id {
317	CONTEXT_OPT_DEFAULT,
318	CONTEXT_OPT_SIZE,
319	CONTEXT_OPT_SIZE_DEFAULT,
320	CONTEXT_OPT_INPUT, CONTEXT_OPT_STANDALONE,
321	CONTEXT_OPT_TIMESTAMP, CONTEXT_OPT_NOTIMESTAMP,
322	CONTEXT_OPT_HEADER, CONTEXT_OPT_NOHEADER,
323	CONTEXT_OPT_COLOR, CONTEXT_OPT_MONOCHROME,
324	CONTEXT_OPT_DASHED, CONTEXT_OPT_SOLID,
325	CONTEXT_OPT_LINEJOIN_MITERED, CONTEXT_OPT_LINEJOIN_ROUNDED, CONTEXT_OPT_LINEJOIN_BEVELED,
326	CONTEXT_OPT_LINECAP_BUTT, CONTEXT_OPT_LINECAP_ROUNDED, CONTEXT_OPT_LINECAP_SQUARED,
327	CONTEXT_OPT_SCALE_DASHLENGTH, CONTEXT_OPT_SCALE_LINEWIDTH, CONTEXT_OPT_SCALE_TEXT,
328	CONTEXT_OPT_POINTS_WITH_METAPOST, CONTEXT_OPT_POINTS_WITH_TEX,
329	CONTEXT_OPT_IMAGES_INLINE, CONTEXT_OPT_IMAGES_EXTERNAL,
330	CONTEXT_OPT_DEFAULTFONT,
331	CONTEXT_OPT_FONT,
332	CONTEXT_OPT_OTHER
333};
334static struct gen_table CONTEXT_opts[] = {
335	{ "d$efault", CONTEXT_OPT_DEFAULT },
336	{ "size", CONTEXT_OPT_SIZE },
337	{ "defaultsize", CONTEXT_OPT_SIZE_DEFAULT },
338	{ "inp$ut", CONTEXT_OPT_INPUT },
339	{ "stand$alone", CONTEXT_OPT_STANDALONE },
340	{ "time$stamp", CONTEXT_OPT_TIMESTAMP },
341	{ "notime$stamp", CONTEXT_OPT_NOTIMESTAMP },
342	{ "header", CONTEXT_OPT_HEADER },
343	{ "noheader", CONTEXT_OPT_NOHEADER },
344	{ "col$or", CONTEXT_OPT_COLOR },
345	{ "col$our", CONTEXT_OPT_COLOR },
346	{ "mono$chrome", CONTEXT_OPT_MONOCHROME },
347	{ "da$shed", CONTEXT_OPT_DASHED },
348	{ "so$lid", CONTEXT_OPT_SOLID },
349	{ "miter$ed", CONTEXT_OPT_LINEJOIN_MITERED },
350	{ "rounded", CONTEXT_OPT_LINEJOIN_ROUNDED },
351	{ "bevel$ed", CONTEXT_OPT_LINEJOIN_BEVELED },
352	{ "butt", CONTEXT_OPT_LINECAP_BUTT },
353	{ "round", CONTEXT_OPT_LINECAP_ROUNDED },
354	{ "square$d", CONTEXT_OPT_LINECAP_SQUARED },
355	{ "dashl$ength", CONTEXT_OPT_SCALE_DASHLENGTH },
356	{ "dl", CONTEXT_OPT_SCALE_DASHLENGTH },
357	{ "linew$idth", CONTEXT_OPT_SCALE_LINEWIDTH },
358	{ "lw", CONTEXT_OPT_SCALE_LINEWIDTH },
359	{ "fontscale", CONTEXT_OPT_SCALE_TEXT },
360	{ "textscale", CONTEXT_OPT_SCALE_TEXT },                   /* backward compatibility */
361	{ "mp$points", CONTEXT_OPT_POINTS_WITH_METAPOST},
362	{ "tex$points", CONTEXT_OPT_POINTS_WITH_TEX},
363	{ "pointswithmp", CONTEXT_OPT_POINTS_WITH_METAPOST},       /* (removable) backward compatibility */
364	{ "pointswithmetapost", CONTEXT_OPT_POINTS_WITH_METAPOST}, /* (removable) backward compatibility */
365	{ "pointswithtex", CONTEXT_OPT_POINTS_WITH_TEX},           /* (removable) backward compatibility */
366	{ "inline$images", CONTEXT_OPT_IMAGES_INLINE},
367	{ "external$images", CONTEXT_OPT_IMAGES_EXTERNAL},
368	{ "font", CONTEXT_OPT_FONT },
369	{ "defaultfont", CONTEXT_OPT_DEFAULTFONT },
370	{ NULL, CONTEXT_OPT_OTHER }
371};
372
373/* **********************
374 * CONTEXT_params_reset *
375 * **********************
376 *
377 * Resets all parameters of the terminal to their default value.
378 */
379static void
380CONTEXT_params_reset()
381{
382	static const CONTEXT_params_t CONTEXT_params_default = CONTEXT_PARAMS_DEFAULT;
383
384	/* free the memory with header first */
385	if (CONTEXT_params.header) {
386		free(CONTEXT_params.header);
387		CONTEXT_params.header = NULL;
388	}
389
390	memcpy(&CONTEXT_params, &CONTEXT_params_default, sizeof(CONTEXT_params_t));
391}
392
393
394/* *****************
395 * CONTEXT_options *
396 * *****************
397 *
398 * Parses "set term context [options]".
399 */
400TERM_PUBLIC void
401CONTEXT_options()
402{
403	struct value a;
404	char   *tmp_string;
405	char   tmp_term_options[MAX_LINE_LEN+1] = "";
406
407	while (!END_OF_COMMAND) {
408		switch (lookup_table(&CONTEXT_opts[0], c_token)) {
409		case CONTEXT_OPT_DEFAULT:
410			c_token++;
411			/* there should be a better way to do it, but I don't know how */
412			CONTEXT_params_reset();
413			break;
414		case CONTEXT_OPT_SIZE: {
415			float xmax_t, ymax_t;
416			size_units unit;
417			c_token++;
418
419			/* size <xsize> {cm|in}, <ysize> {cm|in} */
420			unit = parse_term_size(&xmax_t, &ymax_t, CM);
421			CONTEXT_params.xsize = (double)xmax_t / gp_resolution;
422			CONTEXT_params.ysize = (double)ymax_t / gp_resolution;
423			CONTEXT_params.unit  = unit;
424			if (unit == CM) {
425				CONTEXT_params.xsize *= 2.54;
426				CONTEXT_params.ysize *= 2.54;
427			}
428			break;
429		}
430		case CONTEXT_OPT_SIZE_DEFAULT:
431			c_token++;
432			CONTEXT_params.xsize = CONTEXT_XSIZE_VALUE;
433			CONTEXT_params.ysize = CONTEXT_YSIZE_VALUE;
434			CONTEXT_params.unit  = CONTEXT_SIZE_UNIT;
435			break;
436		case CONTEXT_OPT_INPUT:
437			c_token++;
438			CONTEXT_params.standalone = FALSE;
439			break;
440		case CONTEXT_OPT_STANDALONE:
441			c_token++;
442			CONTEXT_params.standalone = TRUE;
443			break;
444		case CONTEXT_OPT_TIMESTAMP:
445			c_token++;
446			CONTEXT_params.timestamp = TRUE;
447			break;
448		case CONTEXT_OPT_NOTIMESTAMP:
449			c_token++;
450			CONTEXT_params.timestamp = FALSE;
451			break;
452
453		case CONTEXT_OPT_HEADER:
454			c_token++;
455			/* parse the string */
456			tmp_string = try_to_get_string();
457			if (!tmp_string) {
458				int_error(c_token,"String containing header information expected");
459			/* only touch the options if the string is OK */
460			} else {
461				/* remove the old header if any */
462				if (CONTEXT_params.header) {
463					free(CONTEXT_params.header);
464					CONTEXT_params.header = NULL;
465				}
466				/* and set the new one if nonempty;
467				 * empty header will be treated as 'noheader' */
468				if (strlen(tmp_string) > 0) {
469					CONTEXT_params.header = tmp_string;
470				} else {
471					free(tmp_string);
472				}
473			}
474			break;
475		case CONTEXT_OPT_NOHEADER:
476			c_token++;
477			/* delete the header if it exists */
478			if (CONTEXT_params.header) {
479				free(CONTEXT_params.header);
480				CONTEXT_params.header = NULL;
481			}
482			break;
483		case CONTEXT_OPT_COLOR:
484			c_token++;
485			CONTEXT_params.color = TRUE;
486			/* just mimic other terminals; no idea what it does;
487			   at the moment monochrome is not fully implemented either */
488			term->flags &= ~TERM_MONOCHROME;
489			break;
490		case CONTEXT_OPT_MONOCHROME:
491			c_token++;
492			CONTEXT_params.color = FALSE;
493			term->flags |= TERM_MONOCHROME;
494			break;
495		case CONTEXT_OPT_DASHED:
496			c_token++;
497			CONTEXT_params.dashed = TRUE;
498			break;
499		case CONTEXT_OPT_SOLID:
500			c_token++;
501			CONTEXT_params.dashed = FALSE;
502			break;
503		case CONTEXT_OPT_LINEJOIN_MITERED:
504			c_token++;
505			CONTEXT_params.linejoin = LINEJOIN_MITER;
506			break;
507		case CONTEXT_OPT_LINEJOIN_ROUNDED:
508			c_token++;
509			CONTEXT_params.linejoin = LINEJOIN_ROUND;
510			break;
511		case CONTEXT_OPT_LINEJOIN_BEVELED:
512			c_token++;
513			CONTEXT_params.linejoin = LINEJOIN_BEVEL;
514			break;
515		case CONTEXT_OPT_LINECAP_BUTT:
516			c_token++;
517			CONTEXT_params.linecap = LINECAP_BUTT;
518			break;
519		case CONTEXT_OPT_LINECAP_ROUNDED:
520			c_token++;
521			CONTEXT_params.linecap = LINECAP_ROUND;
522			break;
523		case CONTEXT_OPT_LINECAP_SQUARED:
524			c_token++;
525			CONTEXT_params.linecap = LINECAP_SQUARE;
526			break;
527		case CONTEXT_OPT_SCALE_DASHLENGTH:
528			c_token++;
529			CONTEXT_params.scale_dashlength = real(const_express(&a));
530			break;
531		case CONTEXT_OPT_SCALE_LINEWIDTH:
532			c_token++;
533			CONTEXT_params.scale_linewidth = real(const_express(&a));
534			break;
535		case CONTEXT_OPT_SCALE_TEXT:
536			c_token++;
537			CONTEXT_params.scale_text = real(const_express(&a));
538			break;
539		case CONTEXT_OPT_DEFAULTFONT:
540			c_token++;
541			/* CONTEXT_params.font should be an empty string */
542			CONTEXT_params.font[0] = 0;
543			/* default fontsize is 12pt */
544			CONTEXT_params.fontsize = CONTEXT_FONTSIZE;
545			break;
546		case CONTEXT_OPT_POINTS_WITH_METAPOST:
547			c_token++;
548			CONTEXT_params.points = CONTEXT_POINTS_WITH_METAPOST;
549			break;
550		case CONTEXT_OPT_POINTS_WITH_TEX:
551			c_token++;
552			CONTEXT_params.points = CONTEXT_POINTS_WITH_TEX;
553			break;
554		case CONTEXT_OPT_IMAGES_INLINE:
555			c_token++;
556			CONTEXT_params.images = CONTEXT_IMAGES_INLINE;
557			break;
558		case CONTEXT_OPT_IMAGES_EXTERNAL:
559#ifdef WRITE_PNG_IMAGE
560			c_token++;
561			CONTEXT_params.images = CONTEXT_IMAGES_EXTERNAL;
562#else
563			int_warn(c_token, "Gnuplot was built without support for PNG images. You cannot use this option unless you rebuild gnuplot.");
564#endif
565			break;
566		/*
567		 * The preferred way to set the font is to set it in a document itself,
568		 * labels in gnuplot in graphs will then inherit that font.
569		 *
570		 * However, it is important to tell gnuplot which size is going to be used,
571		 * so that it can estimate size of text labels.
572		 *
573		 * Whenever you specify
574		 *     set term context font "fontname,14"
575		 *
576		 * there are two possibilities:
577		 * - if STANDALONE mode is on, then the whole string will be used as
578		 *   \setupbodyfont[fontname,14pt]
579		 *   somewhere on top of the document (you still have to make sure that you
580		 *   included the proper typescript, so that "fontname" will be recognised
581		 * - in the other case (INPUT mode) only the font size will be used
582		 *   internally to estimate sizes of labels, but the font name
583		 *   won't be written anywhere
584		 */
585		case CONTEXT_OPT_FONT: {
586			double tmp_fontsize;
587			char tmp_font[MAX_ID_LEN+1] = "";
588			c_token++;
589			if ((tmp_string = try_to_get_string()) && (tmp_string != NULL)) {
590				CONTEXT_fontstring_parse(tmp_string, tmp_font, MAX_ID_LEN+1, &tmp_fontsize);
591				/* copies font name to parameters */
592				safe_strncpy(CONTEXT_params.font, tmp_font, sizeof(CONTEXT_params.font));
593				tmp_font[MAX_ID_LEN] = NUL;
594				free(tmp_string);
595				/* save font size:
596				 *
597				 * - if size > 0, copy
598				 * - if size < 0, fix the size to default value (12pt)
599				 * - if size = 0, ignore
600				 */
601				if (tmp_fontsize > 0)
602					CONTEXT_params.fontsize = tmp_fontsize;
603				else if (tmp_fontsize < 0)
604					CONTEXT_params.fontsize = CONTEXT_FONTSIZE;
605			}
606			break;
607		}
608		case CONTEXT_OPT_OTHER:
609		default:
610			/* error */
611			int_error(c_token, "extraneous argument in set terminal %s",term->name);
612			break;
613		}
614	}
615
616	/* current font size in pt (to be used in CONTEXT_adjust_dimensions) */
617	CONTEXT_fontsize = CONTEXT_params.fontsize;
618
619	/* sets term->xmax, ymax, vchar, hchar */
620	CONTEXT_adjust_dimensions();
621
622	snprintf(term_options, sizeof(term_options),
623			"size %g%s,%g%s %s %s %s",
624			CONTEXT_params.xsize,
625			(CONTEXT_params.unit == INCHES) ? "in" : "cm",
626			CONTEXT_params.ysize,
627			(CONTEXT_params.unit == INCHES) ? "in" : "cm",
628			CONTEXT_params.standalone ? "standalone" : "input",
629			CONTEXT_params.timestamp ? "timestamp" : "notimestamp",
630			CONTEXT_params.header == NULL ? "noheader \\\n   " : "\\\n   header ");
631
632	if (CONTEXT_params.header != NULL) {
633		strncat(term_options,"\"",                  sizeof(term_options)-strlen(term_options)-1);
634		strncat(term_options,CONTEXT_params.header, sizeof(term_options)-strlen(term_options)-1);
635		strncat(term_options,"\" \\\n   ",          sizeof(term_options)-strlen(term_options)-1);
636	}
637
638	strncat(term_options,
639		CONTEXT_params.color ? "color " : "monochrome ",
640		sizeof(term_options)-strlen(term_options)-1);
641
642	switch (CONTEXT_params.linejoin) {
643		case LINEJOIN_MITER:
644			strncat(term_options, "mitered ",
645				sizeof(term_options)-strlen(term_options)-1);
646                        break;
647		case LINEJOIN_ROUND:
648			strncat(term_options, "rounded ",
649				sizeof(term_options)-strlen(term_options)-1);
650                        break;
651		case LINEJOIN_BEVEL:
652			strncat(term_options, "beveled ",
653				sizeof(term_options)-strlen(term_options)-1);
654                        break;
655	}
656	switch (CONTEXT_params.linecap) {
657		case LINECAP_BUTT  :
658			strncat(term_options, "butt",
659				sizeof(term_options)-strlen(term_options)-1);
660                        break;
661		case LINECAP_ROUND :
662			strncat(term_options, "round",
663				sizeof(term_options)-strlen(term_options)-1);
664                        break;
665		case LINECAP_SQUARE:
666			strncat(term_options, "squared",
667				sizeof(term_options)-strlen(term_options)-1);
668                        break;
669	}
670
671	snprintf(tmp_term_options, sizeof(tmp_term_options),
672		" %s dashlength %g linewidth %g fontscale %g \\\n   ",
673		CONTEXT_params.dashed ? "dashed" : "solid",
674		CONTEXT_params.scale_dashlength,
675		CONTEXT_params.scale_linewidth,
676		CONTEXT_params.scale_text
677		);
678	strncat(term_options, tmp_term_options, sizeof(term_options)-strlen(term_options)-1);
679
680	switch (CONTEXT_params.points) {
681		case CONTEXT_POINTS_WITH_TEX :
682			strncat(term_options, "texpoints ",
683				sizeof(term_options)-strlen(term_options)-1);
684                        break;
685		case CONTEXT_POINTS_WITH_METAPOST :
686			strncat(term_options, "mppoints ",
687				sizeof(term_options)-strlen(term_options)-1);
688                        break;
689	}
690#ifdef WRITE_PNG_IMAGE
691	switch (CONTEXT_params.images) {
692		case CONTEXT_IMAGES_INLINE :
693			strncat(term_options, "inlineimages ",
694				sizeof(term_options)-strlen(term_options)-1);
695                        break;
696		case CONTEXT_IMAGES_EXTERNAL :
697			strncat(term_options, "externalimages ",
698				sizeof(term_options)-strlen(term_options)-1);
699                        break;
700	}
701#endif
702	snprintf(tmp_term_options, sizeof(tmp_term_options), "font \"%s,%g\"",
703		CONTEXT_params.font, CONTEXT_params.fontsize);
704	strncat(term_options, tmp_term_options, sizeof(term_options) - strlen(term_options)-1);
705}
706
707/* **************
708 * CONTEXT_init *
709 * **************
710 *
711 * Starts a new file.
712 *
713 * XXX: "set term context" multiple times will only include those graphics
714 *      that were create before issuing a new "set term context options"
715 *      this should be fixed in the core by reopening the file
716 *      (removing previously written content).
717 * - PDF & binary terminals start a new file
718 * - PS & TeX-based terminals continue
719 */
720TERM_PUBLIC void
721CONTEXT_init()
722{
723	time_t now;
724	char timebuffer[100];
725#ifdef WRITE_PNG_IMAGE
726	int i;
727#endif
728
729	time(&now);
730
731	CONTEXT_posx = CONTEXT_posy = 0;
732	CONTEXT_path_count = 0;
733	CONTEXT_path_is_dot = 0;
734
735	CONTEXT_counter = 0;
736
737	/* setup bitmap images */
738	CONTEXT_image_counter = 0;
739	/* the default is to use inline images */
740	CONTEXT_images = CONTEXT_IMAGES_INLINE;
741
742	/* only if external images are both requested and supported, we switch to them (double paranoia) */
743	/* delete the stored filename first */
744	if (CONTEXT_image_filename) {
745		free(CONTEXT_image_filename);
746		CONTEXT_image_filename = NULL;
747		CONTEXT_image_filename_length = 0;
748		CONTEXT_image_filename_start  = 0;
749	};
750#ifdef WRITE_PNG_IMAGE
751	if (CONTEXT_params.images == CONTEXT_IMAGES_EXTERNAL) {
752		CONTEXT_images = CONTEXT_IMAGES_EXTERNAL;
753
754		/* but only if 'set output' was set because we use that string as base for image names */
755		if (outstr) {
756			CONTEXT_image_filename_length = strlen(outstr);
757			CONTEXT_image_filename_start  = strlen(outstr) - strlen(gp_basename(outstr));
758			/* we will cut off the last .tex ending if present */
759			/* find the last dot if present */
760			for (i = CONTEXT_image_filename_length - 1; i >= 0 && outstr[i] != '.'; i--);
761			if (outstr[i] == '.')
762				CONTEXT_image_filename_length = i;
763			/* it would also be very nice to do some sanity checks on filenames */
764
765			/* <name>.xx.png; must be at least 7 characters long */
766			CONTEXT_image_filename = (char *)gp_alloc(CONTEXT_image_filename_length + 10, "ConTeXt image filename");
767			strncpy(CONTEXT_image_filename, outstr, CONTEXT_image_filename_length);
768			CONTEXT_image_filename[CONTEXT_image_filename_length] = 0;
769		} else {
770			CONTEXT_image_filename_length = strlen("gp_image");
771			CONTEXT_image_filename_start  = 0;
772			/* <name>.xx.png; must be at least 7 characters long */
773			CONTEXT_image_filename = (char *)gp_alloc(CONTEXT_image_filename_length + 10, "ConTeXt image filename");
774			strncpy(CONTEXT_image_filename, "gp_image", CONTEXT_image_filename_length);
775			CONTEXT_image_filename[CONTEXT_image_filename_length] = 0;
776		}
777	}
778#endif
779
780	fprintf(gpoutfile, "%% Written by ConTeXt terminal for GNUPLOT");
781	if (CONTEXT_params.timestamp) {
782		if (strftime(timebuffer, 100, "%Y-%m-%d %H:%M %Z", localtime(&now)) != 0)
783			fprintf(gpoutfile, " on: %s", timebuffer);
784	}
785	fprintf(gpoutfile, "\n");
786	fprintf(gpoutfile, "%% GNUPLOT version: %s.%s, terminal version: %s.%s (%s)\n",
787		gnuplot_version, gnuplot_patchlevel, CONTEXT_term_version, CONTEXT_term_patch, CONTEXT_term_date);
788	fprintf(gpoutfile, "%% See also http://wiki.contextgarden.net/Gnuplot\n%%\n");
789
790	/* place the header first if this is a standalone graphic */
791	if (CONTEXT_params.standalone) {
792		/* If encoding is explicitly set to UTF-8 by gnuplot, use that setting.
793		 * \enableregime only makes a difference for pdfTeX; in LuaTeX and XeTeX UTF-8 is already default,
794		 * so this line will be ignored.
795		 *
796		 * There is no extra support for other encodings on purpose:
797		 * - ConTeXt doesn't support all encodings supported by Gnuplot.
798		 * - In LuaTeX and XeTeX one should not use any other encoding anyway.
799		 * - pdfTeX users are free to use "header '\enableregime[...]'" */
800		switch (encoding) {
801			case S_ENC_UTF8:
802				fputs("\\enableregime\n   [utf-8]\n", gpoutfile);
803				break;
804			default:
805				/* do nothing */
806				break;
807		}
808		/* load the gnuplot module */
809		fputs("\\usemodule\n   [gnuplot]\n", gpoutfile);
810		/* enable or disable color (the only place where "color" is indeed used so far) */
811		fprintf(gpoutfile, "\\setupcolors\n   [state=%s]\n", CONTEXT_params.color ? "start" : "stop");
812		/* additional user-provided header information (if available) */
813		if (CONTEXT_params.header)
814			fprintf(gpoutfile, "%s\n", CONTEXT_params.header);
815		/* for some reason setting \bodyfontenvironment is needed,
816		 * otherwise \switchtobodyfont[name] doesn't work OK */
817		if (!(CONTEXT_params.fontsize == CONTEXT_FONTSIZE))
818			fprintf(gpoutfile, "\\definebodyfontenvironment\n   [%gpt]\n",
819				CONTEXT_params.fontsize);
820		/* set the proper font: \setupbodyfont[{fontname,}fontsize sizeunit] */
821		fprintf(gpoutfile, "\\setupbodyfont\n   [%s%s%gpt]\n",
822			CONTEXT_params.font,
823			/* write a comma only if the last string was non-empty */
824			((strlen(CONTEXT_params.font)>0) ? "," : ""),
825			CONTEXT_params.fontsize);
826
827		/*---------*
828		 * options *
829		 *---------*/
830		fprintf(gpoutfile, "\\setupGNUPLOTterminal\n   [context]\n   [");
831
832		/* color (gp_use_color): yes/no (true/false)
833		 * default: yes
834		 * - doesn't do anything useful yet;
835		 *   and besides that, it's already set in \setupcolors[state=start] */
836		/* fprintf(gpoutfile, "    color=%s, %% *yes* | no\n", CONTEXT_params.color ? "yes" : "no"); */
837
838		/* linejoin: mitered/rounded/beveled
839		 * default: mitered */
840		fprintf(gpoutfile, "linejoin=");
841		switch (CONTEXT_params.linejoin) {
842			case LINEJOIN_MITER: fprintf(gpoutfile, "mitered"); break;
843			case LINEJOIN_ROUND: fprintf(gpoutfile, "rounded"); break;
844			case LINEJOIN_BEVEL: fprintf(gpoutfile, "beveled"); break;
845		}
846		fprintf(gpoutfile, ", %% *mitered* | rounded | beveled\n");
847
848		/* linecap: butt/rounded/squared
849		 * default: butt */
850		fprintf(gpoutfile, "    linecap=");
851		switch (CONTEXT_params.linecap) {
852			case LINECAP_BUTT  : fprintf(gpoutfile, "butt"); break;
853			case LINECAP_ROUND : fprintf(gpoutfile, "rounded"); break;
854			case LINECAP_SQUARE: fprintf(gpoutfile, "squared"); break;
855		}
856		fprintf(gpoutfile, ", %% *butt* | rounded | squared\n");
857
858		/* dashed (gp_use_dashed): yes/no (true/false)
859		 * default: yes */
860		fprintf(gpoutfile, "    dashed=%s, %% *yes* | no\n", CONTEXT_params.dashed ? "yes" : "no");
861		/* dashlength (gp_scale_dashlength): 1.0 */
862		fprintf(gpoutfile, "    dashlength=%g, %% scaling factor for dash lengths\n", CONTEXT_params.scale_dashlength);
863
864		/* linewidth (gp_scale_linewidth): 1.0 */
865		fprintf(gpoutfile, "    linewidth=%g, %% scaling factor for line widths (1.0 means 0.5bp)\n", CONTEXT_params.scale_linewidth);
866
867		/* fontscale (gp_scale_text): 1.0 */
868		/* written out just for reference - it's commented out since it needs to be part of graphic
869		   and affects estimation of label sizes */
870		fprintf(gpoutfile, "    %%fontscale=%g, %% scaling factor for text labels\n", CONTEXT_params.scale_text);
871
872		/* points (gp_points_with): metapost/tex (gp_points_with_metapost/gp_points_with_tex)
873		 * default: metapost */
874		fprintf(gpoutfile, "    points=%s, %% *metapost* | tex (Should points be drawn with MetaPost or TeX?)\n",
875			CONTEXT_params.points == CONTEXT_POINTS_WITH_METAPOST ? "metapost" : "tex");
876
877		/* images
878		 * default: inline */
879		fprintf(gpoutfile, "    images=%s] %% *inline* | external (inline only works in MKIV, external requires png support in gnuplot)\n",
880			CONTEXT_images == CONTEXT_IMAGES_INLINE ? "inline" : "external");
881
882		/*----------------*
883		 * end of options *
884		 *----------------*/
885
886		fputs("\n\\starttext\n\n", gpoutfile);
887	} else {
888		/* Sorry, nothing! In non-standalone graphic, parameters make no sense.
889		 * Setup everything in the file which includes such a graphic instead.
890		 */
891	}
892}
893
894/* ***************
895 * CONTEXT_reset *
896 * ***************
897 *
898 * finish writing the file
899 */
900TERM_PUBLIC void
901CONTEXT_reset()
902{
903	/* we only have to end the document if this is a stand-alone graphic */
904	if (CONTEXT_params.standalone) {
905		fputs("\\stoptext\n", gpoutfile);
906	} else {
907		/* This means that any subsequent plots to the same file will be ignored.
908		 * I don't like that - gnuplot should delete the old contents instead,
909		 * just as it does in case of PNG or PDF -
910		 * but it will be at least consistent with standalone graphics that way
911		 */
912		fputs("\\endinput\n", gpoutfile);
913	}
914	/* deallocate image name if present */
915	if (CONTEXT_image_filename) {
916		free(CONTEXT_image_filename);
917		CONTEXT_image_filename = NULL;
918		CONTEXT_image_filename_length = 0;
919		CONTEXT_image_filename_start  = 0;
920	};
921}
922
923/* **************
924 * CONTEXT_text *
925 * **************
926 *
927 * Ends the current graphic.
928 */
929TERM_PUBLIC void
930CONTEXT_text()
931{
932	/* close and draw the current path first */
933	if (CONTEXT_path_count > 0)
934		CONTEXT_endpath();
935
936	fprintf(gpoutfile, "setbounds currentpicture to unitsquare xyscaled (w,h);\n");
937
938	/* standalone graphic is a whole-page graphic */
939	if (CONTEXT_params.standalone) {
940		fputs("\\stopGNUPLOTpage\n", gpoutfile);
941	/* otherwise we define a MPgraphic to be included later */
942	} else {
943		fputs("\\stopGNUPLOTgraphic\n", gpoutfile);
944	}
945}
946
947/* ******************
948 * CONTEXT_graphics *
949 * ******************
950 *
951 * Starts a new graphic.
952 */
953TERM_PUBLIC void
954CONTEXT_graphics()
955{
956	/* standalone graphic is a whole-page graphic */
957	if (CONTEXT_params.standalone) {
958		fprintf(gpoutfile, "\\startGNUPLOTpage %% Graphic Nr. %d\n", ++CONTEXT_counter);
959	/* otherwise we define a MPgraphic to be included later */
960	} else {
961		/* the first parameter holds the graphic number */
962		fprintf(gpoutfile, "\\startGNUPLOTgraphic[%d]\n", ++CONTEXT_counter);
963	}
964
965	fprintf(gpoutfile, "string gnuplotversion; gnuplotversion := \"%s\";\n", gnuplot_version);
966	fprintf(gpoutfile, "string termversion;    termversion    := \"%s\";\n", CONTEXT_term_version);
967	/*
968	 * MetaPost can only handle numbers up to 4096. Too high resolution
969	 * would thus result in number overflow, that's why we scale down all the
970	 * integers from gnuplot by 1000 and multiply those numbers later by
971	 * appropriate scaling factor 'a' to get the proper dimensions.
972	 */
973	fprintf(gpoutfile, "%% scaling factor, width and height of the figure\na := 1cm; w := %.3fa; h := %.3fa; %% (%g%s, %g%s)\n",
974		CONTEXT_params.xsize * ((CONTEXT_params.unit == INCHES) ? 2.54 : 1), /* cm */
975		CONTEXT_params.ysize * ((CONTEXT_params.unit == INCHES) ? 2.54 : 1), /* cm */
976		CONTEXT_params.xsize, (CONTEXT_params.unit == INCHES) ? "in" : "cm",
977		CONTEXT_params.ysize, (CONTEXT_params.unit == INCHES) ? "in" : "cm");
978	/* TODO: the following if-else could be slightly nicer */
979	if (CONTEXT_images == CONTEXT_IMAGES_INLINE) {
980		fprintf(gpoutfile, "%% temporary variable for storing the path and images\nsave p, img, ima; path p; string img, ima;\n");
981	} else {
982		fprintf(gpoutfile, "%% temporary variable for storing the path\nsave p; path p;\n");
983	}
984	fprintf(gpoutfile, "%% -------------------------\n");
985	fprintf(gpoutfile, "%% Different initialisations\n");
986	fprintf(gpoutfile, "%% -------------------------\n");
987	fprintf(gpoutfile, "%% for additional user-defined settings\ngp_setup_before;\n");
988	/* needed (depends on terminal settings & needs to be passed) */
989	fprintf(gpoutfile, "%% text scaling factor for the whole figure\n");
990	fprintf(gpoutfile, "gp_scale_text := %g;\n", CONTEXT_params.scale_text);
991	fprintf(gpoutfile, "%% pointsize scaling factor\n");
992	fprintf(gpoutfile, "gp_set_pointsize(%g);\n", CONTEXT_old_pointsize);
993	/* needed (provided by terminal) */
994	fprintf(gpoutfile, "%% linewidth scaling factor for individual lines\n");
995	fprintf(gpoutfile, "gp_set_linewidth(%g);\n", CONTEXT_old_linewidth);
996	fprintf(gpoutfile, "%% for additional user-defined settings\ngp_setup_after;\n");
997	fprintf(gpoutfile, "%% -------------------------\n");
998
999	/* since palette is initialized only once, subsequent plots wouldn't see it
1000	 * unless we write it on the top of relevant plots explicitly */
1001	if (is_plot_with_palette()) {
1002		CONTEXT_write_palette(CONTEXT_old_palette);
1003	}
1004
1005	/* needed, otherwise the first linetype(-2) would be ignored */
1006	CONTEXT_old_linetype = -3;
1007	/* different initializations - not really needed, but they cannot hurt */
1008	CONTEXT_posx = CONTEXT_posy = 0;
1009	CONTEXT_path_count = 0;
1010	CONTEXT_path_is_dot = 0;
1011}
1012
1013/* ---------------
1014 * CONTEXT_endpath
1015 * ---------------
1016 *
1017 * Closes and strokes (draws) the current path.
1018 *
1019 * It the path ends where it started, it ends it with --cycle (we get cyclic path),
1020 * otherwise just with a semicolon.
1021 */
1022static void
1023CONTEXT_endpath()
1024{
1025	/* if we have a dot, draw only the dot */
1026	if (CONTEXT_path_is_dot) {
1027		fprintf(gpoutfile, "gp_dot(%.3fa,%.3fa);\n", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1028		CONTEXT_path_is_dot = 0;
1029
1030	/* cyclic path, so let's end it with "--cycle" */
1031	} else if ((CONTEXT_posx == CONTEXT_path_start_x) && (CONTEXT_posy == CONTEXT_path_start_y)) {
1032		fputs("--cycle;\ngp_draw(p);\n", gpoutfile);
1033
1034	/* regular non-cyclic path */
1035	} else {
1036		fprintf(gpoutfile, "--(%.3fa,%.3fa);\ngp_draw(p);\n", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1037	}
1038
1039	/* we're not inside path any more */
1040	CONTEXT_path_count = 0;
1041}
1042
1043/* **************
1044 * CONTEXT_move *
1045 * **************
1046 *
1047 * Remembers the new location for a path.
1048 *
1049 * If it doesn't differ from the current location, this is simply ignored.
1050 * If we're still in the middle of path construction and location differs,
1051 * it strokes the old path.
1052 *
1053 */
1054TERM_PUBLIC void
1055CONTEXT_move(unsigned int x, unsigned int y)
1056{
1057	/* we seem to be there already */
1058	if ((x == CONTEXT_posx) && (y == CONTEXT_posy))
1059		return;
1060
1061	/* close and draw the current path before the move */
1062	if (CONTEXT_path_count > 0)
1063		CONTEXT_endpath();
1064
1065	CONTEXT_posx = x;
1066	CONTEXT_posy = y;
1067}
1068
1069/* -----------------
1070 * CONTEXT_startpath
1071 * -----------------
1072 *
1073 * Starts ([but not yet] drawing) a new path.
1074 */
1075static void
1076CONTEXT_startpath()
1077{
1078	CONTEXT_path_start_x = CONTEXT_posx;
1079	CONTEXT_path_start_y = CONTEXT_posy;
1080	CONTEXT_path_count = 2;
1081
1082	fprintf(gpoutfile, "p := (%.3fa,%.3fa)", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1083}
1084
1085/* ****************
1086 * CONTEXT_vector *
1087 * ****************
1088 *
1089 * Prolongs the current path for an additional line (from the last point to (x,y))
1090 * unless it has a zero-length.
1091 *
1092 * Points have to be treated as a special case, since gnuplot sometimes tries
1093 * to draw them as moveto(a,b)--lineto(a,b) - without the proper linecap,
1094 * that wouldn't draw anything in MetaPost or PS.
1095 * (I hope that I got that part right, but I'm not completely sure.)
1096 */
1097TERM_PUBLIC void
1098CONTEXT_vector(unsigned int x, unsigned int y)
1099{
1100	/* this is zero-length line (or a dot)
1101	 *
1102	 * stupid background, has to handle
1103	 * - move(0,0), vector(0,0), whatever: draw a dot
1104	 * - move(0,0), vector(0,0), vector (1,1): draw a line
1105	 */
1106	if ((x == CONTEXT_posx) && (y==CONTEXT_posy)) {
1107		/* as long as this is still a dot candidate, mark it so
1108		 * however - further vector() commands may set this back to 0 */
1109		if (CONTEXT_path_count == 0)
1110			CONTEXT_path_is_dot = 1;
1111		/* if some path was already drawn up to this place, ignore (it's not a dot) */
1112		return;
1113	}
1114
1115	/* start the path if none is started yet */
1116	if (CONTEXT_path_count == 0) {
1117		/* the path is not a dot */
1118		CONTEXT_path_is_dot = 0;
1119		CONTEXT_startpath();
1120	} else {
1121		/* or prevent too long lines if you're in the middle of a path */
1122		if ((CONTEXT_path_count % CONTEXT_LINEMAX) == 2) {
1123			fputs("\n  ", gpoutfile);
1124			CONTEXT_path_count = 2;
1125		}
1126		/* and output the previous point */
1127		fprintf(gpoutfile, "--(%.3fa,%.3fa)", 0.001*CONTEXT_posx, 0.001*CONTEXT_posy);
1128	}
1129
1130	CONTEXT_posx = x;
1131	CONTEXT_posy = y;
1132	CONTEXT_path_count++;
1133}
1134
1135/* ******************
1136 * CONTEXT_linetype *
1137 * ******************
1138 *
1139 * - If only color has been changed (recently), but not the linetype,
1140 *   it resets only the color.
1141 * - If linetype was changed, it sets the new linetype
1142 */
1143TERM_PUBLIC void
1144CONTEXT_linetype(int lt)
1145{
1146	/* reset the color in case it has been changed in CONTEXT_set_color() */
1147	if (CONTEXT_old_linetype != lt || CONTEXT_color_changed) {
1148		/* close and draw the current path first */
1149		if (CONTEXT_path_count > 0)
1150			CONTEXT_endpath();
1151
1152		fprintf(gpoutfile, "gp_set_linetype(%d);\n", lt);
1153
1154		CONTEXT_old_linetype = lt;
1155		CONTEXT_color_changed = FALSE;
1156	}
1157}
1158
1159/* ******************
1160 * CONTEXT_put_text *
1161 * ******************
1162 *
1163 * Places text labels.
1164 */
1165TERM_PUBLIC void
1166CONTEXT_put_text(unsigned int x, unsigned int y, const char str[])
1167{
1168	const char *s; /* pointer to string */
1169	int  alignment = 0;
1170	char alignments[3][10] = {"center", "left", "right"};
1171
1172	/* ignore empty strings */
1173	if (!str || !strlen(str))
1174		return;
1175
1176	/* close and draw the current path first */
1177	if (CONTEXT_path_count > 0)
1178		CONTEXT_endpath();
1179
1180	/* see the values of "alignments" above */
1181	switch (CONTEXT_justify) {
1182		case CENTRE:
1183			alignment = 0;
1184			break;
1185		case LEFT:
1186			alignment = 1;
1187			break;
1188		case RIGHT:
1189			alignment = 2;
1190			break;
1191	}
1192
1193	/* remove whitespace at the beginning of string
1194	 * (usually a problem in positive numbers)
1195	 * They interfere with positioning: whitespace at the beginning takes
1196	 * some place although it's invisible, so left-aligned and centered labels
1197	 * are positioned incorrectly.
1198	 * Example:
1199	 *   -1 0 1 2: centered labels on x axis
1200	 * if we had a space in front, positive numbers would be "centered" in a weird way */
1201	for (s = str; s[0] == ' '; s++);
1202
1203	/* label position */
1204	fprintf(gpoutfile, "gp_put_text((%.3fa, %.3fa), ", 0.001*x, 0.001*y);
1205	/* angle of rotation - optional and needed only if it's different from 0 */
1206	if (CONTEXT_ang != 0)
1207		fprintf(gpoutfile, "angle(%d), ", CONTEXT_ang);
1208
1209	/* alignment - "center" is optional, but we'll add it anyway */
1210	fprintf(gpoutfile, "align(%s), \\sometxt[gp]", alignments[alignment]);
1211	/* fontface/fontsize - optional second argument */
1212	if (CONTEXT_font_explicit[0] != 0)
1213		fprintf(gpoutfile, "[%s]", CONTEXT_font_explicit);
1214	/* finally the text label itself */
1215	fprintf(gpoutfile, "{%s});\n", s);
1216}
1217
1218
1219/* ********************
1220 * CONTEXT_text_angle *
1221 * ********************
1222 *
1223 * Saves text angle to be used for text labels.
1224 */
1225TERM_PUBLIC int
1226CONTEXT_text_angle(int ang)
1227{
1228	CONTEXT_ang = ang;
1229	return TRUE;
1230}
1231
1232/* **********************
1233 * CONTEXT_justify_text *
1234 * **********************
1235 *
1236 * Saves horizontal text justification (left/middle/right) to be used for text labels.
1237 */
1238TERM_PUBLIC int
1239CONTEXT_justify_text(enum JUSTIFY mode)
1240{
1241	CONTEXT_justify = mode;
1242	return TRUE;
1243}
1244
1245/* ***************
1246 * CONTEXT_point *
1247 * ***************
1248 *
1249 * There are two/three possible ways of drawing points in ConTeXt:
1250 * - let gnuplot draw the points with standard move/vector commands
1251 *   (points_default): not enabled
1252 * - use the points predefined in mp-gnuplot.mp (drawn with metapost)
1253 *   which can easily be redefined
1254 *   (points_with_metapost)
1255 * - use symbols from a symbol set predefined in m-gnuplot.tex (drawn with TeX)
1256 *   (points_with_tex)
1257 *
1258 * At first this routine took care of that, but now it's up to the high-level
1259 * user interface to switch between the last two options.
1260 */
1261TERM_PUBLIC void
1262CONTEXT_point (unsigned int x, unsigned int y, int number)
1263{
1264	/* finish the current line first before the move */
1265	if (CONTEXT_path_count > 0)
1266		CONTEXT_endpath();
1267
1268	fprintf(gpoutfile, "gp_point(%.3fa,%.3fa,%d);\n", 0.001*x, 0.001*y, number);
1269}
1270
1271/* ***************
1272 * CONTEXT_arrow *
1273 * ***************
1274 * ConTeXt could draw nice arrows on its own and in such a way that user could
1275 * simply redefine arrow heads in the template file.
1276 *
1277 * This function is left here just in case that anyoune would find it useful
1278 * to define his own arrow-drawing commands.
1279 *
1280 * Currently it just calls the default gnuplot function for drawing arrows.
1281 */
1282TERM_PUBLIC void
1283CONTEXT_arrow (unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head)
1284{
1285	do_arrow(sx, sy, ex, ey, head);
1286}
1287
1288
1289/* ------------------------
1290 * CONTEXT_fontstring_parse
1291 * ------------------------
1292 *
1293 * Parses from_string, which is divided by commas (,)
1294 * and copies the whole content to to_string except for the part
1295 * which starts with a numeric value.
1296 *
1297 * That value is interpreted separately and saved to fontsize.
1298 *
1299 * to_size is the size of to_string which may not be exceeded while copying the string
1300 */
1301static void
1302CONTEXT_fontstring_parse(char *from_string, char *to_string, int to_size, double *fontsize)
1303{
1304	double tmp_fontsize = 0.;
1305	char * comma;
1306	size_t n;
1307
1308	comma = strrchr(from_string, ',');
1309	if (comma) {
1310		sscanf(comma + 1, "%lf", &tmp_fontsize);
1311		n = comma - from_string;
1312	} else {
1313		n = strlen(from_string);
1314	}
1315	*fontsize = tmp_fontsize;
1316	if (n >= to_size)
1317		n = to_size - 1;
1318	memcpy(to_string, from_string, n);
1319	to_string[n] = NUL;
1320}
1321
1322
1323/* -------------------------
1324 * CONTEXT_adjust_dimensions
1325 * -------------------------
1326 *
1327 * - sets the v_char and h_char based on current font size (approximation only)
1328 *   using CONTEXT_fontsize in points (from CONTEXT_params.fontsize) and CONTEXT_params.scale_text
1329 * - sets xmax and ymax based on CONTEXT_params.xsize and CONTEXT_params.ysize
1330 */
1331static void
1332CONTEXT_adjust_dimensions()
1333{
1334	/* sets vertical dimension of characters based on current fontsize in pt */
1335	term->v_char = (unsigned int)((double)CONTEXT_DPI *
1336		CONTEXT_fontsize / 72.27 * CONTEXT_params.scale_text + 0.5);
1337	/* based on proportions of LM digits at 12pt */
1338	term->h_char = (unsigned int)(CONTEXT_LM_H_TO_V_RATIO * term->v_char + 0.5);
1339
1340	/* we might want to fix CONTEXT_DPI in case that the figure becomes too big */
1341	if (CONTEXT_params.unit == INCHES) {
1342		term->xmax = (unsigned int)((double)CONTEXT_DPI  * CONTEXT_params.xsize + 0.5);
1343		term->ymax = (unsigned int)((double)CONTEXT_DPI  * CONTEXT_params.ysize + 0.5);
1344	} else {
1345		term->xmax = (unsigned int)((double)CONTEXT_DPCM * CONTEXT_params.xsize + 0.5);
1346		term->ymax = (unsigned int)((double)CONTEXT_DPCM * CONTEXT_params.ysize + 0.5);
1347	}
1348}
1349
1350/* *****************
1351 * CONTEXT_set_font*
1352 * *****************
1353 *
1354 * Official description:
1355 * - empty string restores the terminal's default font
1356 * - fonts are selected as strings "name,size",
1357 *   where size should be a floating point number interpreted as "pt" (point)
1358 *
1359 * It's the user's own responsibility to make sure that the proper typescripts
1360 * are included in the header, else the selected font won't work out-of-the-box
1361 *
1362 * The ConTeXt terminal should support things such as
1363 *   "iwona,ss,12"   (iwona sans serif) or
1364 *   ",10"           (10 points)  or
1365 *   "tt"            (typewriter)
1366 *
1367 * The routine saves font name to CONTEXT_font
1368 * and fontsize to CONTEXT_fontsize.
1369 *
1370 * The two are joined in CONTEXT_font_explicit for the usage in
1371 *   \sometxt[gp][fontname,fontsize]{label}
1372 */
1373TERM_PUBLIC int
1374CONTEXT_set_font(const char *font)
1375{
1376	char tmp_fontstring[MAX_ID_LEN+1] = "";
1377
1378	/* saves font name & family to CONTEXT_font */
1379	CONTEXT_fontstring_parse((char *)font, CONTEXT_font, sizeof(CONTEXT_font), &CONTEXT_fontsize_explicit);
1380	safe_strncpy(CONTEXT_font_explicit, CONTEXT_font, sizeof(CONTEXT_font_explicit));
1381
1382	/* valid fontsize has been provided */
1383	if (CONTEXT_fontsize_explicit > 0.) { /* XXX: if valid */
1384
1385		CONTEXT_fontsize = CONTEXT_fontsize_explicit;
1386
1387		snprintf(tmp_fontstring, sizeof(tmp_fontstring), ",%gpt", CONTEXT_fontsize_explicit);
1388		strncat(CONTEXT_font_explicit, tmp_fontstring,
1389                        sizeof(CONTEXT_font_explicit) - strlen(CONTEXT_font_explicit)-1);
1390		tmp_fontstring[MAX_ID_LEN] = NUL;
1391
1392	/* no fontsize has been provided: switch back to default terminal fontsize */
1393	} else if (CONTEXT_fontsize_explicit == 0) {
1394		CONTEXT_fontsize = CONTEXT_params.fontsize;
1395	}
1396
1397	/* tell to gnuplot how big the fonts in labels are */
1398	CONTEXT_adjust_dimensions();
1399
1400	return TRUE;
1401}
1402
1403/* *******************
1404 * CONTEXT_pointsize *
1405 * *******************
1406 *
1407 * Sets the (relative) point size for subsequent points
1408 *
1409 * The base point size is defined "somewhere else":
1410 * - depends on the font[size] used when "texpoints" option is on
1411 */
1412TERM_PUBLIC void
1413CONTEXT_pointsize(double pointsize)
1414{
1415	/*
1416	 * my first thought was not to allow negative sizes of points,
1417	 * but I see no reason why one shouldn't be able to play with
1418	 * inverted point shapes, so finally I commented this out again
1419	 *
1420	 *   if (pointsize < 0)
1421	 *      pointsize = 1;
1422	 */
1423
1424	if (CONTEXT_old_pointsize != pointsize) {
1425		/* close and draw the current path first */
1426		if (CONTEXT_path_count > 0)
1427			CONTEXT_endpath();
1428		fprintf(gpoutfile, "gp_set_pointsize(%.3f);\n", pointsize);
1429		CONTEXT_old_pointsize = pointsize;
1430	}
1431}
1432
1433/* *****************
1434 * CONTEXT_fillbox *
1435 * *****************
1436 *
1437 * Creates the path for the rectangle and calls the CONTEXT_fill(style)
1438 * routine (shared with CONTEXT_filled_polygon) to actually fill that shape
1439 */
1440TERM_PUBLIC void
1441CONTEXT_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)
1442{
1443	/* close and draw the current path first */
1444	if (CONTEXT_path_count > 0)
1445		CONTEXT_endpath();
1446
1447	/* create a new path */
1448	fprintf(gpoutfile, "p := unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n", 0.001*width, 0.001*height, 0.001*x1, 0.001*y1);
1449	/* fprintf(gpoutfile, "p := gp_rect ((%.3fa,%.3fa),(%.3fa,%.3fa));\n", 0.001*x1, 0.001*y1, 0.001*width, 0.001*height); */
1450
1451	/* fills the box according to the "style"
1452	 * the code went out of this routine because of undocumented behaviour
1453	 * that also the filled_polygon should paint with patterns ... */
1454	CONTEXT_fill(style);
1455}
1456
1457/* **************
1458 * CONTEXT_fill *
1459 * **************
1460 *
1461 * Filling routine, yet another undocumented feature of Gnuplot.
1462 * The code was mostly cloned from the PostScript terminal,
1463 * so that you know whom to accuse if it doesn't do what you would expect
1464 * it to do. (In case of cloning errors please inform the author of this terminal.)
1465 *
1466 * The lowest 4 bits of "style" seem to represent the style of filling
1467 * (whether it is solid or pattern-based or whatever that might appear
1468 * in that place in the future).
1469 *
1470 * The rest of the bits of "style" represent either the density
1471 * (ranging from 0 to 100) or the number of the pattern that the polygon
1472 * should be filled with.
1473 *
1474 * Used by CONTEXT_fillbox(...) and CONTEXT_filled_polygon(...)
1475 */
1476TERM_PUBLIC void
1477CONTEXT_fill(int style)
1478{
1479	int density;
1480	int pattern;
1481
1482	/* used in FS_[TRANSPARENT_]SOLID --> fill with intensity according to filldensity
1483	   it extracts a percentage out of "style" */
1484	density = (style >> 4);
1485	if (density < 0)
1486		density = 0;
1487	if (density > 100)
1488		density = 100;
1489
1490	fputs("gp_fill(p", gpoutfile);
1491
1492	/* do some strange trickery */
1493	switch (style & 0xf) {
1494
1495	case FS_DEFAULT:
1496		break;
1497
1498	case FS_TRANSPARENT_SOLID:
1499		/* just a flag to tell the terminal that density() should be used to interpret transparency */
1500		fprintf(gpoutfile, ",transparent");
1501	case FS_SOLID:
1502		/* fill the box with density "density": if no parameter density is specified,
1503		   it implies 100% density by default */
1504		if (density < 100)
1505			fprintf(gpoutfile, ",density(%.2f)", 0.01*density);
1506		break;
1507
1508	case FS_TRANSPARENT_PATTERN:
1509		/* just a flag that should be interpreted in metapost,
1510		   non-transparent patterns have to fill with background color before drawing the pattern */
1511		fprintf(gpoutfile, ",transparent");
1512	case FS_PATTERN:
1513		pattern = (style >> 4);
1514		fprintf(gpoutfile, ",pattern(%d)", pattern);
1515		break;
1516
1517	default: /* style == 0 (FS_EMPTY) or unknown --> fill with background color */
1518		fprintf(gpoutfile, ",density(0)");
1519	}
1520	/* TODO: FS_DEFAULT is missing; what should that one do? */
1521
1522	/* gp_fill(p,...); */
1523	fputs(");\n", gpoutfile);
1524}
1525
1526/* *******************
1527 * CONTEXT_linewidth *
1528 * *******************
1529 *
1530 * scale line width (similar to pointsize)
1531 * remembers the values locally (no serious need for that actually) and writes them into file
1532 */
1533TERM_PUBLIC void
1534CONTEXT_linewidth(double linewidth)
1535{
1536	if (linewidth < 0)
1537		linewidth = 1.0;
1538
1539	if (CONTEXT_old_linewidth != linewidth) {
1540		/* close and draw the current path first */
1541		if (CONTEXT_path_count > 0)
1542			CONTEXT_endpath();
1543		fprintf(gpoutfile, "gp_set_linewidth(%.3f);\n", linewidth);
1544		CONTEXT_old_linewidth = linewidth;
1545	}
1546}
1547
1548/* ------------------------------
1549 * CONTEXT_write_palette_gradient
1550 * ------------------------------
1551 *
1552 * Writes the colors and positions for a gradient palette.
1553 */
1554static void
1555CONTEXT_write_palette_gradient(gradient_struct *gradient, int cnt)
1556{
1557	int i;
1558
1559	/* i-th color */
1560	fprintf(gpoutfile, "colors(");
1561	for (i = 0; i < cnt; i++) {
1562		if (i > 0)
1563		    fprintf(gpoutfile, ",");
1564		fprintf(gpoutfile, "(%.3g,%.3g,%.3g)", gradient[i].col.r, gradient[i].col.g, gradient[i].col.b);
1565	}
1566
1567	/* position of the i-th color */
1568	fprintf(gpoutfile, ");positions(");
1569	for (i = 0; i < cnt; i++) {
1570		if (i > 0)
1571			fprintf(gpoutfile, ",");
1572		fprintf(gpoutfile, "%.4g", gradient[i].pos);
1573	}
1574	fprintf(gpoutfile, ")");
1575}
1576
1577/* ---------------------
1578 * CONTEXT_write_palette
1579 * ---------------------
1580 *
1581 */
1582static void
1583CONTEXT_write_palette(t_sm_palette *palette)
1584{
1585	if (palette == NULL)
1586		return;
1587
1588/* TODO
1589	// Color models: RGB, HSV, CMY, XYZ
1590	//
1591	// RGB: Red, Green, Blue
1592	// HSV: Hue, Saturation, Value
1593	// CMY
1594	//
1595	// two models that gnuplot uses, but which probably won't be supported by this terminal:
1596	// XYZ: three primary colors of the color model defined by the 'Commission Internationale de l'Eclairage' (CIE)
1597	// http://www.cs.rit.edu/~ncs/color/glossary.htm
1598	// http://cs.fit.edu/wds/classes/cse5255/cse5255/davis/index.html
1599*/
1600	fprintf(gpoutfile, "gp_make_palette(");
1601	switch (sm_palette.colorMode) {
1602		/* grayscale only */
1603		case SMPAL_COLOR_MODE_GRAY:
1604			fprintf(gpoutfile, "color_mode(gray)");
1605			break;
1606		/* one of several fixed transformations */
1607		case SMPAL_COLOR_MODE_RGB:
1608			fprintf(gpoutfile, "color_mode(rgb);formulae(%d,%d,%d)",
1609				sm_palette.formulaR,
1610				sm_palette.formulaG,
1611				sm_palette.formulaB);
1612			break;
1613		/* user defined transforms */
1614		case SMPAL_COLOR_MODE_FUNCTIONS:
1615			fprintf(gpoutfile, "color_mode(functions)");
1616			break;
1617		/* interpolated table: explicitly defined or read from file */
1618		case SMPAL_COLOR_MODE_GRADIENT:
1619			fprintf(gpoutfile, "color_mode(gradient);");
1620			CONTEXT_write_palette_gradient(palette->gradient, palette->gradient_num);
1621			break;
1622		case SMPAL_COLOR_MODE_NONE:
1623			break;
1624		default:
1625			break;
1626	}
1627	fprintf(gpoutfile, ");\n");
1628}
1629
1630/* *********************
1631 * CONTEXT_make_palette*
1632 * *********************
1633 *
1634 * 1. if palette==NULL, then return nice/suitable
1635 *    maximal number of colours supported by this terminal.
1636 *    Returns 0 if it can make colours without palette (like
1637 *    postscript).
1638 * 2. if palette!=NULL, then allocate its own palette
1639 *    return value is undefined
1640 * 3. available: some negative values of max_colors for whatever
1641 *    can be useful
1642 */
1643TERM_PUBLIC int
1644CONTEXT_make_palette(t_sm_palette *palette)
1645{
1646	if (palette == NULL)
1647		return 0;  /* ConTeXt can do continuous colors */
1648
1649	/* save the palette */
1650	CONTEXT_old_palette = palette;
1651
1652	return 0;
1653}
1654
1655
1656/*
1657 * most probably this one is not needed
1658 *
1659 * TERM_PUBLIC void
1660 * CONTEXT_previous_palette(){}
1661 *
1662 */
1663
1664/* *******************
1665 * CONTEXT_set_color *
1666 * *******************
1667 *
1668 * typedef struct t_colorspec {
1669 *    int    type;    // TC_ DEFAULT, LT, LINESTYLE, RGB, CB, FRAC, Z
1670 *    int    lt;      // used for TC_LT, TC_LINESTYLE and TC_RGB
1671 *    double value;   // used for TC_CB and TC_FRAC
1672 * } t_colorspec;
1673 */
1674TERM_PUBLIC void
1675CONTEXT_set_color(t_colorspec *colorspec)
1676{
1677	double gray, r, g, b;
1678	/* ConTeXt doesn't offer full support for palettes yet
1679	   (I don't know how to trick metapost to accept the full palette specification)
1680	   so we convert the colors from palettes to RGB instead.
1681	   If terminal starts supporting palettes, this behaviour will change.
1682	*/
1683	rgb_color rgb1;
1684
1685/* If (colorspec->type == TC_FRAC):
1686   Set current color according to colorspec->value, where 0 <= value <= 1.
1687   If using a palette, first map value to an integer i in the interval
1688   [0...num_colors-1], then set to the ith color in the palette.
1689   If (colorspec->type == TC_RGB):
1690   Set current color to the rgb triple given in colorspec->lt. */
1691
1692	/* close and draw the current path first */
1693	if (CONTEXT_path_count > 0)
1694		CONTEXT_endpath();
1695
1696	switch (colorspec->type) {
1697
1698	/* TC_DEFAULT, TC_CB, TC_Z: probably unused; what about linestyle? */
1699
1700	/* color equal as that of linetype in colorspec->lt */
1701	case TC_LT:
1702		fprintf(gpoutfile, "gp_set_color(lt(%d));\n", colorspec->lt);
1703		CONTEXT_color_changed = TRUE;
1704		break;
1705
1706	/* rgb color */
1707	case TC_RGB:
1708		r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
1709		g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
1710		b = (double)(colorspec->lt & 255) / 255.;
1711
1712		fprintf(gpoutfile, "gp_set_color(rgb(%3.2f,%3.2f,%3.2f));\n", r, g, b);
1713		CONTEXT_color_changed = TRUE;
1714		break;
1715
1716	/* map [0:1] to gray colors or to the corresponding color from the palette */
1717	case TC_FRAC:
1718		gray = colorspec->value;
1719
1720		/* limit negative and >1 values to [0:1] first */
1721		if (gray < 0) gray = 0;
1722		if (gray > 1) gray = 1;
1723
1724		/* TODO: if ConTeXt start supporting palettes, we'll uncomment the following: */
1725		fprintf(gpoutfile, "%%gp_set_color(frac(%.4f));\n", gray);
1726		/* but now it doesn't, so let's use the fallback instead: */
1727		rgb1maxcolors_from_gray(gray, &rgb1);
1728		fprintf(gpoutfile, "gp_set_color(rgb(%3.2f,%3.2f,%3.2f));\n", rgb1.r, rgb1.g, rgb1.b);
1729
1730		CONTEXT_color_changed = TRUE;
1731		break;
1732	default:
1733		int_warn(NO_CARET,"context.trm set_color unknown colorspec->type %i", colorspec->type);
1734		break;
1735	}
1736}
1737
1738
1739/* ************************
1740 * CONTEXT_filled_polygon *
1741 * ************************
1742 *
1743 * Draws a polygon with the fill color set by set_color, and no border.
1744 */
1745TERM_PUBLIC void
1746CONTEXT_filled_polygon(int points, gpiPoint *corners)
1747{
1748	int i;
1749
1750	/* nothing to be filled if less than 3 points */
1751	if (points < 3)
1752		return;
1753
1754	/* close and draw the current path first */
1755	if (CONTEXT_path_count > 0)
1756		CONTEXT_endpath();
1757
1758	/* if the first point equals the last one, skip the last point; --cycle does that already
1759	 * this condition is probably always true in gnuplot, so the if condition may not be needed */
1760	if ((corners[0].x == corners[points-1].x) && (corners[0].y == corners[points-1].y))
1761		points--;
1762
1763	/* create new path with corners */
1764	fputs("p := ", gpoutfile);
1765	fprintf(gpoutfile, "(%.3fa,%.3fa)", 0.001*corners[0].x, 0.001*corners[0].y);
1766	for (i = 1; i < points; i++) {
1767		if (i % CONTEXT_LINEMAX == 0)
1768			fputs("\n  ", gpoutfile);
1769		fprintf(gpoutfile, "--(%.3fa,%.3fa)", 0.001*corners[i].x, 0.001*corners[i].y);
1770	}
1771	/* and fill it */
1772	fprintf(gpoutfile, "--cycle;\n");
1773
1774	/* fill the polygon
1775	 * undocumented gnuplot behaviour, copied from PostScript terminal
1776	 * see comments for CONTEXT_fill for details */
1777	CONTEXT_fill(corners->style);
1778}
1779
1780/* ***************
1781 * CONTEXT_image *
1782 * ***************
1783 *
1784   Plot a pixel-based image on the display device.
1785   'M' is the number of pixels along the y-dimension of the image and
1786   'N' is the number of pixels along the x-dimension of the image.  The
1787   coordval pointer 'image' is the pixel values normalized to the range
1788   [0:1].  These values should be scaled appropriately for the output
1789   device.  The 'image' data starts in the upper left corner and scans
1790   along rows finishing in the lower right corner.  If 'color_mode' is
1791   IC_PALETTE, the terminal is to use palette lookup to generate color
1792   information.  In this scenario the size of 'image' is M*N.  If
1793   'color_mode' is IC_RGB, successive bytes of the data structure are
1794   interpreted as RGB components of a single pixel.  In this scenario
1795   the size of 'image' is 3*M*N.  The data appears in RGB triples, i.e.,
1796   image[0] = R(1,1), image[1] = G(1,1), image[2] = B(1,1),
1797   image[3] = R(1,2), image[4] = G(1,2), ..., image[3*M*N-1] = B(M,N).
1798   The mode IC_RGBA is similar except that four values red, green, blue,
1799   alpha per pixel are passed to the terminal in the image structure.
1800   The 'image' is actually an "input" image in the sense that
1801   it must also be properly resampled for the output device.  Many output
1802   media, e.g., PostScript, do this work via various driver functions.
1803   To determine the appropriate rescaling, the 'corner' information
1804   should be used.  There are four entries in the gpiPoint data array.
1805   'corner[0]' is the upper left corner (in terms of plot location) of
1806   the outer edge of the image.  Similarly, 'corner[1]' is the lower
1807   right corner of the outer edge of the image.  (Outer edge means the
1808   outer extent of the corner pixels, not the middle of the corner
1809   pixels.)  'corner[2]' is the upper left corner of the visible part
1810   of the image, and 'corner[3]' is the lower right corner of the visible
1811   part of the image.  The information is provided in this way because
1812   often it is necessary to clip a portion of the outer pixels of the
1813   image.
1814 */
1815
1816/* TODO: this code needs some improvements
1817 *
1818 * There are two different modes:
1819 *
1820 * 1. creating PNG image and including it
1821 *    - it only works if gnuplot has been compiled with cairo or gdlib libraries
1822 *    - there are some bugs in MKII/MKIV handling: a different syntax is required
1823 *      and can only be fixed in ConTeXt core; I could abstract the code a bit
1824 * 2. printing out a string with colors
1825 *    - MKIV: works, but transparency is not yet implemented
1826 *    - MKII: requires MetaPost > 0.750 and is not implemented at all
1827 *            two possible approaches: drawing rectangles & creating proper image
1828 *            it might require one additional level of abstraction like gp_image(...)
1829 */
1830TERM_PUBLIC void
1831CONTEXT_image(unsigned M, unsigned N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
1832{
1833	int i, k, line_length, components_per_color;
1834	rgb_color color;
1835	TBOOLEAN is_clipped = FALSE;
1836
1837	if ((corner[2].x > corner[0].x) || (corner[0].y > corner[2].y) ||
1838	    (corner[1].x > corner[3].x) || (corner[3].y > corner[1].y))
1839		is_clipped = TRUE;
1840
1841	if (CONTEXT_images == CONTEXT_IMAGES_EXTERNAL) {
1842#ifdef WRITE_PNG_IMAGE
1843		/* we reserved 10 extra bytes, so we can afford images up to 9999 */
1844		if (CONTEXT_image_counter < 9999)
1845			sprintf(CONTEXT_image_filename + CONTEXT_image_filename_length,
1846				"_%02d.png", ++CONTEXT_image_counter);
1847		write_png_image (M, N, image, color_mode, CONTEXT_image_filename);
1848
1849		if (is_clipped)
1850			fprintf(gpoutfile, "draw image(\n  ");
1851		fprintf(gpoutfile, "externalfigure \"%s\" xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n",
1852			CONTEXT_image_filename + CONTEXT_image_filename_start, 0.001*(corner[1].x-corner[0].x), 0.001*(corner[0].y-corner[1].y), 0.001*corner[0].x, 0.001*corner[1].y);
1853		if (is_clipped) {
1854			fprintf(gpoutfile, "  clip currentpicture to unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa););\n",
1855				0.001*(corner[3].x-corner[2].x), 0.001*(corner[2].y-corner[3].y), 0.001*corner[2].x, 0.001*corner[3].y);
1856		}
1857#endif
1858	} else {
1859
1860		/* Palette colors have to be converted into RGB first */
1861		if (color_mode == IC_PALETTE) {
1862			/* write the image data */
1863			fprintf(gpoutfile, "img := \"%%\n");
1864			line_length = 0;
1865			for (i = 0; i < M * N; i++) {
1866				if (line_length++ >= 16) {
1867					line_length = 1;
1868					fprintf(gpoutfile, "%%\n");
1869				}
1870				rgb1maxcolors_from_gray(image[i], &color);
1871				fprintf(gpoutfile, "%02x%02x%02x", (unsigned char)(255*color.r), (unsigned char)(255*color.g), (unsigned char)(255*color.b));
1872			}
1873			fprintf(gpoutfile, "\";\n");
1874
1875		/* IC_RGB or IC_RGBA */
1876		} else {
1877			if (color_mode == IC_RGBA) {
1878				components_per_color = 4;
1879			} else { /* IC_RGB */
1880				components_per_color = 3;
1881			}
1882
1883			/* write the image data */
1884			fprintf(gpoutfile, "img := \"%%\n");
1885			line_length = 0;
1886			for (i = 0; i < M * N; i++) {
1887				if (line_length++ >= 16) {
1888					line_length = 1;
1889					fprintf(gpoutfile, "%%\n");
1890				}
1891				for (k = 0; k < 3; k++) {
1892					fprintf(gpoutfile, "%02x", (unsigned char)(image[i*components_per_color+k]*255));
1893				}
1894			}
1895			fprintf(gpoutfile, "\";\n");
1896
1897			/* transparency mask */
1898			if (color_mode == IC_RGBA) {
1899				fprintf(gpoutfile, "ima := \"%%\n");
1900				line_length = 0;
1901				for (i = 0; i < M * N; i++) {
1902					if (line_length++ >= 3*16) {
1903						line_length = 1;
1904						fprintf(gpoutfile, "%%\n");
1905					};
1906					fprintf(gpoutfile, "%02x", (unsigned char)(image[i*components_per_color+3]*255));
1907				}
1908				fprintf(gpoutfile, "\";\n");
1909			}
1910		}
1911
1912		/* TODO: transparency handling is not yet supported in ConTeXt */
1913		if (is_clipped)
1914			fprintf(gpoutfile, "draw image(\n  ");
1915		fprintf(gpoutfile, "draw bitmapimage (%u,%u,img) xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa);\n",
1916			N, M, 0.001*(corner[1].x-corner[0].x), 0.001*(corner[0].y-corner[1].y), 0.001*corner[0].x, 0.001*corner[1].y);
1917		if (is_clipped) {
1918			fprintf(gpoutfile, "  clip currentpicture to unitsquare xyscaled (%.3fa,%.3fa) shifted (%.3fa,%.3fa););\n",
1919				0.001*(corner[3].x-corner[2].x), 0.001*(corner[2].y-corner[3].y), 0.001*corner[2].x, 0.001*corner[3].y);
1920		}
1921
1922		/* (alternative implementation) *
1923		fprintf(gpoutfile, "gp_image_rgb");
1924		if (color_mode == IC_RGB)
1925			fprintf(gpoutfile, "_alpha");
1926		fprintf(gpoutfile, "((%u,%u),(%.3fa,%.3fa),(%.3fa,%.3fa));\n",
1927			N, M, 0.001*corner[0].x, 0.001*corner[1].y, 0.001*corner[1].x, 0.001*corner[0].y);
1928		*/
1929	}
1930}
1931
1932/*
1933 * TODO: Implement this function for smooth shading
1934 *
1935 * you need to fix draw_color_smooth_box(MODE_SPLOT) in graph3d.c -> color.c
1936 *
1937static void
1938CONTEXT_draw_inside_color_smooth_box()
1939{
1940}
1941 */
1942
1943#endif /* TERM_BODY */
1944
1945#ifdef TERM_TABLE
1946
1947TERM_TABLE_START(context_driver)
1948	"context", "ConTeXt with MetaFun (for PDF documents)",
1949	CONTEXT_XMAX, CONTEXT_YMAX, CONTEXT_VCHAR, CONTEXT_HCHAR,
1950	CONTEXT_VTIC, CONTEXT_HTIC, CONTEXT_options, CONTEXT_init,
1951	CONTEXT_reset, CONTEXT_text, null_scale, CONTEXT_graphics,
1952	CONTEXT_move, CONTEXT_vector,
1953	CONTEXT_linetype, CONTEXT_put_text, CONTEXT_text_angle,
1954	CONTEXT_justify_text, CONTEXT_point, CONTEXT_arrow, CONTEXT_set_font,
1955	CONTEXT_pointsize,
1956	/* also add TERM_CAN_CLIP once you understand what it does */
1957	TERM_CAN_DASH | TERM_ALPHA_CHANNEL | TERM_LINEWIDTH | TERM_FONTSCALE | TERM_IS_LATEX /* flags */,
1958	0 /* suspend */, 0 /* resume*/,
1959	CONTEXT_fillbox, CONTEXT_linewidth
1960#ifdef USE_MOUSE
1961	, 0, 0, 0, 0, 0 /* no mouse support */
1962#endif /* USE_MOUSE */
1963	, CONTEXT_make_palette,
1964	0, /* XXX: CONTEXT_previous_palette: not sure if we need it at all (PS does "grestore") */
1965	CONTEXT_set_color,
1966	CONTEXT_filled_polygon,
1967	CONTEXT_image,
1968	0, 0, 0, /* No enhanced text mode because this is TeX */
1969	0,       /* layer (used to signal front/back text, used in canvas, PS, epslatex, ...); XXX: figure out what this has to do */
1970	0        /* path (Path control for end-joins of closed polygons on PostScript-like devices); TODO: implement it (CONTEXT_path) */
1971TERM_TABLE_END(context_driver)
1972#undef LAST_TERM
1973#define LAST_TERM context_driver
1974
1975#endif /* TERM_TABLE */
1976#endif /* TERM_PROTO_ONLY */
1977
1978#ifdef TERM_HELP
1979START_HELP(context)
1980"1 context",
1981"?commands set terminal context",
1982"?set terminal context",
1983"?terminal context",
1984"?set term context",
1985"?term context",
1986"?context",
1987" ConTeXt is a macro package for TeX, highly integrated with Metapost",
1988" (for drawing figures) and intended for creation of high-quality PDF documents.",
1989" The terminal outputs Metafun source, which can be edited manually,",
1990" but you should be able to configure most things from outside.",
1991"",
1992" For an average user of ConTeXt + gnuplot module it's recommended to refer to",
1993" `Using ConTeXt` rather than reading this page",
1994" or to read the manual of the gnuplot module for ConTeXt.",
1995"",
1996" The `context` terminal supports the following options:",
1997"",
1998" Syntax:",
1999"      set term context {default}",
2000"              {defaultsize | size <scale> | size <xsize>{in|cm}, <ysize>{in|cm}}",
2001"              {input | standalone}",
2002"              {timestamp | notimestamp}",
2003"              {noheader | header \"<header>\"}",
2004"              {color | colour | monochrome}",
2005"              {rounded | mitered | beveled} {round | butt | squared}",
2006"              {dashed | solid} {dashlength | dl <dl>}",
2007"              {linewidth | lw <lw>}",
2008"              {fontscale <fontscale>}",
2009"              {mppoints | texpoints}",
2010"              {inlineimages | externalimages}",
2011"              {defaultfont | font \"{<fontname>}{,<fontsize>}\"}",
2012"",
2013" In non-standalone (`input`) graphic only parameters `size` to select graphic",
2014" size, `fontscale` to scale all the labels for a factor <fontscale>",
2015" and font size, make sense, the rest is silently",
2016" ignored and should be configured in the .tex file which inputs the graphic.",
2017" It's highly recommended to set the proper fontsize if document font differs from",
2018" 12pt, so that gnuplot will know how much space to reserve for labels.",
2019"",
2020" `default` resets all the options to their default values.",
2021"",
2022" `defaultsize` sets the plot size to 5in,3in.",
2023" `size` <scale> sets the plot size to <scale> times <default value>.",
2024" If two arguments are given (separated with ','), the first one sets",
2025" the horizontal size and the second one the vertical size.",
2026" Size may be given without units (in which case it means relative to the default",
2027" value), with inches ('in') or centimeters ('cm').",
2028"",
2029" `input` (default) creates a graphic that can be included into another ConTeXt",
2030" document.",
2031" `standalone` adds some lines, so that the document might be compiled as-is.",
2032" You might also want to add `header` in that case.",
2033"",
2034" Use `header` for any additional settings/definitions/macros",
2035" that you might want to include in a standalone graphic. `noheader` is the default.",
2036"",
2037" `notimestamp` prevents printing creation time in comments",
2038" (if version control is used, one may prefer not to commit new version when only date changes).",
2039"",
2040" `color` to make color plots is the default, but `monochrome` doesn't do anything special yet.",
2041" If you have any good ideas how the behaviour should differ to suit the monochrome printers better,",
2042" your suggestions are welcome.",
2043"",
2044" `rounded` (default), `mitered` and `beveled` control the shape of line joins.",
2045" `round` (default), `butt` and `squared` control the shape of line caps.",
2046" See PostScript or PDF Reference Manual for explanation. For wild-behaving functions",
2047" and thick lines",
2048" it is better to use `rounded` and `round` to prevent sharp corners in line joins.",
2049" (Some general support for this should be added to Gnuplot, so that the same options",
2050" could be set for each line (style) separately).",
2051"",
2052" `dashed` (default) uses different dash patterns for different line types,",
2053" `solid` draws all plots with solid lines.",
2054"",
2055" `dashlength` or `dl` scales the length of the dashed-line segments by <dl>.",
2056" `linewidth` or `lw` scales all linewidths by <lw>.",
2057" (lw 1 stands for 0.5bp, which is the default line width when drawing with Metapost.)",
2058" `fontscale` scales text labels for factor <fontscale> relative to default document font.",
2059"",
2060" `mppoints` uses predefined point shapes, drawn in Metapost.",
2061" `texpoints` uses easily configurable set of symbols, defined with ConTeXt",
2062" in the following way:",
2063"      \\defineconversion[my own points][+,{\\ss x},\\mathematics{\\circ}]",
2064"      \\setupGNUPLOTterminal[context][points=tex,pointset=my own points]",
2065"",
2066" `inlineimages` writes binary images to a string and only works in ConTeXt MKIV.",
2067" `externalimages` writes PNG files to disk and also works with ConTeXt MKII.",
2068" Gnuplot needs to have support for PNG images built in for this to work.",
2069"",
2070" With `font` you can set font name and size in standalone graphics.",
2071" In non-standalone (`input`) mode only the font size is important",
2072" to reserve enough space for text labels.",
2073" The command",
2074"      set term context font \"myfont,ss,10\"",
2075" will result in",
2076"      \\setupbodyfont[myfont,ss,10pt]",
2077" If you additionally set `fontscale` to 0.8 for example,",
2078" then the resulting font will be 8pt big and",
2079"      set label ... font \"myfont,12\"",
2080" will come out as 9.6pt.",
2081"",
2082" It is your own responsibility to provide proper typescripts (and header),",
2083" otherwise switching the font will have no effect.",
2084" For a standard font in ConTeXt MKII (pdfTeX) you could use:",
2085"      set terminal context standalone header '\\usetypescript[iwona][ec]' \\",
2086"          font \"iwona,ss,11\"",
2087" Please take a look into ConTeXt documentation, wiki or mailing list (archives)",
2088" for any up-to-date information about font usage.",
2089"",
2090" Examples:",
2091"      set terminal context size 10cm, 5cm     # 10cm, 5cm",
2092"      set terminal context size 4in, 3in      # 4in, 3in",
2093" For standalone (whole-page) plots with labels in UTF-8 encoding:",
2094"      set terminal context standalone header '\\enableregime[utf-8]'",
2095"", /* TODO: LaTeX formatting */
2096"2 Requirements",
2097" You need gnuplot module for ConTeXt",
2098"^ <a href=\"http://ctan.org/pkg/context-gnuplot\">",
2099"      http://ctan.org/pkg/context-gnuplot",
2100"^ </a>",
2101" and a recent version of ConTeXt.",
2102" If you want to call gnuplot on-the-fly, you also need write18 enabled.",
2103" In most TeX distributions this can be set with shell_escape=t in texmf.cnf.",
2104"",
2105" See",
2106"^ <a href=\"http://wiki.contextgarden.net/Gnuplot\">",
2107"           http://wiki.contextgarden.net/Gnuplot",
2108"^ </a>",
2109" for details about this terminal and for more exhaustive help & examples.",
2110"",
2111"2 Calling gnuplot from ConTeXt",
2112" The easiest way to make plots in ConTeXt documents is",
2113"      \\usemodule[gnuplot]",
2114"      \\starttext",
2115"      \\title{How to draw nice plots with {\\sc gnuplot}?}",
2116"      \\startGNUPLOTscript[sin]",
2117"      set format y \"%.1f\"",
2118"      plot sin(x) t '$\\sin(x)$'",
2119"      \\stopGNUPLOTscript",
2120"      \\useGNUPLOTgraphic[sin]",
2121"      \\stoptext",
2122" This will run gnuplot automatically and include the resulting figure in the document."
2123END_HELP(context)
2124#endif /* TERM_HELP */
2125
2126