Graphics Character Fonts

Doug Gwyn (VLD/VMB) gwyn at Brl-Vld.ARPA
Wed Jan 9 03:01:08 AEST 1985


/*
	symbol -- software character generator subroutine

	last edit:	26-Nov-1984	D A Gwyn


Function:

	This routine plots an ASCII character string as vector strokes.


Calling sequence:

	void symbol(
		     char *string,	// -> NUL-terminated string
		     int llcx,		// X position of text LLC
		     int llcy,		// X position of text LLC
		     int height,	// text height & spacing
		     double theta	// rotation (degrees CCW)
		   );


Calls:

	void move( int x, int y );	// PLOT(3X) move-pen
	void cont( int x, int y );	// PLOT(3X) draw
*/

#include	<math.h>

extern void	cont(), move();


/*
				STROKE TABLES

	The stroke[] table contains encodings for all vector strokes
	needed to draw each character at a standard size.  Actual plot
	output is of course properly positioned, scaled, and rotated.
	To keep code size small, variable-length entries are used; each
	character stroke sequence is terminated by a 0 datum.  Pointers
	to the appropriate data for every character is stored into
	sstroke[] during a one-time initialization.

	The prototypes are constrained to a 4 x 6 unit area, except for
	occasional descenders up to 2 units below the baseline.  All
	visible strokes should be "basic" vectors (in directions that
	are integral multiples of 45 degrees) for best overall results
	on most devices, especially with small character height.  The
	first 16 "control" characters are plotted as non-standard extra
	symbols, the next 16 produce Calcomp "centered plotting symbols"
	(not centered here!), and the final 96 characters are plotted as
	corresponding ASCII graphics (DEL plots as a grid).

	A prototype stroke is encoded as 8 bits SVXXXYYY:
		S	= 0 if YYY is correct as is
			  1 if YYY needs to have 2 subtracted
		V	= 0 if stroke is invisible (move)
			  1 if stroke is visible (draw)
		XXX	= final X coord of stroke (0..4)
		YYY	= final Y coord of stroke (0..6)
*/

/* bit masks for fields in stroke vector */

#define	S	0200
#define	V	0100
#define	XXX	0070
#define	YYY	0007

#define	XJUST	3			/* bits to the right of XXX */

/* stroke vectors for all characters */

