#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <bio.h>
#define MAXVARS 7
// test cmd awk 'BEGIN{for(x=0;x<100;x++) { print x " " 100*rand() " " 100*(rand()*rand()) }}' | 8.out -t 'awk rand() distribution' -s 0 -e 100 -m 120 -v x,'rand()','rand()^2' | topng > sample.png
/* colors */
enum {
Peach,
Aqua,
Green,
Blue,
Grey,
Pink,
Yellow,
White,
Black,
};
struct Color {
Memimage *bg;
Memimage *fg;
Memimage *hl;
};
typedef struct Color Color;
/* figures */
typedef struct fpoint {
double x, y;
} fpoint;
typedef struct frectangle {
fpoint min, max;
} frectangle;
typedef struct polygon {
Point *p; /* a malloc'ed array */
int n; /* p[] has n elements: p[0..n] */
} polygon;
/* input values */
struct Var {
char *s;
int c;
double max;
double min;
double mean;
double sum;
polygon fig;
};
typedef struct Var Var;
Var *V;
int Nvars;
Color Pallete[8];
/* utils */
void*
emalloc(ulong sz)
{
void *v;
if((v = malloc(sz)) == nil) {
fprint(2, "out of memory allocating %lud\n", sz);
exits("mem");
}
memset(v, 0, sz);
setmalloctag(v, getcallerpc(&sz));
return v;
}
void*
erealloc(void *v, ulong sz)
{
void *nv;
if((nv = realloc(v, sz)) == nil) {
fprint(2, "out of memory allocating %lud\n", sz);
exits("mem");
}
if(v == nil)
setmalloctag(nv, getcallerpc(&v));
setrealloctag(nv, getcallerpc(&v));
return nv;
}
void
mkcol(int i, int c0, int c1, int c2, Rectangle clipr)
{
Pallete[i].bg = allocmemimage(Rect(0,0,1,1),RGB24);
memfillcolor(Pallete[i].bg,c0); Pallete[i].bg->flags=Frepl;
Pallete[i].bg->clipr = clipr;
Pallete[i].fg = allocmemimage(Rect(0,0,1,1),RGB24);
memfillcolor(Pallete[i].fg,c1);Pallete[i].fg->flags=Frepl;
Pallete[i].fg->clipr = clipr;
Pallete[i].hl = allocmemimage(Rect(0,0,1,1),RGB24);
memfillcolor(Pallete[i].hl,c2);Pallete[i].hl->flags=Frepl;
Pallete[i].hl->clipr = clipr;
}
void
colinit(Rectangle clipr)
{
mkcol(Peach, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF,clipr);
mkcol(Aqua, DPalebluegreen, DPalegreygreen, DPurpleblue,clipr);
mkcol(Yellow, DPaleyellow, DDarkyellow, DYellowgreen,clipr);
mkcol(Green, DPalegreen, DMedgreen, DDarkgreen,clipr);
mkcol(Blue, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF,clipr);
mkcol(Grey,0xEEEEEEFF,0xCCCCCCFF,0x888888FF,clipr);
mkcol(Pink,0xffaaaaFF, 0x990099FF, 0xffaa00FF,clipr);
mkcol(White,0xffffffff,0xffffffff,0xffffffff,clipr);
mkcol(Black,0,0,0,clipr);
}
Rectangle
frtor(frectangle fr)
{
Rectangle r;
r.max.x = (int) fr.max.x;
r.max.y = (int) fr.max.y;
r.min.x = (int) fr.min.x;
r.min.y = (int) fr.min.y;
return r;
}
Point
fptop(fpoint fp)
{
Point p;
p.x = (int)fp.x;
p.y = (int)fp.y;
return p;
}
fpoint
fPt(double x, double y)
{
fpoint p;
p.x = x;
p.y = y;
return p;
}
frectangle
fRect(double x, double y, double bx, double by)
{
frectangle r;
r.min.x = x;
r.min.y = y;
r.max.x = bx;
r.max.y = by;
return r;
}
fpoint
transform(frectangle dr, frectangle s, fpoint sp)
{
fpoint dp;
( sp.x > s.max.x ) ? sp.x = s.max.x-1 : 1;
( sp.x <= s.min.x ) ? sp.x=s.min.x+1 : 1;
(sp.y > s.max.y) ? sp.y=s.max.y-1 : 1;
(sp.y <= s.min.y) ? sp.y=s.min.y+1 : 1;
if ( sp.x == 0 )
dp.x = dr.min.x;
else {
dp.x =(dr.max.x-dr.min.x)/((s.max.x-s.min.x)/(sp.x-s.min.x));
dp.x += dr.min.x;
}
if (sp.y == 0 )
dp.y = dr.min.y;
else {
dp.y = (dr.max.y-dr.min.y)/((s.max.y-s.min.y)/(sp.y-s.min.y));
dp.y += dr.min.y;
}
// adjust the y coords
dp.y = (dr.max.y - dp.y)+dr.min.y;
return dp;
}
void
addptvar(int i, fpoint p) {
if( V[i].fig.p == nil ) {
V[i].fig.p = emalloc(sizeof(Point));
V[i].fig.p[0] = fptop(p);
V[i].fig.n = 0;
} else {
V[i].fig.p = erealloc(V[i].fig.p,sizeof(Point)*(V[i].fig.n+1));
V[i].fig.p[V[i].fig.n] = fptop(p);
V[i].fig.n++;
}
}
void
endpolys(fpoint end){
for(int i=1;i<Nvars;i++) {
if ( V[i].fig.n >=1 ) {
addptvar(i,fPt(V[i].fig.p[V[i].fig.n-1].x, end.y));
addptvar(i,fPt(V[i].fig.p[0].x, end.y));
}
}
}
void
getvals(frectangle dst, double start, double end, double maxval)
{
Biobuf bin;
char *line;
double xval,yval;
char *vals[MAXVARS];
fpoint p;
frectangle src;
int i,n, nvals;
src=fRect(start,0,end,maxval);
Binit(&bin,0,OREAD);
nvals = 1;
while((line=Brdstr(&bin, '\n', 1)) != nil){
n =getfields(line, vals, Nvars, 1, " ");
if ( n != Nvars )
sysfatal("getvals(): error getting values");
xval=strtod(vals[0],0);
for(i=1;i<Nvars;i++) {
yval=strtod(vals[i],0);
p = transform(dst,src,fPt(xval,yval));
addptvar(i,p);
// fill stats
if ( V[i].fig.n < 1 )
V[i].min = yval;
if ( yval > V[i].max )
V[i].max = yval;
else if ( yval < V[i].min )
V[i].min = yval;
V[i].sum += yval;
V[i].mean = V[i].sum / nvals;
}
free(line);
line = nil;
nvals++;
}
Bterm(&bin);
endpolys(dst.max);
}
void
drawvalue(Memimage *dst,polygon *pol, int color, int fill)
{
if (fill)
memfillpoly(dst, pol->p, pol->n, 0,Pallete[color].fg, pol->p[0], SoverD);
mempoly(dst,pol->p,pol->n,Endsquare,Endsquare,0,Pallete[color].hl,pol->p[0],SoverD);
}
/* draw functions */
void
drawbox(Memimage *dst, frectangle box,int color, int fill)
{
int radius;
Point rect[5];
Drawop dop;
dop = SoverD;
radius=0;
rect[0] = fptop(box.min);
rect[1].x = box.max.x; rect[1].y = box.min.y;
rect[2] = fptop(box.max);
rect[3].x = box.min.x; rect[3].y = box.max.y;
rect[4] = fptop(box.min);
if (fill)
memfillpoly(dst, rect, 5, 1,Pallete[color].fg, ZP, dop);
else
mempoly(dst,rect,5,Endsquare,Endsquare,radius,Pallete[color].fg,ZP,dop);
}
void
drawtext(Memimage *dst,Point p, int color,int size,char *s)
{
Memsubfont *f;
char *font;
font=smprint("/lib/font/bit/lucida/latin1.%d.0",size);
f = openmemsubfont(font);
if ( f == nil )
sysfatal("cannot open font: %r\n");
memimagestring(dst, p, Pallete[color].fg, ZP, f, s);
freememsubfont(f);
}
void
drawresume(Memimage *dst,frectangle coord)
{
char *str;
frectangle c;
c = fRect(coord.min.x+2,coord.min.y+2,coord.min.x+10,coord.min.y+10);
for(int i=1;i<Nvars;i++) {
drawbox(dst,c,V[i].c,1);
str=smprint("%s: max %f min %f mean %f",V[i].s,V[i].max, V[i].min,V[i].mean);
drawtext(dst,Pt(c.min.x+15,c.min.y-4),Black,7,str);
// next point
c = fRect(c.min.x+0,c.min.y+15,c.max.x+0,c.max.y+15);
}
}
void
drawgrid(Memimage *dst,frectangle grid, frectangle stats, double xmin, double xmax, double ymax, int istime)
{
Point p0x,p1x,p0y,p1y;
int i;
double stepx, stepy, vstepx;
char *str;
long xval,hms,hour,min,d1;
long clockl;
/* a line each 10% of the total */
stepx = (stats.max.x-stats.min.x)/10;
stepy = (stats.max.y-stats.min.y)/10;
/* estimated value for the x coord */
vstepx = (xmax-xmin)/10;
for(i=10;i>=0;i--)
{
p0x=Pt(stats.min.x+i*stepx,stats.min.y);
p1x=Pt(stats.min.x+i*stepx,grid.max.y-10);
p0y=Pt(grid.min.x+15,(stats.max.y-i*stepy));
p1y=Pt(grid.max.x,(stats.max.y-i*stepy));
memimageline(dst,p0x,p1x,0,0,0,Pallete[Grey].hl,ZP,SoverD);
memimageline(dst,p0y,p1y,0,0,0,Pallete[Grey].hl,ZP,SoverD);
xval = i*vstepx+xmin;
if ( istime) {
hms = xval % 86400L;
if(hms < 0)
hms += 86400L;
d1 = hms / 60;
min = d1 % 60;
d1 /= 60;
hour = d1;
str = smprint("%0.2d:%0.2d",hour,min);
} else
str=smprint("%3.0G",xval);
drawtext(dst,Pt(p1x.x-10,p1x.y+5),Black,6,str);
free(str);
str=smprint("%G",(ymax*i)/10);
drawtext(dst,Pt(p0y.x-25,p0y.y-5),Black,6,str);free(str);
}
drawtext(dst,Pt(stats.min.x-25,grid.max.y-7), Black,8,V[0].s);
}
void
usage(char *s)
{
fprint(2,"%s [-T] -t title -s start -e end -m maxval -v var1,var2,var3. . .\n",s);
exits("usage");
}
void
main(int argc, char *argv[])
{
frectangle r,stats,grid,legend,resume,total,title;
Memimage *m;
char *varlist, *tstr;
char *varnames[MAXVARS];
int maxval,start,end,i;
int istime=0;
if (argc < 8 )
usage(argv[0]);
ARGBEGIN {
case 's':
start=strtod(ARGF(),0);
break;
case 'e':
end=strtod(ARGF(),0);
break;
case 'm':
maxval=strtod(ARGF(),0);
break;
case 'v':
varlist=ARGF();
break;
case 't':
tstr=ARGF();
break;
case 'T':
istime=1;
break;
default:
fprint(2,"unknown flag ('%c')",ARGC());
exits("error in flags");
} ARGEND
if ( argc != 0 || tstr == nil )
usage(argv[0]);
memimageinit();
Nvars = getfields(varlist, varnames, MAXVARS, 1, ",");
if ( Nvars == 0 || Nvars > MAXVARS)
sysfatal("Incorrect var number check -v option (%d)\n",Nvars);
V = emalloc(sizeof(Var)*Nvars);
for(i=0;i<Nvars;i++) {
V[i].s=smprint("%s",varnames[i]);
V[i].c=i;
V[i].fig.p = nil;
V[i].max = V[i].min = V[i].sum = V[i].mean = V[i].fig.n = 0;
}
r = fRect(0,0,550,300);
m = allocmemimage(frtor(r),RGB24);
m->clipr = m->r;
colinit(m->clipr);
grid = fRect(r.min.x+20,r.min.y+30,r.max.x-20,r.max.y-80);
stats= fRect(grid.min.x+20,grid.min.y,grid.max.x,grid.max.y-20);
resume = fRect(grid.min.x,grid.max.y+15,grid.max.x,r.max.y-2);
title = fRect(grid.min.x,r.min.y+2,grid.max.x,stats.min.y-2);
getvals(stats, start, end, maxval);
// draw the data!!
memfillcolor(m,DWhite);
drawbox(m,stats,White,1);
drawgrid(m,grid,stats,start,end,maxval, istime);
for(i=1;i<Nvars;i++) {
drawvalue(m,&V[i].fig, V[i].c, 1);
}
drawtext(m,fptop(title.min),Black,8,tstr);
drawresume(m,resume);
drawbox(m,stats,Black,0);
r.max.x--; r.max.y--;
drawbox(m,r,Grey,0);
writememimage(1,m);
}
|