home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff280.lzh
/
Graph
/
object
/
x_y.c
< prev
Wrap
C/C++ Source or Header
|
1989-11-20
|
14KB
|
446 lines
/*
* GRAPH, Version 1.00 - 4 August 1989
*
* Copyright 1989, David Gay. All Rights Reserved.
* This software is freely redistrubatable.
*/
#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include <math.h>
#include <string.h>
#include "object.h"
#include "object/function.h"
#include "file.h"
#include "graph.h"
#include "uio.h"
#include "coords.h"
#include "list.h"
#include "grph.h"
#include "user/eval.h"
#include "user/gadgets.h"
#include "tracker.h"
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
struct x_y {
struct function f;
char x[EXPRLEN], y[EXPRLEN];
value x_t, y_t, dx, dy;
};
struct point_x_y {
point p;
double t;
};
typedef struct point_x_y point_x_y;
/*-------------------------------------------------------------------------*/
/* x_y class implementation */
/*-------------------------------------------------------------------------*/
/* Is the function displayable ? */
static int x_y_ok(const struct x_y *this)
{
return this->f.min != NOVAL && this->f.max != NOVAL &&
this->f.min < this->f.max &&
(this->f.steps == INOVAL || this->f.steps >= 3);
}
/* Free resources */
static void destroy_x_y(struct x_y *this)
{
free_var_list(&this->f.used);
if (this->f.calc) free_list(&this->f.pts, this->f.sizept);
this->f.calc = FALSE;
if (this->x_t) free_expr(this->x_t);
if (this->dx) free_expr(this->dx);
if (this->y_t) free_expr(this->y_t);
if (this->dy) free_expr(this->dy);
this->dx = this->dy = this->x_t = this->y_t = NULL;
}
/* Init dependant parts of function */
static int create_x_y(struct x_y *this)
{
this->f.calc = FALSE;
this->f.var.name = this->f.vname;
this->x_t = compile(this->x);
if (eval_error != 0)
{
message(this->f.o.g, "Compilation error in x(t):", eval_messages[eval_e
rror], (char *)NULL);
return FALSE;
}
this->dx = differentiate(this->x_t, this->f.vname);
if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
{
message(this->f.o.g, "Differentiation error (x):", eval_messages[eval_e
rror], (char *)NULL);
return FALSE;
}
this->y_t = compile(this->y);
if (eval_error != 0)
{
message(this->f.o.g, "Compilation error in y(t):", eval_messages[eval_e
rror], (char *)NULL);
return FALSE;
}
this->dy = differentiate(this->y_t, this->f.vname);
if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
{
message(this->f.o.g, "Differentiation error(y):", eval_messages[eval_er
ror], (char *)NULL);
return FALSE;
}
if (!make_var_list(this->x_t, &this->f.used) || !make_var_list(this->y_t, &
this->f.used))
init_var_list(&this->f.used);
return TRUE;
}
/* Allow user to define function */
static int edit_x_y(struct x_y *this, struct Region **ref)
{
struct Requester *req;
struct Memory *m;
struct Gadget *gl = NULL, *sd, *nd;
char from[NBLEN], to[NBLEN], steps[INTLEN], x[EXPRLEN], y[EXPRLEN], tname[V
ARLEN], colour[INTLEN];
int ret = FALSE;
*ref = NULL;
/* Create requester */
double2str(from, this->f.min);
double2str(to, this->f.max);
int2str(steps, this->f.steps);
int2str(colour, this->f.colour);
strcpy(x, this->x);
strcpy(y, this->y);
strcpy(tname, this->f.vname);
if ((m = NewMemory()) &&
(req = InitReq(50, 20, 255, 165, m)) &&
SetReqBorder(req, 1, m) &&
AddIntuiText(&req->ReqText, "Function", 95, 6, m) &&
AddText(&gl, 0, "x(", FALSE, tname, VARLEN, TRUE, 0, RELVERIFY, 25, 20,
24, 10, TRUE, m) &&
AddText(&gl, 0, ")=", FALSE, x, EXPRLEN, TRUE, 0, RELVERIFY, 81, 20, 16
0, 10, TRUE, m) &&
AddText(&gl, 0, "y( )=", FALSE, y, EXPRLEN, TRUE, 0, RELVERIFY, 81, 4
0, 160, 10, TRUE, m) &&
AddText(&gl, 0, "from ", FALSE, from, NBLEN, TRUE, 0, RELVERIFY, 49, 60
, 80, 10, TRUE, m) &&
AddText(&gl, 0, "to ", FALSE, to, NBLEN, TRUE, 0, RELVERIFY, 167, 60, 8
0, 10, TRUE, m) &&
AddText(&gl, 0, "steps ", FALSE, steps, INTLEN, TRUE, 0, RELVERIFY, 57,
80, 32, 10, TRUE, m) &&
AddText(&gl, 0, "colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 1
56, 80, 32, 10, TRUE, m) &&
(sd = AddOption(&gl, 0, "Show discontinuities", TRUE, this->f.showdisc
* SELECTED, 0, 9, 100, 10, 10, m)) &&
(nd = AddOption(&gl, 0, "Allow flat discontinuities", TRUE, this->f.nic
edisc * SELECTED, 0, 9, 120, 10, 10, m)) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 40, 140, 65, 15, FALS
E, m) &&
AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 145, 140, 65, 15
, FALSE, m))
{
SetReqGadgets(req, gl);
if (ret = DoRequest(req, this->f.o.g, std_ghandler))
{
*ref = full_refresh(this->f.o.g);
/* Extract info */
this->f.min = str2double(from);
this->f.max = str2double(to);
this->f.steps = str2int(steps);
if ((this->f.colour = str2int(colour)) == INOVAL) this->f.colour =
1;
this->f.showdisc = (sd->Flags & SELECTED) != 0;
this->f.nicedisc = (nd->Flags & SELECTED) != 0;
strcpy(this->x, x);
strcpy(this->y, y);
strcpy(this->f.vname, tname);
/* Create function */
destroy_x_y(this);
if (this->f.o.ok = x_y_ok(this)) this->f.o.ok = create_x_y(this);
}
}
Free(m);
return ret;
}
/* Calculate points of function */
static int calc_x_y(struct x_y *this, int allow_mes)
{
double t;
int i;
struct graph *const g = this->f.o.g;
double const tmin = this->f.min;
double const tmax = this->f.max;
int const steps = this->f.steps == INOVAL ? DEFSTEPS : this->f.steps;
double const step = (tmax - tmin) / (steps - 1);
static char func[FNAMELEN + 30];
strcpy(func, "Can't calculate points for ");
strcat(func, this->f.o.name);
strcat(func, ":");
new_list(&this->f.pts);
if (!create_quick(&this->f.var))
{
if (allow_mes) message(g, func, "Couldn't create variable", (char *)NUL
L);
else alert(g->io.win, func, "Couldn't create variable");
return FALSE;
}
/* Calculate steps points, spread evenly from min to max */
for (i = 0, t = tmin; i < steps; i++, t += step)
{
point_x_y *pt = alloc_node(this->f.sizept);
if (!pt)
{ /* No mem */
free_list(&this->f.pts, this->f.sizept);
free_quick(&this->f.var);
if (allow_mes) message(g, func, "No memory", (char *)NULL);
else alert(g->io.win, func, "No memory");
return FALSE;
}
add_tail(&this->f.pts, pt);
set_quick(&this->f.var, t);
pt->t = t;
pt->p.x = quick_eval(this->x_t);
pt->p.state = (eval_error == 0) ? EXISTS : 0;
if (pt->p.state == EXISTS)
{
pt->p.y = quick_eval(this->y_t);
pt->p.state = (eval_error == 0) ? EXISTS : 0;
}
}
free_quick(&this->f.var);
return TRUE;
}
/* Try to improve look of function by adding points. If fails, decides that
there is a discontinuity */
/* see f_of_x.c for details */
static int improve_x_y(struct x_y *this)
{
struct graph *const g = this->f.o.g;
point_x_y *pt, *next;
int ok = FALSE, iter, abort = FALSE;
double flatx = FLAT * (g->a.y.max - g->a.y.min) / g->io.win->Height;
double flaty = FLAT * (g->a.x.max - g->a.x.min) / g->io.win->Width;
char msg[FNAMELEN + 30];
char pass[20];
struct Requester *req;
struct Region *full = NULL;
/* Flat has no meaning when graph incorrect */
if (!this->f.o.g->ok) flatx = flaty = 0.0;
if (!this->f.calc)
{
strcpy(msg, this->f.o.name);
strcpy(msg, "not calculated!");
message(g, msg, (char *)NULL);
return NULL;
}
if (!this->dx || !this->dy)
{
strcpy(msg, this->f.o.name);
strcat(msg, " wasn't differentiable");
message(g, msg, (char *)NULL);
return NULL;
}
if (!create_quick(&this->f.var))
{
message(g, "Couldn't create variable", (char *)NULL);
return NULL;
}
if (!(req = abort_request(g, "Improve: Pass 1")))
message(g, "No Memory !", (char *)NULL);
else
{
full = full_refresh(this->f.o.g);
for (iter = 1; iter <= MAXITER && !ok && !abort; iter++)
{
sprintf(pass, "Improve: Pass %d", iter);
set_abort_msg(req, pass);
ok = TRUE;
for (pt = first(&this->f.pts); succ(next = succ(pt)); pt = next)
{
if ((pt->p.state & (EXISTS | OK)) == EXISTS) /* Only exists */
{
double dx, dy;
pt->p.state |= OK;
pt->p.state &= ~DISC;
set_quick(&this->f.var, pt->t);
dx = quick_eval(this->dx);
if (eval_error == 0)
{
dy = quick_eval(this->dy);
if (eval_error == 0)
{
double ecartx = next->p.x - pt->p.x;
double errorx = fabs(ecartx - (next->t - pt->t) * d
x);
double ecarty = next->p.y - pt->p.y;
double errory = fabs(ecarty - (next->t - pt->t) * d
y);
/* Check both axes */
if ((errorx > fabs(ecartx) * MAXERROR && (!this->f.
nicedisc || errorx > flatx)) ||
(errory > fabs(ecarty) * MAXERROR && (!this->f.
nicedisc || errory > flaty)))
{
pt->p.state &= ~OK;
ok = FALSE;
if (iter == MAXITER) pt->p.state |= DISC;
else /* cut interval in 2 */
{
point_x_y *newpt = alloc_node(this->f.sizep
t);
if (!newpt)
{
nomem(g->io.win);
abort = TRUE;
break;
}
newpt->t = (pt->t + next->t) / 2;
set_quick(&this->f.var, newpt->t);
newpt->p.x = quick_eval(this->x_t);
newpt->p.state = (eval_error == 0) ? EXISTS
: 0;
if (newpt->p.state == EXISTS)
{
newpt->p.y = quick_eval(this->y_t);
newpt->p.state = (eval_error == 0) ? EX
ISTS : 0;
}
insert(&this->f.pts, newpt, pt);
}
}
}
}
}
}
}
end_abort_request(req);
}
free_quick(&this->f.var);
return full;
}
/* String representation of function */
static char *f2str_x_y(struct x_y *this, char *buf, int maxlen)
{
buf[maxlen - 1] = '\0';
strncpy(buf, this->f.o.name, maxlen - 1);
strncat(buf, ": x(", maxlen - strlen(buf) - 1);
strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
strncat(buf, ")=", maxlen - strlen(buf) - 1);
strncat(buf, this->x, maxlen - strlen(buf) - 1);
strncat(buf, ", y(", maxlen - strlen(buf) - 1);
strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
strncat(buf, ")=", maxlen - strlen(buf) - 1);
strncat(buf, this->y, maxlen - strlen(buf) - 1);
return buf;
}
/* Save local data to file */
static int save_x_y(struct x_y *this, FILE *f)
{
short tag = X_Y_TAG;
short end = X_Y_END;
return WRITE(f, tag) &&
WRITE(f, this->x) &&
WRITE(f, this->y) &&
WRITE(f, end);
}
/* free function */
static struct Region *delete_x_y(struct x_y *this)
{
struct Region *full = full_refresh(this->f.o.g);
destroy_x_y(this);
FreeMem(this, sizeof(struct x_y));
return full;
}
/* Create a new function */
struct x_y *new_x_y(struct graph *g, char *name)
{
struct x_y *this = AllocMem(sizeof(struct x_y), MEMF_CLEAR);
if (this)
{
/* Standard init */
init_function(&this->f, g, name);
/* Local methods */
this->f.o.delete = (void *)delete_x_y;
this->f.o.edit = (void *)edit_x_y;
this->f.o.improve = (void *)improve_x_y;
this->f.o.f2str = (void *)f2str_x_y;
this->f.calcf = (void *)calc_x_y;
this->f.save = (void *)save_x_y;
this->f.sizept = sizeof(point_x_y);
return this;
}
message(g, "Couldn't create function:", "No memory", (char *)NULL);
return NULL;
}
/* load from file */
struct x_y *load_x_y(struct graph *g, FILE *f)
{
struct x_y *this = new_x_y(g, "");
if (this)
{
short end;
/* Read local data */
if (READ(f, this->x) &&
READ(f, this->y) &&
READ(f, end) &&
end == X_Y_END)
{
load_rest(&this->f, f); /* Read standard data */
if (this->f.o.ok = x_y_ok(this)) this->f.o.ok = create_x_y(this);
return this;
}
delete_x_y(this);
}
return NULL;
}