Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "pic.h"
#include "y.tab.h"

obj *linegen(int type)
{
        static double prevdx = HT;
        static double prevdy = 0;
        static double prevw = HT10;
        static double prevh = HT5;
        int i, j, some, head, ddtype, invis, chop, battr, with;
        double ddval, chop1, chop2, x0, y0, x1, y1;
        double fillval = 0;
        double theta;
        double defx, defy, xwith, ywith;
        obj *p, *ppos;
        static int xtab[] = { 1, 0, -1, 0 };    /* R=0, U=1, L=2, D=3 */
        static int ytab[] = { 0, 1, 0, -1 };
        double dx[500], dy[500];
        int ndxy;
        double nx, ny;
        Attr *ap, *chop_ap[4];

        nx = curx;
        ny = cury;
        defx = getfval("linewid");
        defy = getfval("lineht");
        prevh = getfval("arrowht");
        prevw = getfval("arrowwid");
        dx[0] = dy[0] = ndxy = some = head = invis = battr = with = 0;
        chop = chop1 = chop2 = 0;
        ddtype = ddval = xwith = ywith = 0;
        for (i = 0; i < nattr; i++) {
                ap = &attr[i];
                switch (ap->a_type) {
                case TEXTATTR:
                        savetext(ap->a_sub, ap->a_val.p);
                        break;
                case HEAD:
                        head += ap->a_val.i;
                        break;
                case INVIS:
                        invis = INVIS;
                        break;
                case NOEDGE:
                        battr |= NOEDGEBIT;
                        break;
                case DOT:
                case DASH:
                        ddtype = ap->a_type==DOT ? DOTBIT : DASHBIT;
                        if (ap->a_sub == DEFAULT)
                                ddval = getfval("dashwid");
                        else
                                ddval = ap->a_val.f;
                        break;
                case SAME:
                        dx[ndxy] = prevdx;
                        dy[ndxy] = prevdy;
                        some++;
                        break;
                case LEFT:
                        dx[ndxy] -= (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
                        some++;
                        hvmode = L_DIR;
                        break;
                case RIGHT:
                        dx[ndxy] += (ap->a_sub==DEFAULT) ? defx : ap->a_val.f;
                        some++;
                        hvmode = R_DIR;
                        break;
                case UP:
                        dy[ndxy] += (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
                        some++;
                        hvmode = U_DIR;
                        break;
                case DOWN:
                        dy[ndxy] -= (ap->a_sub==DEFAULT) ? defy : ap->a_val.f;
                        some++;
                        hvmode = D_DIR;
                        break;
                case HEIGHT:    /* length of arrowhead */
                        prevh = ap->a_val.f;
                        break;
                case WIDTH:     /* width of arrowhead */
                        prevw = ap->a_val.f;
                        break;
                case TO:
                        if (some) {
                                nx += dx[ndxy];
                                ny += dy[ndxy];
                                ndxy++;
                                dx[ndxy] = dy[ndxy] = some = 0;
                        }
                        ppos = attr[i].a_val.o;
                        if (ppos == NULL)
                                ERROR "no tag defined for `to'" FATAL;
                        dx[ndxy] = ppos->o_x - nx;
                        dy[ndxy] = ppos->o_y - ny;
                        some++;
                        break;
                case BY:
                        if (some) {
                                nx += dx[ndxy];
                                ny += dy[ndxy];
                                ndxy++;
                                dx[ndxy] = dy[ndxy] = some = 0;
                        }
                        ppos = ap->a_val.o;
                        if (ppos == NULL)
                                ERROR "no tag defined for `by'" FATAL;
                        dx[ndxy] = ppos->o_x;
                        dy[ndxy] = ppos->o_y;
                        some++;
                        break;
                case THEN:      /* turn off any previous accumulation */
                        if (some) {
                                nx += dx[ndxy];
                                ny += dy[ndxy];
                                ndxy++;
                                dx[ndxy] = dy[ndxy] = some = 0;
                        }
                        break;
                case FROM:
                case AT:
                        ppos = ap->a_val.o;
                        if (ppos == NULL)
                                ERROR "no tag defined for `from' or `at'" FATAL;
                        nx = curx = ppos->o_x;
                        ny = cury = ppos->o_y;
                        break;
                case WITH:
                        with = ap->a_val.i;
                        break;
                case CHOP:
                        if (ap->a_sub != PLACENAME) {
                                if( chop == 0)
                                        chop1 = chop2 = ap->a_val.f;
                                else
                                        chop2 = ap->a_val.f;
                        }
                        chop_ap[chop++] = ap;
                        break;
                case FILL:
                        battr |= FILLBIT;
                        if (ap->a_sub == DEFAULT)
                                fillval = getfval("fillval");
                        else
                                fillval = ap->a_val.f;
                        break;
                }
        }
        if (with) {     /* this doesn't work at all */
                switch (with) {
                case CENTER:
                        xwith = (dx[1] - dx[0]) / 2; ywith = (dy[1] - dy[0]) / 2; break;
                }
                for (i = 0; i < ndxy; i++) {
                        dx[i] -= xwith;
                        dy[i] -= ywith;
                }
                curx += xwith;
                cury += ywith;
        }
        if (some) {
                nx += dx[ndxy];
                ny += dy[ndxy];
                ndxy++;
                defx = dx[ndxy-1];
                defy = dy[ndxy-1];
        } else {
                defx *= xtab[hvmode];
                defy *= ytab[hvmode];
                dx[ndxy] = defx;
                dy[ndxy] = defy;
                ndxy++;
                nx += defx;
                ny += defy;
        }
        prevdx = defx;
        prevdy = defy;
        if (chop) {
                if (chop == 1 && chop1 == 0)    /* just said "chop", so use default */
                        chop1 = chop2 = getfval("circlerad");
                theta = atan2(dy[0], dx[0]);
                x0 = chop1 * cos(theta);
                y0 = chop1 * sin(theta);
                curx += x0;
                cury += y0;
                dx[0] -= x0;
                dy[0] -= y0;

                theta = atan2(dy[ndxy-1], dx[ndxy-1]);
                x1 = chop2 * cos(theta);
                y1 = chop2 * sin(theta);
                nx -= x1;
                ny -= y1;
                dx[ndxy-1] -= x1;
                dy[ndxy-1] -= y1;
                dprintf("chopping %g %g %g %g; cur=%g,%g end=%g,%g\n",
                        x0, y0, x1, y1, curx, cury, nx, ny);
        }
        p = makenode(type, 5 + 2 * ndxy);
        curx = p->o_val[0] = nx;
        cury = p->o_val[1] = ny;
        if (head || type == ARROW) {
                p->o_nhead = getfval("arrowhead");
                p->o_val[2] = prevw;
                p->o_val[3] = prevh;
                if (head == 0)
                        head = HEAD2;   /* default arrow head */
        }
        p->o_attr = head | invis | ddtype | battr;
        p->o_fillval = fillval;
        p->o_val[4] = ndxy;
        nx = p->o_x;
        ny = p->o_y;
        for (i = 0, j = 5; i < ndxy; i++, j += 2) {
                p->o_val[j] = dx[i];
                p->o_val[j+1] = dy[i];
                if (type == LINE || type == ARROW)
                        extreme(nx += dx[i], ny += dy[i]);
                else if (type == SPLINE && i < ndxy-1) {
                        /* to compute approx extreme of spline at p,
                        /* compute midway between p-1 and p+1,
                        /* then go 3/4 from there to p */
                        double ex, ey, xi, yi, xi1, yi1;
                        xi = nx + dx[i]; yi = ny + dy[i];       /* p */
                        xi1 = xi + dx[i+1]; yi1 = yi + dy[i+1]; /* p+1 */
                        ex = (nx+xi1)/2; ey = (ny+yi1)/2;       /* midway */
                        ex += 0.75*(xi-ex); ey += 0.75*(yi-ey);
                        extreme(ex, ey);
                        nx = xi; ny = yi;
                }
                        
        }
        p->o_ddval = ddval;
        if (dbg) {
                printf("S or L from %g %g to %g %g with %d elements:\n", p->o_x, p->o_y, curx, cury, ndxy);
                for (i = 0, j = 5; i < ndxy; i++, j += 2)
                        printf("%g %g\n", p->o_val[j], p->o_val[j+1]);
        }
        extreme(p->o_x, p->o_y);
        extreme(curx, cury);
        return(p);
}