improved on fplot

This commit is contained in:
aiju 2011-07-17 12:53:41 +02:00
parent e140aa0aee
commit e183ea231d

View file

@ -101,6 +101,10 @@ int nfns;
Token *opstackbot; Token *opstackbot;
double xmin = -10, xmax = 10; double xmin = -10, xmax = 10;
double ymin = -10, ymax = 10; double ymin = -10, ymax = 10;
Image *color;
int cflag;
char *imagedata;
int picx = 640, picy = 480;
void * void *
emalloc(int size) emalloc(int size)
@ -317,62 +321,84 @@ calc(Code *c, double x)
} }
double double
convx(Image *i, int x) convx(Rectangle *r, int x)
{ {
return (xmax - xmin) * (x - i->r.min.x) / (i->r.max.x - i->r.min.x) + xmin; return (xmax - xmin) * (x - r->min.x) / (r->max.x - r->min.x) + xmin;
} }
int int
deconvx(Image *i, double dx) deconvx(Rectangle *r, double dx)
{ {
return (dx - xmin) * (i->r.max.x - i->r.min.x) / (xmax - xmin) + i->r.min.x + 0.5; return (dx - xmin) * (r->max.x - r->min.x) / (xmax - xmin) + r->min.x + 0.5;
} }
double double
convy(Image *i, int y) convy(Rectangle *r, int y)
{ {
return (ymax - ymin) * (i->r.max.y - y) / (i->r.max.y - i->r.min.y) + ymin; return (ymax - ymin) * (r->max.y - y) / (r->max.y - r->min.y) + ymin;
} }
int int
deconvy(Image *i, double dy) deconvy(Rectangle *r, double dy)
{ {
return (ymax - dy) * (i->r.max.y - i->r.min.y) / (ymax - ymin) + i->r.min.y + 0.5; return (ymax - dy) * (r->max.y - r->min.y) / (ymax - ymin) + r->min.y + 0.5;
} }
void void
drawinter(Code *co, Image *i, Image *c, double x1, double x2, int n) pixel(int x, int y)
{
char *p;
if(cflag) {
if(x >= picx || y >= picy || x < 0 || y < 0)
return;
p = imagedata + (picx * y + x) * 3;
p[0] = p[1] = p[2] = 0;
} else
draw(screen, Rect(x, y, x + 1, y + 1), color, nil, ZP);
}
void
drawinter(Code *co, Rectangle *r, double x1, double x2, int n)
{ {
double y1, y2; double y1, y2;
int iy1, iy2; int iy1, iy2;
int ix1, ix2; int ix1, ix2;
ix1 = deconvx(i, x1); ix1 = deconvx(r, x1);
ix2 = deconvx(i, x2); ix2 = deconvx(r, x2);
iy1 = iy2 = 0; iy1 = iy2 = 0;
y1 = calc(co, x1); y1 = calc(co, x1);
if(!isNaN(y1)) { if(!isNaN(y1)) {
iy1 = deconvy(i, y1); iy1 = deconvy(r, y1);
draw(i, Rect(ix1, iy1, ix1 + 1, iy1 + 1), c, nil, ZP); pixel(ix1, iy1);
} }
y2 = calc(co, x2); y2 = calc(co, x2);
if(!isNaN(y2)) { if(!isNaN(y2)) {
iy2 = deconvy(i, y2); iy2 = deconvy(r, y2);
draw(i, Rect(ix2, iy2, ix2 + 1, iy2 + 1), c, nil, ZP); pixel(ix2, iy2);
}
if(!isNaN(y1) && !isNaN(y2) && (iy2 < iy1 - 1 || iy2 > iy1 + 1) && n < 10) {
drawinter(co, i, c, x1, (x1 + x2) / 2, n + 1);
drawinter(co, i, c, (x1 + x2) / 2, x2, n + 1);
} }
if(isNaN(y1) || isNaN(y2))
return;
if(n >= 10)
return;
if(iy2 >= iy1 - 1 && iy2 <= iy1 + 1)
return;
if(iy1 > r->max.y && iy2 > r->max.y)
return;
if(iy1 < r->min.y && iy2 < r->min.y)
return;
drawinter(co, r, x1, (x1 + x2) / 2, n + 1);
drawinter(co, r, (x1 + x2) / 2, x2, n + 1);
} }
void void
drawgraph(Code *co, Image *i, Image *c) drawgraph(Code *co, Rectangle *r)
{ {
int x; int x;
for(x = i->r.min.x; x < i->r.max.x; x++) for(x = r->min.x; x < r->max.x; x++)
drawinter(co, i, c, convx(i, x), convx(i, x + 1), 0); drawinter(co, r, convx(r, x), convx(r, x + 1), 0);
} }
void void
@ -380,15 +406,16 @@ drawgraphs(void)
{ {
int i; int i;
color = display->black;
for(i = 0; i < nfns; i++) for(i = 0; i < nfns; i++)
drawgraph(&fns[i], screen, display->black); drawgraph(&fns[i], &screen->r);
flushimage(display, 1); flushimage(display, 1);
} }
void void
usage(void) usage(void)
{ {
fprint(2, "usage: fplot function\n"); fprint(2, "usage: fplot [-c [-s size]] [-r range] functions ...\n");
exits("usage"); exits("usage");
} }
@ -403,10 +430,10 @@ zoom(void)
r = egetrect(1, &m); r = egetrect(1, &m);
if(r.min.x == 0 && r.min.y == 0 && r.max.x == 0 && r.max.y == 0) if(r.min.x == 0 && r.min.y == 0 && r.max.x == 0 && r.max.y == 0)
return; return;
xmin_ = convx(screen, r.min.x); xmin_ = convx(&screen->r, r.min.x);
xmax_ = convx(screen, r.max.x); xmax_ = convx(&screen->r, r.max.x);
ymin_ = convy(screen, r.max.y); ymin_ = convy(&screen->r, r.max.y);
ymax_ = convy(screen, r.min.y); ymax_ = convy(&screen->r, r.min.y);
xmin = xmin_; xmin = xmin_;
xmax = xmax_; xmax = xmax_;
ymin = ymin_; ymin = ymin_;
@ -432,25 +459,74 @@ parsefns(int n, char **s)
stack = emalloc(sizeof(*stack) * max); stack = emalloc(sizeof(*stack) * max);
} }
void
parserange(char *s)
{
while(*s && !isdigit(*s)) s++;
if(*s == 0) return;
xmin = strtod(s, &s);
while(*s && !isdigit(*s)) s++;
if(*s == 0) return;
xmax = strtod(s, &s);
while(*s && !isdigit(*s)) s++;
if(*s == 0) return;
ymin = strtod(s, &s);
while(*s && !isdigit(*s)) s++;
if(*s == 0) return;
ymax = strtod(s, &s);
}
void
parsesize(char *s)
{
while(*s && !isdigit(*s)) s++;
if(*s == 0) return;
picx = strtol(s, &s, 0);
while(*s && !isdigit(*s)) s++;
if(*s == 0) return;
picy = strtol(s, &s, 0);
}
void void
main(int argc, char **argv) main(int argc, char **argv)
{ {
Event e; Event e;
Rectangle r;
int i;
if(argc < 2) ARGBEGIN {
case 'r': parserange(EARGF(usage())); break;
case 's': parsesize(EARGF(usage())); break;
case 'c': cflag++; break;
default: usage();
} ARGEND;
if(argc < 1)
usage(); usage();
setfcr(getfcr() & ~(FPZDIV | FPINVAL)); setfcr(getfcr() & ~(FPZDIV | FPINVAL));
parsefns(argc - 1, argv + 1); parsefns(argc, argv);
if(initdraw(nil, nil, "fplot") < 0) if(cflag) {
sysfatal("initdraw: %r"); imagedata = emalloc(picx * picy * 3);
einit(Emouse | Ekeyboard); memset(imagedata, 0xFF, picx * picy * 3);
drawgraphs(); print("%11s %11d %11d %11d %11d ", "r8g8b8", 0, 0, picx, picy);
for(;;) { r.min.x = r.min.y = 0;
switch(event(&e)) { r.max.x = picx;
case Ekeyboard: r.max.y = picy;
switch(e.kbdc) { for(i = 0; i < nfns; i++)
case 'q': exits(nil); drawgraph(&fns[i], &r);
case 'z': zoom(); if(write(1, imagedata, picx * picy * 3) < picx * picy * 3)
sysfatal("write: %r");
} else {
if(initdraw(nil, nil, "fplot") < 0)
sysfatal("initdraw: %r");
einit(Emouse | Ekeyboard);
drawgraphs();
for(;;) {
switch(event(&e)) {
case Ekeyboard:
switch(e.kbdc) {
case 'q': exits(nil);
case 'z': zoom();
}
} }
} }
} }