1*3e12c5d1SDavid du Colombier #include <u.h> 2*3e12c5d1SDavid du Colombier #include <libc.h> 3*3e12c5d1SDavid du Colombier #include <stdio.h> 4*3e12c5d1SDavid du Colombier #include "iplot.h" 5*3e12c5d1SDavid du Colombier #define INF 1.e+37 6*3e12c5d1SDavid du Colombier #define F .25 7*3e12c5d1SDavid du Colombier 8*3e12c5d1SDavid du Colombier struct xy { 9*3e12c5d1SDavid du Colombier int xlbf; /*flag:explicit lower bound*/ 10*3e12c5d1SDavid du Colombier int xubf; /*flag:explicit upper bound*/ 11*3e12c5d1SDavid du Colombier int xqf; /*flag:explicit quantum*/ 12*3e12c5d1SDavid du Colombier double (*xf)(double); /*transform function, e.g. log*/ 13*3e12c5d1SDavid du Colombier float xa,xb; /*scaling coefficients*/ 14*3e12c5d1SDavid du Colombier float xlb,xub; /*lower and upper bound*/ 15*3e12c5d1SDavid du Colombier float xquant; /*quantum*/ 16*3e12c5d1SDavid du Colombier float xoff; /*screen offset fraction*/ 17*3e12c5d1SDavid du Colombier float xsize; /*screen fraction*/ 18*3e12c5d1SDavid du Colombier int xbot,xtop; /*screen coords of border*/ 19*3e12c5d1SDavid du Colombier float xmult; /*scaling constant*/ 20*3e12c5d1SDavid du Colombier } xd,yd; 21*3e12c5d1SDavid du Colombier struct val { 22*3e12c5d1SDavid du Colombier float xv; 23*3e12c5d1SDavid du Colombier float yv; 24*3e12c5d1SDavid du Colombier int lblptr; 25*3e12c5d1SDavid du Colombier } *xx; 26*3e12c5d1SDavid du Colombier 27*3e12c5d1SDavid du Colombier char *labels; 28*3e12c5d1SDavid du Colombier int labelsiz; 29*3e12c5d1SDavid du Colombier 30*3e12c5d1SDavid du Colombier int tick = 50; 31*3e12c5d1SDavid du Colombier int top = 4000; 32*3e12c5d1SDavid du Colombier int bot = 200; 33*3e12c5d1SDavid du Colombier float absbot; 34*3e12c5d1SDavid du Colombier int n; 35*3e12c5d1SDavid du Colombier int erasf = 1; 36*3e12c5d1SDavid du Colombier int gridf = 2; 37*3e12c5d1SDavid du Colombier int symbf = 0; 38*3e12c5d1SDavid du Colombier int absf = 0; 39*3e12c5d1SDavid du Colombier int transf; 40*3e12c5d1SDavid du Colombier int equf; 41*3e12c5d1SDavid du Colombier int brkf; 42*3e12c5d1SDavid du Colombier int ovlay = 1; 43*3e12c5d1SDavid du Colombier float dx; 44*3e12c5d1SDavid du Colombier char *plotsymb; 45*3e12c5d1SDavid du Colombier 46*3e12c5d1SDavid du Colombier #define BSIZ 80 47*3e12c5d1SDavid du Colombier char labbuf[BSIZ]; 48*3e12c5d1SDavid du Colombier char titlebuf[BSIZ]; 49*3e12c5d1SDavid du Colombier 50*3e12c5d1SDavid du Colombier char *modes[] = { 51*3e12c5d1SDavid du Colombier "disconnected", 52*3e12c5d1SDavid du Colombier "solid", 53*3e12c5d1SDavid du Colombier "dotted", 54*3e12c5d1SDavid du Colombier "dotdashed", 55*3e12c5d1SDavid du Colombier "shortdashed", 56*3e12c5d1SDavid du Colombier "longdashed" 57*3e12c5d1SDavid du Colombier }; 58*3e12c5d1SDavid du Colombier int mode = 1; 59*3e12c5d1SDavid du Colombier double ident(double x){ 60*3e12c5d1SDavid du Colombier return(x); 61*3e12c5d1SDavid du Colombier } 62*3e12c5d1SDavid du Colombier 63*3e12c5d1SDavid du Colombier struct z { 64*3e12c5d1SDavid du Colombier float lb,ub,mult,quant; 65*3e12c5d1SDavid du Colombier }; 66*3e12c5d1SDavid du Colombier init(struct xy *); 67*3e12c5d1SDavid du Colombier setopt(int, char *[]); 68*3e12c5d1SDavid du Colombier readin(void); 69*3e12c5d1SDavid du Colombier transpose(void); 70*3e12c5d1SDavid du Colombier getlim(struct xy *, struct val *); 71*3e12c5d1SDavid du Colombier equilibrate(struct xy *, struct xy *); 72*3e12c5d1SDavid du Colombier scale(struct xy *); 73*3e12c5d1SDavid du Colombier limread(struct xy *, int *, char ***); 74*3e12c5d1SDavid du Colombier numb(float *, int *, char ***); 75*3e12c5d1SDavid du Colombier copystring(int); 76*3e12c5d1SDavid du Colombier struct z setloglim(int, int, float, float); 77*3e12c5d1SDavid du Colombier struct z setlinlim(int, int, float, float); 78*3e12c5d1SDavid du Colombier axes(void); 79*3e12c5d1SDavid du Colombier setmark(int *, struct xy *); 80*3e12c5d1SDavid du Colombier submark(int *, int *, float, struct xy *); 81*3e12c5d1SDavid du Colombier plot(void); 82*3e12c5d1SDavid du Colombier getfloat(float *); 83*3e12c5d1SDavid du Colombier getstring(void); 84*3e12c5d1SDavid du Colombier title(void); 85*3e12c5d1SDavid du Colombier badarg(void); 86*3e12c5d1SDavid du Colombier conv(float, struct xy *, int *); 87*3e12c5d1SDavid du Colombier symbol(int, int, int); 88*3e12c5d1SDavid du Colombier axlab(char, struct xy *, char *); 89*3e12c5d1SDavid du Colombier main(int argc,char *argv[]){ 90*3e12c5d1SDavid du Colombier 91*3e12c5d1SDavid du Colombier openpl(); 92*3e12c5d1SDavid du Colombier range(0,0,4096,4096); 93*3e12c5d1SDavid du Colombier init(&xd); 94*3e12c5d1SDavid du Colombier init(&yd); 95*3e12c5d1SDavid du Colombier xd.xsize = yd.xsize = 1.; 96*3e12c5d1SDavid du Colombier xx = (struct val *)malloc((unsigned)sizeof(struct val)); 97*3e12c5d1SDavid du Colombier labels = malloc(1); 98*3e12c5d1SDavid du Colombier labels[labelsiz++] = 0; 99*3e12c5d1SDavid du Colombier setopt(argc,argv); 100*3e12c5d1SDavid du Colombier if(erasf) 101*3e12c5d1SDavid du Colombier erase(); 102*3e12c5d1SDavid du Colombier readin(); 103*3e12c5d1SDavid du Colombier transpose(); 104*3e12c5d1SDavid du Colombier getlim(&xd,(struct val *)&xx->xv); 105*3e12c5d1SDavid du Colombier getlim(&yd,(struct val *)&xx->yv); 106*3e12c5d1SDavid du Colombier if(equf) { 107*3e12c5d1SDavid du Colombier equilibrate(&xd,&yd); 108*3e12c5d1SDavid du Colombier equilibrate(&yd,&xd); 109*3e12c5d1SDavid du Colombier } 110*3e12c5d1SDavid du Colombier scale(&xd); 111*3e12c5d1SDavid du Colombier scale(&yd); 112*3e12c5d1SDavid du Colombier axes(); 113*3e12c5d1SDavid du Colombier title(); 114*3e12c5d1SDavid du Colombier plot(); 115*3e12c5d1SDavid du Colombier closepl(); 116*3e12c5d1SDavid du Colombier exits(0); 117*3e12c5d1SDavid du Colombier } 118*3e12c5d1SDavid du Colombier 119*3e12c5d1SDavid du Colombier init(struct xy *p){ 120*3e12c5d1SDavid du Colombier p->xf = ident; 121*3e12c5d1SDavid du Colombier p->xmult = 1; 122*3e12c5d1SDavid du Colombier } 123*3e12c5d1SDavid du Colombier 124*3e12c5d1SDavid du Colombier setopt(int argc, char *argv[]){ 125*3e12c5d1SDavid du Colombier char *p1, *p2; 126*3e12c5d1SDavid du Colombier float temp; 127*3e12c5d1SDavid du Colombier 128*3e12c5d1SDavid du Colombier xd.xlb = yd.xlb = INF; 129*3e12c5d1SDavid du Colombier xd.xub = yd.xub = -INF; 130*3e12c5d1SDavid du Colombier while(--argc > 0) { 131*3e12c5d1SDavid du Colombier argv++; 132*3e12c5d1SDavid du Colombier again: switch(argv[0][0]) { 133*3e12c5d1SDavid du Colombier case '-': 134*3e12c5d1SDavid du Colombier argv[0]++; 135*3e12c5d1SDavid du Colombier goto again; 136*3e12c5d1SDavid du Colombier case 'l': /* label for plot */ 137*3e12c5d1SDavid du Colombier p1 = titlebuf; 138*3e12c5d1SDavid du Colombier if (argc>=2) { 139*3e12c5d1SDavid du Colombier argv++; 140*3e12c5d1SDavid du Colombier argc--; 141*3e12c5d1SDavid du Colombier p2 = argv[0]; 142*3e12c5d1SDavid du Colombier while (*p1++ = *p2++); 143*3e12c5d1SDavid du Colombier } 144*3e12c5d1SDavid du Colombier break; 145*3e12c5d1SDavid du Colombier 146*3e12c5d1SDavid du Colombier case 'd': /*disconnected,obsolete option*/ 147*3e12c5d1SDavid du Colombier case 'm': /*line mode*/ 148*3e12c5d1SDavid du Colombier mode = 0; 149*3e12c5d1SDavid du Colombier if(!numb(&temp,&argc,&argv)) 150*3e12c5d1SDavid du Colombier break; 151*3e12c5d1SDavid du Colombier if(temp>=sizeof(modes)/sizeof(*modes)) 152*3e12c5d1SDavid du Colombier mode = 1; 153*3e12c5d1SDavid du Colombier else if(temp>=-1) 154*3e12c5d1SDavid du Colombier mode = temp; 155*3e12c5d1SDavid du Colombier break; 156*3e12c5d1SDavid du Colombier 157*3e12c5d1SDavid du Colombier case 'o': 158*3e12c5d1SDavid du Colombier if(numb(&temp,&argc,&argv) && temp>=1) 159*3e12c5d1SDavid du Colombier ovlay = temp; 160*3e12c5d1SDavid du Colombier break; 161*3e12c5d1SDavid du Colombier case 'a': /*automatic abscissas*/ 162*3e12c5d1SDavid du Colombier absf = 1; 163*3e12c5d1SDavid du Colombier dx = 1; 164*3e12c5d1SDavid du Colombier if(!numb(&dx,&argc,&argv)) 165*3e12c5d1SDavid du Colombier break; 166*3e12c5d1SDavid du Colombier if(numb(&absbot,&argc,&argv)) 167*3e12c5d1SDavid du Colombier absf = 2; 168*3e12c5d1SDavid du Colombier break; 169*3e12c5d1SDavid du Colombier 170*3e12c5d1SDavid du Colombier case 's': /*save screen, overlay plot*/ 171*3e12c5d1SDavid du Colombier erasf = 0; 172*3e12c5d1SDavid du Colombier break; 173*3e12c5d1SDavid du Colombier 174*3e12c5d1SDavid du Colombier case 'g': /*grid style 0 none, 1 ticks, 2 full*/ 175*3e12c5d1SDavid du Colombier gridf = 0; 176*3e12c5d1SDavid du Colombier if(!numb(&temp,&argc,&argv)) 177*3e12c5d1SDavid du Colombier temp = argv[0][1]-'0'; /*for caompatibility*/ 178*3e12c5d1SDavid du Colombier if(temp>=0&&temp<=2) 179*3e12c5d1SDavid du Colombier gridf = temp; 180*3e12c5d1SDavid du Colombier break; 181*3e12c5d1SDavid du Colombier 182*3e12c5d1SDavid du Colombier case 'c': /*character(s) for plotting*/ 183*3e12c5d1SDavid du Colombier if(argc >= 2) { 184*3e12c5d1SDavid du Colombier symbf = 1; 185*3e12c5d1SDavid du Colombier plotsymb = argv[1]; 186*3e12c5d1SDavid du Colombier argv++; 187*3e12c5d1SDavid du Colombier argc--; 188*3e12c5d1SDavid du Colombier } 189*3e12c5d1SDavid du Colombier break; 190*3e12c5d1SDavid du Colombier 191*3e12c5d1SDavid du Colombier case 't': /*transpose*/ 192*3e12c5d1SDavid du Colombier transf = 1; 193*3e12c5d1SDavid du Colombier break; 194*3e12c5d1SDavid du Colombier case 'e': /*equal scales*/ 195*3e12c5d1SDavid du Colombier equf = 1; 196*3e12c5d1SDavid du Colombier break; 197*3e12c5d1SDavid du Colombier case 'b': /*breaks*/ 198*3e12c5d1SDavid du Colombier brkf = 1; 199*3e12c5d1SDavid du Colombier break; 200*3e12c5d1SDavid du Colombier case 'x': /*x limits */ 201*3e12c5d1SDavid du Colombier limread(&xd,&argc,&argv); 202*3e12c5d1SDavid du Colombier break; 203*3e12c5d1SDavid du Colombier case 'y': 204*3e12c5d1SDavid du Colombier limread(&yd,&argc,&argv); 205*3e12c5d1SDavid du Colombier break; 206*3e12c5d1SDavid du Colombier case 'h': /*set height of plot */ 207*3e12c5d1SDavid du Colombier if(!numb(&yd.xsize, &argc,&argv)) 208*3e12c5d1SDavid du Colombier badarg(); 209*3e12c5d1SDavid du Colombier break; 210*3e12c5d1SDavid du Colombier case 'w': /*set width of plot */ 211*3e12c5d1SDavid du Colombier if(!numb(&xd.xsize, &argc, &argv)) 212*3e12c5d1SDavid du Colombier badarg(); 213*3e12c5d1SDavid du Colombier break; 214*3e12c5d1SDavid du Colombier case 'r': /* set offset to right */ 215*3e12c5d1SDavid du Colombier if(!numb(&xd.xoff, &argc, &argv)) 216*3e12c5d1SDavid du Colombier badarg(); 217*3e12c5d1SDavid du Colombier break; 218*3e12c5d1SDavid du Colombier case 'u': /*set offset up the screen*/ 219*3e12c5d1SDavid du Colombier if(!numb(&yd.xoff,&argc,&argv)) 220*3e12c5d1SDavid du Colombier badarg(); 221*3e12c5d1SDavid du Colombier break; 222*3e12c5d1SDavid du Colombier default: 223*3e12c5d1SDavid du Colombier badarg(); 224*3e12c5d1SDavid du Colombier } 225*3e12c5d1SDavid du Colombier } 226*3e12c5d1SDavid du Colombier } 227*3e12c5d1SDavid du Colombier 228*3e12c5d1SDavid du Colombier limread(struct xy *p, int *argcp, char ***argvp){ 229*3e12c5d1SDavid du Colombier if(*argcp>1 && (*argvp)[1][0]=='l') { 230*3e12c5d1SDavid du Colombier (*argcp)--; 231*3e12c5d1SDavid du Colombier (*argvp)++; 232*3e12c5d1SDavid du Colombier p->xf = log10; 233*3e12c5d1SDavid du Colombier } 234*3e12c5d1SDavid du Colombier if(!numb(&p->xlb,argcp,argvp)) 235*3e12c5d1SDavid du Colombier return; 236*3e12c5d1SDavid du Colombier p->xlbf = 1; 237*3e12c5d1SDavid du Colombier if(!numb(&p->xub,argcp,argvp)) 238*3e12c5d1SDavid du Colombier return; 239*3e12c5d1SDavid du Colombier p->xubf = 1; 240*3e12c5d1SDavid du Colombier if(!numb(&p->xquant,argcp,argvp)) 241*3e12c5d1SDavid du Colombier return; 242*3e12c5d1SDavid du Colombier p->xqf = 1; 243*3e12c5d1SDavid du Colombier } 244*3e12c5d1SDavid du Colombier 245*3e12c5d1SDavid du Colombier isdigit(char c){ 246*3e12c5d1SDavid du Colombier return '0'<=c && c<='9'; 247*3e12c5d1SDavid du Colombier } 248*3e12c5d1SDavid du Colombier numb(float *np, int *argcp, char ***argvp){ 249*3e12c5d1SDavid du Colombier register char c; 250*3e12c5d1SDavid du Colombier 251*3e12c5d1SDavid du Colombier if(*argcp <= 1) 252*3e12c5d1SDavid du Colombier return(0); 253*3e12c5d1SDavid du Colombier while((c=(*argvp)[1][0]) == '+') 254*3e12c5d1SDavid du Colombier (*argvp)[1]++; 255*3e12c5d1SDavid du Colombier if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.')) 256*3e12c5d1SDavid du Colombier return(0); 257*3e12c5d1SDavid du Colombier *np = atof((*argvp)[1]); 258*3e12c5d1SDavid du Colombier (*argcp)--; 259*3e12c5d1SDavid du Colombier (*argvp)++; 260*3e12c5d1SDavid du Colombier return(1); 261*3e12c5d1SDavid du Colombier } 262*3e12c5d1SDavid du Colombier 263*3e12c5d1SDavid du Colombier readin(void){ 264*3e12c5d1SDavid du Colombier register t,i; 265*3e12c5d1SDavid du Colombier struct val *temp; 266*3e12c5d1SDavid du Colombier 267*3e12c5d1SDavid du Colombier if(absf==1) { 268*3e12c5d1SDavid du Colombier if(xd.xlbf) 269*3e12c5d1SDavid du Colombier absbot = xd.xlb; 270*3e12c5d1SDavid du Colombier else if(xd.xf==log10) 271*3e12c5d1SDavid du Colombier absbot = 1; 272*3e12c5d1SDavid du Colombier } 273*3e12c5d1SDavid du Colombier for(;;) { 274*3e12c5d1SDavid du Colombier temp = (struct val *)realloc((char*)xx, 275*3e12c5d1SDavid du Colombier (unsigned)(n+ovlay)*sizeof(struct val)); 276*3e12c5d1SDavid du Colombier if(temp==0) 277*3e12c5d1SDavid du Colombier return; 278*3e12c5d1SDavid du Colombier xx = temp; 279*3e12c5d1SDavid du Colombier if(absf) 280*3e12c5d1SDavid du Colombier xx[n].xv = n*dx/ovlay + absbot; 281*3e12c5d1SDavid du Colombier else 282*3e12c5d1SDavid du Colombier if(!getfloat(&xx[n].xv)) 283*3e12c5d1SDavid du Colombier return; 284*3e12c5d1SDavid du Colombier for(i=0;i<ovlay;i++) { 285*3e12c5d1SDavid du Colombier xx[n+i].xv = xx[n].xv; 286*3e12c5d1SDavid du Colombier if(!getfloat(&xx[n+i].yv)) 287*3e12c5d1SDavid du Colombier return; 288*3e12c5d1SDavid du Colombier xx[n+i].lblptr = -1; 289*3e12c5d1SDavid du Colombier t = getstring(); 290*3e12c5d1SDavid du Colombier if(t>0) 291*3e12c5d1SDavid du Colombier xx[n+i].lblptr = copystring(t); 292*3e12c5d1SDavid du Colombier if(t<0 && i+1<ovlay) 293*3e12c5d1SDavid du Colombier return; 294*3e12c5d1SDavid du Colombier } 295*3e12c5d1SDavid du Colombier n += ovlay; 296*3e12c5d1SDavid du Colombier if(t<0) 297*3e12c5d1SDavid du Colombier return; 298*3e12c5d1SDavid du Colombier } 299*3e12c5d1SDavid du Colombier } 300*3e12c5d1SDavid du Colombier 301*3e12c5d1SDavid du Colombier transpose(void){ 302*3e12c5d1SDavid du Colombier register i; 303*3e12c5d1SDavid du Colombier float f; 304*3e12c5d1SDavid du Colombier struct xy t; 305*3e12c5d1SDavid du Colombier if(!transf) 306*3e12c5d1SDavid du Colombier return; 307*3e12c5d1SDavid du Colombier t = xd; xd = yd; yd = t; 308*3e12c5d1SDavid du Colombier for(i= 0;i<n;i++) { 309*3e12c5d1SDavid du Colombier f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f; 310*3e12c5d1SDavid du Colombier } 311*3e12c5d1SDavid du Colombier } 312*3e12c5d1SDavid du Colombier 313*3e12c5d1SDavid du Colombier copystring(int k){ 314*3e12c5d1SDavid du Colombier register char *temp; 315*3e12c5d1SDavid du Colombier register i; 316*3e12c5d1SDavid du Colombier int q; 317*3e12c5d1SDavid du Colombier 318*3e12c5d1SDavid du Colombier temp = realloc(labels,(unsigned)(labelsiz+1+k)); 319*3e12c5d1SDavid du Colombier if(temp==0) 320*3e12c5d1SDavid du Colombier return(0); 321*3e12c5d1SDavid du Colombier labels = temp; 322*3e12c5d1SDavid du Colombier q = labelsiz; 323*3e12c5d1SDavid du Colombier for(i=0;i<=k;i++) 324*3e12c5d1SDavid du Colombier labels[labelsiz++] = labbuf[i]; 325*3e12c5d1SDavid du Colombier return(q); 326*3e12c5d1SDavid du Colombier } 327*3e12c5d1SDavid du Colombier 328*3e12c5d1SDavid du Colombier float modceil(float f, float t){ 329*3e12c5d1SDavid du Colombier 330*3e12c5d1SDavid du Colombier t = fabs(t); 331*3e12c5d1SDavid du Colombier return(ceil(f/t)*t); 332*3e12c5d1SDavid du Colombier } 333*3e12c5d1SDavid du Colombier 334*3e12c5d1SDavid du Colombier float 335*3e12c5d1SDavid du Colombier modfloor(float f, float t){ 336*3e12c5d1SDavid du Colombier t = fabs(t); 337*3e12c5d1SDavid du Colombier return(floor(f/t)*t); 338*3e12c5d1SDavid du Colombier } 339*3e12c5d1SDavid du Colombier 340*3e12c5d1SDavid du Colombier getlim(struct xy *p, struct val *v){ 341*3e12c5d1SDavid du Colombier register i; 342*3e12c5d1SDavid du Colombier 343*3e12c5d1SDavid du Colombier i = 0; 344*3e12c5d1SDavid du Colombier do { 345*3e12c5d1SDavid du Colombier if(!p->xlbf && p->xlb>v[i].xv) 346*3e12c5d1SDavid du Colombier p->xlb = v[i].xv; 347*3e12c5d1SDavid du Colombier if(!p->xubf && p->xub<v[i].xv) 348*3e12c5d1SDavid du Colombier p->xub = v[i].xv; 349*3e12c5d1SDavid du Colombier i++; 350*3e12c5d1SDavid du Colombier } while(i < n); 351*3e12c5d1SDavid du Colombier } 352*3e12c5d1SDavid du Colombier 353*3e12c5d1SDavid du Colombier setlim(struct xy *p){ 354*3e12c5d1SDavid du Colombier float t,delta,sign; 355*3e12c5d1SDavid du Colombier struct z z; 356*3e12c5d1SDavid du Colombier int mark[50]; 357*3e12c5d1SDavid du Colombier float lb,ub; 358*3e12c5d1SDavid du Colombier int lbf,ubf; 359*3e12c5d1SDavid du Colombier 360*3e12c5d1SDavid du Colombier lb = p->xlb; 361*3e12c5d1SDavid du Colombier ub = p->xub; 362*3e12c5d1SDavid du Colombier delta = ub-lb; 363*3e12c5d1SDavid du Colombier if(p->xqf) { 364*3e12c5d1SDavid du Colombier if(delta*p->xquant <=0 ) 365*3e12c5d1SDavid du Colombier badarg(); 366*3e12c5d1SDavid du Colombier return; 367*3e12c5d1SDavid du Colombier } 368*3e12c5d1SDavid du Colombier sign = 1; 369*3e12c5d1SDavid du Colombier lbf = p->xlbf; 370*3e12c5d1SDavid du Colombier ubf = p->xubf; 371*3e12c5d1SDavid du Colombier if(delta < 0) { 372*3e12c5d1SDavid du Colombier sign = -1; 373*3e12c5d1SDavid du Colombier t = lb; 374*3e12c5d1SDavid du Colombier lb = ub; 375*3e12c5d1SDavid du Colombier ub = t; 376*3e12c5d1SDavid du Colombier t = lbf; 377*3e12c5d1SDavid du Colombier lbf = ubf; 378*3e12c5d1SDavid du Colombier ubf = t; 379*3e12c5d1SDavid du Colombier } 380*3e12c5d1SDavid du Colombier else if(delta == 0) { 381*3e12c5d1SDavid du Colombier if(ub > 0) { 382*3e12c5d1SDavid du Colombier ub = 2*ub; 383*3e12c5d1SDavid du Colombier lb = 0; 384*3e12c5d1SDavid du Colombier } 385*3e12c5d1SDavid du Colombier else 386*3e12c5d1SDavid du Colombier if(lb < 0) { 387*3e12c5d1SDavid du Colombier lb = 2*lb; 388*3e12c5d1SDavid du Colombier ub = 0; 389*3e12c5d1SDavid du Colombier } 390*3e12c5d1SDavid du Colombier else { 391*3e12c5d1SDavid du Colombier ub = 1; 392*3e12c5d1SDavid du Colombier lb = -1; 393*3e12c5d1SDavid du Colombier } 394*3e12c5d1SDavid du Colombier } 395*3e12c5d1SDavid du Colombier if(p->xf==log10 && lb>0 && ub>lb) { 396*3e12c5d1SDavid du Colombier z = setloglim(lbf,ubf,lb,ub); 397*3e12c5d1SDavid du Colombier p->xlb = z.lb; 398*3e12c5d1SDavid du Colombier p->xub = z.ub; 399*3e12c5d1SDavid du Colombier p->xmult *= z.mult; 400*3e12c5d1SDavid du Colombier p->xquant = z.quant; 401*3e12c5d1SDavid du Colombier if(setmark(mark,p)<2) { 402*3e12c5d1SDavid du Colombier p->xqf = lbf = ubf = 1; 403*3e12c5d1SDavid du Colombier lb = z.lb; ub = z.ub; 404*3e12c5d1SDavid du Colombier } else 405*3e12c5d1SDavid du Colombier return; 406*3e12c5d1SDavid du Colombier } 407*3e12c5d1SDavid du Colombier z = setlinlim(lbf,ubf,lb,ub); 408*3e12c5d1SDavid du Colombier if(sign > 0) { 409*3e12c5d1SDavid du Colombier p->xlb = z.lb; 410*3e12c5d1SDavid du Colombier p->xub = z.ub; 411*3e12c5d1SDavid du Colombier } else { 412*3e12c5d1SDavid du Colombier p->xlb = z.ub; 413*3e12c5d1SDavid du Colombier p->xub = z.lb; 414*3e12c5d1SDavid du Colombier } 415*3e12c5d1SDavid du Colombier p->xmult *= z.mult; 416*3e12c5d1SDavid du Colombier p->xquant = sign*z.quant; 417*3e12c5d1SDavid du Colombier } 418*3e12c5d1SDavid du Colombier 419*3e12c5d1SDavid du Colombier struct z 420*3e12c5d1SDavid du Colombier setloglim(int lbf, int ubf, float lb, float ub){ 421*3e12c5d1SDavid du Colombier float r,s,t; 422*3e12c5d1SDavid du Colombier struct z z; 423*3e12c5d1SDavid du Colombier 424*3e12c5d1SDavid du Colombier for(s=1; lb*s<1; s*=10) ; 425*3e12c5d1SDavid du Colombier lb *= s; 426*3e12c5d1SDavid du Colombier ub *= s; 427*3e12c5d1SDavid du Colombier for(r=1; 10*r<=lb; r*=10) ; 428*3e12c5d1SDavid du Colombier for(t=1; t<ub; t*=10) ; 429*3e12c5d1SDavid du Colombier z.lb = !lbf ? r : lb; 430*3e12c5d1SDavid du Colombier z.ub = !ubf ? t : ub; 431*3e12c5d1SDavid du Colombier if(ub/lb<100) { 432*3e12c5d1SDavid du Colombier if(!lbf) { 433*3e12c5d1SDavid du Colombier if(lb >= 5*z.lb) 434*3e12c5d1SDavid du Colombier z.lb *= 5; 435*3e12c5d1SDavid du Colombier else if(lb >= 2*z.lb) 436*3e12c5d1SDavid du Colombier z.lb *= 2; 437*3e12c5d1SDavid du Colombier } 438*3e12c5d1SDavid du Colombier if(!ubf) { 439*3e12c5d1SDavid du Colombier if(ub*5 <= z.ub) 440*3e12c5d1SDavid du Colombier z.ub /= 5; 441*3e12c5d1SDavid du Colombier else if(ub*2 <= z.ub) 442*3e12c5d1SDavid du Colombier z.ub /= 2; 443*3e12c5d1SDavid du Colombier } 444*3e12c5d1SDavid du Colombier } 445*3e12c5d1SDavid du Colombier z.mult = s; 446*3e12c5d1SDavid du Colombier z.quant = r; 447*3e12c5d1SDavid du Colombier return(z); 448*3e12c5d1SDavid du Colombier } 449*3e12c5d1SDavid du Colombier 450*3e12c5d1SDavid du Colombier struct z 451*3e12c5d1SDavid du Colombier setlinlim(int lbf, int ubf, float xlb, float xub){ 452*3e12c5d1SDavid du Colombier struct z z; 453*3e12c5d1SDavid du Colombier float r,s,delta; 454*3e12c5d1SDavid du Colombier float ub,lb; 455*3e12c5d1SDavid du Colombier 456*3e12c5d1SDavid du Colombier loop: 457*3e12c5d1SDavid du Colombier ub = xub; 458*3e12c5d1SDavid du Colombier lb = xlb; 459*3e12c5d1SDavid du Colombier delta = ub - lb; 460*3e12c5d1SDavid du Colombier /*scale up by s, a power of 10, so range (delta) exceeds 1*/ 461*3e12c5d1SDavid du Colombier /*find power of 10 quantum, r, such that delta/10<=r<delta*/ 462*3e12c5d1SDavid du Colombier r = s = 1; 463*3e12c5d1SDavid du Colombier while(delta*s < 10) 464*3e12c5d1SDavid du Colombier s *= 10; 465*3e12c5d1SDavid du Colombier delta *= s; 466*3e12c5d1SDavid du Colombier while(10*r < delta) 467*3e12c5d1SDavid du Colombier r *= 10; 468*3e12c5d1SDavid du Colombier lb *= s; 469*3e12c5d1SDavid du Colombier ub *= s; 470*3e12c5d1SDavid du Colombier /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/ 471*3e12c5d1SDavid du Colombier if(r>=delta/2) 472*3e12c5d1SDavid du Colombier r /= 2; 473*3e12c5d1SDavid du Colombier else if(r<delta/5) 474*3e12c5d1SDavid du Colombier r *= 2; 475*3e12c5d1SDavid du Colombier z.ub = ubf? ub: modceil(ub,r); 476*3e12c5d1SDavid du Colombier z.lb = lbf? lb: modfloor(lb,r); 477*3e12c5d1SDavid du Colombier if(!lbf && z.lb<=r && z.lb>0) { 478*3e12c5d1SDavid du Colombier xlb = 0; 479*3e12c5d1SDavid du Colombier goto loop; 480*3e12c5d1SDavid du Colombier } 481*3e12c5d1SDavid du Colombier else if(!ubf && z.ub>=-r && z.ub<0) { 482*3e12c5d1SDavid du Colombier xub = 0; 483*3e12c5d1SDavid du Colombier goto loop; 484*3e12c5d1SDavid du Colombier } 485*3e12c5d1SDavid du Colombier z.quant = r; 486*3e12c5d1SDavid du Colombier z.mult = s; 487*3e12c5d1SDavid du Colombier return(z); 488*3e12c5d1SDavid du Colombier } 489*3e12c5d1SDavid du Colombier 490*3e12c5d1SDavid du Colombier scale(struct xy *p){ 491*3e12c5d1SDavid du Colombier float edge; 492*3e12c5d1SDavid du Colombier 493*3e12c5d1SDavid du Colombier setlim(p); 494*3e12c5d1SDavid du Colombier edge = top-bot; 495*3e12c5d1SDavid du Colombier p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb)); 496*3e12c5d1SDavid du Colombier p->xbot = bot + edge*p->xoff; 497*3e12c5d1SDavid du Colombier p->xtop = p->xbot + (top-bot)*p->xsize; 498*3e12c5d1SDavid du Colombier p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5; 499*3e12c5d1SDavid du Colombier } 500*3e12c5d1SDavid du Colombier 501*3e12c5d1SDavid du Colombier equilibrate(struct xy *p, struct xy *q){ 502*3e12c5d1SDavid du Colombier if(p->xlbf|| /* needn't test xubf; it implies xlbf*/ 503*3e12c5d1SDavid du Colombier q->xubf&&q->xlb>q->xub) 504*3e12c5d1SDavid du Colombier return; 505*3e12c5d1SDavid du Colombier if(p->xlb>q->xlb) { 506*3e12c5d1SDavid du Colombier p->xlb = q->xlb; 507*3e12c5d1SDavid du Colombier p->xlbf = q->xlbf; 508*3e12c5d1SDavid du Colombier } 509*3e12c5d1SDavid du Colombier if(p->xub<q->xub) { 510*3e12c5d1SDavid du Colombier p->xub = q->xub; 511*3e12c5d1SDavid du Colombier p->xubf = q->xubf; 512*3e12c5d1SDavid du Colombier } 513*3e12c5d1SDavid du Colombier } 514*3e12c5d1SDavid du Colombier 515*3e12c5d1SDavid du Colombier axes(void){ 516*3e12c5d1SDavid du Colombier register i; 517*3e12c5d1SDavid du Colombier int mark[50]; 518*3e12c5d1SDavid du Colombier int xn, yn; 519*3e12c5d1SDavid du Colombier if(gridf==0) 520*3e12c5d1SDavid du Colombier return; 521*3e12c5d1SDavid du Colombier 522*3e12c5d1SDavid du Colombier line(xd.xbot,yd.xbot,xd.xtop,yd.xbot); 523*3e12c5d1SDavid du Colombier vec(xd.xtop,yd.xtop); 524*3e12c5d1SDavid du Colombier vec(xd.xbot,yd.xtop); 525*3e12c5d1SDavid du Colombier vec(xd.xbot,yd.xbot); 526*3e12c5d1SDavid du Colombier 527*3e12c5d1SDavid du Colombier xn = setmark(mark,&xd); 528*3e12c5d1SDavid du Colombier for(i=0; i<xn; i++) { 529*3e12c5d1SDavid du Colombier if(gridf==2) 530*3e12c5d1SDavid du Colombier line(mark[i],yd.xbot,mark[i],yd.xtop); 531*3e12c5d1SDavid du Colombier if(gridf==1) { 532*3e12c5d1SDavid du Colombier line(mark[i],yd.xbot,mark[i],yd.xbot+tick); 533*3e12c5d1SDavid du Colombier line(mark[i],yd.xtop-tick,mark[i],yd.xtop); 534*3e12c5d1SDavid du Colombier } 535*3e12c5d1SDavid du Colombier } 536*3e12c5d1SDavid du Colombier yn = setmark(mark,&yd); 537*3e12c5d1SDavid du Colombier for(i=0; i<yn; i++) { 538*3e12c5d1SDavid du Colombier if(gridf==2) 539*3e12c5d1SDavid du Colombier line(xd.xbot,mark[i],xd.xtop,mark[i]); 540*3e12c5d1SDavid du Colombier if(gridf==1) { 541*3e12c5d1SDavid du Colombier line(xd.xbot,mark[i],xd.xbot+tick,mark[i]); 542*3e12c5d1SDavid du Colombier line(xd.xtop-tick,mark[i],xd.xtop,mark[i]); 543*3e12c5d1SDavid du Colombier } 544*3e12c5d1SDavid du Colombier } 545*3e12c5d1SDavid du Colombier } 546*3e12c5d1SDavid du Colombier 547*3e12c5d1SDavid du Colombier setmark(int *xmark, struct xy *p){ 548*3e12c5d1SDavid du Colombier int xn = 0; 549*3e12c5d1SDavid du Colombier float x,xl,xu; 550*3e12c5d1SDavid du Colombier float q; 551*3e12c5d1SDavid du Colombier if(p->xf==log10&&!p->xqf) { 552*3e12c5d1SDavid du Colombier for(x=p->xquant; x<p->xub; x*=10) { 553*3e12c5d1SDavid du Colombier submark(xmark,&xn,x,p); 554*3e12c5d1SDavid du Colombier if(p->xub/p->xlb<=100) { 555*3e12c5d1SDavid du Colombier submark(xmark,&xn,2*x,p); 556*3e12c5d1SDavid du Colombier submark(xmark,&xn,5*x,p); 557*3e12c5d1SDavid du Colombier } 558*3e12c5d1SDavid du Colombier } 559*3e12c5d1SDavid du Colombier } else { 560*3e12c5d1SDavid du Colombier xn = 0; 561*3e12c5d1SDavid du Colombier q = p->xquant; 562*3e12c5d1SDavid du Colombier if(q>0) { 563*3e12c5d1SDavid du Colombier xl = modceil(p->xlb+q/6,q); 564*3e12c5d1SDavid du Colombier xu = modfloor(p->xub-q/6,q)+q/2; 565*3e12c5d1SDavid du Colombier } else { 566*3e12c5d1SDavid du Colombier xl = modceil(p->xub-q/6,q); 567*3e12c5d1SDavid du Colombier xu = modfloor(p->xlb+q/6,q)-q/2; 568*3e12c5d1SDavid du Colombier } 569*3e12c5d1SDavid du Colombier for(x=xl; x<=xu; x+=fabs(p->xquant)) 570*3e12c5d1SDavid du Colombier xmark[xn++] = (*p->xf)(x)*p->xa + p->xb; 571*3e12c5d1SDavid du Colombier } 572*3e12c5d1SDavid du Colombier return(xn); 573*3e12c5d1SDavid du Colombier } 574*3e12c5d1SDavid du Colombier submark(int *xmark, int *pxn, float x, struct xy *p){ 575*3e12c5d1SDavid du Colombier if(1.001*p->xlb < x && .999*p->xub > x) 576*3e12c5d1SDavid du Colombier xmark[(*pxn)++] = log10(x)*p->xa + p->xb; 577*3e12c5d1SDavid du Colombier } 578*3e12c5d1SDavid du Colombier 579*3e12c5d1SDavid du Colombier plot(void){ 580*3e12c5d1SDavid du Colombier int ix,iy; 581*3e12c5d1SDavid du Colombier int i,j; 582*3e12c5d1SDavid du Colombier int conn; 583*3e12c5d1SDavid du Colombier 584*3e12c5d1SDavid du Colombier for(j=0;j<ovlay;j++) { 585*3e12c5d1SDavid du Colombier switch(mode) { 586*3e12c5d1SDavid du Colombier case -1: 587*3e12c5d1SDavid du Colombier pen(modes[j%(sizeof modes/sizeof *modes-1)+1]); 588*3e12c5d1SDavid du Colombier break; 589*3e12c5d1SDavid du Colombier case 0: 590*3e12c5d1SDavid du Colombier break; 591*3e12c5d1SDavid du Colombier default: 592*3e12c5d1SDavid du Colombier pen(modes[mode]); 593*3e12c5d1SDavid du Colombier } 594*3e12c5d1SDavid du Colombier conn = 0; 595*3e12c5d1SDavid du Colombier for(i=j; i<n; i+=ovlay) { 596*3e12c5d1SDavid du Colombier if(!conv(xx[i].xv,&xd,&ix) || 597*3e12c5d1SDavid du Colombier !conv(xx[i].yv,&yd,&iy)) { 598*3e12c5d1SDavid du Colombier conn = 0; 599*3e12c5d1SDavid du Colombier continue; 600*3e12c5d1SDavid du Colombier } 601*3e12c5d1SDavid du Colombier if(mode!=0) { 602*3e12c5d1SDavid du Colombier if(conn != 0) 603*3e12c5d1SDavid du Colombier vec(ix,iy); 604*3e12c5d1SDavid du Colombier else 605*3e12c5d1SDavid du Colombier move(ix,iy); 606*3e12c5d1SDavid du Colombier conn = 1; 607*3e12c5d1SDavid du Colombier } 608*3e12c5d1SDavid du Colombier conn &= symbol(ix,iy,xx[i].lblptr); 609*3e12c5d1SDavid du Colombier } 610*3e12c5d1SDavid du Colombier } 611*3e12c5d1SDavid du Colombier pen(modes[1]); 612*3e12c5d1SDavid du Colombier } 613*3e12c5d1SDavid du Colombier 614*3e12c5d1SDavid du Colombier conv(float xv, struct xy *p, int *ip){ 615*3e12c5d1SDavid du Colombier long ix; 616*3e12c5d1SDavid du Colombier ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb; 617*3e12c5d1SDavid du Colombier if(ix<p->xbot || ix>p->xtop) 618*3e12c5d1SDavid du Colombier return(0); 619*3e12c5d1SDavid du Colombier *ip = ix; 620*3e12c5d1SDavid du Colombier return(1); 621*3e12c5d1SDavid du Colombier } 622*3e12c5d1SDavid du Colombier 623*3e12c5d1SDavid du Colombier getfloat(float *p){ 624*3e12c5d1SDavid du Colombier register i; 625*3e12c5d1SDavid du Colombier 626*3e12c5d1SDavid du Colombier i = scanf("%f",p); 627*3e12c5d1SDavid du Colombier return(i==1); 628*3e12c5d1SDavid du Colombier } 629*3e12c5d1SDavid du Colombier getstring(void){ 630*3e12c5d1SDavid du Colombier register i; 631*3e12c5d1SDavid du Colombier char junk[20]; 632*3e12c5d1SDavid du Colombier i = scanf("%1s",labbuf); 633*3e12c5d1SDavid du Colombier if(i==-1) 634*3e12c5d1SDavid du Colombier return(-1); 635*3e12c5d1SDavid du Colombier switch(*labbuf) { 636*3e12c5d1SDavid du Colombier default: 637*3e12c5d1SDavid du Colombier if(!isdigit(*labbuf)) { 638*3e12c5d1SDavid du Colombier ungetc(*labbuf,stdin); 639*3e12c5d1SDavid du Colombier i = scanf("%s",labbuf); 640*3e12c5d1SDavid du Colombier break; 641*3e12c5d1SDavid du Colombier } 642*3e12c5d1SDavid du Colombier case '.': 643*3e12c5d1SDavid du Colombier case '+': 644*3e12c5d1SDavid du Colombier case '-': 645*3e12c5d1SDavid du Colombier ungetc(*labbuf,stdin); 646*3e12c5d1SDavid du Colombier return(0); 647*3e12c5d1SDavid du Colombier case '"': 648*3e12c5d1SDavid du Colombier i = scanf("%[^\"\n]",labbuf); 649*3e12c5d1SDavid du Colombier scanf("%[\"]",junk); 650*3e12c5d1SDavid du Colombier break; 651*3e12c5d1SDavid du Colombier } 652*3e12c5d1SDavid du Colombier if(i==-1) 653*3e12c5d1SDavid du Colombier return(-1); 654*3e12c5d1SDavid du Colombier return(strlen(labbuf)); 655*3e12c5d1SDavid du Colombier } 656*3e12c5d1SDavid du Colombier 657*3e12c5d1SDavid du Colombier 658*3e12c5d1SDavid du Colombier symbol(int ix, int iy, int k){ 659*3e12c5d1SDavid du Colombier 660*3e12c5d1SDavid du Colombier if(symbf==0&&k<0) { 661*3e12c5d1SDavid du Colombier if(mode==0) 662*3e12c5d1SDavid du Colombier point(ix,iy); 663*3e12c5d1SDavid du Colombier return(1); 664*3e12c5d1SDavid du Colombier } 665*3e12c5d1SDavid du Colombier else { 666*3e12c5d1SDavid du Colombier move(ix,iy); 667*3e12c5d1SDavid du Colombier text(k>=0?labels+k:plotsymb); 668*3e12c5d1SDavid du Colombier move(ix,iy); 669*3e12c5d1SDavid du Colombier return(!brkf|k<0); 670*3e12c5d1SDavid du Colombier } 671*3e12c5d1SDavid du Colombier } 672*3e12c5d1SDavid du Colombier 673*3e12c5d1SDavid du Colombier title(void){ 674*3e12c5d1SDavid du Colombier char buf[BSIZ+100]; 675*3e12c5d1SDavid du Colombier buf[0] = ' '; 676*3e12c5d1SDavid du Colombier buf[1] = ' '; 677*3e12c5d1SDavid du Colombier buf[2] = ' '; 678*3e12c5d1SDavid du Colombier strcpy(buf+3,titlebuf); 679*3e12c5d1SDavid du Colombier if(erasf&&gridf) { 680*3e12c5d1SDavid du Colombier axlab('x',&xd,buf); 681*3e12c5d1SDavid du Colombier strcat(buf,","); 682*3e12c5d1SDavid du Colombier axlab('y',&yd,buf); 683*3e12c5d1SDavid du Colombier } 684*3e12c5d1SDavid du Colombier move(xd.xbot,yd.xbot-60); 685*3e12c5d1SDavid du Colombier text(buf); 686*3e12c5d1SDavid du Colombier } 687*3e12c5d1SDavid du Colombier 688*3e12c5d1SDavid du Colombier axlab(char c, struct xy *p, char *b){ 689*3e12c5d1SDavid du Colombier char *dir; 690*3e12c5d1SDavid du Colombier dir = p->xlb<p->xub? "<=": ">="; 691*3e12c5d1SDavid du Colombier sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult, 692*3e12c5d1SDavid du Colombier dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult); 693*3e12c5d1SDavid du Colombier } 694*3e12c5d1SDavid du Colombier 695*3e12c5d1SDavid du Colombier badarg(void){ 696*3e12c5d1SDavid du Colombier fprintf(stderr,"graph: error in arguments\n"); 697*3e12c5d1SDavid du Colombier closepl(); 698*3e12c5d1SDavid du Colombier exits("bad arg"); 699*3e12c5d1SDavid du Colombier } 700