/*
 * TransFig: Facility for Translating Fig code
 * Copyright (c) 1991 by Micah Beck
 * Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
 * Parts Copyright (c) 1989-2002 by Brian V. Smith
 *
 * Any party obtaining a copy of these files is granted, free of charge, a
 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
 * nonexclusive right and license to deal in this software and
 * documentation files (the "Software"), including without limitation the
 * rights to use, copy, modify, merge, publish and/or distribute copies of
 * the Software, and to permit persons who receive copies from any such
 * party to do so, with the only requirement being that this copyright
 * notice remain intact.
 *
 */

/*
 *	genpictex.C : PiCTeX driver for fig2dev
 *
 *	Author Micah Beck, Cornell University, 4/88
 *    Color, rotated text and ISO-chars added by Herbert Bauer 11/91
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "bool.h"
#include "pi.h"
#ifdef HAVE_GETPWUID
#include <pwd.h>
#endif

#include "fig2dev.h"
#include "object.h"	/* does #include <X11/xpm.h> */
#include "genlatex.h"
#include "setfigfont.h"
#include "texfonts.h"
#include "localmath.h"
#include "creationdate.h"

#define UNIT "cm"	/* dip */
#define CONVUNIT 2.54	/* dip */

extern char	*ISO1toTeX[];
extern char	*ISO2toTeX[];
extern bool	 FontSizeOnly;	/* defined in setfigfont.c */

static void	genpictex_ctl_spline(), genpictex_itp_spline();
static void	bezier_spline();
static void	put_box();
static void	set_style();
static void	putline();
static void	rtop();
static void	draw_arrow_head();
static void	set_linewidth();

static int	encoding = 1;
static double	dash_length = -1;
static int	line_style = SOLID_LINE;
static char	*linethick = "1pt";
static char	*plotsymbol = "\\makebox(0,0)[l]{\\tencirc\\symbol{'160}}";
static int	cur_thickness = -1;
static bool	anonymous = true;
static bool	rotate = true;

static void
genpictex_option(char opt, char *optarg)
{
	int i;

	FontSizeOnly = false;
	switch (opt) {

		case 'a':			/* anonymous (don't output user name) */
		    anonymous = true;
		    break;

		case 'f':			/* set default text font */
		    for ( i = 1; i <= MAX_FONT; i++ )
			if ( !strcmp(optarg, texfontnames[i]) ) break;

	    if ( i > MAX_FONT)
			{
			  fprintf(stderr,
						 "warning: non-standard font name %s ignored\n", optarg);
			}
		 else
			{
			  texfontnames[0] = texfontnames[i];
#ifdef NFSS
			  texfontfamily[0] = texfontfamily[i];
			  texfontseries[0] = texfontseries[i];
			  texfontshape[0] = texfontshape[i];
#endif
			}
		    break;

		case 'l':			/* set line thickness */
		    linethick = optarg;
		    break;

		case 'p':			/* set plot symbol */
		    plotsymbol = optarg;
		    break;

		case 'r':			/* do not use dvips */
		    rotate = false;
		    break;

		case 'E':
		    encoding = atoi(optarg);
		    if (encoding < 0 || encoding > 2)
		      encoding = 1;
		    break;

		case 'G':
		case 'L':
		    break;

	default:
		put_msg(Err_badarg, opt, "pictex");
		exit(1);
	}
}

#define		TOP	10.5	/* top of page is 10.5 inch */

static double
convy(double a)
{
	return((double) TOP-a);
}

