/*
 * $Id: tpic.trm%v 3.50 1993/07/09 05:35:24 woo Exp $
 */

/* GNUPLOT - tpic.trm */
/*
 * Copyright (C) 1990 - 1993   
 *
 * 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 modified code.  Modifications are to be distributed 
 * as patches to released version.
 *  
 * This software  is provided "as is" without express or implied warranty.
 * 
 * This file is included by ../term.c.
 *
 * This terminal driver supports:
 *   The tpic \specials (version 2.2) for LaTeX. 
 *
 * AUTHORS
 *   Oh-Yeah?   3 Sep. 1992 (closely following eepic.trm by David Kotz)
 *   A. Woo     5 Oct. 1992 (removed ansi prototypes for braindead compilers)
 *
 * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
 * 
 */
/*
 *  This file contains the tpic terminal driver for use with LaTeX. 
 *  This is an alternative to the latex and eepic drivers. You need 
 *  a printer driver that supports the tpic \specials version 2.2.
 *
 * Comparison with the eepic driver (eepic.trm):
 *  Merits
 *    - More point and line types
 *    - Options to change point size, linewidth, dot & dash intervals
 *    - Dotted and dashed lines for high-sample-rate curves (but may
 *      depend on tpic (da & dt) implementation of your dvi driver :-)
 *    - Overlapped points made fancier by tpic shading facility
 *    - Optional comments for trimming figure margins
 *    - No need for epic and eepic macros
 *  Drawback
 *    - You cannot use eepicemu macro for non-tpic-support dvi drivers
 *
 * LATEX must also be defined.
 */


/* These parameters can be modified as you like, through options.  Say 
   "set terminal tpic <pointsize> <linewidth> <interval>".  <pointsize> 
   and <linewidth> are integers in milli-inches; <interval> is a float 
   in inches.  If non-positive value is specified, the default (below) 
   is chosen. 
*/
static int tpic_pointsize   =  40; /* min point radius   (in milli-inches) */
static int tpic_linewidth   =   6; /* min line thickness (in milli-inches) */
static double tpic_interval = 0.1; /* min dot & dash intervals (in inches) */

/* ARROWS: same code as for LATEX */
/* static void best\_latex\_arrow(int sx, int sy, int ex, int ey, int who, 
	TBOOLEAN head); figure out the best arrow. in latex.trm */
static void best_latex_arrow();

