13e12c5d1SDavid du Colombier #include <stdio.h>
23e12c5d1SDavid du Colombier #include <math.h>
33e12c5d1SDavid du Colombier #include "pic.h"
43e12c5d1SDavid du Colombier #include "y.tab.h"
53e12c5d1SDavid du Colombier
63e12c5d1SDavid du Colombier void arc_extreme(double, double, double, double, double, double);
73e12c5d1SDavid du Colombier int quadrant(double x, double y);
83e12c5d1SDavid du Colombier
arcgen(int type)93e12c5d1SDavid du Colombier obj *arcgen(int type) /* handles circular and (eventually) elliptical arcs */
103e12c5d1SDavid du Colombier {
113e12c5d1SDavid du Colombier static double prevw = HT10;
123e12c5d1SDavid du Colombier static double prevh = HT5;
133e12c5d1SDavid du Colombier static double prevrad = HT2;
143e12c5d1SDavid du Colombier static int dtox[2][4] ={ 1, -1, -1, 1, 1, 1, -1, -1 };
153e12c5d1SDavid du Colombier static int dtoy[2][4] ={ 1, 1, -1, -1, -1, 1, 1, -1 };
163e12c5d1SDavid du Colombier static int dctrx[2][4] ={ 0, -1, 0, 1, 0, 1, 0, -1 };
173e12c5d1SDavid du Colombier static int dctry[2][4] ={ 1, 0, -1, 0, -1, 0, 1, 0 };
183e12c5d1SDavid du Colombier static int nexthv[2][4] ={ U_DIR, L_DIR, D_DIR, R_DIR, D_DIR, R_DIR, U_DIR, L_DIR };
193e12c5d1SDavid du Colombier double dx2, dy2, ht, phi, r, d;
20*7dd7cddfSDavid du Colombier int i, head, to, at, cw, invis, ddtype, battr;
213e12c5d1SDavid du Colombier obj *p, *ppos;
22*7dd7cddfSDavid du Colombier double fromx, fromy, tox, toy, fillval = 0;
233e12c5d1SDavid du Colombier Attr *ap;
243e12c5d1SDavid du Colombier
253e12c5d1SDavid du Colombier prevrad = getfval("arcrad");
263e12c5d1SDavid du Colombier prevh = getfval("arrowht");
273e12c5d1SDavid du Colombier prevw = getfval("arrowwid");
283e12c5d1SDavid du Colombier fromx = curx;
293e12c5d1SDavid du Colombier fromy = cury;
30*7dd7cddfSDavid du Colombier head = to = at = cw = invis = ddtype = battr = 0;
313e12c5d1SDavid du Colombier for (i = 0; i < nattr; i++) {
323e12c5d1SDavid du Colombier ap = &attr[i];
333e12c5d1SDavid du Colombier switch (ap->a_type) {
343e12c5d1SDavid du Colombier case TEXTATTR:
353e12c5d1SDavid du Colombier savetext(ap->a_sub, ap->a_val.p);
363e12c5d1SDavid du Colombier break;
373e12c5d1SDavid du Colombier case HEAD:
383e12c5d1SDavid du Colombier head += ap->a_val.i;
393e12c5d1SDavid du Colombier break;
403e12c5d1SDavid du Colombier case INVIS:
413e12c5d1SDavid du Colombier invis = INVIS;
423e12c5d1SDavid du Colombier break;
433e12c5d1SDavid du Colombier case HEIGHT: /* length of arrowhead */
443e12c5d1SDavid du Colombier prevh = ap->a_val.f;
453e12c5d1SDavid du Colombier break;
463e12c5d1SDavid du Colombier case WIDTH: /* width of arrowhead */
473e12c5d1SDavid du Colombier prevw = ap->a_val.f;
483e12c5d1SDavid du Colombier break;
493e12c5d1SDavid du Colombier case RADIUS:
503e12c5d1SDavid du Colombier prevrad = ap->a_val.f;
513e12c5d1SDavid du Colombier break;
523e12c5d1SDavid du Colombier case DIAMETER:
533e12c5d1SDavid du Colombier prevrad = ap->a_val.f / 2;
543e12c5d1SDavid du Colombier break;
553e12c5d1SDavid du Colombier case CW:
563e12c5d1SDavid du Colombier cw = 1;
573e12c5d1SDavid du Colombier break;
583e12c5d1SDavid du Colombier case FROM: /* start point of arc */
593e12c5d1SDavid du Colombier ppos = ap->a_val.o;
603e12c5d1SDavid du Colombier fromx = ppos->o_x;
613e12c5d1SDavid du Colombier fromy = ppos->o_y;
623e12c5d1SDavid du Colombier break;
633e12c5d1SDavid du Colombier case TO: /* end point of arc */
643e12c5d1SDavid du Colombier ppos = ap->a_val.o;
653e12c5d1SDavid du Colombier tox = ppos->o_x;
663e12c5d1SDavid du Colombier toy = ppos->o_y;
673e12c5d1SDavid du Colombier to++;
683e12c5d1SDavid du Colombier break;
693e12c5d1SDavid du Colombier case AT: /* center of arc */
703e12c5d1SDavid du Colombier ppos = ap->a_val.o;
713e12c5d1SDavid du Colombier curx = ppos->o_x;
723e12c5d1SDavid du Colombier cury = ppos->o_y;
733e12c5d1SDavid du Colombier at = 1;
743e12c5d1SDavid du Colombier break;
753e12c5d1SDavid du Colombier case UP:
763e12c5d1SDavid du Colombier hvmode = U_DIR;
773e12c5d1SDavid du Colombier break;
783e12c5d1SDavid du Colombier case DOWN:
793e12c5d1SDavid du Colombier hvmode = D_DIR;
803e12c5d1SDavid du Colombier break;
813e12c5d1SDavid du Colombier case RIGHT:
823e12c5d1SDavid du Colombier hvmode = R_DIR;
833e12c5d1SDavid du Colombier break;
843e12c5d1SDavid du Colombier case LEFT:
853e12c5d1SDavid du Colombier hvmode = L_DIR;
863e12c5d1SDavid du Colombier break;
87*7dd7cddfSDavid du Colombier case FILL:
88*7dd7cddfSDavid du Colombier battr |= FILLBIT;
89*7dd7cddfSDavid du Colombier if (ap->a_sub == DEFAULT)
90*7dd7cddfSDavid du Colombier fillval = getfval("fillval");
91*7dd7cddfSDavid du Colombier else
92*7dd7cddfSDavid du Colombier fillval = ap->a_val.f;
93*7dd7cddfSDavid du Colombier break;
943e12c5d1SDavid du Colombier }
953e12c5d1SDavid du Colombier }
963e12c5d1SDavid du Colombier if (!at && !to) { /* the defaults are mostly OK */
973e12c5d1SDavid du Colombier curx = fromx + prevrad * dctrx[cw][hvmode];
983e12c5d1SDavid du Colombier cury = fromy + prevrad * dctry[cw][hvmode];
993e12c5d1SDavid du Colombier tox = fromx + prevrad * dtox[cw][hvmode];
1003e12c5d1SDavid du Colombier toy = fromy + prevrad * dtoy[cw][hvmode];
1013e12c5d1SDavid du Colombier hvmode = nexthv[cw][hvmode];
1023e12c5d1SDavid du Colombier }
1033e12c5d1SDavid du Colombier else if (!at) {
1043e12c5d1SDavid du Colombier dx2 = (tox - fromx) / 2;
1053e12c5d1SDavid du Colombier dy2 = (toy - fromy) / 2;
1063e12c5d1SDavid du Colombier phi = atan2(dy2, dx2) + (cw ? -PI/2 : PI/2);
1073e12c5d1SDavid du Colombier if (prevrad <= 0.0)
1083e12c5d1SDavid du Colombier prevrad = dx2*dx2+dy2*dy2;
1093e12c5d1SDavid du Colombier for (r=prevrad; (d = r*r - (dx2*dx2+dy2*dy2)) <= 0.0; r *= 2)
1103e12c5d1SDavid du Colombier ; /* this kludge gets around too-small radii */
1113e12c5d1SDavid du Colombier prevrad = r;
1123e12c5d1SDavid du Colombier ht = sqrt(d);
1133e12c5d1SDavid du Colombier curx = fromx + dx2 + ht * cos(phi);
1143e12c5d1SDavid du Colombier cury = fromy + dy2 + ht * sin(phi);
1153e12c5d1SDavid du Colombier dprintf("dx2,dy2=%g,%g, phi=%g, r,ht=%g,%g\n",
1163e12c5d1SDavid du Colombier dx2, dy2, phi, r, ht);
1173e12c5d1SDavid du Colombier }
1183e12c5d1SDavid du Colombier else if (at && !to) { /* do we have all the cases??? */
1193e12c5d1SDavid du Colombier tox = fromx + prevrad * dtox[cw][hvmode];
1203e12c5d1SDavid du Colombier toy = fromy + prevrad * dtoy[cw][hvmode];
1213e12c5d1SDavid du Colombier hvmode = nexthv[cw][hvmode];
1223e12c5d1SDavid du Colombier }
1233e12c5d1SDavid du Colombier if (cw) { /* interchange roles of from-to and heads */
1243e12c5d1SDavid du Colombier double temp;
1253e12c5d1SDavid du Colombier temp = fromx; fromx = tox; tox = temp;
1263e12c5d1SDavid du Colombier temp = fromy; fromy = toy; toy = temp;
1273e12c5d1SDavid du Colombier if (head == HEAD1)
1283e12c5d1SDavid du Colombier head = HEAD2;
1293e12c5d1SDavid du Colombier else if (head == HEAD2)
1303e12c5d1SDavid du Colombier head = HEAD1;
1313e12c5d1SDavid du Colombier }
1323e12c5d1SDavid du Colombier p = makenode(type, 7);
1333e12c5d1SDavid du Colombier arc_extreme(fromx, fromy, tox, toy, curx, cury);
1343e12c5d1SDavid du Colombier p->o_val[0] = fromx;
1353e12c5d1SDavid du Colombier p->o_val[1] = fromy;
1363e12c5d1SDavid du Colombier p->o_val[2] = tox;
1373e12c5d1SDavid du Colombier p->o_val[3] = toy;
1383e12c5d1SDavid du Colombier if (cw) {
1393e12c5d1SDavid du Colombier curx = fromx;
1403e12c5d1SDavid du Colombier cury = fromy;
1413e12c5d1SDavid du Colombier } else {
1423e12c5d1SDavid du Colombier curx = tox;
1433e12c5d1SDavid du Colombier cury = toy;
1443e12c5d1SDavid du Colombier }
1453e12c5d1SDavid du Colombier p->o_val[4] = prevw;
1463e12c5d1SDavid du Colombier p->o_val[5] = prevh;
1473e12c5d1SDavid du Colombier p->o_val[6] = prevrad;
148*7dd7cddfSDavid du Colombier p->o_attr = head | (cw ? CW_ARC : 0) | invis | ddtype | battr;
149*7dd7cddfSDavid du Colombier p->o_fillval = fillval;
1503e12c5d1SDavid du Colombier if (head)
1513e12c5d1SDavid du Colombier p->o_nhead = getfval("arrowhead");
1523e12c5d1SDavid du Colombier dprintf("arc rad %g at %g %g from %g %g to %g %g head %g %g\n",
1533e12c5d1SDavid du Colombier prevrad, p->o_x, p->o_y,
1543e12c5d1SDavid du Colombier p->o_val[0], p->o_val[1], p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5]);
1553e12c5d1SDavid du Colombier return(p);
1563e12c5d1SDavid du Colombier }
1573e12c5d1SDavid du Colombier
1583e12c5d1SDavid du Colombier /***************************************************************************
1593e12c5d1SDavid du Colombier bounding box of a circular arc Eric Grosse 24 May 84
1603e12c5d1SDavid du Colombier
1613e12c5d1SDavid du Colombier Conceptually, this routine generates a list consisting of the start,
1623e12c5d1SDavid du Colombier end, and whichever north, east, south, and west points lie on the arc.
1633e12c5d1SDavid du Colombier The bounding box is then the range of this list.
1643e12c5d1SDavid du Colombier list = {start,end}
1653e12c5d1SDavid du Colombier j = quadrant(start)
1663e12c5d1SDavid du Colombier k = quadrant(end)
1673e12c5d1SDavid du Colombier if( j==k && long way 'round ) append north,west,south,east
1683e12c5d1SDavid du Colombier else
1693e12c5d1SDavid du Colombier while( j != k )
1703e12c5d1SDavid du Colombier append center+radius*[j-th of north,west,south,east unit vectors]
1713e12c5d1SDavid du Colombier j += 1 (mod 4)
1723e12c5d1SDavid du Colombier return( bounding box of list )
1733e12c5d1SDavid du Colombier The following code implements this, with simple optimizations.
1743e12c5d1SDavid du Colombier ***********************************************************************/
1753e12c5d1SDavid du Colombier
1763e12c5d1SDavid du Colombier
arc_extreme(double x0,double y0,double x1,double y1,double xc,double yc)1773e12c5d1SDavid du Colombier void arc_extreme(double x0, double y0, double x1, double y1, double xc, double yc)
1783e12c5d1SDavid du Colombier /* start, end, center */
1793e12c5d1SDavid du Colombier {
1803e12c5d1SDavid du Colombier /* assumes center isn't too far out */
1813e12c5d1SDavid du Colombier double r, xmin, ymin, xmax, ymax;
1823e12c5d1SDavid du Colombier int j, k;
1833e12c5d1SDavid du Colombier x0 -= xc; y0 -= yc; /* move to center */
1843e12c5d1SDavid du Colombier x1 -= xc; y1 -= yc;
1853e12c5d1SDavid du Colombier xmin = (x0<x1)?x0:x1; ymin = (y0<y1)?y0:y1;
1863e12c5d1SDavid du Colombier xmax = (x0>x1)?x0:x1; ymax = (y0>y1)?y0:y1;
1873e12c5d1SDavid du Colombier r = sqrt(x0*x0 + y0*y0);
1883e12c5d1SDavid du Colombier if (r > 0.0) {
1893e12c5d1SDavid du Colombier j = quadrant(x0,y0);
1903e12c5d1SDavid du Colombier k = quadrant(x1,y1);
1913e12c5d1SDavid du Colombier if (j == k && y1*x0 < x1*y0) {
1923e12c5d1SDavid du Colombier /* viewed as complex numbers, if Im(z1/z0)<0, arc is big */
1933e12c5d1SDavid du Colombier if( xmin > -r) xmin = -r; if( ymin > -r) ymin = -r;
1943e12c5d1SDavid du Colombier if( xmax < r) xmax = r; if( ymax < r) ymax = r;
1953e12c5d1SDavid du Colombier } else {
1963e12c5d1SDavid du Colombier while (j != k) {
1973e12c5d1SDavid du Colombier switch (j) {
1983e12c5d1SDavid du Colombier case 1: if( ymax < r) ymax = r; break; /* north */
1993e12c5d1SDavid du Colombier case 2: if( xmin > -r) xmin = -r; break; /* west */
2003e12c5d1SDavid du Colombier case 3: if( ymin > -r) ymin = -r; break; /* south */
2013e12c5d1SDavid du Colombier case 4: if( xmax < r) xmax = r; break; /* east */
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier j = j%4 + 1;
2043e12c5d1SDavid du Colombier }
2053e12c5d1SDavid du Colombier }
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier xmin += xc; ymin += yc;
2083e12c5d1SDavid du Colombier xmax += xc; ymax += yc;
2093e12c5d1SDavid du Colombier extreme(xmin, ymin);
2103e12c5d1SDavid du Colombier extreme(xmax, ymax);
2113e12c5d1SDavid du Colombier }
2123e12c5d1SDavid du Colombier
quadrant(double x,double y)2133e12c5d1SDavid du Colombier quadrant(double x, double y)
2143e12c5d1SDavid du Colombier {
2153e12c5d1SDavid du Colombier if ( x>=0.0 && y> 0.0) return(1);
2163e12c5d1SDavid du Colombier else if( x< 0.0 && y>=0.0) return(2);
2173e12c5d1SDavid du Colombier else if( x<=0.0 && y< 0.0) return(3);
2183e12c5d1SDavid du Colombier else if( x> 0.0 && y<=0.0) return(4);
2193e12c5d1SDavid du Colombier else return 0; /* shut up lint */
2203e12c5d1SDavid du Colombier }
2213e12c5d1SDavid du Colombier
222