void
genpictex_start(F_compound *objects)
{
	char		host[256];
	struct passwd	*who;
	char		date_buf[CREATION_TIME_LEN];

	texfontsizes[0] = texfontsizes[1] =
		TEXFONTSIZE(font_size != 0.0? font_size : DEFAULT_FONT_SIZE);

	/* PiCTeX start */

	/* announce filename, version etc */

	fprintf(tfp, "%%Title: %s\n",
		(name? name: ((from) ? from : "stdin")));
	fprintf(tfp, "%%%%Created by: %s Version %s\n",
		prog, PACKAGE_VERSION);
	if (creation_date(date_buf))
	    fprintf(tfp, "%%%%CreationDate: %s\n", date_buf);
#ifdef HAVE_GETHOSTNAME
	if (gethostname(host, sizeof(host)) == -1)
#endif
	    (void)strcpy(host, "unknown-host!?!?");
#ifdef HAVE_GETPWUID
	if ( !anonymous) {
	    who = getpwuid(getuid());
	    if (who)
		fprintf(tfp, "%%%%User: %s@%s (%s)\n",
			who->pw_name, host, who->pw_gecos);
	}
#endif

	/* print any whole-figure comments prefixed with "% " */
	if (objects->comments) {
	    fprintf(tfp,"%%\n");
	    print_comments("% ",objects->comments, "");
	    fprintf(tfp,"%%\n");
	}
	fprintf(tfp, "\\font\\thinlinefont=cmr5\n");
	define_setfigfont(tfp);
	fprintf(tfp, "\\mbox{\\beginpicture\n");
	fprintf(tfp, "\\setcoordinatesystem units <%6.5f%s,%6.5f%s>\n",
			mag, UNIT, mag, UNIT);
	fprintf(tfp, "\\unitlength=%6.5f%s\n", mag, UNIT);
	fprintf(tfp, "\\linethickness=%s\n", linethick);
	fprintf(tfp, "\\setplotsymbol ({%s})\n", plotsymbol);
	fprintf(tfp, "\\setshadesymbol ({\\thinlinefont .})\n");
	fprintf(tfp, "\\setlinear\n");
}

int
genpictex_end(void)
{
	/* PiCTeX ending */
	fprintf(tfp, "\\linethickness=0pt\n");
	fprintf(tfp, "\\putrectangle corners at %6.3f %6.3f and %6.3f %6.3f\n",
		(llx/ppi)*CONVUNIT, (convy(lly/ppi))*CONVUNIT,
		(urx/ppi)*CONVUNIT, (convy(ury/ppi))*CONVUNIT);
	fprintf(tfp, "\\endpicture}\n");

	/* all ok */
	return 0;
}

static void
set_linewidth(int w)
{

	    if (!w) {
		fprintf(tfp, "\\linethickness=0pt\n");
		cur_thickness = 0;
		}
	    else {
		cur_thickness = round(w*mag*80/ppi);

		if (!cur_thickness || cur_thickness == 1) {
		    cur_thickness = 1;
		    fprintf(tfp, "\\linethickness=%6.3fpt\n", 0.5*cur_thickness);
		    }
		else {
		    fprintf(tfp, "\\linethickness=%dpt\n", cur_thickness-1);
		    }
		}
	    switch (cur_thickness) {
		case 0:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n", "\\thinlinefont \\ ");
		    break;
		case 1:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n", "\\thinlinefont .");
		    break;
		case 2:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'160}}");
		    break;
		case 3:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'161}}");
		    break;
		case 4:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'162}}");
		    break;
		case 5:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'163}}");
		    break;
		case 6:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'164}}");
		    break;
		case 7:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'165}}");
		    break;
		case 8:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'166}}");
		    break;
		case 9:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'167}}");
		    break;
		case 10:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'170}}");
		    break;
		case 11:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'171}}");
		    break;
		case 12:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'172}}");
		    break;
		case 13:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'173}}");
		    break;
		case 14:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'174}}");
		    break;
		case 15:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'175}}");
		    break;
		case 16:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'176}}");
		    break;
		default:
		    fprintf(tfp, "\\setplotsymbol ({%s})\n",
				"\\makebox(0,0)[l]{\\tencirc\\symbol{'176}}");
		    break;
	    }
}