/* all prototypes ... */
int TPIC_options(); /* get size options */
int TPIC_init();
int TPIC_reset();
int TPIC_text();
/* TBOOLEAN TPIC_scale(double xs, double ys);  scaling factors */
TBOOLEAN TPIC_scale();
int TPIC_graphics();
/* int TPIC_move(unsigned int x, unsigned int y);
int TPIC_vector(unsigned int ux, unsigned int uy); */
int TPIC_move();
int TPIC_vector();
static void tpic_startline();  /* private */
static void tpic_endline();  /* private */
/* static void tpic_pushpath(unsigned int x, unsigned int y); /* private */
static void tpic_pushpath();
static void tpic_scanpath();
/* int TPIC_linetype(int linetype);
int TPIC_put_text(int x, int y, char *str); /* ref point and text */
int TPIC_linetype();
int TPIC_put_text();
/* TBOOLEAN TPIC_text_angle(int angle);
TBOOLEAN TPIC_justify_text(enum JUSTIFY mode); */
TBOOLEAN TPIC_text_angle();
TBOOLEAN TPIC_justify_text();
/* int TPIC_point(unsigned int x, unsigned int y, int number); */
int TPIC_point();
/* int TPIC_arrow(int sx, int sy, int ex, int ey, TBOOLEAN head); */
int TPIC_arrow();
/* void tpic_diamond(int size); */
void tpic_diamond();
/* void tpic_plus(int size); */
void tpic_plus();
/* void tpic_box(int size); */
void tpic_box();
/* void tpic_times(int size); */
void tpic_times();
/* void tpic_triangle(int size); */
void tpic_triangle();
/* void tpic_star(int size); */
void tpic_star();
/* void tpic_hexagon(int size); */
void tpic_hexagon();
/* void tpic_circle(int size); */
void tpic_circle();
/* void tpic_doublecircle(int size); */
void tpic_doublecircle();
/* void tpic_vercircle(int size); /* circle with | */
void tpic_vercircle(); /* circle with | */
/* void tpic_horcircle(int size); /* circle with - */
void tpic_horcircle(); /* circle with - */
/* void tpic_pluscircle(int size); /* circle with + */
void tpic_pluscircle(); /* circle with + */
/* void tpic_timescircle(int size); /* circle with times */
void tpic_timescircle(); /* circle with times */
/* void tpic_starcircle(int size); /* circle with star */
void tpic_starcircle(); /* circle with star */
/* void tpic_dotcircle(int size); /* circle with dot (black circle) */
void tpic_dotcircle(); /* circle with dot (black circle) */
/* void tpic_diamondcircle(int size); /* circle with black diamond */
void tpic_diamondcircle(); /* circle with black diamond */
/* void tpic_boxcircle(int size); /* circle with black box */
void tpic_boxcircle(); /* circle with black box */
/* void tpic_trianglecircle(int size); /* circle with black triangle */
void tpic_trianglecircle(); /* circle with black triangle */
/* void tpic_hexagoncircle(int size); /* circle with black hexagon */
void tpic_hexagoncircle(); /* circle with black hexagon */
/* void tpic_plustimescircle(int size); /* no more idea ... with plus & times */
void tpic_plustimescircle(); /* no more idea ... with plus & times */
/* void tpic_abspath(unsigned int x, unsigned int y); /* absolute coord */
void tpic_abspath(); /* absolute coord */
/* void tpic_path(int x, int y); */
void tpic_path();
/* void tpic_flush(void); */
void tpic_flush();
/* void tpic_arc(int radius); /* actually, draw a full circle */
void tpic_arc(); /* actually, draw a full circle */
/* void tpic_shade(double grayscale); */
void tpic_shade();
/* void tpic_pen(int thickness); */
void tpic_pen();
/* void tpic_dottedflush(double interval); */
void tpic_dottedflush();
/* void tpic_dashedflush(double interval); */
void tpic_dashedflush();

#define TPIC_UNIT 0.001 /* tpic \specials unit in inches (1 milli-inch) */
/* 5 inches wide by 3 inches high (default) */
#define TPIC_XMAX (unsigned int) (5 / TPIC_UNIT)
#define TPIC_YMAX (unsigned int) (3 / TPIC_UNIT)
#define TPIC_PTS_PER_UNIT (72.27 * TPIC_UNIT)
#define TPIC_HTIC  (unsigned int) ( 5.0 / TPIC_PTS_PER_UNIT) /* 5pt */
#define TPIC_VTIC  (unsigned int) ( 5.0 / TPIC_PTS_PER_UNIT) /* 5pt */
#define TPIC_HCHAR (unsigned int) ( 5.3 / TPIC_PTS_PER_UNIT) /* 5.3pt */
#define TPIC_VCHAR (unsigned int) (11.0 / TPIC_PTS_PER_UNIT) /* 11pt */

typedef enum {tpic_none, tpic_white, tpic_gray, tpic_black} tpic_shadestyle;
typedef enum {tpic_nosize, tpic_small, tpic_medium, tpic_large} tpic_size;
/* typedef void (*tpic_function)(int size); */
typedef void (*tpic_function)();
typedef struct {
	tpic_shadestyle shadestyle;
	tpic_size size;
	tpic_function function;
} tpic_point_info;

