/*
 *	Copyright (c) 1992, Mats Bergstr"om.
 *	All Rights Reserved.
 *	See 'TGIFCRTL.license' for complete information.
 *
 *	TGIFCRTL - Run Time Library in C to create TGIF object files.
 *
 *	Author:	Mats Bergst"om, University of Lund, Sweden.
 *			(Mats.Bergstrom@kosufy.lu.se)
 *
 */

/*	If indetation looks bad, try 4 column tabs! */

#define __TGIFCRTL_C__
#ifndef __TGIFCRTL_H__
#include "TGIFCRTL.h"
#endif /* __TGIFCRTL_H__ */
#undef  __TGIFCRTL_C__

#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 *	Default arrow head size look up tables.
 */
static TRbp_t TRdefault_arrow_w[LIW_MAX] = { 6, 8, 10, 12, 14, 18, 20, 22 };
static TRbp_t TRdefault_arrow_h[LIW_MAX] = { 1, 3,  4,  5,  6,  7,  8,  9 }; 

/*
 *	Colour name lookup tables.
 */
static char *TRcolour_names[FIC_MAX] = {
	"magenta",	"red",		"green",	"blue",		"yellow",		"pink",
	"cyan", 	"CadetBlue","white", 	"black", 	"DarkSlateGray"
};


/*
 *	Point-size to text_size/text_dpi conversion tables.
 */
/*					   Point size:   8,10,11,12,14x,14,17,18,20,24,25,34	*/
static TRbp_t TRtext_size[TXP_MAX] = { 0, 1, 0, 2, 1,  3, 2, 4, 3, 5, 4, 5 };
static TRbp_t TRtext_dpi[TXP_MAX] =  { 0, 0, 1, 0, 1,  0, 1, 0, 1, 0, 1, 1 };




/*
 *			Internal functions.
 */


void
TR0whdr( TR_FILE *tp )
{
	fprintf(tp->fp,"%%%s Ver:%s\n", TR_NAME, TR_VER );
	fprintf(tp->fp,
"state(0,27,100,0,0,1,16,1,9,1,1,0,0,0,0,1,0,1,0,4,0,0,1,5,0,0,1,1,0,16,0).\n"
			);
}

void
TR0set_mark (TRmark0_t *tp,
				TRbp_t m_t, TRbp_t m_s)
{
	if ( m_t < MKT_MAX ) tp->type	= m_t;
	if ( m_s < MKS_MAX ) tp->size	= m_s;
}


void
TR0set_line (TRline_t  *tp,
				TRbp_t l_w, TRbp_t l_s, TRbp_t l_t)
{
	if ( l_w >= LIW_MIN
	&&   l_w < LIW_MAX ) tp->width = l_w;
	if ( l_s < LIS_MAX ) tp->style = l_s;
	if ( l_t < LIT_MAX ) tp->type  = l_t;
}


void
TR0set_fill (TRfill_t  *tp,
				TRbp_t f_c, TRbp_t f_p, TRbp_t f_l)
{
	if ( f_c < FIC_MAX ) tp->colour	= f_c;
	if ( f_p < FIP_MAX ) tp->pat	= f_p;
	if ( f_l < FIP_MAX ) tp->pen	= f_l;
}


void
TR0set_arrow(TRarrow_t *tp,
				TRbp_t a_t, TRbp_t a_s, TRbp_t a_w, TRbp_t a_h)
{
	if ( a_t < ART_MAX ) tp->type   = a_t;
	if ( a_s < ARS_MAX ) tp->state  = a_s;
	if ( a_w < ARW_MAX ) tp->width  = a_w;
	if ( a_h < ARH_MAX ) tp->height = a_h;
}


void
TR0set_text (TRtext0_t *tp,
				TRbp_t t_f, TRbp_t t_s, TRbp_t t_a, TRbp_t t_p, TRbp_t t_r )
{
	if ( t_f < TXF_MAX ) tp->font	= t_f;
	if ( t_s < TXS_MAX ) tp->style	= t_s;
	if ( t_a < TXA_MAX ) tp->align	= t_a;
	if ( t_p < TXP_MAX ) tp->points	= t_p;
	if ( t_r < TXR_MAX ) tp->rot	= t_r;
	tp->space	= 0;							/* NOT USED.				*/
	tp->asc		= 1;							/* NOT USED.				*/
	tp->des		= 1;							/* NOT USED.				*/
}



