Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / metapost.trm
1 /* Hello, Emacs, this is -*-C-*-
2  * $Id: metapost.trm,v 1.38.2.2 2008/05/31 16:08:26 sfeam Exp $
3  */
4
5 /* GNUPLOT - metapost.trm */
6
7 /*[
8  * Copyright 1990 - 1993, 1998, 2004
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /* 1999/04/22
38  *                      GNUPLOT -- metapost.trm
39  *
40  *                      This terminal driver supports:
41  *                              Metapost Commands
42  *
43  * Based on metafont.trm, written by
44  *              Pl Hedne
45  *              Trondheim, Norway
46  *              Pal.Hedne@termo.unit.no;
47  *              with improvements by Carsten Steger
48  *
49  * and pstricks.trm, written by
50  *              David Kotz and Raymond Toy
51  *
52  * Adapted to metapost by:
53  *              Daniel H. Luecking <luecking@comp.uark.edu> and
54  *              L Srinivasa Mohan <mohan@chemeng.iisc.ernet.in>
55  */
56
57 #include "driver.h"
58
59 #ifdef TERM_REGISTER
60 register_term(mp)
61 #endif
62
63 #ifdef TERM_PROTO
64 TERM_PUBLIC void MP_options __PROTO((void));
65 TERM_PUBLIC void MP_init __PROTO((void));
66 TERM_PUBLIC void MP_graphics __PROTO((void));
67 TERM_PUBLIC void MP_text __PROTO((void));
68 TERM_PUBLIC void MP_linetype __PROTO((int linetype));
69 TERM_PUBLIC void MP_move __PROTO((unsigned int x, unsigned int y));
70 TERM_PUBLIC void MP_point __PROTO((unsigned int x, unsigned int y, int number));
71 TERM_PUBLIC void MP_pointsize __PROTO((double size));
72 TERM_PUBLIC void MP_linewidth __PROTO((double width));
73 TERM_PUBLIC void MP_vector __PROTO((unsigned int ux, unsigned int uy));
74 TERM_PUBLIC void MP_arrow __PROTO((unsigned int sx, unsigned int sy,
75                                    unsigned int ex, unsigned int ey,
76                                    int head));
77 TERM_PUBLIC void MP_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
78 TERM_PUBLIC int MP_justify_text __PROTO((enum JUSTIFY mode));
79 TERM_PUBLIC int MP_text_angle __PROTO((int ang));
80 TERM_PUBLIC void MP_reset __PROTO((void));
81 TERM_PUBLIC int MP_set_font __PROTO((const char *font));
82 TERM_PUBLIC void MP_boxfill __PROTO((int style, unsigned int x1,
83                                      unsigned int y1, unsigned int width,
84                                      unsigned int height));
85 TERM_PUBLIC int MP_make_palette __PROTO((t_sm_palette *));
86 TERM_PUBLIC void MP_previous_palette __PROTO((void));
87 TERM_PUBLIC void MP_set_color __PROTO((t_colorspec *));
88 TERM_PUBLIC void MP_filled_polygon __PROTO((int, gpiPoint *));
89
90 /* 5 inches wide by 3 inches high (default) */
91 #define MP_XSIZE 5.0
92 #define MP_YSIZE 3.0
93
94 /* gnuplot units will be one pixel if printing device has this
95    resolution. Too small resolutions (like 300) can give rough
96    appearence to curves when user tries to smooth a curve by choosing
97    high sampling rate. */
98 #define MP_DPI (2400)
99
100 #define MP_XMAX (MP_XSIZE*MP_DPI)
101 #define MP_YMAX (MP_YSIZE*MP_DPI)
102
103 #define MP_HTIC (5*MP_DPI/72)   /* nominally 5pt   */
104 #define MP_VTIC (5*MP_DPI/72)   /*    "      5pt   */
105 #define MP_HCHAR (MP_DPI*53/10/72)      /*    "      5.3pt */
106 #define MP_VCHAR (MP_DPI*11/72) /*    "      11pt  */
107 #endif /* TERM_PROTO */
108
109 #ifndef TERM_PROTO_ONLY
110 #ifdef TERM_BODY
111
112 static double MP_xsize = MP_XSIZE;
113 static double MP_ysize = MP_YSIZE;
114 /* static double MP_xmax = MP_XMAX;
115    static double MP_ymax = MP_YMAX;
116  * unused, for now
117  */
118 static int MP_posx;
119 static int MP_posy;
120 static char MP_fontname[MAX_ID_LEN + 1];
121 static double MP_fontsize;
122 static double MP_textmag;
123 static enum JUSTIFY MP_justify = LEFT;
124 static int MP_ang = 0;
125 static int MP_char_code = 0;
126
127 /* number of nodes in an output line so far */
128 static int MP_linecount = 1;
129
130 /* Number of point types */
131 #define MP_POINT_TYPES 10
132
133 /* Number of line types */
134 #define MP_LINE_TYPES 8
135
136 /* are we in the middle of a MP path? */
137 static TBOOLEAN MP_inline = FALSE;
138 /* colored or dashed lines? */
139 static TBOOLEAN MP_color = FALSE;
140 static TBOOLEAN MP_solid = FALSE;
141
142 /* compatability mode*/
143 /* static TBOOLEAN MP_notex = FALSE; */
144 #define MP_NO_TEX 0
145 #define MP_TEX 1
146 #define MP_LATEX 2
147 static int MP_tex = MP_TEX;
148 /* add usepackage instructions for PSNFSS ? */
149 #define MP_PSNFSS_NONE 0
150 #define MP_PSNFSS_7    1
151 #define MP_PSNFSS_8    2
152 static int MP_psnfss = MP_PSNFSS_NONE;
153 /* should amstex packages be included? */
154 static int MP_amstex = 0;
155 /* add a4paper option to documentclass */
156 static int MP_a4paper = 0;
157 /* write a prologues line */
158 static int MP_prologues = -1;
159
160 /* has color changed? */
161 static int MP_color_changed = 0;
162
163 /* has a font change taken place? */
164 static TBOOLEAN MP_fontchanged = FALSE;
165
166 /* The old types */
167 static int MP_oldline = -2;
168
169 /* The old sizes */
170 static double MP_oldptsize = 1.0;
171 static double MP_oldpen = 1.0;
172
173 /* terminate any path in progress */
174 static void MP_endline __PROTO((void));
175
176 /* max number of path nodes before a newline */
177 #define MP_LINEMAX 5
178
179 enum MP_id {
180     MP_OPT_MONOCHROME, MP_OPT_COLOUR,
181     MP_OPT_SOLID, MP_OPT_DASHED,
182     MP_OPT_NOTEX, MP_OPT_TEX, MP_OPT_LATEX,
183     MP_OPT_A4PAPER,
184     MP_OPT_PSNFSS, MP_OPT_PSNFSS_V7, MP_OPT_NOPSNFSS,
185     MP_OPT_AMSTEX,
186     MP_OPT_FONT, MP_OPT_FONTSIZE,
187     MP_OPT_PROLOGUES, MP_OPT_NOPROLOGUES,
188     MP_OPT_MAGNIFICATION, MP_OPT_OTHER
189 };
190
191 static struct gen_table MP_opts[] = {
192     { "mo$nochrome", MP_OPT_MONOCHROME },
193     { "c$olor", MP_OPT_COLOUR },
194     { "c$olour", MP_OPT_COLOUR },
195     { "s$olid", MP_OPT_SOLID },
196     { "da$shed", MP_OPT_DASHED },
197     { "n$otex", MP_OPT_NOTEX },
198     { "t$ex", MP_OPT_TEX },
199     { "la$tex", MP_OPT_LATEX },
200     { "a4$paper", MP_OPT_A4PAPER },
201     { "am$stex", MP_OPT_AMSTEX },
202     { "ps$nfss", MP_OPT_PSNFSS },
203     { "psnfss-v$ersion7", MP_OPT_PSNFSS_V7 },
204     { "nops$nfss", MP_OPT_NOPSNFSS },
205     { "pro$logues", MP_OPT_PROLOGUES },
206     { "nopro$logues", MP_OPT_NOPROLOGUES },
207     { "ma$gnification", MP_OPT_MAGNIFICATION },
208     { "fo$nt", MP_OPT_FONT },
209     { NULL, MP_OPT_OTHER }
210 };
211
212 TERM_PUBLIC void
213 MP_options()
214 {
215     struct value a;
216
217     /* Annoying hack to handle the case of 'set termoption' after */
218     /* we have already initialized the terminal.                  */
219     if (c_token != 2) {
220         MP_color = FALSE;
221         MP_solid = FALSE;
222         MP_tex = MP_TEX;
223         MP_a4paper = 0;
224         MP_amstex  = 0;
225         MP_psnfss = MP_PSNFSS_NONE;
226         MP_fontsize = 10.0;
227         MP_textmag = 1.0;
228         MP_prologues = -1;
229         strcpy(MP_fontname, "cmr10");
230     }
231
232     while (!END_OF_COMMAND) {
233         switch (lookup_table(&MP_opts[0], c_token)) {
234         case MP_OPT_MONOCHROME:
235             MP_color = FALSE;
236             c_token++;
237             break;
238         case MP_OPT_COLOUR:
239             MP_color = TRUE;
240             c_token++;
241             break;
242         case MP_OPT_SOLID:
243             MP_solid = TRUE;
244             c_token++;
245             break;
246         case MP_OPT_DASHED:
247             MP_solid = FALSE;
248             c_token++;
249             break;
250         case MP_OPT_NOTEX:
251             MP_tex = MP_NO_TEX;
252             strcpy(MP_fontname, "pcrr8r");
253             c_token++;
254             break;
255         case MP_OPT_TEX:
256             MP_tex = MP_TEX;
257             c_token++;
258             break;
259         case MP_OPT_LATEX:
260             MP_tex = MP_LATEX;
261             c_token++;
262             break;
263         case MP_OPT_AMSTEX:
264             MP_tex = MP_LATEX; /* only makes sense when using LaTeX */
265             MP_amstex = 1;
266             c_token++;
267             break;
268         case MP_OPT_A4PAPER:
269             MP_tex = MP_LATEX; /* only makes sense when using LaTeX */
270             MP_a4paper = 1;
271             c_token++;
272             break;
273         case MP_OPT_PSNFSS:
274             MP_tex = MP_LATEX;    /* only makes sense when using LaTeX */
275             MP_psnfss = MP_PSNFSS_8;
276             c_token++;
277             break;
278         case MP_OPT_PSNFSS_V7:
279             MP_tex = MP_LATEX; /* only makes sense when using LaTeX */
280             MP_psnfss = MP_PSNFSS_7;
281             c_token++;
282             break;
283         case MP_OPT_NOPSNFSS:
284             MP_psnfss = MP_PSNFSS_NONE;
285             c_token++;
286             break;
287         case MP_OPT_PROLOGUES:
288             c_token++;
289             if (!(END_OF_COMMAND)) {
290                 int dummy_for_prologues;
291
292                 if (sscanf(gp_input_line + token[c_token].start_index,
293                            "%d", &dummy_for_prologues) == 1) {
294                     MP_prologues = dummy_for_prologues;
295                 }
296                 c_token++;
297             }
298             break;
299         case MP_OPT_NOPROLOGUES:
300             MP_prologues = -1;
301             c_token++;
302             break;
303         case MP_OPT_MAGNIFICATION:
304             c_token++;
305             if (!END_OF_COMMAND)        /* global text scaling */
306                 MP_textmag = (double) real(const_express(&a));
307             /* c_token++; */ /* Needed ??? */
308             break;
309         case MP_OPT_FONT:
310             c_token++;
311             if (isstringvalue(c_token)) {
312                 char *s = try_to_get_string();
313                 strncpy(MP_fontname, s, sizeof(MP_fontname));
314             }
315             break;
316         case MP_OPT_OTHER:
317         default:
318             if (isstring(c_token)) {    /* font name */
319                 quote_str(MP_fontname, c_token, MAX_ID_LEN);
320                 c_token++;
321             }
322             if (!END_OF_COMMAND) {      /*font size */
323                 MP_fontsize = (double) real(const_express(&a));
324                 c_token++;
325             }
326             break;
327         }
328     }
329
330     /* minimal error recovery: */
331     if (MP_fontsize < 5.0)
332         MP_fontsize = 5.0;
333     if (MP_fontsize > 99.99)
334         MP_fontsize = 99.99;
335
336     term->v_char = (unsigned int) (MP_DPI * MP_fontsize * MP_textmag * 11 / 720);
337     if (MP_tex == MP_NO_TEX) {  /* Courier is a little wider than cmtt */
338         term->h_char = (unsigned int) (MP_DPI * MP_fontsize * MP_textmag * 6.0 / 720 + 0.5);
339     } else {
340         term->h_char = (unsigned int) (MP_DPI * MP_fontsize * MP_textmag * 5.3 / 720 + 0.5);
341     }
342
343     if (MP_psnfss == MP_PSNFSS_NONE) { /* using the normal font scheme */
344       sprintf(term_options,
345             "%s %s %stex%s%s mag %.3f font \"%s\" %.2f %sprologues(%d)",
346             MP_color ? "color" : "monochrome",
347             MP_solid ? "solid" : "dashed",
348             (MP_tex == MP_NO_TEX) ? "no" : (MP_tex == MP_LATEX) ? "la" : "",
349             MP_a4paper ? " a4paper" : "",
350             MP_amstex ? " amstex" : "",
351             MP_textmag,
352             MP_fontname, MP_fontsize,
353             (MP_prologues > -1) ? "" : "no", MP_prologues );
354     } else { /* using postscript fonts */
355       sprintf(term_options,
356             "%s %s %stex%s%s mag %.3f %s %sprologues(%d)",
357             MP_color ? "color" : "monochrome",
358             MP_solid ? "solid" : "dashed",
359             (MP_tex == MP_NO_TEX) ? "no" : (MP_tex == MP_LATEX) ? "la" : "",
360             MP_a4paper ? " a4paper" : "",
361             MP_amstex ? " amstex" : "",
362             MP_textmag,
363             (MP_psnfss == MP_PSNFSS_7) ? "psnsfss(v7)" : "psnsfss",
364             (MP_prologues > -1) ? "" : "no", MP_prologues );
365     };
366 }
367
368 TERM_PUBLIC void
369 MP_init()
370 {
371     time_t now;
372     time(&now);
373     MP_posx = MP_posy = 0;
374     fprintf(gpoutfile, "%%GNUPLOT Metapost output: %s\n", asctime(localtime(&now)));
375     if (MP_prologues > -1) {
376         fprintf(gpoutfile, "prologues:=%d;\n", MP_prologues);
377     }
378     if (MP_tex == MP_LATEX) {
379         fputs("\n\
380 %% Add \\documentclass and \\begin{dcoument} for latex\n\
381 %% NB you should set the environment variable TEX to the name of your\n\
382 %% latex executable (normally latex) inorder for metapost to work\n\
383 %% or run\n\
384 %% mpost --tex=latex ...\n\
385 \n\
386 % BEGPRE\n\
387 verbatimtex\n", gpoutfile);
388         if (MP_a4paper) {
389             fputs("\\documentclass[a4paper]{article}\n", gpoutfile);
390         } else {
391             fputs("\\documentclass{article}\n", gpoutfile);
392         }
393         switch (MP_psnfss) {
394         case MP_PSNFSS_7:{
395                 fputs("\\usepackage[latin1]{inputenc}\n\
396 \\usepackage[T1]{fontenc}\n\
397 \\usepackage{times,mathptmx}\n\
398 \\usepackage{helvet}\n\
399 \\usepackage{courier}\n", gpoutfile);
400             }
401             break;
402         case MP_PSNFSS_8:{
403                 fputs("\\usepackage[latin1]{inputenc}\n\
404 \\usepackage[T1]{fontenc}\n\
405 \\usepackage{textcomp}\n\
406 \\usepackage{mathptmx}\n\
407 \\usepackage[scaled=.92]{helvet}\n\
408 \\usepackage{courier}\n\
409 \\usepackage{latexsym}\n", gpoutfile);
410             }
411             break;
412         }
413         if (MP_amstex) {
414           fputs("\\usepackage[intlimits]{amsmath}\n\
415 \\usepackage{amsfonts}\n", gpoutfile);
416           };
417         fputs("\\begin{document}\n\
418 etex\n% ENDPRE\n", gpoutfile);
419     }
420
421     fputs("\n\
422 warningcheck:=0;\n\
423 defaultmpt:=mpt:=4;\n\
424 th:=.6;\n\
425 %% Have nice sharp joins on our lines\n\
426 linecap:=butt;\n\
427 linejoin:=mitered;\n\
428 \n\
429 def scalepen expr n = pickup pencircle scaled (n*th) enddef;\n\
430 def ptsize expr n = mpt:=n*defaultmpt enddef;\n\
431 \n", gpoutfile);
432
433     fprintf(gpoutfile, "\ntextmag:=%6.3f;\n", MP_textmag);
434
435     fputs("\
436 vardef makepic(expr str) =\n\
437   if picture str : str scaled textmag\n\
438   % otherwise a string\n\
439   else: str infont defaultfont scaled (defaultscale*textmag)\n\
440   fi\n\
441 enddef;\n\
442 \n\
443 def infontsize(expr str, size) =\n\
444   infont str scaled (size / fontsize str)\n\
445 enddef;\n", gpoutfile);
446
447     if (MP_tex == MP_NO_TEX) {
448         fprintf(gpoutfile, "\n\
449 defaultfont:= \"%s\";\n\
450 defaultscale := %6.3f/fontsize defaultfont;\n", MP_fontname, MP_fontsize);
451     } else {
452         if (MP_tex != MP_LATEX) {
453             fputs("\n\
454 %font changes\n\
455 verbatimtex\n\
456 \\def\\setfont#1#2{%.\n\
457   \\font\\gpfont=#1 at #2pt\n\
458 \\gpfont}\n", gpoutfile);
459             fprintf(gpoutfile, "\\setfont{%s}{%5.2f}\netex\n",
460                     MP_fontname, MP_fontsize);
461         }
462     }
463     fputs("\n\
464 color currentcolor; currentcolor:=black;\n\
465 color fillcolor;\n\
466 boolean colorlines,dashedlines;\n", gpoutfile);
467     if (MP_color) {
468         fputs("colorlines:=true;\n", gpoutfile);
469     } else {
470         fputs("colorlines:=false;\n", gpoutfile);
471     }
472     if (MP_solid) {
473         fputs("dashedlines:=false;\n", gpoutfile);
474     } else {
475         fputs("dashedlines:=true;\n", gpoutfile);
476     }
477     fputs("\n\
478 def _wc = withpen currentpen withcolor currentcolor enddef;\n\
479 def _ac = addto currentpicture enddef;\n\
480 def _sms = scaled mpt shifted enddef;\n\
481 % drawing point-types\n\
482 def gpdraw (expr n, x, y) =\n\
483   if n<0: _ac contour fullcircle _sms (x,y)\n\
484   elseif (n=1) or (n=3):\n\
485     _ac doublepath ptpath[n] _sms (x,y) _wc;\n\
486     _ac doublepath ptpath[n] rotated 90 _sms (x,y) _wc\n\
487   elseif n<6: _ac doublepath ptpath[n] _sms (x,y) _wc\n\
488   else: _ac contour ptpath[n] _sms (x,y) _wc\n\
489   fi\n\
490 enddef;\n\
491 \n\
492 % the point shapes\n\
493 path ptpath[];\n\
494 %diamond\n\
495 ptpath0 = ptpath6 = (-1/2,0)--(0,-1/2)--(1/2,0)--(0,1/2)--cycle;\n\
496 % plus sign\n\
497 ptpath1 = (-1/2,0)--(1/2,0);\n\
498 % square\n\
499 ptpath2 = ptpath7 = (-1/2,-1/2)--(1/2,-1/2)--(1/2,1/2)--(-1/2,1/2)--cycle;\n\
500 % cross\n\
501 ptpath3 := (-1/2,-1/2)--(1/2,1/2);\n\
502 % circle:\n\
503 ptpath4 = ptpath8:= fullcircle;\n\
504 % triangle\n\
505 ptpath5 = ptpath9 := (0,1/2)--(-1/2,-1/2)--(1/2,-1/2)--cycle;\n\
506 \n\
507 def linetype expr n =\n\
508   currentcolor:= if colorlines : col[n] else: black fi;\n\
509   if n = -1 :\n\
510       drawoptions(withcolor currentcolor withpen (currentpen scaled .5));\n\
511   elseif n < 1 :\n\
512     drawoptions(_wc);\n\
513   else :\n\
514     drawoptions( if dashedlines: dashed lt[n] fi _wc);\n\
515   fi\n\
516 enddef;\n\
517 \n\
518 % dash patterns\n\
519 picture lt[];\n\
520 lt1=dashpattern(on 2 off 2); % dashes\n\
521 lt2=dashpattern(on 2 off 2 on 0.2 off 2); %dash-dot\n\
522 lt3=lt1 scaled 1.414;\n\
523 lt4=lt2 scaled 1.414;\n\
524 lt5=lt1 scaled 2;\n\
525 lt6:=lt2 scaled 2;\n\
526 lt7=dashpattern(on 0.2 off 2); %dots\n\
527 \n\
528 color col[],cyan, magenta, yellow;\n\
529 cyan=blue+green; magenta=red+blue;yellow=green+red;\n\
530 col[-2]:=col[-1]:=col0:=black;\n\
531 col1:=red;\n\
532 col2:=(.2,.2,1); %blue\n\
533 col3:=(1,.66,0); %orange\n\
534 col4:=.85*green;\n\
535 col5:=.9*magenta;\n\
536 col6:=0.85*cyan;\n\
537 col7:=.85*yellow;\n\
538 \n\
539 %placing text\n\
540 picture GPtext;\n\
541 def put_text(expr pic, x, y, r, j) =\n\
542   GPtext:=makepic(pic);\n\
543   GPtext:=GPtext shifted\n\
544     if j = 1: (-(ulcorner GPtext + llcorner GPtext)/2)\n\
545     elseif j = 2: (-center GPtext)\n\
546     else: (-(urcorner GPtext + lrcorner GPtext)/2)\n\
547     fi\n\
548     rotated r;\n\
549   draw GPtext shifted (x,y)\n\
550 enddef;\n", gpoutfile);
551 }
552
553 TERM_PUBLIC void
554 MP_graphics()
555 {
556     /* initialize "remembered" drawing parameters */
557     MP_oldline = -2;
558     MP_oldpen = 1.0;
559     MP_oldptsize = pointsize;
560     fprintf(gpoutfile, "\nbeginfig(%d);\nw:=%.3fin;h:=%.3fin;\n",
561             MP_char_code, MP_xsize, MP_ysize);
562     /* MetaPost can only handle numbers up to 4096. When MP_DPI
563      * is larger than 819, this is exceeded by (term->xmax). So we
564      * scale it and all coordinates down by factor of 10.0. And
565      * compensate by scaling a and b up.
566      */
567     fprintf(gpoutfile, "a:=w/%.1f;b:=h/%.1f;\n",
568             (term->xmax) / 10.0, (term->ymax) / 10.0);
569     fprintf(gpoutfile, "scalepen 1; ptsize %.3f;linetype -2;\n", pointsize);
570     MP_char_code++;
571     /* reset MP_color_changed */
572     MP_color_changed = 0;
573 }
574
575 TERM_PUBLIC void
576 MP_text()
577 {
578     if (MP_inline)
579         MP_endline();
580     fputs("endfig;\n", gpoutfile);
581 }
582
583 TERM_PUBLIC void
584 MP_linetype(int lt)
585 {
586     int linetype = lt;
587
588     if (linetype >= MP_LINE_TYPES)
589         linetype %= MP_LINE_TYPES;
590     if (MP_inline)
591         MP_endline();
592     /* reset the color in case it has been changed in MP_set_color() */
593     if (MP_color_changed) {
594         MP_oldline = linetype + 1;
595         MP_color_changed = 0;
596     }
597     if (MP_oldline != linetype) {
598         fprintf(gpoutfile, "linetype %d;\n", linetype);
599         MP_oldline = linetype;
600     }
601 }
602
603 TERM_PUBLIC void
604 MP_move(unsigned int x, unsigned int y)
605 {
606     if ((x != MP_posx) || (y != MP_posy)) {
607         if (MP_inline)
608             MP_endline();
609         MP_posx = x;
610         MP_posy = y;
611     }                           /* else we seem to be there already */
612 }
613
614 TERM_PUBLIC void
615 MP_point(unsigned int x, unsigned int y, int pt)
616 {
617     int pointtype = pt;
618     if (MP_inline)
619         MP_endline();
620
621     /* Print the shape defined by 'number'; number < 0 means
622        to use a dot, otherwise one of the defined points. */
623
624     if (pointtype >= MP_POINT_TYPES)
625         pointtype %= MP_POINT_TYPES;
626 /* Change %d to %f, divide x,y by 10 */
627     fprintf(gpoutfile, "gpdraw(%d,%.1fa,%.1fb);\n", pointtype, x / 10.0, y / 10.0);
628 }
629
630 TERM_PUBLIC void
631 MP_pointsize(double ps)
632 {
633     if (ps < 0)
634         ps = 1;
635     if (MP_oldptsize != ps) {
636         if (MP_inline)
637             MP_endline();
638         fprintf(gpoutfile, "ptsize %.3f;\n", ps);
639         MP_oldptsize = ps;
640     }
641 }
642
643
644 TERM_PUBLIC void
645 MP_linewidth(double lw)
646 {
647     if (MP_oldpen != lw) {
648         if (MP_inline)
649             MP_endline();
650         fprintf(gpoutfile, "scalepen %.3f;\n", lw);
651         MP_oldpen = lw;
652     }
653 }
654
655
656 TERM_PUBLIC void
657 MP_vector(unsigned int ux, unsigned int uy)
658 {
659     if ((ux == MP_posx) && (uy == MP_posy))
660         return;                 /* Zero length line */
661
662     if (MP_inline) {
663         if (MP_linecount++ >= MP_LINEMAX) {
664             fputs("\n", gpoutfile);
665             MP_linecount = 1;
666         }
667     } else {
668         MP_inline = TRUE;
669         fprintf(gpoutfile, "draw (%.1fa,%.1fb)", MP_posx / 10.0, MP_posy / 10.0);
670         MP_linecount = 2;
671     }
672     MP_posx = ux;
673     MP_posy = uy;
674     fprintf(gpoutfile, "--(%.1fa,%.1fb)", MP_posx / 10.0, MP_posy / 10.0);
675 }
676
677 static void
678 MP_endline()
679 {
680     MP_inline = FALSE;
681     fprintf(gpoutfile, ";\n");
682 }
683
684 TERM_PUBLIC void
685 MP_arrow(unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head)
686 {
687     MP_move(sx, sy);
688     if (head) {
689         fprintf(gpoutfile, "%s (%.1fa,%.1fb)--(%.1fa,%.1fb);\n",
690                 head == 1 ? "drawarrow" : "drawdblarrow",
691                 sx / 10.0, sy / 10.0, ex / 10.0, ey / 10.0);
692     } else if ((sx != ex) || (sy != ey)) {
693         fprintf(gpoutfile, "draw (%.1fa,%.1fb)--(%.1fa,%.1fb);\n",
694                 sx / 10.0, sy / 10.0, ex / 10.0, ey / 10.0);
695     }   /* else: arrow with no length and no head = sound of one hand clapping? */
696     MP_posx = ex;
697     MP_posy = ey;
698
699 }
700
701 TERM_PUBLIC void
702 MP_put_text(unsigned int x, unsigned int y, const char str[])
703 {
704     int i, j = 0;
705     char *text;
706
707     /* ignore empty strings */
708     if (!str || !*str)
709         return;
710
711     /* F***. why do drivers need to modify string args? */
712     text = gp_strdup(str);
713
714     if (MP_inline)
715         MP_endline();
716
717
718     switch (MP_justify) {
719     case LEFT:
720         j = 1;
721         break;
722     case CENTRE:
723         j = 2;
724         break;
725     case RIGHT:
726         j = 3;
727         break;
728     }
729     if (MP_tex == MP_NO_TEX) {
730         for (i = 0; i < strlen(text); i++)
731             if (text[i] == '"')
732                 text[i] = '\''; /* Replace " with ' */
733         if (MP_fontchanged) {
734             fprintf(gpoutfile, "\
735 put_text(\"%s\" infontsize(\"%s\",%5.2f), %.1fa, %.1fb, %d, %d);\n",
736                     text, MP_fontname, MP_fontsize,
737                     x / 10.0, y / 10.0, MP_ang, j);
738         } else {
739             fprintf(gpoutfile, "put_text(\"%s\", %.1fa, %.1fb, %d, %d);\n",
740                     text, x / 10.0, y / 10.0, MP_ang, j);
741         }
742     } else if (MP_fontchanged) {
743         if (MP_tex != MP_LATEX) {
744             fprintf(gpoutfile, "\
745 put_text( btex \\setfont{%s}{%5.2f} %s etex, %.1fa, %.1fb, %d, %d);\n",
746                     MP_fontname, MP_fontsize, text,
747                     x / 10.0, y / 10.0, MP_ang, j);
748         } else {
749             fprintf(gpoutfile, "put_text( btex %s etex, %.1fa, %.1fb, %d, %d);\n",
750                     text, x / 10.0, y / 10.0, MP_ang, j);
751         }
752     } else {
753         fprintf(gpoutfile, "put_text( btex %s etex, %.1fa, %.1fb, %d, %d);\n",
754                 text, x / 10.0, y / 10.0, MP_ang, j);
755     }
756
757     free(text);
758 }
759
760 TERM_PUBLIC int
761 MP_justify_text(enum JUSTIFY mode)
762 {
763     MP_justify = mode;
764     return (TRUE);
765 }
766
767 TERM_PUBLIC int
768 MP_text_angle(int ang)
769 {
770     /* Metapost code does the conversion */
771     MP_ang = ang;
772     return (TRUE);
773 }
774
775 TERM_PUBLIC int
776 MP_set_font(const char *font)
777 {
778     if (*font) {
779         size_t sep = strcspn(font, ",");
780         strncpy(MP_fontname, font, sep);
781         MP_fontname[sep] = NUL;
782         sscanf(&(font[sep + 1]), "%lf", &MP_fontsize);
783         if (MP_fontsize < 5)
784             MP_fontsize = 5.0;
785         if (MP_fontsize >= 100)
786             MP_fontsize = 99.99;
787         /*  */
788         MP_fontchanged = TRUE;
789     } else {
790         MP_fontchanged = FALSE;
791     }
792     return TRUE;
793 }
794
795
796 TERM_PUBLIC void
797 MP_reset()
798 {
799     if (MP_tex == MP_LATEX) {
800         fputs("% BEGPOST\n",gpoutfile);
801         fputs("verbatimtex\n",gpoutfile);
802         fputs(" \\end{document}\n",gpoutfile);
803         fputs("etex\n",gpoutfile);
804         fputs("% ENDPOST\n",gpoutfile);
805     };
806     fputs("end.\n", gpoutfile);
807 }
808
809 TERM_PUBLIC void
810 MP_boxfill(
811     int style,
812     unsigned int x1, unsigned int y1,
813     unsigned int wd, unsigned int ht)
814 {
815
816     /* fillpar:
817      * - solid   : 0 - 100% intensity
818      * - pattern : 0 - n    pattern number
819      */
820     int fillpar = style >> 4;
821     style &= 0xf;
822
823     if (MP_inline)
824         MP_endline();
825
826     switch (style) {
827
828         case FS_EMPTY: /* fill with background color */
829             fprintf(gpoutfile, "\
830 fill (%.1fa,%.1fb)--(%.1fa,%.1fb)--(%.1fa,%.1fb)--(%.1fa,%.1fb)--cycle withcolor background;\n",
831                 x1 / 10.0, y1 / 10.0, (x1 + wd) / 10.0, y1 / 10.0,
832                 (x1 + wd) / 10.0, (y1 + ht) / 10.0, x1 / 10.0,
833                 (y1 + ht) / 10.0);
834             break;
835
836         case FS_PATTERN: /* pattern fill */
837             /* FIXME: not yet implemented, dummy it up as fill density */
838             fillpar *= 12;
839
840         default:
841         case FS_SOLID: /* solid fill */
842             if (fillpar < 100) {
843                 double density = (100-fillpar) * 0.01;
844                 fprintf(gpoutfile,"fillcolor:=currentcolor*%.2f+background*%.2f;\n",
845                     1.0-density, density);
846                 MP_color_changed = 1;
847             } else
848                 fprintf(gpoutfile,"fillcolor:=currentcolor;\n");
849             fprintf(gpoutfile, "\
850 fill (%.1fa,%.1fb)--(%.1fa,%.1fb)--(%.1fa,%.1fb)--(%.1fa,%.1fb)--cycle withpen (pencircle scaled 0pt) withcolor fillcolor;\n",
851             x1 / 10.0, y1 / 10.0, (x1 + wd) / 10.0, y1 / 10.0,
852             (x1 + wd) / 10.0, (y1 + ht) / 10.0, x1 / 10.0,
853             (y1 + ht) / 10.0);
854             break;
855
856     }
857
858 }
859
860 TERM_PUBLIC int
861 MP_make_palette(t_sm_palette *palette)
862 {
863     /* metapost can do continuous number of colours */
864     return 0;
865 }
866
867
868 TERM_PUBLIC void
869 MP_set_color(t_colorspec *colorspec)
870 {
871     double gray = colorspec->value;
872     rgb_color color;
873
874     /* remeber that we changed the color, needed to reset color in MP_linetype()*/
875     MP_color_changed = 1;
876
877     if (MP_inline)
878         MP_endline();
879
880     if (!MP_color) {            /* gray mode */
881         if (gray < 1e-3) gray = 0;
882         fprintf(gpoutfile, "currentcolor:=%.3gwhite;\n", gray);
883     } else {                    /* color mode */
884         if (colorspec->type == TC_LT) {
885             int linecolor = colorspec->lt;
886             if (linecolor >= MP_LINE_TYPES)
887                 linecolor %= MP_LINE_TYPES;
888             if (linecolor == -1)
889                 fprintf(gpoutfile, "currentcolor:=black;\n");
890             else if (linecolor >= 0)
891                 fprintf(gpoutfile, "currentcolor:=col%d;\n",linecolor);
892         }
893         if (colorspec->type == TC_FRAC) {
894             if (sm_palette.colors != 0) /* finite nb of colors explicitly requested */
895                 gray = (gray >= ((double)(sm_palette.colors-1)) / sm_palette.colors) ?
896                     1 : floor(gray * sm_palette.colors) / sm_palette.colors;
897             rgb1_from_gray( gray, &color );
898         } else if (colorspec->type == TC_RGB) {
899             color.r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
900             color.g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
901             color.b = (double)(colorspec->lt & 255) / 255.;
902         } else
903             return;
904
905         if (color.r < 1e-4) color.r = 0;
906         if (color.g < 1e-4) color.g = 0;
907         if (color.b < 1e-4) color.b = 0;
908         fprintf(gpoutfile, "currentcolor:=%.4g*red+%.4g*green+%.4g*blue;\n",
909                 color.r, color.g, color.b);
910     }
911     return;
912 }
913
914 TERM_PUBLIC void
915 MP_filled_polygon(int points, gpiPoint *corners)
916 {
917     int i;
918     int fillpar = corners->style >> 4;
919     int style = corners->style & 0xf;
920
921     if (MP_inline)
922         MP_endline();
923
924     switch (style) {
925         case FS_EMPTY:  /* fill with background color */
926                 fprintf(gpoutfile,"fillcolor:=background;\n");
927                 break;
928         case FS_PATTERN: /* pattern fill implemented as partial density */
929                 fillpar *= 12;
930         case FS_SOLID:  /* solid fill */
931                 if (fillpar < 100) {
932                     double density = (100-fillpar) * 0.01;
933                     fprintf(gpoutfile,"fillcolor:=currentcolor*%.2f+background*%.2f;\n",
934                         1.0-density, density);
935                 } else {
936                     fprintf(gpoutfile,"fillcolor:=currentcolor;\n");
937                 }
938         default:
939                 break;
940     }
941
942     fprintf(gpoutfile, "fill ");
943     for (i = 0; i < points; i++)
944         fprintf(gpoutfile, "(%.1fa,%.1fb)%s",
945                 corners[i].x / 10.0, corners[i].y / 10.0,
946                 (i < points - 1 && (i + 1) % MP_LINEMAX == 0) ? "\n--" : "--");
947     fprintf(gpoutfile, "cycle withcolor fillcolor;\n");
948 }
949
950 TERM_PUBLIC void
951 MP_previous_palette()
952 {
953     return;
954 }
955
956 #endif /* TERM_BODY */
957
958 #ifdef TERM_TABLE
959
960 TERM_TABLE_START(mp_driver)
961     "mp", "MetaPost plotting standard",
962     MP_XMAX, MP_YMAX, MP_VCHAR, MP_HCHAR,
963     MP_VTIC, MP_HTIC, MP_options, MP_init, MP_reset,
964     MP_text, null_scale, MP_graphics, MP_move, MP_vector,
965     MP_linetype, MP_put_text, MP_text_angle,
966     MP_justify_text, MP_point, MP_arrow, MP_set_font, MP_pointsize,
967     TERM_BINARY|TERM_CAN_CLIP /*flags*/, 
968     0, 0, MP_boxfill, MP_linewidth
969 #ifdef USE_MOUSE
970     , 0, 0, 0, 0, 0             /* no mouse support for metapost */
971 #endif
972     , MP_make_palette,
973     MP_previous_palette,        /* write grestore */
974     MP_set_color,
975     MP_filled_polygon
976 TERM_TABLE_END(mp_driver)
977 #undef LAST_TERM
978 #define LAST_TERM mp_driver
979
980 #endif                          /* TERM_TABLE */
981 #endif                          /* TERM_PROTO_ONLY */
982
983 #ifdef TERM_HELP
984 START_HELP(mp)
985 "1 mp",
986 "?commands set terminal mpost",
987 "?set terminal mp",
988 "?set term mp",
989 "?terminal mp",
990 "?term mp",
991 "?mp",
992 "?metapost",
993 "",
994 " The `mp` driver produces output intended to be input to the Metapost program.",
995 " Running Metapost on the file creates EPS files containing the plots. By",
996 " default, Metapost passes all text through TeX.  This has the advantage of",
997 " allowing essentially  any TeX symbols in titles and labels.",
998 "",
999 " Syntax:",
1000 "    set term mp {color | colour | monochrome}",
1001 "                {solid | dashed}",
1002 "                {notex | tex | latex}",
1003 "                {magnification <magsize>}",
1004 "                {psnfss | psnfss-version7 | nopsnfss}",
1005 "                {prologues <value>}",
1006 "                {a4paper}",
1007 "                {amstex}",
1008 "                {\"<fontname>\"} {<fontsize>}",
1009 "",
1010 " The option `color` causes lines to be drawn in color (on a printer or display",
1011 " that supports it), `monochrome` (or nothing) selects black lines.  The option",
1012 " `solid` draws solid lines, while `dashed` (or nothing) selects lines with",
1013 " different patterns of dashes.  If `solid` is selected but `color` is not,",
1014 " nearly all lines will be identical.  This may occasionally be useful, so it is",
1015 " allowed.",
1016 "",
1017 " The option `notex` bypasses TeX entirely, therefore no TeX code can be used in",
1018 " labels under this option.  This is intended for use on old plot files or files",
1019 " that make frequent use of common characters like `$` and `%` that require",
1020 " special handling in TeX.",
1021 "",
1022 " The option `tex` sets the terminal to output its text for TeX to process.",
1023 "",
1024 " The option `latex` sets the terminal to output its text for processing by",
1025 " LaTeX. This allows things like \\frac for fractions which LaTeX knows about",
1026 " but TeX does not.  Note that you must set the environment variable TEX to the",
1027 " name of your LaTeX executable (normally latex) if you use this option or use",
1028 " `mpost --tex=<name of LaTeX executable> ...`. Otherwise metapost will try and",
1029 " use TeX to process the text and it won't work.",
1030 "",
1031 " Changing font sizes in TeX has no effect on the size of mathematics, and there",
1032 " is no foolproof way to make such a change, except by globally  setting a",
1033 " magnification factor. This is the purpose of the `magnification` option. It",
1034 " must be followed by a scaling factor. All text (NOT the graphs) will be scaled",
1035 " by this factor. Use this if you have math that you want at some size other",
1036 " than the default 10pt. Unfortunately, all math will be the same size, but see",
1037 " the discussion below on editing the MP output. `mag` will also work under",
1038 " `notex` but there seems no point in using it as the font size option (below)",
1039 " works as well.",
1040 "",
1041 " The option `psnfss` uses postscript fonts in combination with LaTeX. Since",
1042 " this option only makes sense, if LaTeX is being used, the `latex` option is selected",
1043 " automatically. This option includes the following packages for LaTeX:",
1044 " inputenc(latin1), fontenc(T1), mathptmx, helvet(scaled=09.2), courier, latexsym ",
1045 " and textcomp.",
1046 "",
1047 " The option `psnfss-version7` uses also postscript fonts in LaTeX (option `latex`",
1048 " is also automatically selected), but uses the following packages with LaTeX:",
1049 " inputenc(latin1), fontenc(T1), times, mathptmx, helvet and courier.",
1050 "",
1051 " The option `nopsnfss` is the default and uses the standard font (cmr10 if not",
1052 " otherwise specified).",
1053 "",
1054 " The option `prologues` takes a value as an additional argument and adds the line",
1055 " `prologues:=<value>` to the metapost file. If a value of `2` is specified metapost",
1056 " uses postscript fonts to generate the eps-file, so that the result can be viewed",
1057 " using e.g. ghostscript. Normally the output of metapost uses TeX fonts and therefore",
1058 " has to be included in a (La)TeX file before you can look at it.",
1059 "",
1060 " The option `noprologues` is the default. No additional line specifying the prologue",
1061 " will be added.",
1062 "",
1063 " The option `a4paper` adds a `[a4paper]` to the documentclass. Normally letter paper",
1064 " is used (default). Since this option is only used in case of LaTeX, the `latex` option",
1065 " is selected automatically.",
1066 "",
1067 " The option `amstex` automatically selects the `latex` option and includes the following",
1068 " LaTeX packages: amsfonts, amsmath(intlimits). By default these packages are not",
1069 " included.",
1070 "",
1071 " A name in quotes selects the font that will be used when no explicit font is",
1072 " given in a `set label` or `set title`.  A name recognized by TeX (a TFM file",
1073 " exists) must be used.  The default is \"cmr10\" unless `notex` is selected,",
1074 " then it is \"pcrr8r\" (Courier).  Even under `notex`, a TFM file is needed by",
1075 " Metapost. The file `pcrr8r.tfm` is the name given to Courier in LaTeX's psnfss",
1076 " package.  If you change the font from the `notex` default, choose a font that",
1077 " matches the ASCII encoding at least in the range 32-126.  `cmtt10` almost",
1078 " works, but it has a nonblank character in position 32 (space).",
1079 "",
1080 " The size can be any number between 5.0 and 99.99.  If it is omitted, 10.0 is",
1081 " used.  It is advisable to use `magstep` sizes: 10 times an integer or",
1082 " half-integer power of 1.2, rounded to two decimals, because those are the most",
1083 " available sizes of fonts in TeX systems.",
1084 "",
1085 " All the options are optional.  If font information is given, it must be at the",
1086 " end, with size (if present) last.  The size is needed to select a size for the",
1087 " font, even if the font name includes size information.  For example,",
1088 " `set term mp \"cmtt12\"` selects cmtt12 shrunk to the default size 10.  This",
1089 " is probably not what you want or you would have used cmtt10.",
1090 "",
1091 " The following common ascii characters need special treatment in TeX:",
1092 "    $, &, #, %, _;  |, <, >;  ^, ~,  \\, {, and }",
1093 " The five characters $, #, &, _, and % can simply be escaped, e.g., `\\$`.",
1094 " The three characters <, >, and | can be wrapped in math mode, e.g., `$<$`.",
1095 " The remainder require some TeX work-arounds.  Any good book on TeX will give",
1096 " some guidance.",
1097 "",
1098 " If you type your labels inside double quotes, backslashes in TeX code need to",
1099 " be escaped (doubled). Using single quotes will avoid having to do this, but",
1100 " then you cannot use `\\n` for line breaks.  As of this writing, version 3.7 of",
1101 " gnuplot processes titles given in a `plot` command differently than in other",
1102 " places, and backslashes in TeX commands need to be doubled regardless of the",
1103 " style of quotes.",
1104 "",
1105 " Metapost pictures are typically used in TeX documents.  Metapost deals with",
1106 " fonts pretty much the same way TeX does, which is different from most other",
1107 " document preparation programs.  If the picture is included in a LaTeX document",
1108 " using the graphics package, or in a plainTeX document via epsf.tex, and then",
1109 " converted to PostScript with dvips (or other dvi-to-ps converter), the text in",
1110 " the plot will usually be handled correctly.  However, the text may not appear",
1111 " if you send the Metapost output as-is to a PostScript interpreter.",
1112 "",
1113 "2 Metapost Instructions",
1114 "?commands set terminal mp detailed",
1115 "?set terminal mp detailed",
1116 "?set term mp detailed",
1117 "?mp detailed",
1118 "?metapost detailed",
1119 "",
1120 " - Set your terminal to Metapost, e.g.:",
1121 "    set terminal mp mono \"cmtt12\" 12",
1122 "",
1123 " - Select an output-file, e.g.:",
1124 "    set output \"figure.mp\"",
1125 "",
1126 " - Create your pictures.  Each plot (or multiplot group) will generate a",
1127 " separate Metapost beginfig...endfig group.  Its default size will be 5 by 3",
1128 " inches.  You can change the size by saying `set size 0.5,0.5` or whatever",
1129 " fraction of the default size you want to have.",
1130 "",
1131 " - Quit gnuplot.",
1132 "",
1133 " - Generate EPS files by running Metapost on the output of gnuplot:",
1134 "    mpost figure.mp  OR  mp figure.mp",
1135 " The name of the Metapost program depends on the system, typically `mpost` for",
1136 " a Unix machine and `mp` on many others.  Metapost will generate one EPS file",
1137 " for each picture.",
1138 "",
1139 " - To include your pictures in your document you can use the graphics package",
1140 " in LaTeX or epsf.tex in plainTeX:",
1141 "    \\usepackage{graphics} % LaTeX",
1142 "    \\input epsf.tex       % plainTeX",
1143 " If you use a driver other than dvips for converting TeX DVI output to PS, you",
1144 " may need to add the following line in your LaTeX document:",
1145 "    \\DeclareGraphicsRule{*}{eps}{*}{}",
1146 " Each picture you made is in a separate file.  The first picture is in, e.g.,",
1147 " figure.0, the second in figure.1, and so on....  To place the third picture in",
1148 " your document, for example, all you have to do is:",
1149 "    \\includegraphics{figure.2} % LaTeX",
1150 "    \\epsfbox{figure.2}         % plainTeX",
1151 "",
1152 " The advantage, if any, of the mp terminal over a postscript terminal is",
1153 " editable output.  Considerable effort went into making this output as clean as",
1154 " possible.  For those knowledgeable in the Metapost language, the default line",
1155 " types and colors can be changed by editing the arrays `lt[]` and `col[]`.",
1156 " The choice of solid vs dashed lines, and color vs black lines can be change by",
1157 " changing the values assigned to the booleans `dashedlines` and `colorlines`.",
1158 " If the default `tex` option was in effect, global changes to the text of",
1159 " labels can be achieved by editing the `vebatimtex...etex` block.  In",
1160 " particular, a LaTeX preamble can be added if desired, and then LaTeX's",
1161 " built-in size changing commands can be used for maximum flexibility. Be sure",
1162 " to set the appropriate MP configuration variable to force Metapost to run",
1163 " LaTeX instead of plainTeX."
1164 END_HELP(mp)
1165 #endif                          /* TERM_HELP */