1 /* Hey Emacs this is -*- C -*-
3 * $Id: pstricks.trm,v 1.32.2.1 2006/11/18 17:27:02 sfeam Exp $
6 /* GNUPLOT - pstricks.trm */
9 * Copyright 1990 - 1993, 1998, 2004
11 * Permission to use, copy, and distribute this software and its
12 * documentation for any purpose with or without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and
14 * that both that copyright notice and this permission notice appear
15 * in supporting documentation.
17 * Permission to modify the software is granted, but not the right to
18 * distribute the complete modified source code. Modifications are to
19 * be distributed as patches to the released version. Permission to
20 * distribute binaries produced by compiling modified sources is granted,
22 * 1. distribute the corresponding source modifications from the
23 * released version in the form of a patch file along with the binaries,
24 * 2. add special version identification to distinguish your version
25 * in addition to the base release version number,
26 * 3. provide your name and address as the primary contact for the
27 * support of your modified version, and
28 * 4. retain our contact information in regard to use of the base
30 * Permission to distribute the released version of the source code along
31 * with corresponding source modifications in the form of a patch file is
32 * granted with same provisions 2 through 4 for binary distributions.
34 * This software is provided "as is" without express or implied warranty
35 * to the extent permitted by applicable law.
39 * This file is included by ../term.c.
41 * This terminal driver supports:
42 * The PSTricks macros for LaTeX.
47 * Raymond Toy toy@soho.crd.ge.com
48 * Modified the eepic.trm file to use PSTricks macros instead.
51 * Utilized many suggestions from Gisli Ottarsson
52 * (gisli@liapunov.eecs.umich.edu) to create a new version.
53 * Should also work with TeX as well as LaTeX.
55 * If you have PSTricks version 0.91, #define OLD_PST to
58 * Added a really ugly hack (enabled by default) to print
59 * "nice" numbers for axis labels. This should really be at
60 * a higher level in the code, but I'm lazy right now.
62 * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
67 * This file contains the PSTricks terminal driver, intended for use with the
68 * pstricks.sty macro package for LaTeX. This is an alternative to the
69 * eepic and latex driver. You need pstricks.sty, and, of course, a printer
70 * that understands PostScript. Ghostscript understands Postscript too.
72 * PSTricks is available via anonymous ftp from the /pub directory
73 * at Princeton.EDU. This driver definitely does not come close to
74 * using the full capability of the PSTricks package.
77 * adapted to the new terminal layout by Stefan Bodewig (Dec. 1995)
79 * adapted to support pm3d by Tim Piessens and Petr Mikulik (Jan. 2003)
85 register_term(pstricks)
89 TERM_PUBLIC void PSTRICKS_options __PROTO((void));
90 TERM_PUBLIC void PSTRICKS_init __PROTO((void));
91 TERM_PUBLIC void PSTRICKS_graphics __PROTO((void));
92 TERM_PUBLIC void PSTRICKS_text __PROTO((void));
93 TERM_PUBLIC void PSTRICKS_linetype __PROTO((int linetype));
94 TERM_PUBLIC void PSTRICKS_move __PROTO((unsigned int x, unsigned int y));
95 TERM_PUBLIC void PSTRICKS_point __PROTO((unsigned int x, unsigned int y, int number));
96 TERM_PUBLIC void PSTRICKS_vector __PROTO((unsigned int ux, unsigned int uy));
97 TERM_PUBLIC void PSTRICKS_arrow __PROTO((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head));
98 TERM_PUBLIC void PSTRICKS_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
99 TERM_PUBLIC int PSTRICKS_justify_text __PROTO((enum JUSTIFY mode));
100 TERM_PUBLIC int PSTRICKS_text_angle __PROTO((int ang));
101 TERM_PUBLIC void PSTRICKS_reset __PROTO((void));
102 TERM_PUBLIC int PSTRICKS_make_palette __PROTO((t_sm_palette *));
103 TERM_PUBLIC void PSTRICKS_set_color __PROTO((t_colorspec *));
104 TERM_PUBLIC void PSTRICKS_filled_polygon __PROTO((int, gpiPoint *));
106 #define PSTRICKS_XMAX 10000.0
107 #define PSTRICKS_YMAX 10000.0
109 #define PSTRICKS_HTIC 150
110 #define PSTRICKS_VTIC 200
111 #define PSTRICKS_HCHAR 160
112 #define PSTRICKS_VCHAR 420
113 #endif /* TERM_PROTO */
115 #ifndef TERM_PROTO_ONLY
117 static void PSTRICKS_endline __PROTO((void));
118 static char *PSTRICKS_hack_text __PROTO((const char *s));
120 static float PSTRICKS_posx;
121 static float PSTRICKS_posy;
122 static enum JUSTIFY PSTRICKS_justify = LEFT;
123 static int PSTRICKS_angle = 0;
125 /* if 1 below, then the file size is shorter thanks to a macro for polygon */
126 #define PSTRICKS_SHORTER_FILE 1
128 #ifdef PSTRICKS_SHORTER_FILE
129 static int PSTRICKS_color = 0;
131 static char PSTRICKS_color_str[16] = "";
133 static int PSTRICKS_palette_set = FALSE;
134 static int PSTRICKS_palette_size = 128;
136 #define PSTRICKS_TINY_DOT 0.00025 /* A tiny dot */
139 #define PSTRICKS_POINT_TYPES 12 /* we supply more point types */
141 static const char *PSTRICKS_points[] = {
151 "\\PST@Filltriangle",
157 #define PSTRICKS_NUMLINES 6 /* number of linetypes below */
159 static const char *PSTRICKS_lines[] = {
168 /* current line type */
169 static int PSTRICKS_type;
171 /* are we in the middle of a line */
172 static TBOOLEAN PSTRICKS_inline = FALSE;
174 /* terminate any line in progress */
175 static void PSTRICKS_endline __PROTO((void));
177 /* number of points in line so far */
178 static int PSTRICKS_linecount = 0;
180 /* max value for linecount */
181 #define PSTRICKS_LINEMAX 100
187 static int PST_hack_text = TRUE; /* Hack text on */
188 static int PST_unit_plot = FALSE; /* Unit-sized plot off */
193 if (!END_OF_COMMAND) {
194 if (almost_equals(c_token, "no$hacktext")) {
195 PST_hack_text = FALSE;
197 } else if (almost_equals(c_token, "u$nit")) {
198 PST_unit_plot = TRUE;
207 PSTRICKS_posx = PSTRICKS_posy = 0;
208 PSTRICKS_linetype(-1);
209 fseek(gpoutfile,0,SEEK_SET);
210 fputs("% GNUPLOT: LaTeX picture using PSTRICKS macros\n", gpoutfile);
211 PSTRICKS_palette_set = FALSE; /* PM3D palette set? */
219 % Define new PST objects, if not already defined\n\
220 \\ifx\\PSTloaded\\undefined\n\
221 \\def\\PSTloaded{t}\n\
222 \\psset{arrowsize=.01 3.2 1.4 .3}\n\
223 \\psset{dotsize=.01}\n\
224 \\catcode`@=11\n\n", gpoutfile);
226 /* Define line type objects */
228 \\newpsobject{PST@Border}{psline}{linewidth=.0015,linestyle=solid}\n\
229 \\newpsobject{PST@Axes}{psline}{linewidth=.0015,linestyle=dotted,dotsep=.004}\n\
230 \\newpsobject{PST@Solid}{psline}{linewidth=.0015,linestyle=solid}\n\
231 \\newpsobject{PST@Dashed}{psline}{linewidth=.0015,linestyle=dashed,dash=.01 .01}\n\
232 \\newpsobject{PST@Dotted}{psline}{linewidth=.0025,linestyle=dotted,dotsep=.008}\n\
233 \\newpsobject{PST@LongDash}{psline}{linewidth=.0015,linestyle=dashed,dash=.02 .01}\n", gpoutfile);
235 /* Define point objects */
238 /* PSTricks version 0.91 had x and diamond dot types */
240 \\newpsobject(PST@Diamond}{psdots}{linewidth=.001,linestyle=solid,dotstyle=diamond}\n\
241 \\newpsobject(PST@Filldiamond}{psdots}{linewidth=.001,linestyle=solid,dotstyle=diamond*}\n\
242 \\newpsobject{PST@Cross}{psdots}{linewidth=.001,linestyle=solid,dotstyle=x}\n", gpoutfile);
244 /* Newer versions use rotated plus and square to get the x and diamond dots */
246 \\newpsobject{PST@Diamond}{psdots}{linewidth=.001,linestyle=solid,dotstyle=square,dotangle=45}\n\
247 \\newpsobject{PST@Filldiamond}{psdots}{linewidth=.001,linestyle=solid,dotstyle=square*,dotangle=45}\n\
248 \\newpsobject{PST@Cross}{psdots}{linewidth=.001,linestyle=solid,dotstyle=+,dotangle=45}\n", gpoutfile);
252 \\newpsobject{PST@Plus}{psdots}{linewidth=.001,linestyle=solid,dotstyle=+}\n\
253 \\newpsobject{PST@Square}{psdots}{linewidth=.001,linestyle=solid,dotstyle=square}\n\
254 \\newpsobject{PST@Circle}{psdots}{linewidth=.001,linestyle=solid,dotstyle=o}\n\
255 \\newpsobject{PST@Triangle}{psdots}{linewidth=.001,linestyle=solid,dotstyle=triangle}\n\
256 \\newpsobject{PST@Pentagon}{psdots}{linewidth=.001,linestyle=solid,dotstyle=pentagon}\n\
257 \\newpsobject{PST@Fillsquare}{psdots}{linewidth=.001,linestyle=solid,dotstyle=square*}\n\
258 \\newpsobject{PST@Fillcircle}{psdots}{linewidth=.001,linestyle=solid,dotstyle=*}\n\
259 \\newpsobject{PST@Filltriangle}{psdots}{linewidth=.001,linestyle=solid,dotstyle=triangle*}\n\
260 \\newpsobject{PST@Fillpentagon}{psdots}{linewidth=.001,linestyle=solid,dotstyle=pentagon*}\n", gpoutfile);
262 /* Define arrow object */
264 \\newpsobject{PST@Arrow}{psline}{linewidth=.001,linestyle=solid}\n\
268 /* Set the scaled plot size, if it's not a unit plot */
269 if (!PST_unit_plot) {
270 fputs("\\psset{unit=5.0in,xunit=5.0in,yunit=3.0in}\n", gpoutfile);
272 /* HBB 20001027: fix bounding box bug by letting the currently
273 * active 'size' and 'offset' setting influence the area used by
274 * the picture environment */
275 fprintf(gpoutfile, "\
276 \\pspicture(%f,%f)(%f,%f)\n\
277 \\ifx\\nofigs\\undefined\n\
294 \\endpspicture\n", gpoutfile);
299 PSTRICKS_linetype(int linetype)
303 if (linetype >= PSTRICKS_NUMLINES - 2)
304 linetype %= (PSTRICKS_NUMLINES - 2);
309 PSTRICKS_type = linetype;
315 PSTRICKS_move(unsigned int x, unsigned int y)
319 PSTRICKS_posx = x / PSTRICKS_XMAX;
320 PSTRICKS_posy = y / PSTRICKS_YMAX;
325 PSTRICKS_point(unsigned int x, unsigned int y, int number)
329 /* Print the character defined by 'number'; number < 0 means
330 to use a dot, otherwise one of the defined points. */
333 fprintf(gpoutfile, "\\qdisk(%.4f,%.4f){%.4f}\n",
338 fprintf(gpoutfile, "%s(%.4f,%.4f)\n",
339 PSTRICKS_points[number % PSTRICKS_POINT_TYPES],
347 PSTRICKS_vector(unsigned ux, unsigned uy)
349 if (!PSTRICKS_inline) {
350 PSTRICKS_inline = TRUE;
352 /* Start a new line. This depends on line type */
353 fprintf(gpoutfile, "%s(%.4f,%.4f)\n",
354 PSTRICKS_lines[PSTRICKS_type + 2],
355 PSTRICKS_posx, PSTRICKS_posy);
356 PSTRICKS_linecount = 1;
359 * Even though we are in middle of a path,
360 * we may want to start a new path command.
361 * If they are too long then latex will choke.
363 if (PSTRICKS_linecount++ >= PSTRICKS_LINEMAX) {
364 /* fprintf(gpoutfile, "\n"); */
365 fprintf(gpoutfile, "%s(%.4f,%.4f)\n",
366 PSTRICKS_lines[PSTRICKS_type + 2],
367 PSTRICKS_posx, PSTRICKS_posy);
368 PSTRICKS_linecount = 1;
371 PSTRICKS_posx = ux / PSTRICKS_XMAX;
372 PSTRICKS_posy = uy / PSTRICKS_YMAX;
373 fprintf(gpoutfile, "(%.4f,%.4f)\n", PSTRICKS_posx, PSTRICKS_posy);
379 if (PSTRICKS_inline) {
380 putc('\n', gpoutfile);
381 PSTRICKS_inline = FALSE;
388 unsigned int sx, unsigned int sy,
389 unsigned int ex, unsigned int ey,
392 fprintf(gpoutfile, "\\PST@Arrow%s(%.4f,%.4f)(%.4f,%.4f)\n",
399 PSTRICKS_posx = ex / PSTRICKS_XMAX;
400 PSTRICKS_posy = ey / PSTRICKS_YMAX;
404 * A really ugly hack!!!
406 * This function takes an input string and hacks it up. If the
407 * input string starts with a number, it converts the number into a
408 * TeX style number including exponential notation. Thus, if
409 * the input is the string "3.14159e3 is a number", then
410 * the output is "$3.14159\cdot 10^{3}$ is a number", so that TeX
411 * will produce something nice.
413 * This is basically meant for producing axis labels that look nice.
420 PSTRICKS_hack_text(const char *s)
424 static char hack[BUFSIZ];
427 * Does the string start with a number?
430 value = strtod(s, &ends);
434 * This doesn't start a number, so just copy the string over
442 * We have a number! Check to see if the number
443 * is in scientific notation
446 safe_strncpy(hack, s, ends - s + 1);
447 /* hack[ends - s] = '\0'; */
449 ptr = strchr(hack, 'e');
451 ptr = strchr(hack, 'E');
455 * Exponential notation! Let's get the mantissa and exponent separately
463 man_val = atof(hack);
464 expo_val = atoi(ptr + 1);
468 } else if (man_val == 1) {
469 sprintf(hack, "$10^{%d}$", expo_val);
470 } else if (man_val == (int) man_val) {
472 sprintf(hack, "$%d$", (int) man_val);
474 sprintf(hack, "$%d \\times 10^{%d}$", (int) man_val, expo_val);
478 sprintf(hack, "$%f$", man_val);
480 sprintf(hack, "$%f \\times 10^{%d}$", man_val, expo_val);
485 * Copy anything that's left of the string
495 PSTRICKS_put_text(unsigned int x, unsigned int y, const char str[])
499 /* Skip this if the string is empty */
501 if (strlen(str) > 0) {
502 fputs("\\rput", gpoutfile);
504 /* Set justification */
506 switch (PSTRICKS_justify) {
508 fputs("[l]", gpoutfile);
513 fputs("[r]", gpoutfile);
519 switch (PSTRICKS_angle) {
523 fputs("{L}", gpoutfile);
527 /* Set reference position and text */
529 fprintf(gpoutfile, "(%.4f,%.4f)",
535 /* Hack leading numbers to something nice for TeX */
537 hack = PSTRICKS_hack_text(str);
538 fprintf(gpoutfile, "{%s}\n", hack);
540 fprintf(gpoutfile, "{%s}\n", str);
548 PSTRICKS_justify_text(enum JUSTIFY mode)
550 PSTRICKS_justify = mode;
555 PSTRICKS_text_angle(int ang)
557 PSTRICKS_angle = (ang ? 1 : 0);
565 PSTRICKS_posx = PSTRICKS_posy = 0;
570 PSTRICKS_make_palette (t_sm_palette *palette)
572 /* Query to determine palette size */
574 return PSTRICKS_palette_size;
577 if (PSTRICKS_palette_set == FALSE) {
579 /* Create new palette */
580 PSTRICKS_palette_set = TRUE;
581 if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) {
583 for (i=0; i < sm_palette.colors; i++) {
584 double g = i * 1.0 / (sm_palette.colors - 1);
585 g = 1e-3 * (int)(g * 1000); /* round to 3 digits to use %g below */
586 fprintf(gpoutfile, "\\newgray{PST@COLOR%d}{%g}\n", i, g);
589 if (sm_palette.colorMode == SMPAL_COLOR_MODE_RGB) {
592 for (i=0; i < sm_palette.colors; i++) {
593 /* round to 3 digits to avoid sth like 1e-7 in %g below */
594 r = 1e-3 * (int)(palette->color[i].r * 1000);
595 g = 1e-3 * (int)(palette->color[i].g * 1000);
596 b = 1e-3 * (int)(palette->color[i].b * 1000);
597 fprintf(gpoutfile, "\\newrgbcolor{PST@COLOR%d}{%g %g %g}\n", i, r, g, b);
601 /* use the following macro to shorten the file size */
602 fprintf(gpoutfile, "\\def\\polypmIIId#1{\\pspolygon[linestyle=none,fillstyle=solid,fillcolor=PST@COLOR#1]}\n\n");
608 PSTRICKS_set_color (t_colorspec *colorspec)
611 double gray = colorspec->value;
613 if (colorspec->type != TC_FRAC)
616 new_color = (gray <=0) ? 0 : (int)(gray*sm_palette.colors);
617 if (new_color >= PSTRICKS_palette_size)
618 new_color = PSTRICKS_palette_size - 1;
619 if (PSTRICKS_palette_set == FALSE) {
620 fprintf(stderr, "pstricks: Palette used before set!\n");
622 #ifdef PSTRICKS_SHORTER_FILE
623 PSTRICKS_color = new_color;
625 sprintf(PSTRICKS_color_str, "PST@COLOR%d", new_color);
631 PSTRICKS_filled_polygon (int points, gpiPoint *corners)
635 #ifdef PSTRICKS_SHORTER_FILE
636 /* using a macro for an abbreviation */
637 fprintf(gpoutfile, "\\polypmIIId{%d}", PSTRICKS_color);
639 fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=solid,fillcolor=%s]", PSTRICKS_color_str);
641 for (i=0; i < points; i++) {
642 if (i % 8 == 7) /* up to 8 corners per line */
643 fprintf(gpoutfile, "\n");
644 fprintf(gpoutfile,"(%.4g,%.4g)", corners[i].x/PSTRICKS_XMAX, corners[i].y/PSTRICKS_YMAX);
646 fprintf(gpoutfile, "\n");
649 #endif /* TERM_BODY */
654 TERM_TABLE_START(pstricks_driver)
655 "pstricks", "LaTeX picture environment with PSTricks macros",
656 PSTRICKS_XMAX, PSTRICKS_YMAX, PSTRICKS_VCHAR, PSTRICKS_HCHAR,
657 PSTRICKS_VTIC, PSTRICKS_HTIC, PSTRICKS_options, PSTRICKS_init, PSTRICKS_reset,
658 PSTRICKS_text, null_scale, PSTRICKS_graphics, PSTRICKS_move, PSTRICKS_vector,
659 PSTRICKS_linetype, PSTRICKS_put_text, PSTRICKS_text_angle,
660 PSTRICKS_justify_text, PSTRICKS_point, PSTRICKS_arrow, set_font_null, 0,
661 TERM_BINARY /*flags*/, 0 /*suspend*/, 0 /*resume*/, 0 , 0
665 , PSTRICKS_make_palette, 0, PSTRICKS_set_color, PSTRICKS_filled_polygon
666 TERM_TABLE_END(pstricks_driver)
669 #define LAST_TERM pstricks_driver
671 #endif /* TERM_TABLE */
672 #endif /* TERM_PROTO_ONLY */
677 "?commands set terminal pstricks",
678 "?set terminal pstricks",
679 "?set term pstricks",
680 "?terminal pstricks",
683 " The `pstricks` driver is intended for use with the \"pstricks.sty\" macro",
684 " package for LaTeX. It is an alternative to the `eepic` and `latex` drivers.",
685 " You need \"pstricks.sty\", and, of course, a printer that understands",
686 " PostScript, or a converter such as Ghostscript.",
688 " PSTricks is available via anonymous ftp from the /pub directory at",
689 " Princeton.edu. This driver definitely does not come close to using the full",
690 " capability of the PSTricks package.",
693 " set terminal pstricks {hacktext | nohacktext} {unit | nounit}",
695 " The first option invokes an ugly hack that gives nicer numbers; the second",
696 " has to do with plot scaling. The defaults are `hacktext` and `nounit`."
698 #endif /* TERM_HELP */