void
genpictex_line(F_line *l)
{
	F_point		*p, *q;
	int		x, y, llx, lly, urx, ury;

	/* print any comments */
	print_comments("% ",l->comments, "");

	fprintf(tfp, "%%\n%% Fig POLYLINE object\n%%\n");

	if (l->type == T_ARC_BOX) { /* A box with rounded corners */
	  fprintf(stderr, "Arc box not implemented; substituting box.\n");
	  l->type = T_BOX;
	}

	set_linewidth(l->thickness);
	set_style(l->style, l->style_val);
	set_color(l->pen_color);

	p = l->points;
	q = p->next;

	if (q == NULL) { /* A single point line */
	    fprintf(tfp, "\\plot %6.3f %6.3f %6.3f %6.3f /\n",
			(p->x/ppi)*CONVUNIT, (convy(p->y/ppi))*CONVUNIT,
			(p->x/ppi)*CONVUNIT, (convy(p->y/ppi))*CONVUNIT);
	    return;
	    }

	if (l->type == T_BOX || l->type == T_ARC_BOX) /* A (rounded corner) box */
	{
	    x = p->x; y=p->y;
	    llx =urx = x;
	    lly =ury = y;
	    while ( q!= NULL )
	    {
		x = q->x; y=q->y;
		if (x < llx) llx = x;
		if (y < lly) lly = y;
		if (x > urx) urx = x;
		if (y > ury) ury = y;
		q = q->next;
	    }
	    put_box (llx, lly, urx, ury, l);
	    return;
	}

	if (l->back_arrow)
	    draw_arrow_head(q->x/ppi, convy(q->y/ppi), p->x/ppi,
		convy(p->y/ppi), l->back_arrow->ht/ppi, l->back_arrow->wid/ppi);
	set_style(l->style, l->style_val);

	while (q->next != NULL) {

	    putline(p->x, p->y, (double) q->x, (double) q->y,
		    (q->next)->x, (q->next)->y, -1, -1, -1, -1);
	    p = q;
	    q = q->next;
	    }

	putline(p->x, p->y, (double) q->x, (double) q->y, -1, -1,
		l->points->x, l->points->y,
		l->points->next->x,l->points->next->y);
	if (l->for_arrow)
	    draw_arrow_head(p->x/ppi, convy(p->y/ppi), q->x/ppi,
		convy(q->y/ppi), l->for_arrow->ht/ppi, l->for_arrow->wid/ppi);

	if (l->fill_style != UNFILLED)
		fprintf(stderr, "Line area fill not implemented\n");
	reset_color(l->pen_color);
	}


/*
 * draw box
 */
static void
put_box(int llx, int lly, int urx, int ury, F_line *l)
{
	int radius;

	set_color(l->pen_color);
	if (l->type == T_BOX)
	{
	   if (l->fill_style == BLACK_FILL)
	   {
	       fprintf(tfp,"\\linethickness=%6.3f%s\n",
		    ((convy(lly/ppi))-(convy(ury/ppi)))*CONVUNIT*mag, UNIT);
	       fprintf(tfp,"{\\setsolid");
	       fprintf(tfp,"\\putrule from %6.3f %6.3f to %6.3f %6.3f }%%\n",
		    (llx/ppi)*CONVUNIT,
		    ((convy(lly/ppi)+convy(ury/ppi))/2)*CONVUNIT,
		    (urx/ppi)*CONVUNIT,
		    ((convy(lly/ppi)+convy(ury/ppi))/2)*CONVUNIT);
	       fprintf(tfp,"\\linethickness=%dpt\n", l->thickness);
	   }
	   else if (l->fill_style > BLACK_FILL*3/4)
	   {
	       fprintf(tfp,"\\setshadegrid span <1pt>\n");
	       fprintf(tfp,"\\shaderectangleson\n");
	   }
	   else if (l->fill_style > BLACK_FILL*2/4)
	   {
	       fprintf(tfp,"\\setshadegrid span <2pt>\n");
	       fprintf(tfp,"\\shaderectangleson\n");
	   }
	   else if (l->fill_style > BLACK_FILL*1/4)
	   {
	       fprintf(tfp,"\\setshadegrid span <4pt>\n");
	       fprintf(tfp,"\\shaderectangleson\n");
	   }
	   else if (l->fill_style == WHITE_FILL)
	   {
	       fprintf(stderr,"WHITE_FILL not implemented for boxes\n");
	   }

	   fprintf(tfp,"\\putrectangle corners at %6.3f %6.3f and %6.3f %6.3f\n",
		(llx/ppi)*CONVUNIT, (convy(lly/ppi))*CONVUNIT,
		(urx/ppi)*CONVUNIT, (convy(ury/ppi))*CONVUNIT);

	   if (l->fill_style != UNFILLED
		&& l->fill_style != WHITE_FILL && l->fill_style != BLACK_FILL)
	   {
	       fprintf(tfp,"\\setshadegrid span <5pt>\n");
	       fprintf(tfp,"\\shaderectanglesoff\n");
	   }
	}
	else if (l->type == T_ARC_BOX)
	{
	   radius = l->radius;

	   if (l->fill_style != UNFILLED)
	   {
	       fprintf(stderr,"area fill not implemented for rounded corner boxes\n");
	   }

	   fprintf(tfp,"\\putrule from %6.3f %6.3f to %6.3f %6.3f\n",
		   ((llx+radius)/ppi)*CONVUNIT, (convy(lly/ppi))*CONVUNIT,
		   ((urx-radius)/ppi)*CONVUNIT, (convy(lly/ppi))*CONVUNIT);
	   fprintf(tfp,"\\putrule from %6.3f %6.3f to %6.3f %6.3f\n",
		   (urx/ppi)*CONVUNIT, (convy((lly+radius)/ppi))*CONVUNIT,
		   (urx/ppi)*CONVUNIT, (convy((ury-radius)/ppi))*CONVUNIT);
	   fprintf(tfp,"\\putrule from %6.3f %6.3f to %6.3f %6.3f\n",
		   ((urx-radius)/ppi)*CONVUNIT, (convy(ury/ppi))*CONVUNIT,
		   ((llx+radius)/ppi)*CONVUNIT, (convy(ury/ppi))*CONVUNIT);
	   fprintf(tfp,"\\putrule from %6.3f %6.3f to %6.3f %6.3f\n",
		   (llx/ppi)*CONVUNIT, (convy((ury-radius)/ppi))*CONVUNIT,
		   (llx/ppi)*CONVUNIT, (convy((lly+radius)/ppi))*CONVUNIT);
	   fprintf(tfp,"\\circulararc -90 degrees from %6.3f %6.3f center at %6.3f %6.3f\n",
		   ((urx-radius)/ppi)*CONVUNIT, (convy(lly/ppi))*CONVUNIT,
		   ((urx-radius)/ppi)*CONVUNIT, (convy((lly+radius)/ppi))*CONVUNIT);
	   fprintf(tfp,"\\circulararc -90 degrees from %6.3f %6.3f center at %6.3f %6.3f\n",
		   (urx/ppi)*CONVUNIT, (convy((ury-radius)/ppi))*CONVUNIT,
		   ((urx-radius)/ppi)*CONVUNIT, (convy((ury-radius)/ppi))*CONVUNIT);
	   fprintf(tfp,"\\circulararc -90 degrees from %6.3f %6.3f center at %6.3f %6.3f\n",
		   ((llx+radius)/ppi)*CONVUNIT, (convy(ury/ppi))*CONVUNIT,
		   ((llx+radius)/ppi)*CONVUNIT, (convy((ury-radius)/ppi))*CONVUNIT);
	   fprintf(tfp,"\\circulararc -90 degrees from %6.3f %6.3f center at %6.3f %6.3f\n",
		   (llx/ppi)*CONVUNIT, (convy((lly+radius)/ppi))*CONVUNIT,
		   ((llx+radius)/ppi)*CONVUNIT, (convy((lly+radius)/ppi))*CONVUNIT);
	}
	reset_color(l->pen_color);
}


