DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T g

⟦5f910e65f⟧ TextFile

    Length: 20302 (0x4f4e)
    Types: TextFile
    Names: »genlatex.c«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦63303ae94⟧ »unix3.14/TeX3.14.tar.Z« 
        └─⟦c58930e5c⟧ 
            └─⟦this⟧ »TeX3.14/TeXgraphics/transfig/fig2dev/dev/genlatex.c« 

TextFile

/* 
 *	genlatex.c : LaTeX driver for fig2dev
 *
 *	Author: Frank Schmuck, Cornell University 6/88
 * 	Converted from fig2latex 5/89 by Micah Beck
 *
*/
#if defined(hpux) || defined(SYSV)
#include <sys/types.h>
#endif
#include <sys/file.h>
#include <stdio.h>
#include <math.h>
#include "object.h"
#include "fig2dev.h"
#include "texfonts.h"

extern double rad2deg, sin(), cos(), acos(), fabs(), atan();
extern void unpsfont();

#define rint(a) floor((a)+0.5)     /* close enough? */

/* 
 *  Installation dependent constants:
 *
 *  THINDOT	latex command for generating a dot if line width = \thinlines
 *  THICKDOT	latex command for generating a dot if line width = \thicklines
 *  MIN_LEN	shortest slanted line that latex can produce; shorter lines will
 *		we translated into a sequence of dots generated by \multiput.
 *  THICK_LDOT	latex command for generating the dot for making short slanted
 *		lines if line width = \thinlines
 *  THIN_LDOT	...  if line width = \thicklines
 */
#define THICKDOT	"\\tenrm ."
#define THINDOT		"\\sevrm ."
double	THIN_XOFF =	(0.1/72.0);
double	THIN_YOFF =	(0.7/72.0);
double	THICK_XOFF =	(0.4/72.0);
double	THICK_YOFF =	(0.6/72.0);
#define THICK_LDOT	"\\sevrm ."
#define THIN_LDOT	"\\fivrm ."
double	THIN_LXOFF =	(0.1/72.0);
double	THIN_LYOFF =	(0.7/72.0);
double	THICK_LXOFF =	(0.4/72.0);
double	THICK_LYOFF =	(0.6/72.0);
#define MIN_LEN		(13.0/72.0)	/* 13  points */

/*
 *  other constants and macros
 */
#define TOP		840
#define THINLINES	1
#define THICKLINES	2

#define MAXCIRCLEDIA	80
#define MAXCIRCLERAD	((MAXCIRCLEDIA-0.5)/(2*72.27))

#define	SWAP(x,y)	{tmp=x; x=y; y=tmp;}
#define TRANS(x,y)		(*translate_coordinates)(&x,&y)
#define TRANS2(x1,y1,x2,y2)	(*translate_coordinates)(&x1,&y1); \
				(*translate_coordinates)(&x2,&y2)
#define TRANSD(x,y)		(*translate_coordinates_d)(&x,&y)
#define	MIN(x,y)	(((x) <= (y))? (x): (y))
#define	MAX(x,y)	(((x) >= (y))? (x): (y))
#define	ABS(x)		(((x) >= 0)? (x): -(x))
#define round4(x)	((round(10000.0*(x))/10000.0))

char		thindot [] = THINDOT;
char		thickdot[] = THICKDOT;
char		thin_ldot [] = THIN_LDOT;
char		thick_ldot[] = THICK_LDOT;

int		coord_system;
int		verbose = 0;
double		dash_mag = 1.0;
int		thick_width = 1;
double		tolerance = 2.0;
double		arc_tolerance = 1.0;
int		(*translate_coordinates)() = NULL;
int		(*translate_coordinates_d)() = NULL;
double		unitlength;
int		cur_thickness = -1;
double		ldot_diameter = 1.0/72.0;
char		*dot_cmd = thindot;
char		*ldot_cmd = thin_ldot;
double		dot_xoffset;
double		dot_yoffset;
double		ldot_xoffset;
double		ldot_yoffset;

