Annotation of researchv10no/cmd/grap/ticks.c, revision 1.1.1.1

1.1       root        1: #include <stdio.h>
                      2: #include <stdlib.h>
                      3: #include <string.h>
                      4: #include <math.h>
                      5: #include "grap.h"
                      6: #include "y.tab.h"
                      7: 
                      8: #define        MAXTICK 200
                      9: int    ntick   = 0;
                     10: double tickval[MAXTICK];       /* tick values (one axis at a time */
                     11: char   *tickstr[MAXTICK];      /* and labels */
                     12: 
                     13: int    tside   = 0;
                     14: int    tlist   = 0;            /* 1 => explicit values given */
                     15: int    toffside = 0;           /* no ticks on these sides */
                     16: int    goffside = 0;           /* no ticks on grid on these sides */
                     17: int    tick_dir = OUT;
                     18: double ticklen = TICKLEN;      /* default tick length */
                     19: int    autoticks = LEFT|BOT;
                     20: int    autodir = 0;            /* set LEFT, etc. if automatic ticks go in */
                     21: 
                     22: void savetick(double f, char *s)       /* remember tick location and label */
                     23: {
                     24:        if (ntick >= MAXTICK)
                     25:                ERROR "too many ticks (%d)", MAXTICK FATAL;
                     26:        tickval[ntick] = f;
                     27:        tickstr[ntick] = s;
                     28:        ntick++;
                     29: }
                     30: 
                     31: void dflt_tick(double f)
                     32: {
                     33:        if (f >= 0.0)
                     34:                savetick(f, tostring("%g"));
                     35:        else
                     36:                savetick(f, tostring("\\%g"));
                     37: }
                     38: 
                     39: void tickside(int n)   /* remember which side these ticks/gridlines go on */
                     40: {
                     41:        tside |= n;
                     42: }
                     43: 
                     44: void tickoff(int side) /* remember explicit sides */
                     45: {
                     46:        toffside |= side;
                     47: }
                     48: 
                     49: void gridtickoff(void) /* turn grid ticks off on the side previously specified (ugh) */
                     50: {
                     51:        goffside = tside;
                     52: }
                     53: 
                     54: void setlist(void)     /* remember that there was an explicit list */
                     55: {
                     56:        tlist = 1;
                     57: }
                     58: 
                     59: void tickdir(int dir, double val, int explicit)        /* remember in/out [expr] */
                     60: {
                     61:        tick_dir = dir;
                     62:        if (explicit)
                     63:                ticklen = val;
                     64: }
                     65: 
                     66: void ticks(void)               /* set autoticks after ticks statement */
                     67: {
                     68:        /* was there an explicit "ticks [side] off"? */
                     69:        if (toffside)
                     70:                autoticks &= ~toffside;
                     71:        /* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */
                     72:        if (tlist) {
                     73:                if (tside & (BOT|TOP))
                     74:                        autoticks &= ~(BOT|TOP);
                     75:                if (tside & (LEFT|RIGHT))
                     76:                        autoticks &= ~(LEFT|RIGHT);
                     77:        }
                     78:        /* was there a side without a list? (eg "ticks left in") */
                     79:        if (tside && !tlist) {
                     80:                if (tick_dir == IN)
                     81:                        autodir |= tside;
                     82:                if (tside & (BOT|TOP))
                     83:                        autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP));
                     84:                if (tside & (LEFT|RIGHT))
                     85:                        autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT));
                     86:        }
                     87:        tlist = tside = toffside = goffside = 0;
                     88:        tick_dir = OUT;
                     89: }
                     90: 
                     91: double modfloor(double f, double t)
                     92: {
                     93:        t = fabs(t);
                     94:        return floor(f/t) * t;
                     95: }
                     96: 
                     97: double modceil(double f, double t)
                     98: {
                     99:        t = fabs(t);
                    100:        return ceil(f/t) * t;
                    101: }
                    102: 
                    103: double xtmin, xtmax;   /* range of ticks */
                    104: double ytmin, ytmax;
                    105: double xquant, xmult;  /* quantization & scale for auto x ticks */
                    106: double yquant, ymult;
                    107: double lograt = 5;
                    108: 
                    109: void do_autoticks(Obj *p)      /* make set of ticks for default coord only */
                    110: {
                    111:        double x, xl, xu, q;
                    112: 
                    113:        if (p == NULL)
                    114:                return;
                    115:        fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g",
                    116:                p->pt.x, p->pt1.x, p->pt.y, p->pt1.y);
                    117:        fprintf(tfd, ";   xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n",
                    118:                xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult);
                    119:        if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) {   /* make x ticks */
                    120:                q = xquant;
                    121:                xl = p->pt.x;
                    122:                xu = p->pt1.x;
                    123:                if (xl >= xu)
                    124:                        dflt_tick(xl);
                    125:                else if ((p->log & XFLAG) && xu/xl >= lograt) {
                    126:                        for (x = q; x < xu; x *= 10) {
                    127:                                logtick(x, xl, xu);
                    128:                                if (xu/xl <= 100) {
                    129:                                        logtick(2*x, xl, xu);
                    130:                                        logtick(5*x, xl, xu);
                    131:                                }
                    132:                        }
                    133:                } else {
                    134:                        xl = modceil(xtmin - q/100, q);
                    135:                        xu = modfloor(xtmax + q/100, q) + q/2;
                    136:                        for (x = xl; x <= xu; x += q)
                    137:                                dflt_tick(x);
                    138:                }
                    139:                tside = autoticks & (BOT|TOP);
                    140:                ticklist(p, 0);
                    141:        }
                    142:        if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) {        /* make y ticks */
                    143:                q = yquant;
                    144:                xl = p->pt.y;
                    145:                xu = p->pt1.y;
                    146:                if (xl >= xu)
                    147:                        dflt_tick(xl);
                    148:                else if ((p->log & YFLAG) && xu/xl >= lograt) {
                    149:                        for (x = q; x < xu; x *= 10) {
                    150:                                logtick(x, xl, xu);
                    151:                                if (xu/xl <= 100) {
                    152:                                        logtick(2*x, xl, xu);
                    153:                                        logtick(5*x, xl, xu);
                    154:                                }
                    155:                        }
                    156:                } else {
                    157:                        xl = modceil(ytmin - q/100, q);
                    158:                        xu = modfloor(ytmax + q/100, q) + q/2;
                    159:                        for (x = xl; x <= xu; x += q)
                    160:                                dflt_tick(x);
                    161:                }
                    162:                tside = autoticks & (LEFT|RIGHT);
                    163:                ticklist(p, 0);
                    164:        }
                    165: }
                    166: 
                    167: void logtick(double v, double lb, double ub)
                    168: {
                    169:        float slop = 1.0;       /* was 1.001 */
                    170: 
                    171:        if (slop * lb <= v && ub >= slop * v)
                    172:                dflt_tick(v);
                    173: }
                    174: 
                    175: Obj *setauto(void)     /* compute new min,max, and quant & mult */
                    176: {
                    177:        Obj *p, *q;
                    178: 
                    179:        if ((q = lookup("lograt",0)) != NULL)
                    180:                lograt = q->fval;
                    181:        for (p = objlist; p; p = p->next)
                    182:                if (p->type == NAME && strcmp(p->name,dflt_coord) == 0)
                    183:                        break;
                    184:        if (p) {
                    185:                if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt)
                    186:                        autolog(p, 'x');
                    187:                else
                    188:                        autoside(p, 'x');
                    189:                if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt)
                    190:                        autolog(p, 'y');
                    191:                else
                    192:                        autoside(p, 'y');
                    193:        }
                    194:        return p;
                    195: }
                    196: 
                    197: void autoside(Obj *p, int side)
                    198: {
                    199:        double r, s, d, ub, lb;
                    200: 
                    201:        if (side == 'x') {
                    202:                xtmin = lb = p->pt.x;
                    203:                xtmax = ub = p->pt1.x;
                    204:        } else {
                    205:                ytmin = lb = p->pt.y;
                    206:                ytmax = ub = p->pt1.y;
                    207:        }
                    208:        if (ub <= lb)
                    209:                return; /* cop out on little ranges */
                    210:        d = ub - lb;
                    211:        r = s = 1;
                    212:        while (d * s < 10)
                    213:                s *= 10;
                    214:        d *= s;
                    215:        while (10 * r < d)
                    216:                r *= 10;
                    217:        if (r > d/3)
                    218:                r /= 2;
                    219:        else if (r <= d/6)
                    220:                r *= 2;
                    221:        if (side == 'x') {
                    222:                xquant = r / s;
                    223:        } else {
                    224:                yquant = r / s;
                    225:        }
                    226: }
                    227: 
                    228: void autolog(Obj *p, int side)
                    229: {
                    230:        double r, s, t, ub, lb;
                    231:        int flg;
                    232: 
                    233:        if (side == 'x') {
                    234:                xtmin = lb = p->pt.x;
                    235:                xtmax = ub = p->pt1.x;
                    236:                flg = p->coord & XFLAG;
                    237:        } else {
                    238:                ytmin = lb = p->pt.y;
                    239:                ytmax = ub = p->pt1.y;
                    240:                flg = p->coord & YFLAG;
                    241:        }
                    242:        for (s = 1; lb * s < 1; s *= 10)
                    243:                ;
                    244:        lb *= s;
                    245:        ub *= s;
                    246:        for (r = 1; 10 * r < lb; r *= 10)
                    247:                ;
                    248:        for (t = 1; t < ub; t *= 10)
                    249:                ;
                    250:        if (side == 'x')
                    251:                xquant = r / s;
                    252:        else
                    253:                yquant = r / s;
                    254:        if (flg)
                    255:                return;
                    256:        if (ub / lb < 100) {
                    257:                if (lb >= 5 * r)
                    258:                        r *= 5;
                    259:                else if (lb >= 2 * r)
                    260:                        r *= 2;
                    261:                if (ub * 5 <= t)
                    262:                        t /= 5;
                    263:                else if (ub * 2 <= t)
                    264:                        t /= 2;
                    265:                if (side == 'x') {
                    266:                        xtmin = r / s;
                    267:                        xtmax = t / s;
                    268:                } else {
                    269:                        ytmin = r / s;
                    270:                        ytmax = t / s;
                    271:                }
                    272:        }
                    273: }
                    274: 
                    275: void iterator(double from, double to, int op, double by, char *fmt)    /* create an iterator */
                    276: {
                    277:        double x;
                    278: 
                    279:        /* should validate limits, etc. */
                    280:        /* punt for now */
                    281: 
                    282:        dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n",
                    283:                from, to, by, op, fmt ? fmt : "");
                    284:        switch (op) {
                    285:        case '+':
                    286:        case ' ':
                    287:                for (x = from; x <= to + (SLOP-1) * by; x += by)
                    288:                        if (fmt)
                    289:                                savetick(x, tostring(fmt));
                    290:                        else
                    291:                                dflt_tick(x);
                    292:                break;
                    293:        case '-':
                    294:                for (x = from; x >= to; x -= by)
                    295:                        if (fmt)
                    296:                                savetick(x, tostring(fmt));
                    297:                        else
                    298:                                dflt_tick(x);
                    299:                break;
                    300:        case '*':
                    301:                for (x = from; x <= SLOP * to; x *= by)
                    302:                        if (fmt)
                    303:                                savetick(x, tostring(fmt));
                    304:                        else
                    305:                                dflt_tick(x);
                    306:                break;
                    307:        case '/':
                    308:                for (x = from; x >= to; x /= by)
                    309:                        if (fmt)
                    310:                                savetick(x, tostring(fmt));
                    311:                        else
                    312:                                dflt_tick(x);
                    313:                break;
                    314:        }
                    315:        if (fmt)
                    316:                free(fmt);
                    317: }
                    318: 
                    319: void ticklist(Obj *p, int explicit)    /* fire out the accumulated ticks */
                    320:                                        /* 1 => list, 0 => auto */
                    321: {
                    322:        if (p == NULL)
                    323:                return;
                    324:        fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen);
                    325:        print_ticks(TICKS, explicit, p, "ticklen", "");
                    326: }
                    327: 
                    328: void print_ticks(int type, int explicit, Obj *p, char *lenstr, char *descstr)
                    329: {
                    330:        int i, logflag, inside;
                    331:        char buf[100];
                    332:        double tv;
                    333: 
                    334:        for (i = 0; i < ntick; i++)     /* any ticks given explicitly? */
                    335:                if (tickstr[i] != NULL)
                    336:                        break;
                    337:        if (i >= ntick && type == TICKS)        /* no, so use values */
                    338:                for (i = 0; i < ntick; i++) {
                    339:                        if (tickval[i] >= 0.0)
                    340:                                sprintf(buf, "%g", tickval[i]);
                    341:                        else
                    342:                                sprintf(buf, "\\-%g", -tickval[i]);
                    343:                        tickstr[i] = tostring(buf);
                    344:                }
                    345:        else
                    346:                for (i = 0; i < ntick; i++) {
                    347:                        if (tickstr[i] != NULL) {
                    348:                                sprintf(buf, tickstr[i], tickval[i]);
                    349:                                free(tickstr[i]);
                    350:                                tickstr[i] = tostring(buf);
                    351:                        }
                    352:                }
                    353:        logflag = sidelog(p->log, tside);
                    354:        for (i = 0; i < ntick; i++) {
                    355:                tv = tickval[i];
                    356:                halfrange(p, tside, tv);
                    357:                if (logflag) {
                    358:                        if (tv <= 0.0)
                    359:                                ERROR "can't take log of tick value %g", tv FATAL;
                    360:                        logit(tv);
                    361:                }
                    362:                if (type == GRID)
                    363:                        inside = LEFT|RIGHT|TOP|BOT;
                    364:                else if (explicit)
                    365:                        inside = (tick_dir == IN) ? tside : 0;
                    366:                else
                    367:                        inside = autodir;
                    368:                if (tside & BOT)
                    369:                        maketick(type, p->name, BOT, inside, tv, tickstr[i], lenstr, descstr);
                    370:                if (tside & TOP)
                    371:                        maketick(type, p->name, TOP, inside, tv, tickstr[i], lenstr, descstr);
                    372:                if (tside & LEFT)
                    373:                        maketick(type, p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr);
                    374:                if (tside & RIGHT)
                    375:                        maketick(type, p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr);
                    376:                if (tickstr[i]) {
                    377:                        free(tickstr[i]);
                    378:                        tickstr[i] = NULL;
                    379:                }
                    380:        }
                    381:        ntick = 0;
                    382: }
                    383: 
                    384: void maketick(int type, char *name, int side, int inflag, double val, char *lab, char *lenstr, char *descstr)
                    385: {
                    386:        char *sidestr, *td;
                    387: 
                    388:        fprintf(tfd, "\tline %s ", descstr);
                    389:        inflag &= side;
                    390:        switch (side) {
                    391:        case BOT:
                    392:        case 0:
                    393:                td = inflag ? "up" : "down";
                    394:                fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val);
                    395:                break;
                    396:        case TOP:
                    397:                td = inflag ? "down" : "up";
                    398:                fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val);
                    399:                break;
                    400:        case LEFT:
                    401:                td = inflag ? "right" : "left";
                    402:                fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val);
                    403:                break;
                    404:        case RIGHT:
                    405:                td = inflag ? "left" : "right";
                    406:                fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val);
                    407:                break;
                    408:        }
                    409:        fprintf(tfd, "\n");
                    410:        if (type == GRID && (side & goffside))  /* wanted no ticks on grid */
                    411:                return;
                    412:        sidestr = tick_dir == IN ? "start" : "end";
                    413:        if (lab != NULL) {
                    414:                /* BUG: should fix size of lab here */
                    415:                double wid = strlen(lab)/7.5 + (tick_dir == IN ? 0 : 0.1);      /* estimate width at 15 chars/inch */
                    416:                switch (side) {
                    417:                case BOT: case 0:
                    418:                        /* can drop "box invis" with new pic */
                    419:                        fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s",
                    420:                                lab, sidestr);
                    421:                        break;
                    422:                case TOP:
                    423:                        fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s",
                    424:                                lab, sidestr);
                    425:                        break;
                    426:                case LEFT:
                    427:                        fprintf(tfd, "\t\"%s \" wid %.2f rjust at last line.%s",
                    428:                                lab, wid, sidestr);
                    429:                        break;
                    430:                case RIGHT:
                    431:                        fprintf(tfd, "\t\" %s\" wid %.2f ljust at last line.%s",
                    432:                                lab, wid, sidestr);
                    433:                        break;
                    434:                }
                    435:                /* BUG: works only if "down x" comes before "at wherever" */
                    436:                lab_adjust();
                    437:                fprintf(tfd, "\n");
                    438:        }
                    439: }
                    440: 
                    441: Attr   *grid_desc      = 0;
                    442: 
                    443: void griddesc(Attr *a)
                    444: {
                    445:        grid_desc = a;
                    446: }
                    447: 
                    448: void gridlist(Obj *p)
                    449: {
                    450:        char *framestr;
                    451: 
                    452:        if ((tside & (BOT|TOP)) || tside == 0)
                    453:                framestr = "frameht";
                    454:        else
                    455:                framestr = "framewid";
                    456:        fprintf(tfd, "Grid_%s:\n", p->name);
                    457:        tick_dir = IN;
                    458:        print_ticks(GRID, 0, p, framestr, desc_str(grid_desc));
                    459:        if (grid_desc) {
                    460:                freeattr(grid_desc);
                    461:                grid_desc = 0;
                    462:        }
                    463: }
                    464: 
                    465: char *desc_str(Attr *a)        /* convert DOT to "dotted", etc. */
                    466: {
                    467:        static char buf[50], *p;
                    468: 
                    469:        if (a == NULL)
                    470:                return p = "";
                    471:        switch (a->type) {
                    472:        case DOT:       p = "dotted"; break;
                    473:        case DASH:      p = "dashed"; break;
                    474:        case INVIS:     p = "invis"; break;
                    475:        default:        p = "";
                    476:        }
                    477:        if (a->fval != 0.0) {
                    478:                sprintf(buf, "%s %g", p, a->fval);
                    479:                return buf;
                    480:        } else
                    481:                return p;
                    482: }
                    483: 
                    484: sidelog(int logflag, int side) /* figure out whether to scale a side */
                    485: {
                    486:        if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0))
                    487:                return 1;
                    488:        else if ((logflag & YFLAG) && (side & (LEFT|RIGHT)))
                    489:                return 1;
                    490:        else
                    491:                return 0;
                    492: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.