void
TR0switch( int *a, int *b )
{
	int c; c = *a; *a = *b; *b = c;
}

int
TR0lines(char *s)
{
	int rv = 1;
	if (!s) return 0;

	for (;*s;s++) {
		if (*s < ' ') {
			rv++;
			(*s) = '\n';
		};
	};
	return rv;
}


void
TR0term( TR_FILE *tp )
{
	if ( (tp->is_first)++ ) {
		if ( tp->glevel > 0 )	{	fprintf(tp->fp, ",\n");		}
		else					{	fprintf(tp->fp, ".\n");		};
	};
}



void
TR0mcircle( TR_FILE *tp, double x0, double y0	)
{
	TRpc_t iulx, iuly, ilrx, ilry;

	TR0term(tp);

	iulx = TRhtrans(tp,x0);
	iuly = TRvtrans(tp,y0);

	ilrx = iulx + tp->gs.mark.mark.size;
	ilry = iuly + tp->gs.mark.mark.size;
	iulx = iulx - tp->gs.mark.mark.size;
	iuly = iuly - tp->gs.mark.mark.size;

	if ( iulx > ilrx ) TR0switch( &iulx, &ilrx );
	if ( iuly > ilry ) TR0switch( &iuly, &ilry );

	fprintf ( tp->fp,
		"oval('%1s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n])",
				TRcolour_names[tp->gs.mark.fill.colour],
				iulx,iuly,ilrx,ilry,
				tp->gs.mark.fill.pat,
				tp->gs.mark.line.width,
				tp->gs.mark.fill.pen,
				(tp->id)++,
				tp->gs.mark.line.style,
				tp->gs.rot.rot,
				tp->gs.lock.state);
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;
}


void
TR0mbox( TR_FILE *tp, double x0, double y0	)
{
	int iulx, iuly, ilrx, ilry;

	TR0term(tp);

	iulx = TRhtrans(tp,x0);
	iuly = TRvtrans(tp,y0);

	ilrx = iulx + tp->gs.mark.mark.size;
	ilry = iuly + tp->gs.mark.mark.size;
	iulx = iulx - tp->gs.mark.mark.size;
	iuly = iuly - tp->gs.mark.mark.size;

	if ( iulx > ilrx ) TR0switch( &iulx, &ilrx );
	if ( iuly > ilry ) TR0switch( &iuly, &ilry );

	fprintf ( tp->fp,
		"box('%1s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n])",
				TRcolour_names[tp->gs.mark.fill.colour],
				iulx,iuly,ilrx,ilry,
				tp->gs.mark.fill.pat,
				tp->gs.mark.line.width,
				tp->gs.mark.fill.pen,
				(tp->id)++,
				tp->gs.mark.line.style,
				tp->gs.rot.rot,
				tp->gs.lock.state);
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;
}



/*
 *				Exported functions.
 */

TR_FILE *
TRopen (char *fnam)
{
	TR_FILE *rv;
	rv = (TR_FILE *) malloc ( sizeof(TR_FILE) );
	if (rv) {
		rv->fp = fopen ( fnam, "w" );
		if (rv->fp) {
			rv->err = 0;						/* No errors				*/
			rv->id = 0;
			rv->is_first = 0;
			rv->glevel = 0;						/* Group level.				*/
			TR0whdr(rv);						/* Write header.			*/
			TRset_default(rv);					/* Set default values		*/
		} else {
			free ( rv );
			rv = 0;
		};
	};
	return rv;
}

void
TRclose ( TR_FILE *tp )
{
	while ( tp->glevel ) TRgroup_end(tp);
	TR0term(tp);
	(void) fclose ( tp->fp );
	free ( tp );
}


