/* * GRAPH, Version 1.00 - 4 August 1989 * * Copyright 1989, David Gay. All Rights Reserved. * This software is freely redistrubatable. */ /* The default/non virtual methods for class function */ #include #include #include #include #include #include "object.h" #include "object/default.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 #include #include /* Draw a function */ void display_function(struct function *this) { int up; point *pt; struct RWindow *const rwin = this->o.g->io.rw; int pen = this->selected ? (this->colour == 3 ? 2 : 3) : this->colour; up = TRUE; SetAPen(rwin->rp, pen); SetDrMd(rwin->rp, JAM1); /* Scan points (note that all types of function points have point as base c lass) */ for (pt = first(&this->pts); succ(pt); pt = succ(pt)) { if (pt->state & EXISTS) { if (up) RMove(rwin, pt->x, pt->y); else RDraw(rwin, pt->x, pt->y); up = this->showdisc && (pt->state & DISC); } else up = TRUE; } } /* Select function, redraw in new colour */ static void select_function(struct function *this) { this->selected = TRUE; if (this->o.ok && this->o.g->ok && this->o.g->io.rw && this->calc) display_function(this); } /* Deselect function */ static struct Region *deselect_function(struct function *this) { this->selected = FALSE; if (this->o.ok && this->o.g->ok && this->o.g->io.rw && this->calc) display_function(this); return NULL; /* No refresh needed */ } /* Did user press mouse on function ? */ static int down_function(struct function *this) { int inside = FALSE; if (this->o.ok && this->calc) { struct graph *g = this->o.g; point *pt; long sx = ftol(g->io.rw->sx(g->io.rw, g->s.x)); long sy = ftol(g->io.rw->sy(g->io.rw, g->s.y)); long x0, y0, x1, y1; int up = TRUE; /* Check if mouse "near" drawn line */ for (pt = first(&this->pts); succ(pt); pt = succ(pt)) { if (pt->state & EXISTS) { x1 = ftol(g->io.rw->sx(g->io.rw, pt->x)); y1 = ftol(g->io.rw->sy(g->io.rw, pt->y)); if (!up) /* segment exists, calc distance to it */ { /* A little vectorial algebra */ long ab_x, ab_y, u_x, u_y, h, hd, dist_x, dist_y, dist; ab_x = sx - x0; ab_y = sy - y0; u_x = x1 - x0; u_y = y1 - y0; h = (ab_x * u_x + ab_y * u_y); hd = (u_x * u_x + u_y * u_y); if (hd != 0 && 0 <= h && h <= hd) /* intersection on segmen t */ { dist_x = (hd * ab_x - h * u_x) / hd; dist_y = (hd * ab_ y - h * u_y) / hd; dist = dist_x * dist_x + dist_y * dist_y; if (dist < (FDIST * FDIST)) { /* We're near segment ! */ inside = TRUE; break; } } /* Near point ? */ else if ((x1 - sx) * (x1 - sx) + (y1 - sy) * (y1 - sy) <= F DIST * FDIST) { inside = TRUE; break; } } up = this->showdisc && (pt->state & DISC); x0 = x1; y0 = y1; } else up = TRUE; } } return inside; } /* Impossible ... */ static void move_function(struct function *this) { } /* Nothing to do */ static struct Region *up_function(struct function *this) { return NULL; } /* redraw function, calc if necessary */ static void draw_function(struct function *this, int allow_mes) { if (!this->calc) this->calc = this->calcf(this, allow_mes); if (this->calc) display_function(this); } /* variable name changed. recalc necessary ? */ static void var_change_function(struct function *this, char *name) { if (this->calc && FindName(&this->used, name)) { free_list(&this->pts, this->sizept); this->calc = FALSE; } } /* Write function to file */ static int save_function(struct function *this, FILE *f) { short tag = FUNCTION_TAG; short end = FUNCTION_END; short showdisc = this->showdisc; /* Can't write bitfields directly ... */ short nicedisc = this->nicedisc; return WRITE(f, tag) && this->save(this, f) && /* Easier than rewriting this for each fun ction */ WRITE(f, this->o.name) && WRITE(f, this->vname) && WRITE(f, this->min) && WRITE(f, this->max) && WRITE(f, this->steps) && WRITE(f, this->colour) && WRITE(f, showdisc) && WRITE(f, nicedisc) && WRITE(f, end); } /* Read a function from a file */ struct function *load_function(struct graph *g, FILE *f) { short tag; struct function *this; if (READ(f, tag)) /* Determine which type of function */ switch (tag) { case F_OF_X_TAG: this = (struct function *)load_f_of_x(g, f); break; case X_Y_TAG: this = (struct function *)load_x_y(g, f); break; case R_OF_T_TAG: this = (struct function *)load_r_of_t(g, f); break; case R_T_TAG: this = (struct function *)load_r_t(g, f); break; default: message(g, "Not a graph file", (char *)NULL); } return this; } /* Read "standard" part of function from file */ int load_rest(struct function *this, FILE *f) { short showdisc, nicedisc, end; if (READ(f, this->o.name) && READ(f, this->vname) && READ(f, this->min) && READ(f, this->max) && READ(f, this->steps) && READ(f, this->colour) && READ(f, showdisc) && /* Can't read bitfields directly */ READ(f, nicedisc) && READ(f, end) && end == FUNCTION_END) { this->showdisc = showdisc; this->nicedisc = nicedisc; return TRUE; } return FALSE; } /* Nothing to do (don't care about resolution) */ static int inform_function(struct function *this) { return TRUE; } /* idem */ static void confirm_function(struct object *this, int ok) { } /* Standard function init */ void init_function(struct function *this, struct graph *g, char *name) { const static struct function def_f = { { { NULL }, NULL, "", FALSE, 0, 0, /* Default methods */ (void *)uncalled, (void *)select_function, (void *)deselect_functio n, (void *)down_function, (void *)move_function, (void *)up_function, (void *)uncalled, (void *)draw_function, (void *)ref_uncalled, (void *)uncalled, (void *)var_change_function, (void *)save_functio n, (void *)inform_function, (void *)confirm_function }, (void *)uncalled, (void *)uncalled, "", NOVAL, NOVAL, INOVAL, 1, TRUE, TRUE, FALSE, FALSE }; *this = def_f; this->o.g = g; strcpy(this->o.name, name); init_var_list(&this->used); } /* Create a new function (ask user which type he wants) */ struct function *new_function(struct graph *g) { struct Requester *req; struct Memory *m; struct Gadget *gl = NULL, *fx, *xy, *rt, *r2; char name[FNAMELEN]; int ret = FALSE; struct function *o = NULL; name[0] = '\0'; if ((m = NewMemory()) && (req = InitReq(50, 20, 230, 105, m)) && SetReqBorder(req, 1, m) && AddIntuiText(&req->ReqText, "Add Function", 67, 6, m) && AddText(&gl, 0, "Name ", FALSE, name, FNAMELEN, TRUE, 0, RELVERIFY, 51, 20, 100, 10, TRUE, m) && (fx = AddRadio(&gl, 0, "f(x)", TRUE, SELECTED, RELVERIFY, 28, 11, 40, 1 0, 10, m)) && (rt = AddRadio(&gl, 0, "r(theta)", TRUE, 0, RELVERIFY, 26, 105, 40, 10, 10, m)) && (xy = AddRadio(&gl, 0, "x(t),y(t)", TRUE, 0, RELVERIFY, 22, 11, 60, 10, 10, m)) && (r2 = AddRadio(&gl, 0, "r(t),theta(t)", TRUE, 0, RELVERIFY, 14, 105, 60 , 10, 10, m)) && AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 25, 80, 65, 15, FALSE , m) && AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 140, 80, 65, 15, FALSE, m)) { SetReqGadgets(req, gl); if (ret = DoRequest(req, g, std_ghandler)) { strip(name); if (*name) { if (fx->Flags & SELECTED) o = (struct function *)new_f_of_x(g, name); else if (xy->Flags & SELECTED) o = (struct function *)new_x_y(g , name); else if (rt->Flags & SELECTED) o = (struct function *)new_r_of_ t(g, name); else o = (struct function *)new_r_t(g, name); } else message(g, "Blank names not allowed", (char *)NULL); } } Free(m); return o; }