static translate1(xp, yp)
int	*xp, *yp;
{
	*xp = *xp + 1;
	*yp = *yp + 1;
	}

static translate2(xp, yp)
int	*xp, *yp;
{
	*xp = *xp + 1;
	*yp = TOP - *yp -1;
	}

static translate1_d(xp, yp)
double	*xp, *yp;
{
	*xp = *xp + 1.0;
	*yp = *yp + 1.0;
	}

static translate2_d(xp, yp)
double	*xp, *yp;
{
	*xp = *xp + 1.0;
	*yp = (double)TOP - *yp -1.0;
	}

void genlatex_option(opt, optarg)
char opt, *optarg;
{
    switch (opt) {
	case 'f':		/* set default text font */
	{   int i;

	    for ( i = 1; i <= MAX_FONT + 1; i++ )
		if ( !strcmp(optarg, texfontnames[i]) ) break;

	    if ( i > MAX_FONT + 1 )
		fprintf(stderr,
			"warning: non-standard font name %s\n", optarg);
	}
		
	    texfontnames[0] = texfontnames[1] = optarg;
	    break;

	case 'l':		/* set thin/thick line threshold */
	    thick_width = atoi(optarg);
	    break;

	case 'd':
	    dash_mag = atof(optarg);	/* set dash magnification */
	    break;

	case 'v':
	    verbose = 1;		/* verbose mode */
	    break;

	case 's':
	    if (font_size <= 0 || font_size > MAXFONTSIZE) {
		fprintf(stderr,
			"warning: font size %d out of bounds\n", font_size);
	    }
	    break;

	case 'm':
	case 'L':
	    break;

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

void genlatex_start(objects)
F_compound	*objects;
{
	int tmp;

	texfontsizes[0] = texfontsizes[1] = TEXFONTSIZE(font_size);

	coord_system = objects->nwcorner.y;
 	unitlength = mag/objects->nwcorner.x;

	switch (coord_system) {
	    case 1:
		translate_coordinates = translate1;
		translate_coordinates_d = translate1_d;
		break;
	    case 2:
		translate_coordinates = translate2;
		translate_coordinates_d = translate2_d;
		break;
	    default:
		fprintf(stderr, "Wrong coordinate system; cannot continue\n");
		return;
	    }

	TRANS2(llx, lly, urx, ury);
	if (llx > urx) SWAP(llx, urx)
	if (lly > ury) SWAP(lly, ury)

	/* LaTeX start */
	fprintf(tfp, "\\setlength{\\unitlength}{%.4fin}%%\n",
						round4(unitlength));
	fprintf(tfp, "\\begin{picture}(%d,%d)(%d,%d)\n",
	 				 urx-llx, ury-lly, llx, lly);
}

void genlatex_end()
{
	/* LaTeX ending */
	fprintf(tfp, "\\end{picture}\n");
}

static set_linewidth(w)
int	w;
{
	int		latex_w;

	if (w == 0) return;
	/* latex only knows thin lines or thick lines */
	latex_w = (w >= thick_width)? THICKLINES: THINLINES;
	if (latex_w != cur_thickness) {
	    cur_thickness = latex_w;
	    if (cur_thickness == THICKLINES) {
		fprintf(tfp, "\\thicklines\n");
		dot_cmd = thickdot;
		dot_xoffset = round4(THICK_XOFF/unitlength);
		dot_yoffset = round4(THICK_YOFF/unitlength);
		ldot_cmd = thick_ldot;
		ldot_xoffset = round4(THICK_LXOFF/unitlength);
		ldot_yoffset = round4(THICK_LYOFF/unitlength);
		}
	    else {
		fprintf(tfp, "\\thinlines\n");
		dot_cmd = thin_ldot;
		dot_xoffset = round4(THIN_XOFF/unitlength);
		dot_yoffset = round4(THIN_YOFF/unitlength);
		ldot_cmd = thin_ldot;
		ldot_xoffset = round4(THIN_LXOFF/unitlength);
		ldot_yoffset = round4(THIN_LYOFF/unitlength);
		}
	    }
	}

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

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

	set_linewidth(l->thickness);

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

	if (q == NULL) { /* A single point line */
	    x = p->x; y = p->y;
	    TRANS(x, y);
	    fprintf(tfp, "\\put(%3d,%3d){\\makebox(%.4f,%.4f){%s}}\n",
	      x, y, dot_xoffset, dot_yoffset, dot_cmd);
	    return;
	    }

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

	if (l->type == T_BOX) { /* A box */
	    x = p->x; y = p->y;
	    TRANS(x, y);
	    llx = urx = x;
	    lly = ury = y;
	    while (q != NULL) {
		x = q->x; y = q->y;
		TRANS(x, 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->style, l->style_val);
	    return;
	    }

	while (q != NULL) {
	    arrow = 0;
	    if (l->for_arrow  &&  q->next == NULL)
		arrow = 1;
	    if (l->back_arrow  &&  p == l->points)
		arrow = (arrow)? 2: -1;
	    single_line(p->x, p->y, q->x, q->y, arrow, l->style, l->style_val);
	    p = q;
	    q = q->next;
	    }

	if (l->area_fill && (int)l->area_fill != DEFAULT)
		fprintf(stderr, "Line area fill not implemented\n");
	}

static single_line (x1, y1, x2, y2, arrow, style, val)
int	x1, y1, x2, y2, arrow, style;
double	val;
{
	int    dx, dy, sx, sy;
	double l, m, deviation;

	TRANS2(x1, y1, x2, y2);
	dx = x2-x1;
	dy = y2-y1;
	/*** compute direction vector ***/
	get_slope(dx, dy, &sx, &sy, arrow);
	/*** compute line length in x-direction ***/
	if (sx == 0) {
	    l = (double)abs(dy);
	} else {
	    m = (double)abs(sy) / (double)abs(sx);
	    l = ((double)abs(dx) + m*(double)abs(dy)) / (1.0 + m*m);
	    deviation = fabs(l-abs(dx)) + fabs(m*l-abs(dy));
	    if (deviation > tolerance)
		fprintf(stderr,
		  "Not a LaTeX slope (%d, %d), deviation %.1f pixels\n",
		  dx, dy, deviation);
	}
	l = round4(l);
	/*** output letex command ***/
	switch (style) {
	    case SOLID_LINE:
		put_solidline(x1, y1, sx, sy, l, arrow);
		break;
	    case DASH_LINE:
		put_dashline(x1, y1, sx, sy, l, arrow, val);
		break;
	    case DOTTED_LINE:
		put_dotline(x1, y1, sx, sy, l, arrow, val);
		break;
	    }
	}


/*
 * draw box
 */
static put_box (llx, lly, urx, ury, style, val)
int	llx, lly, urx, ury, style;
double	val;
{
	int	dlen;

	switch (style) {
	    case SOLID_LINE:
		fprintf(tfp, "\\put(%3d,%3d){\\framebox(%d,%d){}}\n",
		  llx, lly, urx-llx, ury-lly);
		break;
	    case DASH_LINE:
		dlen = round(val*dash_mag);
		fprintf(tfp, "\\put(%3d,%3d){\\dashbox{%d}(%d,%d){}}\n",
		  llx, lly, dlen, urx-llx, ury-lly);
		break;
	    case DOTTED_LINE:
		put_dotline (llx, lly, 1, 0, (double)(urx-llx), 0, val);
		put_dotline (llx, ury, 1, 0, (double)(urx-llx), 0, val);
		put_dotline (llx, lly, 0, 1, (double)(ury-lly), 0, val);
		put_dotline (urx, lly, 0, 1, (double)(ury-lly), 0, val);
		break;
	    }
	return;
	}

/*
 * draw a solid line given latex slope
 */
static put_solidline (x, y, sx, sy, l, arrow)
int	x, y, sx, sy, arrow;
double	l;
{
	double	cosine;		/* cosine of line angle */
	double	dx, dy;
	int	x2, y2, n;

	if (sx) {
	    cosine = (double)abs(sx) / hypot((double)sx, (double)sy);
	    x2 = (sx >= 0)? x + round(l): x - round(l);
	    y2 = y + round( ((sx>=0)? l: -l) * (double)sy / (double)sx);
	    }
	else {
	    cosine = 1.0;
	    x2 = x;
	    y2 = (sy >= 0)? y + round(l): y - round(l);
	    }
	if (sx == 0  ||  sy == 0  ||  (l/cosine)*unitlength >= MIN_LEN) {
	    switch (arrow) {
	    case 0:  /* simple line */
		fprintf(tfp, "\\put(%3d,%3d){\\line(%2d,%2d)", x, y, sx,sy);
		break;
	    case 1:  /* forward arrow */
		fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d)", x, y, sx,sy);
		break;
	    case -1: /* backward arrow */
		fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d)", x2, y2, -sx,-sy);
		break;
	    case 2:  /* double arrow */
		fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){  0}}\n", x,y,-sx,-sy);
		fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d)", x, y, sx, sy);
		break;
		}
	    if (l == floor(l))
		fprintf(tfp, "{%3.0f}}\n", l);
	    else
		fprintf(tfp, "{%7.3f}}\n", l);
	    }
	else {
	    n = 2 * (l/cosine) / (ldot_diameter/unitlength);
	    fprintf(stderr, "Line too short; will do %d dots\n", n);
	    dx = l / (double)n;
	    if (sx < 0) dx = -dx;
	    dy = dx * (double)sy / (double)sx;
	    fprintf(tfp, 
	      "\\multiput(%3d,%3d)(%.5f,%.5f){%d}{\\makebox(%.4f,%.4f){%s}}\n",
	      x, y, dx, dy, n+1, ldot_xoffset, ldot_yoffset, ldot_cmd);
	    if (arrow == 1  ||  arrow == 2)  /* forward arrow */
		fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x2,y2, sx,sy);
	    if (arrow == -1  ||  arrow == 2) /* backward arrow */
		fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x,y, -sx,-sy);
	    }
	}