int
TRerr( TR_FILE *tp )
{
	return tp->err;
}


void
TRset_default( TR_FILE *tp )
{
	TRset_htrans(tp,0.0,1.0,0.0,1.0);
	TRset_vtrans(tp,0.0,1.0,0.0,1.0);

	TRset_lock(tp);

	TRset_open_line (tp, LIW_MIN, LIS_SOLID, LIT_STRAIGHT );
	TRset_open_fill (tp, FIC_BLACK, FIP_NONE, FIP_SOLID );
	TRset_open_arrow(tp, ART_PLAIN, ARS_DEFAULT, 8, 3 );

	TRset_closed_line(tp, LIW_MIN, LIS_SOLID, LIT_STRAIGHT );
	TRset_closed_fill(tp, FIC_BLACK, FIP_SHADE5, FIP_SOLID );
	TRset_closed_rc  (tp, RCR_DEFAULT );

	TRset_text_text(tp, TXF_TIMES, TXS_ROMAN, TXA_LEFT, TXP_18, TXR_0 );
	TRset_text_fill(tp, FIC_BLACK, FIP_NONE, FIP_SOLID );

	TRset_mark_mark (tp, MKT_CIRCLE, 4 );
	TRset_mark_line (tp, LIW_MIN, LIS_SOLID, LIT_STRAIGHT );
	TRset_mark_fill (tp, FIC_BLACK, FIP_BACKGR, FIP_SOLID );
	TRset_mark_arrow(tp, ART_PLAIN, ARS_DEFAULT, 8, 3 );
	TRset_mark_text (tp, TXF_TIMES, TXS_ROMAN, TXA_CENTER, TXP_8, TXR_0 );

	tp->gs.rot.rot			= 0;				/* NOT USED					*/
}


void
TRset_htrans (TR_FILE *tp, double pmin, double pmax, double cmin, double cmax)
{
	tp->gs.trans.h1 = TR_DOTS_PER_MM * (pmin - pmax)/(cmin - cmax);
	tp->gs.trans.h0 = pmin * TR_DOTS_PER_MM  - tp->gs.trans.h1 * cmin;
	fprintf(tp->fp,
		"%%Transform H: %g, %g\n",
			tp->gs.trans.h0,tp->gs.trans.h1);
}

void
TRset_vtrans (TR_FILE *tp, double pmin, double pmax, double cmin, double cmax)
{
	tp->gs.trans.v1 = TR_DOTS_PER_MM * (pmin - pmax)/(cmin - cmax);
	tp->gs.trans.v0 = pmin * TR_DOTS_PER_MM - tp->gs.trans.v1 * cmin;
	fprintf(tp->fp,
		"%%Transform V: %g, %g\n",
			tp->gs.trans.v0,tp->gs.trans.v1);
}


void
TRset_lock( TR_FILE *tp )
{
	tp->gs.lock.state = LCK_LOCKED;
}

void
TRset_unlock( TR_FILE *tp )
{
	tp->gs.lock.state = LCK_UNLOCKED;
	if ( tp->glevel == 0) tp->glock.state = LCK_UNLOCKED;
}



void
TRset_open_line(TR_FILE *tp,			/* Set graphic state for open shapes*/
				TRbp_t	l_w,				/*  1 Line width				*/
				TRbp_t	l_s,				/*  2 Line style				*/
				TRbp_t	l_t)				/*  3 Line type					*/
{
	TR0set_line (&(tp->gs.open.line),l_w,l_s,l_t);
}

void
TRset_open_fill(TR_FILE *tp,			/* Set graphic state for open shapes*/
				TRbp_t	f_c,				/*  4 Fill colour				*/
				TRbp_t	f_p,				/*  5 Fill pattern				*/
				TRbp_t	f_l)				/*  6 Fill line-pattern			*/
{
	TR0set_fill (&(tp->gs.open.fill),f_c,f_p,f_l);
}

