123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934 |
- // Draw a graph
- extern "C"{
- #include "fxlib.h"
- }
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "stdafx.h"
- #include "defs.h"
- #define DIMX 128
- #define DIMY 64
- #define F p3
- #define T p4
- #define X p5
- #define Y p6
- #define XT p7
- #define YT p8
- static double tmin, tmax;
- static double xmin, xmax;
- static double ymin, ymax;
- #define YMAX 1000
- typedef struct {
- int x, y;
- double t;
- } DRAWBUF;
- DRAWBUF *draw_buf;
- static int draw_count;
- void
- eval_draw(void)
- {
- draw_buf=(DRAWBUF*)calloc(YMAX,sizeof(DRAWBUF));
- F = cadr(p1);
- T = caddr(p1);
- if (T == symbol(NIL)) {
- push(F);
- rewrite();
- guess();
- T = pop();
- F = pop();
- }
- push(get_binding(T));
- push(get_arglist(T));
- draw_main();
- p2 = pop();
- p1 = pop();
- set_binding_and_arglist(T, p1, p2);
- // return value
- push(symbol(NIL));
- }
- void
- draw_main(void)
- {
- if (draw_flag) {
- draw_flag = 0; // so "stop" really stops
- stop("draw calls draw");
- }
- draw_flag++;
- setup_trange();
- setup_xrange();
- setup_yrange();
- check_for_parametric_draw();
- create_point_set();
- emit_graph();
- draw_flag--;
- }
- /* xrange sets the horizontal scale
- yrange sets the vertical scale
- Normally, the function F is evaluated from xrange[1] to xrange[2].
- However, if F returns a vector then parametric drawing is used. In this
- case F is evaluated from trange[1] to trange[2].
- */
- void
- check_for_parametric_draw(void)
- {
- eval_f(tmin);
- p1 = pop();
- if (!istensor(p1)) {
- tmin = xmin;
- tmax = xmax;
- }
- }
- #define N 100
- void
- create_point_set(void)
- {
- int i, n;
- double t;
- draw_count = 0;
- for (i = 0; i <= N; i++) {
- t = tmin + ((double) i / (double) N) * (tmax - tmin);
- new_point(t);
- }
- n = draw_count;
- for (i = 0; i < n - 1; i++)
- fill(i, i + 1, 0);
- }
- void
- new_point(double t)
- {
- double x, y;
- if (draw_count >= YMAX)
- return;
- draw_buf[draw_count].x = -10000;
- draw_buf[draw_count].y = -10000;
- draw_buf[draw_count].t = t;
- draw_count++;
- get_xy(t);
- if (!isnum(XT) || !isnum(YT))
- return;
- push(XT);
- x = pop_double();
- x = (x - xmin) / (xmax - xmin);
- x = (double) DIMX * x + 0.5; // map 0-1 to 0-DIM, +0.5 so draw(x^3) looks right
- push(YT);
- y = pop_double();
- y = (y - ymin) / (ymax - ymin);
- y = (double) DIMY * y + 0.5; // map 0-1 to 0-DIM, +0.5 so draw(x^3) looks right
- if (x < -10000.0)
- x = -10000.0;
- if (x > 10000.0)
- x = 10000.0;
- if (y < -10000.0)
- y = -10000.0;
- if (y > 10000.0)
- y = 10000.0;
- draw_buf[draw_count - 1].x = (int) x;
- draw_buf[draw_count - 1].y = (int) y;
- }
- // Evaluate F(t) and return in XT and YT.
- void
- get_xy(double t)
- {
- eval_f(t);
- p1 = pop();
- if (istensor(p1)) {
- if (p1->u.tensor->nelem >= 2) {
- XT = p1->u.tensor->elem[0];
- YT = p1->u.tensor->elem[1];
- } else {
- XT = symbol(NIL);
- YT = symbol(NIL);
- }
- return;
- }
- push_double(t);
- XT = pop();
- YT = p1;
- }
- // Evaluate F(t) without stopping due to an error such as divide by zero.
- void
- eval_f(double t)
- {
- // These must be volatile or it crashes. (Compiler error?)
- // Read it backwards, save_tos is a volatile int, etc.
- int volatile save_tos;
- U ** volatile save_frame;
- save();
- save_tos = tos;
- save_frame = frame;
- draw_flag++;
- if (setjmp(draw_stop_return)) {
- tos = save_tos;
- push(symbol(NIL));
- frame = save_frame;
- restore();
- draw_flag--;
- return;
- }
- push_double(t);
- p1 = pop();
- set_binding(T, p1);
- push(F);
- eval();
- yyfloat();
- eval();
- restore();
- draw_flag--;
- }
- #define MAX_DEPTH 6
- void
- fill(int i, int k, int level)
- {
- int dx, dy, j;
- double t;
- if (level >= MAX_DEPTH || draw_count >= YMAX)
- return;
- dx = abs(draw_buf[i].x - draw_buf[k].x);
- dy = abs(draw_buf[i].y - draw_buf[k].y);
- if (dx < 1 && dy < 1)
- return;
- t = (draw_buf[i].t + draw_buf[k].t) / 2.0;
- j = draw_count;
- new_point(t);
- fill(i, j, level + 1);
- fill(j, k, level + 1);
- }
- //-----------------------------------------------------------------------------
- //
- // Normalize x to [0,1]
- //
- // Example: xmin = -10, xmax = 10, xmax - xmin = 20
- //
- // x x - xmin (x - xmin) / (xmax - xmin)
- //
- // -10 0 0.00
- //
- // -5 5 0.25
- //
- // 0 10 0.50
- //
- // 5 15 0.75
- //
- // 10 20 1.00
- //
- //-----------------------------------------------------------------------------
- void
- setup_trange(void)
- {
- save();
- setup_trange_f();
- restore();
- }
- void
- setup_trange_f(void)
- {
- // default range is (-pi, pi)
- tmin = -M_PI;
- tmax = M_PI;
- p1 = usr_symbol("trange");
- if (!issymbol(p1))
- return;
- p1 = get_binding(p1);
- // must be two element vector
- if (!istensor(p1) || p1->u.tensor->ndim != 1 || p1->u.tensor->nelem != 2)
- return;
- push(p1->u.tensor->elem[0]);
- eval();
- yyfloat();
- eval();
- p2 = pop();
- push(p1->u.tensor->elem[1]);
- eval();
- yyfloat();
- eval();
- p3 = pop();
- if (!isnum(p2) || !isnum(p3))
- return;
- push(p2);
- tmin = pop_double();
- push(p3);
- tmax = pop_double();
- if (tmin == tmax)
- stop("draw: trange is zero");
- }
- void
- setup_xrange(void)
- {
- save();
- setup_xrange_f();
- restore();
- }
- void
- setup_xrange_f(void)
- {
- // default range is (-10,10)
- xmin = -10.0;
- xmax = 10.0;
- p1 = usr_symbol("xrange");
- if (!issymbol(p1))
- return;
- p1 = get_binding(p1);
- // must be two element vector
- if (!istensor(p1) || p1->u.tensor->ndim != 1 || p1->u.tensor->nelem != 2)
- return;
- push(p1->u.tensor->elem[0]);
- eval();
- yyfloat();
- eval();
- p2 = pop();
- push(p1->u.tensor->elem[1]);
- eval();
- yyfloat();
- eval();
- p3 = pop();
- if (!isnum(p2) || !isnum(p3))
- return;
- push(p2);
- xmin = pop_double();
- push(p3);
- xmax = pop_double();
- if (xmin == xmax)
- stop("draw: xrange is zero");
- }
- //-----------------------------------------------------------------------------
- //
- // Example: yrange=(-10,10)
- //
- // y d v (vertical pixel coordinate)
- //
- // 10 0.00 0
- //
- // 5 0.25 100
- //
- // 0 0.50 200
- //
- // -5 0.75 300
- //
- // -10 1.00 400
- //
- // We have
- //
- // d = (10 - y) / 20
- //
- // = (B - y) / (B - A)
- //
- // where yrange=(A,B)
- //
- // To convert d to v, multiply by N where N = 400.
- //
- //-----------------------------------------------------------------------------
- void
- setup_yrange(void)
- {
- save();
- setup_yrange_f();
- restore();
- }
- void
- setup_yrange_f(void)
- {
- // default range is (-10,10)
- ymin = -10.0;
- ymax = 10.0;
- p1 = usr_symbol("yrange");
- if (!issymbol(p1))
- return;
- p1 = get_binding(p1);
- // must be two element vector
- if (!istensor(p1) || p1->u.tensor->ndim != 1 || p1->u.tensor->nelem != 2)
- return;
- push(p1->u.tensor->elem[0]);
- eval();
- yyfloat();
- eval();
- p2 = pop();
- push(p1->u.tensor->elem[1]);
- eval();
- yyfloat();
- eval();
- p3 = pop();
- if (!isnum(p2) || !isnum(p3))
- return;
- push(p2);
- ymin = pop_double();
- push(p3);
- ymax = pop_double();
- if (ymin == ymax)
- stop("draw: yrange is zero");
- }
- void get_xyminmax(double* xminp, double* xmaxp, double* yminp, double* ymaxp) {
- *xminp = xmin;
- *xmaxp = xmax;
- *yminp = ymin;
- *ymaxp = ymax;
- }
- #define XOFF 0
- #define YOFF 24
- static void emit_xaxis(void);
- static void emit_yaxis(void);
- static void emit_xscale(void);
- static void emit_yscale(void);
- static void get_xzero(void);
- static void get_yzero(void);
- static int xzero, yzero;
- void
- emit_graph(void)
- {
- int i, x, y;
- Bdisp_AllClr_VRAM();
- get_xzero();
- get_yzero();
- emit_xaxis();
- emit_yaxis();
- emit_xscale();
- emit_yscale();
-
- for (i = 0; i < draw_count; i++) {
- x = draw_buf[i].x;
- y = DIMY - draw_buf[i].y; // flip the y coordinate
- if (x < 0 || x > DIMX)
- continue;
- if (y < 0 || y > DIMY)
- continue;
- Bdisp_SetPoint_VRAM(x+XOFF, y+YOFF, 1);
- }
- set_has_drawn(1);
- }
- static void
- emit_xaxis(void)
- {
- int x, y, x2, y2;
- if (yzero < 0 || yzero > DIMY)
- return;
- x = XOFF;
- y = YOFF + yzero;
- x2 = XOFF + DIMX;
- y2 = YOFF + yzero;
- Bdisp_DrawLineVRAM(x, y, x2, y2);
- }
- static void
- emit_yaxis(void)
- {
- int x, y, x2, y2;
- if (xzero < 0 || xzero > DIMX)
- return;
- x = XOFF + xzero;
- y = YOFF;
- x2 = XOFF + xzero;
- y2 = YOFF + DIMY;
- Bdisp_DrawLineVRAM(x, y, x2, y2);
- }
- static void
- get_xzero(void)
- {
- double x;
- x = -((double) DIMX) * xmin / (xmax - xmin) + 0.5;
- if (x < -10000.0)
- x = -10000.0;
- if (x > 10000.0)
- x = 10000.0;
- xzero = (int) x;
- }
- static void
- get_yzero(void)
- {
- double y;
- y = -((double) DIMY) * ymin / (ymax - ymin) + 0.5;
- if (y < -10000.0)
- y = -10000.0;
- if (y > 10000.0)
- y = 10000.0;
- yzero = DIMY - (int) y; // flip the y coordinate
- }
- static void emit_xscale_f(int, char *);
- static void
- emit_xscale(void)
- {
- static char s[100];
- sprintf(s, "%g", xmin);
- emit_xscale_f(0, s);
- sprintf(s, "%g", xmax);
- emit_xscale_f(DIMX, s);
- }
- static void
- emit_xscale_f(int xx, char *s)
- {
- int w, x, y;
- y = 0;
- w = 0;
- PrintMini( w, y, (unsigned char*)s, 0); // get width
- x = XOFF + xx;
- if(x >= DIMX) x = x-w;
- y = YOFF + yzero - 24+2;
- PrintMini( x, y, (unsigned char*)s, 0);
- }
- static void emit_yscale_f(int, char *);
- static void
- emit_yscale(void)
- {
- static char s[100];
- sprintf(s, "%g", ymax);
- emit_yscale_f(0, s);
- sprintf(s, "%g", ymin);
- emit_yscale_f(DIMY, s);
- }
- static void
- emit_yscale_f(int yy, char *s)
- {
- int w, x, y;
- y = 0;
- w = 0;
- PrintMini( w, y, (unsigned char*)s, 0); // get width
- x = xzero - w;
- y = YOFF + yy;
- if(y >= DIMY) y = y-9;
- y -= 24;
- PrintMini( x, y, (unsigned char*)s, 0);
- }
- /*
- #define XOFF 0
- #define YOFF 0
- #define SHIM 10
- static int k;
- static unsigned char *buf;
- static void emit_box(void);
- static void emit_xaxis(void);
- static void emit_yaxis(void);
- static void emit_xscale(void);
- static void emit_yscale(void);
- static void emit_xzero(void);
- static void emit_yzero(void);
- static void get_xzero(void);
- static void get_yzero(void);
- static int xzero, yzero;
- void
- emit_graph(void)
- {
- int h, i, len, x, y;
- get_xzero();
- get_yzero();
- len = 1000 + 5 * draw_count;
- buf = (unsigned char *) malloc(len);
- h = DIM + SHIM + text_metric[SMALL_FONT].ascent + text_metric[SMALL_FONT].descent;
- //buf[0] = (unsigned char) (h >> 8);
- //buf[1] = (unsigned char) h;
- //buf[2] = (unsigned char) (DIM >> 8);
- //buf[3] = (unsigned char) DIM;
- k = 0;
- emit_box();
- emit_xaxis();
- emit_yaxis();
- emit_xscale();
- emit_yscale();
- emit_xzero();
- emit_yzero();
- for (i = 0; i < draw_count; i++) {
- x = draw_buf[i].x;
- y = DIM - draw_buf[i].y; // flip the y coordinate
- if (x < 0 || x > DIM)
- continue;
- if (y < 0 || y > DIM)
- continue;
- x += XOFF;
- y += YOFF;
- buf[k++] = DRAW_POINT;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- }
- buf[k++] = 0;
- shipout(buf, DIM + 1, h);
- }
- static void
- get_xzero(void)
- {
- double x;
- x = -((double) DIM) * xmin / (xmax - xmin) + 0.5;
- if (x < -10000.0)
- x = -10000.0;
- if (x > 10000.0)
- x = 10000.0;
- xzero = (int) x;
- }
- static void
- get_yzero(void)
- {
- double y;
- y = -((double) DIM) * ymin / (ymax - ymin) + 0.5;
- if (y < -10000.0)
- y = -10000.0;
- if (y > 10000.0)
- y = 10000.0;
- yzero = DIM - (int) y; // flip the y coordinate
- }
- static void
- emit_box(void)
- {
- int x, y;
- buf[k++] = DRAW_BOX;
- x = XOFF;
- y = YOFF;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- x = XOFF + DIM;
- y = YOFF + DIM;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- }
- static void
- emit_xaxis(void)
- {
- int x, y;
- if (yzero < 0 || yzero > DIM)
- return;
- buf[k++] = DRAW_LINE;
- x = XOFF;
- y = YOFF + yzero;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- x = XOFF + DIM;
- y = YOFF + yzero;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- }
- static void
- emit_yaxis(void)
- {
- int x, y;
- if (xzero < 0 || xzero > DIM)
- return;
- buf[k++] = DRAW_LINE;
- x = XOFF + xzero;
- y = YOFF;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- x = XOFF + xzero;
- y = YOFF + DIM;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- }
- static void emit_xscale_f(int, char *);
- static void
- emit_xscale(void)
- {
- static char s[100];
- sprintf(s, "%g", xmin);
- emit_xscale_f(0, s);
- sprintf(s, "%g", xmax);
- emit_xscale_f(DIM, s);
- }
- static void
- emit_xscale_f(int xx, char *s)
- {
- int d, i, len, w, x, y;
- // want to center the number w/o sign
- w = text_width(SMALL_FONT, s);
- if (*s == '-')
- d = w - text_width(SMALL_FONT, s + 1);
- else
- d = 0;
- x = XOFF + xx - (w - d) / 2 - d;
- y = YOFF + DIM + SHIM;
- buf[k++] = SMALL_FONT;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- len = (int) strlen(s);
- buf[k++] = (unsigned char) len;
- for (i = 0; i < len; i++)
- buf[k++] = (unsigned char) s[i];
- }
- static void emit_yscale_f(int, char *);
- static void
- emit_yscale(void)
- {
- static char s[100];
- sprintf(s, "%g", ymax);
- emit_yscale_f(0, s);
- sprintf(s, "%g", ymin);
- emit_yscale_f(DIM, s);
- }
- static void
- emit_yscale_f(int yy, char *s)
- {
- int i, len, w, x, y;
- w = text_width(SMALL_FONT, s);
- x = XOFF - SHIM - w;
- y = YOFF + yy - text_metric[SMALL_FONT].ascent / 2;
- buf[k++] = SMALL_FONT;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- len = (int) strlen(s);
- buf[k++] = (unsigned char) len;
- for (i = 0; i < len; i++)
- buf[k++] = (unsigned char) s[i];
- }
- // emit the '0' axis label
- // make sure it doesn't hit the other labels
- static void
- emit_xzero(void)
- {
- int x, y;
- if (xzero < DIM / 4 || xzero > 3 * DIM / 4)
- return;
- x = XOFF + xzero - text_width(SMALL_FONT, "0") / 2;
- y = YOFF + DIM + SHIM;
- buf[k++] = SMALL_FONT;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- buf[k++] = 1;
- buf[k++] = '0';
- }
- // emit the '0' axis label
- // make sure it doesn't hit the other labels
- static void
- emit_yzero(void)
- {
- int x, y;
- if (yzero < DIM / 4 || yzero > 3 * DIM / 4)
- return;
- x = XOFF - SHIM - text_width(SMALL_FONT, "0");
- y = YOFF + yzero - text_metric[SMALL_FONT].ascent / 2;
- buf[k++] = SMALL_FONT;
- buf[k++] = (unsigned char) (x >> 8);
- buf[k++] = (unsigned char) x;
- buf[k++] = (unsigned char) (y >> 8);
- buf[k++] = (unsigned char) y;
- buf[k++] = 1;
- buf[k++] = '0';
- }
- */
|