/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

  1. /* Last non-groff version: hgraph.c 1.14 (Berkeley) 84/11/27
  2. *
  3. * This file contains the graphics routines for converting gremlin pictures
  4. * to troff input.
  5. */
  6. #include "lib.h"
  7. #include "gprint.h"
  8. #define MAXVECT 40
  9. #define MAXPOINTS 200
  10. #define LINELENGTH 1
  11. #define PointsPerInterval 64
  12. #define pi 3.14159265358979324
  13. #define twopi (2.0 * pi)
  14. #define len(a, b) groff_hypot((double)(b.x-a.x), (double)(b.y-a.y))
  15. extern int dotshifter; /* for the length of dotted curves */
  16. extern int style[]; /* line and character styles */
  17. extern double thick[];
  18. extern char *tfont[];
  19. extern int tsize[];
  20. extern int stipple_index[]; /* stipple font index for stipples 0 - 16 */
  21. extern char *stipple; /* stipple type (cf or ug) */
  22. extern double troffscale; /* imports from main.c */
  23. extern double linethickness;
  24. extern int linmod;
  25. extern int lastx;
  26. extern int lasty;
  27. extern int lastyline;
  28. extern int ytop;
  29. extern int ybottom;
  30. extern int xleft;
  31. extern int xright;
  32. extern enum E {
  33. OUTLINE, FILL, BOTH
  34. } polyfill;
  35. extern double adj1;
  36. extern double adj2;
  37. extern double adj3;
  38. extern double adj4;
  39. extern int res;
  40. void HGSetFont(int font, int size);
  41. void HGPutText(int justify, POINT pnt, register char *string);
  42. void HGSetBrush(int mode);
  43. void tmove2(int px, int py);
  44. void doarc(POINT cp, POINT sp, int angle);
  45. void tmove(POINT * ptr);
  46. void cr();
  47. void drawwig(POINT * ptr, int type);
  48. void HGtline(int x1, int y1);
  49. void deltax(double x);
  50. void deltay(double y);
  51. void HGArc(register int cx, register int cy, int px, int py, int angle);
  52. void picurve(register int *x, register int *y, int npts);
  53. void HGCurve(int *x, int *y, int numpoints);
  54. void Paramaterize(int x[], int y[], double h[], int n);
  55. void PeriodicSpline(double h[], int z[],
  56. double dz[], double d2z[], double d3z[],
  57. int npoints);
  58. void NaturalEndSpline(double h[], int z[],
  59. double dz[], double d2z[], double d3z[],
  60. int npoints);
  61. /*----------------------------------------------------------------------------*
  62. | Routine: HGPrintElt (element_pointer, baseline)
  63. |
  64. | Results: Examines a picture element and calls the appropriate
  65. | routine(s) to print them according to their type. After the
  66. | picture is drawn, current position is (lastx, lasty).
  67. *----------------------------------------------------------------------------*/
  68. void
  69. HGPrintElt(ELT *element,
  70. int /* baseline */)
  71. {
  72. register POINT *p1;
  73. register POINT *p2;
  74. register int length;
  75. register int graylevel;
  76. if (!DBNullelt(element) && !Nullpoint((p1 = element->ptlist))) {
  77. /* p1 always has first point */
  78. if (TEXT(element->type)) {
  79. HGSetFont(element->brushf, element->size);
  80. switch (element->size) {
  81. case 1:
  82. p1->y += adj1;
  83. break;
  84. case 2:
  85. p1->y += adj2;
  86. break;
  87. case 3:
  88. p1->y += adj3;
  89. break;
  90. case 4:
  91. p1->y += adj4;
  92. break;
  93. default:
  94. break;
  95. }
  96. HGPutText(element->type, *p1, element->textpt);
  97. } else {
  98. if (element->brushf) /* if there is a brush, the */
  99. HGSetBrush(element->brushf); /* graphics need it set */
  100. switch (element->type) {
  101. case ARC:
  102. p2 = PTNextPoint(p1);
  103. tmove(p2);
  104. doarc(*p1, *p2, element->size);
  105. cr();
  106. break;
  107. case CURVE:
  108. length = 0; /* keep track of line length */
  109. drawwig(p1, CURVE);
  110. cr();
  111. break;
  112. case BSPLINE:
  113. length = 0; /* keep track of line length */
  114. drawwig(p1, BSPLINE);
  115. cr();
  116. break;
  117. case VECTOR:
  118. length = 0; /* keep track of line length so */
  119. tmove(p1); /* single lines don't get long */
  120. while (!Nullpoint((p1 = PTNextPoint(p1)))) {
  121. HGtline((int) (p1->x * troffscale),
  122. (int) (p1->y * troffscale));
  123. if (length++ > LINELENGTH) {
  124. length = 0;
  125. printf("\\\n");
  126. }
  127. } /* end while */
  128. cr();
  129. break;
  130. case POLYGON:
  131. {
  132. /* brushf = style of outline; size = color of fill:
  133. * on first pass (polyfill=FILL), do the interior using 'P'
  134. * unless size=0
  135. * on second pass (polyfill=OUTLINE), do the outline using a series
  136. * of vectors. It might make more sense to use \D'p ...',
  137. * but there is no uniform way to specify a 'fill character'
  138. * that prints as 'no fill' on all output devices (and
  139. * stipple fonts).
  140. * If polyfill=BOTH, just use the \D'p ...' command.
  141. */
  142. double firstx = p1->x;
  143. double firsty = p1->y;
  144. length = 0; /* keep track of line length so */
  145. /* single lines don't get long */
  146. if (polyfill == FILL || polyfill == BOTH) {
  147. /* do the interior */
  148. char command = (polyfill == BOTH && element->brushf) ? 'p' : 'P';
  149. /* include outline, if there is one and */
  150. /* the -p flag was set */
  151. /* switch based on what gremlin gives */
  152. switch (element->size) {
  153. case 1:
  154. graylevel = 1;
  155. break;
  156. case 3:
  157. graylevel = 2;
  158. break;
  159. case 12:
  160. graylevel = 3;
  161. break;
  162. case 14:
  163. graylevel = 4;
  164. break;
  165. case 16:
  166. graylevel = 5;
  167. break;
  168. case 19:
  169. graylevel = 6;
  170. break;
  171. case 21:
  172. graylevel = 7;
  173. break;
  174. case 23:
  175. graylevel = 8;
  176. break;
  177. default: /* who's giving something else? */
  178. graylevel = NSTIPPLES;
  179. break;
  180. }
  181. /* int graylevel = element->size; */
  182. if (graylevel < 0)
  183. break;
  184. if (graylevel > NSTIPPLES)
  185. graylevel = NSTIPPLES;
  186. printf("\\D'Fg %.3f'",
  187. double(1000 - stipple_index[graylevel]) / 1000.0);
  188. cr();
  189. tmove(p1);
  190. printf("\\D'%c", command);
  191. while (!Nullpoint((PTNextPoint(p1)))) {
  192. p1 = PTNextPoint(p1);
  193. deltax((double) p1->x);
  194. deltay((double) p1->y);
  195. if (length++ > LINELENGTH) {
  196. length = 0;
  197. printf("\\\n");
  198. }
  199. } /* end while */
  200. /* close polygon if not done so by user */
  201. if ((firstx != p1->x) || (firsty != p1->y)) {
  202. deltax((double) firstx);
  203. deltay((double) firsty);
  204. }
  205. putchar('\'');
  206. cr();
  207. break;
  208. }
  209. /* else polyfill == OUTLINE; only draw the outline */
  210. if (!(element->brushf))
  211. break;
  212. length = 0; /* keep track of line length */
  213. tmove(p1);
  214. while (!Nullpoint((PTNextPoint(p1)))) {
  215. p1 = PTNextPoint(p1);
  216. HGtline((int) (p1->x * troffscale),
  217. (int) (p1->y * troffscale));
  218. if (length++ > LINELENGTH) {
  219. length = 0;
  220. printf("\\\n");
  221. }
  222. } /* end while */
  223. /* close polygon if not done so by user */
  224. if ((firstx != p1->x) || (firsty != p1->y)) {
  225. HGtline((int) (firstx * troffscale),
  226. (int) (firsty * troffscale));
  227. }
  228. cr();
  229. break;
  230. } /* end case POLYGON */
  231. } /* end switch */
  232. } /* end else Text */
  233. } /* end if */
  234. } /* end PrintElt */
  235. /*----------------------------------------------------------------------------*
  236. | Routine: HGPutText (justification, position_point, string)
  237. |
  238. | Results: Given the justification, a point to position with, and a
  239. | string to put, HGPutText first sends the string into a
  240. | diversion, moves to the positioning point, then outputs
  241. | local vertical and horizontal motions as needed to justify
  242. | the text. After all motions are done, the diversion is
  243. | printed out.
  244. *----------------------------------------------------------------------------*/
  245. void
  246. HGPutText(int justify,
  247. POINT pnt,
  248. register char *string)
  249. {
  250. int savelasty = lasty; /* vertical motion for text is to be */
  251. /* ignored. Save current y here */
  252. printf(".nr g8 \\n(.d\n"); /* save current vertical position. */
  253. printf(".ds g9 \""); /* define string containing the text. */
  254. while (*string) { /* put out the string */
  255. if (*string == '\\' &&
  256. *(string + 1) == '\\') { /* one character at a */
  257. printf("\\\\\\"); /* time replacing // */
  258. string++; /* by //// to prevent */
  259. } /* interpretation at */
  260. printf("%c", *(string++)); /* printout time */
  261. }
  262. printf("\n");
  263. tmove(&pnt); /* move to positioning point */
  264. switch (justify) {
  265. /* local vertical motions */
  266. /* (the numbers here are used to be somewhat compatible with gprint) */
  267. case CENTLEFT:
  268. case CENTCENT:
  269. case CENTRIGHT:
  270. printf("\\v'0.85n'"); /* down half */
  271. break;
  272. case TOPLEFT:
  273. case TOPCENT:
  274. case TOPRIGHT:
  275. printf("\\v'1.7n'"); /* down whole */
  276. }
  277. switch (justify) {
  278. /* local horizontal motions */
  279. case BOTCENT:
  280. case CENTCENT:
  281. case TOPCENT:
  282. printf("\\h'-\\w'\\*(g9'u/2u'"); /* back half */
  283. break;
  284. case BOTRIGHT:
  285. case CENTRIGHT:
  286. case TOPRIGHT:
  287. printf("\\h'-\\w'\\*(g9'u'"); /* back whole */
  288. }
  289. printf("\\&\\*(g9\n"); /* now print the text. */
  290. printf(".sp |\\n(g8u\n"); /* restore vertical position */
  291. lasty = savelasty; /* vertical position restored to where it */
  292. lastx = xleft; /* was before text, also horizontal is at */
  293. /* left */
  294. } /* end HGPutText */
  295. /*----------------------------------------------------------------------------*
  296. | Routine: doarc (center_point, start_point, angle)
  297. |
  298. | Results: Produces either drawarc command or a drawcircle command
  299. | depending on the angle needed to draw through.
  300. *----------------------------------------------------------------------------*/
  301. void
  302. doarc(POINT cp,
  303. POINT sp,
  304. int angle)
  305. {
  306. if (angle) /* arc with angle */
  307. HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
  308. (int) (sp.x * troffscale), (int) (sp.y * troffscale), angle);
  309. else /* a full circle (angle == 0) */
  310. HGArc((int) (cp.x * troffscale), (int) (cp.y * troffscale),
  311. (int) (sp.x * troffscale), (int) (sp.y * troffscale), 0);
  312. }
  313. /*----------------------------------------------------------------------------*
  314. | Routine: HGSetFont (font_number, Point_size)
  315. |
  316. | Results: ALWAYS outputs a .ft and .ps directive to troff. This is
  317. | done because someone may change stuff inside a text string.
  318. | Changes thickness back to default thickness. Default
  319. | thickness depends on font and pointsize.
  320. *----------------------------------------------------------------------------*/
  321. void
  322. HGSetFont(int font,
  323. int size)
  324. {
  325. printf(".ft %s\n"
  326. ".ps %d\n", tfont[font - 1], tsize[size - 1]);
  327. linethickness = DEFTHICK;
  328. }
  329. /*----------------------------------------------------------------------------*
  330. | Routine: HGSetBrush (line_mode)
  331. |
  332. | Results: Generates the troff commands to set up the line width and
  333. | style of subsequent lines. Does nothing if no change is
  334. | needed.
  335. |
  336. | Side Efct: Sets `linmode' and `linethicknes'.
  337. *----------------------------------------------------------------------------*/
  338. void
  339. HGSetBrush(int mode)
  340. {
  341. register int printed = 0;
  342. if (linmod != style[--mode]) {
  343. /* Groff doesn't understand \Ds, so we take it out */
  344. /* printf ("\\D's %du'", linmod = style[mode]); */
  345. linmod = style[mode];
  346. printed = 1;
  347. }
  348. if (linethickness != thick[mode]) {
  349. linethickness = thick[mode];
  350. printf("\\h'-%.2fp'\\D't %.2fp'", linethickness, linethickness);
  351. printed = 1;
  352. }
  353. if (printed)
  354. cr();
  355. }
  356. /*----------------------------------------------------------------------------*
  357. | Routine: deltax (x_destination)
  358. |
  359. | Results: Scales and outputs a number for delta x (with a leading
  360. | space) given `lastx' and x_destination.
  361. |
  362. | Side Efct: Resets `lastx' to x_destination.
  363. *----------------------------------------------------------------------------*/
  364. void
  365. deltax(double x)
  366. {
  367. register int ix = (int) (x * troffscale);
  368. printf(" %du", ix - lastx);
  369. lastx = ix;
  370. }
  371. /*----------------------------------------------------------------------------*
  372. | Routine: deltay (y_destination)
  373. |
  374. | Results: Scales and outputs a number for delta y (with a leading
  375. | space) given `lastyline' and y_destination.
  376. |
  377. | Side Efct: Resets `lastyline' to y_destination. Since `line' vertical
  378. | motions don't affect `page' ones, `lasty' isn't updated.
  379. *----------------------------------------------------------------------------*/
  380. void
  381. deltay(double y)
  382. {
  383. register int iy = (int) (y * troffscale);
  384. printf(" %du", iy - lastyline);
  385. lastyline = iy;
  386. }
  387. /*----------------------------------------------------------------------------*
  388. | Routine: tmove2 (px, py)
  389. |
  390. | Results: Produces horizontal and vertical moves for troff given the
  391. | pair of points to move to and knowing the current position.
  392. | Also puts out a horizontal move to start the line. This is
  393. | a variation without the .sp command.
  394. *----------------------------------------------------------------------------*/
  395. void
  396. tmove2(int px,
  397. int py)
  398. {
  399. register int dx;
  400. register int dy;
  401. if ((dy = py - lasty)) {
  402. printf("\\v'%du'", dy);
  403. }
  404. lastyline = lasty = py; /* lasty is always set to current */
  405. if ((dx = px - lastx)) {
  406. printf("\\h'%du'", dx);
  407. lastx = px;
  408. }
  409. }
  410. /*----------------------------------------------------------------------------*
  411. | Routine: tmove (point_pointer)
  412. |
  413. | Results: Produces horizontal and vertical moves for troff given the
  414. | pointer of a point to move to and knowing the current
  415. | position. Also puts out a horizontal move to start the
  416. | line.
  417. *----------------------------------------------------------------------------*/
  418. void
  419. tmove(POINT * ptr)
  420. {
  421. register int ix = (int) (ptr->x * troffscale);
  422. register int iy = (int) (ptr->y * troffscale);
  423. register int dx;
  424. register int dy;
  425. if ((dy = iy - lasty)) {
  426. printf(".sp %du\n", dy);
  427. }
  428. lastyline = lasty = iy; /* lasty is always set to current */
  429. if ((dx = ix - lastx)) {
  430. printf("\\h'%du'", dx);
  431. lastx = ix;
  432. }
  433. }
  434. /*----------------------------------------------------------------------------*
  435. | Routine: cr ( )
  436. |
  437. | Results: Ends off an input line. `.sp -1' is also added to counteract
  438. | the vertical move done at the end of text lines.
  439. |
  440. | Side Efct: Sets `lastx' to `xleft' for troff's return to left margin.
  441. *----------------------------------------------------------------------------*/
  442. void
  443. cr()
  444. {
  445. printf("\n.sp -1\n");
  446. lastx = xleft;
  447. }
  448. /*----------------------------------------------------------------------------*
  449. | Routine: line ( )
  450. |
  451. | Results: Draws a single solid line to (x,y).
  452. *----------------------------------------------------------------------------*/
  453. void
  454. line(int px,
  455. int py)
  456. {
  457. printf("\\D'l");
  458. printf(" %du", px - lastx);
  459. printf(" %du'", py - lastyline);
  460. lastx = px;
  461. lastyline = lasty = py;
  462. }
  463. /*----------------------------------------------------------------------------
  464. | Routine: drawwig (ptr, type)
  465. |
  466. | Results: The point sequence found in the structure pointed by ptr is
  467. | placed in integer arrays for further manipulation by the
  468. | existing routing. With the corresponding type parameter,
  469. | either picurve or HGCurve are called.
  470. *----------------------------------------------------------------------------*/
  471. void
  472. drawwig(POINT * ptr,
  473. int type)
  474. {
  475. register int npts; /* point list index */
  476. int x[MAXPOINTS], y[MAXPOINTS]; /* point list */
  477. for (npts = 1; !Nullpoint(ptr); ptr = PTNextPoint(ptr), npts++) {
  478. x[npts] = (int) (ptr->x * troffscale);
  479. y[npts] = (int) (ptr->y * troffscale);
  480. }
  481. if (--npts) {
  482. if (type == CURVE) /* Use the 2 different types of curves */
  483. HGCurve(&x[0], &y[0], npts);
  484. else
  485. picurve(&x[0], &y[0], npts);
  486. }
  487. }
  488. /*----------------------------------------------------------------------------
  489. | Routine: HGArc (xcenter, ycenter, xstart, ystart, angle)
  490. |
  491. | Results: This routine plots an arc centered about (cx, cy) counter
  492. | clockwise starting from the point (px, py) through `angle'
  493. | degrees. If angle is 0, a full circle is drawn. It does so
  494. | by creating a draw-path around the arc whose density of
  495. | points depends on the size of the arc.
  496. *----------------------------------------------------------------------------*/
  497. void
  498. HGArc(register int cx,
  499. register int cy,
  500. int px,
  501. int py,
  502. int angle)
  503. {
  504. double xs, ys, resolution, fullcircle;
  505. int m;
  506. register int mask;
  507. register int extent;
  508. register int nx;
  509. register int ny;
  510. register int length;
  511. register double epsilon;
  512. xs = px - cx;
  513. ys = py - cy;
  514. length = 0;
  515. resolution = (1.0 + groff_hypot(xs, ys) / res) * PointsPerInterval;
  516. /* mask = (1 << (int) log10(resolution + 1.0)) - 1; */
  517. (void) frexp(resolution, &m); /* A bit more elegant than log10 */
  518. for (mask = 1; mask < m; mask = mask << 1);
  519. mask -= 1;
  520. epsilon = 1.0 / resolution;
  521. fullcircle = (2.0 * pi) * resolution;
  522. if (angle == 0)
  523. extent = (int) fullcircle;
  524. else
  525. extent = (int) (angle * fullcircle / 360.0);
  526. HGtline(px, py);
  527. while (--extent >= 0) {
  528. xs += epsilon * ys;
  529. nx = cx + (int) (xs + 0.5);
  530. ys -= epsilon * xs;
  531. ny = cy + (int) (ys + 0.5);
  532. if (!(extent & mask)) {
  533. HGtline(nx, ny); /* put out a point on circle */
  534. if (length++ > LINELENGTH) {
  535. length = 0;
  536. printf("\\\n");
  537. }
  538. }
  539. } /* end for */
  540. } /* end HGArc */
  541. /*----------------------------------------------------------------------------
  542. | Routine: picurve (xpoints, ypoints, num_of_points)
  543. |
  544. | Results: Draws a curve delimited by (not through) the line segments
  545. | traced by (xpoints, ypoints) point list. This is the `Pic'
  546. | style curve.
  547. *----------------------------------------------------------------------------*/
  548. void
  549. picurve(register int *x,
  550. register int *y,
  551. int npts)
  552. {
  553. register int nseg; /* effective resolution for each curve */
  554. register int xp; /* current point (and temporary) */
  555. register int yp;
  556. int pxp, pyp; /* previous point (to make lines from) */
  557. int i; /* inner curve segment traverser */
  558. int length = 0;
  559. double w; /* position factor */
  560. double t1, t2, t3; /* calculation temps */
  561. if (x[1] == x[npts] && y[1] == y[npts]) {
  562. x[0] = x[npts - 1]; /* if the lines' ends meet, make */
  563. y[0] = y[npts - 1]; /* sure the curve meets */
  564. x[npts + 1] = x[2];
  565. y[npts + 1] = y[2];
  566. } else { /* otherwise, make the ends of the */
  567. x[0] = x[1]; /* curve touch the ending points of */
  568. y[0] = y[1]; /* the line segments */
  569. x[npts + 1] = x[npts];
  570. y[npts + 1] = y[npts];
  571. }
  572. pxp = (x[0] + x[1]) / 2; /* make the last point pointers */
  573. pyp = (y[0] + y[1]) / 2; /* point to the start of the 1st line */
  574. tmove2(pxp, pyp);
  575. for (; npts--; x++, y++) { /* traverse the line segments */
  576. xp = x[0] - x[1];
  577. yp = y[0] - y[1];
  578. nseg = (int) groff_hypot((double) xp, (double) yp);
  579. xp = x[1] - x[2];
  580. yp = y[1] - y[2];
  581. /* `nseg' is the number of line */
  582. /* segments that will be drawn for */
  583. /* each curve segment. */
  584. nseg = (int) ((double) (nseg + (int) groff_hypot((double) xp, (double) yp)) /
  585. res * PointsPerInterval);
  586. for (i = 1; i < nseg; i++) {
  587. w = (double) i / (double) nseg;
  588. t1 = w * w;
  589. t3 = t1 + 1.0 - (w + w);
  590. t2 = 2.0 - (t3 + t1);
  591. xp = (((int) (t1 * x[2] + t2 * x[1] + t3 * x[0])) + 1) / 2;
  592. yp = (((int) (t1 * y[2] + t2 * y[1] + t3 * y[0])) + 1) / 2;
  593. HGtline(xp, yp);
  594. if (length++ > LINELENGTH) {
  595. length = 0;
  596. printf("\\\n");
  597. }
  598. }
  599. }
  600. }
  601. /*----------------------------------------------------------------------------
  602. | Routine: HGCurve(xpoints, ypoints, num_points)
  603. |
  604. | Results: This routine generates a smooth curve through a set of
  605. | points. The method used is the parametric spline curve on
  606. | unit knot mesh described in `Spline Curve Techniques' by
  607. | Patrick Baudelaire, Robert Flegal, and Robert Sproull --
  608. | Xerox Parc.
  609. *----------------------------------------------------------------------------*/
  610. void
  611. HGCurve(int *x,
  612. int *y,
  613. int numpoints)
  614. {
  615. double h[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS];
  616. double d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS];
  617. double t, t2, t3;
  618. register int j;
  619. register int k;
  620. register int nx;
  621. register int ny;
  622. int lx, ly;
  623. int length = 0;
  624. lx = x[1];
  625. ly = y[1];
  626. tmove2(lx, ly);
  627. /*
  628. * Solve for derivatives of the curve at each point separately for x and y
  629. * (parametric).
  630. */
  631. Paramaterize(x, y, h, numpoints);
  632. /* closed curve */
  633. if ((x[1] == x[numpoints]) && (y[1] == y[numpoints])) {
  634. PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
  635. PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
  636. } else {
  637. NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
  638. NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
  639. }
  640. /*
  641. * generate the curve using the above information and PointsPerInterval
  642. * vectors between each specified knot.
  643. */
  644. for (j = 1; j < numpoints; ++j) {
  645. if ((x[j] == x[j + 1]) && (y[j] == y[j + 1]))
  646. continue;
  647. for (k = 0; k <= PointsPerInterval; ++k) {
  648. t = (double) k *h[j] / (double) PointsPerInterval;
  649. t2 = t * t;
  650. t3 = t * t * t;
  651. nx = x[j] + (int) (t * dx[j] + t2 * d2x[j] / 2 + t3 * d3x[j] / 6);
  652. ny = y[j] + (int) (t * dy[j] + t2 * d2y[j] / 2 + t3 * d3y[j] / 6);
  653. HGtline(nx, ny);
  654. if (length++ > LINELENGTH) {
  655. length = 0;
  656. printf("\\\n");
  657. }
  658. } /* end for k */
  659. } /* end for j */
  660. } /* end HGCurve */
  661. /*----------------------------------------------------------------------------
  662. | Routine: Paramaterize (xpoints, ypoints, hparams, num_points)
  663. |
  664. | Results: This routine calculates parameteric values for use in
  665. | calculating curves. The parametric values are returned
  666. | in the array h. The values are an approximation of
  667. | cumulative arc lengths of the curve (uses cord length).
  668. | For additional information, see paper cited below.
  669. *----------------------------------------------------------------------------*/
  670. void
  671. Paramaterize(int x[],
  672. int y[],
  673. double h[],
  674. int n)
  675. {
  676. register int dx;
  677. register int dy;
  678. register int i;
  679. register int j;
  680. double u[MAXPOINTS];
  681. for (i = 1; i <= n; ++i) {
  682. u[i] = 0;
  683. for (j = 1; j < i; j++) {
  684. dx = x[j + 1] - x[j];
  685. dy = y[j + 1] - y[j];
  686. /* Here was overflowing, so I changed it. */
  687. /* u[i] += sqrt ((double) (dx * dx + dy * dy)); */
  688. u[i] += groff_hypot((double) dx, (double) dy);
  689. }
  690. }
  691. for (i = 1; i < n; ++i)
  692. h[i] = u[i + 1] - u[i];
  693. } /* end Paramaterize */
  694. /*----------------------------------------------------------------------------
  695. | Routine: PeriodicSpline (h, z, dz, d2z, d3z, npoints)
  696. |
  697. | Results: This routine solves for the cubic polynomial to fit a spline
  698. | curve to the the points specified by the list of values.
  699. | The Curve generated is periodic. The algorithms for this
  700. | curve are from the `Spline Curve Techniques' paper cited
  701. | above.
  702. *----------------------------------------------------------------------------*/
  703. void
  704. PeriodicSpline(double h[], /* paramaterization */
  705. int z[], /* point list */
  706. double dz[], /* to return the 1st derivative */
  707. double d2z[], /* 2nd derivative */
  708. double d3z[], /* 3rd derivative */
  709. int npoints) /* number of valid points */
  710. {
  711. double d[MAXPOINTS];
  712. double deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
  713. double c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS];
  714. int i;
  715. /* step 1 */
  716. for (i = 1; i < npoints; ++i) {
  717. deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
  718. }
  719. h[0] = h[npoints - 1];
  720. deltaz[0] = deltaz[npoints - 1];
  721. /* step 2 */
  722. for (i = 1; i < npoints - 1; ++i) {
  723. d[i] = deltaz[i + 1] - deltaz[i];
  724. }
  725. d[0] = deltaz[1] - deltaz[0];
  726. /* step 3a */
  727. a[1] = 2 * (h[0] + h[1]);
  728. b[1] = d[0];
  729. c[1] = h[0];
  730. for (i = 2; i < npoints - 1; ++i) {
  731. a[i] = 2 * (h[i - 1] + h[i]) -
  732. pow((double) h[i - 1], (double) 2.0) / a[i - 1];
  733. b[i] = d[i - 1] - h[i - 1] * b[i - 1] / a[i - 1];
  734. c[i] = -h[i - 1] * c[i - 1] / a[i - 1];
  735. }
  736. /* step 3b */
  737. r[npoints - 1] = 1;
  738. s[npoints - 1] = 0;
  739. for (i = npoints - 2; i > 0; --i) {
  740. r[i] = -(h[i] * r[i + 1] + c[i]) / a[i];
  741. s[i] = (6 * b[i] - h[i] * s[i + 1]) / a[i];
  742. }
  743. /* step 4 */
  744. d2z[npoints - 1] = (6 * d[npoints - 2] - h[0] * s[1]
  745. - h[npoints - 1] * s[npoints - 2])
  746. / (h[0] * r[1] + h[npoints - 1] * r[npoints - 2]
  747. + 2 * (h[npoints - 2] + h[0]));
  748. for (i = 1; i < npoints - 1; ++i) {
  749. d2z[i] = r[i] * d2z[npoints - 1] + s[i];
  750. }
  751. d2z[npoints] = d2z[1];
  752. /* step 5 */
  753. for (i = 1; i < npoints; ++i) {
  754. dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
  755. d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
  756. }
  757. } /* end PeriodicSpline */
  758. /*----------------------------------------------------------------------------
  759. | Routine: NaturalEndSpline (h, z, dz, d2z, d3z, npoints)
  760. |
  761. | Results: This routine solves for the cubic polynomial to fit a spline
  762. | curve the the points specified by the list of values. The
  763. | alogrithms for this curve are from the `Spline Curve
  764. | Techniques' paper cited above.
  765. *----------------------------------------------------------------------------*/
  766. void
  767. NaturalEndSpline(double h[], /* parameterization */
  768. int z[], /* Point list */
  769. double dz[], /* to return the 1st derivative */
  770. double d2z[], /* 2nd derivative */
  771. double d3z[], /* 3rd derivative */
  772. int npoints) /* number of valid points */
  773. {
  774. double d[MAXPOINTS];
  775. double deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
  776. int i;
  777. /* step 1 */
  778. for (i = 1; i < npoints; ++i) {
  779. deltaz[i] = h[i] ? ((double) (z[i + 1] - z[i])) / h[i] : 0;
  780. }
  781. deltaz[0] = deltaz[npoints - 1];
  782. /* step 2 */
  783. for (i = 1; i < npoints - 1; ++i) {
  784. d[i] = deltaz[i + 1] - deltaz[i];
  785. }
  786. d[0] = deltaz[1] - deltaz[0];
  787. /* step 3 */
  788. a[0] = 2 * (h[2] + h[1]);
  789. b[0] = d[1];
  790. for (i = 1; i < npoints - 2; ++i) {
  791. a[i] = 2 * (h[i + 1] + h[i + 2]) -
  792. pow((double) h[i + 1], (double) 2.0) / a[i - 1];
  793. b[i] = d[i + 1] - h[i + 1] * b[i - 1] / a[i - 1];
  794. }
  795. /* step 4 */
  796. d2z[npoints] = d2z[1] = 0;
  797. for (i = npoints - 1; i > 1; --i) {
  798. d2z[i] = (6 * b[i - 2] - h[i] * d2z[i + 1]) / a[i - 2];
  799. }
  800. /* step 5 */
  801. for (i = 1; i < npoints; ++i) {
  802. dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
  803. d3z[i] = h[i] ? (d2z[i + 1] - d2z[i]) / h[i] : 0;
  804. }
  805. } /* end NaturalEndSpline */
  806. /*----------------------------------------------------------------------------*
  807. | Routine: change (x_position, y_position, visible_flag)
  808. |
  809. | Results: As HGtline passes from the invisible to visible (or vice
  810. | versa) portion of a line, change is called to either draw
  811. | the line, or initialize the beginning of the next one.
  812. | Change calls line to draw segments if visible_flag is set
  813. | (which means we're leaving a visible area).
  814. *----------------------------------------------------------------------------*/
  815. void
  816. change(register int x,
  817. register int y,
  818. register int vis)
  819. {
  820. static int length = 0;
  821. if (vis) { /* leaving a visible area, draw it. */
  822. line(x, y);
  823. if (length++ > LINELENGTH) {
  824. length = 0;
  825. printf("\\\n");
  826. }
  827. } else { /* otherwise, we're entering one, remember */
  828. /* beginning */
  829. tmove2(x, y);
  830. }
  831. }
  832. /*----------------------------------------------------------------------------
  833. | Routine: HGtline (xstart, ystart, xend, yend)
  834. |
  835. | Results: Draws a line from current position to (x1,y1) using line(x1,
  836. | y1) to place individual segments of dotted or dashed lines.
  837. *----------------------------------------------------------------------------*/
  838. void
  839. HGtline(int x_1,
  840. int y_1)
  841. {
  842. register int x_0 = lastx;
  843. register int y_0 = lasty;
  844. register int dx;
  845. register int dy;
  846. register int oldcoord;
  847. register int res1;
  848. register int visible;
  849. register int res2;
  850. register int xinc;
  851. register int yinc;
  852. register int dotcounter;
  853. if (linmod == SOLID) {
  854. line(x_1, y_1);
  855. return;
  856. }
  857. /* for handling different resolutions */
  858. dotcounter = linmod << dotshifter;
  859. xinc = 1;
  860. yinc = 1;
  861. if ((dx = x_1 - x_0) < 0) {
  862. xinc = -xinc;
  863. dx = -dx;
  864. }
  865. if ((dy = y_1 - y_0) < 0) {
  866. yinc = -yinc;
  867. dy = -dy;
  868. }
  869. res1 = 0;
  870. res2 = 0;
  871. visible = 0;
  872. if (dx >= dy) {
  873. oldcoord = y_0;
  874. while (x_0 != x_1) {
  875. if ((x_0 & dotcounter) && !visible) {
  876. change(x_0, y_0, 0);
  877. visible = 1;
  878. } else if (visible && !(x_0 & dotcounter)) {
  879. change(x_0 - xinc, oldcoord, 1);
  880. visible = 0;
  881. }
  882. if (res1 > res2) {
  883. oldcoord = y_0;
  884. res2 += dx - res1;
  885. res1 = 0;
  886. y_0 += yinc;
  887. }
  888. res1 += dy;
  889. x_0 += xinc;
  890. }
  891. } else {
  892. oldcoord = x_0;
  893. while (y_0 != y_1) {
  894. if ((y_0 & dotcounter) && !visible) {
  895. change(x_0, y_0, 0);
  896. visible = 1;
  897. } else if (visible && !(y_0 & dotcounter)) {
  898. change(oldcoord, y_0 - yinc, 1);
  899. visible = 0;
  900. }
  901. if (res1 > res2) {
  902. oldcoord = x_0;
  903. res2 += dy - res1;
  904. res1 = 0;
  905. x_0 += xinc;
  906. }
  907. res1 += dx;
  908. y_0 += yinc;
  909. }
  910. }
  911. if (visible)
  912. change(x_1, y_1, 1);
  913. else
  914. change(x_1, y_1, 0);
  915. }
  916. /* EOF */