void
TRset_open_arrow(TR_FILE *tp,			/* Set graphic state for open shapes*/
				TRbp_t	a_t,				/*  7 Arrow type				*/
				TRbp_t	a_s,				/*  8 Arrow style				*/
				TRbp_t	a_w,				/*  9 Arrow width				*/
				TRbp_t	a_h )				/* 10 Arrow height				*/
{
	TR0set_arrow(&(tp->gs.open.arrow),a_t,a_s,a_w,a_h);
}





void
TRset_closed_line(TR_FILE *tp,			/* Set graphic state for closedshapes*/
				TRbp_t	l_w,				/*  1 Line width				*/
				TRbp_t	l_s,				/*  2 Line style				*/
				TRbp_t	l_t)				/*  3 Line type					*/
{
	TR0set_line (&(tp->gs.closed.line),l_w,l_s,l_t);
}

void
TRset_closed_fill(TR_FILE *tp,			/* Set graphic state for closedshapes*/
				TRbp_t	f_c,				/*  4 Fill colour				*/
				TRbp_t	f_p,				/*  5 Fill pattern				*/
				TRbp_t	f_l)				/*  6 Fill line-pattern			*/
{
	TR0set_fill (&(tp->gs.closed.fill),f_c,f_p,f_l);
}

void
TRset_closed_rc(TR_FILE *tp,			/* Set graphic state for closedshapes*/
				TRbp_t	c_r )				/*  7 RC Box corner radius		*/
{
	if ( c_r != IGNORE ) {
		if 		( c_r < RCR_MIN ) { c_r = RCR_MIN; }
		else if ( c_r > RCR_MAX ) { c_r = RCR_MAX; };
		tp->gs.closed.rc.radius = c_r;
	};
}




void
TRset_text_text(TR_FILE *tp,			/* Set graphic state for text.		*/
				TRbp_t	t_f,				/*  1 Text font					*/
				TRbp_t	t_s,				/*  2 Text Style				*/
				TRbp_t	t_a,				/*  3 Text Alignment			*/
				TRbp_t	t_p,				/*  4 Text Point Size			*/
				TRbp_t	t_r)				/*  5 Text Rotation.			*/
{
	TR0set_text (&(tp->gs.text.text),t_f,t_s,t_a,t_p,t_r );
}

void
TRset_text_fill(TR_FILE *tp,			/* Set graphic state for text.		*/
				TRbp_t	f_c,				/*  6 Fill colour				*/
				TRbp_t	f_p,				/*  7 Fill pattern				*/
				TRbp_t	f_l)				/*  8 Fill line-pattern			*/
{
	TR0set_fill (&(tp->gs.text.fill),f_c,f_p,f_l);
}




void
TRset_mark_mark(TR_FILE *tp,			/* Set Graphic state for Markers.	*/
				TRbp_t	m_t,				/*  1 Marker Type				*/
				TRbp_t	m_s)				/*  2 Marker Size				*/
{
	TR0set_mark (&(tp->gs.mark.mark),m_t,m_s);
}

void
TRset_mark_line(TR_FILE *tp,			/* Set graphic state for mark shapes*/
				TRbp_t	l_w,				/*  3 Line width				*/
				TRbp_t	l_s,				/*  4 Line style				*/
				TRbp_t	l_t)				/*  5 Line type					*/
{
	TR0set_line (&(tp->gs.mark.line),l_w,l_s,l_t);
}

void
TRset_mark_fill(TR_FILE *tp,			/* Set graphic state for mark shapes*/
				TRbp_t	f_c,				/*  6 Fill colour				*/
				TRbp_t	f_p,				/*  7 Fill pattern				*/
				TRbp_t	f_l)				/*  8 Fill line-pattern			*/
{
	TR0set_fill (&(tp->gs.mark.fill),f_c,f_p,f_l);
}

void
TRset_mark_arrow(TR_FILE *tp,			/* Set graphic state for mark shapes*/
				TRbp_t	a_t,				/*  9 Arrow type				*/
				TRbp_t	a_s,				/* 10 Arrow style				*/
				TRbp_t	a_w,				/* 11 Arrow width				*/
				TRbp_t	a_h )				/* 12 Arrow height				*/
{
	TR0set_arrow(&(tp->gs.mark.arrow),a_t,a_s,a_w,a_h);
}

