2005-08-21 03:19:56 +02:00
|
|
|
// Draw evaluates the first argument.
|
|
|
|
//
|
|
|
|
// Test case 1. Checks default arg and verifies "last" is correct.
|
|
|
|
// x^2
|
|
|
|
// draw
|
|
|
|
// integral result should be 1/3 x^3
|
|
|
|
//
|
|
|
|
// Test case 2. Checks that 1st arg is evaluated and "last" is correct.
|
|
|
|
// draw(integral(erf(x)))
|
|
|
|
// derivative result should be erf(x)
|
|
|
|
|
2004-03-03 21:24:06 +01:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "defs.h"
|
|
|
|
|
|
|
|
extern int text_width(int, char *);
|
|
|
|
extern void shipout(unsigned char *, int, int);
|
|
|
|
|
2005-09-02 21:41:19 +02:00
|
|
|
extern struct text_metric text_metric[11];
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
#define SMALL_FONT 1
|
|
|
|
#define DEFAULT_FONT 2
|
|
|
|
#define DRAW_LINE 23
|
|
|
|
#define DRAW_POINT 24
|
|
|
|
#define DRAW_BOX 25
|
|
|
|
|
|
|
|
#define DIM 300
|
|
|
|
|
|
|
|
#define F p1
|
|
|
|
#define T p2
|
|
|
|
#define X p3
|
|
|
|
#define Y p4
|
|
|
|
#define XT p5
|
|
|
|
#define YT p6
|
|
|
|
|
|
|
|
static void setup_trange(void);
|
|
|
|
static void setup_trange_f(void);
|
|
|
|
static void setup_xrange(void);
|
|
|
|
static void setup_xrange_f(void);
|
|
|
|
static void setup_yrange(void);
|
|
|
|
static void setup_yrange_f(void);
|
2004-05-06 20:07:45 +02:00
|
|
|
static void draw(void);
|
2004-03-03 21:24:06 +01:00
|
|
|
static void draw2(void);
|
|
|
|
static void draw3(void);
|
|
|
|
static void new_point(double);
|
|
|
|
static void fill(int, int, int);
|
|
|
|
static void emit_graph(void);
|
|
|
|
|
|
|
|
static double tmin, tmax;
|
|
|
|
static double xmin, xmax;
|
|
|
|
static double ymin, ymax;
|
|
|
|
|
|
|
|
#define YMAX 10000
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
int x, y;
|
|
|
|
double t;
|
|
|
|
} draw_buf[YMAX];
|
|
|
|
|
|
|
|
static int draw_count;
|
|
|
|
|
|
|
|
void
|
2004-05-06 20:07:45 +02:00
|
|
|
eval_draw(void)
|
|
|
|
{
|
2005-08-21 03:19:56 +02:00
|
|
|
// 1st arg
|
|
|
|
|
|
|
|
push(cadr(p1));
|
|
|
|
eval();
|
|
|
|
|
2005-08-05 21:28:02 +02:00
|
|
|
// save "last" so we can do, for example,
|
|
|
|
//
|
|
|
|
// x^2
|
|
|
|
// draw
|
|
|
|
// integral
|
|
|
|
//
|
|
|
|
// and have integral do integral(x^2)
|
|
|
|
|
|
|
|
push(symbol(YYLAST)->u.sym.binding);
|
|
|
|
|
2005-08-21 03:19:56 +02:00
|
|
|
// must eval 2nd arg in case it's $1, $2, etc.
|
2004-06-19 19:51:45 +02:00
|
|
|
|
2005-08-21 03:19:56 +02:00
|
|
|
push(caddr(p1));
|
|
|
|
eval();
|
2004-06-19 19:51:45 +02:00
|
|
|
|
2005-08-21 03:19:56 +02:00
|
|
|
p2 = pop();
|
2004-06-19 19:51:45 +02:00
|
|
|
|
2006-01-16 20:37:31 +01:00
|
|
|
if (p2 == symbol(NIL))
|
2005-08-21 03:19:56 +02:00
|
|
|
guess();
|
|
|
|
else
|
|
|
|
push(p2);
|
2004-06-19 19:51:45 +02:00
|
|
|
|
2004-05-06 20:07:45 +02:00
|
|
|
draw();
|
2004-06-19 19:51:45 +02:00
|
|
|
|
2005-08-05 21:28:02 +02:00
|
|
|
symbol(YYLAST)->u.sym.binding = pop();
|
|
|
|
|
2006-01-16 20:37:31 +01:00
|
|
|
push(symbol(NIL)); // so no result is printed
|
|
|
|
// also, "last" is not modified when result is "nil"
|
2004-05-06 20:07:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-03 21:24:06 +01:00
|
|
|
draw(void)
|
|
|
|
{
|
2006-10-11 19:37:38 +02:00
|
|
|
draw_flag++;
|
2004-03-03 21:24:06 +01:00
|
|
|
save();
|
|
|
|
draw2();
|
|
|
|
restore();
|
2006-10-11 19:37:38 +02:00
|
|
|
draw_flag--;
|
2004-03-03 21:24:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw2(void)
|
|
|
|
{
|
|
|
|
T = pop();
|
|
|
|
F = pop();
|
|
|
|
|
|
|
|
setup_trange();
|
|
|
|
|
|
|
|
setup_xrange();
|
|
|
|
|
|
|
|
setup_yrange();
|
|
|
|
|
2004-05-06 20:07:45 +02:00
|
|
|
// if not parametric draw then trange = xrange
|
2004-03-03 21:24:06 +01:00
|
|
|
|
2004-05-06 20:07:45 +02:00
|
|
|
if (T != symbol(SYMBOL_T)) {
|
2004-03-03 21:24:06 +01:00
|
|
|
tmin = xmin;
|
|
|
|
tmax = xmax;
|
|
|
|
}
|
|
|
|
|
|
|
|
draw3();
|
|
|
|
|
|
|
|
emit_graph();
|
|
|
|
}
|
|
|
|
|
|
|
|
#define N 100
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw3(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern jmp_buf stop_return;
|
|
|
|
static void eval_point(double);
|
|
|
|
|
|
|
|
static 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++;
|
|
|
|
|
|
|
|
eval_point(t); // returns expr in XT, YT
|
|
|
|
|
|
|
|
if (!isnum(XT) || !isnum(YT))
|
|
|
|
return;
|
|
|
|
|
|
|
|
push(XT);
|
|
|
|
x = pop_double();
|
|
|
|
x = (x - xmin) / (xmax - xmin);
|
|
|
|
x = (double) DIM * 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) DIM * 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
eval_point(double t)
|
|
|
|
{
|
|
|
|
jmp_buf save_stop_return;
|
2006-10-06 20:28:26 +02:00
|
|
|
volatile int save_tos;
|
2004-03-03 21:24:06 +01:00
|
|
|
U ** volatile save_frame;
|
|
|
|
|
|
|
|
save();
|
|
|
|
|
|
|
|
// steal the stop vector
|
|
|
|
|
|
|
|
memcpy(save_stop_return, stop_return, sizeof (jmp_buf));
|
|
|
|
save_tos = tos;
|
|
|
|
save_frame = frame;
|
|
|
|
|
|
|
|
if (setjmp(stop_return)) {
|
|
|
|
memcpy(stop_return, save_stop_return, sizeof (jmp_buf));
|
|
|
|
tos = save_tos;
|
|
|
|
frame = save_frame;
|
|
|
|
restore();
|
2006-01-16 20:37:31 +01:00
|
|
|
XT = symbol(NIL);
|
|
|
|
YT = symbol(NIL);
|
2004-03-03 21:24:06 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-05-06 20:07:45 +02:00
|
|
|
push(F);
|
2004-03-03 21:24:06 +01:00
|
|
|
push(T);
|
|
|
|
push_double(t);
|
2006-10-06 20:28:26 +02:00
|
|
|
subst();
|
|
|
|
eval();
|
2004-03-03 21:24:06 +01:00
|
|
|
|
2004-05-06 20:07:45 +02:00
|
|
|
p1 = pop();
|
|
|
|
|
2005-08-06 22:57:37 +02:00
|
|
|
if (istensor(p1) && p1->u.tensor->nelem >= 2) {
|
2004-05-06 20:07:45 +02:00
|
|
|
push(p1->u.tensor->elem[0]);
|
|
|
|
push(p1->u.tensor->elem[1]);
|
|
|
|
} else {
|
|
|
|
push_double(t);
|
|
|
|
push(p1);
|
|
|
|
}
|
2004-03-03 21:24:06 +01:00
|
|
|
|
|
|
|
restore();
|
|
|
|
|
|
|
|
// do after restore
|
|
|
|
|
|
|
|
YT = pop();
|
|
|
|
XT = pop();
|
|
|
|
|
|
|
|
memcpy(stop_return, save_stop_return, sizeof (jmp_buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_DEPTH 6
|
|
|
|
|
|
|
|
static 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
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_trange(void)
|
|
|
|
{
|
|
|
|
save();
|
|
|
|
setup_trange_f();
|
|
|
|
restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_trange_f(void)
|
|
|
|
{
|
|
|
|
// default range is (-pi, pi)
|
|
|
|
|
|
|
|
tmin = -M_PI;
|
|
|
|
|
|
|
|
tmax = M_PI;
|
|
|
|
|
2005-08-07 16:42:42 +02:00
|
|
|
p1 = usr_symbol("trange");
|
2004-03-03 21:24:06 +01:00
|
|
|
|
2005-08-06 22:57:37 +02:00
|
|
|
if (!issymbol(p1))
|
2004-03-03 21:24:06 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
p1 = p1->u.sym.binding;
|
|
|
|
|
|
|
|
// must be two element vector
|
|
|
|
|
2005-08-06 22:57:37 +02:00
|
|
|
if (!istensor(p1) || p1->u.tensor->ndim != 1 || p1->u.tensor->nelem != 2)
|
2004-03-03 21:24:06 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
push(p1->u.tensor->elem[0]);
|
|
|
|
eval();
|
|
|
|
p2 = pop();
|
|
|
|
|
|
|
|
push(p1->u.tensor->elem[1]);
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_xrange(void)
|
|
|
|
{
|
|
|
|
save();
|
|
|
|
setup_xrange_f();
|
|
|
|
restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_xrange_f(void)
|
|
|
|
{
|
|
|
|
// default range is (-10,10)
|
|
|
|
|
|
|
|
xmin = -10.0;
|
|
|
|
|
|
|
|
xmax = 10.0;
|
|
|
|
|
2005-08-07 16:42:42 +02:00
|
|
|
p1 = usr_symbol("xrange");
|
2004-03-03 21:24:06 +01:00
|
|
|
|
2005-08-06 22:57:37 +02:00
|
|
|
if (!issymbol(p1))
|
2004-03-03 21:24:06 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
p1 = p1->u.sym.binding;
|
|
|
|
|
|
|
|
// must be two element vector
|
|
|
|
|
2005-08-06 22:57:37 +02:00
|
|
|
if (!istensor(p1) || p1->u.tensor->ndim != 1 || p1->u.tensor->nelem != 2)
|
2004-03-03 21:24:06 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
push(p1->u.tensor->elem[0]);
|
|
|
|
eval();
|
|
|
|
p2 = pop();
|
|
|
|
|
|
|
|
push(p1->u.tensor->elem[1]);
|
|
|
|
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.
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_yrange(void)
|
|
|
|
{
|
|
|
|
save();
|
|
|
|
setup_yrange_f();
|
|
|
|
restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_yrange_f(void)
|
|
|
|
{
|
|
|
|
// default range is (-10,10)
|
|
|
|
|
|
|
|
ymin = -10.0;
|
|
|
|
|
|
|
|
ymax = 10.0;
|
|
|
|
|
2005-08-07 16:42:42 +02:00
|
|
|
p1 = usr_symbol("yrange");
|
2004-03-03 21:24:06 +01:00
|
|
|
|
2005-08-06 22:57:37 +02:00
|
|
|
if (!issymbol(p1))
|
2004-03-03 21:24:06 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
p1 = p1->u.sym.binding;
|
|
|
|
|
|
|
|
// must be two element vector
|
|
|
|
|
2005-08-06 22:57:37 +02:00
|
|
|
if (!istensor(p1) || p1->u.tensor->ndim != 1 || p1->u.tensor->nelem != 2)
|
2004-03-03 21:24:06 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
push(p1->u.tensor->elem[0]);
|
|
|
|
eval();
|
|
|
|
p2 = pop();
|
|
|
|
|
|
|
|
push(p1->u.tensor->elem[1]);
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
#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;
|
|
|
|
|
|
|
|
static 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
|
2006-10-12 17:57:20 +02:00
|
|
|
if (x < 0 || x > DIM)
|
2004-03-03 21:24:06 +01:00
|
|
|
continue;
|
2006-10-12 17:57:20 +02:00
|
|
|
if (y < 0 || y > DIM)
|
2004-03-03 21:24:06 +01:00
|
|
|
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';
|
|
|
|
}
|