/*
 * set_style - issue style commands as appropriate
 */
static void
set_style(int style, double dash_len)
{
    switch (style) {
	 case SOLID_LINE:
	    if (line_style == SOLID_LINE) break;
	    fprintf(tfp, "\\setsolid\n");
	    break;

	case DASH_LINE:
	    if (line_style == DASH_LINE && dash_length == dash_len)
		break;
	    fprintf(tfp, "\\setdashes <%7.4f%s>\n", (0.5*dash_len*(cur_thickness+1)/80.0)*CONVUNIT, UNIT);
	    break;

	case DOTTED_LINE:
	    if (line_style == DOTTED_LINE)
		break;
	    fprintf(tfp, "\\setdots <%7.4f%s>\n", (0.5*dash_len*(cur_thickness+1)/80.0)*CONVUNIT, UNIT);
	    break;
	    }

	line_style = style;
	dash_length = dash_len;
    }

/*
 * putline - use rules if possible
 */
static void
putline(int start_x, int start_y, double end_x, double end_y,
		int next_x, int next_y, int first_start_x, int first_start_y,
		int first_end_x, int first_end_y)
{
    if (line_style == SOLID_LINE &&
	    ((start_x == end_x) || (start_y == end_y))) {
	if (next_x != -1) {
	    if (start_x == end_x && end_y == next_y) {
		if (end_y > start_y)
		    end_y += 0.5*ppi*(cur_thickness-1)/72/mag;
		else
		    end_y -= 0.5*ppi*(cur_thickness-1)/72/mag;
		}
	    else if (start_y == end_y && end_x == next_x) {
		if (end_x > start_x)
		    end_x += 0.5*ppi*(cur_thickness-1)/72/mag;
		else
		    end_x -= 0.5*ppi*(cur_thickness-1)/72/mag;
		}
	    }
	else if (end_x == first_start_x && end_y == first_start_y) {
	    if (start_x == end_x && first_start_y == first_end_y) {
		if (end_y > start_y)
		    end_y += 0.5*ppi*(cur_thickness-1)/72/mag;
		else
		    end_y -= 0.5*ppi*(cur_thickness-1)/72/mag;
		}
	    else if (start_y == end_y && first_start_x == first_end_x) {
		if (end_x > start_x)
		    end_x += 0.5*ppi*(cur_thickness-1)/72/mag;
		else
		    end_x -= 0.5*ppi*(cur_thickness-1)/72/mag;
		}
	    }

	fprintf(tfp, "\\putrule from %6.3f %6.3f to %6.3f %6.3f\n",
		(start_x/ppi)*CONVUNIT, (convy(start_y/ppi))*CONVUNIT,
		(end_x/ppi)*CONVUNIT, (convy(end_y/ppi))*CONVUNIT);
	}
    else {
	fprintf(tfp, "\\plot %6.3f %6.3f %6.3f %6.3f /\n",
		(start_x/ppi)*CONVUNIT, (convy(start_y/ppi))*CONVUNIT,
		(end_x/ppi)*CONVUNIT, (convy(end_y/ppi))*CONVUNIT);
	}
}