void
TRset_mark_text(TR_FILE *tp,			/* Set graphic state for mark.		*/
				TRbp_t	t_f,				/* 13 Text font					*/
				TRbp_t	t_s,				/* 14 Text Style				*/
				TRbp_t	t_a,				/* 15 Text Alignment			*/
				TRbp_t	t_p,				/* 16 Text Point Size			*/
				TRbp_t	t_r)				/* 17 Text Rotation.			*/
{
	TR0set_text (&(tp->gs.mark.text),t_f,t_s,t_a,t_p,t_r );
}




void
TRpush(TR_FILE *tp)
{
 	struct TRdata_s *gs;
	gs = (struct TRdata_s *) malloc ( sizeof(struct TRdata_s) );
	if (gs) {
		tp->gsdepth++;

		(void) memcpy ( gs, &(tp->gs), sizeof( struct TRdata_s ) );

		tp->gs.next = gs;
	};
}

void
TRpop(TR_FILE *tp)
{
 	struct TRdata_s *gs;
	
	if (tp->gsdepth) {
		tp->gsdepth--;
		gs = tp->gs.next;
		(void) memcpy ( &(tp->gs), gs, sizeof( struct TRdata_s ) );
		free (gs);
	};
}


void
TRpolyline(	TR_FILE *tp, int n, double x[], double y[] )
{
	int  ix, iy, i, count;
	TRbp_t ahw, ahh;

	if ( n < 2 ) return;

	TR0term(tp);

	fprintf( tp->fp,
		"poly('%1s',%1d,[\n\t",
			TRcolour_names[tp->gs.open.fill.colour],
			n);

	for (i = 0, count = 0; i<n-1; i++) {
		ix = TRhtrans(tp,x[i]);
		iy = TRvtrans(tp,y[i]);
		fprintf(tp->fp, "%1d,%1d,", ix, iy );
		if ( ++count == 8 ) {
			count = 0;
			fprintf( tp->fp, "\n\t" );
		};
	};
	i = n-1;
	ix = TRhtrans(tp,x[i]);
	iy = TRvtrans(tp,y[i]);
	fprintf( tp->fp, "%1d,%1d]", ix, iy);

	switch ( tp->gs.open.arrow.state ) {
		default:
		case ARS_DEFAULT:
			ahw = TRdefault_arrow_w[tp->gs.open.line.width];
			ahh = TRdefault_arrow_h[tp->gs.open.line.width];
			break;

		case ARS_EXPLICIT:
			ahw = tp->gs.open.arrow.width;
			ahh = tp->gs.open.arrow.height;
			break;

		case ARS_SCALE:
			ahw = (tp->gs.open.arrow.width)  * (tp->gs.open.line.width);
			ahh = (tp->gs.open.arrow.height) * (tp->gs.open.line.width);
			break;
	};

	fprintf( tp->fp,
		",%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n])",
			tp->gs.open.arrow.type,
			tp->gs.open.line.width,
			tp->gs.open.fill.pen,
			(tp->id)++,
			tp->gs.open.line.type,
			tp->gs.open.fill.pat,
			tp->gs.open.line.style,
			tp->gs.rot.rot,
			ahw,
			ahh,
			tp->gs.lock.state );
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;
}


void
TRoval(	TR_FILE *tp, double x0, double y0, double x1, double y1 )
{
	int iulx, iuly, ilrx, ilry;

	TR0term(tp);

	iulx = TRhtrans(tp,x0);
	iuly = TRvtrans(tp,y0);
	ilrx = TRhtrans(tp,x1);
	ilry = TRvtrans(tp,y1);

	if ( iulx > ilrx ) TR0switch( &iulx, &ilrx );
	if ( iuly > ilry ) TR0switch( &iuly, &ilry );

	fprintf ( tp->fp,
		"oval('%1s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n])",
				TRcolour_names[tp->gs.closed.fill.colour],
				iulx,iuly,ilrx,ilry,
				tp->gs.closed.fill.pat,
				tp->gs.closed.line.width,
				tp->gs.closed.fill.pen,
				(tp->id)++,
				tp->gs.closed.line.style,
				tp->gs.rot.rot,
				tp->gs.lock.state);
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;
}