/* POINTS */
static GPFAR tpic_point_info GPFAR tpic_point[] = {
	{tpic_white, tpic_medium, tpic_diamond},
	{tpic_none,  tpic_medium, tpic_plus},
	{tpic_white, tpic_medium, tpic_box},
	{tpic_none,  tpic_medium, tpic_times},
	{tpic_white, tpic_medium, tpic_triangle},
	{tpic_none,  tpic_medium, tpic_star},
	{tpic_white, tpic_small,  tpic_circle},
	{tpic_white, tpic_medium, tpic_circle},
	{tpic_white, tpic_large,  tpic_circle},
	{tpic_black, tpic_small,  tpic_circle},
	{tpic_black, tpic_medium, tpic_circle},
	{tpic_black, tpic_large,  tpic_circle},
	{tpic_black, tpic_medium, tpic_diamond},
	{tpic_black, tpic_medium, tpic_box},
	{tpic_black, tpic_medium, tpic_triangle},
	{tpic_white, tpic_medium, tpic_hexagon},
	{tpic_black, tpic_medium, tpic_hexagon},
	{tpic_white, tpic_medium, tpic_doublecircle},
	{tpic_white, tpic_medium, tpic_vercircle},
	{tpic_white, tpic_medium, tpic_horcircle},
	{tpic_white, tpic_medium, tpic_pluscircle},
	{tpic_white, tpic_medium, tpic_timescircle},
	{tpic_white, tpic_medium, tpic_starcircle},
	{tpic_black, tpic_medium, tpic_doublecircle},
	{tpic_white, tpic_medium, tpic_dotcircle},
	{tpic_white, tpic_medium, tpic_diamondcircle},
	{tpic_white, tpic_medium, tpic_boxcircle},
	{tpic_white, tpic_medium, tpic_trianglecircle},
	{tpic_white, tpic_medium, tpic_hexagoncircle},
	{tpic_white, tpic_medium, tpic_plustimescircle}
};

typedef enum {tpic_solid, tpic_dotted, tpic_dashed, 
	tpic_dashed_sdot, tpic_dashed_ddot} tpic_linestyle;
typedef struct {
	tpic_size thickness, interval;
	tpic_linestyle linestyle;
} tpic_line_info;

/* LINES */
static GPFAR tpic_line_info GPFAR tpic_line[] = {
	{tpic_medium, tpic_nosize, tpic_solid},  /* -2 border */
	{tpic_small,  tpic_small,  tpic_dashed}, /* -1 axes */
	{tpic_small,  tpic_nosize, tpic_solid},
	{tpic_medium, tpic_nosize, tpic_solid},
	{tpic_large,  tpic_nosize, tpic_solid},
	{tpic_small,  tpic_small,  tpic_dotted},
	{tpic_medium, tpic_small,  tpic_dotted},
	{tpic_large,  tpic_small,  tpic_dotted},
	{tpic_small,  tpic_small,  tpic_dashed},
	{tpic_medium, tpic_small,  tpic_dashed},
	{tpic_large,  tpic_small,  tpic_dashed},
	{tpic_small,  tpic_small,  tpic_dashed_sdot}, /* dash with single dots */
	{tpic_medium, tpic_small,  tpic_dashed_sdot},
	{tpic_large,  tpic_small,  tpic_dashed_sdot},
	{tpic_small,  tpic_small,  tpic_dashed_ddot}, /* dash with double dots */
	{tpic_medium, tpic_small,  tpic_dashed_ddot},
	{tpic_large,  tpic_small,  tpic_dashed_ddot},
	{tpic_small,  tpic_medium, tpic_dotted},
	{tpic_medium, tpic_medium, tpic_dotted},
	{tpic_large,  tpic_medium, tpic_dotted},
	{tpic_small,  tpic_medium, tpic_dashed},
	{tpic_medium, tpic_medium, tpic_dashed},
	{tpic_large,  tpic_medium, tpic_dashed},
	{tpic_small,  tpic_medium, tpic_dashed_sdot},
	{tpic_medium, tpic_medium, tpic_dashed_sdot},
	{tpic_large,  tpic_medium, tpic_dashed_sdot},
	{tpic_small,  tpic_medium, tpic_dashed_ddot},
	{tpic_medium, tpic_medium, tpic_dashed_ddot},
	{tpic_large,  tpic_medium, tpic_dashed_ddot},
	{tpic_small,  tpic_large,  tpic_dotted},
	{tpic_medium, tpic_large,  tpic_dotted},
	{tpic_large,  tpic_large,  tpic_dotted},
	{tpic_small,  tpic_large,  tpic_dashed},
	{tpic_medium, tpic_large,  tpic_dashed},
	{tpic_large,  tpic_large,  tpic_dashed},
	{tpic_small,  tpic_large,  tpic_dashed_sdot},
	{tpic_medium, tpic_large,  tpic_dashed_sdot},
	{tpic_large,  tpic_large,  tpic_dashed_sdot},
	{tpic_small,  tpic_large,  tpic_dashed_ddot},
	{tpic_medium, tpic_large,  tpic_dashed_ddot},
	{tpic_large,  tpic_large,  tpic_dashed_ddot}
};