void
genpictex_spline(F_spline *s)
{
	/* print any comments */
	print_comments("% ",s->comments, "");

	fprintf(tfp, "%%\n%% Fig SPLINE\n%%\n");

	set_linewidth(s->thickness);
	set_style(s->style, s->style_val);
	set_color(s->pen_color);

	if (int_spline(s))
	    genpictex_itp_spline(s);
	else
	    genpictex_ctl_spline(s);

	if (s->fill_style != UNFILLED)
		fprintf(stderr, "Spline area fill not implemented\n");
	reset_color(s->pen_color);
}

#define MAXBLACKDIAM 15 /* pt */

void
genpictex_ellipse(F_ellipse *e)
{
	/* print any comments */
	print_comments("% ",e->comments, "");

	fprintf(tfp, "%%\n%% Fig ELLIPSE\n%%\n");

	set_linewidth(e->thickness);
	set_style(e->style, e->style_val);
	set_color(e->pen_color);

	if ((e->fill_style == BLACK_FILL) && (e->radiuses.x == e->radiuses.y)) {
		if (mag*e->radiuses.x > 0.5*ppi/72*MAXBLACKDIAM)
			fprintf(stderr, "Too big black filled circle substituted by a diameter of %dpt\n", MAXBLACKDIAM);
		fprintf(tfp, "\\put{\\makebox(0,0)[l]{\\circle*{%6.3f}}} at %6.3f %6.3f\n",
		    (2*e->radiuses.x/ppi)*CONVUNIT,
		    ((e->center.x)/ppi)*CONVUNIT, (convy(e->center.y/ppi))*CONVUNIT);

	    }
	else {

		fprintf(tfp, "\\ellipticalarc axes ratio %6.3f:%-6.3f 360 degrees \n",
		    (e->radiuses.x/ppi)*CONVUNIT, (e->radiuses.y/ppi)*CONVUNIT);
		fprintf(tfp, "\tfrom %6.3f %6.3f center at %6.3f %6.3f\n",
		    ((e->center.x+e->radiuses.x)/ppi)*CONVUNIT,
		    (convy(e->center.y/ppi))*CONVUNIT,
		    (e->center.x/ppi)*CONVUNIT, (convy(e->center.y/ppi))*CONVUNIT);
		if (e->fill_style != UNFILLED)
			fprintf(stderr, "Ellipse area fill not implemented\n");
		}
	reset_color(e->pen_color);
	}

#define			HT_OFFSET	(0.2 / 72.0)