void
TRbox ( TR_FILE *tp, double x0, double y0, double x1, double y1 )
{
	int iulx, iuly, ilrx, ilry;

	TR0term(tp);

	iulx = TRhtrans(tp,x0);
	iuly = TRvtrans(tp,y0);
	ilrx = TRhtrans(tp,x1);
	ilry = TRvtrans(tp,y1);

	if ( iulx > ilrx ) TR0switch( &iulx, &ilrx );
	if ( iuly > ilry ) TR0switch( &iuly, &ilry );

	fprintf ( tp->fp,
		"box('%1s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n])",
				TRcolour_names[tp->gs.closed.fill.colour],
				iulx,iuly,ilrx,ilry,
				tp->gs.closed.fill.pat,
				tp->gs.closed.line.width,
				tp->gs.closed.fill.pen,
				(tp->id)++,
				tp->gs.closed.line.style,
				tp->gs.rot.rot,
				tp->gs.lock.state);
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;
}


void
TRrcbox ( TR_FILE *tp, double x0, double y0, double x1, double y1 )
{
	int iulx, iuly, ilrx, ilry;

	TR0term(tp);

	iulx = TRhtrans(tp,x0);
	iuly = TRvtrans(tp,y0);
	ilrx = TRhtrans(tp,x1);
	ilry = TRvtrans(tp,y1);

	if ( iulx > ilrx ) TR0switch( &iulx, &ilrx );
	if ( iuly > ilry ) TR0switch( &iuly, &ilry );

	fprintf ( tp->fp,
		"rcbox('%1s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n])",
				TRcolour_names[tp->gs.closed.fill.colour],
				iulx,iuly,ilrx,ilry,
				tp->gs.closed.fill.pat,
				tp->gs.closed.line.width,
				tp->gs.closed.fill.pen,
				tp->gs.closed.line.style,
				tp->gs.closed.rc.radius,
				(tp->id)++,
				tp->gs.rot.rot,
				tp->gs.lock.state );
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;
}


void
TRpolygon ( TR_FILE *tp, int n, double x[], double y[] )
{
	int ix, iy, i, count;

	if ( n < 2 ) return;

	TR0term(tp);

	fprintf( tp->fp,
		"polygon('%1s',%1d,[\n\t",
			TRcolour_names[tp->gs.closed.fill.colour],
			n+1 );
	for (i = 0, count = 0; i<n; i++) {
		ix = TRhtrans(tp,x[i]);
		iy = TRvtrans(tp,y[i]);
		fprintf(tp->fp,
			"%1d,%1d,",
				ix, iy );
		if ( ++count == 8 ) {
			count = 0;
			fprintf( tp->fp, "\n\t" );
		};
	};
	i = 0;
	ix = TRhtrans(tp,x[i]);
	iy = TRvtrans(tp,y[i]);
	fprintf( tp->fp,
		"%1d,%1d]",
			ix, iy);

	fprintf( tp->fp,
		",%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n])",
			tp->gs.closed.fill.pat,
			tp->gs.closed.line.width,
			tp->gs.closed.fill.pen,
			tp->gs.closed.line.type,
			(tp->id)++,
			tp->gs.closed.line.style,
			tp->gs.rot.rot,
			tp->gs.lock.state );
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;
}



