home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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>
-
- /* (private) class r_t, inherits from function */
- struct r_t {
- struct function f;
- char r[EXPRLEN], theta[EXPRLEN];
- value r_t, theta_t, dr, dtheta;
- };
-
- /* (private) class, inherits from point */
- struct point_r_t {
- point p;
- double r, theta, t;
- };
-
- typedef struct point_r_t point_r_t;
-
- /*-------------------------------------------------------------------------*/
- /* r_t class implementation */
- /*-------------------------------------------------------------------------*/
-
- /* Is the function displayable ? */
- static int r_t_ok(const struct r_t *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_r_t(struct r_t *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->r_t) free_expr(this->r_t);
- if (this->dr) free_expr(this->dr);
- if (this->theta_t) free_expr(this->theta_t);
- if (this->dtheta) free_expr(this->dtheta);
- this->theta_t = this->r_t = this->dtheta = this->dr = NULL;
- }
-
- /* Init dependant parts of function */
- static int create_r_t(struct r_t *this)
- {
- this->f.calc = FALSE;
- this->f.var.name = this->f.vname;
- this->r_t = compile(this->r);
- if (eval_error != 0)
- {
- message(this->f.o.g, "Compilation error in x(t):", eval_messages[eval_e
- rror], (char *)NULL);
- return FALSE;
- }
- this->dr = differentiate(this->r_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->theta_t = compile(this->theta);
- if (eval_error != 0)
- {
- message(this->f.o.g, "Compilation error in y(t):", eval_messages[eval_e
- rror], (char *)NULL);
- return FALSE;
- }
- this->dtheta = differentiate(this->theta_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->r_t, &this->f.used) || !make_var_list(this->theta_
- t, &this->f.used))
- init_var_list(&this->f.used);
- return TRUE;
- }
-
- /* Allow user to define function */
- static int edit_r_t(struct r_t *this, struct Region **ref)
- {
- struct Requester *req;
- struct Memory *m;
- struct Gadget *gl = NULL, *sd, *nd;
- char from[NBLEN], to[NBLEN], steps[INTLEN], r[EXPRLEN], theta[EXPRLEN], tna
- me[VARLEN], 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(r, this->r);
- strcpy(theta, this->theta);
- 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, "r(", FALSE, tname, VARLEN, TRUE, 0, RELVERIFY, 27, 20,
- 24, 10, TRUE, m) &&
- AddText(&gl, 0, ")=", FALSE, r, EXPRLEN, TRUE, 0, RELVERIFY, 75, 20, 16
- 0, 10, TRUE, m) &&
- AddText(&gl, 0, "theta()=", FALSE, theta, EXPRLEN, TRUE, 0, RELVERIFY,
- 75, 40, 160, 10, TRUE, m) &&
- AddText(&gl, 0, "from ", FALSE, from, NBLEN, TRUE, 0, RELVERIFY, 51, 60
- , 80, 10, TRUE, m) &&
- AddText(&gl, 0, "to ", FALSE, to, NBLEN, TRUE, 0, RELVERIFY, 169, 60, 8
- 0, 10, TRUE, m) &&
- AddText(&gl, 0, "steps ", FALSE, steps, INTLEN, TRUE, 0, RELVERIFY, 59,
- 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, 11, 100, 10, 10, m)) &&
- (nd = AddOption(&gl, 0, "Allow flat discontinuities", TRUE, this->f.nic
- edisc * SELECTED, 0, 11, 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->r, r);
- strcpy(this->theta, theta);
- strcpy(this->f.vname, tname);
-
- /* Create function */
- destroy_r_t(this);
- if (this->f.o.ok = r_t_ok(this)) this->f.o.ok = create_r_t(this);
- }
- }
- Free(m);
-
- return ret;
- }
-
- /* Calculate points of function */
- static int calc_r_t(struct r_t *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_r_t *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->r = quick_eval(this->r_t);
- pt->p.state = (eval_error == 0) ? EXISTS : 0;
- if (pt->p.state == EXISTS)
- {
- pt->theta = quick_eval(this->theta_t);
- pt->p.state = (eval_error == 0) ? EXISTS : 0;
- /* Polar -> Rect conversion */
- pt->p.x = fabs(pt->r) * cos(pt->theta);
- pt->p.y = fabs(pt->r) * sin(pt->theta);
- }
- }
- 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 struct Region *improve_r_t(struct r_t *this)
- {
- struct graph *const g = this->f.o.g;
- point_r_t *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->dr || !this->dtheta)
- {
- 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 dr, dtheta, dt;
-
- pt->p.state |= OK;
- pt->p.state &= ~DISC;
-
- dt = next->t - pt->t;
- set_quick(&this->f.var, pt->t);
- dr = quick_eval(this->dr);
- if (eval_error == 0)
- {
- dtheta = quick_eval(this->dtheta);
- if (eval_error == 0)
- {
- double c = cos(pt->theta);
- double s = sin(pt->theta);
- /* A little elementary calculus ... */
- double dx = dr * c - pt->r * dtheta * s;
- double dy = dr * s + pt->r * dtheta * c;
- double ecartx = next->p.x - pt->p.x;
- double errorx = fabs(ecartx - dt * dx);
- double ecarty = next->p.y - pt->p.y;
- double errory = fabs(ecarty - dt * dy);
-
- /* 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_r_t *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->r = quick_eval(this->r_t);
- newpt->p.state = (eval_error == 0) ? EXISTS
- : 0;
- if (newpt->p.state == EXISTS)
- {
- newpt->theta = quick_eval(this->theta_t
- );
- newpt->p.state = (eval_error == 0) ? EX
- ISTS : 0;
- newpt->p.x = fabs(newpt->r) * cos(newpt
- ->theta);
- newpt->p.y = fabs(newpt->r) * sin(newpt
- ->theta);
- }
- insert(&this->f.pts, newpt, pt);
- }
- }
- }
- }
- }
- }
- }
- end_abort_request(req);
- }
- free_quick(&this->f.var);
- return full;
- }
-
- /* String representation of function */
- static char *f2str_r_t(struct r_t *this, char *buf, int maxlen)
- {
- buf[maxlen - 1] = '\0';
- strncpy(buf, this->f.o.name, maxlen - 1);
- strncat(buf, ": r(", maxlen - strlen(buf) - 1);
- strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
- strncat(buf, ")=", maxlen - strlen(buf) - 1);
- strncat(buf, this->r, maxlen - strlen(buf) - 1);
- strncat(buf, ", theta(", maxlen - strlen(buf) - 1);
- strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
- strncat(buf, ")=", maxlen - strlen(buf) - 1);
- strncat(buf, this->theta, maxlen - strlen(buf) - 1);
-
- return buf;
- }
-
- /* Save local data to file */
- static int save_r_t(struct r_t *this, FILE *f)
- {
- short tag = R_T_TAG;
- short end = R_T_END;
-
- return WRITE(f, tag) &&
- WRITE(f, this->r) &&
- WRITE(f, this->theta) &&
- WRITE(f, end);
- }
-
- /* free function */
- static struct Region *delete_r_t(struct r_t *this)
- {
- struct Region *full = full_refresh(this->f.o.g);
-
- destroy_r_t(this);
- FreeMem(this, sizeof(struct r_t));
-
- return full;
- }
-
- /* Create a new function */
- struct r_t *new_r_t(struct graph *g, char *name)
- {
- struct r_t *this = AllocMem(sizeof(struct r_t), MEMF_CLEAR);
-
- if (this)
- {
- /* Standard init */
- init_function(&this->f, g, name);
- /* Local methods */
- this->f.o.delete = (void *)delete_r_t;
- this->f.o.edit = (void *)edit_r_t;
- this->f.o.improve = (void *)improve_r_t;
- this->f.o.f2str = (void *)f2str_r_t;
- this->f.calcf = (void *)calc_r_t;
- this->f.save = (void *)save_r_t;
- this->f.sizept = sizeof(point_r_t);
- return this;
- }
- message(g, "Couldn't create function:", "No memory", (char *)NULL);
- return NULL;
- }
-
- /* load from file */
- struct r_t *load_r_t(struct graph *g, FILE *f)
- {
- struct r_t *this = new_r_t(g, "");
-
- if (this)
- {
- short end;
-
- /* Read local data */
- if (READ(f, this->r) &&
- READ(f, this->theta) &&
- READ(f, end) &&
- end == R_T_END)
- {
- load_rest(&this->f, f); /* Read standard data */
- if (this->f.o.ok = r_t_ok(this)) this->f.o.ok = create_r_t(this);
-
- return this;
- }
- delete_r_t(this);
- }
- return NULL;
- }
-
-