Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site brl-tgr.ARPA Path: utzoo!watmath!clyde!burl!ulysses!allegra!bellcore!decvax!genrad!teddy!panda!talcott!harvard!seismo!brl-tgr!tgr!gwyn@Brl-Vld.ARPA From: Doug Gwyn (VLD/VMB)Newsgroups: net.unix Subject: Re: Graphics Character Fonts Message-ID: <7097@brl-tgr.ARPA> Date: Tue, 8-Jan-85 12:01:08 EST Article-I.D.: brl-tgr.7097 Posted: Tue Jan 8 12:01:08 1985 Date-Received: Fri, 11-Jan-85 06:53:31 EST Sender: news@brl-tgr.ARPA Organization: Ballistic Research Lab Lines: 351 /* 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 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 */ }