void
TRtext( TR_FILE *tp, double x, double y, char *s )
{
	int ix, iy, l;

	l = TR0lines(s);				/* find out no of lines.	*/
	if (!l) return;
	TR0term(tp);

	ix = TRhtrans(tp,x);
	iy = TRvtrans(tp,y);

	fprintf( tp->fp,
"text('%1s',%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,[\n",
			TRcolour_names[tp->gs.text.fill.colour],
			ix,iy,
			tp->gs.text.text.font,
			tp->gs.text.text.style,
			TRtext_size[tp->gs.text.text.points],
			l,
			tp->gs.text.text.align,
			tp->gs.text.text.rot,
			tp->gs.text.fill.pen,
			50,50,				/* Let TGIF fid out the BBox ... ;-) */
			(tp->id)++,
			TRtext_dpi[tp->gs.text.text.points],
			tp->gs.text.text.asc,
			tp->gs.text.text.des,
			tp->gs.text.fill.pat,
			tp->gs.text.text.space,
			tp->gs.rot.rot,
			tp->gs.lock.state	);
	if ( tp->gs.lock.state == LCK_LOCKED && tp->glevel > 0)
		tp->glock.state = LCK_LOCKED;

	fprintf( tp->fp, "\t\"" );
	for (; *s; s++) {
		if ( *s == '\\' ) {
			fprintf( tp->fp, "\\\\" );
		} else if ( *s == '"' ) {
			fprintf( tp->fp, "\\\"" );
		} else if ( (*s) & 0x80 ) {
			fprintf( tp->fp, "\\%o", (*s)&(0xff) );
		} else if ( *s == '\n' ) {
			fprintf( tp->fp, "\",\n\t\"" );
		} else {
			putc( *s, tp->fp );
		};
	};
	fprintf( tp->fp, "\"])" );
}


void
TRgroup_begin( TR_FILE *tp )
{
	TR0term(tp);

	fprintf( tp->fp, "group([\n" );
	tp->glevel++;
	tp->is_first = 0;
}

void
TRgroup_end( TR_FILE *tp )
{
	if ( tp->glevel > 0 ) {
		fprintf( tp->fp,
			"\n],\n%1d,%1d,[\n])",
				(tp->id)++,
				tp->glock.state	);
		tp->glevel--;
		if (tp->glevel == 0) tp->glock.state = tp->gs.lock.state;
	};
}


/*
 * Specials: line.
 */

void
TRline( TR_FILE *tp, double x0, double y0, double x1, double y1 )
{
	static double x[2];
	static double y[2];

	x[0] = x0; x[1] = x1;
	y[0] = y0; y[1] = y1;
	TRpolyline( tp, 2, x, y );
}


void
TRmark( TR_FILE *tp, double x0, double y0	)
{
	switch ( tp->gs.mark.mark.type ) {
		case MKT_CIRCLE:	TR0mcircle(tp,x0,y0);
							break;

		case MKT_BOX:		TR0mbox(tp,x0,y0);
							break;

		default:		break;
	};
}

void
TRpolymark(	TR_FILE *tp, int n, double x[], double y[] )
{
	int i;
	if (n < 1) return;
	TRgroup_begin(tp);
	for (i=0; i<n; i++) {
		TRmark(tp,x[i],y[i]);
	};
	TRgroup_end(tp);
}



TRpc_t
TRhtrans(TR_FILE *tp, double uc)
{
	TRpc_t rv;
	rv = tp->gs.trans.h0 + tp->gs.trans.h1 * uc;
	if (rv < 0) rv = 0;
	if (rv > TR_PAPER_WIDTH) rv = TR_PAPER_WIDTH;
	return rv;
}

TRpc_t
TRvtrans(TR_FILE *tp, double uc)
{
	TRpc_t rv;
	rv = tp->gs.trans.v0 + tp->gs.trans.v1 * uc;
	if (rv < 0) rv = 0;
	if (rv > TR_PAPER_HEIGHT) rv = TR_PAPER_HEIGHT;
	return rv;
}


double
TRhmm(TR_FILE *tp, double x	)
{
	return (x / tp->gs.trans.h1 / TR_DOTS_PER_MM);
}

double
TRvmm(TR_FILE *tp, double x	)
{
	return (x / tp->gs.trans.v1 / TR_DOTS_PER_MM);
}


double
TRhdot(TR_FILE *tp, double x	)
{
	return (x / tp->gs.trans.h1);
}

double
TRvdot(TR_FILE *tp, double x	)
{
	return (x / tp->gs.trans.v1);
}

#ifdef __cplusplus
}
#endif
