|
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 d
Length: 9993 (0x2709) Types: TextFile Names: »draw_sun.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12 └─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z« └─⟦ca79c7339⟧ └─⟦this⟧ »DVIware/crt-viewers/sunview/dvisun/draw_sun.c«
/* * Support drawing routines for dvisun * * Tim Morgan, UC Irvine * * At the time these routines are called, the values of hh and vv 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 the * same as the Imagen and the SUN normally have: * * 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. * * A lot of floating point arithmetic has been converted to integer * arithmetic for speed. In some places, this is kind-of kludgy, but * it's worth it. */ #include <suntool/tool_hs.h> #include <math.h> #define MAXPOINTS 300 /* Max points in a path */ #define TWOPI (3.14159265359*2.0) #define MAX_PEN_SIZE 7 /* Max pixels of pen width */ /* Unfortunately, these values also appear in dvisun.c */ #define xRESOLUTION 118 /* Dots per inch in x-direction */ #define yRESOLUTION 110 /* and in the y-direction */ #undef USEGLOBALMAG #ifdef USEGLOBALMAG extern int mag; /* Magnification from preamble */ extern float ActualFactor(); /* Converts magnification to a fraction */ #endif USEGLOBALMAG extern void Warning(), Fatal(); /* Error-handling routines */ extern void sun_draw_ellipse(); /* Fast ellipse-drawing routine */ extern int hh, vv; /* Current x,y position on screen */ extern int xscreen, yscreen; /* x,y compensation for page on screen */ extern int draw_mode; /* Mode to draw with */ extern struct pixrect *display; /* Pixrect we're going to draw on */ static int xx[MAXPOINTS], yy[MAXPOINTS]; /* Path in milli-inches */ static int path_len = 0; /* # points in current path */ int pen_size = 1; /* Pixel width of lines drawn */ static bool whiten = FALSE, shade = FALSE; /* Attributes for last object */ /* * These two routines scale from milli-inches to pixel coords, but do * not apply the necessary offsets for absolute display positioning. */ #ifdef USEGLOBALMAG #define xsc(x) (((x)*xRESOLUTION*ActualFactor(mag) + 500) / 1000) #define ysc(y) (((y)*yRESOLUTION*ActualFactor(mag) + 500) / 1000) #else #define xsc(x) (((x)*xRESOLUTION + 500) / 1000) #define ysc(y) (((y)*yRESOLUTION + 500) / 1000) #endif /* * These two macros scale from milli-inches to pixel coords, and add * the necessary offsets for absolute screen positions. */ #define xconv(x) (xsc(x) + hh - xscreen) #define yconv(y) (ysc(y) + vv - yscreen) /* * Set the size of the virtual pen used to draw in milli-inches */ /* ARGSUSED */ void set_pen_size(cp) char *cp; { int ps; if (sscanf(cp, " %d ", &ps) != 1) { Warning("Illegal .ps command format: %s", cp); return; } #ifdef USEGLOBALMAG pen_size = (ps*(xRESOLUTION+yRESOLUTION)*ActualFactor(mag) + 1000) / 2000; #else pen_size = (ps*(xRESOLUTION+yRESOLUTION) + 1000) / 2000; #endif USEGLOBALMAG if (pen_size < 1) pen_size = 1; else if (pen_size > MAX_PEN_SIZE) pen_size = MAX_PEN_SIZE; } /* * Apply the requested attributes to the last path (box) drawn. * Attributes are reset. */ static void do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y) int last_min_x, last_max_x, last_min_y, last_max_y; { static struct pixrect *shade_pr; if (last_min_x < last_max_x && last_min_y < last_max_y) { if (whiten) { pr_rop(display, last_min_x, last_min_y, last_max_x-last_min_x, last_max_y-last_min_y, PIX_SRC, (struct pixrect *) 0, 0, 0); } else if (shade) { if (!shade_pr) { shade_pr = mem_create(3, 3, 1); if (!shade_pr) Fatal("Out of memory -- cannot create pixrect"); pr_put(shade_pr, 0, 0, 1); } pr_replrop(display, last_min_x, last_min_y, last_max_x-last_min_x, last_max_y-last_min_y, (PIX_SRC|PIX_DST), shade_pr, 0, 0); } } shade = whiten = FALSE; } /* Put a dot at the indicated position. Args in v-p milli-inches */ #define dot_at(x, y) pr_put(display, xconv(x), yconv(y), 1) /* Draw a line on the screen. Arguments are in virtual-page milli-inches */ static void line_btw(x0, y0, x1, y1) int x0, y0, x1, y1; { int i, xstart, xend, ystart, yend; xstart = xconv(x0); ystart = yconv(y0); xend = xconv(x1); yend = yconv(y1); for (i=0; i<pen_size; i++) { pr_vector(display, xstart, ystart, xend, yend, draw_mode, 1); if (abs(yend-ystart) > abs(xend-xstart)) { ++xstart; ++xend; } else { ++ystart; ++yend; } } } /* * Print the line defined by previous path commands */ void flush_path() { register int i; int last_min_x, last_max_x, last_min_y, last_max_y; last_min_x = 30000; last_min_y = 30000; last_max_x = -30000; last_max_y = -30000; for (i=1; i<path_len; i++) { if (xx[i] > last_max_x) last_max_x = xx[i]; if (xx[i] < last_min_x) last_min_x = xx[i]; if (yy[i] > last_max_y) last_max_y = yy[i]; if (yy[i] < last_min_y) last_min_y = yy[i]; line_btw(xx[i], yy[i], xx[i+1], yy[i+1]); } if (xx[path_len] > last_max_x) last_max_x = xx[path_len]; if (xx[path_len] < last_min_x) last_min_x = xx[path_len]; if (yy[path_len] > last_max_y) last_max_y = yy[path_len]; if (yy[path_len] < last_min_y) last_min_y = yy[path_len]; path_len = 0; do_attribute_path(xconv(last_min_x), xconv(last_max_x), yconv(last_min_y), yconv(last_max_y)); } /* * Print a dashed line along the previously defined path, with * the dashes/inch defined. */ void flush_dashed(cp, dotted) char *cp; int dotted; { int i, numdots, x0, y0, x1, y1; int cx0, cy0, cx1, cy1; float inchesperdash; double d, spacesize, a, b, dx, dy, milliperdash; if (sscanf(cp, " %f ", &inchesperdash) != 1) { Warning("Illegal format for dotted/dashed line: %s", cp); return; } if (path_len <= 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; for (i=0; i <= numdots; i++) { a = (float) i / (float) numdots; cx0 = x0 + a*dx + 0.5; cy0 = y0 + a*dy + 0.5; dot_at(cx0, cy0); } } else { d = sqrt(dx*dx + dy*dy); if (d <= 2.0*milliperdash) line_btw(x0, y0, x1, y1); else { numdots = d / (2.0*milliperdash) + 1.0; spacesize = (d - numdots * milliperdash) / (numdots - 1); for (i=0; i<numdots-1; i++) { a = i * (milliperdash + spacesize) / d; b = a + milliperdash / d; cx0 = x0 + a*dx + 0.5; cy0 = y0 + a*dy + 0.5; cx1 = x0 + b*dx + 0.5; cy1 = y0 + b*dy + 0.5; line_btw(cx0, cy0, cx1, cy1); b += spacesize / d; } cx0 = x0 + b*dx + 0.5; cy0 = y0 + b*dy + 0.5; line_btw(cx0, cy0, x1, y1); } } path_len = 0; } /* * Add a point to the current path */ void add_path(cp) char *cp; { int pathx, pathy; if (++path_len >= MAXPOINTS) Fatal("Too many points"); if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2) Fatal("Malformed path command"); xx[path_len] = pathx; yy[path_len] = pathy; } /* * Draw to a floating point position */ static void im_fdraw(x, y) float x,y; { if (++path_len >= MAXPOINTS) Fatal("Too many arc points"); xx[path_len] = x + 0.5; yy[path_len] = y + 0.5; } /* * Draw an arc */ void arc(cp) char *cp; { int xc, yc, xrad, yrad, n; float start_angle, end_angle, angle, theta, r; double xradius, yradius, xcenter, ycenter; if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle, &end_angle) != 6) { Warning("Illegal arc specification: %s", cp); return; } /* We have a specialized fast way to draw closed circles/ellipses */ if (start_angle <= 0.0 && end_angle >= 6.282) { sun_draw_ellipse(xconv(xc), yconv(yc), xsc(xrad), ysc(yrad)); return; } xcenter = xc; ycenter = yc; xradius = xrad; yradius = yrad; r = (xradius + yradius) / 2.0; theta = sqrt(1.0 / r); n = 0.3 * TWOPI / theta + 0.5; if (n < 6) n = 6; else if (n > 80) n = 80; theta = TWOPI / n; flush_path(); im_fdraw( xcenter + xradius*cos(start_angle), ycenter + yradius*sin(start_angle) ); angle = start_angle + theta; while (angle < end_angle) { im_fdraw(xcenter + xradius*cos(angle), ycenter + yradius*sin(angle) ); angle += theta; } im_fdraw(xcenter + xradius*cos(end_angle), ycenter + yradius*sin(end_angle) ); flush_path(); } /* * APPROXIMATE integer distance between two points */ #define dist(x0, y0, x1, y1) (abs(x0-x1)+abs(y0-y1)) /* * Draw a spline along the previously defined path */ void flush_spline() { int xp, yp, N, lastx=(-1), lasty; int t1, t2, t3, steps, j; register int i, w; N = path_len + 1; xx[0] = xx[1]; yy[0] = yy[1]; xx[N] = xx[N-1]; yy[N] = yy[N-1]; for (i=0; i<N-1; i++) { /* interval */ steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) + dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80; for (j=0; j<steps; j++) { /* points within */ w = (j*1000 + 500) / steps; t1 = w * w / 20; w -= 500; t2 = (750000 - w * w) / 10; w -= 500; t3 = w * w / 20; xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000; yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000; if (lastx > -1) line_btw(lastx, lasty, xp, yp); lastx = xp; lasty = yp; } } path_len = 0; } /* * Shade the last box, circle, or ellipse */ void shade_last() { whiten = FALSE; shade = TRUE; } /* * Make the last box, circle, or ellipse, white inside (shade with white) */ void whiten_last() { whiten = TRUE; shade = FALSE; }