void
genpictex_text(F_text *t)
{
	double	x, y;
	char *tpos;
	unsigned char *cp;

	/* print any comments */
	print_comments("% ",t->comments, "");

	fprintf(tfp, "%%\n%% Fig TEXT object\n%%\n");

	x = t->base_x/ppi;
	y = convy(t->base_y/ppi);

	switch (t->type) {

	    case T_LEFT_JUSTIFIED:
	    case DEFAULT:
		tpos = "[lB]";
		break;

	    case T_CENTER_JUSTIFIED:
		tpos = "[B]";
		break;

	    case T_RIGHT_JUSTIFIED:
		tpos = "[rB]";
		break;

	    default:
		fprintf(stderr, "Text incorrectly positioned\n");
		return;
	    }

	unpsfont(t);
	{ int texsize;
	  double baselineskip;

	  texsize = TEXFONTMAG(t);
	  baselineskip = (texsize * 1.2);

#ifdef NFSS
	  fprintf(tfp, "\\put{\\SetFigFontNFSS{%d}{%.1f}{%s}{%s}{%s}",
				 texsize, baselineskip,
				 TEXFAMILY(t->font),TEXSERIES(t->font),TEXSHAPE(t->font));
#else
	  fprintf(tfp, "\\put{\\SetFigFont{%d}{%.1f}{%s}",
		texsize, baselineskip, TEXFONT(t->font));
#endif
	}

	if(rotate && t->angle && t->type == T_LEFT_JUSTIFIED)
	    fprintf(tfp,
		"\\special{ps:gsave currentpoint currentpoint translate\n-%.1f rotate neg exch neg exch translate}",
		t->angle*180/M_PI);

	set_color(t->color);

	if (!special_text(t))

		/* this loop escapes characters "$&%#_{}" */
		/* and deleted characters "~^\" */
		for(cp = (unsigned char*)t->cstring; *cp; cp++) {
		    if (strchr("$&%#_{}", *cp)) (void)fputc('\\', tfp);
		    if (strchr("~^\\", *cp))
			fprintf(stderr,
				"Bad character in text object '%c'\n" ,*cp);
		    else
			(void)fputc(*cp, tfp);
		}
	else
		for(cp = (unsigned char*)t->cstring; *cp; cp++) {
#ifdef I18N
		    extern bool support_i18n;
		    if (support_i18n && (t->font <= 2))
			    fputc(*cp, tfp);
		    else
#endif
		    if (*cp >= 0xa0) {
			switch (encoding) {
			    case 0: /* no escaping */
				fputc(*cp, tfp);
				break;
			    case 1: /* iso-8859-1 */
				fprintf(tfp, "%s", ISO1toTeX[(int)*cp-0xa0]);
				break;
			    case 2: /* iso-8859-2 */
				fprintf(tfp, "%s", ISO2toTeX[(int)*cp-0xa0]);
				break;
			}
		    } else
			fputc(*cp, tfp);
		}

	reset_color(t->color);

	if(rotate && t->angle) {
	    if (t->type == T_LEFT_JUSTIFIED)
		fprintf(tfp, "\\special{ps:currentpoint grestore moveto}");
	    else
		fprintf(stderr, "Rotated Text only for left justified text\n");
	}

	fprintf(tfp, "} %s at %6.3f %6.3f\n",
	    tpos, (x)*CONVUNIT, (y)*CONVUNIT);
}

void
genpictex_arc(F_arc *a)
{
	double		x, y;
	double		cx, cy, sx, sy, ex, ey;
	double		dx1, dy1, dx2, dy2, r1, r2, th1, th2, theta;

	/* print any comments */
	print_comments("% ",a->comments, "");

	fprintf(tfp, "%%\n%% Fig CIRCULAR ARC object\n%%\n");

	set_linewidth(a->thickness);
	set_style(a->style, a->style_val);
	set_color(a->pen_color);

	cx = a->center.x/ppi; cy = convy(a->center.y/ppi);
	sx = a->point[0].x/ppi; sy = convy(a->point[0].y/ppi);
	ex = a->point[2].x/ppi; ey = convy(a->point[2].y/ppi);

	if ((a->type == T_OPEN_ARC) && (a->thickness != 0) && (a->back_arrow || a->for_arrow)) {
	    if (a->for_arrow) {
		arc_tangent(cx, cy, ex, ey, a->direction, &x, &y);
		draw_arrow_head(x, y, ex, ey,
			a->for_arrow->ht/ppi, a->for_arrow->wid/ppi);
	    }
	    if (a->back_arrow) {
		arc_tangent(cx, cy, sx, sy, !a->direction, &x, &y);
		draw_arrow_head(x, y, sx, sy,
			a->back_arrow->ht/ppi, a->back_arrow->wid/ppi);
	    }
	}

	dx1 = sx - cx;
	dy1 = sy - cy;
	dx2 = ex - cx;
	dy2 = ey - cy;

	rtop(dx1, dy1, &r1, &th1);
	rtop(dx2, dy2, &r2, &th2);
	theta = th2 - th1;
	if (theta > 0) theta -= 2*M_PI;

/*	set_linewidth(a->thickness); */

	if (a->direction)
		fprintf(tfp, "\\circulararc %6.3f degrees from %6.3f %6.3f center at %6.3f %6.3f\n",
			360+(180/M_PI * theta),
			(sx)*CONVUNIT, (sy)*CONVUNIT, (cx)*CONVUNIT, (cy)*CONVUNIT);
	else
		fprintf(tfp, "\\circulararc %6.3f degrees from %6.3f %6.3f center at %6.3f %6.3f\n",
			-180/M_PI * theta,
			(ex)*CONVUNIT, (ey)*CONVUNIT, (cx)*CONVUNIT, (cy)*CONVUNIT);

	if (a->fill_style != UNFILLED)
		fprintf(stderr, "Arc area fill not implemented\n");
	reset_color(a->pen_color);
	}



