URI:
       tarcgen.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tarcgen.c (5688B)
       ---
            1 #include        <stdio.h>
            2 #include        <math.h>
            3 #include        "pic.h"
            4 #include        "y.tab.h"
            5 
            6 obj*
            7 arcgen(int type)        /* handles circular and (eventually) elliptical arcs */
            8 {
            9         static double prevw = HT10;
           10         static double prevh = HT5;
           11         static double prevrad = HT2;
           12         static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 };
           13         static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 };
           14         static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 };
           15         static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 };
           16         static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR, R_DIR, U_DIR, L_DIR };
           17         double dx2, dy2, ht, phi, r, d;
           18         int i, head, to, at, cw, invis, ddtype;
           19         obj *p, *ppos;
           20         double fromx, fromy, tox, toy;
           21         Attr *ap;
           22 
           23         tox = 0;
           24         toy = 0;
           25         prevrad = getfval("arcrad");
           26         prevh = getfval("arrowht");
           27         prevw = getfval("arrowwid");
           28         fromx = curx;
           29         fromy = cury;
           30         head = to = at = cw = invis = ddtype = 0;
           31         for (i = 0; i < nattr; i++) {
           32                 ap = &attr[i];
           33                 switch (ap->a_type) {
           34                 case TEXTATTR:
           35                         savetext(ap->a_sub, ap->a_val.p);
           36                         break;
           37                 case HEAD:
           38                         head += ap->a_val.i;
           39                         break;
           40                 case INVIS:
           41                         invis = INVIS;
           42                         break;
           43                 case HEIGHT:        /* length of arrowhead */
           44                         prevh = ap->a_val.f;
           45                         break;
           46                 case WIDTH:        /* width of arrowhead */
           47                         prevw = ap->a_val.f;
           48                         break;
           49                 case RADIUS:
           50                         prevrad = ap->a_val.f;
           51                         break;
           52                 case DIAMETER:
           53                         prevrad = ap->a_val.f / 2;
           54                         break;
           55                 case CW:
           56                         cw = 1;
           57                         break;
           58                 case FROM:        /* start point of arc */
           59                         ppos = ap->a_val.o;
           60                         fromx = ppos->o_x;
           61                         fromy = ppos->o_y;
           62                         break;
           63                 case TO:        /* end point of arc */
           64                         ppos = ap->a_val.o;
           65                         tox = ppos->o_x;
           66                         toy = ppos->o_y;
           67                         to++;
           68                         break;
           69                 case AT:        /* center of arc */
           70                         ppos = ap->a_val.o;
           71                         curx = ppos->o_x;
           72                         cury = ppos->o_y;
           73                         at = 1;
           74                         break;
           75                 case UP:
           76                         hvmode = U_DIR;
           77                         break;
           78                 case DOWN:
           79                         hvmode = D_DIR;
           80                         break;
           81                 case RIGHT:
           82                         hvmode = R_DIR;
           83                         break;
           84                 case LEFT:
           85                         hvmode = L_DIR;
           86                         break;
           87                 }
           88         }
           89         if (!at && !to) {        /* the defaults are mostly OK */
           90                 curx = fromx + prevrad * dctrx[cw][hvmode];
           91                 cury = fromy + prevrad * dctry[cw][hvmode];
           92                 tox = fromx + prevrad * dtox[cw][hvmode];
           93                 toy = fromy + prevrad * dtoy[cw][hvmode];
           94                 hvmode = nexthv[cw][hvmode];
           95         }
           96         else if (!at) {
           97                 dx2 = (tox - fromx) / 2;
           98                 dy2 = (toy - fromy) / 2;
           99                 phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2);
          100                 if (prevrad <= 0.0)
          101                         prevrad = dx2*dx2+dy2*dy2;
          102                 for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2)
          103                         ;        /* this kludge gets around too-small radii */
          104                 prevrad = r;
          105                 ht = sqrt(d);
          106                 curx = fromx + dx2 + ht * cos(phi);
          107                 cury = fromy + dy2 + ht * sin(phi);
          108                 dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n",
          109                         dx2, dy2, phi, r, ht);
          110         }
          111         else if (at && !to) {        /* do we have all the cases??? */
          112                 tox = fromx + prevrad * dtox[cw][hvmode];
          113                 toy = fromy + prevrad * dtoy[cw][hvmode];
          114                 hvmode = nexthv[cw][hvmode];
          115         }
          116         if (cw) {        /* interchange roles of from-to and heads */
          117                 double temp;
          118                 temp = fromx; fromx = tox; tox = temp;
          119                 temp = fromy; fromy = toy; toy = temp;
          120                 if (head == HEAD1)
          121                         head = HEAD2;
          122                 else if (head == HEAD2)
          123                         head = HEAD1;
          124         }
          125         p = makenode(type, 7);
          126         arc_extreme(fromx, fromy, tox, toy, curx, cury);
          127         p->o_val[0] = fromx;
          128         p->o_val[1] = fromy;
          129         p->o_val[2] = tox;
          130         p->o_val[3] = toy;
          131         if (cw) {
          132                 curx = fromx;
          133                 cury = fromy;
          134         } else {
          135                 curx = tox;
          136                 cury = toy;
          137         }
          138         p->o_val[4] = prevw;
          139         p->o_val[5] = prevh;
          140         p->o_val[6] = prevrad;
          141         p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype;
          142         if (head)
          143                 p->o_nhead = getfval("arrowhead");
          144         dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n",
          145                 prevrad, p->o_x, p->o_y,
          146                 p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]);
          147         return(p);
          148 }
          149 
          150 /***************************************************************************
          151    bounding box of a circular arc             Eric Grosse  24 May 84
          152 
          153 Conceptually, this routine generates a list consisting of the start,
          154 end, and whichever north, east, south, and west points lie on the arc.
          155 The bounding box is then the range of this list.
          156     list = {start,end}
          157     j = quadrant(start)
          158     k = quadrant(end)
          159     if( j==k && long way 'round )  append north,west,south,east
          160     else
          161       while( j != k )
          162          append center+radius*[j-th of north,west,south,east unit vectors]
          163          j += 1  (mod 4)
          164     return( bounding box of list )
          165 The following code implements this, with simple optimizations.
          166 ***********************************************************************/
          167 
          168 
          169 void
          170 arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc)
          171 {
          172         /* assumes center isn't too far out */
          173         double r, xmin, ymin, xmax, ymax;
          174         int j, k;
          175         x0 -= xc; y0 -= yc;        /* move to center */
          176         x1 -= xc; y1 -= yc;
          177         xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
          178         xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
          179         r = sqrt(x0*x0 + y0*y0);
          180         if (r > 0.0) {
          181                 j = quadrant(x0,y0);
          182                 k = quadrant(x1,y1);
          183                 if (j == k && y1*x0 < x1*y0) {
          184                         /* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
          185                         if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
          186                         if( xmax <  r) xmax =  r; if( ymax <  r) ymax =  r;
          187                 } else {
          188                         while (j != k) {
          189                                 switch (j) {
          190                                         case 1: if( ymax <  r) ymax =  r; break; /* north */
          191                                         case 2: if( xmin > -r) xmin = -r; break; /* west */
          192                                         case 3: if( ymin > -r) ymin = -r; break; /* south */
          193                                         case 4: if( xmax <  r) xmax =  r; break; /* east */
          194                                 }
          195                                 j = j%4 + 1;
          196                         }
          197                 }
          198         }
          199         xmin += xc; ymin += yc;
          200         xmax += xc; ymax += yc;
          201         extreme(xmin, ymin);
          202         extreme(xmax, ymax);
          203 }
          204 
          205 int
          206 quadrant(double x, double y)
          207 {
          208         if (     x>=0.0 && y> 0.0) return(1);
          209         else if( x< 0.0 && y>=0.0) return(2);
          210         else if( x<=0.0 && y< 0.0) return(3);
          211         else if( x> 0.0 && y<=0.0) return(4);
          212         else                           return 0;        /* shut up lint */
          213 }