LCOV - code coverage report
Current view: top level - preproc/grn - hgraph.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 296 432 68.5 %
Date: 2026-01-16 17:51:41 Functions: 16 20 80.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14