/*
 * rtop - rectangular to polar conversion
 */
static void
rtop(double x, double y, double *r, double *th)
{
	*r = sqrt(x*x+y*y);
	*th = acos(x/(*r));

	if (y < 0) *th = 2*M_PI - *th;
}

/*	draw arrow heading from (x1, y1) to (x2, y2)	*/

static void
draw_arrow_head(double x1, double y1, double x2, double y2,
		double arrowht, double arrowwid)
{
	double	x, y, xb, yb, dx, dy, l, sina, cosa;
	double	xc, yc, xd, yd;
	int style;
	double dash;

	dx = x2 - x1;  dy = y1 - y2;

	if (!dx && !dy)
	    return ;

	l = sqrt(dx*dx+dy*dy);
	if (l == 0) {
	     return;
	}
	else {
	     sina = dy / l;  cosa = dx / l;
	}
	xb = x2*cosa - y2*sina;
	yb = x2*sina + y2*cosa;
	x = xb - arrowht;
	y = yb - arrowwid / 2;
	xc = x*cosa + y*sina;
	yc = -x*sina + y*cosa;
	y = yb + arrowwid / 2;
	xd = x*cosa + y*sina;
	yd = -x*sina + y*cosa;

	/* save line style and set to solid */
	style = line_style;
	dash = dash_length;
	set_style(SOLID_LINE, 0.0);

	fprintf(tfp, "%%\n%% arrow head\n%%\n");

	fprintf(tfp, "\\plot %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f /\n%%\n",
			(xc)*CONVUNIT, (yc)*CONVUNIT,
			(x2)*CONVUNIT, (y2)*CONVUNIT,
			(xd)*CONVUNIT, (yd)*CONVUNIT);

	/* restore line style */
	set_style(style, dash);
	}

#define		THRESHOLD	.05	/* inch */

static void
quadratic_spline(double a1, double b1, double a2, double b2,
		double a3, double b3, double a4, double b4)
{
	double	x1, y1, x4, y4;
	double	xmid, ymid;

	x1 = a1; y1 = b1;
	x4 = a4; y4 = b4;
	xmid = (a2 + a3) / 2;
	ymid = (b2 + b3) / 2;
	if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD)
	    fprintf(tfp, "\t%6.3f %6.3f\n", (xmid)*CONVUNIT, (ymid)*CONVUNIT);

	else {
	    quadratic_spline(x1, y1, ((x1+a2)/2), ((y1+b2)/2),
			((3*a2+a3)/4), ((3*b2+b3)/4), xmid, ymid);
	    }

	if (fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD)
	    fprintf(tfp, "\t%6.3f %6.3f\n", (x4)*CONVUNIT, (y4)*CONVUNIT);

	else {
	    quadratic_spline(xmid, ymid, ((a2+3*a3)/4), ((b2+3*b3)/4),
			((a3+x4)/2), ((b3+y4)/2), x4, y4);
	    }
	}