/*
 * draw a dashed line given latex slope
 */
static put_dashline (x, y, sx, sy, l, arrow, val)
int	x, y, sx, sy, arrow;
double	l;
double	val;
{
	double	cosine;		/* cosine of line angle */
	double	nd;		/* number of dashes and gaps fitting on line */
	int	n;		/* nd rounded to the nearest odd integer */
	double	dl;		/* actual x-length of each dash */
	double	dg;		/* actual x-length of each gap */
	double	dx, dy;		/* step between dashes */
	int	x2, y2;

	fprintf(stderr, "put_dashline (%d, %d, %d, %d, %f, %d, %f)\n",
		x, y, sx, sy, l, arrow, val);

	if (sx) {
	    cosine = (double)abs(sx) / hypot((double)sx, (double)sy);
	    x2 = (sx >= 0)? x + round(l): x - round(l);
	    y2 = y + round( ((sx>=0)? l: -l) * (double)sy / (double)sx );
	    }
	else {
	    cosine = 1.0;
	    x2 = x;
	    y2 = (sy >= 0)? y + round(l): y - round(l);
	    }
	/*** compute number of dashes, length of dashes and gaps ***/
	nd = l / (val*dash_mag*cosine);
	n = (int) (rint((nd + 1.0)/2.0)*2 - 1);
	dl = l / (double)n;
	if (sx  &&  sy  &&  (dl/cosine)*unitlength < MIN_LEN) {
	    fprintf(stderr, "Dash too small; using larger dash\n");
	    dl = MIN_LEN/unitlength * cosine;
	    nd = l / dl;
	    n = (int) (rint((nd + 1.0)/2.0)*2 - 1);
	    }
	if (2*dl >= l  ||  (sx  &&  sy  &&  (l/cosine)*unitlength < MIN_LEN)) {
	    fprintf(stderr, "Dashed line too short; drawing solid line\n");
	    put_solidline (x, y, sx, sy, l, arrow);
	    return;
	    }
	dg = (l - (n/2+1)*dl) / (double)(n/2);
	if (sx) {
	    dx = dl+dg;
	    if (sx < 0) dx = -dx;
	    dy = dx * (double)sy / (double)sx;
	    }
	else {
	    dx = 0.0;
	    dy = dl+dg;
	    if (sy < 0) dy = -dy;
	    }
	/*** draw dashed line ***/
	fprintf(tfp, "\\multiput(%3d,%3d)(%.5f,%.5f){%d}{\\line(%2d,%2d){%7.3f}}\n",
	    x, y, dx, dy, n/2+1, sx, sy, dl);
	/*** draw arrow heads ***/
	if (arrow == 1  ||  arrow == 2)
	    fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x2, y2, sx, sy);
	if (arrow == -1  ||  arrow == 2)
	    fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x, y, -sx, -sy);
	}