/* int TPIC_options(void) /* get size options */
int TPIC_options() /* get size options */
{
/*
	extern struct value *const_express(struct value *valptr);
	extern double real(struct value *val);
	*/
	extern struct value *const_express();
	extern double real();
	struct value a;
	int pointsize, linewidth;
	double interval;

	if (!END_OF_COMMAND) {
		pointsize = (int)real(const_express(&a));
		if (pointsize > 0) tpic_pointsize = pointsize;
	}

	if (!END_OF_COMMAND) {
		linewidth = (int)real(const_express(&a));
		if (linewidth > 0) tpic_linewidth = linewidth;
	}

	if (!END_OF_COMMAND) {
		interval = (double)real(const_express(&a));
		if (interval > 0) tpic_interval = interval;
	}

	sprintf(term_options, "%d %d %f", tpic_pointsize, tpic_linewidth, 
		tpic_interval);
	return(0);
}

static unsigned int tpic_posx; /* current position */
static unsigned int tpic_posy;
static int tpic_point_types;
static int tpic_numlines;

/* int TPIC_init(void) */
int TPIC_init()
{
static char GPFAR tpic1[] = "\
%% GNUPLOT: LaTeX picture using tpic \\specials\n\
%%          with %d point types and %d line types\n\
%% Options: pointsize = %d, linewidth = %d, interval = %f\n\
%% To change above options, say:\n\
%% set terminal tpic pointsize_value linewidth_value interval_value\n\
%% (pointsize and linewidth - integers in milli-inches.\n\
%%  interval - a float in inches.  If zero is specified, \n\
%%  the default value is chosen.)\n\
\\setlength{\\unitlength}{%fin}%%\n";
	tpic_point_types = sizeof(tpic_point) / sizeof(tpic_point[0]);
	tpic_numlines = sizeof(tpic_line) / sizeof(tpic_line[0]);

	tpic_posx = tpic_posy = 0;
	TPIC_linetype(-1);
	fprintf(outfile, tpic1,
		tpic_point_types, tpic_numlines - 2,
		tpic_pointsize, tpic_linewidth, tpic_interval,
		TPIC_UNIT);
	return(0);
}

/* int TPIC_reset(void) */
int TPIC_reset()
{
	tpic_endline();
	tpic_posx = tpic_posy = 0;
	return(0);
}

/* int TPIC_text(void) */
int TPIC_text()
{
	tpic_endline();
	fprintf(outfile, "\\end{picture}\n");
	return(0);
}

/* TBOOLEAN TPIC_scale(double xs, double ys) /* scaling factors */
TBOOLEAN TPIC_scale(xs,ys)
double xs; double ys; /* scaling factors */
{
	register struct termentry *t = &term_tbl[term];

	/* we change the table for use in graphics.c and TPIC_graphics */
	t->xmax = (unsigned int)(TPIC_XMAX * xs);
	t->ymax = (unsigned int)(TPIC_YMAX * ys);
	return(TRUE);
}

