1*25858Sslatteng /* draw.c 1.11 86/01/12
214924Sslatteng *
314924Sslatteng * This file contains the functions for producing the graphics
415347Sslatteng * images in the canon/imagen driver for ditroff.
514924Sslatteng */
614924Sslatteng
714924Sslatteng
814924Sslatteng #include <stdio.h>
914924Sslatteng #include <ctype.h>
1014924Sslatteng #include <math.h>
1114924Sslatteng #include "canon.h"
1214924Sslatteng
1314924Sslatteng /* imports from dip.c */
1416187Sslatteng #define FATAL 1
1514924Sslatteng #define hmot(n) hpos += n;
1614924Sslatteng #define hgoto(n) hpos = n;
1714924Sslatteng #define vmot(n) vpos += n;
1814924Sslatteng #define vgoto(n) vpos = n;
1914924Sslatteng
2015622Sslatteng extern int output;
2114924Sslatteng extern int hpos;
2214924Sslatteng extern int vpos;
2314924Sslatteng extern int MAXX;
2414924Sslatteng extern int MAXY;
2514924Sslatteng extern FILE *tf;
2614924Sslatteng extern putint();
2714924Sslatteng
2814924Sslatteng #define word(x) putint(x,tf)
2914924Sslatteng #define byte(x) putc(x,tf)
3014924Sslatteng #define MAXPOINTS 200 /* number of points legal for a curve */
3114924Sslatteng
3214924Sslatteng #define SOLID -1 /* line styles: these are used as bit masks to */
3314924Sslatteng #define DOTTED 004 /* create the right style lines. */
3414924Sslatteng #define DASHED 020
3514924Sslatteng #define DOTDASHED 024
3614924Sslatteng #define LONGDASHED 074
3714924Sslatteng /* constants... */
3814924Sslatteng #define pi 3.14159265358979324
3914924Sslatteng
4014924Sslatteng #define START 1
4114924Sslatteng #define POINT 0
4215347Sslatteng /* the imagen complains if a path is drawn at < 1, or > limit, so truncate. */
4316030Sslatteng #define xbound(x) ((x) < 1 ? 1 : (x) > MAXX ? MAXX : (x))
4416030Sslatteng #define ybound(y) ((y) < 1 ? 1 : (y) > MAXY ? MAXY : (y))
4514924Sslatteng
4614924Sslatteng
4714924Sslatteng int linethickness = -1; /* number of pixels wide to make lines */
4814924Sslatteng int linmod = SOLID; /* type of line (SOLID, DOTTED, DASHED...) */
4916461Sslatteng int polyborder = 1; /* flag for whether or not to draw a border */
5014924Sslatteng
5114924Sslatteng
5214924Sslatteng
5314924Sslatteng /*----------------------------------------------------------------------------
5414924Sslatteng | Routine: drawline (horizontal_motion, vertical_motion)
5514924Sslatteng |
5614924Sslatteng | Results: Draws a line of "linethickness" width and "linmod" style
5714924Sslatteng | from current (hpos, vpos) to (hpos + dh, vpos + dv).
5814924Sslatteng |
5914924Sslatteng | Side Efct: Resulting position is at end of line (hpos + dh, vpos + dv)
6014924Sslatteng *----------------------------------------------------------------------------*/
6114924Sslatteng
drawline(dh,dv)6214924Sslatteng drawline(dh, dv)
6314924Sslatteng register int dh;
6414924Sslatteng register int dv;
6514924Sslatteng {
6615622Sslatteng if (output) HGtline (hpos, vpos, hpos + dh, vpos + dv);
6714924Sslatteng hmot (dh); /* new position is at */
6814924Sslatteng vmot (dv); /* the end of the line */
6914924Sslatteng }
7014924Sslatteng
7114924Sslatteng
7214924Sslatteng /*----------------------------------------------------------------------------
7314924Sslatteng | Routine: drawcirc (diameter)
7414924Sslatteng |
7514924Sslatteng | Results: Draws a circle with leftmost point at current (hpos, vpos)
7614924Sslatteng | with the given diameter d.
7714924Sslatteng |
7814924Sslatteng | Side Efct: Resulting position is at (hpos + diameter, vpos)
7914924Sslatteng *----------------------------------------------------------------------------*/
8014924Sslatteng
drawcirc(d)8114924Sslatteng drawcirc(d)
8214924Sslatteng register int d;
8314924Sslatteng { /* 0.0 is the angle to sweep the arc: = full circle */
8415622Sslatteng if (output) HGArc (hpos + d/2, vpos, hpos, vpos, 0.0);
8514924Sslatteng hmot (d); /* new postion is the right of the circle */
8614924Sslatteng }
8714924Sslatteng
8814924Sslatteng
8914924Sslatteng /*----------------------------------------------------------------------------
9014924Sslatteng | Routine: drawellip (horizontal_diameter, vertical_diameter)
9114924Sslatteng |
9214924Sslatteng | Results: Draws regular ellipses given the major "diameters." It does
9316388Sslatteng | so by drawing many small lines along the ellipses perimeter.
9416388Sslatteng | The algorithm is a modified (bresenham-like) circle algorithm
9514924Sslatteng |
9614924Sslatteng | Side Efct: Resulting position is at (hpos + hd, vpos).
9714924Sslatteng |
9814924Sslatteng | Bugs: Odd numbered horizontal axes are rounded up to even numbers.
9914924Sslatteng *----------------------------------------------------------------------------*/
10014924Sslatteng
drawellip(hd,vd)10114924Sslatteng drawellip(hd, vd)
10225608Sslatteng register int hd;
10325608Sslatteng register int vd;
10414924Sslatteng {
10516388Sslatteng double xs, ys, xepsilon, yepsilon; /* ellipse-calculation vairables */
10616388Sslatteng register int basex; /* center of the ellipse */
10716388Sslatteng register int basey;
10816388Sslatteng register int extent; /* number of points to produce */
10914924Sslatteng
11014924Sslatteng
11125608Sslatteng basex = hpos; /* set the center of the ellipse */
11216388Sslatteng basey = vpos;
11316388Sslatteng hmot (hd); /* troff motion done here, once. */
11425608Sslatteng if (!output) return;
11516388Sslatteng if ((hd = hd >> 1) < 1) hd = 1; /* hd and vd are like radii */
11625608Sslatteng basex += ++hd;
11716388Sslatteng if ((vd = vd >> 1) < 1) vd = 1;
11825608Sslatteng ys = (double) ++vd; /* initial distances from center to perimeter */
11916388Sslatteng xs = 0.0;
12016388Sslatteng /* calculate drawing parameters */
12116388Sslatteng if (vd > hd) {
12225608Sslatteng xepsilon = 4.0 * (double) hd / (double) (vd * vd);
12325608Sslatteng yepsilon = 4.0 / (double) hd;
12425608Sslatteng extent = (int) (1.575 * (double) vd);
12516388Sslatteng } else {
12625608Sslatteng xepsilon = 4.0 / (double) vd;
12725608Sslatteng yepsilon = 4.0 * (double) vd / (double) (hd * hd);
12825608Sslatteng extent = (int) (1.575 * (double) hd);
12915622Sslatteng }
13014924Sslatteng
13116388Sslatteng byte(ASPATH); /* start path definition */
13225608Sslatteng word(1 + extent); /* number of points */
13316388Sslatteng word(xbound(basex));
13425608Sslatteng vd += basey;
13525608Sslatteng word(ybound(vd));
13625608Sslatteng while (extent--) {
13716388Sslatteng xs += xepsilon * ys;
13816388Sslatteng ys -= yepsilon * xs;
13925608Sslatteng hd = basex + (int) xs;
14025608Sslatteng vd = basey + (int) ys;
14125608Sslatteng word(xbound(hd)); /* put out a point on ellipse */
142*25858Sslatteng word(ybound(vd));
14315622Sslatteng }
14416388Sslatteng byte(ADRAW); /* now draw the arc */
14514924Sslatteng byte(15);
14614924Sslatteng }
14714924Sslatteng
14814924Sslatteng
14914924Sslatteng /*----------------------------------------------------------------------------
15014924Sslatteng | Routine: drawarc (xcenter, ycenter, xpoint, ypoint)
15114924Sslatteng |
15214924Sslatteng | Results: Draws an arc starting at current (hpos, vpos). Center is
15314924Sslatteng | at (hpos + cdh, vpos + cdv) and the terminating point is
15414924Sslatteng | at <center> + (pdh, pdv). The angle between the lines
15514924Sslatteng | formed by the starting, ending, and center points is figured
15614924Sslatteng | first, then the points and angle are sent to HGArc for the
15714924Sslatteng | drawing.
15814924Sslatteng |
15914924Sslatteng | Side Efct: Resulting position is at the last point of the arc.
16014924Sslatteng *----------------------------------------------------------------------------*/
16114924Sslatteng
drawarc(cdh,cdv,pdh,pdv)16214924Sslatteng drawarc (cdh, cdv, pdh, pdv)
16314924Sslatteng register int cdh;
16414924Sslatteng register int cdv;
16514924Sslatteng register int pdh;
16614924Sslatteng register int pdv;
16714924Sslatteng {
16814924Sslatteng register double angle;
16914924Sslatteng /* figure angle from the three points...*/
17014924Sslatteng /* and convert (and round) to degrees */
17114924Sslatteng angle = (atan2((double) pdh, (double) pdv)
17214924Sslatteng - atan2 ((double) -cdh, (double) -cdv)) * 180.0 / pi;
17314924Sslatteng /* "normalize" and round */
17414924Sslatteng angle += (angle < 0.0) ? 360.5 : 0.5;
17514924Sslatteng
17615622Sslatteng if (output) HGArc(hpos + cdh, vpos + cdv, hpos, vpos, (int) angle);
17714924Sslatteng hmot(cdh + pdh);
17814924Sslatteng vmot(cdv + pdv);
17914924Sslatteng }
18014924Sslatteng
18114924Sslatteng
18214924Sslatteng /*----------------------------------------------------------------------------
18314924Sslatteng | Routine: drawwig (character_buffer, file_pointer, type_flag)
18414924Sslatteng |
18514924Sslatteng | Results: Given the starting position, the motion list in buf, and any
18614924Sslatteng | extra characters from fp (terminated by a \n), drawwig sets
18717428Sslatteng | up a point list to make a spline or polygon from. If "pic" is
18817428Sslatteng | zero, a gremlin curve is drawn with HGCurve; if less than zero
18917428Sslatteng | a polygon is drawn, else (pic > 0) a pic style spline is drawn
19017428Sslatteng | using picurve.
19114924Sslatteng |
19214924Sslatteng | Side Efct: Resulting position is reached from adding successive motions
19314924Sslatteng | to the current position.
19414924Sslatteng *----------------------------------------------------------------------------*/
19514924Sslatteng
drawwig(buf,fp,pic)19614924Sslatteng drawwig (buf, fp, pic)
19714924Sslatteng char *buf;
19814924Sslatteng FILE *fp;
19914924Sslatteng int pic;
20014924Sslatteng {
20114924Sslatteng register int len = strlen(buf); /* length of the string in "buf" */
20214924Sslatteng register int npts = 2; /* point list index */
20314924Sslatteng register char *ptr = buf; /* "walking" pointer into buf */
20414924Sslatteng int x[MAXPOINTS], y[MAXPOINTS]; /* point list */
20514924Sslatteng
20614924Sslatteng while (*ptr == ' ') ptr++; /* skip any leading spaces */
20714924Sslatteng x[1] = hpos; /* the curve starts at the */
20814924Sslatteng y[1] = vpos; /* current position */
20914924Sslatteng
21014924Sslatteng while (*ptr != '\n') { /* curve commands end with a '\n' */
21114924Sslatteng hmot(atoi(ptr)); /* convert motion to curve points */
21214924Sslatteng x[npts] = hpos; /* and remember them */
21314924Sslatteng while (isdigit(*++ptr)); /* skip number*/
21414924Sslatteng while (*++ptr == ' '); /* skip spaces 'tween numbers */
21514924Sslatteng vmot(atoi(ptr));
21614924Sslatteng y[npts] = vpos;
21714924Sslatteng while (isdigit(*++ptr));
21814924Sslatteng while (*ptr == ' ') ptr++;
21914924Sslatteng /* if the amount we read wasn't the */
22014924Sslatteng /* whole thing, read some more in */
22114924Sslatteng if (len - (ptr - buf) < 15 && *(buf + len - 1) != '\n') {
22214924Sslatteng char *cop = buf;
22314924Sslatteng
22414924Sslatteng while (*cop++ = *ptr++); /* copy what's left to the beginning */
22516187Sslatteng if (fgets ((cop - 1), len - (cop - buf), fp) == NULL)
22616187Sslatteng error (FATAL, "unexpected end of input");
22714924Sslatteng ptr = buf;
22814924Sslatteng }
22914924Sslatteng if (npts < MAXPOINTS - 1) /* if too many points, forget some */
23014924Sslatteng npts++;
23114924Sslatteng }
23214924Sslatteng npts--; /* npts must point to the last coordinate in x and y */
23314924Sslatteng /* now, actually DO the curve */
23415622Sslatteng if (output) {
23516388Sslatteng if (pic > 0)
23625608Sslatteng picurve(&x[0], &y[0], npts);
23716388Sslatteng else if (pic < 0)
23825608Sslatteng polygon(&x[0], &y[0], npts);
23915622Sslatteng else
24025608Sslatteng HGCurve(&x[0], &y[0], npts);
24115622Sslatteng }
24214924Sslatteng }
24314924Sslatteng
24414924Sslatteng
24514924Sslatteng /*----------------------------------------------------------------------------*
24614924Sslatteng | Routine: drawthick (thickness)
24714924Sslatteng |
24814924Sslatteng | Results: sets the variable "linethickness" to the given size. If this
24914924Sslatteng | is different than previous thiknesses, informs Imagen of the
25014924Sslatteng | change. NO motion is involved.
25114924Sslatteng *----------------------------------------------------------------------------*/
25214924Sslatteng
drawthick(s)25314924Sslatteng drawthick(s)
25414924Sslatteng int s;
25514924Sslatteng {
25614924Sslatteng if (linethickness != s) {
25714924Sslatteng byte(ASPEN);
25814924Sslatteng byte((linethickness = s) < 1 ? 1 : linethickness > MAXPENW ?
25914924Sslatteng MAXPENW : linethickness);
26014924Sslatteng }
26114924Sslatteng }
26214924Sslatteng
26314924Sslatteng
26414924Sslatteng /*----------------------------------------------------------------------------*
26514924Sslatteng | Routine: drawstyle (style_bit_map)
26614924Sslatteng |
26714924Sslatteng | Results: sets the variable "linmod" to the given bit map.
26814924Sslatteng | NO motion is involved.
26914924Sslatteng *----------------------------------------------------------------------------*/
27014924Sslatteng
drawstyle(s)27114924Sslatteng drawstyle(s)
27214924Sslatteng int s;
27314924Sslatteng {
27414924Sslatteng linmod = s;
27514924Sslatteng }
27614924Sslatteng
27714924Sslatteng
27816388Sslatteng /*----------------------------------------------------------------------------*
27916388Sslatteng | Routine: polygon (xpoints, ypoints, num_of_points)
28016388Sslatteng |
28116388Sslatteng | Results: draws a polygon through the points (xpoints, ypoints).
28216388Sslatteng | The polygon has a raster fill associated with it. The
28316388Sslatteng | fill is already set up from conv(), but if the stipple
28416388Sslatteng | pattern "laststipmem" is zero, polygon draws a "clear"
28516388Sslatteng | polygon.
28616388Sslatteng |
28716388Sslatteng | Bugs: If the path is not closed, polygon will NOT close it.
28816388Sslatteng | (or is that a feature?)
28917428Sslatteng | self-interseting polygons can choke the Imagen - tough luck
29016388Sslatteng | if the path is "counterclockwise", it'll slow down the
29117428Sslatteng | rendering. This is not checked for here.
29216388Sslatteng *----------------------------------------------------------------------------*/
29316388Sslatteng
29416388Sslatteng extern int laststipmem; /* this is set, before this routine, to the */
29516388Sslatteng /* stipple member number to be printed. If */
29616388Sslatteng /* it's zero, the path should not be filled */
polygon(x,y,npts)29716388Sslatteng polygon(x, y, npts)
29825608Sslatteng register int *x;
29925608Sslatteng register int *y;
30025608Sslatteng register int npts;
30116388Sslatteng {
30216388Sslatteng register int i;
30316388Sslatteng
30417428Sslatteng if (polyborder && linmod != SOLID) { /* if the border isn't solid */
30517428Sslatteng for (i = 2; i <= npts; i++) /* have HGtline draw it */
30617428Sslatteng HGtline(x[i-1], y[i-1], x[i], y[i]);
30717428Sslatteng }
30816388Sslatteng byte(ASPATH); /* set up to send the path */
30916388Sslatteng word(npts);
31025608Sslatteng while (npts--) { /* send the path */
31125608Sslatteng x++;
31225608Sslatteng y++;
31325608Sslatteng word(xbound(*x));
31425608Sslatteng word(ybound(*y));
31516388Sslatteng }
31617428Sslatteng if (polyborder && linmod == SOLID) {
31716461Sslatteng byte(ADRAW); /* draw the border, if requested */
31816461Sslatteng byte(15);
31916461Sslatteng }
32016388Sslatteng if (laststipmem) { /* draw a filled path, if requested */
32116388Sslatteng byte(AFPATH);
32216388Sslatteng byte(7);
32316388Sslatteng }
32416388Sslatteng }
32516388Sslatteng
32616388Sslatteng
32714924Sslatteng /*----------------------------------------------------------------------------
32814924Sslatteng | Routine: picurve (xpoints, ypoints, num_of_points)
32914924Sslatteng |
33014924Sslatteng | Results: Draws a curve delimited by (not through) the line segments
33114924Sslatteng | traced by (xpoints, ypoints) point list. This is the "Pic"
33214924Sslatteng | style curve.
33314924Sslatteng *----------------------------------------------------------------------------*/
33414924Sslatteng
picurve(x,y,npts)33514924Sslatteng picurve (x, y, npts)
33625608Sslatteng register int *x;
33725608Sslatteng register int *y;
33814924Sslatteng int npts;
33914924Sslatteng {
34025608Sslatteng register int nseg; /* effective resolution for each curve */
34125608Sslatteng register int xp; /* current point (and temporary) */
34214924Sslatteng register int yp;
34325608Sslatteng int pxp, pyp; /* previous point (to make lines from) */
34425608Sslatteng int i; /* inner curve segment traverser */
34525608Sslatteng double w; /* position factor */
34625608Sslatteng double t1, t2, t3; /* calculation temps */
34714924Sslatteng
34814924Sslatteng
34914924Sslatteng if (x[1] == x[npts] && y[1] == y[npts]) {
35014924Sslatteng x[0] = x[npts - 1]; /* if the lines' ends meet, make */
35114924Sslatteng y[0] = y[npts - 1]; /* sure the curve meets */
35214924Sslatteng x[npts + 1] = x[2];
35314924Sslatteng y[npts + 1] = y[2];
35414924Sslatteng } else { /* otherwise, make the ends of the */
35514924Sslatteng x[0] = x[1]; /* curve touch the ending points of */
35614924Sslatteng y[0] = y[1]; /* the line segments */
35714924Sslatteng x[npts + 1] = x[npts];
35814924Sslatteng y[npts + 1] = y[npts];
35914924Sslatteng }
36014924Sslatteng
36125608Sslatteng pxp = (x[0] + x[1]) / 2; /* make the last point pointers */
36225608Sslatteng pyp = (y[0] + y[1]) / 2; /* point to the start of the 1st line */
36325608Sslatteng
36425608Sslatteng for (; npts--; x++, y++) { /* traverse the line segments */
36525608Sslatteng xp = x[0] - x[1];
36625608Sslatteng yp = y[0] - y[1];
36714924Sslatteng nseg = (int) sqrt((double)(xp * xp + yp * yp));
36825608Sslatteng xp = x[1] - x[2];
36925608Sslatteng yp = y[1] - y[2]; /* "nseg" is the number of line */
37014924Sslatteng /* segments that will be drawn for */
37125608Sslatteng /* each curve segment. ">> 4" is */
37225608Sslatteng /* dropping the resolution ( == / 16) */
37325608Sslatteng nseg = (nseg + (int) sqrt((double)(xp * xp + yp * yp))) >> 4;
37414924Sslatteng
37525608Sslatteng for (i = 1; i < nseg; i++) {
37625608Sslatteng w = (double) i / (double) nseg;
37725608Sslatteng t1 = w * w;
37825608Sslatteng t3 = t1 + 1.0 - (w + w);
37925608Sslatteng t2 = 2.0 - (t3 + t1);
38025608Sslatteng xp = (((int) (t1 * x[2] + t2 * x[1] + t3 * x[0])) + 1) / 2;
38125608Sslatteng yp = (((int) (t1 * y[2] + t2 * y[1] + t3 * y[0])) + 1) / 2;
38225608Sslatteng
38325608Sslatteng HGtline(pxp, pyp, xp, yp);
38416030Sslatteng pxp = xp;
38516030Sslatteng pyp = yp;
38614924Sslatteng }
38714924Sslatteng }
38814924Sslatteng }
38914924Sslatteng
39014924Sslatteng
39114924Sslatteng /*----------------------------------------------------------------------------
39214924Sslatteng | Routine: HGArc (xcenter, ycenter, xstart, ystart, angle)
39314924Sslatteng |
39414924Sslatteng | Results: This routine plots an arc centered about (cx, cy) counter
39514924Sslatteng | clockwise starting from the point (px, py) through 'angle'
39614924Sslatteng | degrees. If angle is 0, a full circle is drawn. It does so
39714924Sslatteng | by creating a draw-path around the arc whose density of
39814924Sslatteng | points depends on the size of the arc.
39914924Sslatteng *----------------------------------------------------------------------------*/
40014924Sslatteng
HGArc(cx,cy,px,py,angle)40114924Sslatteng HGArc(cx,cy,px,py,angle)
40216030Sslatteng register int cx;
40316030Sslatteng register int cy;
40416030Sslatteng int px, py, angle;
40514924Sslatteng {
40614924Sslatteng double xs, ys, resolution, fullcircle;
40716030Sslatteng register int mask;
40814924Sslatteng register int extent;
40914924Sslatteng register int nx;
41014924Sslatteng register int ny;
41114924Sslatteng register double epsilon;
41214924Sslatteng
41314924Sslatteng xs = px - cx;
41414924Sslatteng ys = py - cy;
41514924Sslatteng
41616030Sslatteng /* calculate how fine to make the lines that build
41716030Sslatteng the circle. Resolution cannot be dropped, but
41816030Sslatteng mask is used to skip some points for larger
41916030Sslatteng arcs due to Imagen's path length limitations */
42014924Sslatteng
42116030Sslatteng resolution = sqrt(xs * xs + ys * ys);
42216030Sslatteng mask = (1 << (int) log10(resolution + 1.0)) - 1;
42316030Sslatteng
42414924Sslatteng epsilon = 1.0 / resolution;
42516030Sslatteng fullcircle = (2.0 * pi) * resolution;
42614924Sslatteng if (angle == 0)
42714924Sslatteng extent = fullcircle;
42814924Sslatteng else
42914924Sslatteng extent = angle * fullcircle / 360.0;
43014924Sslatteng
43114924Sslatteng byte(ASPATH); /* start path definition */
43214924Sslatteng if (extent > 1) {
43316030Sslatteng word(2 + (extent-1) / (mask+1)); /* number of points */
43416030Sslatteng word(xbound(px));
43516030Sslatteng word(ybound(py));
43616030Sslatteng while (--extent >= 0) {
43714924Sslatteng xs += epsilon * ys;
43816030Sslatteng nx = cx + (int) (xs + 0.5);
43914924Sslatteng ys -= epsilon * xs;
44016030Sslatteng ny = cy + (int) (ys + 0.5);
44116030Sslatteng if (!(extent&mask)) {
44216030Sslatteng word(xbound(nx)); /* put out a point on circle */
44316030Sslatteng word(ybound(ny));
44416030Sslatteng }
44514924Sslatteng } /* end for */
44614924Sslatteng } else { /* arc is too small: put out point */
44714924Sslatteng word(2);
44816030Sslatteng word(xbound(px));
44916030Sslatteng word(ybound(py));
45016030Sslatteng word(xbound(px));
45116030Sslatteng word(ybound(py));
45214924Sslatteng }
45314924Sslatteng byte(ADRAW); /* now draw the arc */
45414924Sslatteng byte(15);
45514924Sslatteng } /* end HGArc */
45614924Sslatteng
45714924Sslatteng
45814924Sslatteng /*----------------------------------------------------------------------------
45914924Sslatteng | Routine: Paramaterize (xpoints, ypoints, hparams, num_points)
46014924Sslatteng |
46114924Sslatteng | Results: This routine calculates parameteric values for use in
46214924Sslatteng | calculating curves. The parametric values are returned
46314924Sslatteng | in the array h. The values are an approximation of
46414924Sslatteng | cumulative arc lengths of the curve (uses cord length).
46514924Sslatteng | For additional information, see paper cited below.
46614924Sslatteng *----------------------------------------------------------------------------*/
46714924Sslatteng
Paramaterize(x,y,h,n)46814924Sslatteng static Paramaterize(x, y, h, n)
46914924Sslatteng int x[MAXPOINTS];
47014924Sslatteng int y[MAXPOINTS];
47114924Sslatteng float h[MAXPOINTS];
47214924Sslatteng int n;
47314924Sslatteng {
47414924Sslatteng register int dx;
47514924Sslatteng register int dy;
47614924Sslatteng register int i;
47714924Sslatteng register int j;
47814924Sslatteng float u[MAXPOINTS];
47914924Sslatteng
48014924Sslatteng
48114924Sslatteng for (i=1; i<=n; ++i) {
48214924Sslatteng u[i] = 0;
48314924Sslatteng for (j=1; j<i; j++) {
48414924Sslatteng dx = x[j+1] - x[j];
48514924Sslatteng dy = y[j+1] - y[j];
48614924Sslatteng u[i] += sqrt ((double) (dx * dx + dy * dy));
48714924Sslatteng }
48814924Sslatteng }
48914924Sslatteng for (i=1; i<n; ++i) h[i] = u[i+1] - u[i];
49014924Sslatteng } /* end Paramaterize */
49114924Sslatteng
49214924Sslatteng
49314924Sslatteng /*----------------------------------------------------------------------------
49414924Sslatteng | Routine: PeriodicSpline (h, z, dz, d2z, d3z, npoints)
49514924Sslatteng |
49614924Sslatteng | Results: This routine solves for the cubic polynomial to fit a
49714924Sslatteng | spline curve to the the points specified by the list
49814924Sslatteng | of values. The Curve generated is periodic. The algorithms
49914924Sslatteng | for this curve are from the "Spline Curve Techniques" paper
50014924Sslatteng | cited below.
50114924Sslatteng *----------------------------------------------------------------------------*/
50214924Sslatteng
PeriodicSpline(h,z,dz,d2z,d3z,npoints)50314924Sslatteng static PeriodicSpline(h, z, dz, d2z, d3z, npoints)
50414924Sslatteng float h[MAXPOINTS]; /* paramaterization */
50514924Sslatteng int z[MAXPOINTS]; /* point list */
50614924Sslatteng float dz[MAXPOINTS]; /* to return the 1st derivative */
50714924Sslatteng float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */
50814924Sslatteng int npoints; /* number of valid points */
50914924Sslatteng {
51014924Sslatteng float d[MAXPOINTS];
51114924Sslatteng float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
51214924Sslatteng float c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS];
51314924Sslatteng int i;
51414924Sslatteng
51514924Sslatteng /* step 1 */
51614924Sslatteng for (i=1; i<npoints; ++i) {
51714924Sslatteng deltaz[i] = h[i] ? ((double) (z[i+1] - z[i])) / h[i] : 0;
51814924Sslatteng }
51914924Sslatteng h[0] = h[npoints-1];
52014924Sslatteng deltaz[0] = deltaz[npoints-1];
52114924Sslatteng
52214924Sslatteng /* step 2 */
52314924Sslatteng for (i=1; i<npoints-1; ++i) {
52414924Sslatteng d[i] = deltaz[i+1] - deltaz[i];
52514924Sslatteng }
52614924Sslatteng d[0] = deltaz[1] - deltaz[0];
52714924Sslatteng
52814924Sslatteng /* step 3a */
52914924Sslatteng a[1] = 2 * (h[0] + h[1]);
53014924Sslatteng b[1] = d[0];
53114924Sslatteng c[1] = h[0];
53214924Sslatteng for (i=2; i<npoints-1; ++i) {
53314924Sslatteng a[i] = 2*(h[i-1]+h[i]) - pow ((double) h[i-1],(double)2.0) / a[i-1];
53414924Sslatteng b[i] = d[i-1] - h[i-1] * b[i-1]/a[i-1];
53514924Sslatteng c[i] = -h[i-1] * c[i-1]/a[i-1];
53614924Sslatteng }
53714924Sslatteng
53814924Sslatteng /* step 3b */
53914924Sslatteng r[npoints-1] = 1;
54014924Sslatteng s[npoints-1] = 0;
54114924Sslatteng for (i=npoints-2; i>0; --i) {
54214924Sslatteng r[i] = -(h[i] * r[i+1] + c[i])/a[i];
54314924Sslatteng s[i] = (6 * b[i] - h[i] * s[i+1])/a[i];
54414924Sslatteng }
54514924Sslatteng
54614924Sslatteng /* step 4 */
54714924Sslatteng d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1]
54814924Sslatteng - h[npoints-1] * s[npoints-2])
54914924Sslatteng / (h[0] * r[1] + h[npoints-1] * r[npoints-2]
55014924Sslatteng + 2 * (h[npoints-2] + h[0]));
55114924Sslatteng for (i=1; i<npoints-1; ++i) {
55214924Sslatteng d2z[i] = r[i] * d2z[npoints-1] + s[i];
55314924Sslatteng }
55414924Sslatteng d2z[npoints] = d2z[1];
55514924Sslatteng
55614924Sslatteng /* step 5 */
55714924Sslatteng for (i=1; i<npoints; ++i) {
55814924Sslatteng dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
55914924Sslatteng d3z[i] = h[i] ? (d2z[i+1] - d2z[i])/h[i] : 0;
56014924Sslatteng }
56114924Sslatteng } /* end PeriodicSpline */
56214924Sslatteng
56314924Sslatteng
56414924Sslatteng /*----------------------------------------------------------------------------
56514924Sslatteng | Routine: NaturalEndSpline (h, z, dz, d2z, d3z, npoints)
56614924Sslatteng |
56714924Sslatteng | Results: This routine solves for the cubic polynomial to fit a
56814924Sslatteng | spline curve the the points specified by the list of
56914924Sslatteng | values. The alogrithms for this curve are from the
57014924Sslatteng | "Spline Curve Techniques" paper cited below.
57114924Sslatteng *----------------------------------------------------------------------------*/
57214924Sslatteng
NaturalEndSpline(h,z,dz,d2z,d3z,npoints)57314924Sslatteng static NaturalEndSpline(h, z, dz, d2z, d3z, npoints)
57414924Sslatteng float h[MAXPOINTS]; /* parameterization */
57514924Sslatteng int z[MAXPOINTS]; /* Point list */
57614924Sslatteng float dz[MAXPOINTS]; /* to return the 1st derivative */
57714924Sslatteng float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */
57814924Sslatteng int npoints; /* number of valid points */
57914924Sslatteng {
58014924Sslatteng float d[MAXPOINTS];
58114924Sslatteng float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
58214924Sslatteng int i;
58314924Sslatteng
58414924Sslatteng /* step 1 */
58514924Sslatteng for (i=1; i<npoints; ++i) {
58614924Sslatteng deltaz[i] = h[i] ? ((double) (z[i+1] - z[i])) / h[i] : 0;
58714924Sslatteng }
58814924Sslatteng deltaz[0] = deltaz[npoints-1];
58914924Sslatteng
59014924Sslatteng /* step 2 */
59114924Sslatteng for (i=1; i<npoints-1; ++i) {
59214924Sslatteng d[i] = deltaz[i+1] - deltaz[i];
59314924Sslatteng }
59414924Sslatteng d[0] = deltaz[1] - deltaz[0];
59514924Sslatteng
59614924Sslatteng /* step 3 */
59714924Sslatteng a[0] = 2 * (h[2] + h[1]);
59814924Sslatteng b[0] = d[1];
59914924Sslatteng for (i=1; i<npoints-2; ++i) {
60014924Sslatteng a[i] = 2*(h[i+1]+h[i+2]) - pow((double) h[i+1],(double) 2.0)/a[i-1];
60114924Sslatteng b[i] = d[i+1] - h[i+1] * b[i-1]/a[i-1];
60214924Sslatteng }
60314924Sslatteng
60414924Sslatteng /* step 4 */
60514924Sslatteng d2z[npoints] = d2z[1] = 0;
60614924Sslatteng for (i=npoints-1; i>1; --i) {
60714924Sslatteng d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2];
60814924Sslatteng }
60914924Sslatteng
61014924Sslatteng /* step 5 */
61114924Sslatteng for (i=1; i<npoints; ++i) {
61214924Sslatteng dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
61314924Sslatteng d3z[i] = h[i] ? (d2z[i+1] - d2z[i])/h[i] : 0;
61414924Sslatteng }
61514924Sslatteng } /* end NaturalEndSpline */
61614924Sslatteng
61714924Sslatteng
61814924Sslatteng /*----------------------------------------------------------------------------
61914924Sslatteng | Routine: HGCurve(xpoints, ypoints, num_points)
62014924Sslatteng |
62114924Sslatteng | Results: This routine generates a smooth curve through a set of points.
62214924Sslatteng | The method used is the parametric spline curve on unit knot
62314924Sslatteng | mesh described in "Spline Curve Techniques" by Patrick
62414924Sslatteng | Baudelaire, Robert Flegal, and Robert Sproull -- Xerox Parc.
62514924Sslatteng *----------------------------------------------------------------------------*/
62614924Sslatteng
62714924Sslatteng #define PointsPerInterval 32
62814924Sslatteng
HGCurve(x,y,numpoints)62914924Sslatteng HGCurve(x, y, numpoints)
63025608Sslatteng int *x;
63125608Sslatteng int *y;
63214924Sslatteng int numpoints;
63314924Sslatteng {
63414924Sslatteng float h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS];
63514924Sslatteng float d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS];
63614924Sslatteng float t, t2, t3;
63714924Sslatteng register int j;
63814924Sslatteng register int k;
63914924Sslatteng register int nx;
64014924Sslatteng register int ny;
64114924Sslatteng int lx, ly;
64214924Sslatteng
64314924Sslatteng
64414924Sslatteng lx = x[1];
64514924Sslatteng ly = y[1];
64614924Sslatteng
64714924Sslatteng /* Solve for derivatives of the curve at each point
64814924Sslatteng * separately for x and y (parametric).
64914924Sslatteng */
65014924Sslatteng Paramaterize(x, y, h, numpoints);
65114924Sslatteng /* closed curve */
65214924Sslatteng if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) {
65314924Sslatteng PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
65414924Sslatteng PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
65514924Sslatteng } else {
65614924Sslatteng NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
65714924Sslatteng NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
65814924Sslatteng }
65914924Sslatteng
66014924Sslatteng /* generate the curve using the above information and
66114924Sslatteng * PointsPerInterval vectors between each specified knot.
66214924Sslatteng */
66314924Sslatteng
66414924Sslatteng for (j=1; j<numpoints; ++j) {
66514924Sslatteng if ((x[j] == x[j+1]) && (y[j] == y[j+1])) continue;
66614924Sslatteng for (k=0; k<=PointsPerInterval; ++k) {
66714924Sslatteng t = (float) k * h[j] / (float) PointsPerInterval;
66814924Sslatteng t2 = t * t;
66914924Sslatteng t3 = t * t * t;
67014924Sslatteng nx = x[j] + (int) (t * dx[j] + t2 * d2x[j]/2 + t3 * d3x[j]/6);
67114924Sslatteng ny = y[j] + (int) (t * dy[j] + t2 * d2y[j]/2 + t3 * d3y[j]/6);
67214924Sslatteng HGtline(lx, ly, nx, ny);
67314924Sslatteng lx = nx;
67414924Sslatteng ly = ny;
67514924Sslatteng } /* end for k */
67614924Sslatteng } /* end for j */
67714924Sslatteng } /* end HGCurve */
67814924Sslatteng
67914924Sslatteng
68014924Sslatteng /*----------------------------------------------------------------------------
68115347Sslatteng | Routine: line(xstart, ystart, xend, yend)
68214924Sslatteng |
68314924Sslatteng | Results: Creates a drawing path and draws the line. If the line falls
68414924Sslatteng | off the end of the page, a crude clipping is done: truncating
68514924Sslatteng | the offending ordinate.
68614924Sslatteng *----------------------------------------------------------------------------*/
68714924Sslatteng
line(x0,y0,x1,y1)68815347Sslatteng line(x0, y0, x1, y1)
68914924Sslatteng int x0, y0, x1, y1;
69014924Sslatteng {
69114924Sslatteng byte(ASPATH); /* send the coordinates first */
69214924Sslatteng word(2); /* only two */
69314924Sslatteng word(xbound(x0));
69414924Sslatteng word(ybound(y0));
69514924Sslatteng word(xbound(x1));
69614924Sslatteng word(ybound(y1));
69714924Sslatteng byte(ADRAW); /* now draw it */
69814924Sslatteng byte(15); /* black */
69915347Sslatteng } /* end line */
70015347Sslatteng
70115347Sslatteng
70215347Sslatteng /*----------------------------------------------------------------------------*
70315347Sslatteng | Routine: change (x_position, y_position, visible_flag)
70415347Sslatteng |
70515347Sslatteng | Results: As HGtline passes from the invisible to visible (or vice
70615347Sslatteng | versa) portion of a line, change is called to either draw
70715347Sslatteng | the line, or initialize the beginning of the next one.
70815347Sslatteng | Change calls line to draw segments if visible_flag is set
70915347Sslatteng | (which means we're leaving a visible area).
71015347Sslatteng *----------------------------------------------------------------------------*/
71115347Sslatteng
change(x,y,vis)71215347Sslatteng change (x, y, vis)
71315347Sslatteng register int x;
71415347Sslatteng register int y;
71515347Sslatteng register int vis;
71615347Sslatteng {
71715347Sslatteng static int xorg;
71815347Sslatteng static int yorg;
71915347Sslatteng
72015347Sslatteng if (vis) /* leaving a visible area, draw it. */
72115347Sslatteng line (xorg, yorg, x, y);
72215347Sslatteng else { /* otherwise, we're entering one, remember beginning */
72315347Sslatteng xorg = x;
72415347Sslatteng yorg = y;
72515347Sslatteng }
72615347Sslatteng }
72715347Sslatteng
72815347Sslatteng
72915347Sslatteng /*----------------------------------------------------------------------------
73015347Sslatteng | Routine: HGtline (xstart, ystart, xend, yend)
73115347Sslatteng |
73215347Sslatteng | Results: Draws a line from (x0,y0) to (x1,y1) using line(x0,y0,x1,y1)
73315347Sslatteng | to place individual segments of dotted or dashed lines.
73415347Sslatteng *----------------------------------------------------------------------------*/
73515347Sslatteng
HGtline(x0,y0,x1,y1)73615347Sslatteng HGtline(x0, y0, x1, y1)
73716030Sslatteng int x0, y0, x1, y1;
73815347Sslatteng {
73915347Sslatteng register int dx;
74015347Sslatteng register int dy;
74116030Sslatteng register int oldcoord;
74215347Sslatteng register int res1;
74315347Sslatteng register int visible;
74416030Sslatteng register int res2;
74516030Sslatteng register int xinc;
74616030Sslatteng register int yinc;
74715347Sslatteng
74815347Sslatteng
74917428Sslatteng if (linmod == SOLID) {
75015347Sslatteng line(x0, y0, x1, y1);
75115347Sslatteng return;
75215347Sslatteng }
75315347Sslatteng xinc = 1;
75415347Sslatteng yinc = 1;
75515347Sslatteng if ((dx = x1-x0) < 0) {
75615347Sslatteng xinc = -1;
75715347Sslatteng dx = -dx;
75815347Sslatteng }
75915347Sslatteng if ((dy = y1-y0) < 0) {
76015347Sslatteng yinc = -1;
76115347Sslatteng dy = -dy;
76215347Sslatteng }
76315347Sslatteng res1 = 0;
76415347Sslatteng res2 = 0;
76515347Sslatteng visible = 0;
76616030Sslatteng if (dx >= dy) {
76716030Sslatteng oldcoord = y0;
76815347Sslatteng while (x0 != x1) {
76916030Sslatteng if((x0&linmod) && !visible) {
77016030Sslatteng change(x0, y0, 0);
77116030Sslatteng visible = 1;
77216030Sslatteng } else if(visible && !(x0&linmod)) {
77316030Sslatteng change(x0 - xinc, oldcoord, 1);
77416030Sslatteng visible = 0;
77515347Sslatteng }
77615347Sslatteng if (res1 > res2) {
77716030Sslatteng oldcoord = y0;
77815347Sslatteng res2 += dx - res1;
77915347Sslatteng res1 = 0;
78015347Sslatteng y0 += yinc;
78115347Sslatteng }
78215347Sslatteng res1 += dy;
78315347Sslatteng x0 += xinc;
78415347Sslatteng }
78516030Sslatteng } else {
78616030Sslatteng oldcoord = x0;
78715347Sslatteng while (y0 != y1) {
78816030Sslatteng if((y0&linmod) && !visible) {
78916030Sslatteng change(x0, y0, 0);
79016030Sslatteng visible = 1;
79116030Sslatteng } else if(visible && !(y0&linmod)) {
79216030Sslatteng change(oldcoord, y0 - yinc, 1);
79316030Sslatteng visible = 0;
79415347Sslatteng }
79515347Sslatteng if (res1 > res2) {
79616030Sslatteng oldcoord = x0;
79715347Sslatteng res2 += dy - res1;
79815347Sslatteng res1 = 0;
79915347Sslatteng x0 += xinc;
80015347Sslatteng }
80115347Sslatteng res1 += dx;
80215347Sslatteng y0 += yinc;
80315347Sslatteng }
80416030Sslatteng }
80515347Sslatteng if(visible) change(x1, y1, 1);
80615347Sslatteng }
807