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 / r_of_t.c < prev    next >
C/C++ Source or Header  |  1989-11-20  |  13KB  |  428 lines

  1. /*
  2.  *                 GRAPH, Version 1.00 - 4 August 1989
  3.  *
  4.  *            Copyright 1989, David Gay. All Rights Reserved.
  5.  *            This software is freely redistrubatable.
  6.  */
  7.  
  8. #include <exec/types.h>
  9. #include <intuition/intuition.h>
  10. #include <graphics/text.h>
  11. #include <math.h>
  12. #include <string.h>
  13.  
  14. #include "object.h"
  15. #include "object/function.h"
  16. #include "file.h"
  17. #include "graph.h"
  18. #include "uio.h"
  19. #include "coords.h"
  20. #include "list.h"
  21. #include "grph.h"
  22. #include "user/eval.h"
  23. #include "user/gadgets.h"
  24. #include "tracker.h"
  25.  
  26. #include <proto/exec.h>
  27. #include <proto/intuition.h>
  28. #include <proto/graphics.h>
  29.  
  30. /* (private) class r_of_t, inherits from function */
  31. struct r_of_t {
  32.     struct function f;
  33.     char expr[EXPRLEN];
  34.     value function, derivee;
  35. };
  36.  
  37. /* (private) class, inherits from point */
  38. struct point_r_of_t
  39. {
  40.     point p;
  41.     double r, theta;
  42. };
  43.  
  44. typedef struct point_r_of_t point_r_of_t;
  45.  
  46. /*-------------------------------------------------------------------------*/
  47. /*                      r_of_t class implementation                        */
  48. /*-------------------------------------------------------------------------*/
  49.  
  50. /* Is the function displayable ? */
  51. static int r_of_t_ok(const struct r_of_t *this)
  52. {
  53.     return this->f.min != NOVAL && this->f.max != NOVAL &&
  54.            this->f.min < this->f.max &&
  55.            (this->f.steps == INOVAL || this->f.steps >= 3);
  56. }
  57.  
  58. /* Free resources */
  59. static void destroy_r_of_t(struct r_of_t *this)
  60. {
  61.     free_var_list(&this->f.used);
  62.     if (this->f.calc) free_list(&this->f.pts, this->f.sizept);
  63.     this->f.calc = FALSE;
  64.     if (this->function) free_expr(this->function);
  65.     if (this->derivee) free_expr(this->derivee);
  66.     this->function = this->derivee = NULL;
  67. }
  68.  
  69. /* Init dependant parts of function */
  70. static int create_r_of_t(struct r_of_t *this)
  71. {
  72.     this->f.calc = FALSE;
  73.     this->f.var.name = this->f.vname;
  74.     this->function = compile(this->expr);
  75.     if (eval_error != 0)
  76.     {
  77.         message(this->f.o.g, "Compilation error:", eval_messages[eval_error], (
  78. char *)NULL);
  79.         return FALSE;
  80.     }
  81.     this->derivee = differentiate(this->function, this->f.vname);
  82.     if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  83.     {
  84.         message(this->f.o.g, "Differentiation error:", eval_messages[eval_error
  85. ], (char *)NULL);
  86.         return FALSE;
  87.     }
  88.     if (!make_var_list(this->function, &this->f.used))
  89.         init_var_list(&this->f.used);
  90.     return TRUE;
  91. }
  92.  
  93. /* Allow user to define function */
  94. static int edit_r_of_t(struct r_of_t *this, struct Region **ref)
  95. {
  96.     struct Requester *req;
  97.     struct Memory *m;
  98.     struct Gadget *gl = NULL, *sd, *nd;
  99.     char from[NBLEN], to[NBLEN], steps[INTLEN], expr[EXPRLEN], tname[VARLEN], c
  100. olour[INTLEN];
  101.     int ret = FALSE;
  102.  
  103.     *ref = NULL;
  104.  
  105.     /* Create requester */
  106.     double2str(from, this->f.min);
  107.     double2str(to, this->f.max);
  108.     int2str(steps, this->f.steps);
  109.     int2str(colour, this->f.colour);
  110.     strcpy(expr, this->expr);
  111.     strcpy(tname, this->f.vname);
  112.  
  113.     if ((m = NewMemory()) &&
  114.         (req = InitReq(50, 20, 255, 145, m)) &&
  115.         SetReqBorder(req, 1, m) &&
  116.         AddIntuiText(&req->ReqText, "Function", 95, 6, m) &&
  117.         AddText(&gl, 0, "r(", FALSE, tname, VARLEN, TRUE, 0, RELVERIFY, 25, 20,
  118.  25, 10, TRUE, m) &&
  119.         AddText(&gl, 0, ")=", FALSE, expr, EXPRLEN, TRUE, 0, RELVERIFY, 81, 20,
  120.  160, 10, TRUE, m) &&
  121.         AddText(&gl, 0, "from ", FALSE, from, NBLEN, TRUE, 0, RELVERIFY, 49, 40
  122. , 80, 10, TRUE, m) &&
  123.         AddText(&gl, 0, "to ", FALSE, to, NBLEN, TRUE, 0, RELVERIFY, 167, 40, 8
  124. 0, 10, TRUE, m) &&
  125.         AddText(&gl, 0, "steps ", FALSE, steps, INTLEN, TRUE, 0, RELVERIFY, 57,
  126.  60, 32, 10, TRUE, m) &&
  127.         AddText(&gl, 0, "colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 1
  128. 56, 60, 32, 10, TRUE, m) &&
  129.         (sd = AddOption(&gl, 0, "Show discontinuities", TRUE, this->f.showdisc
  130. * SELECTED, 0, 9, 80, 10, 10, m)) &&
  131.         (nd = AddOption(&gl, 0, "Allow flat discontinuities", TRUE, this->f.nic
  132. edisc * SELECTED, 0, 9, 100, 10, 10, m)) &&
  133.         AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 40, 120, 65, 15, FALS
  134. E, m) &&
  135.         AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 145, 120, 65, 15
  136. , FALSE, m))
  137.     {
  138.         SetReqGadgets(req, gl);
  139.         if (ret = DoRequest(req, this->f.o.g, std_ghandler))
  140.         {
  141.             *ref = full_refresh(this->f.o.g);
  142.  
  143.             /* Extract info */
  144.             this->f.min = str2double(from);
  145.             this->f.max = str2double(to);
  146.             this->f.steps = str2int(steps);
  147.             if ((this->f.colour = str2int(colour)) == INOVAL) this->f.colour =
  148. 1;
  149.             this->f.showdisc = (sd->Flags & SELECTED) != 0;
  150.             this->f.nicedisc = (nd->Flags & SELECTED) != 0;
  151.             strcpy(this->expr, expr);
  152.             strcpy(this->f.vname, tname);
  153.  
  154.             /* Create function */
  155.             destroy_r_of_t(this);
  156.             if (this->f.o.ok = r_of_t_ok(this)) this->f.o.ok = create_r_of_t(th
  157. is);
  158.         }
  159.     }
  160.     Free(m);
  161.  
  162.     return ret;
  163. }
  164.  
  165. /* Calculate points of function */
  166. static int calc_r_of_t(struct r_of_t *this, int allow_mes)
  167. {
  168.     double theta;
  169.     int i;
  170.     struct graph *const g = this->f.o.g;
  171.     int const steps = (this->f.steps == INOVAL ? DEFSTEPS : this->f.steps) - 1;
  172.      
  173.     double const step = (this->f.max - this->f.min) / steps;
  174.     char func[FNAMELEN + 30];
  175.  
  176.     new_list(&this->f.pts);
  177.  
  178.     strcpy(func, "Can't calculate points for ");
  179.     strcat(func, this->f.o.name);
  180.     strcat(func, ":");
  181.  
  182.     if (!create_quick(&this->f.var))
  183.     {
  184.         if (allow_mes) message(g, func, "Couldn't create variable", (char *)NUL
  185. L);
  186.         else alert(g->io.win, func, "Couldn't create variable");
  187.         return FALSE;
  188.     }
  189.  
  190.     /* Calculate steps points, spread evenly from min to max */
  191.     for (i = 0, theta = this->f.min; i <= steps; i++, theta += step)
  192.     {
  193.         point_r_of_t *pt = alloc_node(this->f.sizept);
  194.  
  195.         if (!pt)
  196.         { /* No mem */
  197.             free_list(&this->f.pts, this->f.sizept);
  198.             free_quick(&this->f.var);
  199.             if (allow_mes) message(g, func, "No memory", (char *)NULL);
  200.             else alert(g->io.win, func, "No memory");
  201.             return FALSE;
  202.         }
  203.         add_tail(&this->f.pts, pt);
  204.  
  205.         pt->theta = theta;
  206.         set_quick(&this->f.var, theta);
  207.         pt->r = quick_eval(this->function);
  208.         pt->p.state = (eval_error == 0) ? EXISTS : 0;
  209.         /* Polar -> Rect conversion */
  210.         pt->p.x = fabs(pt->r) * cos(theta); pt->p.y = fabs(pt->r) * sin(theta);
  211.      
  212.     }
  213.     free_quick(&this->f.var);
  214.     return TRUE;
  215. }
  216.  
  217. /* Try to improve look of function by adding points. If fails, decides that
  218.    there is a discontinuity */
  219. /* see f_of_x.c for details */
  220. static struct Region *improve_r_of_t(struct r_of_t *this)
  221. {
  222.     struct graph *const g = this->f.o.g;
  223.     point_r_of_t *pt, *next;
  224.     int ok = FALSE, iter, abort = FALSE;
  225.     double flatx = FLAT * (g->a.y.max - g->a.y.min) / g->io.win->Height;
  226.     double flaty = FLAT * (g->a.x.max - g->a.x.min) / g->io.win->Width;
  227.     char msg[FNAMELEN + 30];
  228.     char pass[20];
  229.     struct Requester *req;
  230.     struct Region *full = NULL;
  231.  
  232.     /* Flat has no meaning when graph incorrect */
  233.     if (!this->f.o.g->ok) flatx = flaty = 0.0;
  234.  
  235.     if (!this->f.calc)
  236.     {
  237.         strcpy(msg, this->f.o.name);
  238.         strcpy(msg, "not calculated!");
  239.         message(g, msg, (char *)NULL);
  240.         return NULL;
  241.     }
  242.     if (!this->derivee)
  243.     {
  244.         strcpy(msg, this->f.o.name);
  245.         strcat(msg, " wasn't differentiable");
  246.         message(g, msg, (char *)NULL);
  247.         return NULL;
  248.     }
  249.     if (!create_quick(&this->f.var))
  250.     {
  251.         message(g, "Couldn't create variable", (char *)NULL);
  252.         return NULL;
  253.     }
  254.  
  255.     if (!(req = abort_request(g, "Improve: Pass 1")))
  256.         message(g, "No Memory !", (char *)NULL);
  257.     else
  258.     {
  259.         full = full_refresh(this->f.o.g);
  260.  
  261.         for (iter = 1; iter <= MAXITER && !ok && !abort; iter++)
  262.         {
  263.             sprintf(pass, "Improve: Pass %d", iter);
  264.             set_abort_msg(req, pass);
  265.             ok = TRUE;
  266.  
  267.             for (pt = first(&this->f.pts); succ(next = succ(pt)); pt = next)
  268.             {
  269.                 if (aborted(req)) { abort = TRUE; break; }
  270.  
  271.                 if ((pt->p.state & (EXISTS | OK)) == EXISTS) /* Only exists */
  272.                 {
  273.                     double dx, dy, dr, dtheta;
  274.  
  275.                     pt->p.state |= OK;
  276.                     pt->p.state &= ~DISC;
  277.  
  278.                     dtheta = next->theta - pt->theta;
  279.                     set_quick(&this->f.var, pt->theta);
  280.                     dr = quick_eval(this->derivee);
  281.                     if (eval_error == 0)
  282.                     {
  283.                         double c = cos(pt->theta);
  284.                         double s = sin(pt->theta);
  285.  
  286.                         /* A little elementary calculus ... */
  287.                         dx = dr * c - pt->r * s;
  288.                         dy = dr * s + pt->r * c;
  289.  
  290.                         if (eval_error == 0)
  291.                         {
  292.                             double ecartx = next->p.x - pt->p.x;
  293.                             double errorx = fabs(ecartx - dtheta * dx);
  294.                             double ecarty = next->p.y - pt->p.y;
  295.                             double errory = fabs(ecarty - dtheta * dy);
  296.  
  297.                             /* Check both axes */
  298.                             if ((errorx > fabs(ecartx) * MAXERROR && (!this->f.
  299. nicedisc || errorx > flatx)) ||
  300.                                 (errory > fabs(ecarty) * MAXERROR && (!this->f.
  301. nicedisc || errory > flaty)))
  302.                             {
  303.                                 pt->p.state &= ~OK;
  304.                                 ok = FALSE;
  305.  
  306.                                 if (iter == MAXITER) pt->p.state |= DISC;
  307.                                 else /* cut interval in 2 */
  308.                                 {
  309.                                     point_r_of_t *newpt = alloc_node(this->f.si
  310. zept);
  311.  
  312.                                     if (!newpt)
  313.                                     {
  314.                                         nomem(g->io.win);
  315.                                         abort = TRUE;
  316.                                         break;
  317.                                     }
  318.  
  319.                                     newpt->theta = (pt->theta + next->theta) /
  320. 2;
  321.                                     set_quick(&this->f.var, newpt->theta);
  322.                                     newpt->r = quick_eval(this->function);
  323.                                     newpt->p.state = (eval_error == 0) ? EXISTS
  324.  : 0;
  325.                                     newpt->p.x = fabs(newpt->r) * cos(newpt->th
  326. eta);
  327.                                     newpt->p.y = fabs(newpt->r) * sin(newpt->th
  328. eta);
  329.                                     insert(&this->f.pts, newpt, pt);
  330.                                 }
  331.                             }
  332.                         }
  333.                     }
  334.                 }
  335.             }
  336.         }
  337.         end_abort_request(req);
  338.     }
  339.     free_quick(&this->f.var);
  340.     return full;
  341. }
  342.  
  343. /* String representation of function */
  344. static char *f2str_r_of_t(struct r_of_t *this, char *buf, int maxlen)
  345. {
  346.     buf[maxlen - 1] = '\0';
  347.     strncpy(buf, "polar ", maxlen - 1);
  348.     strncat(buf, this->f.o.name, maxlen - strlen(buf) - 1);
  349.     strncat(buf, "(", maxlen - strlen(buf) - 1);
  350.     strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  351.     strncat(buf, ")=", maxlen - strlen(buf) - 1);
  352.     strncat(buf, this->expr, maxlen - strlen(buf) - 1);
  353.  
  354.     return buf;
  355. }
  356.  
  357. static int save_r_of_t(struct r_of_t *this, FILE *f)
  358. {
  359.     short tag = R_OF_T_TAG;
  360.     short end = R_OF_T_END;
  361.  
  362.     return WRITE(f, tag) &&
  363.            WRITE(f, this->expr) &&
  364.            WRITE(f, end);
  365. }
  366.  
  367. /* free function */
  368. static struct Region *delete_r_of_t(struct r_of_t *this)
  369. {
  370.     struct Region *full = full_refresh(this->f.o.g);
  371.  
  372.     destroy_r_of_t(this);
  373.     FreeMem(this, sizeof(struct r_of_t));
  374.  
  375.     return full;
  376. }
  377.  
  378. /* Create a new function */
  379. struct r_of_t *new_r_of_t(struct graph *g, char *name)
  380. {
  381.     struct r_of_t *this = AllocMem(sizeof(struct r_of_t), MEMF_CLEAR);
  382.  
  383.     if (this)
  384.     {
  385.         /* Standard init */
  386.         init_function(&this->f, g, name);
  387.         /* Local methods */
  388.         this->f.o.delete = (void *)delete_r_of_t;
  389.         this->f.o.edit = (void *)edit_r_of_t;
  390.         this->f.o.improve = (void *)improve_r_of_t;
  391.         this->f.o.f2str = (void *)f2str_r_of_t;
  392.         this->f.calcf = (void *)calc_r_of_t;
  393.         this->f.save = (void *)save_r_of_t;
  394.         this->f.sizept = sizeof(point_r_of_t);
  395.         init_var_list(&this->f.used);
  396.         return this;
  397.     }
  398.     message(g, "Couldn't create function:", "No memory", (char *)NULL);
  399.     return NULL;
  400. }
  401.  
  402. /* Save local data to file */
  403. /* load from file */
  404. struct r_of_t *load_r_of_t(struct graph *g, FILE *f)
  405. {
  406.     struct r_of_t *this = new_r_of_t(g, "");
  407.  
  408.     if (this)
  409.     {
  410.         short end;
  411.  
  412.         /* Read local data */
  413.         if (READ(f, this->expr) &&
  414.             READ(f, end) &&
  415.             end == R_OF_T_END)
  416.         {
  417.             load_rest(&this->f, f); /* Read standard data */
  418.             if (this->f.o.ok = r_of_t_ok(this)) this->f.o.ok = create_r_of_t(th
  419. is);
  420.  
  421.             return this;
  422.         }
  423.         delete_r_of_t(this);
  424.     }
  425.     return NULL;
  426. }
  427.  
  428.