home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xditview / draw.c next >
Encoding:
C/C++ Source or Header  |  1991-08-26  |  10.5 KB  |  492 lines

  1. /*
  2.  * $XConsortium: draw.c,v 1.7 91/08/26 11:02:36 gildea Exp $
  3.  *
  4.  * Copyright 1991 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  */
  24.  
  25. /*
  26.  * draw.c
  27.  *
  28.  * accept dvi function calls and translate to X
  29.  */
  30.  
  31. /*
  32.   Support for ditroff drawing commands added: lines, circles, ellipses,
  33.   arcs and splines.  Splines are approximated as short lines by iterating
  34.   a simple approximation algorithm.  This seems good enough for previewing.
  35.  
  36.   David Evans <dre@cs.nott.ac.uk>, 14th March, 1990
  37. */
  38.  
  39. #include <X11/Xos.h>
  40. #include <X11/IntrinsicP.h>
  41. #include <X11/StringDefs.h>
  42. #include <stdio.h>
  43. #include <ctype.h>
  44. #include <math.h>
  45. #include "DviP.h"
  46.  
  47. #if defined(ISC) && defined(SYSV) && defined(SYSV386) && __STDC__
  48. extern double atof(char *);
  49. #endif
  50.  
  51. #ifndef M_PI
  52. #define M_PI 3.14159265358979323846264338327950
  53. #endif
  54.  
  55. /*    the following are for use in the spline approximation algorithm */
  56.  
  57. typedef struct    Point {
  58.     double    x;
  59.     double    y;
  60.     struct Point    *next;
  61. } Point;
  62.  
  63. #define    ITERATIONS    10    /* iterations to approximate spline */
  64.  
  65. #define    midx(p,q)    ((p->x + q->x) / 2)    /* mid x point on pq */
  66. #define    midy(p,q)    ((p->y + q->y) / 2)    /* mid y point on pq */
  67.  
  68. #define    length(p,q)    sqrt(((q->x - p->x)*(q->x - p->x)) \
  69.                  + ((q->y - p->y)*(q->y - p->y))) /* length of pq */
  70.  
  71. Point    *spline = (Point *)NULL;    /* head of spline linked list */
  72. Point    *MakePoint();
  73.  
  74.  
  75. HorizontalMove(dw, delta)
  76.     DviWidget    dw;
  77.     int        delta;
  78. {
  79.     dw->dvi.state->x += delta;
  80. }
  81.  
  82. HorizontalGoto(dw, NewPosition)
  83.     DviWidget    dw;
  84.     int        NewPosition;
  85. {
  86.     dw->dvi.state->x = NewPosition;
  87. }
  88.  
  89. VerticalMove(dw, delta)
  90.     DviWidget    dw;
  91.     int        delta;
  92. {
  93.     dw->dvi.state->y += delta;
  94. }
  95.  
  96. VerticalGoto(dw, NewPosition)
  97.     DviWidget    dw;
  98.     int        NewPosition;
  99. {
  100.     dw->dvi.state->y = NewPosition;
  101. }
  102.  
  103. FlushCharCache (dw)
  104.     DviWidget    dw;
  105. {
  106.     int        xx, yx;
  107.  
  108.     xx = ToX(dw, dw->dvi.state->x);
  109.     yx = ToX(dw, dw->dvi.state->y);
  110.     if (dw->dvi.cache.char_index != 0)
  111.     XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  112.             dw->dvi.cache.start_x, dw->dvi.cache.start_y,
  113.             dw->dvi.cache.cache, dw->dvi.cache.index + 1);
  114.     dw->dvi.cache.index = 0;
  115.     dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
  116.     if (dw->dvi.noPolyText)
  117.     dw->dvi.cache.max = 1;
  118.     dw->dvi.cache.char_index = 0;
  119.     dw->dvi.cache.cache[0].nchars = 0;
  120.     dw->dvi.cache.start_x = dw->dvi.cache.x = xx;
  121.     dw->dvi.cache.start_y = dw->dvi.cache.y = yx;
  122. }
  123.  
  124. ClearPage (dw)
  125.     DviWidget    dw;
  126. {
  127.     if (dw->dvi.display_enable)
  128.     XClearWindow (XtDisplay (dw), XtWindow (dw));
  129. }
  130.  
  131. SetGCForDraw (dw)
  132.     DviWidget    dw;
  133. {
  134.     int    lw;
  135.     if (dw->dvi.state->line_style != dw->dvi.line_style ||
  136.     dw->dvi.state->line_width != dw->dvi.line_width)
  137.     {
  138.     lw = ToX(dw, dw->dvi.state->line_width);
  139.     if (lw <= 1)
  140.         lw = 0;
  141.     XSetLineAttributes (XtDisplay (dw), dw->dvi.normal_GC,
  142.                 lw, LineSolid, CapButt, JoinMiter);
  143.     dw->dvi.line_style = dw->dvi.state->line_style;
  144.     dw->dvi.line_width = dw->dvi.state->line_width;
  145.     }
  146. }
  147.  
  148. DrawLine (dw, x, y)
  149.     DviWidget    dw;
  150.     int        x, y;
  151. {
  152.     if (dw->dvi.display_enable)
  153.     XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  154.            ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y),
  155.            ToX(dw, dw->dvi.state->x + x), ToX(dw,dw->dvi.state->y + y));
  156.     dw->dvi.state->x += x;
  157.     dw->dvi.state->y += y;
  158. }
  159.  
  160. DrawCircle (dw, diameter)
  161.     DviWidget    dw;
  162.     int        diameter;
  163. {
  164.     if (dw->dvi.display_enable)
  165.         XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  166.                 ToX(dw, dw->dvi.state->x),
  167.                 ToX(dw, dw->dvi.state->y - (diameter / 2)),
  168.                 ToX(dw, diameter), ToX(dw, diameter), 0, 360 * 64);
  169.     dw->dvi.state->x += diameter;
  170. }
  171.  
  172. DrawEllipse (dw, a, b)
  173.     DviWidget    dw;
  174.     int        a, b;
  175. {
  176.     if (dw->dvi.display_enable)
  177.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  178.           ToX(dw, dw->dvi.state->x), ToX(dw, dw->dvi.state->y - (b / 2)),
  179.           ToX(dw,a), ToX(dw,b), 0, 360 * 64);
  180.     dw->dvi.state->x += a;
  181. }
  182.  
  183.  
  184. /*    Convert angle in degrees to 64ths of a degree */
  185.  
  186. ConvertAngle(theta)
  187. int theta;
  188. {
  189.     return(theta * 64);
  190. }
  191.  
  192. DrawArc (dw, x0, y0, x1, y1)
  193.     DviWidget    dw;
  194.     int        x0, y0, x1, y1;
  195. {
  196.     int    xc, yc, x2, y2, r;
  197.     int    angle1, angle2;
  198.  
  199.     /* centre */
  200.     xc = dw->dvi.state->x + x0;
  201.     yc = dw->dvi.state->y + y0;
  202.  
  203.     /* to */
  204.     x2 = xc + x1;
  205.     y2 = yc + y1;
  206.  
  207.     dw->dvi.state->x = x2;
  208.     dw->dvi.state->y = y2;
  209.  
  210.     if (dw->dvi.display_enable) {
  211.  
  212.     /* radius */
  213.     r = (int)sqrt((float) x1 * x1 + (float) y1 * y1);
  214.  
  215.     /* start and finish angles */
  216.     if (x0 == 0) {
  217.         if (y0 >= 0)
  218.             angle1 = 90;
  219.         else
  220.             angle1 = 270;
  221.     }
  222.     else {
  223.         angle1 = (int) (atan((double)(y0) / (double)(x0)) * 180 / M_PI);
  224.         if (x0 > 0)
  225.             angle1 = 180 - angle1;
  226.         else
  227.             angle1 = -angle1;
  228.     }
  229.  
  230.     if (x1 == 0) {
  231.         if (y1 <= 0)
  232.             angle2 = 90;
  233.         else
  234.             angle2 = 270;
  235.     }
  236.     else {
  237.         angle2 = (int) (atan((double)(y1) / (double)(x1)) * 180 / M_PI);
  238.         if (x1 < 0)
  239.             angle2 = 180 - angle2;
  240.         else
  241.             angle2 = -angle2;
  242.     }
  243.  
  244.     if (angle1 < 0)
  245.         angle1 += 360;
  246.     if (angle2 < 0)
  247.         angle2 += 360;
  248.  
  249.     if (angle2 < angle1)
  250.         angle1 -= 360;
  251.     angle2 = angle2 - angle1;
  252.  
  253.     angle1 = ConvertAngle(angle1);
  254.     angle2 = ConvertAngle(angle2);
  255.  
  256.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  257.           ToX(dw, xc - r), ToX(dw, yc - r),
  258.           ToX(dw, 2 * r), ToX(dw, 2 * r),
  259.           angle1, angle2);
  260.     }
  261. }
  262.  
  263. /* copy next non-blank string from p to temp, update p */
  264.  
  265. char *getstr(p, temp)
  266. char *p, *temp;
  267. {
  268.     while (*p == ' ' || *p == '\t' || *p == '\n')
  269.     p++;
  270.     if (*p == '\0') {
  271.     temp[0] = 0;
  272.     return((char *)NULL);
  273.     }
  274.     while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
  275.     *temp++ = *p++;
  276.     *temp = '\0';
  277.     return(p);
  278. }
  279.  
  280.  
  281. /*    Draw a spline by approximating with short lines.      */
  282.  
  283. /*ARGSUSED*/
  284. DrawSpline (dw, s, len)
  285.     DviWidget    dw;
  286.     char        *s;
  287.     int        len;
  288. {
  289.     int        n;
  290.  
  291.     /* get coordinate pairs into spline linked list */
  292.     if ((n = GetSpline(s)) <= 0)
  293.     return;
  294.  
  295.     ApproxSpline(n);
  296.  
  297.     DrawSplineSegments(dw);
  298. }
  299.  
  300.  
  301. /*    Parse string s to create a linked list of Point's with spline */
  302. /*    as its head.  Return the number of coordinate pairs found.    */
  303.  
  304. GetSpline(s)
  305.     char *s;
  306. {
  307.     double    x, y, x1, y1;
  308.     int        n = 0;
  309.     Point    *pt;
  310.     char    *p = s, d[10];
  311.  
  312.     if (!*p)
  313.     return(n);
  314.  
  315.     pt = spline = MakePoint(0.0, 0.0);
  316.     n = 1;
  317.     x = y = 0.0;
  318.     p = s;
  319.     while (p && *p) {
  320.     if ((p = getstr(p, d)) == (char *)NULL)
  321.         break;
  322.     x1 = x + atof(d);
  323.     if ((p = getstr(p, d)) == (char *)NULL)
  324.         break;
  325.     y1 = y + atof(d);
  326.     pt->next = MakePoint(x1, y1);
  327.     pt = pt->next;
  328.     x = pt->x;
  329.     y = pt->y;
  330.     n++;
  331.     }
  332.  
  333.     /* number of pairs of points */
  334.  
  335.     return(n);
  336. }
  337.  
  338. /*    Approximate a spline by lines generated by iterations of the      */
  339. /*    approximation algorithm from the original n points in the spline. */
  340.  
  341. ApproxSpline(n)
  342. int n;
  343. {
  344.     int        mid, j;
  345.     Point    *p1, *p2, *p3, *p;
  346.  
  347.     if (n < 3)
  348.     return;
  349.  
  350.     /* number of mid-points to calculate */
  351.     mid = n - 3;
  352.  
  353.     /* remember original points are stored as an array of n points */
  354.     /* so I can index it directly to calculate mid-points only.       */
  355.     if (mid > 0) {
  356.     p = spline->next;
  357.     j = 1;
  358.     while (j < n-2) {
  359.         p1 = p;
  360.         p = p->next;
  361.         p2 = p;
  362.         InsertPoint(p1, MakePoint(midx(p1, p2), midy(p1, p2)));
  363.         j++;
  364.     }
  365.     }
  366.  
  367.     /* Now approximate curve by line segments.           */
  368.     /* There *should* be the correct number of points now! */
  369.  
  370.     p = spline;
  371.     while (p != (Point *)NULL) {
  372.     p1 = p;
  373.     if ((p = p->next) == (Point *)NULL)
  374.         break;
  375.     p2 = p;
  376.     if ((p = p->next) == (Point *)NULL)
  377.         break;
  378.     p3 = p;        /* This point becomes first point of next curve */
  379.  
  380.     LineApprox(p1, p2, p3);
  381.     }
  382. }
  383.  
  384.  
  385. /*    p1, p2, and p3 are initially 3 *consecutive* points on the curve. */
  386. /*    For each adjacent pair of points find the mid-point, insert this  */
  387. /*    in the linked list, delete the first of the two used (unless it   */
  388. /*    is the first for this curve).  Repeat this ITERATIONS times.      */
  389.  
  390. /*ARGSUSED*/
  391. LineApprox(p1, p2, p3)
  392. Point    *p1, *p2, *p3;
  393. {
  394.     Point    *p4, *p;
  395.     int        reps = ITERATIONS;
  396.  
  397.     while (reps) {
  398.     for (p = p1; p != (Point *)NULL && p != p3; ) {
  399.         InsertPoint(p, p4 = MakePoint( midx(p,p->next), midy(p,p->next) ));
  400.         if (p != p1)
  401.         DeletePoint(p);
  402.         p = p4->next;        /* skip inserted point! */
  403.     }
  404.     reps--;
  405.     }
  406. }
  407.  
  408.  
  409. /*    Traverse the linked list, calling DrawLine to approximate the */
  410. /*    spline curve.  Rounding errors are taken into account so that */
  411. /*    the "curve" is continuous, and ends up where expected.          */
  412.  
  413. DrawSplineSegments(dw)
  414. DviWidget dw;
  415. {
  416.     Point    *p, *q;
  417.     double    x1, y1;
  418.     int        dx, dy;
  419.     double    xpos, ypos;
  420.  
  421.     p = spline;
  422.     dx = dy = 0;
  423.  
  424.     /* save the start position */
  425.  
  426.     xpos = dw->dvi.state->x;
  427.     ypos = dw->dvi.state->y;
  428.  
  429.     x1 = y1 = 0.0;
  430.  
  431.     while (p != (Point *)NULL) {
  432.     dx = p->x - x1 + 0.5;
  433.     dy = p->y - y1 + 0.5;
  434.     DrawLine (dw, dx, dy);
  435.  
  436.     x1 = p->x;
  437.     y1 = p->y;
  438.     dw->dvi.state->x = xpos + x1;
  439.     dw->dvi.state->y = ypos + y1;
  440.  
  441.     q = p;
  442.     p = p->next;
  443.     XtFree((char *)q);
  444.     }
  445.     spline = (Point *)NULL;
  446. }
  447.  
  448.  
  449. /*    Malloc memory for a Point, and initialise the elements to x, y, NULL */
  450. /*    Return a pointer to the new Point.                     */
  451.  
  452. Point *MakePoint(x, y)
  453. double x, y;
  454. {
  455.     Point    *p;
  456.  
  457.     p = (Point *) XtMalloc (sizeof (Point));
  458.     p->x = x;
  459.     p->y = y;
  460.     p->next = (Point *)NULL;
  461.  
  462.     return(p);
  463. }
  464.  
  465.  
  466. /*    Insert point q in linked list after point p. */
  467.  
  468. InsertPoint(p, q)
  469. Point *p, *q;
  470. {
  471.     /* point q to the next point */
  472.     q->next = p->next;
  473.  
  474.     /* point p to new inserted one */
  475.     p->next = q;
  476. }
  477.  
  478. /*    Delete point p from the linked list. */
  479.  
  480. DeletePoint(p)
  481. Point    *p;
  482. {
  483.     Point    *tmp;
  484.  
  485.     tmp = p->next;
  486.     p->x = p->next->x;
  487.     p->y = p->next->y;
  488.     p->next = p->next->next;
  489.     XtFree((char *)tmp);
  490. }
  491.  
  492.