/* int TPIC_graphics(void) */
int TPIC_graphics()
{
	register struct termentry *t = &term_tbl[term];
	int left, right, top, bottom; /* margins */
	static char GPFAR begin[] = "%s\\begin{picture}(%d,%d)(%d,%d)%% %s\n";

	fprintf(outfile, begin, "", t->xmax, t->ymax, 0, 0, "");

	/* the following is dependent on boundary() function in graphics.c */
	left = TPIC_HCHAR * 12;
	right = TPIC_HCHAR * 2 + TPIC_HTIC;
	bottom = TPIC_VCHAR * 7 / 2 + 1;
	top = TPIC_VCHAR * 5 / 2 - 1;
	fprintf(outfile, begin, "%% ", t->xmax - left, t->ymax, left, 0, 
		"trim left margin");
	fprintf(outfile, begin, "%% ", t->xmax - right, t->ymax, 0, 0, 
		"trim right margin");
	fprintf(outfile, begin, "%% ", t->xmax - left - right, t->ymax, left, 0, 
		"trim left & right margins");
	fprintf(outfile, begin, "%% ", t->xmax, t->ymax - top, 0, 0, 
		"trim top margin");
	fprintf(outfile, begin, "%% ", t->xmax, t->ymax - bottom, 0, bottom, 
		"trim bottom margin");
	fprintf(outfile, begin, "%% ", t->xmax, t->ymax - top - bottom, 0, bottom,
		"trim top & bottom margins");

	fprintf(outfile, "\\tenrm%%\n");
	return(0);
}

/* int TPIC_move(unsigned int x, unsigned int y) */
int TPIC_move(x,y)
unsigned int x; unsigned int y;
{
	tpic_endline();
	tpic_posx = x;
	tpic_posy = y;
	return(0);
}

#define TPIC_LINEMAX 100 /* max value for linecount */
static TBOOLEAN tpic_inline = FALSE; /* are we in the middle of a line */
static int tpic_linecount = 0; /* number of points in line so far */

/* int TPIC_vector(unsigned int ux, unsigned int uy) */
int TPIC_vector(ux,uy)
unsigned int ux; unsigned int uy;
{
	if (!tpic_inline) {
		tpic_startline();
	} else if (tpic_linecount >= TPIC_LINEMAX) {
		/* Even though we are in middle of a path, we may start a new path 
		command once in a while; if they are too long, latex will choke. */
		tpic_endline();
		tpic_startline();
	}
	tpic_pushpath(ux, uy);
	tpic_posx = ux;
	tpic_posy = uy;
	return(0);
}

static int tpic_linetype; /* current line type */

/* static void tpic_startline(void) /* private */
static void tpic_startline() /* private */
{
	int thickness;

	tpic_inline = TRUE;
	switch (tpic_line[tpic_linetype + 2].thickness) {
	case tpic_small:
		thickness = tpic_linewidth;
		break;
	case tpic_medium:
		thickness = (int)(tpic_linewidth * 3);
		break;
	case tpic_large:
		thickness = (int)(tpic_linewidth * 5);
		break;
	}
	tpic_pen(thickness);
	tpic_linecount = 0;
	tpic_pushpath(tpic_posx, tpic_posy);
	return;
}

/* static void tpic_endline(void) /* private */
static void tpic_endline() /* private */
{
	double interval;

	if (tpic_inline) {
		tpic_scanpath(); /* draw actually */
		switch (tpic_line[tpic_linetype + 2].interval) {
		case tpic_small:
			interval = tpic_interval;
			break;
		case tpic_medium:
			interval = tpic_interval * 2;
			break;
		case tpic_large:
			interval = tpic_interval * 3;
			break;
		case tpic_nosize:
			break;
		}
		switch (tpic_line[tpic_linetype + 2].linestyle) {
		case tpic_solid:
			tpic_flush();
			break;
		case tpic_dotted:
			tpic_dottedflush(interval);
			break;
		case tpic_dashed:
			tpic_dashedflush(interval);
			break;
		case tpic_dashed_sdot: /* dashed with single dots in between */
			tpic_dashedflush(interval);
			tpic_scanpath(); /* draw again */
			tpic_dottedflush(interval / 2);
			break;
		case tpic_dashed_ddot: /* dashed with double dots in between */
			tpic_dashedflush(interval);
			tpic_scanpath(); /* draw again */
			tpic_dottedflush(interval / 3);
			break;
		}
		tpic_inline = FALSE;
	}
	return;
}

