📄 ticks.c
字号:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include "grap.h"#include "y.tab.h"#define MAXTICK 200int ntick = 0;double tickval[MAXTICK]; /* tick values (one axis at a time */char *tickstr[MAXTICK]; /* and labels */int tside = 0;int tlist = 0; /* 1 => explicit values given */int toffside = 0; /* no ticks on these sides */int goffside = 0; /* no ticks on grid on these sides */int tick_dir = OUT;double ticklen = TICKLEN; /* default tick length */int autoticks = LEFT|BOT;int autodir = 0; /* set LEFT, etc. if automatic ticks go in */void savetick(double f, char *s) /* remember tick location and label */{ if (ntick >= MAXTICK) ERROR "too many ticks (%d)", MAXTICK FATAL; tickval[ntick] = f; tickstr[ntick] = s; ntick++;}void dflt_tick(double f){ if (f >= 0.0) savetick(f, tostring("%g")); else savetick(f, tostring("\\%g"));}void tickside(int n) /* remember which side these ticks/gridlines go on */{ tside |= n;}void tickoff(int side) /* remember explicit sides */{ toffside |= side;}void gridtickoff(void) /* turn grid ticks off on the side previously specified (ugh) */{ goffside = tside;}void setlist(void) /* remember that there was an explicit list */{ tlist = 1;}void tickdir(int dir, double val, int explicit) /* remember in/out [expr] */{ tick_dir = dir; if (explicit) ticklen = val;}void ticks(void) /* set autoticks after ticks statement */{ /* was there an explicit "ticks [side] off"? */ if (toffside) autoticks &= ~toffside; /* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */ if (tlist) { if (tside & (BOT|TOP)) autoticks &= ~(BOT|TOP); if (tside & (LEFT|RIGHT)) autoticks &= ~(LEFT|RIGHT); } /* was there a side without a list? (eg "ticks left in") */ if (tside && !tlist) { if (tick_dir == IN) autodir |= tside; if (tside & (BOT|TOP)) autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP)); if (tside & (LEFT|RIGHT)) autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT)); } tlist = tside = toffside = goffside = 0; tick_dir = OUT;}double modfloor(double f, double t){ t = fabs(t); return floor(f/t) * t;}double modceil(double f, double t){ t = fabs(t); return ceil(f/t) * t;}double xtmin, xtmax; /* range of ticks */double ytmin, ytmax;double xquant, xmult; /* quantization & scale for auto x ticks */double yquant, ymult;double lograt = 5;void do_autoticks(Obj *p) /* make set of ticks for default coord only */{ double x, xl, xu, q; if (p == NULL) return; fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g", p->pt.x, p->pt1.x, p->pt.y, p->pt1.y); fprintf(tfd, "; xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n", xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult); if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) { /* make x ticks */ q = xquant; xl = p->pt.x; xu = p->pt1.x; if (xl >= xu) dflt_tick(xl); else if ((p->log & XFLAG) && xu/xl >= lograt) { for (x = q; x < xu; x *= 10) { logtick(x, xl, xu); if (xu/xl <= 100) { logtick(2*x, xl, xu); logtick(5*x, xl, xu); } } } else { xl = modceil(xtmin - q/100, q); xu = modfloor(xtmax + q/100, q) + q/2; for (x = xl; x <= xu; x += q) dflt_tick(x); } tside = autoticks & (BOT|TOP); ticklist(p, 0); } if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) { /* make y ticks */ q = yquant; xl = p->pt.y; xu = p->pt1.y; if (xl >= xu) dflt_tick(xl); else if ((p->log & YFLAG) && xu/xl >= lograt) { for (x = q; x < xu; x *= 10) { logtick(x, xl, xu); if (xu/xl <= 100) { logtick(2*x, xl, xu); logtick(5*x, xl, xu); } } } else { xl = modceil(ytmin - q/100, q); xu = modfloor(ytmax + q/100, q) + q/2; for (x = xl; x <= xu; x += q) dflt_tick(x); } tside = autoticks & (LEFT|RIGHT); ticklist(p, 0); }}void logtick(double v, double lb, double ub){ float slop = 1.0; /* was 1.001 */ if (slop * lb <= v && ub >= slop * v) dflt_tick(v);}Obj *setauto(void) /* compute new min,max, and quant & mult */{ Obj *p, *q; if ((q = lookup("lograt",0)) != NULL) lograt = q->fval; for (p = objlist; p; p = p->next) if (p->type == NAME && strcmp(p->name,dflt_coord) == 0) break; if (p) { if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt) autolog(p, 'x'); else autoside(p, 'x'); if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt) autolog(p, 'y'); else autoside(p, 'y'); } return p;}void autoside(Obj *p, int side){ double r, s, d, ub, lb; if (side == 'x') { xtmin = lb = p->pt.x; xtmax = ub = p->pt1.x; } else { ytmin = lb = p->pt.y; ytmax = ub = p->pt1.y; } if (ub <= lb) return; /* cop out on little ranges */ d = ub - lb; r = s = 1; while (d * s < 10) s *= 10; d *= s; while (10 * r < d) r *= 10; if (r > d/3) r /= 2; else if (r <= d/6) r *= 2; if (side == 'x') { xquant = r / s; } else { yquant = r / s; }}void autolog(Obj *p, int side){ double r, s, t, ub, lb; int flg; if (side == 'x') { xtmin = lb = p->pt.x; xtmax = ub = p->pt1.x; flg = p->coord & XFLAG; } else { ytmin = lb = p->pt.y; ytmax = ub = p->pt1.y; flg = p->coord & YFLAG; } for (s = 1; lb * s < 1; s *= 10) ; lb *= s; ub *= s; for (r = 1; 10 * r < lb; r *= 10) ; for (t = 1; t < ub; t *= 10) ; if (side == 'x') xquant = r / s; else yquant = r / s; if (flg) return; if (ub / lb < 100) { if (lb >= 5 * r) r *= 5; else if (lb >= 2 * r) r *= 2; if (ub * 5 <= t) t /= 5; else if (ub * 2 <= t) t /= 2; if (side == 'x') { xtmin = r / s; xtmax = t / s; } else { ytmin = r / s; ytmax = t / s; } }}void iterator(double from, double to, int op, double by, char *fmt) /* create an iterator */{ double x; /* should validate limits, etc. */ /* punt for now */ dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n", from, to, by, op, fmt ? fmt : ""); switch (op) { case '+': case ' ': for (x = from; x <= to + (SLOP-1) * by; x += by) if (fmt) savetick(x, tostring(fmt)); else dflt_tick(x); break; case '-': for (x = from; x >= to; x -= by) if (fmt) savetick(x, tostring(fmt)); else dflt_tick(x); break; case '*': for (x = from; x <= SLOP * to; x *= by) if (fmt) savetick(x, tostring(fmt)); else dflt_tick(x); break; case '/': for (x = from; x >= to; x /= by) if (fmt) savetick(x, tostring(fmt)); else dflt_tick(x); break; } if (fmt) free(fmt);}void ticklist(Obj *p, int explicit) /* fire out the accumulated ticks */ /* 1 => list, 0 => auto */{ if (p == NULL) return; fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen); print_ticks(TICKS, explicit, p, "ticklen", "");}void print_ticks(int type, int explicit, Obj *p, char *lenstr, char *descstr){ int i, logflag, inside; char buf[100]; double tv; for (i = 0; i < ntick; i++) /* any ticks given explicitly? */ if (tickstr[i] != NULL) break; if (i >= ntick && type == TICKS) /* no, so use values */ for (i = 0; i < ntick; i++) { if (tickval[i] >= 0.0) sprintf(buf, "%g", tickval[i]); else sprintf(buf, "\\-%g", -tickval[i]); tickstr[i] = tostring(buf); } else for (i = 0; i < ntick; i++) { if (tickstr[i] != NULL) { sprintf(buf, tickstr[i], tickval[i]); free(tickstr[i]); tickstr[i] = tostring(buf); } } logflag = sidelog(p->log, tside); for (i = 0; i < ntick; i++) { tv = tickval[i]; halfrange(p, tside, tv); if (logflag) { if (tv <= 0.0) ERROR "can't take log of tick value %g", tv FATAL; logit(tv); } if (type == GRID) inside = LEFT|RIGHT|TOP|BOT; else if (explicit) inside = (tick_dir == IN) ? tside : 0; else inside = autodir; if (tside & BOT) maketick(type, p->name, BOT, inside, tv, tickstr[i], lenstr, descstr); if (tside & TOP) maketick(type, p->name, TOP, inside, tv, tickstr[i], lenstr, descstr); if (tside & LEFT) maketick(type, p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr); if (tside & RIGHT) maketick(type, p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr); if (tickstr[i]) { free(tickstr[i]); tickstr[i] = NULL; } } ntick = 0;}void maketick(int type, char *name, int side, int inflag, double val, char *lab, char *lenstr, char *descstr){ char *sidestr, *td; fprintf(tfd, "\tline %s ", descstr); inflag &= side; switch (side) { case BOT: case 0: td = inflag ? "up" : "down"; fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val); break; case TOP: td = inflag ? "down" : "up"; fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val); break; case LEFT: td = inflag ? "right" : "left"; fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val); break; case RIGHT: td = inflag ? "left" : "right"; fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val); break; } fprintf(tfd, "\n"); if (type == GRID && (side & goffside)) /* wanted no ticks on grid */ return; sidestr = tick_dir == IN ? "start" : "end"; if (lab != NULL) { /* BUG: should fix size of lab here */ double wid = strlen(lab)/7.5 + (tick_dir == IN ? 0 : 0.1); /* estimate width at 15 chars/inch */ switch (side) { case BOT: case 0: /* can drop "box invis" with new pic */ fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s", lab, sidestr); break; case TOP: fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s", lab, sidestr); break; case LEFT: fprintf(tfd, "\t\"%s \" wid %.2f rjust at last line.%s", lab, wid, sidestr); break; case RIGHT: fprintf(tfd, "\t\" %s\" wid %.2f ljust at last line.%s", lab, wid, sidestr); break; } /* BUG: works only if "down x" comes before "at wherever" */ lab_adjust(); fprintf(tfd, "\n"); }}Attr *grid_desc = 0;void griddesc(Attr *a){ grid_desc = a;}void gridlist(Obj *p){ char *framestr; if ((tside & (BOT|TOP)) || tside == 0) framestr = "frameht"; else framestr = "framewid"; fprintf(tfd, "Grid_%s:\n", p->name); tick_dir = IN; print_ticks(GRID, 0, p, framestr, desc_str(grid_desc)); if (grid_desc) { freeattr(grid_desc); grid_desc = 0; }}char *desc_str(Attr *a) /* convert DOT to "dotted", etc. */{ static char buf[50], *p; if (a == NULL) return p = ""; switch (a->type) { case DOT: p = "dotted"; break; case DASH: p = "dashed"; break; case INVIS: p = "invis"; break; default: p = ""; } if (a->fval != 0.0) { sprintf(buf, "%s %g", p, a->fval); return buf; } else return p;}sidelog(int logflag, int side) /* figure out whether to scale a side */{ if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0)) return 1; else if ((logflag & YFLAG) && (side & (LEFT|RIGHT))) return 1; else return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -