home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / dv_x / dvix.zip / DVI_DRAW.C < prev    next >
C/C++ Source or Header  |  1992-10-25  |  9KB  |  372 lines

  1. /*
  2.  * Support drawing routines for TeXsun and TeX
  3.  *
  4.  *      Copyright, (C) 1987, 1988 Tim Morgan, UC Irvine
  5.  *
  6.  * At the time these routines are called, the values of hh and vv should
  7.  * have been updated to the upper left corner of the graph (the position
  8.  * the \special appears at in the dvi file).  Then the coordinates in the
  9.  * graphics commands are in terms of a virtual page with axes oriented the
  10.  * same as the Imagen and the SUN normally have:
  11.  *
  12.  *                      0,0
  13.  *                       +-----------> +x
  14.  *                       |
  15.  *                       |
  16.  *                       |
  17.  *                      \ /
  18.  *                       +y
  19.  *
  20.  * Angles are measured in the conventional way, from +x towards +y.
  21.  * Unfortunately, that reverses the meaning of "counterclockwise"
  22.  * from what it's normally thought of.
  23.  *
  24.  * A lot of floating point arithmetic has been converted to integer
  25.  * arithmetic for speed.  In some places, this is kind-of kludgy, but
  26.  * it's worth it.
  27.  */
  28.  
  29. static char *rcsid="$Header: /user/bruce/dvix/RCS/dvi_draw.c,v 1.2 1991/11/04 02:04:08 root Exp $" ;
  30.  
  31. #include <ctype.h>
  32. #include <stdio.h>
  33. #include <math.h>
  34.  
  35. #define    MAXPOINTS    300    /* Max points in a path */
  36. #define    TWOPI        (3.14159265359*2.0)
  37. #define    MAX_PEN_SIZE    7    /* Max pixels of pen width */
  38.  
  39.  
  40. static int xx[MAXPOINTS], yy[MAXPOINTS];    /* Path in milli-inches */
  41. static int path_len = 0;    /* # points in current path */
  42. int pen_size = 1;        /* Pixel width of lines drawn */
  43. #define    FALSE    0
  44. #define    TRUE    1
  45. int whiten = FALSE, shade = FALSE, blacken = FALSE;
  46.  
  47. extern void dot_at(), line_btw(), do_attribute_path();
  48.  
  49. /* Unfortunately, these values also appear in dvisun.c */
  50. #define    xRESOLUTION    (pixels_per_inch/shrink_factor)
  51. #define    yRESOLUTION    (pixels_per_inch/shrink_factor)
  52.  
  53. extern int pixels_per_inch, shrink_factor;
  54.  
  55.  
  56. /*
  57.  * Issue warning/error messages
  58.  */
  59. void Fatal(msg)
  60. char *msg;
  61. {
  62.     fprintf(stderr, "%s\n", msg);
  63.     exit(1);
  64. }
  65.  
  66. static void Warning(fmt, msg)
  67. char *fmt, *msg;
  68. {
  69.     fprintf(stderr, fmt, msg);
  70.     fputc ('\n', stderr);
  71. }
  72.  
  73.  
  74. /*
  75.  * Set the size of the virtual pen used to draw in milli-inches
  76.  */
  77. /* ARGSUSED */
  78. void set_pen_size(cp)
  79. char *cp;
  80. {
  81.     int ps;
  82.  
  83.     if (sscanf(cp, " %d ", &ps) != 1) {
  84.     Warning("illegal .ps command format: %s", cp);
  85.     return;
  86.     }
  87.     pen_size = (ps*(xRESOLUTION+yRESOLUTION) + 1000) / 2000;
  88.     if (pen_size < 1) pen_size = 1;
  89.     else if (pen_size > MAX_PEN_SIZE) pen_size = MAX_PEN_SIZE;
  90. }
  91.  
  92.  
  93. /*
  94.  * Print the line defined by previous path commands
  95.  */
  96. void flush_path(invis)
  97. int invis;
  98. {
  99.     register int i;
  100.     int last_min_x, last_max_x, last_min_y, last_max_y;
  101.  
  102.     last_min_x = 30000;    last_min_y = 30000;
  103.     last_max_x = -30000; last_max_y = -30000;
  104.     for (i=1; i<path_len; i++) {
  105.     if (xx[i] > last_max_x) last_max_x = xx[i];
  106.     if (xx[i] < last_min_x) last_min_x = xx[i];
  107.     if (yy[i] > last_max_y) last_max_y = yy[i];
  108.     if (yy[i] < last_min_y) last_min_y = yy[i];
  109.     if (! invis) line_btw(xx[i], yy[i], xx[i+1], yy[i+1]);
  110.     }
  111.     if (xx[path_len] > last_max_x) last_max_x = xx[path_len];
  112.     if (xx[path_len] < last_min_x) last_min_x = xx[path_len];
  113.     if (yy[path_len] > last_max_y) last_max_y = yy[path_len];
  114.     if (yy[path_len] < last_min_y) last_min_y = yy[path_len];
  115.     path_len = 0;
  116.     do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y);
  117. }
  118.  
  119.  
  120. /*
  121.  * Print a dashed line along the previously defined path, with
  122.  * the dashes/inch defined.
  123.  */
  124. void flush_dashed(cp, dotted)
  125. char *cp;
  126. int dotted;
  127. {
  128.     int i, numdots, x0, y0, x1, y1;
  129.     int cx0, cy0, cx1, cy1;
  130.     float inchesperdash;
  131.     double d, spacesize, a, b, dx, dy, milliperdash;
  132.  
  133.     if (sscanf(cp, " %f ", &inchesperdash) != 1) {
  134.     Warning("illegal format for dotted/dashed line: %s", cp);
  135.     return;
  136.     }
  137.     if (path_len <= 1 || inchesperdash <= 0.0) {
  138.     Warning("illegal conditions for dotted/dashed line", "");
  139.     return;
  140.     }
  141.     milliperdash = inchesperdash * 1000.0;
  142.     x0 = xx[1];    y0 = yy[1];
  143.     x1 = xx[2];    y1 = yy[2];
  144.     dx = x1 - x0;
  145.     dy = y1 - y0;
  146.     if (dotted) {
  147.     numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5;
  148.     for (i=0; i <= numdots; i++) {
  149.         a = (float) i / (float) numdots;
  150.         cx0 = x0 + a*dx + 0.5;
  151.         cy0 = y0 + a*dy + 0.5;
  152.         dot_at(cx0, cy0);
  153.     }
  154.     }
  155.     else {
  156.     d = sqrt(dx*dx + dy*dy);
  157.     if (d <= 2.0*milliperdash)
  158.         line_btw(x0, y0, x1, y1);
  159.     else {
  160.         numdots = d / (2.0*milliperdash) + 1.0;
  161.         spacesize = (d - numdots * milliperdash) / (numdots - 1);
  162.         for (i=0; i<numdots-1; i++) {
  163.         a = i * (milliperdash + spacesize) / d;
  164.         b = a + milliperdash / d;
  165.         cx0 = x0 + a*dx + 0.5;
  166.         cy0 = y0 + a*dy + 0.5;
  167.         cx1 = x0 + b*dx + 0.5;
  168.         cy1 = y0 + b*dy + 0.5;
  169.         line_btw(cx0, cy0, cx1, cy1);
  170.         b += spacesize / d;
  171.         }
  172.         cx0 = x0 + b*dx + 0.5;
  173.         cy0 = y0 + b*dy + 0.5;
  174.         line_btw(cx0, cy0, x1, y1);
  175.     }
  176.     }
  177.     path_len = 0;
  178. }
  179.  
  180.  
  181. /*
  182.  * Add a point to the current path
  183.  */
  184. void add_path(cp)
  185. char *cp;
  186. {
  187.     int pathx, pathy;
  188.  
  189.     if (++path_len >= MAXPOINTS) Fatal("Too many points");
  190.     if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2)
  191.     Fatal("Malformed path command");
  192.     xx[path_len] = pathx;
  193.     yy[path_len] = pathy;
  194. }
  195.  
  196.  
  197. /*
  198.  * Draw to a floating point position
  199.  */
  200. static void im_fdraw(x, y)
  201. double x,y;
  202. {
  203.     if (++path_len >= MAXPOINTS) Fatal("Too many arc points");
  204.     xx[path_len] = x + 0.5;
  205.     yy[path_len] = y + 0.5;
  206. }
  207.  
  208.  
  209. /*
  210.  * Draw an arc
  211.  */
  212. void arc(cp, invis)
  213. char *cp;
  214. int invis;
  215. {
  216.     int xc, yc, xrad, yrad, n;
  217.     float start_angle, end_angle, angle, theta, r;
  218.     double xradius, yradius, xcenter, ycenter;
  219.  
  220.     if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
  221.     &end_angle) != 6) {
  222.     Warning("illegal arc specification: %s", cp);
  223.     return;
  224.     }
  225.     /* We have a specialized fast way to draw closed circles/ellipses */
  226.     if (start_angle <= 0.0 && end_angle >= 6.282) {
  227.     draw_ellipse(xc, yc, xrad, yrad, invis);
  228.     return;
  229.     }
  230.     xcenter = xc;
  231.     ycenter = yc;
  232.     xradius = xrad;
  233.     yradius = yrad;
  234.     r = (xradius + yradius) / 2.0;
  235.     theta = sqrt(1.0 / r);
  236.     n = 0.3 * TWOPI / theta + 0.5;
  237.     if (n < 12) n = 12;
  238.     else if (n > 80) n = 80;
  239.     n /= 2;
  240.     theta = TWOPI / n;
  241.     flush_path(invis);
  242.     im_fdraw( xcenter + xradius*cos(start_angle),
  243.         ycenter + yradius*sin(start_angle) );
  244.     angle = start_angle + theta;
  245.     while (angle < end_angle) {
  246.     im_fdraw(xcenter + xradius*cos(angle),
  247.          ycenter + yradius*sin(angle) );
  248.     angle += theta;
  249.     }
  250.     im_fdraw(xcenter + xradius*cos(end_angle),
  251.         ycenter + yradius*sin(end_angle) );
  252.     flush_path(invis);
  253. }
  254.  
  255.  
  256. /*
  257.  * APPROXIMATE integer distance between two points
  258.  */
  259. #define    dist(x0, y0, x1, y1)    (abs(x0-x1)+abs(y0-y1))
  260.  
  261.  
  262. /*
  263.  * Draw a spline along the previously defined path
  264.  */
  265. void flush_spline(invis)
  266. int invis;
  267. {
  268.     int xp, yp, N, lastx=(-1), lasty;
  269.     int t1, t2, t3, steps, j;
  270.     register int i, w;
  271.  
  272. #ifdef    lint
  273.     lasty = -1;
  274. #endif
  275.     N = path_len + 1;
  276.     xx[0] = xx[1];    yy[0] = yy[1];
  277.     xx[N] = xx[N-1];    yy[N] = yy[N-1];
  278.     for (i=0; i<N-1; i++) {    /* interval */
  279.     steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) +
  280.          dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80;
  281.     for (j=0; j<steps; j++) {    /* points within */
  282.         w = (j*1000 + 500) / steps;
  283.         t1 = w * w / 20;
  284.         w -= 500;
  285.         t2 = (750000 - w * w) / 10;
  286.         w -= 500;
  287.         t3 = w * w / 20;
  288.         xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000;
  289.         yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000;
  290.         if (lastx > -1 && !invis) line_btw(lastx, lasty, xp, yp);
  291.         lastx = xp;
  292.         lasty = yp;
  293.     }
  294.     }
  295.     path_len = 0;
  296. }
  297.  
  298.  
  299. /*
  300.  * Shade the last box, circle, or ellipse
  301.  */
  302. void shade_last(cp)
  303. char *cp;
  304. {
  305.     float f;
  306.  
  307.     blacken = whiten = shade = FALSE;
  308.     if (sscanf(cp, " %f", &f) == 1) {
  309.     int grey = (f * 100 + 5) / 10;
  310.  
  311.     if (grey > 0 && grey < 10)
  312.         shade = TRUE;
  313.     else if (grey <= 0)
  314.         whiten = TRUE;
  315.     else if (grey >= 0)
  316.         blacken = TRUE;
  317.     } else {
  318.     shade = TRUE;
  319.     }
  320. }
  321.  
  322.  
  323. /*
  324.  * Make the last box, circle, or ellipse, white inside (shade with white)
  325.  */
  326. void whiten_last()
  327. {
  328.     whiten = TRUE;
  329.     blacken = shade = FALSE;
  330. }
  331.  
  332.  
  333. /*
  334.  * Make last box, etc, black inside
  335.  */
  336. void blacken_last()
  337. {
  338.     blacken = TRUE;
  339.     whiten = shade = FALSE;
  340. }
  341.  
  342.  
  343. /*
  344.  * Draw an ellipse with the indicated center and radices.
  345.  */
  346. draw_ellipse(xc, yc, xr, yr, invis)
  347. int xc, yc, xr, yr;
  348. {
  349.     double angle, theta;
  350.     int n, px0, py0, px1, py1;
  351.  
  352.     angle = (xr + yr) / 2.0;
  353.     theta = sqrt(1.0 / angle);
  354.     n = TWOPI / theta + 0.5;
  355.     if (n < 12) n = 12;
  356.     else if (n > 80) n = 80;
  357.     n /= 2;
  358.     theta = TWOPI / n;
  359.  
  360.     angle = 0.0;
  361.     px0 = xc + xr;    /* cos(0) = 1 */
  362.     py0 = yc;        /* Sin(0) = 0 */
  363.     while ((angle += theta) <= TWOPI) {
  364.     px1 = xc + xr*cos(angle) + 0.5;
  365.     py1 = yc + yr*sin(angle) + 0.5;
  366.     if (!invis) line_btw(px0, py0, px1, py1);
  367.     px0 = px1;
  368.     py0 = py1;
  369.     }
  370.     if (!invis) line_btw(px0, py0, xc + xr, yc);
  371. }
  372.