/* private: stack functions */
static unsigned int pathpoint[TPIC_LINEMAX][2]; /* point stack */

/* static void tpic_pushpath(unsigned int x, unsigned int y) /* private */
static void tpic_pushpath(x,y)
unsigned int x; unsigned int y; /* private */
{
	if (tpic_linecount < TPIC_LINEMAX) {
		pathpoint[tpic_linecount][0] = x;
		pathpoint[tpic_linecount][1] = y;
		tpic_linecount++;
	}
	return;
}

/* static void tpic_scanpath(void) */
static void tpic_scanpath()
{
	int i;

	for (i = 0; i < tpic_linecount; i++)
		tpic_abspath(pathpoint[i][0], pathpoint[i][1]);
	return;
}

/* int TPIC_linetype(int linetype) */
int TPIC_linetype(linetype)
int linetype;
{
	tpic_endline();
	if (linetype >= tpic_numlines - 2) linetype %= (tpic_numlines - 2);
	tpic_linetype = linetype;
	return(0);
}

static int tpic_angle = 0; /* 0 = horizontal, 1 = vertical */
static enum JUSTIFY tpic_justify = LEFT;

/* int TPIC_put_text(int x, int y, char *str) /* ref point and text */
int TPIC_put_text(x,y,str)
int x; int y; char *str; /* ref point and text */
{
	char *justify;

	tpic_endline();
	fprintf(outfile, "\\put(%d,%d)", x, y);

	switch (tpic_angle) {
	case 0: /* horizontal */
		switch (tpic_justify) {
		case LEFT:
			justify = "[l]";
			break;
		case CENTRE:
			justify = "";
			break;
		case RIGHT:
			justify = "[r]";
			break;
		}
		fprintf(outfile, "{\\makebox(0,0)%s{%s}}\n", justify, str);
		break;
	case 1: /* vertical */
		/* we can't really write text vertically, but will put the ylabel 
		centred at the left of the plot, and then we'll make a \shortstack */
		switch (tpic_justify) {
		case LEFT:
			justify = "[lb]";
			break;
		case CENTRE:
			justify = "[l]";
			break;
		case RIGHT:
			justify = "[lt]";
			break;
		}
		fprintf(outfile, "{\\makebox(0,0)%s{\\shortstack{%s}}}\n", 
			justify, str);
		break;
	}
	return(0);
}

/* TBOOLEAN TPIC_text_angle(int angle) */
TBOOLEAN TPIC_text_angle(angle)
int angle;
{
	tpic_angle = angle;
	return(TRUE);
}

/* TBOOLEAN TPIC_justify_text(enum JUSTIFY mode) */
TBOOLEAN TPIC_justify_text(mode)
enum JUSTIFY mode;
{
	tpic_justify = mode;
	return(TRUE);
}

/* int TPIC_point(unsigned int x, unsigned int y, int number) */
int TPIC_point(x,y,number)
unsigned int x; unsigned int y; int number;
{
	int size;

	TPIC_move(x, y);

	/* Print the character defined by 'number'; number < 0 means 
	to use a dot, otherwise one of the defined points. */

	fprintf(outfile, "\\put(%d,%d){", x, y); /* start putting */

	if (number < 0) {
		fprintf(outfile, "\\rule{.1pt}{.1pt}"); /* tiny dot */
	} else {
		number %= tpic_point_types;
		switch (tpic_point[number].shadestyle) {
		case tpic_white:
			tpic_pen(tpic_linewidth); /* set it thin */
			tpic_shade(0.0);
			break;
		case tpic_gray:
			tpic_pen(tpic_linewidth);
			tpic_shade(0.5);
			break;
		case tpic_black:
			tpic_pen(tpic_linewidth);
			tpic_shade(1.0);
			break;
		case tpic_none:
			tpic_pen(tpic_linewidth * 3); /* set it thick */
			break;
		}
		switch (tpic_point[number].size) {
		case tpic_small:
			size = tpic_pointsize;
			break;
		case tpic_medium:
			size = (int)(tpic_pointsize * 1.4142);
			break;
		case tpic_large:
			size = (int)(tpic_pointsize * 2.0);
			break;
		}
		(tpic_point[number].function)(size);
	}

	fprintf(outfile, "}%%\n"); /* end putting */
	return(0);
}