/*
 * draw a dotted line given latex slope
 */
static put_dotline (x, y, sx, sy, l, arrow, val)
int	x, y, sx, sy, arrow;
double	l;
double	val;
{
	double	cosine;		/* cosine of line angle */
	double	nd;		/* number of dots fitting on line */
	int	n;		/* nd rounded to the nearest integer */
	double	dx, dy;		/* step between dashes */
	int	x2, y2;


	cosine = (sx)? (double)abs(sx) / hypot((double)sx, (double)sy): 1.0;
	/*** compute step width ***/
	nd = l / (3*val*cosine);
	n = rint(nd);
	dx = l / (double)n;
	if (sx) {
	    dx = l / (double)n;
	    if (sx < 0) dx = -dx;
	    dy = dx * (double)sy / (double)sx;
	    }
	else {
	    dx = 0.0;
	    dy = l / (double)n;
	    if (sy < 0) dy = -dy;
	    }
	/*** draw arrow heads ***/
	if (arrow == 1  ||  arrow == 2) {
	    /* forward arrow */
	    if (sx) {
		x2 = (sx >= 0)? x + round(l): x - round(l);
		y2 = y + round( ((sx>=0)? l: -l) * (double)sy / (double)sx );
		}
	    else {
		x2 = x;
		y2 = (sy >= 0)? y + round(l): y - round(l);
		}
	    fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x2, y2, sx, sy);
	    n--;
	    }
	if (arrow == -1  ||  arrow == 2) {
	    fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x, y, -sx, -sy);
	    x = round(x + dx);
	    y = round(y + dy);
	    n--;
	    }
	/*** draw dotted line ***/
	fprintf(tfp, "\\multiput(%3d,%3d)(%.5f,%.5f){%d}{\\makebox(%.4f,%.4f){%s}}\n",
	    x, y, dx, dy, n+1, dot_xoffset, dot_yoffset, dot_cmd);
	}