static char	stroke[] =
	{
/*NUL*/	0003, 0105, 0123, 0143, 0141, 0121, 0125, 0,
/*SOH*/	0006, 0115, 0112, 0142, 0022, 0121, 0141, 0140, 0120, 0013,
	0133, 0034, 0114, 0015, 0126, 0,
/*STX*/	0021, 0125, 0105, 0103, 0123, 0141, 0143, 0,
/*ETX*/	0012, 0114, 0034, 0104, 0106, 0126, 0124, 0033, 0113, 0021,
	0141, 0042, 0122, 0120, 0,
/*EOT*/	0005, 0125, 0134, 0145, 0143, 0023, 0125, 0015, 0113, 0,
/*ENQ*/	0011, 0131, 0142, 0144, 0135, 0115, 0104, 0102, 0111, 0012,
	0114, 0134, 0133, 0113, 0023, 0132, 0,
/*ACK*/	0011, 0131, 0142, 0144, 0135, 0115, 0104, 0102, 0111, 0034,
	0114, 0112, 0132, 0,
/*BEL*/	0021, 0122, 0142, 0133, 0134, 0124, 0125, 0024, 0114, 0113,
	0102, 0122, 0,
/*BS */	0012, 0103, 0114, 0003, 0143, 0,
/*HT */	0003, 0143, 0034, 0143, 0132, 0,
/*LF */	0012, 0121, 0132, 0021, 0125, 0,
/*VT */	0021, 0125, 0014, 0125, 0134, 0,
/*FF */	0012, 0121, 0132, 0021, 0125, 0014, 0125, 0134, 0,
/*CR */	0012, 0103, 0114, 0003, 0143, 0034, 0143, 0132, 0,
/*SO */	0004, 0124, 0126, 0106, 0104, 0014, 0112, 0142, 0034, 0130, 0,
/*SI */	0021, 0123, 0013, 0115, 0025, 0105, 0003, 0123, 0141, 0143, 0,
/*DLE*/	0023, 0125, 0145, 0141, 0101, 0105, 0125, 0,
/*DC1*/	0023, 0125, 0135, 0144, 0142, 0131, 0111, 0102, 0104, 0115,
	0125, 0,
/*DC2*/	0023, 0124, 0142, 0102, 0124, 0,
/*DC3*/	0021, 0125, 0003, 0143, 0,
/*DC4*/	0001, 0145, 0005, 0141, 0,
/*NAK*/	0023, 0125, 0143, 0121, 0103, 0125, 0,
/*SYN*/	0021, 0125, 0143, 0103, 0125, 0,
/*ETB*/	0001, 0145, 0105, 0141, 0,
/*CAN*/	0005, 0145, 0101, 0141, 0,
/*EM */	0023, 0121, 0005, 0123, 0145, 0,
/*SUB*/	0023, 0145, 0034, 0132, 0141, 0032, 0112, 0101, 0012, 0114,
	0105, 0014, 0134, 0,
/*ESC*/	0001, 0145, 0025, 0121, 0041, 0105, 0003, 0143, 0,
/*FS */	0001, 0141, 0105, 0145, 0101, 0,
/*GS */	0021, 0125, 0,
/*RS */	0023, 0125, 0024, 0142, 0102, 0124, 0021, 0122, 0144, 0104,
	0122, 0,
/*US */	0023, 0143, 0,
/*SP */	0,
/* ! */	0020, 0121, 0022, 0126, 0,
/* " */	0014, 0116, 0036, 0134, 0,
/* # */	0010, 0116, 0036, 0130, 0042, 0102, 0004, 0144, 0,
/* $ */	0002, 0111, 0131, 0142, 0133, 0113, 0104, 0115, 0135, 0144,
	0026, 0120, 0,
/* % */	0001, 0145, 0025, 0114, 0105, 0116, 0125, 0032, 0141, 0130,
	0121, 0132, 0,
/* & */	0040, 0104, 0105, 0116, 0125, 0124, 0102, 0101, 0110, 0120,
	0142, 0,
/* ' */	0014, 0136, 0,
/* ( */	0030, 0112, 0114, 0136, 0,
/* ) */	0010, 0132, 0134, 0116, 0,
/* * */	0001, 0145, 0025, 0121, 0041, 0105, 0,
/* + */	0021, 0125, 0003, 0143, 0,
/* , */	0211, 0120, 0121, 0,
/* - */	0003, 0143, 0,
/* . */	0020, 0121, 0,
/* / */	0001, 0145, 0,
/* 0 */	0001, 0145, 0136, 0116, 0105, 0101, 0110, 0130, 0141, 0145, 0,
/* 1 */	0010, 0130, 0020, 0126, 0115, 0,
/* 2 */	0005, 0116, 0136, 0145, 0144, 0100, 0140, 0,
/* 3 */	0001, 0110, 0130, 0141, 0142, 0133, 0144, 0145, 0136, 0116,
	0105, 0023, 0133, 0,
/* 4 */	0030, 0136, 0024, 0102, 0142, 0,
/* 5 */	0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, 0106, 0146, 0,
/* 6 */	0002, 0113, 0133, 0142, 0141, 0130, 0110, 0101, 0105, 0116,
	0136, 0145, 0,
/* 7 */	0006, 0146, 0145, 0112, 0110, 0,
/* 8 */	0013, 0102, 0101, 0110, 0130, 0141, 0142, 0133, 0113, 0104,
	0105, 0116, 0136, 0145, 0144, 0133, 0,
/* 9 */	0001, 0110, 0130, 0141, 0145, 0136, 0116, 0105, 0104, 0113,
	0133, 0144, 0,
/* : */	0020, 0121, 0023, 0124, 0,
/* ; */	0211, 0120, 0121, 0023, 0124, 0,
/* < */	0030, 0103, 0136, 0,
/* = */	0002, 0142, 0044, 0104, 0,
/* > */	0010, 0143, 0116, 0,
/* ? */	0005, 0116, 0136, 0145, 0144, 0122, 0021, 0120, 0,
/* @ */	0031, 0133, 0124, 0113, 0112, 0121, 0131, 0142, 0144, 0135,
	0115, 0104, 0101, 0110, 0130, 0,
/* A */	0104, 0126, 0144, 0140, 0042, 0102, 0,
/* B */	0130, 0141, 0142, 0133, 0144, 0145, 0136, 0106, 0100, 0003,
	0133, 0,
/* C */	0045, 0136, 0116, 0105, 0101, 0110, 0130, 0141, 0,
/* D */	0130, 0141, 0145, 0136, 0106, 0100, 0,
/* E */	0003, 0133, 0046, 0106, 0100, 0140, 0,
/* F */	0106, 0146, 0033, 0103, 0,
/* G */	0022, 0142, 0141, 0130, 0110, 0101, 0105, 0116, 0136, 0145, 0,
/* H */	0106, 0046, 0140, 0043, 0103, 0,
/* I */	0010, 0130, 0020, 0126, 0016, 0136, 0,
/* J */	0001, 0110, 0130, 0141, 0146, 0,
/* K */	0106, 0046, 0102, 0013, 0140, 0,
/* L */	0006, 0100, 0140, 0,
/* M */	0106, 0124, 0146, 0140, 0,
/* N */	0106, 0005, 0141, 0040, 0146, 0,
/* O */	0010, 0130, 0141, 0145, 0136, 0116, 0105, 0101, 0110, 0,
/* P */	0106, 0136, 0145, 0144, 0133, 0103, 0,
/* Q */	0010, 0130, 0141, 0145, 0136, 0116, 0105, 0101, 0110, 0022,
	0140, 0,
/* R */	0106, 0136, 0145, 0144, 0133, 0103, 0013, 0140, 0,
/* S */	0001, 0110, 0130, 0141, 0142, 0133, 0113, 0104, 0105, 0116,
	0136, 0145, 0,
/* T */	0020, 0126, 0006, 0146, 0,
/* U */	0006, 0101, 0110, 0130, 0141, 0146, 0,
/* V */	0006, 0102, 0120, 0142, 0146, 0,
/* W */	0006, 0100, 0122, 0140, 0146, 0,
/* X */	0101, 0145, 0146, 0006, 0105, 0141, 0140, 0,
/* Y */	0020, 0123, 0105, 0106, 0046, 0145, 0123, 0,
/* Z */	0040, 0100, 0101, 0145, 0146, 0106, 0013, 0133, 0,
/* [ */	0030, 0110, 0116, 0136, 0,
/* \ */	0005, 0141, 0,
/* ] */	0010, 0130, 0136, 0116, 0,
/* ^ */	0004, 0126, 0144, 0,
/* _ */	0201, 0341, 0,
/* ` */	0016, 0134, 0,
/* a */	0003, 0114, 0134, 0143, 0140, 0042, 0112, 0101, 0110, 0130,
	0141, 0,
/* b */	0106, 0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, 0,
/* c */	0043, 0134, 0114, 0103, 0101, 0110, 0130, 0141, 0,
/* d */	0043, 0134, 0114, 0103, 0101, 0110, 0130, 0141, 0040, 0146, 0,
/* e */	0002, 0142, 0143, 0134, 0114, 0103, 0101, 0110, 0130, 0141, 0,
/* f */	0010, 0115, 0126, 0136, 0145, 0034, 0104, 0,
/* g */	0201, 0310, 0330, 0341, 0144, 0041, 0130, 0110, 0101, 0103,
	0114, 0134, 0143, 0,
/* h */	0106, 0003, 0114, 0134, 0143, 0140, 0,
/* i */	0020, 0124, 0114, 0025, 0126, 0,
/* j */	0201, 0310, 0330, 0341, 0144, 0045, 0146, 0,
/* k */	0106, 0044, 0100, 0022, 0140, 0,
/* l */	0020, 0126, 0116, 0,
/* m */	0104, 0003, 0114, 0123, 0120, 0040, 0143, 0134, 0123, 0,
/* n */	0104, 0003, 0114, 0134, 0143, 0140, 0,
/* o */	0010, 0130, 0141, 0143, 0134, 0114, 0103, 0101, 0110, 0,
/* p */	0001, 0110, 0130, 0141, 0143, 0134, 0114, 0103, 0004, 0300, 0,
/* q */	0041, 0130, 0110, 0101, 0103, 0114, 0134, 0143, 0044, 0340, 0,
/* r */	0104, 0003, 0114, 0134, 0143, 0,
/* s */	0001, 0110, 0130, 0141, 0132, 0112, 0103, 0114, 0134, 0143, 0,
/* t */	0004, 0134, 0015, 0111, 0120, 0130, 0141, 0,
/* u */	0004, 0101, 0110, 0130, 0141, 0040, 0144, 0,
/* v */	0004, 0102, 0120, 0142, 0144, 0,
/* w */	0004, 0101, 0110, 0121, 0022, 0121, 0130, 0141, 0144, 0,
/* x */	0144, 0004, 0140, 0,
/* y */	0201, 0310, 0330, 0341, 0144, 0004, 0101, 0110, 0130, 0141, 0,
/* z */	0004, 0144, 0100, 0140, 0,
/* { */	0030, 0121, 0122, 0113, 0124, 0125, 0136, 0,
/* | */	0020, 0126, 0,
/* } */	0010, 0121, 0122, 0133, 0124, 0125, 0116, 0,
/* ~ */	0005, 0116, 0134, 0145, 0,
/*DEL*/	0140, 0146, 0106, 0100, 0010, 0116, 0026, 0120, 0030, 0136, 0
	};