/* int TPIC_arrow(int sx, int sy, int ex, int ey, TBOOLEAN head) */
int TPIC_arrow(sx,sy,ex,ey,head)
int sx; int sy; int ex; int ey; TBOOLEAN head;
{
	best_latex_arrow(sx, sy, ex, ey, 1, head); /* call latex routine */
	tpic_posx = ex;
	tpic_posy = ey;
	return(0);
}

/* private: draw points with tpic commands */

/* void tpic_diamond(int size) */
void tpic_diamond(size)
int size;
{
	size = (int)(size * 1.4142); /* spread by sqrt(2) */

	tpic_path(0, size);
	tpic_path(-size, 0);
	tpic_path(0, -size);
	tpic_path(size, 0);
	tpic_path(0, size);
	tpic_flush();
	return;
}

/* void tpic_plus(int size) */
void tpic_plus(size)
int size;
{
	tpic_path(0, size);
	tpic_path(0, -size);
	tpic_flush();
	tpic_path(size, 0);
	tpic_path(-size, 0);
	tpic_flush();
	return;
}

/* void tpic_box(int size) */
void tpic_box(size)
int size;
{
	tpic_path(size, size);
	tpic_path(-size, size);
	tpic_path(-size, -size);
	tpic_path(size, -size);
	tpic_path(size, size);
	tpic_flush();
	return;
}

/* void tpic_times(int size) */
void tpic_times(size)
int size;
{
	size = (int)(size / 1.4142); /* reduce by sqrt(2) */

	tpic_path(size, size);
	tpic_path(-size, -size);
	tpic_flush();
	tpic_path(size, -size);
	tpic_path(-size, size);
	tpic_flush();
	return;
}

/* void tpic_triangle(int size) */
void tpic_triangle(size)
int size;
{
	int x;

	size = (int)(size / 1.6119); /* reduce by sqrt(3 * sqrt(3) / 2) */
	x = (int)(size * 1.7321);

	tpic_path(0, -size * 2);
	tpic_path(-x, size);
	tpic_path(x, size);
	tpic_path(0, -size * 2);
	tpic_flush();
	return;
}

/* void tpic_star(int size) */
void tpic_star(size)
int size;
{
	int x;

	size = (int)(size / 2); /* reduce by 2 */
	x = (int)(size * 1.7321);

	tpic_path(0, size * 2);
	tpic_path(0, -size * 2);
	tpic_flush();
	tpic_path(x, size);
	tpic_path(-x, -size);
	tpic_flush();
	tpic_path(x, -size);
	tpic_path(-x, size);
	tpic_flush();
	return;
}

/* void tpic_hexagon(int size) */
void tpic_hexagon(size)
int size;
{
	int x;

	size = (int)(size / 2); /* reduce by 2 */
	x = (int)(size * 1.7321);

	tpic_path(0, size * 2);
	tpic_path(-x, size);
	tpic_path(-x, -size);
	tpic_path(0, -size * 2);
	tpic_path(x, -size);
	tpic_path(x, size);
	tpic_path(0, size * 2);
	tpic_flush();
	return;
}

/* void tpic_circle(int size) */
void tpic_circle(size)
int size;
{
	tpic_arc(size);
	return;
}

/* void tpic_doublecircle(int size) */
void tpic_doublecircle(size)
int size;
{
	tpic_arc(size);
	tpic_shade(0.0);
	tpic_arc(size / 2);
	return;
}

/* void tpic_vercircle(int size) /* circle with | */
void tpic_vercircle(size)
int size; /* circle with | */
{
	tpic_arc(size);
	tpic_path(0, size);
	tpic_path(0, -size);
	tpic_flush();
	return;
}

/* void tpic_horcircle(int size) /* circle with - */
void tpic_horcircle(size)
int size; /* circle with - */
{
	tpic_arc(size);
	tpic_path(size, 0);
	tpic_path(-size, 0);
	tpic_flush();
	return;
}