void genlatex_spline(s)
F_spline	*s;
{
	fprintf(stderr, "Can't generate spline; omitting object\n");
	}

void genlatex_ellipse(e)
F_ellipse	*e;
{
	int  x, y, d, dx, dy;

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

	set_linewidth(e->thickness);
	switch (e->style) {
	    case SOLID_LINE:
		break;
	    case DASH_LINE:
		fprintf(stderr, "Dashed circles and elipses not supported\n");
		break;
	    case DOTTED_LINE:
		fprintf(stderr, "Dotted circles and elipses not supported\n");
		break;
	    }

	x = e->center.x;
	y = e->center.y;
	TRANS(x, y);
	if ((e->type == T_CIRCLE_BY_RAD || e->type == T_CIRCLE_BY_DIA)
			&& e->radiuses.x*unitlength <= MAXCIRCLERAD) {

	    d = 2 * e->radiuses.x;
	    if (e->area_fill == BLACK_FILL)
	    	fprintf(tfp, "\\put(%3d,%3d){\\circle*{%d}}\n", x, y, d);
	    else {
	      	fprintf(tfp, "\\put(%3d,%3d){\\circle{%d}}\n", x, y, d);
		if (e->area_fill && (int)e->area_fill != DEFAULT)
			fprintf(stderr, "Circle area fill not implemented\n");
	    }

	} else {	    
	    dx = 2 * e->radiuses.x;
	    dy = 2 * e->radiuses.y;
	    fprintf(tfp, "\\put(%3d,%3d){\\oval(%d,%d)}\n", x, y, dx, dy);
	    if (e->area_fill && (int)e->area_fill != DEFAULT)
		fprintf(stderr, "Ellipse area fill not implemented\n");
	}
      }

