/contrib/groff/src/preproc/grn/hgraph.cpp
https://bitbucket.org/freebsd/freebsd-head/ · C++ · 1048 lines · 695 code · 132 blank · 221 comment · 117 complexity · 5c19d13e6ccd4acf10356ad8386bfab4 MD5 · raw file
- /* Last non-groff version: hgraph.c 1.14 (Berkeley) 84/11/27
- *
- * This file contains the graphics routines for converting gremlin pictures
- * to troff input.
- */
- #include "lib.h"
- #include "gprint.h"
- #define MAXVECT 40
- #define MAXPOINTS 200
- #define LINELENGTH 1
- #define PointsPerInterval 64
- #define pi 3.14159265358979324
- #define twopi (2.0 * pi)
- #define len(a, b) groff_hypot((double)(b.x-a.x), (double)(b.y-a.y))
- extern int dotshifter; /* for the length of dotted curves */
- extern int style[]; /* line and character styles */
- extern double thick[];
- extern char *tfont[];
- extern int tsize[];
- extern int stipple_index[]; /* stipple font index for stipples 0 - 16 */
- extern char *stipple; /* stipple type (cf or ug) */
- extern double troffscale; /* imports from main.c */
- extern double linethickness;
- extern int linmod;
- extern int lastx;
- extern int lasty;
- extern int lastyline;
- extern int ytop;
- extern int ybottom;
- extern int xleft;
- extern int xright;
- extern enum E {
- OUTLINE, FILL, BOTH
- } polyfill;
- extern double adj1;
- extern double adj2;
- extern double adj3;
- extern double adj4;
- extern int res;
- void HGSetFont(int font, int size);
- void HGPutText(int justify, POINT pnt, register char *string);
- void HGSetBrush(int mode);
- void tmove2(int px, int py);
- void doarc(POINT cp, POINT sp, int angle);
- void tmove(POINT * ptr);
- void cr();
- void drawwig(POINT * ptr, int type);
- void HGtline(int x1, int y1);
- void deltax(double x);
- void deltay(double y);
- void HGArc(register int cx, register int cy, int px, int py, int angle);
- void picurve(register int *x, register int *y, int npts);
- void HGCurve(int *x, int *y, int numpoints);
- void Paramaterize(int x[], int y[], double h[], int n);
- void PeriodicSpline(double h[], int z[],
- double dz[], double d2z[], double d3z[],
- int npoints);
- void NaturalEndSpline(double h[], int z[],
- double dz[], double d2z[], double d3z[],
- int npoints);
- /*----------------------------------------------------------------------------*
- | Routine: HGPrintElt (element_pointer, baseline)
- |
- | Results: Examines a picture element and calls the appropriate
- | routine(s) to print them according to their type. After the
- | picture is drawn, current position is (lastx, lasty).
- *----------------------------------------------------------------------------*/
- void
- HGPrintElt(ELT *element,
- int /* baseline */)
- {
- register POINT *p1;
- register POINT *p2;
- register int length;
- register int graylevel;
- if (!DBNullelt(element) && !Nullpoint((p1 = element->ptlist))) {
- /* p1 always has first point */
- if (TEXT(element->type)) {
- HGSetFont(element->brushf, element->size);
- switch (element->size) {
- case 1:
- p1->y += adj1;
- break;
- case 2:
- p1->y += adj2;
- break;
- case 3:
- p1->y += adj3;
- break;
- case 4:
- p1->y += adj4;
- break;
- default:
- break;
- }
- HGPutText(element->type, *p1, element->textpt);
- } else {
- if (element->brushf) /* if there is a brush, the */
- HGSetBrush(element->brushf); /* graphics need it set */
- switch (element->type) {
- case ARC:
- p2 = PTNextPoint(p1);
- tmove(p2);
- doarc(*p1, *p2, element->size);
- cr();
- break;
- case CURVE:
- length = 0; /* keep track of line length */
- drawwig(p1, CURVE);
- cr();
- break;
- case BSPLINE:
- length = 0; /* keep track of line length */
- drawwig(p1, BSPLINE);
- cr();
- break;
- case VECTOR:
- length = 0; /* keep track of line length so */
- tmove(p1); /* single lines don't get long */
- while (!Nullpoint((p1 = PTNextPoint(p1)))) {
- HGtline((int) (p1->x * troffscale),
- (int) (p1->y * troffscale));
- if (length++ > LINELENGTH) {
- length = 0;
- printf("\\\n");
- }
- } /* end while */
- cr();
- break;
- case POLYGON:
- {
- /* brushf = style of outline; size = color of fill:
- * on first pass (polyfill=FILL), do the interior using 'P'
- * unless size=0
- * on second pass (polyfill=OUTLINE), do the outline using a series
- * of vectors. It might make more sense to use \D'p ...',
- * but there is no uniform way to specify a 'fill character'
- * that prints as 'no fill' on all output devices (and
- * stipple fonts).
- * If polyfill=BOTH, just use the \D'p ...' command.
- */
- double firstx = p1->x;
- double firsty = p1->y;
- length = 0; /* keep track of line length so */
- /* single lines don't get long */
- if (polyfill == FILL || polyfill == BOTH) {
- /* do the interior */
- char command = (polyfill == BOTH && element->brushf) ? 'p' : 'P';
- /* include outline, if there is one and */
- /* the -p flag was set */
- /* switch based on what gremlin gives */
- switch (element->size) {
- case 1:
- graylevel = 1;
- break;
- case 3:
- graylevel = 2;
- break;
- case 12:
- graylevel = 3;
- break;
- case 14:
- graylevel = 4;
- break;
- case 16:
- graylevel = 5;
- break;
- case 19:
- graylevel = 6;
- break;
- case 21:
- graylevel = 7;
- break;
- case 23:
- graylevel = 8;
- break;
- default: /* who's giving something else? */
- graylevel = NSTIPPLES;
- break;
- }
- /* int graylevel = element->size; */
- if (graylevel < 0)
- break;
- if (graylevel > NSTIPPLES)
- graylevel = NSTIPPLES;
- printf("\\D'Fg %.3f'",
- double(1000 - stipple_index[graylevel]) / 1000.0);
- cr();
- tmove(p1);
- printf("\\D'%c", command);
- while (!Nullpoint((PTNextPoint(p1)))) {
- p1 = PTNextPoint(p1);
- deltax((double) p1->x);
- deltay((double) p1->y);
- if (length++ > LINELENGTH) {
- length = 0;
- printf("\\\n");
- }
- } /* end while */
- /* close polygon if not done so by user */
- if ((firstx != p1->x) || (firsty != p1->y)) {
- deltax((double) firstx);
- deltay((double) firsty);
- }
- putchar('\'');
- cr();
- break;
- }
- /* else polyfill == OUTLINE; only draw the outline */
- if (!(element->brushf))
- break;
- length = 0; /* keep track of line length */
- tmove(p1);
- while (!Nullpoint((PTNextPoint(p1)))) {
- p1 = PTNextPoint(p1);
- HGtline((int) (p1->x * troffscale),
- (int) (p1->y * troffscale));
- if (length++ > LINELENGTH) {
- length = 0;
- printf("\\\n");
- }
- } /* end while */
- /* close polygon if not done so by user */
- if ((firstx != p1->x) || (firsty != p1->y)) {
- HGtline((int) (firstx * troffscale),
- (int) (firsty * troffscale));
- }
- cr();
- break;
- } /* end case POLYGON */
- } /* end switch */
- } /* end else Text */
- } /* end if */
- } /* end PrintElt */
- /*----------------------------------------------------------------------------*
- | Routine: HGPutText (justification, position_point, string)
- |
- | Results: Given the justification, a point to position with, and a
- | string to put, HGPutText first sends the string into a
- | diversion, moves to the positioning point, then outputs
- | local vertical and horizontal motions as needed to justify
- | the text. After all motions are done, the diversion is
- | printed out.
- *----------------------------------------------------------------------------*/
- void
- HGPutText(int justify,
- POINT pnt,
- register char *string)
- {
- int savelasty = lasty; /* vertical motion for text is to be */
- /* ignored. Save current y here */
- printf(".nr g8 \\n(.d\n"); /* save current vertical position. */
- printf(".ds g9 \""); /* define string containing the text. */
- while (*string) { /* put out the string */
- if (*string == '\\' &&
- *(string + 1) == '\\') { /* one character at a */
- printf("\\\\\\"); /* time replacing // */
- string++; /* by //// to prevent */
- } /* interpretation at */
- printf("%c", *(string++)); /* printout time */
- }
- printf("\n");
- tmove(&pnt); /* move to positioning point */
- switch (justify) {
- /* local vertical motions */
- /* (the numbers here are used to be somewhat compatible with gprint) */
- case CENTLEFT:
- case CENTCENT:
- case CENTRIGHT:
- printf("\\v'0.85n'"); /* down half */
- break;
- case TOPLEFT:
- case TOPCENT:
- case TOPRIGHT:
- printf("\\v'1.7n'"); /* down whole */
- }
- switch (justify) {
- /* local horizontal motions */
- case BOTCENT:
- case CENTCENT:
- case TOPCENT:
- printf("\\h'-\\w'\\*(g9'u/2u'"); /* back half */
- break;
- case BOTRIGHT:
- case CENTRIGHT:
- case TOPRIGHT:
- printf("\\h'-\\w'\\*(g9'u'"); /* back whole */
- }
- printf("\\&\\*(g9\n"); /* now print the text. */
- printf(".sp |\\n(g8u\n"); /* restore vertical position */
- lasty = savelasty; /* vertical position restored to where it */
- lastx = xleft; /* was before text, also horizontal is at */
- /* left */
- } /* end HGPutText */
- /*----------------------------------------------------------------------------*
- | Routine: doarc (center_point, start_point, angle)
- |
- | Results: Produces either drawarc command or a drawcircle command
- | depending on the angle needed to draw through.
- *----------------------------------------------------------------------------*/
- void
- doarc(POINT cp,
- POINT sp,
- int angle)
- {
- if (angle) /* arc with angle */
- HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
- (int) (sp.x * troffscale), (int) (sp.y * troffscale), angle);
- else /* a full circle (angle == 0) */
- HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
- (int) (sp.x * troffscale), (int) (sp.y * troffscale), 0);
- }
- /*----------------------------------------------------------------------------*
- | Routine: HGSetFont (font_number, Point_size)
- |
- | Results: ALWAYS outputs a .ft and .ps directive to troff. This is
- | done because someone may change stuff inside a text string.
- | Changes thickness back to default thickness. Default
- | thickness depends on font and pointsize.
- *----------------------------------------------------------------------------*/
- void
- HGSetFont(int font,
- int size)
- {
- printf(".ft %s\n"
- ".ps %d\n", tfont[font - 1], tsize[size - 1]);
- linethickness = DEFTHICK;
- }
- /*----------------------------------------------------------------------------*
- | Routine: HGSetBrush (line_mode)
- |
- | Results: Generates the troff commands to set up the line width and
- | style of subsequent lines. Does nothing if no change is
- | needed.
- |
- | Side Efct: Sets `linmode' and `linethicknes'.
- *----------------------------------------------------------------------------*/
- void
- HGSetBrush(int mode)
- {
- register int printed = 0;
- if (linmod != style[--mode]) {
- /* Groff doesn't understand \Ds, so we take it out */
- /* printf ("\\D's %du'", linmod = style[mode]); */
- linmod = style[mode];
- printed = 1;
- }
- if (linethickness != thick[mode]) {
- linethickness = thick[mode];
- printf("\\h'-%.2fp'\\D't %.2fp'", linethickness, linethickness);
- printed = 1;
- }
- if (printed)
- cr();
- }
- /*----------------------------------------------------------------------------*
- | Routine: deltax (x_destination)
- |
- | Results: Scales and outputs a number for delta x (with a leading
- | space) given `lastx' and x_destination.
- |
- | Side Efct: Resets `lastx' to x_destination.
- *----------------------------------------------------------------------------*/
- void
- deltax(double x)
- {
- register int ix = (int) (x * troffscale);
- printf(" %du", ix - lastx);
- lastx = ix;
- }
- /*----------------------------------------------------------------------------*
- | Routine: deltay (y_destination)
- |
- | Results: Scales and outputs a number for delta y (with a leading
- | space) given `lastyline' and y_destination.
- |
- | Side Efct: Resets `lastyline' to y_destination. Since `line' vertical
- | motions don't affect `page' ones, `lasty' isn't updated.
- *----------------------------------------------------------------------------*/
- void
- deltay(double y)
- {
- register int iy = (int) (y * troffscale);
- printf(" %du", iy - lastyline);
- lastyline = iy;
- }
- /*----------------------------------------------------------------------------*
- | Routine: tmove2 (px, py)
- |
- | Results: Produces horizontal and vertical moves for troff given the
- | pair of points to move to and knowing the current position.
- | Also puts out a horizontal move to start the line. This is
- | a variation without the .sp command.
- *----------------------------------------------------------------------------*/
- void
- tmove2(int px,
- int py)
- {
- register int dx;
- register int dy;
- if ((dy = py - lasty)) {
- printf("\\v'%du'", dy);
- }
- lastyline = lasty = py; /* lasty is always set to current */
- if ((dx = px - lastx)) {
- printf("\\h'%du'", dx);
- lastx = px;
- }
- }
- /*----------------------------------------------------------------------------*
- | Routine: tmove (point_pointer)
- |
- | Results: Produces horizontal and vertical moves for troff given the
- | pointer of a point to move to and knowing the current
- | position. Also puts out a horizontal move to start the
- | line.
- *----------------------------------------------------------------------------*/
- void
- tmove(POINT * ptr)
- {
- register int ix = (int) (ptr->x * troffscale);
- register int iy = (int) (ptr->y * troffscale);
- register int dx;
- register int dy;
- if ((dy = iy - lasty)) {
- printf(".sp %du\n", dy);
- }
- lastyline = lasty = iy; /* lasty is always set to current */
- if ((dx = ix - lastx)) {
- printf("\\h'%du'", dx);
- lastx = ix;
- }
- }
- /*----------------------------------------------------------------------------*
- | Routine: cr ( )
- |
- | Results: Ends off an input line. `.sp -1' is also added to counteract
- | the vertical move done at the end of text lines.
- |
- | Side Efct: Sets `lastx' to `xleft' for troff's return to left margin.
- *----------------------------------------------------------------------------*/
- void
- cr()
- {
- printf("\n.sp -1\n");
- lastx = xleft;
- }
- /*----------------------------------------------------------------------------*
- | Routine: line ( )
- |
- | Results: Draws a single solid line to (x,y).
- *----------------------------------------------------------------------------*/
- void
- line(int px,
- int py)
- {
- printf("\\D'l");
- printf(" %du", px - lastx);
- printf(" %du'", py - lastyline);
- lastx = px;
- lastyline = lasty = py;
- }
- /*----------------------------------------------------------------------------
- | Routine: drawwig (ptr, type)
- |
- | Results: The point sequence found in the structure pointed by ptr is
- | placed in integer arrays for further manipulation by the
- | existing routing. With the corresponding type parameter,
- | either picurve or HGCurve are called.
- *----------------------------------------------------------------------------*/
- void
- drawwig(POINT * ptr,
- int type)
- {
- register int npts; /* point list index */
- int x[MAXPOINTS], y[MAXPOINTS]; /* point list */
- for (npts = 1; !Nullpoint(ptr); ptr = PTNextPoint(ptr), npts++) {
- x[npts] = (int) (ptr->x * troffscale);
- y[npts] = (int) (ptr->y * troffscale);
- }
- if (--npts) {
- if (type == CURVE) /* Use the 2 different types of curves */
- HGCurve(&x[0], &y[0], npts);
- else
- picurve(&x[0], &y[0], npts);
- }
- }
- /*----------------------------------------------------------------------------
- | Routine: HGArc (xcenter, ycenter, xstart, ystart, angle)
- |
- | Results: This routine plots an arc centered about (cx, cy) counter
- | clockwise starting from the point (px, py) through `angle'
- | degrees. If angle is 0, a full circle is drawn. It does so
- | by creating a draw-path around the arc whose density of
- | points depends on the size of the arc.
- *----------------------------------------------------------------------------*/
- void
- HGArc(register int cx,
- register int cy,
- int px,
- int py,
- int angle)
- {
- double xs, ys, resolution, fullcircle;
- int m;
- register int mask;
- register int extent;
- register int nx;
- register int ny;
- register int length;
- register double epsilon;
- xs = px - cx;
- ys = py - cy;
- length = 0;
- resolution = (1.0 + groff_hypot(xs, ys) / res) * PointsPerInterval;
- /* mask = (1 << (int) log10(resolution + 1.0)) - 1; */
- (void) frexp(resolution, &m); /* A bit more elegant than log10 */
- for (mask = 1; mask < m; mask = mask << 1);
- mask -= 1;
- epsilon = 1.0 / resolution;
- fullcircle = (2.0 * pi) * resolution;
- if (angle == 0)
- extent = (int) fullcircle;
- else
- extent = (int) (angle * fullcircle / 360.0);
- HGtline(px, py);
- while (--extent >= 0) {
- xs += epsilon * ys;
- nx = cx + (int) (xs + 0.5);
- ys -= epsilon * xs;
- ny = cy + (int) (ys + 0.5);
- if (!(extent & mask)) {
- HGtline(nx, ny); /* put out a point on circle */
- if (length++ > LINELENGTH) {
- length = 0;
- printf("\\\n");
- }
- }
- } /* end for */
- } /* end HGArc */
- /*----------------------------------------------------------------------------
- | Routine: picurve (xpoints, ypoints, num_of_points)
- |
- | Results: Draws a curve delimited by (not through) the line segments
- | traced by (xpoints, ypoints) point list. This is the `Pic'
- | style curve.
- *----------------------------------------------------------------------------*/
- void
- picurve(register int *x,
- register int *y,
- int npts)
- {
- register int nseg; /* effective resolution for each curve */
- register int xp; /* current point (and temporary) */
- register int yp;
- int pxp, pyp; /* previous point (to make lines from) */
- int i; /* inner curve segment traverser */
- int length = 0;
- double w; /* position factor */
- double t1, t2, t3; /* calculation temps */
- if (x[1] == x[npts] && y[1] == y[npts]) {
- x[0] = x[npts - 1]; /* if the lines' ends meet, make */
- y[0] = y[npts - 1]; /* sure the curve meets */
- x[npts + 1] = x[2];
- y[npts + 1] = y[2];
- } else { /* otherwise, make the ends of the */
- x[0] = x[1]; /* curve touch the ending points of */
- y[0] = y[1]; /* the line segments */
- x[npts + 1] = x[npts];
- y[npts + 1] = y[npts];
- }
- pxp = (x[0] + x[1]) / 2; /* make the last point pointers */
- pyp = (y[0] + y[1]) / 2; /* point to the start of the 1st line */
- tmove2(pxp, pyp);
- for (; npts--; x++, y++) { /* traverse the line segments */
- xp = x[0] - x[1];
- yp = y[0] - y[1];
- nseg = (int) groff_hypot((double) xp, (double) yp);
- xp = x[1] - x[2];
- yp = y[1] - y[2];
- /* `nseg' is the number of line */
- /* segments that will be drawn for */
- /* each curve segment. */
- nseg = (int) ((double) (nseg + (int) groff_hypot((double) xp, (double) yp)) /
- res * PointsPerInterval);
- for (i = 1; i < nseg; i++) {
- w = (double) i / (double) nseg;
- t1 = w * w;
- t3 = t1 + 1.0 - (w + w);
- t2 = 2.0 - (t3 + t1);
- xp = (((int) (t1 * x[2] + t2 * x[1] + t3 * x[0])) + 1) / 2;
- yp = (((int) (t1 * y[2] + t2 * y[1] + t3 * y[0])) + 1) / 2;
- HGtline(xp, yp);
- if (length++ > LINELENGTH) {
- length = 0;
- printf("\\\n");
- }
- }
- }
- }
- /*----------------------------------------------------------------------------
- | Routine: HGCurve(xpoints, ypoints, num_points)
- |
- | Results: This routine generates a smooth curve through a set of
- | points. The method used is the parametric spline curve on
- | unit knot mesh described in `Spline Curve Techniques' by
- | Patrick Baudelaire, Robert Flegal, and Robert Sproull --
- | Xerox Parc.
- *----------------------------------------------------------------------------*/
- void
- HGCurve(int *x,
- int *y,
- int numpoints)
- {
- double h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS];
- double d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS];
- double t, t2, t3;
- register int j;
- register int k;
- register int nx;
- register int ny;
- int lx, ly;
- int length = 0;
- lx = x[1];
- ly = y[1];
- tmove2(lx, ly);
- /*
- * Solve for derivatives of the curve at each point separately for x and y
- * (parametric).
- */
- Paramaterize(x, y, h, numpoints);
- /* closed curve */
- if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) {
- PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
- PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
- } else {
- NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
- NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
- }
- /*
- * generate the curve using the above information and PointsPerInterval
- * vectors between each specified knot.
- */
- for (j = 1; j < numpoints; ++j) {
- if ((x[j] == x[j + 1]) && (y[j] == y[j + 1]))
- continue;
- for (k = 0; k <= PointsPerInterval; ++k) {
- t = (double) k *h[j] / (double) PointsPerInterval;
- t2 = t * t;
- t3 = t * t * t;
- nx = x[j] + (int) (t * dx[j] + t2 * d2x[j] / 2 + t3 * d3x[j] / 6);
- ny = y[j] + (int) (t * dy[j] + t2 * d2y[j] / 2 + t3 * d3y[j] / 6);
- HGtline(nx, ny);
- if (length++ > LINELENGTH) {
- length = 0;
- printf("\\\n");
- }
- } /* end for k */
- } /* end for j */
- } /* end HGCurve */
- /*----------------------------------------------------------------------------
- | Routine: Paramaterize (xpoints, ypoints, hparams, num_points)
- |
- | Results: This routine calculates parameteric values for use in
- | calculating curves. The parametric values are returned
- | in the array h. The values are an approximation of
- | cumulative arc lengths of the curve (uses cord length).
- | For additional information, see paper cited below.
- *----------------------------------------------------------------------------*/
- void
- Paramaterize(int x[],
- int y[],
- double h[],
- int n)
- {
- register int dx;
- register int dy;
- register int i;
- register int j;
- double u[MAXPOINTS];
- for (i = 1; i <= n; ++i) {
- u[i] = 0;
- for (j = 1; j < i; j++) {
- dx = x[j + 1] - x[j];
- dy = y[j + 1] - y[j];
- /* Here was overflowing, so I changed it. */
- /* u[i] += sqrt ((double) (dx * dx + dy * dy)); */
- u[i] += groff_hypot((double) dx, (double) dy);
- }
- }
- for (i = 1; i < n; ++i)
- h[i] = u[i + 1] - u[i];
- } /* end Paramaterize */
- /*----------------------------------------------------------------------------
- | Routine: PeriodicSpline (h, z, dz, d2z, d3z, npoints)
- |
- | Results: This routine solves for the cubic polynomial to fit a spline
- | curve to the the points specified by the list of values.
- | The Curve generated is periodic. The algorithms for this
- | curve are from the `Spline Curve Techniques' paper cited
- | above.
- *----------------------------------------------------------------------------*/
- void
- PeriodicSpline(double h[], /* paramaterization */
- int z[], /* point list */
- double dz[], /* to return the 1st derivative */
- double d2z[], /* 2nd derivative */
- double d3z[], /* 3rd derivative */
- int npoints) /* number of valid points */
- {
- double d[MAXPOINTS];
- double deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
- double c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS];
- int i;
- /* step 1 */
- for (i = 1; i < npoints; ++i) {
- deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
- }
- h[0] = h[npoints - 1];
- deltaz[0] = deltaz[npoints - 1];
- /* step 2 */
- for (i = 1; i < npoints - 1; ++i) {
- d[i] = deltaz[i + 1] - deltaz[i];
- }
- d[0] = deltaz[1] - deltaz[0];
- /* step 3a */
- a[1] = 2 * (h[0] + h[1]);
- b[1] = d[0];
- c[1] = h[0];
- for (i = 2; i < npoints - 1; ++i) {
- a[i] = 2 * (h[i - 1] + h[i]) -
- pow((double) h[i - 1], (double) 2.0) / a[i - 1];
- b[i] = d[i - 1] - h[i - 1] * b[i - 1] / a[i - 1];
- c[i] = -h[i - 1] * c[i - 1] / a[i - 1];
- }
- /* step 3b */
- r[npoints - 1] = 1;
- s[npoints - 1] = 0;
- for (i = npoints - 2; i > 0; --i) {
- r[i] = -(h[i] * r[i + 1] + c[i]) / a[i];
- s[i] = (6 * b[i] - h[i] * s[i + 1]) / a[i];
- }
- /* step 4 */
- d2z[npoints - 1] = (6 * d[npoints - 2] - h[0] * s[1]
- - h[npoints - 1] * s[npoints - 2])
- / (h[0] * r[1] + h[npoints - 1] * r[npoints - 2]
- + 2 * (h[npoints - 2] + h[0]));
- for (i = 1; i < npoints - 1; ++i) {
- d2z[i] = r[i] * d2z[npoints - 1] + s[i];
- }
- d2z[npoints] = d2z[1];
- /* step 5 */
- for (i = 1; i < npoints; ++i) {
- dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
- d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
- }
- } /* end PeriodicSpline */
- /*----------------------------------------------------------------------------
- | Routine: NaturalEndSpline (h, z, dz, d2z, d3z, npoints)
- |
- | Results: This routine solves for the cubic polynomial to fit a spline
- | curve the the points specified by the list of values. The
- | alogrithms for this curve are from the `Spline Curve
- | Techniques' paper cited above.
- *----------------------------------------------------------------------------*/
- void
- NaturalEndSpline(double h[], /* parameterization */
- int z[], /* Point list */
- double dz[], /* to return the 1st derivative */
- double d2z[], /* 2nd derivative */
- double d3z[], /* 3rd derivative */
- int npoints) /* number of valid points */
- {
- double d[MAXPOINTS];
- double deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
- int i;
- /* step 1 */
- for (i = 1; i < npoints; ++i) {
- deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
- }
- deltaz[0] = deltaz[npoints - 1];
- /* step 2 */
- for (i = 1; i < npoints - 1; ++i) {
- d[i] = deltaz[i + 1] - deltaz[i];
- }
- d[0] = deltaz[1] - deltaz[0];
- /* step 3 */
- a[0] = 2 * (h[2] + h[1]);
- b[0] = d[1];
- for (i = 1; i < npoints - 2; ++i) {
- a[i] = 2 * (h[i + 1] + h[i + 2]) -
- pow((double) h[i + 1], (double) 2.0) / a[i - 1];
- b[i] = d[i + 1] - h[i + 1] * b[i - 1] / a[i - 1];
- }
- /* step 4 */
- d2z[npoints] = d2z[1] = 0;
- for (i = npoints - 1; i > 1; --i) {
- d2z[i] = (6 * b[i - 2] - h[i] * d2z[i + 1]) / a[i - 2];
- }
- /* step 5 */
- for (i = 1; i < npoints; ++i) {
- dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
- d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
- }
- } /* end NaturalEndSpline */
- /*----------------------------------------------------------------------------*
- | Routine: change (x_position, y_position, visible_flag)
- |
- | Results: As HGtline passes from the invisible to visible (or vice
- | versa) portion of a line, change is called to either draw
- | the line, or initialize the beginning of the next one.
- | Change calls line to draw segments if visible_flag is set
- | (which means we're leaving a visible area).
- *----------------------------------------------------------------------------*/
- void
- change(register int x,
- register int y,
- register int vis)
- {
- static int length = 0;
- if (vis) { /* leaving a visible area, draw it. */
- line(x, y);
- if (length++ > LINELENGTH) {
- length = 0;
- printf("\\\n");
- }
- } else { /* otherwise, we're entering one, remember */
- /* beginning */
- tmove2(x, y);
- }
- }
- /*----------------------------------------------------------------------------
- | Routine: HGtline (xstart, ystart, xend, yend)
- |
- | Results: Draws a line from current position to (x1,y1) using line(x1,
- | y1) to place individual segments of dotted or dashed lines.
- *----------------------------------------------------------------------------*/
- void
- HGtline(int x_1,
- int y_1)
- {
- register int x_0 = lastx;
- register int y_0 = lasty;
- register int dx;
- register int dy;
- register int oldcoord;
- register int res1;
- register int visible;
- register int res2;
- register int xinc;
- register int yinc;
- register int dotcounter;
- if (linmod == SOLID) {
- line(x_1, y_1);
- return;
- }
- /* for handling different resolutions */
- dotcounter = linmod << dotshifter;
- xinc = 1;
- yinc = 1;
- if ((dx = x_1 - x_0) < 0) {
- xinc = -xinc;
- dx = -dx;
- }
- if ((dy = y_1 - y_0) < 0) {
- yinc = -yinc;
- dy = -dy;
- }
- res1 = 0;
- res2 = 0;
- visible = 0;
- if (dx >= dy) {
- oldcoord = y_0;
- while (x_0 != x_1) {
- if ((x_0 & dotcounter) && !visible) {
- change(x_0, y_0, 0);
- visible = 1;
- } else if (visible && !(x_0 & dotcounter)) {
- change(x_0 - xinc, oldcoord, 1);
- visible = 0;
- }
- if (res1 > res2) {
- oldcoord = y_0;
- res2 += dx - res1;
- res1 = 0;
- y_0 += yinc;
- }
- res1 += dy;
- x_0 += xinc;
- }
- } else {
- oldcoord = x_0;
- while (y_0 != y_1) {
- if ((y_0 & dotcounter) && !visible) {
- change(x_0, y_0, 0);
- visible = 1;
- } else if (visible && !(y_0 & dotcounter)) {
- change(oldcoord, y_0 - yinc, 1);
- visible = 0;
- }
- if (res1 > res2) {
- oldcoord = x_0;
- res2 += dy - res1;
- res1 = 0;
- x_0 += xinc;
- }
- res1 += dx;
- y_0 += yinc;
- }
- }
- if (visible)
- change(x_1, y_1, 1);
- else
- change(x_1, y_1, 0);
- }
- /* EOF */