/* void tpic_pluscircle(int size) /* circle with + */
void tpic_pluscircle(size)
int size; /* circle with + */
{
	tpic_arc(size);
	tpic_plus(size);
	return;
}

/* void tpic_timescircle(int size) /* circle with times */
void tpic_timescircle(size)
int size; /* circle with times */
{
	tpic_arc(size);
	tpic_times(size);
	return;
}

/* void tpic_starcircle(int size) /* circle with star */
void tpic_starcircle(size)
int size; /* circle with star */
{
	tpic_arc(size);
	tpic_star(size);
	return;
}

/* void tpic_dotcircle(int size) /* circle with dot (black circle) */
void tpic_dotcircle(size)
int size; /* circle with dot (black circle) */
{
	tpic_arc(size);
	tpic_shade(1.0);
	tpic_arc(size / 2);
	return;
}

/* void tpic_diamondcircle(int size) /* not enough? circle with black diamond */
void tpic_diamondcircle(size)
int size; /* not enough? circle with black diamond */
{
	tpic_arc(size);
	tpic_shade(1.0);
	tpic_diamond((int)(size / 1.5));
	return;
}

/* void tpic_boxcircle(int size) /* need more? circle with black box */
void tpic_boxcircle(size)
int size; /* need more? circle with black box */
{
	tpic_arc(size);
	tpic_shade(1.0);
	tpic_box((int)(size / 1.5));
	return;
}

/* void tpic_trianglecircle(int size) /* circle with black triangle */
void tpic_trianglecircle(size)
int size; /* circle with black triangle */
{
	tpic_arc(size);
	tpic_shade(1.0);
	tpic_triangle((int)(size / 1.5));
	return;
}

/* void tpic_hexagoncircle(int size) /* how about circle with black hexagon? */
void tpic_hexagoncircle(size)
int size; /* how about circle with black hexagon? */
{
	tpic_arc(size);
	tpic_shade(1.0);
	tpic_hexagon((int)(size / 1.2));
	return;
}

/* void tpic_plustimescircle(int size) /* no more idea ... with plus & times */
void tpic_plustimescircle(size)
int size; /* no more idea ... with plus & times */
{
	tpic_arc(size);
	tpic_plus(size);
	tpic_times(size);
	return;
}

/* private: draw lines */

/* void tpic_abspath(unsigned int x, unsigned int y) /* absolute coord */
void tpic_abspath(x,y)
unsigned int x; unsigned int y; /* absolute coord */
{
	fprintf(outfile, "\\put(%u,%u){", x, y); /* start putting */
	tpic_path(0, 0);
	fprintf(outfile, "}%%\n"); /* end putting */
	return;
}

/* private: tpic primitive functions */

/* void tpic_path(int x, int y) */
void tpic_path(x,y)
int x; int y;
{
	fprintf(outfile, "\\special{pa %d %d}", x, y);
	return;
}

/* void tpic_flush(void) */
void tpic_flush()
{
	fprintf(outfile, "\\special{fp}%%\n");
	return;
}

/* void tpic_arc(int radius) /* actually, draw a full circle */
void tpic_arc(radius)
int radius; /* actually, draw a full circle */
{
	fprintf(outfile, "\\special{ar 0 0 %d %d 0 7}", radius, radius);
	return;
}

/* void tpic_shade(double grayscale) */
void tpic_shade(grayscale)
double grayscale;
{
	fprintf(outfile, "\\special{sh %f}", grayscale);
	return;
}

/* void tpic_pen(int thickness) */
void tpic_pen(thickness)
int thickness;
{
	fprintf(outfile, "\\special{pn %d}", thickness);
	return;
}

/* void tpic_dottedflush(double interval) */
void tpic_dottedflush(interval)
double interval;
{
	fprintf(outfile, "\\special{dt %f}%%\n", interval);
	return;
}

/* void tpic_dashedflush(double interval) */
void tpic_dashedflush(interval)
double interval;
{
	fprintf(outfile, "\\special{da %f}%%\n", interval);
	return;
}