/* pointers to start of stroke data for each character */

static char	*sstroke[128] = { (char *)0 };


/*
				CONSTANTS
*/

#define	STDHT	6.0			/* prototype height */
#define	CHSPAC	6			/* prototype text spacing */

#define	DEGRAD	57.29577951308232087679815481410517033240547246656424
					/* degrees per radian */

#define	ASCMASK	0177			/* 7-bit ASCII mask */
#define	NUL	'\0'			/* string terminator */


/*
				GLOBAL DATA
*/

static double	xorg, yorg;		/* text LLC coordinates */

static double	symcos, symsin;		/* transformation coeffs */


/*
				ENTRY POINT
*/

void
symbol( string, llcx, llcy, height, theta )
	char	*string;		/* -> NUL-terminated string */
	int	llcx, llcy;		/* coordinates of text LLC */
	int	height;			/* text height & spacing */
	double	theta;			/* rotation (degrees CCW) */
	{

	/* initialize starting stroke pointers upon first entry only */

	if ( sstroke[0] == (char *)0 )
		{
		register int	code;	/* ASCII code values */
		register char	*sp = stroke;	/* -> stroke data */

		for ( code = 0; code < 128; ++code )
			{
			sstroke[code] = sp;	/* starts here */
			while ( *sp++ != (char)0 )
				;	/* 0 terminates the data */
			}
		}

	/* set up global parameters for text */

		{
		double	angle;		/* rotation (radians CCW) */
		double	ht;		/* normalized height */

		xorg = (double)llcx;	/* text origin (LLC) */
		yorg = (double)llcy;

		ht = (double)height / STDHT;
		angle = theta / DEGRAD;

		symcos = cos( angle ) * ht;
		symsin = sin( angle ) * ht;
		}

	/* look up strokes for each character and plot them */

		{
		extern void	plot();	/* move/draw routine */
		register int	c;	/* char from ASCII string */
					/* also used for stroke data */
		register int	cornx;	/* proto X of cell corner */

		for ( cornx = 0;
		      (c = (int)*string++) != NUL;	/* next char */
		      cornx += CHSPAC
		    )	{
			register char	*sp = sstroke[c & ASCMASK];
					/* -> stroke data */

			/* get to character cell LLC */

			plot( cornx, 0, 0 );
			/* no move optimization is done */

			/* draw the strokes starting at LLC */

			while ( c = (int)*sp++ )	/* get stroke */
				plot( cornx + ((c & XXX) >> XJUST),
				      (c & YYY) - ((c & S) ? 2 : 0),
				      (c & V)
				    );	/* move or draw */
			}
		}
	}


static void
plot( dx, dy, vis )			/* plot adjusted stroke */
	int	dx, dy;			/* unrot pos rel to text LLC */
	int	vis;			/* nonzero => visible */
	{

	/* transform prototype coordinates to actual plot coordinates */

	double	xf = (double)dx;
	double	yf = (double)dy;

	int	posx = (int)(xorg + xf * symcos - yf * symsin + 0.5);
	int	posy = (int)(yorg + yf * symcos + xf * symsin + 0.5);
	/* no arithmetic overflow checking is done */

	if ( vis == 0 )
		move( posx, posy );	/* move pen */
		/* no move optimization is done */
	else
		cont( posx, posy );	/* draw */
	}



More information about the Comp.unix mailing list