/* Hey Emacs this is -*- C -*- */
/* GNUPLOT - pstricks.trm */
/*[
* Copyright 1990 - 1993, 1998, 2004, 2018
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
/*
* This file is included by ../term.c.
*
* This terminal driver supports:
* The PSTricks macros for LaTeX.
*
* AUTHORS
* David Kotz
*
* Raymond Toy toy@soho.crd.ge.com
* Modified the eepic.trm file to use PSTricks macros instead.
*
* 20 Mar 93:
* Utilized many suggestions from Gisli Ottarsson
* (gisli@liapunov.eecs.umich.edu) to create a new version.
* Should also work with TeX as well as LaTeX.
*
* Bastian Maerkisch
*
* send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
*
*/
/*
* This file contains the PSTricks terminal driver, intended for use with the
* pstricks.sty macro package for LaTeX. This is an alternative to the
* eepic and latex driver. You need pstricks.sty, and, of course, a printer
* that understands PostScript. Ghostscript understands Postscript too.
*
* PSTricks is available at
* http://tug.org/PSTricks/
* This driver definitely does not come close to using the full capability
* of the PSTricks package.
*/
/*
* adapted to the new terminal layout by Stefan Bodewig (Dec. 1995)
*
* adapted to support pm3d by Tim Piessens and Petr Mikulik (Jan. 2003)
*
* remove "hacktext" option since this functionality is now provided by
* the %H format. Add rotated text at arbitrary angles, full color and
* version 5 linetype support, filled boxes, pattern fill, variable
* point size and line width, point symbols in line with other terminals,
* boxed text, more arrow features, standalone (LaTeX) mode (including
* text encoding support), transparency. (BM, March/April 2018)
* compatibility with plain TeX, and pdflatex/lualatex. (BM, Feb 2022)
*
*/
#include "driver.h"
#ifdef TERM_REGISTER
register_term(pstricks)
#endif
#ifdef TERM_PROTO
TERM_PUBLIC void PSTRICKS_options(void);
TERM_PUBLIC void PSTRICKS_init(void);
TERM_PUBLIC void PSTRICKS_graphics(void);
TERM_PUBLIC void PSTRICKS_text(void);
TERM_PUBLIC void PSTRICKS_linetype(int linetype);
TERM_PUBLIC void PSTRICKS_move(unsigned int x, unsigned int y);
TERM_PUBLIC void PSTRICKS_point(unsigned int x, unsigned int y, int number);
TERM_PUBLIC void PSTRICKS_vector(unsigned int ux, unsigned int uy);
TERM_PUBLIC void PSTRICKS_arrow(unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, int head);
TERM_PUBLIC void PSTRICKS_pointsize(double pointsize);
TERM_PUBLIC void PSTRICKS_put_text(unsigned int x, unsigned int y, const char str[]);
TERM_PUBLIC int PSTRICKS_justify_text(enum JUSTIFY mode);
TERM_PUBLIC int PSTRICKS_text_angle(float ang);
TERM_PUBLIC void PSTRICKS_reset(void);
TERM_PUBLIC void PSTRICKS_linewidth(double linewidth);
TERM_PUBLIC int PSTRICKS_make_palette(t_sm_palette *);
TERM_PUBLIC void PSTRICKS_set_color(t_colorspec *);
TERM_PUBLIC void PSTRICKS_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height);
TERM_PUBLIC void PSTRICKS_filled_polygon(int, gpiPoint *);
TERM_PUBLIC void PSTRICKS_dashtype(int type, t_dashtype *custom_dash_pattern);
TERM_PUBLIC void PSTRICKS_boxed_text(unsigned int x, unsigned int y, int option);
#define PSTRICKS_XMAX 10000.0
#define PSTRICKS_YMAX 10000.0
#define PSTRICKS_HTIC 150
#define PSTRICKS_VTIC 150
#define PSTRICKS_HCHAR 160
#define PSTRICKS_VCHAR 250
#endif /* TERM_PROTO */
#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY
/* terminate any line in progress */
static void PSTRICKS_endline(void);
/* coordinate mapping functions */
static inline double PSTRICKS_map_x(int x);
static inline double PSTRICKS_map_y(int y);
/* apply line color */
static void PSTRICKS_save_color(const char * color);
static void PSTRICKS_apply_linecolor(void);
/* mode */
static TBOOLEAN PST_standalone = FALSE;
static TBOOLEAN PST_pdftricks2 = FALSE;
/* plot size */
static TBOOLEAN PST_unit_plot = FALSE; /* Unit-sized plot off */
static size_units PSTRICKS_explicit_units = INCHES;
static float PSTRICKS_size_x = 5.f;
static float PSTRICKS_size_y = 3.f;
static float PSTRICKS_posx;
static float PSTRICKS_posy;
/* TEXT */
static TBOOLEAN PST_colortext = FALSE;
static enum JUSTIFY PSTRICKS_justify = LEFT;
static int PSTRICKS_angle = 0;
/* if 1 below, then the file size is shorter thanks to a macro for polygon */
/* FIXME: This feature is broken, deactivate for now */
//#define PSTRICKS_SHORTER_FILE 1
static int PSTRICKS_color_type = TC_DEFAULT;
static int PSTRICKS_color = 0;
static char PSTRICKS_color_str[24] = "";
static TBOOLEAN PSTRICKS_palette_set = FALSE;
static int PSTRICKS_palette_size = 128;
static rgb_color PSTRICKS_rgbcolor;
static double PSTRICKS_alpha = 1.;
static double PSTRICKS_alpha_old = 1.;
static TBOOLEAN PSTRICKS_have_bg;
static rgb_color PSTRICKS_background = { 1., 1., 1. };
/* POINTS */
#define PSTRICKS_TINY_DOT 0.00025 /* A tiny dot */
static double PST_pointsize;
static double PSTRICKS_ps = 1.;
static const char *PSTRICKS_points[] = {
"\\PST@Plus",
"\\PST@Cross",
"\\PST@Star",
"\\PST@Square",
"\\PST@Fillsquare",
"\\PST@Circle",
"\\PST@Fillcircle",
"\\PST@Triangle",
"\\PST@Filltriangle",
"\\PST@TriangleD",
"\\PST@FilltriangleD",
"\\PST@Diamond",
"\\PST@Filldiamond",
"\\PST@Pentagon",
"\\PST@Fillpentagon"
};
#define PSTRICKS_POINT_TYPES (sizeof(PSTRICKS_points) / sizeof(char *))
/* LINES */
#define PSTRICKS_NUMLINES 6 /* number of linetypes below */
static const char *PSTRICKS_lines[] = {
"\\PST@Border",
"\\PST@Axes",
"\\PST@Solid",
"\\PST@Dashed",
"\\PST@Dotted",
"\\PST@LongDash"
};
#define PSTRICKS_NUMCOLORS 6
static const char *PSTRICKS_colors[] = {
"red",
"green",
"blue",
"magenta",
"darkgray",
"cyan",
"yellow"
};
/* line caps and joins */
static TBOOLEAN PST_rounded = FALSE;
/* current line type */
static int PSTRICKS_type;
/* current line color */
static char PSTRICKS_old_linecolor[24] = "black";
/* new line color */
static char PSTRICKS_linecolor[24] = "black";
/* line width */
static double PSTRICKS_lw;
static double PSTRICKS_lw_scale = 1.;
/* are we in the middle of a line */
static TBOOLEAN PSTRICKS_inline = FALSE;
/* number of points in line so far */
static int PSTRICKS_linecount = 0;
/* max value for linecount */
#define PSTRICKS_LINEMAX 100
/* ARROWS */
static TBOOLEAN PST_psarrows = TRUE;
static double PSTRICKS_arrowwidth = -1.;
static double PSTRICKS_arrowlength = -1.;
static double PSTRICKS_arrowinset = -1.;
/* FILL PATTERN */
static const char * PSTRICKS_patterns[] = {
"solid",
"crosshatch%s", "crosshatch%s,hatchsep=2.5pt",
"solid",
"vlines%s", "hlines%s",
"vlines%s,hatchsep=2.5pt", "hlines%s,hatchsep=2.5pt",
"dots*", "penrose%s"
};
#define PSTRICKS_NUMPATTERN (sizeof(PSTRICKS_patterns) / sizeof(char *))
/* BOXED TEXT */
static TBOOLEAN PSTRICKS_in_textbox = FALSE;
static TBOOLEAN PSTRICKS_textbox_fill;
static TBOOLEAN PSTRICKS_textbox_frame;
static char * PSTRICKS_textbox_text = NULL;
static double PSTRICKS_textbox_x;
static double PSTRICKS_textbox_y;
static char * PSTRICKS_textbox_fillcolor;
static double PSTRICKS_textbox_sep;
/*
* Handle options
*/
/* option names */
enum PSTRICKS_id { PSTRICKS_DEFAULTOPTIONS,
PSTRICKS_SIZE,
PSTRICKS_UNIT, PSTRICKS_NOUNIT,
PSTRICKS_STANDALONE, PSTRICKS_INPUT,
PSTRICKS_PSTRICKS, PSTRICKS_PDFTRICKS2,
PSTRICKS_BLACKTEXT, PSTRICKS_COLORTEXT,
PSTRICKS_ROUNDED, PSTRICKS_BUTT,
PSTRICKS_LINEWIDTH, PSTRICKS_POINTSCALE,
PSTRICKS_PSARROWS, PSTRICKS_GPARROWS,
PSTRICKS_BACKGROUND,
PSTRICKS_OTHER };
static struct gen_table PSTRICKS_opts[] =
{
{ "def$ault", PSTRICKS_DEFAULTOPTIONS },
{ "size", PSTRICKS_SIZE },
{ "u$nit", PSTRICKS_UNIT },
{ "nou$nit", PSTRICKS_NOUNIT },
{ "stand$alone", PSTRICKS_STANDALONE },
{ "inp$ut", PSTRICKS_INPUT },
{ "b$lacktext", PSTRICKS_BLACKTEXT },
{ "colort$ext", PSTRICKS_COLORTEXT },
{ "colourt$ext", PSTRICKS_COLORTEXT },
{ "round$ed", PSTRICKS_ROUNDED },
{ "butt", PSTRICKS_BUTT },
{ "backg$round", PSTRICKS_BACKGROUND },
{ "lw", PSTRICKS_LINEWIDTH },
{ "linew$idth", PSTRICKS_LINEWIDTH },
{ "points$cale", PSTRICKS_POINTSCALE },
{ "ps", PSTRICKS_POINTSCALE },
{ "psarrows", PSTRICKS_PSARROWS },
{ "gparrows", PSTRICKS_GPARROWS },
{ "pst$ricks", PSTRICKS_PSTRICKS },
{ "pdf$tricks2", PSTRICKS_PDFTRICKS2 },
{ NULL, PSTRICKS_OTHER }
};
TERM_PUBLIC void
PSTRICKS_options()
{
char size_str[80] = "";
while (!END_OF_COMMAND) {
switch ((enum PSTRICKS_id) lookup_table(&PSTRICKS_opts[0], c_token)) {
case PSTRICKS_DEFAULTOPTIONS:
PST_unit_plot = FALSE;
PST_standalone = FALSE;
PST_pdftricks2 = FALSE;
PSTRICKS_size_x = 5.;
PSTRICKS_size_y = 3.;
break;
case PSTRICKS_UNIT:
PST_unit_plot = TRUE;
PSTRICKS_size_x = 5.;
PSTRICKS_size_y = 5.;
term->xmax = PSTRICKS_XMAX;
term->ymax = PSTRICKS_YMAX;
term->v_char = PSTRICKS_VCHAR * 5. / 3.;
term->v_tic = PSTRICKS_VTIC * 5. / 3.;
c_token++;
break;
case PSTRICKS_NOUNIT:
PST_unit_plot = FALSE;
PSTRICKS_size_x = 5.;
PSTRICKS_size_y = 3.;
term->xmax = PSTRICKS_size_x * PSTRICKS_XMAX / 5.;
term->ymax = PSTRICKS_size_y * PSTRICKS_YMAX / 5.;
term->v_char = PSTRICKS_VCHAR;
term->v_tic = PSTRICKS_VTIC;
c_token++;
break;
case PSTRICKS_SIZE: {
float width, height;
c_token++;
PST_unit_plot = FALSE;
PSTRICKS_explicit_units = parse_term_size(&width, &height, INCHES);
PSTRICKS_size_x = width / gp_resolution;
PSTRICKS_size_y = height / gp_resolution;
term->xmax = PSTRICKS_size_x * PSTRICKS_XMAX / 5.;
term->ymax = PSTRICKS_size_y * PSTRICKS_YMAX / 5.;
term->v_char = PSTRICKS_VCHAR;
term->v_tic = PSTRICKS_VTIC;
break;
}
case PSTRICKS_STANDALONE:
PST_standalone = TRUE;
c_token++;
break;
case PSTRICKS_INPUT:
PST_standalone = FALSE;
c_token++;
break;
case PSTRICKS_COLORTEXT:
PST_colortext = TRUE;
c_token++;
break;
case PSTRICKS_BLACKTEXT:
PST_colortext = FALSE;
c_token++;
break;
case PSTRICKS_BUTT:
PST_rounded = FALSE;
c_token++;
break;
case PSTRICKS_ROUNDED:
PST_rounded = TRUE;
c_token++;
break;
case PSTRICKS_LINEWIDTH:
c_token++;
PSTRICKS_lw_scale = real_expression();
if (PSTRICKS_lw_scale < 0.0)
PSTRICKS_lw_scale = 1.0;
break;
case PSTRICKS_POINTSCALE:
c_token++;
PSTRICKS_ps = real_expression();
if (PSTRICKS_ps < 0.0)
PSTRICKS_ps = 1.0;
break;
case PSTRICKS_BACKGROUND: {
int background;
c_token++;
background = parse_color_name();
PSTRICKS_background.r = (double)((background >> 16) & 0xff) / 255.;
PSTRICKS_background.g = (double)((background >> 8) & 0xff) / 255.;
PSTRICKS_background.b = (double)( background & 0xff) / 255.;
break;
}
case PSTRICKS_GPARROWS:
c_token++;
PST_psarrows = FALSE;
break;
case PSTRICKS_PSARROWS:
c_token++;
PST_psarrows = TRUE;
break;
case PSTRICKS_PSTRICKS:
c_token++;
PST_pdftricks2 = FALSE;
break;
case PSTRICKS_PDFTRICKS2:
c_token++;
PST_pdftricks2 = TRUE;
break;
default:
int_error(c_token, "Unknown terminal option");
}
}
if (!PST_unit_plot) {
if (PSTRICKS_explicit_units == INCHES)
snprintf(size_str, sizeof(size_str), "size %.2fin, %.2fin", PSTRICKS_size_x, PSTRICKS_size_y);
else if (PSTRICKS_explicit_units == CM)
snprintf(size_str, sizeof(size_str), "size %.2fcm, %.2fcm", PSTRICKS_size_x * 2.54, PSTRICKS_size_y * 2.54);
}
// update terminal option string
snprintf(term_options, MAX_LINE_LEN + 1,
"%s %s linewidth %.1f pointscale %.1f %s " \
"background \"#%02x%02x%02x\" %sarrows %s %s",
PST_unit_plot ? "unit" : size_str,
PST_rounded ? "rounded" : "butt",
PSTRICKS_lw_scale, PSTRICKS_ps,
PST_colortext ? "colortext" : "blacktext",
(int) floor(PSTRICKS_background.r * 255 + 0.5),
(int) floor(PSTRICKS_background.g * 255 + 0.5),
(int) floor(PSTRICKS_background.b * 255 + 0.5),
PST_psarrows ? "ps" : "gp",
PST_standalone ? "standalone" : "input",
PST_pdftricks2 ? "pdftricks2" : "pstricks");
}
TERM_PUBLIC void
PSTRICKS_init()
{
fseek(gpoutfile, 0, SEEK_SET);
if (PST_standalone) {
const char * inputenc = latex_input_encoding(encoding);
/* multiple standalone graphs */
fputs("\\documentclass[a4paper]{article}\n"
"\\usepackage[T1]{fontenc}\n",
gpoutfile);
if (PST_pdftricks2)
fputs("\\usepackage{pdftricks2}\n", gpoutfile);
else
fputs("\\usepackage{pstricks}\n", gpoutfile);
if (inputenc != NULL) {
if (encoding == S_ENC_UTF8)
fputs("\\usepackage{pifont}\n"
"\\usepackage[postscript,warnunknown]{ucs}\n",
gpoutfile);
fprintf(gpoutfile,
"\\usepackage[%s]{inputenc}\n",
inputenc);
}
fputs("\\begin{document}\n",
gpoutfile);
}
fputs("% GNUPLOT: LaTeX picture using PSTRICKS macros\n", gpoutfile);
}
TERM_PUBLIC void
PSTRICKS_graphics()
{
char background[80] = "";
if (PST_standalone) {
fputs("\\begin{figure}\n", gpoutfile);
}
if (PST_pdftricks2)
fputs("\\begin{configpsblock}\n", gpoutfile);
fputs("\
% Define new PST objects, if not already defined\n\
\\ifx\\PSTloaded\\undefined\n\
\\def\\PSTloaded{t}\n\
\\psset{arrowsize=.01 3.2 1.4 .3}\n\
\\psset{dotsize=0.15}\n\
\\catcode`@=11\n\n", gpoutfile);
/* Define line type objects */
fputs("\
\\newpsobject{PST@Border}{psline}{linestyle=solid}\n\
\\newpsobject{PST@Axes}{psline}{linestyle=dotted,dotsep=.004}\n\
\\newpsobject{PST@Solid}{psline}{linestyle=solid}\n\
\\newpsobject{PST@Dashed}{psline}{linestyle=dashed,dash=.01 .01}\n\
\\newpsobject{PST@Dotted}{psline}{linestyle=dotted,dotsep=.008}\n\
\\newpsobject{PST@LongDash}{psline}{linestyle=dashed,dash=.02 .01}\n", gpoutfile);
/* Define point objects */
fputs("\
\\newpsobject{PST@Plus}{psdot}{linewidth=.001,linestyle=solid,dotstyle=+}\n\
\\newpsobject{PST@Cross}{psdot}{linewidth=.001,linestyle=solid,dotstyle=+,dotangle=45}\n\
\\newpsobject{PST@Star}{psdot}{linewidth=.001,linestyle=solid,dotstyle=*}\n\
\\newpsobject{PST@Square}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square}\n\
\\newpsobject{PST@Fillsquare}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square*}\n\
\\newpsobject{PST@Circle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=o}\n\
\\newpsobject{PST@Fillcircle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=*}\n\
\\newpsobject{PST@Triangle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle}\n\
\\newpsobject{PST@Filltriangle}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle*}\n\
\\newpsobject{PST@TriangleD}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle,dotangle=180}\n\
\\newpsobject{PST@FilltriangleD}{psdot}{linewidth=.001,linestyle=solid,dotstyle=triangle*,dotangle=180}\n\
\\newpsobject{PST@Diamond}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square,dotangle=45}\n\
\\newpsobject{PST@Filldiamond}{psdot}{linewidth=.001,linestyle=solid,dotstyle=square*,dotangle=45}\n\
\\newpsobject{PST@Pentagon}{psdot}{linewidth=.001,linestyle=solid,dotstyle=pentagon}\n\
\\newpsobject{PST@Fillpentagon}{psdot}{linewidth=.001,linestyle=solid,dotstyle=pentagon*}\n", gpoutfile);
/* Define arrow object */
fputs("\
\\newpsobject{PST@Arrow}{psline}{linestyle=solid}\n\
\\catcode`@=12\n\n\
\\fi\n", gpoutfile);
if (PST_pdftricks2)
fputs("\\end{configpsblock}\n", gpoutfile);
/* background color */
PSTRICKS_have_bg = FALSE;
if (PSTRICKS_background.r != 1. || PSTRICKS_background.g != 1. || PSTRICKS_background.b != 1.) {
PSTRICKS_have_bg = TRUE;
fprintf(gpoutfile, "\\newrgbcolor{PST@BGCOLOR}{%f %f %f}\n",
PSTRICKS_background.r, PSTRICKS_background.g, PSTRICKS_background.b);
safe_strncpy(background, "[bgcolor=PST@BGCOLOR]", sizeof(background));
}
/* Set the scaled plot size, if it's not a unit plot */
if (!PST_unit_plot) {
// Choose 5in as unit for historical reasons only.
fputs("\\psset{unit=5.0in}\n", gpoutfile);
fprintf(gpoutfile,
PST_pdftricks2 ?
"\\begin{pspicture*}%s(%f,%f)(%f,%f)\n" :
"\\pspicture%s(%f,%f)(%f,%f)\n",
background,
0., 0.,
PSTRICKS_size_x / 5., PSTRICKS_size_y / 5.
);
fputs("\
\\ifx\\nofigs\\undefined\n\
\\catcode`@=11\n\n",
gpoutfile
);
} else {
fprintf(gpoutfile, "\
\\pspicture%s(%f,%f)(%f,%f)\n\
\\ifx\\nofigs\\undefined\n\
\\catcode`@=11\n\n",
background,
0., 0., 1., 1.
);
}
PSTRICKS_posx = PSTRICKS_posy = 0;
PSTRICKS_linetype(-1);
PSTRICKS_palette_set = FALSE; /* PM3D palette set? */
/* Re-set point symbol size */
fputs("\\psset{dotscale=1}\n", gpoutfile);
PST_pointsize = 1.;
strcpy(PSTRICKS_old_linecolor, "black");
strcpy(PSTRICKS_linecolor, "black");
PSTRICKS_lw = 1;
PSTRICKS_arrowwidth = PSTRICKS_arrowlength = PSTRICKS_arrowinset = -1;
fprintf(gpoutfile, "\\psset{linecap=%d,linejoin=%d}\n", PST_rounded ? 1 : 0, PST_rounded ? 1 : 0);
}
TERM_PUBLIC void
PSTRICKS_text()
{
PSTRICKS_endline();
fputs("\
\\catcode`@=12\n\
\\fi\n", gpoutfile);
fputs(PST_pdftricks2 ?
"\\end{pspicture*}\n" : "\\endpspicture\n",
gpoutfile);
if (PST_standalone) {
fputs("\\end{figure}\n", gpoutfile);
}
}
/* coordinate mapping functions */
static inline double
PSTRICKS_map_x(int x)
{
return x / PSTRICKS_XMAX;
}
static inline double
PSTRICKS_map_y(int y)
{
return y / PSTRICKS_YMAX;
}
TERM_PUBLIC void
PSTRICKS_linetype(int linetype)
{
PSTRICKS_endline();
/* all lines except for axis default to solid */
if (linetype == LT_AXIS)
PSTRICKS_type = -1;
else
PSTRICKS_type = 0;
/* negative line types are all black */
if (linetype < 0) {
PSTRICKS_color_type = TC_DEFAULT;
PSTRICKS_save_color("black");
} else {
PSTRICKS_color_type = TC_LT;
PSTRICKS_color = linetype % PSTRICKS_NUMCOLORS;
PSTRICKS_save_color(PSTRICKS_colors[PSTRICKS_color]);
}
}
TERM_PUBLIC void
PSTRICKS_dashtype(int dt, t_dashtype *custom_dash_pattern)
{
PSTRICKS_endline();
if (dt >= 0) {
int linetype = dt;
if (linetype >= PSTRICKS_NUMLINES + LT_BLACK)
linetype %= (PSTRICKS_NUMLINES + LT_BLACK);
if (linetype < LT_BLACK)
linetype = LT_BLACK;
PSTRICKS_type = linetype;
} else if (dt == DASHTYPE_SOLID) {
PSTRICKS_type = 0;
} else if (dt == DASHTYPE_AXIS) {
PSTRICKS_type = -1;
} else if (dt == DASHTYPE_CUSTOM) {
/* not supported */
}
}
TERM_PUBLIC void
PSTRICKS_move(unsigned int x, unsigned int y)
{
PSTRICKS_endline();
PSTRICKS_posx = PSTRICKS_map_x(x);
PSTRICKS_posy = PSTRICKS_map_y(y);
}
TERM_PUBLIC void
PSTRICKS_point(unsigned int x, unsigned int y, int number)
{
PSTRICKS_move(x, y);
/* Print the character defined by 'number'; number < 0 means
to use a dot, otherwise one of the defined points. */
if (PST_pointsize = PSTRICKS_LINEMAX) {
putc('\n', gpoutfile);
fprintf(gpoutfile, "%s(%.4f,%.4f)",
PSTRICKS_lines[PSTRICKS_type + 2],
PSTRICKS_posx, PSTRICKS_posy);
PSTRICKS_linecount = 1;
}
}
if (PSTRICKS_linecount % 8 == 0)
putc('\n', gpoutfile);
PSTRICKS_posx = PSTRICKS_map_x(ux);
PSTRICKS_posy = PSTRICKS_map_y(uy);
fprintf(gpoutfile, "(%.4f,%.4f)", PSTRICKS_posx, PSTRICKS_posy);
}
static void
PSTRICKS_endline()
{
if (PSTRICKS_inline) {
if (PSTRICKS_linecount % 8 != 0)
putc('\n', gpoutfile);
putc('\n', gpoutfile);
PSTRICKS_inline = FALSE;
}
}
TERM_PUBLIC void
PSTRICKS_arrow(
unsigned int sx, unsigned int sy,
unsigned int ex, unsigned int ey,
int head)
{
const char * head_str = "";
double width, length, inset = 0.;
/* Note: we cannot handle curr_arrow_headfilled, HEADS_ONLY, and SHAFT_ONLY */
PSTRICKS_endline();
PSTRICKS_apply_linecolor();
if (!PST_psarrows) {
do_arrow(sx, sy, ex, ey, head);
return;
}
if (curr_arrow_headlength 0) {
fputs("\\rput", gpoutfile);
/* Set justification */
switch (PSTRICKS_justify) {
case LEFT:
fputs("[l]", gpoutfile);
break;
case CENTRE:
break;
case RIGHT:
fputs("[r]", gpoutfile);
break;
}
/* Set text angle */
switch (PSTRICKS_angle) {
case 0:
break;
case 90:
fputs("{L}", gpoutfile);
break;
default:
fprintf(gpoutfile, "{%i}", PSTRICKS_angle);
break;
}
/* Set reference position and text */
fprintf(gpoutfile, "(%.4f,%.4f)",
PSTRICKS_map_x(x),
PSTRICKS_map_y(y));
if (!PST_colortext || (strcmp(PSTRICKS_linecolor, "black") == 0))
fprintf(gpoutfile, "{%s}\n", str);
else
fprintf(gpoutfile, "{\\%s %s}\n", PSTRICKS_linecolor, str);
}
}
TERM_PUBLIC int
PSTRICKS_justify_text(enum JUSTIFY mode)
{
PSTRICKS_justify = mode;
return TRUE;
}
TERM_PUBLIC int
PSTRICKS_text_angle(float ang)
{
PSTRICKS_angle = ang;
while (PSTRICKS_angle < 0)
PSTRICKS_angle += 360;
while (PSTRICKS_angle > 360)
PSTRICKS_angle -= 360;
return TRUE;
}
TERM_PUBLIC void
PSTRICKS_reset()
{
PSTRICKS_endline();
PSTRICKS_posx = PSTRICKS_posy = 0;
if (PST_standalone)
fputs("\\end{document}\n", gpoutfile);
}
TERM_PUBLIC void
PSTRICKS_linewidth(double linewidth)
{
linewidth *= PSTRICKS_lw_scale;
if (linewidth * 0.0015 != PSTRICKS_lw) {
PSTRICKS_endline();
PSTRICKS_lw = linewidth * 0.0015;
fprintf(gpoutfile, "\\psset{linewidth=%.4f}\n", PSTRICKS_lw);
}
}
TERM_PUBLIC int
PSTRICKS_make_palette(t_sm_palette *palette)
{
/* Query to determine palette size */
if (palette == NULL) {
return PSTRICKS_palette_size;
}
PSTRICKS_endline();
if (PSTRICKS_palette_set == FALSE) {
int i;
/* Create new palette */
PSTRICKS_palette_set = TRUE;
if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) {
/* Grey palette */
for (i = 0; i < sm_palette.colors; i++) {
double g = i * 1.0 / (sm_palette.colors - 1);
g = 1e-3 * (int)(g * 1000); /* round to 3 digits to use %g below */
fprintf(gpoutfile, "\\newgray{PST@COLOR%d}{%g}\n", i, g);
}
} else {
for (i = 0; i < sm_palette.colors; i++) {
double r, g, b;
/* round to 3 digits */
r = 1e-3 * (int)(palette->color[i].r * 1000);
g = 1e-3 * (int)(palette->color[i].g * 1000);
b = 1e-3 * (int)(palette->color[i].b * 1000);
fprintf(gpoutfile, "\\newrgbcolor{PST@COLOR%d}{%f %f %f}\n", i, r, g, b);
}
}
}
#ifdef PSTRICKS_SHORTER_FILE
/* use the following macro to shorten the file size */
fputs("\\def\\polypmIIId#1{\\pspolygon[linestyle=none,fillstyle=solid,fillcolor=PST@COLOR#1]}\n\n", gpoutfile);
#endif
return 0;
}
static void
PSTRICKS_save_color(const char * color)
{
if (color != NULL)
strcpy(PSTRICKS_linecolor, color);
}
static void
PSTRICKS_apply_linecolor(void)
{
if (strcmp(PSTRICKS_linecolor, PSTRICKS_old_linecolor) != 0) {
PSTRICKS_endline();
strcpy(PSTRICKS_old_linecolor, PSTRICKS_linecolor);
fprintf(gpoutfile, "\\psset{linecolor=%s}\n", PSTRICKS_linecolor);
}
if (PSTRICKS_alpha != PSTRICKS_alpha_old) {
/* We set the opacity of lines and fills. Required for transparent symbols. */
fprintf(gpoutfile, "\\psset{strokeopacity=%0.2f,opacity=%0.2f}\n", PSTRICKS_alpha, PSTRICKS_alpha);
PSTRICKS_alpha_old = PSTRICKS_alpha;
}
}
TERM_PUBLIC void
PSTRICKS_set_color(t_colorspec *colorspec)
{
int new_color;
double gray = colorspec->value;
switch (colorspec->type) {
case TC_FRAC:
PSTRICKS_color_type = colorspec->type;
if (CHECK_SMPAL_IS_DISCRETE_GRADIENT) {
new_color = index_from_gray(gray);
} else {
if (sm_palette.use_maxcolors != 0)
gray = quantize_gray(gray);
new_color = (gray = 1) ? sm_palette.colors - 1 : (int)(gray * sm_palette.colors);
if (new_color >= PSTRICKS_palette_size)
new_color = PSTRICKS_palette_size - 1;
}
if (PSTRICKS_palette_set == FALSE) {
fputs("pstricks: Palette used before set!\n", stderr);
fputs("% ERROR: Palette used before set!\n", gpoutfile);
}
PSTRICKS_color = new_color;
snprintf(PSTRICKS_color_str, sizeof(PSTRICKS_color_str), "PST@COLOR%d", new_color);
PSTRICKS_save_color(PSTRICKS_color_str);
PSTRICKS_alpha = 1.;
break;
case TC_RGB: {
int red, green, blue;
double r, g, b, alpha;
red = (colorspec->lt >> 16) & 0xff;
green = (colorspec->lt >> 8) & 0xff;
blue = (colorspec->lt ) & 0xff;
alpha = (double) (255 - ((colorspec->lt >> 24) & 0xff)) / 255;
/* round to 3 digits */
r = 1e-3 * (int)(red / 255. * 1000);
g = 1e-3 * (int)(green / 255. * 1000);
b = 1e-3 * (int)(blue / 255. * 1000);
if ((PSTRICKS_color_type != TC_RGB) ||
(PSTRICKS_rgbcolor.r != r) ||
(PSTRICKS_rgbcolor.g != g) ||
(PSTRICKS_rgbcolor.b != b)) {
PSTRICKS_endline();
fprintf(gpoutfile, "\\newrgbcolor{c}{%g %g %g}\n", r, g, b);
PSTRICKS_old_linecolor[0] = 0; /* invalidate old color */
strcpy(PSTRICKS_linecolor, "c");
PSTRICKS_color_type = colorspec->type;
PSTRICKS_rgbcolor.r = r;
PSTRICKS_rgbcolor.g = g;
PSTRICKS_rgbcolor.b = b;
}
PSTRICKS_alpha = alpha;
break;
}
case TC_LT:
if (colorspec->lt < 0) {
PSTRICKS_color_type = TC_DEFAULT;
PSTRICKS_save_color("black");
} else {
PSTRICKS_color_type = TC_LT;
PSTRICKS_color = colorspec->lt % PSTRICKS_NUMCOLORS;
PSTRICKS_save_color(PSTRICKS_colors[PSTRICKS_color]);
}
PSTRICKS_alpha = 1.;
break;
default:
break;
}
}
TERM_PUBLIC void
PSTRICKS_fillbox(int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height)
{
int pattern = style >> 4;
int frac = style >> 4;
const char * stylestr = "solid";
const char * colorstr = "fillcolor";
char patfill[80];
char opacity[80] = "";
char fraction[80] = "";
PSTRICKS_endline();
switch (style & 0x0f) {
case FS_SOLID:
// color already set
if (frac != 100)
snprintf(fraction, sizeof(fraction), "!%d", frac);
if (PSTRICKS_alpha != 1.)
snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", PSTRICKS_alpha);
break;
case FS_TRANSPARENT_SOLID:
// color already set
if (frac != 100)
snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", (double) frac / 100.);
break;
case FS_PATTERN:
case FS_TRANSPARENT_PATTERN:
stylestr = (char *) PSTRICKS_patterns[pattern % PSTRICKS_NUMPATTERN];
if (pattern != 0)
colorstr = "hatchcolor";
snprintf(patfill, sizeof(patfill), stylestr, (style & 0x0f) == FS_PATTERN ? "*" : "");
if ((style & 0x0f) == FS_PATTERN && PSTRICKS_have_bg)
strncat(patfill, ",fillcolor=PST@BGCOLOR", sizeof(patfill)-strlen(patfill)-1);
stylestr = patfill;
break;
case FS_EMPTY:
break;
case FS_DEFAULT:
default:
break;
}
fprintf(gpoutfile, "\\psframe[linestyle=none,fillstyle=%s", stylestr);
if (PSTRICKS_color_type == TC_FRAC) {
#ifdef PSTRICKS_SHORTER_FILE
fprintf(gpoutfile, "%s,%s=PST@COLOR%d%s]", opacity, colorstr, PSTRICKS_color, fraction);
#else
fprintf(gpoutfile, "%s,%s=%s%s]", opacity, colorstr, PSTRICKS_color_str, fraction);
#endif
} else if (PSTRICKS_color_type == TC_RGB) {
fprintf(gpoutfile, "%s,%s=c%s]", opacity, colorstr, fraction);
} else if (PSTRICKS_color_type == TC_LT) {
fprintf(gpoutfile, "%s,%s=%s%s]", opacity, colorstr, PSTRICKS_colors[PSTRICKS_color], fraction);
} else { // e.g. TC_DEFAULT
fprintf(gpoutfile, "%s]", opacity);
}
fprintf(gpoutfile, "(%.4g,%.4g)(%.4g,%.4g)\n",
PSTRICKS_map_x(x1), PSTRICKS_map_y(y1),
PSTRICKS_map_x(x1 + width), PSTRICKS_map_y(y1 + height));
}
TERM_PUBLIC void
PSTRICKS_filled_polygon(int points, gpiPoint *corners)
{
int style = corners->style;
int pattern = style >> 4;
int frac = style >> 4;
const char * stylestr = "solid";
const char * colorstr = "fillcolor";
char patfill[80];
char opacity[80] = "";
char fraction[80] = "";
int i;
PSTRICKS_endline();
switch (style & 0x0f) {
case FS_SOLID:
// color already set
if (frac != 100)
snprintf(fraction, sizeof(fraction), "!%d", frac);
if (PSTRICKS_alpha != 1.)
snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", PSTRICKS_alpha);
break;
case FS_TRANSPARENT_SOLID:
// color already set
if (frac != 100)
snprintf(opacity, sizeof(opacity), ",opacity=%0.2f", (double) frac / 100.);
break;
case FS_PATTERN:
case FS_TRANSPARENT_PATTERN:
stylestr = (char *) PSTRICKS_patterns[pattern % PSTRICKS_NUMPATTERN];
if (pattern != 0)
colorstr = "hatchcolor";
snprintf(patfill, sizeof(patfill), stylestr, (style & 0x0f) == FS_PATTERN ? "*" : "");
if ((style & 0x0f) == FS_PATTERN && PSTRICKS_have_bg)
strncat(patfill, ",fillcolor=PST@BGCOLOR", sizeof(patfill)-strlen(patfill)-1);
stylestr = patfill;
break;
case FS_EMPTY:
break;
case FS_DEFAULT:
default:
break;
}
if (PSTRICKS_color_type == TC_FRAC) {
#ifdef PSTRICKS_SHORTER_FILE
/* using a macro for an abbreviation */
fprintf(gpoutfile, "\\polypmIIId{%d}", PSTRICKS_color);
#else
fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s,%s=%s%s]", stylestr, opacity, colorstr, PSTRICKS_color_str, fraction);
#endif
} else if (PSTRICKS_color_type == TC_RGB) {
fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s,%s=c%s]", stylestr, opacity, colorstr, fraction);
} else if (PSTRICKS_color_type == TC_LT) {
fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s,%s=%s%s]", stylestr, opacity, colorstr, PSTRICKS_colors[PSTRICKS_color], fraction);
} else {
fprintf(gpoutfile, "\\pspolygon[linestyle=none,fillstyle=%s%s]", stylestr, opacity);
}
for (i = 0; i < points; i++) {
if (i % 8 == 7) /* up to 8 corners per line */
fputs("\n", gpoutfile);
fprintf(gpoutfile,"(%.4g,%.4g)", PSTRICKS_map_x(corners[i].x), PSTRICKS_map_y(corners[i].y));
}
/* make sure that polygons are closed - avoids spurious artifacts */
if ((corners[0].x != corners[points - 1].x) || (corners[0].y != corners[points - 1].y))
fprintf(gpoutfile,"(%.4g,%.4g)", PSTRICKS_map_x(corners[0].x), PSTRICKS_map_y(corners[0].y));
fputs("\n\n", gpoutfile);
}
TERM_PUBLIC void
PSTRICKS_boxed_text(unsigned int x, unsigned int y, int option)
{
switch (option) {
case TEXTBOX_INIT:
if (!PSTRICKS_in_textbox) {
/* ignore second init call */
PSTRICKS_in_textbox = TRUE;
PSTRICKS_textbox_x = PSTRICKS_map_x(x);
PSTRICKS_textbox_y = PSTRICKS_map_y(y);
PSTRICKS_textbox_fill = FALSE;
PSTRICKS_textbox_frame = FALSE;
PSTRICKS_textbox_text = NULL;
PSTRICKS_textbox_fillcolor = NULL;
}
//printf("textbox init ");
break;
case TEXTBOX_OUTLINE:
PSTRICKS_textbox_frame = TRUE;
//printf(" outline ");
break;
case TEXTBOX_BACKGROUNDFILL:
PSTRICKS_textbox_fill = TRUE;
if (PSTRICKS_color_type == TC_DEFAULT)
PSTRICKS_textbox_fillcolor = strdup("white");
else
PSTRICKS_textbox_fillcolor = strdup(PSTRICKS_linecolor);
//printf(" border ");
break;
case TEXTBOX_MARGINS:
PSTRICKS_textbox_sep = PSTRICKS_map_x(term->h_char * GPMAX(x, y) / 1000);
break;
case TEXTBOX_FINISH:
//printf("... finish\n");
PSTRICKS_in_textbox = FALSE;
if (!PSTRICKS_textbox_text)
return;
if (PSTRICKS_textbox_fill && PSTRICKS_textbox_frame) {
fprintf(gpoutfile,
"\\rput(%.4f,%.4f){"
"\\psframebox[linecolor=%s,framesep=0]{"
"\\psframebox*[fillcolor=%s,fillstyle=solid,framesep=%.4f]{%s}}}",
PSTRICKS_textbox_x, PSTRICKS_textbox_y,
PSTRICKS_linecolor, PSTRICKS_textbox_fillcolor,
PSTRICKS_textbox_sep,
PSTRICKS_textbox_text);
} else if (PSTRICKS_textbox_frame) {
fprintf(gpoutfile,
"\\rput(%.4f,%.4f){"
"\\psframebox[linecolor=black,framesep=%.4f]{%s}}",
PSTRICKS_textbox_x, PSTRICKS_textbox_y,
PSTRICKS_textbox_sep,
PSTRICKS_textbox_text);
} else {
fprintf(gpoutfile,
"\\rput(%.4f,%.4f){"
"\\psframebox*[fillcolor=%s,fillstyle=solid,framesep=%.4f]{%s}}",
PSTRICKS_textbox_x, PSTRICKS_textbox_y,
PSTRICKS_textbox_fillcolor,
PSTRICKS_textbox_sep,
PSTRICKS_textbox_text);
}
free(PSTRICKS_textbox_text);
if (PSTRICKS_textbox_fillcolor)
free(PSTRICKS_textbox_fillcolor);
break;
}
}
#endif /* TERM_BODY */
#ifdef TERM_TABLE
TERM_TABLE_START(pstricks_driver)
"pstricks", "LaTeX picture environment with PSTricks macros",
PSTRICKS_XMAX, PSTRICKS_YMAX * 3./5., PSTRICKS_VCHAR, PSTRICKS_HCHAR,
PSTRICKS_VTIC, PSTRICKS_HTIC, PSTRICKS_options, PSTRICKS_init, PSTRICKS_reset,
PSTRICKS_text, null_scale, PSTRICKS_graphics, PSTRICKS_move, PSTRICKS_vector,
PSTRICKS_linetype, PSTRICKS_put_text, PSTRICKS_text_angle,
PSTRICKS_justify_text, PSTRICKS_point, PSTRICKS_arrow, set_font_null, PSTRICKS_pointsize,
TERM_BINARY | TERM_IS_LATEX | TERM_CAN_DASH | TERM_ALPHA_CHANNEL |
TERM_LINEWIDTH | TERM_POINTSCALE,
0 /*suspend*/, 0 /*resume*/,
PSTRICKS_fillbox, PSTRICKS_linewidth,
#ifdef USE_MOUSE
0, 0, 0, 0, 0,
#endif
PSTRICKS_make_palette, 0, PSTRICKS_set_color, PSTRICKS_filled_polygon,
0, /* image */
0, 0, 0, /* enhanced text */
0, /* layer */
0, /* path */
0.0, /* scale (unused) */
0, /* hypertext */
PSTRICKS_boxed_text,
0,
PSTRICKS_dashtype
TERM_TABLE_END(pstricks_driver)
#undef LAST_TERM
#define LAST_TERM pstricks_driver
#endif /* TERM_TABLE */
#endif /* TERM_PROTO_ONLY */
#ifdef TERM_HELP
START_HELP(pstricks)
"1 pstricks",
"?commands set terminal pstricks",
"?set terminal pstricks",
"?set term pstricks",
"?terminal pstricks",
"?term pstricks",
"?pstricks",
" The `pstricks` driver is intended for use with the \"pstricks.sty\" macro",
" package for TeX or LaTeX.",
" You need \"pstricks.sty\", and, of course, a printer that understands",
" PostScript, or a converter such as Ghostscript.",
"",
" PSTricks is available at",
"^ ",
" http://tug.org/PSTricks/.",
"^ ",
" This driver definitely does not come close to using the full",
" capability of the PSTricks package.",
"",
" Syntax:",
" set terminal pstricks",
" {unit | size {unit},{unit}}",
" {standalone | input}",
" {blacktext | colortext | colourtext}",
" {linewidth } {rounded | butt}",
" {pointscale }",
" {psarrows | gparrows}",
" {background }",
" {pstricks | pdftricks2}",
"",
" The `unit` option produces a plot with internal dimensions 1x1. The default",
" is a plot of `size 5in,3in`.",
"",
" `standalone` produces a LaTeX file with possibly multiple plots, ready",
" to be compiled. The default is `input` to produce a TeX file which can",
" be included.",
"",
" `blacktext` forces all text to be written in black. `colortext` enables",
" colored text. The default is `blacktext`.",
"",
" `rounded` sets line caps and line joins to be rounded. `butt` sets butt",
" caps and mitered joins and is the default.",
"",
" `linewidth` and `pointscale` scale the width of lines and the size of point",
" symbols, respectively.",
"",
" `psarrows` draws `arrow`s using PSTricks commands which are shorter but do",
" not offer all options. `gparrows` selects drawing arrows using gnuplot's own",
" routine for full functionality instead.",
"",
" With the option `pdftricks2` you can create output for the `pdftricks2`",
" macro package, which can be used with pdflatex/lualatex. Otherwise, output",
" for the `pstricks` package with traditional tex/latex or xelatex is",
" produced.",
"",
" The old `hacktext` option has been replaced by the new default format (%h),",
" see `format specifiers`.",
"",
" Transparency requires support by Ghostscript or conversion to PDF."
END_HELP(pstricks)
#endif /* TERM_HELP */