static void
genpictex_ctl_spline(F_spline *s)
{
	F_point	*p;
	double	cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
	double	x1, y1, x2, y2;

	fprintf(tfp, "%%\n%% Fig CONTROL PT SPLINE\n%%\n");

	p = s->points;
	x1 = p->x/ppi;	y1 = convy(p->y/ppi);
	p = p->next;
	x2 = p->x/ppi;	y2 = convy(p->y/ppi);
	cx1 = (x1 + x2) / 2;	  cy1 = (y1 + y2) / 2;
	cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;

	if (closed_spline(s)) {
	    fprintf(tfp, "%% closed spline\n%%\n");
	    fprintf(tfp, "\\plot\t%6.3f %6.3f \n ", (cx1)*CONVUNIT, (cy1)*CONVUNIT);
	    }
	else {
	    fprintf(tfp, "%% open spline\n%%\n");
	    if (s->back_arrow)
		draw_arrow_head(cx1, cy1, x1, y1,
			s->back_arrow->ht/ppi, s->back_arrow->wid/ppi);
	    fprintf(tfp, "\\plot\t%6.3f %6.3f %6.3f %6.3f\n ",
		(x1)*CONVUNIT, (y1)*CONVUNIT, (cx1)*CONVUNIT, (cy1)*CONVUNIT);
	    }

	for (p = p->next; p != NULL; p = p->next) {
	    x1 = x2;  y1 = y2;
	    x2 = p->x/ppi;  y2 = convy(p->y/ppi);
	    cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
	    cx4 = (x1 + x2) / 2;      cy4 = (y1 + y2) / 2;
	    quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
	    cx1 = cx4;	cy1 = cy4;
	    cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;
	    }
	x1 = x2;  y1 = y2;
	p = s->points->next;
	x2 = p->x/ppi;	y2 = convy(p->y/ppi);
	cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
	cx4 = (x1 + x2) / 2;	  cy4 = (y1 + y2) / 2;
	if (closed_spline(s)) {
	    quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
	    fprintf(tfp, "\t/\n");
	    }
	else {
	    fprintf(tfp, "\t /\n\\plot %6.3f %6.3f %6.3f %6.3f /\n",
		(cx1)*CONVUNIT, (cy1)*CONVUNIT, (x1)*CONVUNIT, (y1)*CONVUNIT);
	    if (s->for_arrow)
		draw_arrow_head(cx1, cy1, x1, y1,
			s->for_arrow->ht/ppi, s->for_arrow->wid/ppi);
	    }

	}

static void
genpictex_itp_spline(F_spline *s)
{
	F_point		*p1, *p2;
	F_control	*cp1, *cp2;
	double		x1, x2, y1, y2;

	fprintf(tfp, "%%\n%% Fig INTERPOLATED PT SPLINE\n%%\n");

	p1 = s->points;
	cp1 = s->controls;
	x2 = p1->x/ppi; y2 = convy(p1->y/ppi);

	if (s->back_arrow)
	    draw_arrow_head(cp1->rx/ppi, convy(cp1->ry/ppi), x2, y2,
		s->back_arrow->ht/ppi, s->back_arrow->wid/ppi);

	fprintf(tfp, "\\plot %6.3f %6.3f ", (x2)*CONVUNIT, (y2)*CONVUNIT);
	for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
		p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
	    x1 = x2; y1 = y2;
	    x2 = p2->x/ppi; y2 = convy(p2->y/ppi);
	    bezier_spline(x1, y1, (double)cp1->rx/ppi, convy(cp1->ry/ppi),
		(double)cp2->lx/ppi, convy(cp2->ly/ppi), x2, y2);
	    }
	fprintf(tfp, "\t/\n");

	if (s->for_arrow)
	    draw_arrow_head(cp1->lx/ppi, convy(cp1->ly/ppi), x2, y2,
		s->for_arrow->ht/ppi, s->for_arrow->wid/ppi);
	}

static void
bezier_spline(double a0, double b0, double a1, double b1, double a2, double b2,
		double a3, double b3)
{
	double	x0, y0, x3, y3;
	double	sx1, sy1, sx2, sy2, tx, ty, tx1, ty1, tx2, ty2, xmid, ymid;

	x0 = a0; y0 = b0;
	x3 = a3; y3 = b3;
	if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD)
	    fprintf(tfp, "\t%6.3f %6.3f\n", (x3)*CONVUNIT, (y3)*CONVUNIT);

	else {
	    tx = (a1 + a2) / 2;		ty = (b1 + b2) / 2;
	    sx1 = (x0 + a1) / 2;	sy1 = (y0 + b1) / 2;
	    sx2 = (sx1 + tx) / 2;	sy2 = (sy1 + ty) / 2;
	    tx2 = (a2 + x3) / 2;	ty2 = (b2 + y3) / 2;
	    tx1 = (tx2 + tx) / 2;	ty1 = (ty2 + ty) / 2;
	    xmid = (sx2 + tx1) / 2;	ymid = (sy2 + ty1) / 2;

	    bezier_spline(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
	    bezier_spline(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
	    }
	}

struct driver dev_pictex = {
	genpictex_option,
	genpictex_start,
	gendev_nogrid,
	genpictex_arc,
	genpictex_ellipse,
	genpictex_line,
	genpictex_spline,
	genpictex_text,
	genpictex_end,
	EXCLUDE_TEXT
};
