|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 15060 (0x3ad4) Types: TextFile Names: »tpic_support.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12 └─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z« └─⟦ca79c7339⟧ └─⟦this⟧ »DVIware/laser-setters/dvi-to-ps/TeXPS/dvitps/src/tpic_support.c«
/* Copyright 1988 Stephan v. Bechtolsheim */ /* This file is part of the TeXPS Software Package. The TeXPS Software Package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the TeXPS Software Package General Public License for full details. Everyone is granted permission to copy, modify and redistribute the TeXPS Software Package, but only under the conditions described in the TeXPS Software Package General Public License. A copy of this license is supposed to have been given to you along with TeXPS Software Package so you can know your rights and responsibilities. It should be in a file named CopyrightLong. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* * Tpic support routines * * Tim Morgan, UC Irvine, morgan@ics.uci.edu * Fletcher Mattox, fletcher@sally.utexas.edu, (adapted to dvitps) * Stephan Bechtolsheim made some changes (more to conform to * the conventions in this driver than anything else). * \special{pn pensize} Tpic_set_pen_size(pensize) * \special{tx count pattern} not implemented * \special{pa x y} Tpic_add_path(x, y) * \special{fp} Tpic_flush_path_fp() * \special{ip} Tpic_flush_path_ip() * \special{dt length} Tpic_flush_dashed(length, 1) * \special{da length} Tpic_flush_dashed(length, 0) * \special{ar x y xrad yrad start end} arc(x, y, xrad, yrad, start, end) * \special{sh} Tpic_shade_last(grey) * \special{wh} Tpic_shade_last(white) * \special{bl} Tpic_shade_last(black) * * At the time these routines are called, the values of hhh and vvv should * have been updated to the upper left corner of the graph (the position * the \special appears at in the dvi file). Then the coordinates in the * graphics commands are in terms of a virtual page with axes oriented: * * 0,0 * +-----------> +x * | * | * | * \ / * +y * * Angles are measured in the conventional way, from +x towards +y. * Unfortunately, that reverses the meaning of "counterclockwise" * from what it's normally thought of. */ #include <stdio.h> #include <math.h> #include "defs.h" #include "dvitps.h" #include "emit.h" #include "special-tokenlex.h" /* External declarations. */ extern int IntFromLex(); extern int LexInt; extern double LexDouble; extern double DoubleFromLex(); extern double DoubleOrIntFromLex(); extern int PssColumn; extern void PssSendInteger(); extern void PssSendCommand(); extern int Verbose; extern int DriverMag; /* Magnification used for this dvi file */ extern int Resolution;/* Pixels per Inch */ extern int hhh, vvv; /* device coordinates in pixels */ /* Forward declarations. */ void TpicOutputLinetoPath(); void TpicSaveShadingColor(); #define MAXPOINTS 300 /* Max points in a path. */ static int xx[MAXPOINTS], yy[MAXPOINTS]; /* Path in milli-inches, absolute coordinates. */ static int TpicPathLength = 0; /* # points in current path */ int pen_size = 1; /* Pixel width of lines drawn */ /* * These two macros scale from milli-inches to pixel coords, but do * not apply the necessary offsets for absolute display positioning. * Because of overflow problems has to be done with "double". */ #define xsc(x) (int) (((x)*(double)Resolution*(double)DriverMag/1000.0\ + 500.0) / 1000) #define ysc(y) (int) (((y)*(double)Resolution*(double)DriverMag/1000.0\ + 500.0) / 1000) /* * These two macros scale from milli-inches to pixel coords, and add * the necessary offsets for absolute device positions. */ #define XCONV(x) (xsc(x) + hhh) #define YCONV(y) (ysc(y) + vvv) /* The following variable, if set to TRUE, means the next object is shaded, and if set to FALSE, it means it's "stroked", that is a line is drawn. After shading, it's always reset to stroke. */ int ShadeNextObject = FALSE; /* Color values in general: Tpic's language defines color such that 0 is white, 1 is black and that's the way colors are stored in the following variable. Postscript needs 1 white and 0 black, just the reverse. It's reversed when it's sent out. */ double ColorOfNextShade; /* * TpicShadeCommandGeneral * *********************** * This procedure deals with the "sh" command. This command can be * one of the following: * sh s (where s indicated the color, 0 ... 1 * sh (default to gray in this case) */ void TpicShadeCommandGeneral() { int tok; tok = yylex(); switch (tok) { case 0: TpicSaveShadingColor(0.7); break; case T_INT: TpicSaveShadingColor((double)LexInt); break; case T_DOUBLE: TpicSaveShadingColor(LexDouble); break; default: Fatal2 ("TpicShadeCommandGeneral(): default, code = %d\n", tok); } } TpicShadeCommandWhite() {TpicSaveShadingColor(0.0);} TpicShadeCommandBlack() {TpicSaveShadingColor(1.0);} /* * TpicSaveShadingColor * ******************** * Expects a `color' between 0 (white) and 1 (black). * It saves that color. * * color: the new incoming color. */ void TpicSaveShadingColor(color) double color; { if (color < 0.0 || color > 1.0) { Warning2 ("Tpic_shade_last(): Illegal shade %f", color); return; } ShadeNextObject = TRUE; ColorOfNextShade = color; #ifdef DEBUG fprintf (stderr, "TpicSaveShadingColor(): gray value = %4.2lf\n", color); #endif } /* * TpicShadeOrStroke * ***************** * This is where the shading and stroking actually happens. * See comment in the beginning for an explanation about shading * colors here and in PostScript. */ void TpicShadeOrStroke() { char buffer[256]; if (ShadeNextObject) { PssSendCommand ("currentgray"); /* Save current color. */ sprintf (buffer, "%4.2lf ", 1.0 - ColorOfNextShade); /* Send new color. */ PssSendCommand (buffer); PssSendCommand ("setgray"); /* Set new color. */ PssSendCommand("fill"); /* fill the area. */ /* The following setgray matches the currentgray from the preceding procedure. */ PssSendCommand("setgray"); /* Restore old color. */ ShadeNextObject = FALSE; /* No more shading. */ } else { PssSendCommand("stroke"); } } /* * TpicSaveCurrentPoint * ******************** * * Tpic \specials must be careful not to forget what the current state * is, so that it can restore it later on. I think `current state' * == `current point'. The driver expects an rmoveto to work after * a \special, so the current point must be saved (at least). */ void TpicSaveCurrentPoint() { PssSendCommand("currentpoint"); } /* * Pop the currentpoint off the stack. Note that TpicSaveCurrentPoint() * and TpicRestoreCurrentPoint() must come in pairs, or we are in big trouble. */ void TpicRestoreCurrentPoint() { PssSendCommand("moveto"); } /* * Set the size of the virtual pen used to draw in milli-inches */ void Tpic_set_pen_size() { int ps; ps = IntFromLex(); pen_size = xsc(ps); PssSendInteger (pen_size); PssSendCommand ("setlinewidth"); } /* * Tpic_flush_path_ip * ****************** * The "ip", if shading was turned on before, does shading. * If shading was not turned on, it does nothing, but does clear the path. */ void Tpic_flush_path_ip() { if (ShadeNextObject) { TpicSaveCurrentPoint(); TpicOutputLinetoPath(); TpicShadeOrStroke(); TpicRestoreCurrentPoint(); } else { TpicPathLength = 0; } } /* * Tpic_flush_path_fp * ****************** * The "fp" flush path definition was originally to * simply shade the figure if shading was in effect, or stroke * it otherwise (= default). * New function is as follows: * * 1. always draw a line * 2. If shading in effect also shade. */ void Tpic_flush_path_fp() { register int i; #ifdef ABC for (;;) { printf ("Give x: "); scanf ("%d", &k); printf (":%d:\n", XCONV(k)); } #endif #ifdef TESTING EMIT_NEW_LINE; #endif /* If Shading is in effect, do it now (that is first). Color is not deal with here but in TpicShadeOrStroke(). */ if (ShadeNextObject) { TpicSaveCurrentPoint(); TpicOutputLinetoPath(); TpicShadeOrStroke(); TpicRestoreCurrentPoint(); } /* Now comes the stroking part. */ if (ShadeNextObject) Fatal ("Tpic_flush_path_fp(): shading still on."); TpicSaveCurrentPoint(); TpicOutputLinetoPath(); TpicShadeOrStroke(); TpicRestoreCurrentPoint(); #ifdef TESTING EMIT_NEW_LINE; #endif TpicPathLength = 0; } /* * TpicOutputLinetoPath * ******************** */ void TpicOutputLinetoPath() { int i; PssSendCommand("newpath"); PssSendInteger (XCONV(xx[1])); PssSendInteger (YCONV(yy[1])); PssSendCommand ("moveto"); for (i=1; i<TpicPathLength; i++) { #ifdef TESTING EMIT_NEW_LINE; #endif PssSendInteger(XCONV(xx[i+1])); PssSendInteger(YCONV(yy[i+1])); PssSendCommand("lineto"); } } /* * Draw a dot -- the call to Tpic_dot_at() must be protected * by a TpicSaveCurrentPoint(). */ Tpic_dot_at(x, y) int x,y; { int radius = 1; /* in pixels */ PssSendCommand ("newpath"); PssSendInteger(XCONV(x)); PssSendInteger(YCONV(y)); PssSendInteger(radius); PssSendInteger(0); PssSendInteger(360); PssSendCommand("arc"); PssSendCommand("fill"); } /* * Print a dashed line along the previously defined path, with * the dashes/inch defined. */ void Tpic_flush_dashed(dotted) int dotted; { int i, numdots, x0, y0, x1, y1; int cx0, cy0; double inchesperdash; double d, spacesize, a, dx, dy, milliperdash; inchesperdash = DoubleOrIntFromLex(); if (TpicPathLength <= 1 || inchesperdash <= 0.0) { Warning("Illegal conditions for dotted/dashed line"); return; } milliperdash = inchesperdash * 1000.0; x0 = xx[1]; y0 = yy[1]; x1 = xx[2]; y1 = yy[2]; dx = x1 - x0; dy = y1 - y0; if (dotted) { numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5; TpicSaveCurrentPoint(); for (i=0; i <= numdots; i++) { a = (double) i / (double) numdots; cx0 = x0 + a*dx + 0.5; cy0 = y0 + a*dy + 0.5; Tpic_dot_at(cx0, cy0); } TpicRestoreCurrentPoint(); } else { d = sqrt(dx*dx + dy*dy); numdots = d / (2.0*milliperdash) + 1.0; if (numdots == 1) spacesize = 0; else spacesize = (d - numdots * milliperdash) / (numdots - 1); PssSendCommand ("["); PssSendInteger (xsc(milliperdash)); PssSendInteger (xsc(spacesize)); PssSendCommand ("] 0 setdash"); Tpic_flush_path_fp(); /* OOOPS ?!?!? */ PssSendCommand("[] 0 setdash"); } TpicPathLength = 0; } /* * Add a point to the current path */ void Tpic_add_path() { if (++TpicPathLength >= MAXPOINTS) Fatal("Tpic_add_path(): Too many points."); xx[TpicPathLength] = IntFromLex(); yy[TpicPathLength] = IntFromLex(); } /* * TpicArcBusiness * *************** * Draw an arc. This function is called by either K_ar or K_ia. * * control: TRUE: original command is K_ar * FALSE: original command is K_ia */ void TpicArcBusiness(control) int control; { int xc, yc, xrad, yrad; double start_angle, end_angle; char buffer[256]; int closed_arc = FALSE; /* closed arc, that is circle or ellipsis? */ int draw_arc_path; /* Draw the arc itself? */ /* Read in all the arguments. */ xc = IntFromLex(); yc = IntFromLex(); xrad = IntFromLex(); yrad = IntFromLex(); start_angle = DoubleOrIntFromLex(); end_angle = DoubleOrIntFromLex(); /* Normalization of angles. */ while (start_angle < 0.0) start_angle += TWOPI; while (end_angle < 0.0) end_angle += TWOPI; while (start_angle > TWOPI) start_angle -= TWOPI; while (end_angle > TWOPI) end_angle -= TWOPI; /* The following code fixes up the end_angle, if the difference between start and end_angle is very small, because the assumption is then, that this very small difference comes from the fact that the difference between the two angles is supposed to be 2*pi instead of zero, but the normalization of the angles above did reduce the difference to zero. */ if (ABS_MACRO(start_angle - end_angle) < 0.001) { closed_arc = TRUE; end_angle += TWOPI; } /* If shading is in effect, the path must be closed. Otherwise shading is turned off. */ if (ShadeNextObject && !closed_arc) { ShadeNextObject = FALSE; if (Verbose > 0) { fprintf (stderr, "TpicArcBusiness(): K_ia/K_ar: shading in effect, path not closed.\n"); fprintf (stderr, " shading turned off.\n"); } } /* The next question is whether the arc / circle / ellipsis should be drawn or not. If it's the K_ia command it should be not. But for debugging purposes we deemed it as better, that the path is drawn in the case of the K_ia command, if the path is not closed. If it's closed, the K_ia does shading only. K_ar always draws the path. */ if (control) draw_arc_path = TRUE; else { if (closed_arc) draw_arc_path = FALSE; else { draw_arc_path = TRUE; if (Verbose > 0) fprintf (stderr, "TpicArcBusiness(): K_ia, path not closed: draw arc, no shading.\n"); } } /* Angles in PostScript are in degrees. */ start_angle *= 360.0/TWOPI; end_angle *= 360.0/TWOPI; /* Write out the PostScript code here. */ TpicSaveCurrentPoint(); PssSendCommand("newpath"); PssSendInteger(XCONV(xc)); PssSendInteger(YCONV(yc)); PssSendInteger(xsc(xrad)); PssSendInteger(ysc(yrad)); /* To use PssSendCommand for the following is a little bit of cheating but it works. */ sprintf (buffer, "%5.2lf", start_angle); PssSendCommand (buffer); sprintf (buffer, "%5.2lf", end_angle); PssSendCommand (buffer); /* The shading value reported here is -1, if no shading takes place, and otherwise it's a number in the range 0 .. 1, which is the setgray value for PostScript to be used. */ sprintf (buffer, "%5.2lf", ShadeNextObject ? 1.0 - ColorOfNextShade:-1.0); PssSendCommand (buffer); /* Now convey information whether path should be drawn or not. */ PssSendCommand (draw_arc_path ? "true":"false"); /* Send information out here whether the path should be drawn or not. */ PssSendCommand ("@ellipse"); /* Resetting things. */ if (ShadeNextObject) ShadeNextObject = FALSE; TpicRestoreCurrentPoint(); } /* * Draw a Chaikin spline along the previously defined path * @ChaikinSplineDraw strokes the path, so we don't do it here. */ void Tpic_flush_spline() { int i; TpicSaveCurrentPoint(); for (i=1; i<=TpicPathLength; i++) { PssSendInteger(XCONV(xx[i])); PssSendInteger(YCONV(yy[i])); } PssSendInteger(TpicPathLength); PssSendCommand ("@ChaikinSplineDraw"); TpicRestoreCurrentPoint(); TpicPathLength = 0; }