rsalz@bbn.com (Rich Salz) (04/07/88)
Submitted-by: Joe Dellinger <joe@hanauma.STANFORD.EDU> Posting-number: Volume 14, Issue 28 Archive-name: vplot/part23 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 23 (of 24)." # Contents: Vplot_Kernel/filters/genlib/gentext.c # Wrapped by rsalz@fig.bbn.com on Fri Mar 25 11:47:35 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Vplot_Kernel/filters/genlib/gentext.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Vplot_Kernel/filters/genlib/gentext.c'\" else echo shar: Extracting \"'Vplot_Kernel/filters/genlib/gentext.c'\" \(37130 characters\) sed "s/^X//" >'Vplot_Kernel/filters/genlib/gentext.c' <<'END_OF_FILE' X/* X * Copyright 1987 the Board of Trustees of the Leland Stanford Junior X * University. Official permission to use this software is included in X * the documentation. It authorizes you to use this file for any X * non-commercial purpose, provided that this copyright notice is not X * removed and that any modifications made to this file are commented X * and dated in the style of my example below. X */ X X/* X * X * source file: ./filters/genlib/gentext.c X * X * Joe Dellinger (SEP), June 11 1987 X * Inserted this sample edit history entry. X * Please log any further modifications made to this file: X */ X/* X * Joe Dellinger Oct 18 1987 X * Keep track of fatness as a float, not an int. Round when needed. X * Joe Dellinger Jan 16 1988 X * Allow user-defined fonts. As a check, require that they have a X * magic sequence on the front. If they ask for a font >= NUMGENFONT, X * modulo back into range. X * Joe Dellinger Feb 16 1988 X * Make number of arguments to dev.attributes consistent. X */ X X/* X * VPLOT soft text plotting X * X * Keywords: vplot text vector hershey font X */ X#include <stdio.h> X#include <math.h> X#include <strings.h> X#include <sys/file.h> X#include <vplot.h> X#include "../include/extern.h" X#include "../include/err.h" X#include "../include/enum.h" X#include "../include/params.h" X#include "../include/font_definitions.h" X#include "../include/attrcom.h" X#include "../include/round.h" X X#define NMARK 8 /* Maximum number of marks to use */ X#define MAXPOLY 100 /* Maximum number of points in polygon */ X X/* X * The font to use for undefined fonts. X * It should NOT be a runtime-loaded font! X */ X#define ERRFONT 0 X/* X * The glyph to use for undefined glyphs. X * It must be a glyph in the font ERRFONT. X * Needless to say, this glyph at least had better exist or you're X * in real trouble. X */ X/* We use Glyph 30 in font 0, which is a '?' with a square around it. */ X#define ERRGLYPH (30-font[0].dim[START]) X X/* Fraction of height of capital letter to use as vertical padding for box */ X#define VSPACE_FRAC .20 X/* Fraction of inter-letter space to use for horizontal padding of box */ X#define HSPACE_FRAC 0.5 X X#define EOC 0x8000 /* END OF CHARACTER BIT */ X#define DRAWBIT 0x4000 /* DRAW BIT */ X#define POLYBITS (EOC | DRAWBIT) /* Polygon */ X#define XBIT 0x0040 X#define YBIT 0x2000 X#define UNDEFINED -1 X X#define SIGN_X (glyph_stroke & XBIT) X#define SIGN_Y (glyph_stroke & YBIT) X#define DRAW (glyph_stroke & DRAWBIT) X#define INPOLY ((glyph_stroke & POLYBITS) == POLYBITS) X X#define COLOR_MAP(A) color_set[A][MAP]; X X/* X * Correct for difference in size between what you want and what you've got X */ X#define SIZE_FACTOR(A) (((double)tsize/100.)*(A)/(double)(font[ttxfont].dim[CAP]-font[ttxfont].dim[BASE])) X X/* X * When you change sizes or fonts in midstream, what level do you line up on? X */ X#define ALIGN_HEIGHT (font[ttxfont].dim[BASE]) X X#define CONTROL 001 X#define BS 010 X#define CR 015 X#define NL 012 X static double path_orient_dx, path_orient_dy; static double up_orient_dx, up_orient_dy; static double xorigin_f, yorigin_f, xold_f, yold_f; static int ttxfont, cur_color_save, overlay_save; extern int cur_color, ipat, need_devcolor, overlay; extern int color_set[MAX_COL + 1][_NUM_PRIM]; X extern char *malloc (); extern char *calloc (); X X/* X * interpret characters into vectors X */ gentext (string, pathx, pathy, upx, upy) X char *string; X float pathx, pathy, upx, upy; X{ double fpathx, fpathy, fupx, fupy; double up, path; double xp, yp; float tfat; int add; int ixp, iyp; int *istring; unsigned short *glyphptr, glyph_stroke; double xtxshift, ytxshift; int a, b, ii, jj, kk; int string_length; double last_widthl, last_widthr; double widthl_1st_char, char_width, total_width = 0.; int tsize, first, ttxfont_save, txfont_checked; int ghost = 0; double th_symb, th_symb_s, tv_symb, tv_symb_s; double char_width_s[NMARK]; double total_width_s[NMARK]; int mark_flag[NMARK]; double last_widthl_s[NMARK], last_widthr_s[NMARK]; double xold_f_s[NMARK]; double yold_f_s[NMARK]; double maxtop, minbot; double vspace, hspace, vline; int flag; char *charp; int polycount, xxx[MAXPOLY], yyy[MAXPOLY]; int *ligp; static int one_error = YES; int linecount; X X if (*string == '\0') X return; X X/* X * Set the initial parameters X */ X X/* X * Convert the input float path vectors to doubles. X */ X fpathx = (double) pathx; X fpathy = (double) pathy; X fupx = (double) upx; X fupy = (double) upy; X X path = sqrt ((double) (fpathx * fpathx + fpathy * fpathy)); X up = sqrt ((double) (fupx * fupx + fupy * fupy)); X X if (path == 0. || up == 0.) X { X/* Text got squashed away to nothing */ X return; X } X X path_orient_dx = fpathx / path; X path_orient_dy = fpathy / path; X up_orient_dx = fupx / up; X up_orient_dy = fupy / up; X X/* X * We didn't bomb out right away, so save things we may change so X * they can be restored at exit X */ X cur_color_save = cur_color; X overlay_save = overlay; X X overlay = NO; X X for (ii = 0; ii < NMARK; ii++) X mark_flag[ii] = 0; X X/* Text starts out in the default font at 100% of the requested size */ X tsize = 100; X txfont_checked = txfont; X X if (txfont_checked >= 0) X { X ttxfont = txfont_checked % NUMGENFONT; X if (font[ttxfont] .load == NO) X { X load_font (txfont_checked); X } X txfont_checked = ttxfont; X } X else X { X txfont_checked = ERRFONT; X } X X ttxfont = txfont_checked; X total_width = 0.; X char_width = font[ttxfont] .dim[SPACE] * SIZE_FACTOR (path); X th_symb = char_width / 2.; X last_widthl = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path); X last_widthr = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path); X widthl_1st_char = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path); X tv_symb = (font[ttxfont] .dim[HALF] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X maxtop = (font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X minbot = (font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X X/* These used in making the bounding box */ X vline = (font[ttxfont] .dim[TOP] - font[ttxfont] .dim[BOTTOM] + font[ttxfont] .dim[LINE]) * SIZE_FACTOR (up); X vspace = VSPACE_FRAC * (font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE]) * SIZE_FACTOR (up); X hspace = (HSPACE_FRAC * font[ttxfont] .dim[SPACE] + font[ttxfont] .dim[LETTER]) * SIZE_FACTOR (path); X X/* X * Parse ligatures, control sequences, etc. X * each object gets 2 ints; X * The first tells what sort of object it is. X * Positive == printing character X * Negative == command X * The second is there for any parameters that are associated. X * For normal characters, it gives the glyph number in this font. X * For commands it gives any parameter the command may have. X */ X string_length = strlen (string); X istring = (int *) calloc ((unsigned) 2 * (string_length + 1), sizeof (int)); X X for (ii = 0, charp = string; (charp - string) < string_length; ii++, charp++) X { X switch ((int) (*charp)) X { X/* Check for special ASCII characters first */ X case ' ': X case NL: X case CR: X case BS: X istring[2 * ii] = -(int) (*charp); X continue; X break; X/* Check for \ commands */ X case '\\': X charp++; X switch (*charp) X { X/* \\ just falls through and makes a \ with no special properties */ X case '\\': X break; X/* \ commands with no arguments */ X case '-': X case '>': X case '<': X case '^': X case '_': X case 'g': X case 'G': X case 'n': X case 'h': X istring[2 * ii] = -(int) (*charp); X continue; X break; X/* \ commands with arguments */ X case 's': X case 'f': X case 'F': X case 'k': X case 'r': X case 'm': X case 'M': X case 'v': X case 'c': X istring[2 * ii] = -(int) (*charp); X charp++; X/* default value of the argument is 0 if they just leave a space */ X istring[2 * ii + 1] = 0; X/* read the argument */ X sscanf (charp, "%d ", &istring[2 * ii + 1]); X/* skip past it and check for syntax */ X do X { X if ((*charp >= '0' && *charp <= '9') || X *charp == '-' || *charp == '+') X { X charp++; X } X else X ERR (FATAL, name, "In text \\%c must be followed by an integer and then a space.", (char) (-istring[2 * ii])); X } while (*charp != ' '); X X if (istring[2 * ii] == -(int) ('v')) X { X/* X * The \v command. X * Make an ordinary character with the proper value. X */ X istring[2 * ii] = istring[2 * ii + 1]; X istring[2 * ii + 1] = 0; X } X else X if (istring[2 * ii] == -(int) ('F')) X { X/* Font change command */ X if (istring[2 * ii + 1] >= 0) X { X ttxfont = istring[2 * ii + 1] % NUMGENFONT; X/* On this first pass through, load all the fonts we're going to need */ X if (font[ttxfont] .load == NO) X { X load_font (istring[2 * ii + 1]); X } X istring[2 * ii + 1] = ttxfont; X } X else X { X/* \F-1 means the default font again. */ X if (istring[2 * ii + 1] == -1) X istring[2 * ii + 1] = txfont_checked; X else X istring[2 * ii + 1] = ERRFONT; X } X } X else X if (istring[2 * ii] == -(int) ('c')) X { X/* Color change command */ X if (istring[2 * ii + 1] == -1) X { X/* X * They want to return to the original text color. X * This has already been checked to be within range and X * properly mapped, so just use it! X */ X istring[2 * ii + 1] = cur_color_save; X } X else X { X/* X * Map from the color asked for to the colors that are available. X * Normally only dovplot is allowed to do this, but this is an X * unusual case where dovplot can't do it for us. X */ X if (istring[2 * ii + 1] > MAX_COL || istring[2 * ii + 1] < 0) X ERR (FATAL, name, "(gentext) bad color number %d (max %d, min 0)", X istring[2 * ii + 1], MAX_COL); X istring[2 * ii + 1] = COLOR_MAP (istring[2 * ii + 1]); X } X } X continue; X break; X default: X ERR (WARN, name, "(gentext) Unknown command \\%c.", *charp); X charp--; X break; X } X default: X break; X } X/* Normal character */ X istring[2 * ii] = (int) (*charp); X } X string_length = ii; X X/* Ligatures */ X if (txprec > 1) X { X ttxfont = txfont_checked; X/* X * Turning things into ligatures can only make the string shorter. X * ii keeps track of where we are without ligatures, X * kk keeps track of where we are with ligatures included. X * The string is copied back into itself. Since ii >= kk, there is X * no recursion problem. X */ X for (ii = 0, kk = 0; ii < string_length; ii++, kk++) X { X if (istring[2 * ii] < 0) X { X/* X * The only special command we care about for constructing ligatures X * is the font change command, since ligatures are font dependent. X * The commands WILL break up a ligature, but other than that aren't X * interpreted at all here. X */ X if (-istring[2 * ii] == 'F') X ttxfont = istring[2 * ii + 1]; X istring[2 * kk] = istring[2 * ii]; X istring[2 * kk + 1] = istring[2 * ii + 1]; X continue; X } X X/* X * Take the first ligature that matches. This means that longer ligatures X * MUST be listed first in the font data! X */ X/* X * Loop over ligatures. X * Each ligature has 1 number at the beginning giving the number of characters X * in this ligature. The next number gives the glyph that is drawn for this X * ligature. The next several numbers give the glyphs that are combined. X * ligp points to the ligature we are currently searching for. X * ligp += 2 + ligp[0] moves to the beginning of the next ligature: X * 2 places for the 2 numbers at the beginning plus the ligp[0] characters X * making up the ligature. X */ X for (ligp = font[ttxfont] .lig; ligp[0] > 0; ligp += 2 + ligp[0]) X { X/* Is there enough room before the end to possibly make this? */ X if (ii + ligp[0] - 1 < string_length) X { X/* Loop over the characters in the ligature */ X for (jj = 0; jj < ligp[0]; jj++) X { X/* Didn't match. Stop looking on this one. */ X if (ligp[jj + 2] != istring[2 * (ii + jj)]) X goto failed; X } X/* Got to the end and so it worked. Put in the glyph for the ligature */ X istring[2 * kk] = ligp[1]; X/* skip past the ligp[0] characters in the original string that went into it */ X ii += ligp[0] - 1; X goto success; X } X failed: X continue; X } X/* No ligatures for this one. Copy it across unchanged */ X istring[2 * kk] = istring[2 * ii]; X/* X * Don't need to look at any more ligatures for this character X * (Ligatures don't nest) X */ X success: X continue; X } X/* Update the length of the string */ X string_length = kk; X } X X X/************************************************************************/ X/************************************************************************/ X X/* X * This section conducts a "dry run" through the text string to determine X * its length. X * X * Each character has a left half-width (widthl) and a right half-width (widthr). X * These give the left and right half-widths of the character's bounding box X * away from the character's origin. X * The vertical dimensions of each character's bounding box are a function of X * the font only; font[font_number].dim[TOP] and font[font_number].dim[BOTTOM] X * give the coordinates in font units of the top and bottom of the character's box. X * X * Each character is also separated from its neighbors by an inter-letter space X * (font[font_number].dim[LETTER]). This is effectively tacked onto the beginning X * of each new character, with the exception of the first. X * X * When we actually output vectors we will start with the center of the X * 1st character as our origin. (So we have to remember the left half-width X * in order to be able to compensate for the fact that we measure the length X * of the string starting from the left hand edge of the first character.) X * Variables like "char_width" keep track of the latest character's width X * in case we have to back up over it again. X * X * Multiplying by SIZE_FACTOR converts from the Font's units to Vplot's. X * (Horizontal scales with "path", vertical scales with "up". These simply X * give the length of the path and up vectors.) X * All variables except for those in the font structure itself are in Vplot units. X * X * Left and right the total width of everything (characters and inter-spaces X * between them) is summed into total_width. This is used to do the horizontal X * text justification. X * X * Up and down the highest top and lowest bottom to date are saved in "maxtop" and X * "minbot". These are used for vertical text justification. "ALIGN_HEIGHT" X * gives the effective origin for vertical glyph positioning. X * X * The "symb" variables keep track of the symbol position of the latest character. X */ X first = 1; X flag = 1; X linecount = 1; X ttxfont = txfont_checked; X for (ii = 0; ii < string_length; ii++) X { X/* X * Figure the lenth of the message string. X * Justification is based on the first line of text only X * (That's what "flag" is for) X */ X X/* X * Check for special characters X */ X if (istring[2 * ii] < 0) X { X switch (-istring[2 * ii]) X { X case 'n': X case NL: X linecount++; X case CR: X flag = 0; X break; X case 'h': X case BS: X total_width -= font[ttxfont] .dim[LETTER] * X SIZE_FACTOR (path) + char_width; X break; X case 'F': X/* Change the font */ X ttxfont = istring[2 * ii + 1]; X break; X case 's': X/* Change the size. This affects the SIZE_FACTOR. */ X tsize = istring[2 * ii + 1]; X break; X case 'k': X if (flag) X { X/* X * Add in the blank space created by horizontal 'k'earning. X * This is measured in percent of the width of a space in this font. X * X * Similar vertical movements are ignored for the purposes of justification. X */ X total_width += font[ttxfont] .dim[SPACE] X * SIZE_FACTOR (path) * (istring[2 * ii + 1] / 100.); X } X break; X case 'm': X if (istring[2 * ii + 1] < 0 || istring[2 * ii + 1] >= NMARK) X ERR (FATAL, name, X "(gentext) Too high a mark number %d", istring[2 * ii + 1]); X/* Save all relevant parameters as they are at this instant */ X if (flag) X { X/* Vertical symbol alignment position */ X tv_symb_s = tv_symb; X/* Horizontal symbol alignment position */ X th_symb_s = th_symb; X/* Width of this character (in case the next thing is a backspace) */ X char_width_s[istring[2 * ii + 1]] = char_width; X/* The width so far up to this point */ X total_width_s[istring[2 * ii + 1]] = total_width; X } X mark_flag[istring[2 * ii + 1]] = 1; X break; X case 'M': X if (istring[2 * ii + 1] < 0 || istring[2 * ii + 1] >= NMARK) X ERR (FATAL, name, X "(gentext) Too high a mark number %d", istring[2 * ii + 1]); X/* Make sure it isn't junk */ X if (!mark_flag[istring[2 * ii + 1]]) X ERR (FATAL, name, X "(gentext) Attempt to use undefined mark number %d", X istring[2 * ii + 1]); X/* X * Restore the parameters previously saved. All events after that point X * are now ignored for the purposes of justification. X */ X if (flag) X { X tv_symb = tv_symb_s; X th_symb = th_symb_s; X char_width = char_width_s[istring[2 * ii + 1]]; X total_width = total_width_s[istring[2 * ii + 1]]; X } X break; X case '-': /* Nothing */ X break; X case '>': /* Forward one inter-letter space */ X if (flag) X total_width += font[ttxfont] .dim[LETTER] X * SIZE_FACTOR (path); X break; X case '<': /* Remove one inter-letter space */ X if (flag) X total_width -= font[ttxfont] .dim[LETTER] X * SIZE_FACTOR (path); X break; X case '^': /* Up a half letter */ X case '_': /* Down a half letter */ X case 'g': /* Make text invisible */ X case 'G': /* Make text visible again */ X break; X case ' ': /* Space */ X if (flag) X { X char_width = font[ttxfont] .dim[SPACE] X * SIZE_FACTOR (path); X th_symb = char_width / 2.; X tv_symb = (font[ttxfont] .dim[HALF] - ALIGN_HEIGHT) X * SIZE_FACTOR (up); X total_width += char_width; X if (first) X { X/* If it is the first character, remember the left half width */ X widthl_1st_char = font[ttxfont] .dim[SPACE] * .5 X * SIZE_FACTOR (path); X/* No longer at the first printable character */ X first = 0; X } X else X { X/* else add inter-letter space between it and the previous character */ X total_width += font[ttxfont] .dim[LETTER] X * SIZE_FACTOR (path); X } X } X break; X } X continue; X } X X if (flag) X { X/* X * There are 2 ways a glyph can be undefined: it can be outside the range of X * the font, OR it can have no data associated with it X */ X if (istring[2 * ii] >= font[ttxfont] .dim[START] && istring[2 * ii] <= font[ttxfont] .dim[END]) X { X/* Find the glyph number, and save it so we don't have to recalculate it */ X istring[2 * ii + 1] = istring[2 * ii] - font[ttxfont] .dim[START]; X if (font[ttxfont] .saddr[istring[2 * ii + 1]] != UNDEFINED) X { X/* OK glyph */ X/* In case it's the last one, save its vertical symbol position */ X tv_symb = (font[ttxfont] .symbol[istring[2 * ii + 1]] - ALIGN_HEIGHT) X * SIZE_FACTOR (up); X/* And in case we back up later its width */ X char_width = (font[ttxfont] .swidthl[istring[2 * ii + 1]] + X font[ttxfont] .swidthr[istring[2 * ii + 1]]) X * SIZE_FACTOR (path); X/* and horizontal symbol position */ X th_symb = font[ttxfont] .swidthr[istring[2 * ii + 1]] X * SIZE_FACTOR (path); X/* See if it sets a new record high */ X if ((font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up) > maxtop) X maxtop = (font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X/* Or a record low */ X if ((font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) X * SIZE_FACTOR (up) < minbot) X minbot = (font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) X * SIZE_FACTOR (up); X/* Add it into the total width */ X total_width += char_width; X if (first) X { X/* If it's the first remember its left half width */ X widthl_1st_char = font[ttxfont] .swidthl[istring[2 * ii + 1]] X * SIZE_FACTOR (path); X } X else X { X/* or if not first add in the space between it and the previous glyph */ X total_width += font[ttxfont] .dim[LETTER] X * SIZE_FACTOR (path); X } X } X else X { X/* Second way to be undefined. Turn it into a "special" character */ X istring[2 * ii] = UNDEFINED; X } X } X else X { X/* First way to be undefined. Turn it into a "special" character */ X istring[2 * ii] = UNDEFINED; X } X X if (istring[2 * ii] == UNDEFINED) X { X/* X * If it is undefined, use the special "ERROR" glyph and then X * treat that just like we would treat a regular character. X */ X ttxfont_save = ttxfont; X ttxfont = ERRFONT; X istring[2 * ii + 1] = ERRGLYPH; X char_width = (font[ttxfont] .swidthl[ERRGLYPH] + X font[ttxfont] .swidthr[ERRGLYPH]) X * SIZE_FACTOR (path); X th_symb = font[ttxfont] .swidthr[ERRGLYPH] * SIZE_FACTOR (path); X tv_symb = (font[ttxfont] .symbol[ERRGLYPH] - ALIGN_HEIGHT) X * SIZE_FACTOR (up); X if ((font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up) > maxtop) X maxtop = (font[ttxfont] .dim[TOP] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X if ((font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) * SIZE_FACTOR (up) < minbot) X minbot = (font[ttxfont] .dim[BOTTOM] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X total_width += char_width; X if (first) X { X widthl_1st_char = font[ttxfont] .swidthl[ERRGLYPH] * SIZE_FACTOR (path); X } X else X total_width += font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path); X ttxfont = ttxfont_save; X } X X/* We printed something, so we aren't at the first character anymore */ X first = 0; X } X else X { X/* X * If we're past the first line of text, do the few things that aren't related X * to justification (looking for undefined glyphs, finding the glyph numbers) X */ X if (istring[2 * ii] >= font[ttxfont] .dim[START] && istring[2 * ii] <= font[ttxfont] .dim[END]) X { X istring[2 * ii + 1] = istring[2 * ii] - font[ttxfont] .dim[START]; X if (font[ttxfont] .saddr[istring[2 * ii + 1]] == UNDEFINED) X { X istring[2 * ii] = UNDEFINED; X } X } X else X { X istring[2 * ii] = UNDEFINED; X } X if (istring[2 * ii] == UNDEFINED) X { X istring[2 * ii + 1] = ERRGLYPH; X } X } X } X X/* X * Set the proper alignment from the calculated length of the X * text string. Remember that when we plot zero will be in the center X * of the first character and not the left hand edge of the first character, X * so we have to use widthl_1st_char to compensate for that. X */ X switch (txalign.hor) X { X case TH_SYMBOL: X xtxshift = total_width - widthl_1st_char - th_symb; X break; X case TH_CENTER: X xtxshift = total_width / 2. - widthl_1st_char; X break; X case TH_RIGHT: X xtxshift = total_width - widthl_1st_char; X break; X case TH_NORMAL: X case TH_LEFT: X default: X xtxshift = -widthl_1st_char; X break; X } X X tsize = 100; X ttxfont = txfont_checked; X tfat = fat; X X/* X * CAP, HALF, and BASE are calculated based on font and size of default X * TOP and BOTTOM are based on highest TOP and lowest BOTTOM of all X * glyphs in string. X */ X switch (txalign.ver) X { X case TV_SYMBOL: X ytxshift = tv_symb; X break; X case TV_TOP: X ytxshift = maxtop; X break; X case TV_CAP: X ytxshift = (font[ttxfont] .dim[CAP] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X break; X case TV_HALF: X ytxshift = (font[ttxfont] .dim[HALF] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X break; X case TV_BOTTOM: X ytxshift = minbot; X break; X case TV_NORMAL: X case TV_BASE: X default: X ytxshift = (font[ttxfont] .dim[BASE] - ALIGN_HEIGHT) * SIZE_FACTOR (up); X break; X } X X X/************************************************************************/ X/************************************************************************/ X X X/* X * This part of the code draws the characters. X * X * The complexity arises because when we do each character we have to X * be at its CENTER in the left-right direction and at its ALIGN_HEIGHT X * in the up-down direction. X * So to move from one character to the next we have to move over by X * the right half-width of the previous character, an inter-letter space, X * and then the left half-width of the character we're on! X * This helps to make the code confusing. X * X * We also have to always be ready to unexpectedly back up over the last X * character, so we also have to keep around the left half-width of the X * previous character as well. X */ X xold_f = xold; X yold_f = yold; X X/* X * The "mov" routine moves us around in the cock-eyed coordinate system X * determined by the up and path vectors. There's no problem if these X * vectors aren't orthogonal! X */ X mov (-xtxshift, -ytxshift); X xorigin_f = xold_f; X yorigin_f = yold_f; X X if (txovly) X { X mov (-widthl_1st_char - hspace, minbot - vline * (linecount - 1) - vspace); X xxx[0] = ROUND (xold_f); X yyy[0] = ROUND (yold_f); X mov (0., maxtop - minbot + vline * (linecount - 1) + 2. * vspace); X xxx[1] = ROUND (xold_f); X yyy[1] = ROUND (yold_f); X mov (total_width + 2. * hspace, 0.); X xxx[2] = ROUND (xold_f); X yyy[2] = ROUND (yold_f); X mov (0., -(maxtop - minbot + vline * (linecount - 1) + 2. * vspace)); X xxx[3] = ROUND (xold_f); X yyy[3] = ROUND (yold_f); X X if (txovly == 2 || txovly == 3) X { X if (cur_color != 0 || need_devcolor) X { X cur_color = 0; X dev.attributes (SET_COLOR, cur_color, 0, 0, 0); X need_devcolor = NO; X } X drawpolygon (4, xxx, yyy); X if (cur_color != cur_color_save || need_devcolor) X { X cur_color = cur_color_save; X dev.attributes (SET_COLOR, cur_color, 0, 0, 0); X need_devcolor = NO; X } X } X X if (txovly == 1 || txovly == 3) X { X dev.vector (xxx[0], yyy[0], xxx[1], yyy[1], ROUND (tfat), 0); X dev.vector (xxx[1], yyy[1], xxx[2], yyy[2], ROUND (tfat), 0); X dev.vector (xxx[2], yyy[2], xxx[3], yyy[3], ROUND (tfat), 0); X dev.vector (xxx[3], yyy[3], xxx[0], yyy[0], ROUND (tfat), 0); X } X X xold_f = xorigin_f; X yold_f = yorigin_f; X } X X first = 1; X X/* X * This is where the actual drawing of the characters takes place. X * Loop over all the characters in the string X */ X for (ii = 0; ii < string_length; ii++) X { X/* X * Check for special characters first X */ X if (istring[2 * ii] < 0) X { X switch (-istring[2 * ii]) X { /* standard carriage controls */ X case 'h': X case BS: X mov (-font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path) - X (last_widthl + last_widthr), 0.); X break; X case NL: X case 'n': X xold_f = xorigin_f; X yold_f = yorigin_f; X mov (0., -( X (font[ttxfont] .dim[TOP] - font[ttxfont] .dim[BOTTOM] + font[ttxfont] .dim[LINE]) X * SIZE_FACTOR (up))); X xorigin_f = xold_f; X yorigin_f = yold_f; X first = 1; X break; X case CR: X xold_f = xorigin_f; X yold_f = yorigin_f; X first = 1; X break; X case 'F': X ttxfont = istring[2 * ii + 1]; X break; X case 'c': X if (cur_color != istring[2 * ii + 1] || need_devcolor) X { X cur_color = istring[2 * ii + 1]; X dev.attributes (SET_COLOR, cur_color, 0, 0, 0); X need_devcolor = NO; X } X break; X case 's': X tsize = istring[2 * ii + 1]; X break; X case 'f': X tfat += istring[2 * ii + 1] * fatmult; X break; X case 'k': X/* Horizontal motion */ X mov (font[ttxfont] .dim[SPACE] * SIZE_FACTOR (path) * X (istring[2 * ii + 1] / 100.), 0.); X break; X case 'r': X/* Vertical motion */ X mov (0., (font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE]) X * SIZE_FACTOR (up) * (istring[2 * ii + 1] / 100.)); X break; X case 'm': X/* X * Save the current position. No need to check mark number valid; this X * was checked when we did the justification X */ X last_widthl_s[istring[2 * ii + 1]] = last_widthl; X last_widthr_s[istring[2 * ii + 1]] = last_widthr; X xold_f_s[istring[2 * ii + 1]] = xold_f; X yold_f_s[istring[2 * ii + 1]] = yold_f; X break; X case 'M': X/* X * Restore the current position X */ X last_widthl = last_widthl_s[istring[2 * ii + 1]]; X last_widthr = last_widthr_s[istring[2 * ii + 1]]; X xold_f = xold_f_s[istring[2 * ii + 1]]; X yold_f = yold_f_s[istring[2 * ii + 1]]; X break; X case 'G': X ghost = 0; X break; X case 'g': X ghost = 1; X break; X case '^': X/* Up half a character */ X mov (0., X (font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE]) X * (.5) * SIZE_FACTOR (up)); X break; X case '_': X/* Down half a character */ X mov (0., -( X (font[ttxfont] .dim[CAP] - font[ttxfont] .dim[BASE]) X * (.5) * SIZE_FACTOR (up))); X break; X case '-': X break; X case '>': X/* Right an inter-letter space */ X mov (font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path), 0.); X break; X case '<': X/* Left an inter-letter space */ X mov (-(font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path)), 0.); X break; X case -(UNDEFINED): X /* Don't overload them with error messages */ X if (one_error) X { X ERR (WARN, name, X "(gentext) Attempt(s) to use undefined glyph(s) in font %d", X ttxfont); X one_error = NO; X } X/* Switch to use the ERROR glyph, and the treat it as a regular glyph */ X ttxfont_save = ttxfont; X ttxfont = ERRFONT; X goto not_special; X break; X case ' ': X default: X if (!first) X { X mov ( X (font[ttxfont] .dim[SPACE] * .5 + X font[ttxfont] .dim[LETTER]) X * SIZE_FACTOR (path) X + last_widthr X ,0.); X } X else X { X first = 0; X } X last_widthl = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path); X last_widthr = font[ttxfont] .dim[SPACE] * .5 * SIZE_FACTOR (path); X break; X } X } X else X { X not_special: X/* X * Printable character. X * Pull out the actual strokes that make up each glyph. X * First get the address of the character from the address array X * Get the address by adding the offset (add) to the base array address X * (font[ttxfont].svec). X */ X add = font[ttxfont] .saddr[istring[2 * ii + 1]]; X glyphptr = font[ttxfont] .svec + add; X/* X * Now that we have the address of the fonts, X * we position the pen at the beginning of the next character X * (Unless it's the first printable character in which case we are already X * there) X */ X if (!first) X { X mov ( X (font[ttxfont] .swidthl[istring[2 * ii + 1]] + X font[ttxfont] .dim[LETTER]) X * SIZE_FACTOR (path) X + last_widthr X ,0.); X } X else X first = 0; X X/* Save the left and right half-widths of this glyph */ X last_widthl = font[ttxfont] .swidthl[istring[2 * ii + 1]] X * SIZE_FACTOR (path); X last_widthr = font[ttxfont] .swidthr[istring[2 * ii + 1]] X * SIZE_FACTOR (path); X X/* X * Calculate where to position each character in high precision. X */ X xnew = ROUND (xold_f); X ynew = ROUND (yold_f); X/* X * This loop contains the structure for the actual drawing of the characters X * We go through this block until an "END OF CHARACTER" is read X * X * Strokes are kept in a packed format to save X * space. Each stroke is packed into an unsigned X * short int with the following format: X * X * edsyyyyyysxxxxxx X * ||||____|||____|--> The x-coordinate value X * ||| | `--------> Set if X < 0 X * ||| `-----------> The y-coordinate value X * ||`---------------> Set if Y < 0 X * |`----------------> Draw bit, set if X * | command is draw. X * | Clear, if move. X * `-----------------> End of Character Bit X * X * This is enough bits per coordinate to accomodate all the "Hershey" fonts. X * X * Polygons are also encoded into this scheme. If the EOC and DRAW bits X * are simultaneously on, then we are inside a polygon. The last point of X * the polygon will only have the draw flag on, and at that point the entire X * polygon will be outputted. X */ X X polycount = 0; X X while ((glyph_stroke = *glyphptr++) != EOC) X { X a = glyph_stroke & 077; X if (SIGN_X) X a = -a; X b = (glyph_stroke >> 7) & 077; X if (SIGN_Y) X b = -b; X b -= ALIGN_HEIGHT; X X/* X * Here is the correct place to insert code to rotate a glyph. X * You want to do that before it gets distorted by the global coordinate X * transformation. The "ALIGN_HEIGHT" defines where the vertical origin X * is for a glyph in a font. Note that we are in the font's coordinate X * system units at this point. X */ X xp = xold_f; X yp = yold_f; X/* X * Cock-eyed coordinate system. X * "up" is in the direction of the up vector, X * "right" is in the direction of the path vector. X * These can be screwy, and thus distort the glyph. X * X * "path" and "up" contain the magnitude, and the X * "orient_dx"'s and "orient_dy"'s contain the direction cosines X */ X xp += SIZE_FACTOR (path) * a * path_orient_dx + X SIZE_FACTOR (up) * b * up_orient_dx; X yp += SIZE_FACTOR (path) * a * path_orient_dy + X SIZE_FACTOR (up) * b * up_orient_dy; X ixp = ROUND (xp); X iyp = ROUND (yp); X X if (polycount > 0 && !INPOLY) X { X/* X * If we just WERE in a polygon, but are not now, then we must have just X * finished one. Plot it out. X */ X xxx[polycount] = ixp; X yyy[polycount] = iyp; X polycount++; X if (!ghost) X { X drawpolygon (polycount, xxx, yyy); X } X/* X * Done with this one, reset the vertex counter X */ X polycount = 0; X } X else X if (INPOLY) X { X/* X * We're still saving up the polygon. Save this vertex. X */ X xxx[polycount] = ixp; X yyy[polycount] = iyp; X polycount++; X if (polycount > MAXPOLY - 1) X { X ERR (FATAL, name, X "(gentext) Too many points in polygon."); X } X } X else X { X/* No polygons, just output the vector */ X if (DRAW && !ghost) X dev.vector (xnew, ynew, ixp, iyp, ROUND (tfat), 0); X } X X xnew = ixp; X ynew = iyp; X } X X/* X * If we switched to the error font just to plot the error glyph, X * then switch back to the correct font X */ X if (istring[2 * ii] == UNDEFINED) X { X ttxfont = ttxfont_save; X } X } X } X X/* Restore the correct color, if necessary */ X if (cur_color != cur_color_save) X { X cur_color = cur_color_save; X need_devcolor = YES; X } X X/* Restore overlay mode */ X overlay = overlay_save; X X/* X * If they jump back into text they can continue right where they left off X * (As long as they do nothing to move the pen between now and then.) X */ X mov (last_widthr + font[ttxfont] .dim[LETTER] * SIZE_FACTOR (path), X ytxshift); X xold = ROUND (xold_f); X yold = ROUND (yold_f); X cfree ((char *) istring); X} X mov (hadd, vadd) X double hadd, vadd; X{ X xold_f += hadd * path_orient_dx + vadd * up_orient_dx; X yold_f += hadd * path_orient_dy + vadd * up_orient_dy; X} X load_font (ifont) X int ifont; X{ int fd, length; char filename[120]; char string[80]; char *newfont; int offs[7]; static int done[NUMGENFONT]; X X if (done[ttxfont]) X { X ttxfont = ERRFONT; X return; X } X X done[ttxfont] = YES; X X sprintf (string, "font%d", ifont); X X if (ttxfont < NUM_FONTS) X sprintf (filename, "%s%s.bin", SYSTEM_FONT_DIRECTORY, font[ttxfont] .name); X else X strcpy (filename, string); X X getpar (string, "s", filename); X X if ((fd = open (filename, O_RDONLY)) == -1) X { X ERR (WARN, name, X "(gentext) Couldn't find font %d, file %s", X ttxfont, filename); X ttxfont = ERRFONT; X return; X } X else X { X/* X * First check to make sure it has the magic sequence "Vplot Binary fonT \n" X * followed by the binary integer FONTCHECK at the beginning. X * If it doesn't, it's junk, so don't read it in. X */ X read (fd, string, 20); X read (fd, (char *) &length, sizeof (int)); X X if (strncmp ("Vplot Binary fonT \n", string, 20) != 0 || length != FONTCHECK) X { X close (fd); X ERR (WARN, name, X "(gentext) Font %d file %s is garbled.", X ttxfont, filename); X ttxfont = ERRFONT; X return; X } X X/* X * Binary fonts are machine-specific. Just suck it into memory. X * The start of the file contains the length and then the X * offsets from the beginning to the 7 structures defining the font. X */ X read (fd, (char *) &length, sizeof (int)); X newfont = (char *) malloc ((unsigned) (length * sizeof (char))); X if (newfont == NULL) X { X close (fd); X ERR (WARN, name, X "(gentext) Font %d file %s is too big.", X ttxfont, filename); X ttxfont = ERRFONT; X return; X } X read (fd, (char *) offs, 7 * sizeof (int)); X read (fd, (char *) newfont, length); X close (fd); X/* The 7 structures defining the font... */ X X/* The vital parameters (dimensions, bounds, and lengths) */ X font[ttxfont] .dim = (short *) (newfont + offs[0]); X/* Pointers to the addresses of the glyphs themselves */ X font[ttxfont] .saddr = (int *) (newfont + offs[1]); X/* Left widths */ X font[ttxfont] .swidthl = (short *) (newfont + offs[2]); X/* Right widths */ X font[ttxfont] .swidthr = (short *) (newfont + offs[3]); X/* Vertical symbol hot-spot position */ X font[ttxfont] .symbol = (short *) (newfont + offs[4]); X/* The actual glyph strokes */ X font[ttxfont] .svec = (unsigned short *) (newfont + offs[5]); X/* Ligature data */ X font[ttxfont] .lig = (int *) (newfont + offs[6]); X X/* Whether or not this font has been loaded into memory or not yet */ X font[ttxfont] .load = YES; X } X} END_OF_FILE if test 37130 -ne `wc -c <'Vplot_Kernel/filters/genlib/gentext.c'`; then echo shar: \"'Vplot_Kernel/filters/genlib/gentext.c'\" unpacked with wrong size! fi # end of 'Vplot_Kernel/filters/genlib/gentext.c' fi echo shar: End of archive 23 \(of 24\). cp /dev/null ark23isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 24 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.