home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / xdvi / part02 / tpic.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-07  |  10.0 KB  |  415 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. #ifndef lint
  30. static char *rcsid=
  31.   "$Header: dvi_draw.c,v 1.1 88/10/20 00:10:09 xwindows Exp $" ;
  32. #endif lint
  33.  
  34. #include <math.h>
  35. #include <stdio.h>
  36. #include <ctype.h>
  37.  
  38. #include "xdvi.h"
  39.  
  40. #define    MAXPOINTS    300    /* Max points in a path */
  41. #define    TWOPI        (3.14159265359*2.0)
  42. #define    MAX_PEN_SIZE    7    /* Max pixels of pen width */
  43.  
  44.  
  45. static    int xx[MAXPOINTS], yy[MAXPOINTS];    /* Path in milli-inches */
  46. static    int path_len = 0;    /* # points in current path */
  47. static    int pen_size = 1;    /* Pixel width of lines drawn */
  48.  
  49. static    Boolean    whiten = False, shade = False, blacken = False;
  50.  
  51. extern    void    dot_at(), line_btw(), do_attribute_path();
  52.  
  53. /* Unfortunately, these values also appear in dvisun.c */
  54. #define    xRESOLUTION    (pixels_per_inch/shrink_factor)
  55. #define    yRESOLUTION    (pixels_per_inch/shrink_factor)
  56.  
  57.  
  58. /*
  59.  * Issue warning messages
  60.  */
  61. static    void
  62. Warning(fmt, msg)
  63. char *fmt, *msg;
  64. {
  65.     Fprintf(stderr, fmt, msg);
  66.     (void) fputc('\n', stderr);
  67. }
  68.  
  69.  
  70. /*
  71.  * Set the size of the virtual pen used to draw in milli-inches
  72.  */
  73. /* ARGSUSED */
  74. static    void
  75. set_pen_size(cp)
  76. char *cp;
  77. {
  78.     int ps;
  79.  
  80.     if (sscanf(cp, " %d ", &ps) != 1) {
  81.     Warning("illegal .ps command format: %s", cp);
  82.     return;
  83.     }
  84.     pen_size = (ps*(xRESOLUTION+yRESOLUTION) + 1000) / 2000;
  85.     if (pen_size < 1) pen_size = 1;
  86.     else if (pen_size > MAX_PEN_SIZE) pen_size = MAX_PEN_SIZE;
  87. }
  88.  
  89.  
  90. /*
  91.  * Print the line defined by previous path commands
  92.  */
  93. static    void
  94. flush_path()
  95. {
  96.     register int i;
  97.     int last_min_x, last_max_x, last_min_y, last_max_y;
  98.  
  99.     last_min_x = 30000;    last_min_y = 30000;
  100.     last_max_x = -30000; last_max_y = -30000;
  101.     for (i=1; i<path_len; i++) {
  102.     if (xx[i] > last_max_x) last_max_x = xx[i];
  103.     if (xx[i] < last_min_x) last_min_x = xx[i];
  104.     if (yy[i] > last_max_y) last_max_y = yy[i];
  105.     if (yy[i] < last_min_y) last_min_y = yy[i];
  106.     line_btw(xx[i], yy[i], xx[i+1], yy[i+1]);
  107.     }
  108.     if (xx[path_len] > last_max_x) last_max_x = xx[path_len];
  109.     if (xx[path_len] < last_min_x) last_min_x = xx[path_len];
  110.     if (yy[path_len] > last_max_y) last_max_y = yy[path_len];
  111.     if (yy[path_len] < last_min_y) last_min_y = yy[path_len];
  112.     path_len = 0;
  113.     do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y);
  114. }
  115.  
  116.  
  117. /*
  118.  * Print a dashed line along the previously defined path, with
  119.  * the dashes/inch defined.
  120.  */
  121. static    void
  122. flush_dashed(cp, dotted)
  123. char *cp;
  124. int dotted;
  125. {
  126.     int i, numdots, x0, y0, x1, y1;
  127.     int cx0, cy0, cx1, cy1;
  128.     float inchesperdash;
  129.     double d, spacesize, a, b, dx, dy, milliperdash;
  130.  
  131.     if (sscanf(cp, " %f ", &inchesperdash) != 1) {
  132.     Warning("illegal format for dotted/dashed line: %s", cp);
  133.     return;
  134.     }
  135.     if (path_len <= 1 || inchesperdash <= 0.0) {
  136.     Warning("illegal conditions for dotted/dashed line", "");
  137.     return;
  138.     }
  139.     milliperdash = inchesperdash * 1000.0;
  140.     x0 = xx[1];    y0 = yy[1];
  141.     x1 = xx[2];    y1 = yy[2];
  142.     dx = x1 - x0;
  143.     dy = y1 - y0;
  144.     if (dotted) {
  145.     numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5;
  146.     for (i=0; i <= numdots; i++) {
  147.         a = (float) i / (float) numdots;
  148.         cx0 = x0 + a*dx + 0.5;
  149.         cy0 = y0 + a*dy + 0.5;
  150.         dot_at(cx0, cy0);
  151.     }
  152.     }
  153.     else {
  154.     d = sqrt(dx*dx + dy*dy);
  155.     if (d <= 2.0*milliperdash)
  156.         line_btw(x0, y0, x1, y1);
  157.     else {
  158.         numdots = d / (2.0*milliperdash) + 1.0;
  159.         spacesize = (d - numdots * milliperdash) / (numdots - 1);
  160.         for (i=0; i<numdots-1; i++) {
  161.         a = i * (milliperdash + spacesize) / d;
  162.         b = a + milliperdash / d;
  163.         cx0 = x0 + a*dx + 0.5;
  164.         cy0 = y0 + a*dy + 0.5;
  165.         cx1 = x0 + b*dx + 0.5;
  166.         cy1 = y0 + b*dy + 0.5;
  167.         line_btw(cx0, cy0, cx1, cy1);
  168.         b += spacesize / d;
  169.         }
  170.         cx0 = x0 + b*dx + 0.5;
  171.         cy0 = y0 + b*dy + 0.5;
  172.         line_btw(cx0, cy0, x1, y1);
  173.     }
  174.     }
  175.     path_len = 0;
  176. }
  177.  
  178.  
  179. /*
  180.  * Add a point to the current path
  181.  */
  182. static    void
  183. add_path(cp)
  184. char *cp;
  185. {
  186.     int pathx, pathy;
  187.  
  188.     if (++path_len >= MAXPOINTS) oops("Too many points");
  189.     if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2)
  190.     oops("Malformed path command");
  191.     xx[path_len] = pathx;
  192.     yy[path_len] = pathy;
  193. }
  194.  
  195.  
  196. /*
  197.  * Draw to a floating point position
  198.  */
  199. static void
  200. im_fdraw(x, y)
  201. double x,y;
  202. {
  203.     if (++path_len >= MAXPOINTS) oops("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 ellipse with the indicated center and radices.
  211.  */
  212. static    void
  213. draw_ellipse(xc, yc, xr, yr)
  214. int xc, yc, xr, yr;
  215. {
  216.     double angle, theta;
  217.     int n, px0, py0, px1, py1;
  218.  
  219.     angle = (xr + yr) / 2.0;
  220.     theta = sqrt(1.0 / angle);
  221.     n = TWOPI / theta + 0.5;
  222.     if (n < 12) n = 12;
  223.     else if (n > 80) n = 80;
  224.     n /= 2;
  225.     theta = TWOPI / n;
  226.  
  227.     angle = 0.0;
  228.     px0 = xc + xr;    /* cos(0) = 1 */
  229.     py0 = yc;        /* Sin(0) = 0 */
  230.     while ((angle += theta) <= TWOPI) {
  231.     px1 = xc + xr*cos(angle) + 0.5;
  232.     py1 = yc + yr*sin(angle) + 0.5;
  233.     line_btw(px0, py0, px1, py1);
  234.     px0 = px1;
  235.     py0 = py1;
  236.     }
  237.     line_btw(px0, py0, xc + xr, yc);
  238. }
  239.  
  240. /*
  241.  * Draw an arc
  242.  */
  243. static    void
  244. arc(cp)
  245. char *cp;
  246. {
  247.     int xc, yc, xrad, yrad, n;
  248.     float start_angle, end_angle, angle, theta, r;
  249.     double xradius, yradius, xcenter, ycenter;
  250.  
  251.     if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
  252.     &end_angle) != 6) {
  253.     Warning("illegal arc specification: %s", cp);
  254.     return;
  255.     }
  256.     /* We have a specialized fast way to draw closed circles/ellipses */
  257.     if (start_angle <= 0.0 && end_angle >= 6.282) {
  258.     draw_ellipse(xc, yc, xrad, yrad);
  259.     return;
  260.     }
  261.     xcenter = xc;
  262.     ycenter = yc;
  263.     xradius = xrad;
  264.     yradius = yrad;
  265.     r = (xradius + yradius) / 2.0;
  266.     theta = sqrt(1.0 / r);
  267.     n = 0.3 * TWOPI / theta + 0.5;
  268.     if (n < 12) n = 12;
  269.     else if (n > 80) n = 80;
  270.     n /= 2;
  271.     theta = TWOPI / n;
  272.     flush_path();
  273.     im_fdraw( xcenter + xradius*cos(start_angle),
  274.         ycenter + yradius*sin(start_angle) );
  275.     angle = start_angle + theta;
  276.     while (angle < end_angle) {
  277.     im_fdraw(xcenter + xradius*cos(angle),
  278.          ycenter + yradius*sin(angle) );
  279.     angle += theta;
  280.     }
  281.     im_fdraw(xcenter + xradius*cos(end_angle),
  282.         ycenter + yradius*sin(end_angle) );
  283.     flush_path();
  284. }
  285.  
  286.  
  287. /*
  288.  * APPROXIMATE integer distance between two points
  289.  */
  290. #define    dist(x0, y0, x1, y1)    (abs(x0-x1)+abs(y0-y1))
  291.  
  292.  
  293. /*
  294.  * Draw a spline along the previously defined path
  295.  */
  296. static    void
  297. flush_spline()
  298. {
  299.     int xp, yp, N, lastx=(-1), lasty;
  300.     int t1, t2, t3, steps, j;
  301.     register int i, w;
  302.  
  303. #ifdef    lint
  304.     lasty = -1;
  305. #endif
  306.     N = path_len + 1;
  307.     xx[0] = xx[1];    yy[0] = yy[1];
  308.     xx[N] = xx[N-1];    yy[N] = yy[N-1];
  309.     for (i=0; i<N-1; i++) {    /* interval */
  310.     steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) +
  311.          dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80;
  312.     for (j=0; j<steps; j++) {    /* points within */
  313.         w = (j*1000 + 500) / steps;
  314.         t1 = w * w / 20;
  315.         w -= 500;
  316.         t2 = (750000 - w * w) / 10;
  317.         w -= 500;
  318.         t3 = w * w / 20;
  319.         xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000;
  320.         yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000;
  321.         if (lastx > -1) line_btw(lastx, lasty, xp, yp);
  322.         lastx = xp;
  323.         lasty = yp;
  324.     }
  325.     }
  326.     path_len = 0;
  327. }
  328.  
  329.  
  330. /*
  331.  * Shade the last box, circle, or ellipse
  332.  */
  333. static    void
  334. shade_last()
  335. {
  336.     blacken = whiten = False;
  337.     shade = True;
  338. }
  339.  
  340.  
  341. /*
  342.  * Make the last box, circle, or ellipse, white inside (shade with white)
  343.  */
  344. static    void
  345. whiten_last()
  346. {
  347.     whiten = True;
  348.     blacken = shade = False;
  349. }
  350.  
  351.  
  352. /*
  353.  * Make last box, etc, black inside
  354.  */
  355. static    void
  356. blacken_last()
  357. {
  358.     blacken = True;
  359.     whiten = shade = False;
  360. }
  361.  
  362.  
  363. /*
  364.  *    The following copyright message applies to the rest of this file.  --PV
  365.  */
  366.  
  367. /*
  368.  *    This program is Copyright (C) 1987 by the Board of Trustees of the
  369.  *    University of Illinois, and by the author Dirk Grunwald.
  370.  *
  371.  *    This program may be freely copied, as long as this copyright
  372.  *    message remaines affixed. It may not be sold, although it may
  373.  *    be distributed with other software which is sold. If the
  374.  *    software is distributed, the source code must be made available.
  375.  *
  376.  *    No warranty, expressed or implied, is given with this software.
  377.  *    It is presented in the hope that it will prove useful.
  378.  *
  379.  *    Hacked in ignorance and desperation by jonah@db.toronto.edu
  380.  */
  381.  
  382. /*
  383.  *      The code to handle the \specials generated by tpic was modified
  384.  *      by Dirk Grunwald using the code Tim Morgan at Univ. of Calif, Irvine
  385.  *      wrote for TeXsun.
  386.  */
  387.  
  388. #define COMLEN  4
  389.  
  390. void
  391. applicationDoSpecial(cp)
  392. char *cp;
  393. {
  394.     char command[COMLEN], *orig_cp;
  395.     register int len;
  396.  
  397.     orig_cp = cp;
  398.     while (isspace(*cp)) ++cp;
  399.     len = 0;
  400.     while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
  401.     command[len] = '\0';
  402.     if (strcmp(command, "pn") == 0) set_pen_size(cp);
  403.     else if (strcmp(command, "fp") == 0) flush_path();
  404.     else if (strcmp(command, "da") == 0) flush_dashed(cp, 0);
  405.     else if (strcmp(command, "dt") == 0) flush_dashed(cp, 1);
  406.     else if (strcmp(command, "pa") == 0) add_path(cp);
  407.     else if (strcmp(command, "ar") == 0) arc(cp);
  408.     else if (strcmp(command, "sp") == 0) flush_spline();
  409.     else if (strcmp(command, "sh") == 0) shade_last();
  410.     else if (strcmp(command, "wh") == 0) whiten_last();
  411.     else if (strcmp(command, "bk") == 0) blacken_last();
  412.     else if (spec_warn)
  413.     Fprintf(stderr, "%s:  special \"%s\" not implemented\n", prog, orig_cp);
  414. }
  415.