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