void genlatex_text(t)
F_text	*t;
{
	int   	x, y;
	char	*tpos, *cp;

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

	x = t->base_x;
	y = t->base_y;
	TRANS(x, y);

	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");
	    }

	/* raisebox is used to position text at baseline */
	unpsfont(t);
	fprintf(tfp, 
	  "\\put(%3d,%3d){\\makebox(0,0)%s{\\raisebox{0pt}[0pt][0pt]",
	  x, y, tpos);
	fprintf(tfp, "{\\%s%s ", TEXFONTMAG(t), TEXFONT(t->font));

	if (!special_text(t))

		/* this loop escapes characters "$&%#_{}" */
		/* and deleted characters "~^\" */
		for(cp = 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 
		fprintf(tfp, "%s", t->cstring);

 	fprintf(tfp, "}}}\n");
	}

void genlatex_arc(a)
F_arc	*a;
/*
 *  Approximates an arc by a sequence of quarter ovals.
 *
 *  Example:
 *
 *	Arc with center at (0,0) and radius 10 from +45 degree to +225 degree
 *	(arc from p1 = (7.07, 7.07) to p2 = (-7.07, -7.07) counterclockwise).
 *	This arc is approximated by three quarter ovals, one for each quadrant
 *	through which the arc goes:
 *
 *	 1. quarter oval from p1 to the intersection of arc and y-axis,
 *	    i.e., from (7.07, 7.07) to (0, 10) in quadrant 0
 *
 *		\put(0, 7.07){\oval(14.14, 5.86)[tr]}
 *
 *	 2. quarter oval from intersection arc/y-axis to intersection arc/x-axis
 *	    i.e., from (0, 10) to (-10, 0) in quadrant 1
 *
 *		\put(0, 0){\oval(20,20)[tl]}
 *
 *	 3. quarter oval from p1 to the intersection of arc and y-axis,
 *	    i.e., from (-10, 0) to (-7.07, -7.07) in quadrant 2
 *
 *		\put(-7.07, 0){\oval(5.86, 14.14)[bl]}
 */
{
	F_pos		p1, p2, pq[4];
	double		cx, cy;
	double		v1x, v1y, v2x, v2y;
	double		r, angle1, angle2;
	int		q1, q2;
	int		p1_arrow, p2_arrow;
	static char	*ad1[4] = { " 0,-1", " 1, 0", " 0, 1", "-1, 0" };
	static char	*ad2[4] = { "-1, 0", " 0,-1", " 1, 0", " 0, 1" };

	set_linewidth(a->thickness);
	switch (a->style) {
	    case SOLID_LINE:
		break;
	    case DASH_LINE:
		fprintf(stderr, "Dashed arcs not supported\n");
		break;
	    case DOTTED_LINE:
		fprintf(stderr, "Dotted arcs not supported\n");
		break;
	    }
	if (a->direction == 1) {
	    p1 = a->point[0];
	    p2 = a->point[2];
	    p1_arrow = (a->back_arrow != NULL);
	    p2_arrow = (a->for_arrow != NULL);
	    }
	else {
	    p1 = a->point[2];
	    p2 = a->point[0];
	    p1_arrow = (a->for_arrow != NULL);
	    p2_arrow = (a->back_arrow != NULL);
	    }
	cx = a->center.x;
	cy = a->center.y;
	TRANS2(p1.x, p1.y, p2.x, p2.y);
	TRANSD(cx, cy);
	/*** compute vectors and angles from arc center to p1, p2 ***/
	v1x = (double)p1.x - cx;
	v1y = (double)p1.y - cy;
	v2x = (double)p2.x - cx;
	v2y = (double)p2.y - cy;
	angle1 = atan2(v1y, v1x) * rad2deg;
	angle2 = atan2(v2y, v2x) * rad2deg;
	if (angle1 < 0.0)
	    angle1 += 360.0; 
	if (angle2 < 0.0)
	    angle2 += 360.0; 
	/* compute arc radius */
	r = hypot(v1x, v1y);
	/*** compute intersection of arc with x and y axis (origin at cx, cy) */
	pq[0].x = round(cx);
	pq[0].y = round(cy + r);
	pq[1].x = round(cx - r);
	pq[1].y = round(cy);
	pq[2].x = round(cx);
	pq[2].y = round(cy - r);
	pq[3].x = round(cx + r);
	pq[3].y = round(cy);
	/*** compute in which quadrants p1 and p2 are located ***/
	q1 = (int)(angle1/90.0);
	q2 = (int)(angle2/90.0);
	if (fabs(angle1 - 90.0*q1) > arc_tolerance 
	 || fabs(angle2 - 90.0*q2) > arc_tolerance)
	    fprintf(stderr, "Approximating arc by ovals\n");
	/*** Draw arc ***/
	if (p1_arrow)
	    fprintf(tfp, "\\put(%3d,%3d){\\vector(%s){0}}\n", p1.x, p1.y, ad1[q1]);
	while (q1 != q2) {
	    put_quarter(p1, pq[q1], q1);
	    p1 = pq[q1];
	    q1 = (q1 + 1) % 4;
	    }
	put_quarter(p1, p2, q1);
	if (p2_arrow)
	    fprintf(tfp, "\\put(%3d,%3d){\\vector(%s){0}}\n", p2.x, p2.y, ad2[q2]);

	if (a->area_fill && (int)a->area_fill != DEFAULT)
		fprintf(stderr, "Arc area fill not implemented\n");
	}

static put_quarter(p1, p2, q)
F_pos	p1, p2;
int	q;
/*
 *  Draw quarter oval from p1 to p2 in quadrant q
 */
{
	char	*opt;
	int	px, py, dx, dy;

	dx = 2*ABS(p1.x - p2.x);
	dy = 2*ABS(p1.y - p2.y);
	if (dx == 0  &&  dy == 0)
	    return;
	switch (q) {
	    case 0:
		px = MIN(p1.x, p2.x);
		py = MIN(p1.y, p2.y);
		opt = "tr";
		break;
	    case 1:
		px = MAX(p1.x, p2.x);
		py = MIN(p1.y, p2.y);
		opt = "tl";
		break;
	    case 2:
		px = MAX(p1.x, p2.x);
		py = MAX(p1.y, p2.y);
		opt = "bl";
		break;
	    case 3:
		px = MIN(p1.x, p2.x);
		py = MAX(p1.y, p2.y);
		opt = "br";
		break;
	    }
	fprintf(tfp, "\\put(%3d,%3d){\\oval(%3d,%3d)[%s]}\n", px, py, dx, dy, opt);
	}

struct driver dev_latex = {
     	genlatex_option,
	genlatex_start,
	genlatex_arc,
	genlatex_ellipse,
	genlatex_line,
	genlatex_spline,
	genlatex_text,
	genlatex_end,
	EXCLUDE_TEXT
};