home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Graphics / Gnuplot / Source / Status.m < prev    next >
Encoding:
Text File  |  1993-03-18  |  37.8 KB  |  1,914 lines

  1.  
  2. static char RCSId[] = "$Id: Status.m,v 1.1.1.1 1993/03/18 03:35:28 davis Exp $";
  3.  
  4.  
  5. #import <appkit/Font.h>
  6. #import <appkit/nextstd.h>    /* NX_FREE            */
  7.  
  8. #import <objc/hashtable.h>    /* NXCopyStringBufferFromZone()    */
  9. #import <objc/zone.h>
  10.  
  11. #import <setjmp.h>        /* setjmp()             */
  12. #import <stdio.h>
  13. #import <stdlib.h>
  14. #import <strings.h>        /* strcat(), strcpy(), index()    */
  15.  
  16. #import "FunctionObject.h"
  17. #import "GnuplotPlot.h"
  18. #import "Status.h"
  19. #import "TicObject.h"
  20.  
  21.  
  22. @interface Status (Private)
  23.  
  24. - (const char *) _copyString:(const char *)source to:(char **)dest;
  25. - _doText:(const char *)theText;
  26. - _setText:(const char *) aString;
  27.  
  28. @end
  29.  
  30.  
  31. /* 
  32.  *  We can't import all of plot.h because of various complications 
  33.  *  (redefinitions, conflicting identifiers, etc.), but we need the 
  34.  *  following structures which are defined there.
  35.  */
  36. struct ticdef {
  37.     int type;                /* one of three constants    */
  38.     union {
  39.            struct {            /* for TIC_SERIES        */
  40.                   double start, incr;
  41.                   double end;
  42.           } series;
  43.            struct ticmark *user;    /* for TIC_USER            */
  44.        } def;
  45. };
  46.  
  47. struct ticmark {
  48.     double position;            /* where on axis is this    */
  49.     char *label;            /* optional string label    */
  50.     struct ticmark *next;        /* linked list            */
  51. };
  52.  
  53.  
  54.  
  55. /* 
  56.  *  The class records which Status object was the last to issue a plot 
  57.  *  command to Gnuplot.  We need to know this when we set our instance 
  58.  *  variables to the corresponding Gnuplot values -- see -grabCurrent.
  59.  */
  60. static id lastplot = nil;
  61.  
  62. #define MAX_LINE_LEN 1024    /* Same as in plot.h    */
  63. #define DEFAULT_FONT        "Helvetica"
  64.  
  65. #define CONTOUR_NONE     0       /* Where to place contour maps if at all. */
  66. #define CONTOUR_BASE     1
  67. #define CONTOUR_SRF      2
  68. #define CONTOUR_BOTH     3
  69.  
  70.  
  71. /*
  72.  *  All instance variables begin with s_ to avoid confusion with the 
  73.  *  variables defined in gnuplot .c files.
  74.  *
  75.  *  gnuplot Variable (setshow.c)       Status Instance Variable
  76.  *  ----------------------------       ------------------------
  77.  */
  78. extern char nextfe_font[];        /* s_font            */
  79. extern int nextfe_fontsize;        /* s_fontsize            */
  80. extern char title[];            /* s_title            */
  81. extern char xlabel[];            /* s_labelCoord[]        */
  82. extern char ylabel[];
  83. extern char zlabel[];
  84. extern char dummy_var[][51];        /* s_dummy_var[]        */
  85. extern int parametric;            /* s_parametric            */
  86. extern int polar;            /* s_polar            */
  87. extern int draw_border;            /* s_border            */
  88. extern int draw_surface;        /* s_draw_surface        */
  89. extern int draw_contour;
  90. extern int contour_kind;        /* s_contour_kind        */
  91. extern int contour_pts;            /* s_contour_pts        */
  92. extern int contour_order;        /* s_contour_order        */
  93. extern int label_contours;        /* s_label_contours        */
  94. extern int grid;            /* s_grid            */
  95. extern int xzeroaxis;            /* s_xzeroaxis            */
  96. extern int yzeroaxis;            /* s_yzeroaxis            */
  97. extern int tic_in;            /* s_tics_in            */
  98. extern int xtics, ytics, ztics;        /* s_ticsCoord[]        */
  99. extern struct ticdef xticdef;        /* s_ticdefCoord[]        */
  100. extern struct ticdef yticdef;
  101. extern struct ticdef zticdef;
  102. extern int is_log_x, is_log_y, is_log_z;/* s_isLogCoord[]        */
  103.  
  104. extern double base_log_x, base_log_y,    /* Currently unused by Status    */
  105.           base_log_z;        //
  106. extern double log_base_log_x,
  107.           log_base_log_y,
  108.           log_base_log_z;
  109.  
  110.  
  111. extern int key;                /* s_key            */
  112. extern double key_x, key_y, key_z;    /* s_keyCoord[]            */
  113. extern int timedate;            /* s_time            */
  114. extern int time_xoffset, time_yoffset;    /* s_timeCoord[]        */
  115. extern float xsize, ysize;        /* s_xsize, s_ysize        */
  116. extern float surface_rot_x;        /* s_rot_x            */
  117. extern float surface_rot_z;        /* s_rot_z            */
  118. extern int hidden3d;            /* s_hidden3d            */
  119. extern int autoscale_x;            /* s_autoscaleCoord[]        */
  120. extern int autoscale_y;
  121. extern int autoscale_z;
  122. extern int autoscale_r;
  123. extern double xmin, xmax;        /* s_minCoord[], s_maxCoord[]    */
  124. extern double ymin, ymax;
  125. extern double zmin, zmax;
  126. extern double rmin, rmax;
  127. extern int angles_format;        /* degrees            */
  128. extern int samples;            /* s_samples            */
  129. extern int samples_1;            /* s_samplesCoord        */
  130. extern int samples_2;
  131. extern int iso_samples_1;        /* s_iso_samplesCoord        */
  132. extern int iso_samples_2;
  133. extern char replot_line[];        /* s_plotargs            */
  134. extern NXStream *EPSStream;        /* s_epsStream (terminal)    */
  135. extern int nextfe_halve;        /* (GnuplotPlot preference)    */
  136. extern NEXTFE_reset();            /* Appends PS Trailer to stream    */
  137.  
  138.  
  139. /*
  140.  *  Removes leading blanks and tabs.
  141.  */
  142. static char *_removeLeadingBlanks (char *aString)
  143. {
  144.     char *cur;
  145.  
  146.     cur = aString;
  147.     if (cur && ((*cur == ' ') || (*cur == '\t')))
  148.         cur++;
  149.  
  150.     strcpy (aString, cur);
  151.     return aString;
  152. }
  153.  
  154.  
  155. /*
  156.  *  Stores the first line, up to max characters,  from the multi-line 
  157.  *  string source in dest and returns a pointer to it.  It replaces 
  158.  *  the newline with a null character.  If the line was the last in 
  159.  *  the string, it returns NULL.
  160.  */
  161. static char *_get_line (char *dest, int max, const char *source)
  162. {
  163.     char *returnVal = dest;
  164.  
  165.     if (source && dest)  {
  166.     while ((*source != '\n') && (*source != '\0') && (max > 0)) {
  167.         *dest = *source;
  168.         dest++;
  169.         source++;
  170.         max--;
  171.     }
  172.  
  173.     *dest = '\0';
  174.  
  175.     if (*source == '\n')
  176.         return returnVal;
  177.     }                    /*  NULL is returned if line is    */
  178.                     /*  too long or end of source    */
  179.     return NULL;            /*  or dest string is reached.    */
  180. }
  181.     
  182.  
  183. /* 
  184.  *  Frees the list of ticmarks whose head is pointed to by t and sets 
  185.  *  t to NULL.
  186.  */
  187. static void _freeLinkedList(struct ticmark **t)
  188. {
  189.     struct ticmark *cur;
  190.  
  191.     while (*t) {
  192.     cur = *t;
  193.     *t = (*t)->next;
  194.     free (cur);
  195.     }
  196.  
  197.     *t = NULL;
  198.     return;
  199. }
  200.  
  201.  
  202. @implementation Status
  203.  
  204. + lastplot
  205. {
  206.     return lastplot;
  207. }
  208.  
  209.  
  210. + setHalvePlot:(BOOL)condition
  211. {
  212.     nextfe_halve = condition;
  213.     return self;
  214. }
  215.  
  216.  
  217. - init
  218. {
  219.     int counter;
  220.  
  221.     [super init];
  222.     zone = [self zone];
  223.  
  224.     functions = nil;
  225.  
  226.     delegate = nil;
  227.     report = YES;
  228.  
  229.     s_epsStream = NULL;
  230.  
  231.     /* 
  232.      *  Set all pointers to NULL or nil so -resetCurrent
  233.      *  doesn't try to free them.
  234.      */
  235.     text = s_title = s_plotargs = s_font = appendix =
  236.     s_dummy_var[0] = s_dummy_var[1] = NULL;
  237.  
  238.     for (counter = 0 ; counter < 3 ; counter++) {
  239.     s_labelCoord[counter] = NULL;
  240.     ticDefs[counter] = nil;
  241.     }
  242.  
  243.     [self resetCurrent];
  244.  
  245.     return self;
  246. }
  247.  
  248.  
  249. - free
  250. {
  251.     int counter;
  252.  
  253.     if (s_epsStream)
  254.     NXCloseMemory (s_epsStream, NX_FREEBUFFER);
  255.  
  256.     /*  
  257.      *  NXZoneFree() doesn't bomb if you give it a NULL pointer, so we 
  258.      *  don't bother to check the pointer.
  259.      */
  260.  
  261.     NXZoneFree (zone, text);
  262.     NXZoneFree (zone, appendix);
  263.  
  264.     NXZoneFree (zone, s_title);
  265.     NXZoneFree (zone, s_font);
  266.  
  267.     NXZoneFree (zone, s_dummy_var[0]);
  268.     NXZoneFree (zone, s_dummy_var[1]);
  269.  
  270.     for (counter = 0 ; counter < 3 ; counter++) {
  271.     if (ticDefs[counter])
  272.         [[ticDefs[counter] freeObjects] free];
  273.     NXZoneFree (zone, s_labelCoord[counter]);
  274.     }
  275.  
  276.     NXZoneFree (zone, s_plotargs);
  277.  
  278.     if (functions)
  279.     [[functions freeObjects] free];
  280.  
  281.     lastplot = nil;
  282.  
  283.     return [super free];
  284. }
  285.  
  286.  
  287. - setReport:(BOOL)cond
  288. {
  289.     report = cond;
  290.     return self;
  291. }
  292.  
  293.  
  294. - (BOOL)report
  295. {
  296.     return report;
  297. }
  298.  
  299.  
  300. - setDelegate: anObject
  301. {
  302.     delegate = anObject;
  303.     return self;
  304. }
  305.  
  306.  
  307. - delegate
  308. {
  309.     return delegate;
  310. }
  311.  
  312.  
  313. - (NXStream *)stream
  314. {
  315.     return s_epsStream;
  316. }
  317.  
  318.  
  319.  
  320. - (BOOL)canPlot
  321. {
  322.     int count = 0, index;
  323.     int total = [functions count];
  324.  
  325.     /* Count the number of functions */
  326.     index = total;
  327.     while (index--)
  328.     count += ([[functions objectAt:index] isDataFile]) ? 0 : 1;
  329.  
  330.     /* 
  331.      *  We can plot iff
  332.      * 
  333.      *         1) there is an appendix
  334.      *         
  335.      *             or
  336.      *             
  337.      *         2) there is at least one FunctionObject and
  338.      *         3) if the plot is parametric then
  339.      *             a) we have pairs of functions (two-dimensional),
  340.      *             b) or we have triplets of functions (3-dimens.)
  341.      *
  342.      */
  343.     
  344.     return ((appendix && *appendix) ||
  345.         (total && 
  346.          (s_parametric? (isThreeD? !(count % 3)
  347.                      : (!(count % 2) && (total == count)))
  348.               :YES)));
  349.  
  350. }
  351.  
  352.  
  353. - plot
  354. {
  355.     [self applyCurrent];
  356.     lastplot = self;
  357.  
  358.     if (areSettingsEdited && !appendix)  {
  359.     [self buildPlotargs];
  360.     [self _setText:s_plotargs];
  361.  
  362.     areSettingsEdited = NO;
  363.     }
  364.  
  365.     if (appendix && *appendix)
  366.     [self _setText:appendix];    /* Appendix overrides current plot */
  367.  
  368.     return [self _doText:text];
  369. }
  370.  
  371.  
  372.  
  373. - saveToFile:(const char *)filename
  374. {
  375.     char *copy, *line, *cur;
  376.     id returnVal;
  377.  
  378.     /* 
  379.      *  Gnuplot sometimes drops characters off the end of long 
  380.      *  pathnames given to the "save" command, a bug that seems to 
  381.      *  have been introduced between 3.1 and 3.2.  We work around it 
  382.      *  by cd'ing to the directory first and then saving the file.
  383.      */
  384.     copy = NXCopyStringBufferFromZone (filename, zone);
  385.  
  386.     if (cur = rindex (copy, '/')) {
  387.     *(cur++) = '\0';
  388.     line = NXZoneMalloc (zone, 15 + strlen (filename));
  389.     sprintf (line, "cd '%s'\nsave '%s'\n", copy, cur);
  390.     } else {
  391.     line = NXZoneMalloc (zone, 9 + strlen (filename));
  392.     sprintf (line, "save '%s'\n", filename);
  393.     }
  394.  
  395.     returnVal = [self _doText:line]? self : nil;
  396.     NXZoneFree (zone, copy);
  397.     NXZoneFree (zone, line);
  398.  
  399.     return returnVal;
  400. }
  401.  
  402.  
  403.  
  404. - reportSettingsChange:sender
  405. {
  406.     areSettingsEdited = YES;
  407.     lastplot = nil;        /* Last valid plot is no longer valid */
  408.  
  409.     if (delegate && report)
  410.     [delegate settingsDidChange:self];
  411.  
  412.     return self;
  413. }
  414.  
  415.  
  416.  
  417. /* 
  418.  *  Resets all the instance variables to their default values.
  419.  */
  420. - resetCurrent
  421. {
  422.     int counter;
  423.  
  424.     if (functions)
  425.     [functions freeObjects];
  426.     else
  427.     functions = [[List allocFromZone:zone] init];
  428.  
  429.     NXZoneFree (zone, text);
  430.     text = NULL;
  431.  
  432.     NXZoneFree (zone, s_title);
  433.     s_title = NULL;
  434.  
  435.     NXZoneFree (zone, s_dummy_var[0]);
  436.     s_dummy_var[0] = NULL;
  437.  
  438.     NXZoneFree (zone, s_dummy_var[1]);
  439.     s_dummy_var[1] = NULL;
  440.  
  441.     for (counter = 0 ; counter < 3 ; counter++)  {
  442.     NXZoneFree (zone, s_labelCoord[counter]);
  443.     s_labelCoord[counter] = NULL;
  444.     s_minCoord[counter] = -10.0;
  445.     s_maxCoord[counter] = 10.0;
  446.     s_isLogCoord[counter] = 0;
  447.     s_ticsCoord[counter] = 1;
  448.     s_ticTypeCoord[counter] = TIC_COMPUTED;
  449.     s_ticSeriesCoord[counter].start = -10.0;
  450.     s_ticSeriesCoord[counter].incr = 5.0;
  451.     s_ticSeriesCoord[counter].end = 10.0;
  452.     if (ticDefs[counter])
  453.         [ticDefs[counter] freeObjects];
  454.     else
  455.         ticDefs[counter] = [[DoubleValueSortedList allocFromZone:zone]
  456.                                init];
  457.     }
  458.  
  459.     s_minCoord[R_TAG] = -0.0;    /* Gnuplot uses -0.0, not sure why    */
  460.     s_maxCoord[R_TAG] = 10.0;
  461.  
  462.     degrees = NO;
  463.  
  464.     NXZoneFree (zone, s_plotargs);
  465.     s_plotargs = NULL;
  466.  
  467.     NXZoneFree (zone, s_font);
  468.     s_font = NULL;
  469.  
  470.     NXZoneFree (zone, appendix);
  471.     appendix = NULL;
  472.  
  473.     s_fontsize = 16;
  474.  
  475.     isThreeD = NO;
  476.     s_parametric = NO;
  477.     s_polar = NO;
  478.     s_border = YES;
  479.     s_draw_surface = YES;
  480.     contourBase = NO;
  481.     contourSurface = NO;
  482.     s_contour_kind = CONTOUR_KIND_LINEAR;
  483.     s_contour_pts = 5;
  484.     s_contour_order = 4;
  485.     s_label_contours = YES;
  486.     s_hidden3d = NO;
  487.     s_grid = NO;
  488.     s_xzeroaxis = YES;
  489.     s_yzeroaxis = YES;
  490.  
  491.     s_tics_in = YES;
  492.  
  493.     s_key = YES;        /* Plot has a key, in default location    */
  494.     s_key_default = YES;
  495.  
  496.     s_time = NO;        /* Don't show time/date            */
  497.     s_time_default = YES;
  498.  
  499.     for (counter = 0 ; counter < 4 ; counter++)
  500.     s_autoscaleCoord[counter] = 1;
  501.  
  502.     sizeProp = YES;    /* Keep x, y, z proportional */
  503.     s_xsize = s_ysize = 1.0;
  504.     s_samples = s_samplesCoord[X_TAG] = s_samplesCoord[Y_TAG] = 100;
  505.     s_iso_samplesCoord[X_TAG] = s_iso_samplesCoord[Y_TAG] = 10;
  506.  
  507.     s_rotCoord[X_TAG] = 60.0;
  508.     s_rotCoord[Z_TAG] = 30.0;
  509.  
  510.     areSettingsEdited = NO;
  511.  
  512.     return self;
  513. }
  514.  
  515.  
  516.  
  517.  
  518.  
  519. /*  Sets the current gnuplot settings to the Status instance variables.  */
  520. - applyCurrent
  521. {
  522.     if (s_font)
  523.     strcpy (nextfe_font, s_font);
  524.     else
  525.     strcpy (nextfe_font, DEFAULT_FONT);
  526.  
  527.     nextfe_fontsize = s_fontsize;
  528.  
  529.     if (s_title)
  530.     strcpy (title, s_title);
  531.     else
  532.     strcpy (title, "");
  533.  
  534.     if (s_dummy_var[0])
  535.     strcpy (dummy_var[0], s_dummy_var[0]);
  536.     else
  537.     strcpy (dummy_var[0], "x");
  538.  
  539.     if (s_dummy_var[1])
  540.     strcpy (dummy_var[1], s_dummy_var[1]);
  541.     else
  542.     strcpy (dummy_var[1], "y");
  543.  
  544.     if (s_labelCoord[X_TAG])
  545.     strcpy (xlabel, s_labelCoord[X_TAG]);
  546.     else
  547.     strcpy (xlabel, "");
  548.  
  549.     if (s_labelCoord[Y_TAG])
  550.     strcpy (ylabel, s_labelCoord[Y_TAG]);
  551.     else
  552.     strcpy (ylabel, "");
  553.  
  554.     if (s_labelCoord[Z_TAG])
  555.     strcpy (zlabel, s_labelCoord[Z_TAG]);
  556.     else
  557.     strcpy (zlabel, "");
  558.  
  559.     parametric = s_parametric;
  560.     polar = s_polar;
  561.     draw_border = s_border;
  562.     draw_surface = s_draw_surface;
  563.  
  564.     if (!contourBase && !contourSurface)
  565.     draw_contour = CONTOUR_NONE;
  566.     else if (contourBase && contourSurface)
  567.     draw_contour = CONTOUR_BOTH;
  568.     else if (contourBase)
  569.     draw_contour = CONTOUR_BASE;
  570.     else if (contourSurface)
  571.     draw_contour = CONTOUR_SRF;
  572.  
  573.     contour_kind = s_contour_kind;
  574.     contour_pts = s_contour_pts;
  575.     contour_order = s_contour_order;
  576.     label_contours = s_label_contours;
  577.  
  578.     hidden3d = s_hidden3d;
  579.     grid = s_grid;
  580.     xzeroaxis = s_xzeroaxis;
  581.     yzeroaxis = s_yzeroaxis;
  582.  
  583.     tic_in = s_tics_in;
  584.     xtics = s_ticsCoord[X_TAG];
  585.     ytics = s_ticsCoord[Y_TAG];
  586.     ztics = s_ticsCoord[Z_TAG];
  587.     [self applyCurrentTicDefs];
  588.  
  589.     is_log_x = s_isLogCoord[X_TAG];
  590.     is_log_y = s_isLogCoord[Y_TAG];
  591.     is_log_z = s_isLogCoord[Z_TAG];
  592.  
  593.     base_log_x = base_log_y = base_log_z = 10.0;
  594.     log_base_log_x = log_base_log_y = log_base_log_z = log(10.0);
  595.  
  596.     autoscale_x = s_autoscaleCoord[X_TAG];
  597.     autoscale_y = s_autoscaleCoord[Y_TAG];
  598.     autoscale_z = s_autoscaleCoord[Z_TAG];
  599.     autoscale_r = s_autoscaleCoord[R_TAG];
  600.  
  601.     xmin = s_minCoord[X_TAG];
  602.     xmax = s_maxCoord[X_TAG];
  603.     ymin = s_minCoord[Y_TAG];
  604.     ymax = s_maxCoord[Y_TAG];
  605.     zmin = s_minCoord[Z_TAG];
  606.     zmax = s_maxCoord[Z_TAG];
  607.     rmin = s_minCoord[R_TAG];
  608.     rmax = s_maxCoord[R_TAG];
  609.  
  610.     angles_format = degrees? ANGLES_DEGREES :ANGLES_RADIANS;
  611.  
  612.     key = s_key? (s_key_default? -1 :1) :0;
  613.     key_x = s_keyCoord[X_TAG];
  614.     key_y = s_keyCoord[Y_TAG];
  615.     key_z = s_keyCoord[Z_TAG];
  616.  
  617.     timedate = s_time? 1 :0;
  618.     if (s_time && !(s_title && *s_title))
  619.     strcpy (title, " ");    // Kludge to make time visible if no title
  620.     time_xoffset = (s_time_default? 0 :s_timeCoord[X_TAG]);
  621.     time_yoffset = (s_time_default? 0 :s_timeCoord[Y_TAG]);
  622.  
  623.     xsize = s_xsize;
  624.     ysize = s_ysize;
  625.  
  626.     surface_rot_x = s_rotCoord[X_TAG];
  627.     surface_rot_z = s_rotCoord[Z_TAG];
  628.  
  629.     samples = s_samples;
  630.     samples_1 = s_samplesCoord[X_TAG];
  631.     samples_2 = s_samplesCoord[Y_TAG];
  632.     iso_samples_1 = s_iso_samplesCoord[X_TAG];
  633.     iso_samples_2 = s_iso_samplesCoord[Y_TAG];
  634.  
  635.     return self;
  636. }
  637.  
  638.  
  639.  
  640. - applyCurrentTicDefs
  641. {
  642.     int count;
  643.     struct ticmark *new;
  644.     id tic;
  645.  
  646.     switch (s_ticTypeCoord[X_TAG]) {
  647.     case TIC_SERIES:
  648.     xticdef.def.series.start = s_ticSeriesCoord[X_TAG].start;
  649.     xticdef.def.series.incr = s_ticSeriesCoord[X_TAG].incr;
  650.     xticdef.def.series.end = s_ticSeriesCoord[X_TAG].end;
  651.     break;
  652.     case TIC_USER:
  653.     if (xticdef.type == TIC_USER)
  654.         _freeLinkedList (&(xticdef.def.user));
  655.     else
  656.         xticdef.def.user = NULL;
  657.     if ((count = [ticDefs[X_TAG] count] - 1) >= 0) {
  658.         new = xticdef.def.user = malloc (sizeof (struct ticmark));
  659.         while (count >= 0) {
  660.         new->position = [tic = [ticDefs[X_TAG] objectAt:count]
  661.                  doubleValue];
  662.         new->label = (char *) [tic stringValue];
  663.         if (count--) {
  664.             new->next = malloc (sizeof (struct ticmark));
  665.             new = new->next;
  666.         } else
  667.             new->next = NULL;
  668.         }
  669.         break;
  670.     }
  671.     }
  672.     xticdef.type = s_ticTypeCoord[X_TAG];
  673.  
  674.     switch (s_ticTypeCoord[Y_TAG]) {
  675.     case TIC_SERIES:
  676.     yticdef.def.series.start = s_ticSeriesCoord[Y_TAG].start;
  677.     yticdef.def.series.incr = s_ticSeriesCoord[Y_TAG].incr;
  678.     yticdef.def.series.end = s_ticSeriesCoord[Y_TAG].end;
  679.     break;
  680.     case TIC_USER:
  681.     if (yticdef.type == TIC_USER)
  682.         _freeLinkedList (&(yticdef.def.user));
  683.     else
  684.         yticdef.def.user = NULL;
  685.     if ((count = [ticDefs[Y_TAG] count] - 1) >= 0) {
  686.         new = yticdef.def.user = malloc (sizeof (struct ticmark));
  687.         while (count >= 0) {
  688.         new->position = [tic = [ticDefs[Y_TAG] objectAt:count] 
  689.                  doubleValue];
  690.         new->label = (char *) [tic stringValue];
  691.         if (count--) {
  692.             new->next = malloc (sizeof (struct ticmark));
  693.             new = new->next;
  694.         } else
  695.             new->next = NULL;
  696.         }
  697.         break;
  698.     }
  699.     }
  700.     yticdef.type = s_ticTypeCoord[Y_TAG];
  701.  
  702.     switch (s_ticTypeCoord[Z_TAG]) {
  703.     case TIC_SERIES:
  704.     zticdef.def.series.start = s_ticSeriesCoord[Z_TAG].start;
  705.     zticdef.def.series.incr = s_ticSeriesCoord[Z_TAG].incr;
  706.     zticdef.def.series.end = s_ticSeriesCoord[Z_TAG].end;
  707.     break;
  708.     case TIC_USER:
  709.     if (zticdef.type == TIC_USER)
  710.         _freeLinkedList (&(zticdef.def.user));
  711.     else
  712.         zticdef.def.user = NULL;
  713.     if ((count = [ticDefs[Z_TAG] count] - 1) >= 0) {
  714.         new = zticdef.def.user = malloc (sizeof (struct ticmark));
  715.         while (count >= 0) {
  716.         new->position = [tic = [ticDefs[Z_TAG] objectAt:count]
  717.                  doubleValue];
  718.         new->label = (char *) [tic stringValue];
  719.         if (count--) {
  720.             new->next = malloc (sizeof (struct ticmark));
  721.             new = new->next;
  722.         } else
  723.             new->next = NULL;
  724.         }
  725.         break;
  726.     }
  727.  
  728.     }
  729.     zticdef.type = s_ticTypeCoord[Z_TAG];
  730.  
  731.     return self;
  732. }
  733.  
  734.  
  735. /* 
  736.  *  Resets all the instance variables to the current gnuplot settings, 
  737.  *  all of which pertain to the most recent plot:
  738.  */
  739. - grabCurrent
  740. {
  741.     char *cur;
  742.  
  743.     NXZoneFree (zone, s_font);
  744.     s_font = NXCopyStringBufferFromZone (nextfe_font, zone);
  745.  
  746.     s_fontsize = nextfe_fontsize;
  747.  
  748.     NXZoneFree (zone, s_title);
  749.     s_title = NXCopyStringBufferFromZone (title, zone);
  750.  
  751.     NXZoneFree (zone, s_dummy_var[0]);
  752.     s_dummy_var[0] = NXCopyStringBufferFromZone (dummy_var[0], zone);
  753.  
  754.     NXZoneFree (zone, s_dummy_var[1]);
  755.     s_dummy_var[1] = NXCopyStringBufferFromZone (dummy_var[1], zone);
  756.  
  757.     NXZoneFree (zone, s_labelCoord[X_TAG]);
  758.     s_labelCoord[X_TAG] = NXCopyStringBufferFromZone (xlabel, zone);
  759.  
  760.     NXZoneFree (zone, s_labelCoord[Y_TAG]);
  761.     s_labelCoord[Y_TAG] = NXCopyStringBufferFromZone (ylabel, zone);
  762.  
  763.     NXZoneFree (zone, s_labelCoord[Z_TAG]);
  764.     s_labelCoord[Z_TAG] = NXCopyStringBufferFromZone (zlabel, zone);
  765.  
  766.     [self grabCurrentTicDefs];
  767.  
  768.     /*  
  769.      *  If the last plot command was "splot," as opposed to "plot,"  
  770.      *  it is three dimensional.
  771.      */
  772.     isThreeD = (*(_removeLeadingBlanks(replot_line)) == 's');
  773.  
  774.     s_parametric = parametric;
  775.     s_polar = polar;
  776.     s_border = draw_border;
  777.     s_draw_surface = draw_surface;
  778.  
  779.     switch (draw_surface) {
  780.     case CONTOUR_NONE:
  781.     contourBase = contourSurface = NO;
  782.     break;
  783.     case CONTOUR_BASE:
  784.     contourBase = YES;
  785.     contourSurface = NO;
  786.     break;
  787.     case CONTOUR_SRF:
  788.     contourBase = NO;
  789.     contourSurface = YES;
  790.     break;
  791.     default:
  792.     contourBase = YES;
  793.     contourSurface = YES;
  794.     break;
  795.     }
  796.  
  797.     s_contour_kind = contour_kind;
  798.     s_contour_pts = contour_pts;
  799.     s_contour_order = contour_order;
  800.     s_label_contours = label_contours;
  801.  
  802.     s_hidden3d = hidden3d;
  803.     s_grid = grid;
  804.     s_xzeroaxis = xzeroaxis;
  805.     s_yzeroaxis = yzeroaxis;
  806.  
  807.     s_tics_in = tic_in;
  808.     s_ticsCoord[X_TAG] = xtics;
  809.     s_ticsCoord[Y_TAG] = ytics;
  810.     s_ticsCoord[Z_TAG] = ztics;
  811.  
  812.     s_isLogCoord[X_TAG] = is_log_x;
  813.     s_isLogCoord[Y_TAG] = is_log_y;
  814.     s_isLogCoord[Z_TAG] = is_log_z;
  815.  
  816.     s_autoscaleCoord[X_TAG] = autoscale_x;
  817.     s_autoscaleCoord[Y_TAG] = autoscale_y;
  818.     s_autoscaleCoord[Z_TAG] = autoscale_z;
  819.     s_autoscaleCoord[R_TAG] = autoscale_r;
  820.  
  821.     s_minCoord[X_TAG] = xmin;
  822.     s_maxCoord[X_TAG] = xmax;
  823.     s_minCoord[Y_TAG] = ymin;
  824.     s_maxCoord[Y_TAG] = ymax;
  825.     s_minCoord[Z_TAG] = zmin;
  826.     s_maxCoord[Z_TAG] = zmax;
  827.     s_minCoord[R_TAG] = rmin;
  828.     s_maxCoord[R_TAG] = rmax;
  829.  
  830.     degrees = (angles_format == ANGLES_DEGREES);
  831.  
  832.     s_key = ((key == -1) || (key == 1));
  833.     s_key_default = (key == -1);
  834.     s_keyCoord[X_TAG] = key_x;
  835.     s_keyCoord[Y_TAG] = key_y;
  836.     s_keyCoord[Z_TAG] = key_z;
  837.  
  838.     s_time = timedate;
  839.     s_time_default = (time_xoffset == 0.0) && (time_yoffset == 0.0);
  840.     s_timeCoord[X_TAG] = time_xoffset;
  841.     s_timeCoord[Y_TAG] = time_yoffset;
  842.  
  843.     s_xsize = xsize;
  844.     s_ysize = ysize;
  845.  
  846.     s_samples = samples;
  847.     s_samplesCoord[X_TAG] = samples_1;
  848.     s_samplesCoord[Y_TAG] = samples_2;
  849.     s_iso_samplesCoord[X_TAG] = iso_samples_1;
  850.     s_iso_samplesCoord[Y_TAG] = iso_samples_2;
  851.  
  852.     s_rotCoord[X_TAG] = surface_rot_x;
  853.     s_rotCoord[Z_TAG] = surface_rot_z;
  854.  
  855.     NXZoneFree (zone, s_plotargs);
  856.     if (cur = index (replot_line, ' ')) {    /* todo What about tabs? */
  857.     s_plotargs = NXZoneMalloc (zone, strlen (replot_line) + 1);
  858.     strcpy (s_plotargs, cur + 1);
  859.     } else
  860.     s_plotargs = NULL;
  861.  
  862.     /* Break plotargs into separate functions */
  863.     [self grabFunctionsFrom:s_plotargs];
  864.     [self buildPlotargs];
  865.  
  866.     [self _setText: s_plotargs];
  867.     areSettingsEdited = YES;
  868.  
  869.     return self;
  870. }
  871.  
  872.  
  873. - grabCurrentTicDefs
  874. {
  875.     int count, i;
  876.     struct ticmark *cur;
  877.     id tic;
  878.  
  879.     switch (s_ticTypeCoord[X_TAG] = xticdef.type) {
  880.     case TIC_SERIES:
  881.     s_ticSeriesCoord[X_TAG].start = xticdef.def.series.start;
  882.     s_ticSeriesCoord[X_TAG].incr = xticdef.def.series.incr;
  883.     s_ticSeriesCoord[X_TAG].end = xticdef.def.series.end;
  884.     break;
  885.     case TIC_USER:
  886.     count = [ticDefs[X_TAG] count] - 1;
  887.     i = 0;
  888.     for (cur = xticdef.def.user ; cur != NULL ; cur = cur->next) {
  889.         if (i <= count) {
  890.         [tic = [ticDefs[X_TAG] objectAt:i]
  891.                       setDoubleValue:cur->position];
  892.         [tic setStringValue:cur->label];
  893.         } else {
  894.         [ticDefs[X_TAG] addObject:[[TicObject allocFromZone:zone]
  895.                         initFromString:cur->label
  896.                            doubleValue:cur->position]];
  897.         }
  898.         i++;
  899.     }
  900.     break;
  901.     }
  902.  
  903.     switch (s_ticTypeCoord[Y_TAG] = yticdef.type) {
  904.     case TIC_SERIES:
  905.     s_ticSeriesCoord[Y_TAG].start = yticdef.def.series.start;
  906.     s_ticSeriesCoord[Y_TAG].incr = yticdef.def.series.incr;
  907.     s_ticSeriesCoord[Y_TAG].end = yticdef.def.series.end;
  908.     break;
  909.     case TIC_USER:
  910.     count = [ticDefs[Y_TAG] count] - 1;
  911.     i = 0;
  912.     for (cur = yticdef.def.user ; cur != NULL ; cur = cur->next) {
  913.         if (i <= count) {
  914.         [tic = [ticDefs[Y_TAG] objectAt:i]
  915.                setDoubleValue:cur->position];
  916.         [tic setStringValue:cur->label];
  917.         } else {
  918.         [ticDefs[Y_TAG] addObject:[[TicObject allocFromZone:zone]
  919.                         initFromString:cur->label
  920.                            doubleValue:cur->position]];
  921.         }
  922.         i++;
  923.     }
  924.     break;
  925.     }
  926.  
  927.     switch (s_ticTypeCoord[Z_TAG] = zticdef.type) {
  928.     case TIC_SERIES:
  929.     s_ticSeriesCoord[Z_TAG].start = zticdef.def.series.start;
  930.     s_ticSeriesCoord[Z_TAG].incr = zticdef.def.series.incr;
  931.     s_ticSeriesCoord[Z_TAG].end = zticdef.def.series.end;
  932.     break;
  933.     case TIC_USER:
  934.     count = [ticDefs[Z_TAG] count] - 1;
  935.     i = 0;
  936.     for (cur = zticdef.def.user ; cur != NULL ; cur = cur->next) {
  937.         if (i <= count) {
  938.         [tic = [ticDefs[Z_TAG] objectAt:i]
  939.              setDoubleValue:cur->position];
  940.         [tic setStringValue:cur->label];
  941.         } else {
  942.         [ticDefs[Z_TAG] addObject:[[TicObject allocFromZone:zone]
  943.                    initFromString:cur->label 
  944.                   doubleValue:cur->position]];
  945.         }
  946.         i++;
  947.     }
  948.     break;
  949.     }
  950.  
  951.  
  952.  
  953.     return self;
  954. }
  955.  
  956.  
  957. /*  
  958.  *  We use a list of FunctionObjects to store each function (a 
  959.  *  "function" is a mathematical expression that gnuplot will evaluate 
  960.  *  at certain points or a data file containing pairs/triples of 
  961.  *  numbers on each line).  We create these objects by parsing the 
  962.  *  plot arguments.
  963.  */
  964. - grabFunctionsFrom: (char *) aString
  965. {
  966.     int count;
  967.     FunctionObject *aFunction;
  968.     char *src, *end;
  969.     BOOL done;
  970.  
  971.     if ([functions count])
  972.     [functions freeObjects];
  973.  
  974.     if (!aString)
  975.     return nil;
  976.  
  977.     /* Skip any range specifications */
  978.     if (src = rindex (aString, ']'))
  979.     aString = src + 1;
  980.  
  981.     /* Count the functions */
  982.     count = 1;
  983.     src = aString;
  984.     while (src = index(src, ','))  {
  985.     count ++;
  986.     src++;
  987.     }
  988.  
  989.     /* Copy them to the strings list */
  990.  
  991.     src = aString;
  992.     done = NO;
  993.     while (!done)  {
  994.     if (end = index (src, ','))
  995.         *end = '\0';
  996.     else
  997.         done = YES;
  998.  
  999.     aFunction = [[FunctionObject allocFromZone:zone]
  1000.          initFromString: _removeLeadingBlanks (src)];
  1001.     [functions addObject:aFunction];
  1002.  
  1003.     if (!done) {
  1004.         *end = ',';
  1005.         src = ++end;
  1006.     }
  1007.     }
  1008.  
  1009.     return self;
  1010. }
  1011.  
  1012.  
  1013.  
  1014.  
  1015. - setThreeD:(BOOL) aCondition
  1016. {
  1017.  
  1018.     if (isThreeD != aCondition)  {
  1019.  
  1020.     isThreeD = aCondition;
  1021.  
  1022.     if (s_parametric) {
  1023.         if (isThreeD) {
  1024.         [self _copyString:"u" to:&(s_dummy_var[X_TAG])];
  1025.         [self _copyString:"v" to:&(s_dummy_var[Y_TAG])];
  1026.         } else
  1027.         [self _copyString:"t" to:&(s_dummy_var[X_TAG])];
  1028.     }
  1029.  
  1030.     [self reportSettingsChange:self];
  1031.     }
  1032.     return self;
  1033. }
  1034.  
  1035.  
  1036. - (BOOL) isThreeD
  1037. {
  1038.     return isThreeD;
  1039. }
  1040.  
  1041.  
  1042.  
  1043. - setParametric:(BOOL) cond
  1044. {
  1045.     if (s_parametric != cond)  {
  1046.  
  1047.     s_parametric = cond;
  1048.  
  1049.     if (cond) {
  1050.         if (isThreeD) {
  1051.         [self _copyString:"u" to:&(s_dummy_var[X_TAG])];
  1052.         [self _copyString:"v" to:&(s_dummy_var[Y_TAG])];
  1053.         } else
  1054.         [self _copyString:"t" to:&(s_dummy_var[X_TAG])];
  1055.     } else {
  1056.         [self _copyString:"x" to:&(s_dummy_var[X_TAG])];
  1057.         [self _copyString:"y" to:&(s_dummy_var[Y_TAG])];
  1058.     }
  1059.  
  1060.     [self reportSettingsChange:self];
  1061.  
  1062.     }
  1063.     return self;
  1064. }
  1065.  
  1066.  
  1067. - (BOOL) parametric
  1068. {
  1069.     return s_parametric;
  1070. }
  1071.  
  1072.  
  1073.  
  1074. - setPolar:(BOOL) cond
  1075. {
  1076.     if (s_polar != cond) {
  1077.     s_polar = cond;
  1078.  
  1079.     if (cond) {
  1080.         s_minCoord[X_TAG] = 0;
  1081.         s_maxCoord[X_TAG] = degrees? 360 :6.283186;
  1082.         s_isLogCoord[X_TAG] = 0;
  1083.     } else {
  1084.         s_minCoord[X_TAG] = -10.0;
  1085.         s_maxCoord[X_TAG] = 10.0;
  1086.     }
  1087.     [self reportSettingsChange:self];
  1088.     }
  1089.  
  1090.     return self;
  1091. }
  1092.  
  1093.  
  1094. - (BOOL) isPolar
  1095. {
  1096.     return s_polar;
  1097. }
  1098.  
  1099.  
  1100.  
  1101. - setBorder:(BOOL) cond
  1102. {
  1103.     if (s_border != cond) {
  1104.     s_border = cond;
  1105.     [self reportSettingsChange:self];
  1106.     }
  1107.  
  1108.     return self;
  1109. }
  1110.  
  1111.  
  1112. - (BOOL) border
  1113. {
  1114.     return s_border;
  1115. }
  1116.  
  1117.  
  1118.  
  1119. - setSurface:(BOOL) cond
  1120. {
  1121.     if (s_draw_surface != cond) {
  1122.     s_draw_surface = cond;
  1123.     [self reportSettingsChange:self];
  1124.     }
  1125.  
  1126.     return self;
  1127. }
  1128.  
  1129.  
  1130. - (BOOL) surface
  1131. {
  1132.     return s_draw_surface;
  1133. }
  1134.  
  1135.  
  1136.  
  1137. - setHiddenThreeD:(BOOL) cond
  1138. {
  1139.     if (s_hidden3d != cond) {
  1140.     s_hidden3d = cond;
  1141.     [self reportSettingsChange:self];
  1142.     }
  1143.  
  1144.     return self;
  1145. }
  1146.  
  1147.  
  1148. - (BOOL) hiddenThreeD
  1149. {
  1150.     return s_hidden3d;
  1151. }
  1152.  
  1153.  
  1154.  
  1155. - setGrid:(BOOL) cond
  1156. {
  1157.     if (s_grid != cond) {
  1158.     s_grid = cond;
  1159.     [self reportSettingsChange:self];
  1160.     }
  1161.  
  1162.     return self;
  1163. }
  1164.  
  1165.  
  1166. - (BOOL) grid
  1167. {
  1168.     return s_grid;
  1169. }
  1170.  
  1171.  
  1172.  
  1173. - setAxisX:(int) anInt
  1174. {
  1175.     if (s_xzeroaxis != anInt) {
  1176.     s_xzeroaxis = anInt;
  1177.     [self reportSettingsChange:self];
  1178.     }
  1179.  
  1180.     return self;
  1181. }
  1182.  
  1183.  
  1184. - (int) axisX
  1185. {
  1186.     return s_xzeroaxis;
  1187. }
  1188.  
  1189.  
  1190.  
  1191. - setAxisY:(int) anInt
  1192. {
  1193.     if (s_yzeroaxis != anInt) {
  1194.     s_yzeroaxis = anInt;
  1195.     [self reportSettingsChange:self];
  1196.     }
  1197.  
  1198.     return self;
  1199. }
  1200.  
  1201.  
  1202. - (int) axisY
  1203. {
  1204.     return s_yzeroaxis;
  1205. }
  1206.  
  1207.  
  1208.  
  1209. - setIsLogCoord:(int)coord isOn:(BOOL)isOn
  1210. {
  1211.     if (s_isLogCoord[coord] != isOn) {
  1212.     s_isLogCoord[coord] = isOn;
  1213.     [self reportSettingsChange:self];
  1214.     }
  1215.     return self;
  1216. }
  1217.  
  1218.  
  1219.  
  1220. - (BOOL) isLogCoord:(int)coord
  1221. {
  1222.     return s_isLogCoord[coord];
  1223. }
  1224.  
  1225.  
  1226.  
  1227. - setTitle:(const char *) aString
  1228. {
  1229.     [self _copyString:aString to:&s_title];
  1230.     [self reportSettingsChange:self];
  1231.  
  1232.     return self;
  1233. }
  1234.  
  1235.  
  1236. - (const char *) title
  1237. {
  1238.     return s_title;
  1239. }
  1240.  
  1241.  
  1242. - setLabelCoord:(int)coord to:(const char *) aString
  1243. {
  1244.     [self _copyString:aString to:&(s_labelCoord[coord])];
  1245.     [self reportSettingsChange:self];
  1246.  
  1247.     return self;
  1248. }
  1249.  
  1250.  
  1251.  
  1252. - (const char *) labelCoord:(int) coord
  1253. {
  1254.     return s_labelCoord[coord];
  1255. }
  1256.  
  1257.  
  1258. - setDummyVar:(int)coord to:(const char *)aString
  1259. {
  1260.     [self _copyString:aString to:&(s_dummy_var[coord])];
  1261.     [self reportSettingsChange:self];
  1262.     return self;
  1263. }
  1264.  
  1265.  
  1266. - (const char *)dummyVar:(int)coord
  1267. {
  1268.     if (!s_dummy_var[coord])
  1269.     switch (coord) {
  1270.     case X_TAG:
  1271.         return "x";
  1272.         break;
  1273.     case Y_TAG:
  1274.         return "y";
  1275.         break;
  1276.     }
  1277.  
  1278.     return s_dummy_var[coord];
  1279. }
  1280.  
  1281.  
  1282. - setAppendix: (const char *) aString
  1283. {
  1284.     NXZoneFree (zone, appendix);
  1285.  
  1286.     if (aString)
  1287.     appendix = NXCopyStringBufferFromZone (aString, zone);
  1288.     else
  1289.     appendix = NULL;
  1290.  
  1291.     return self;
  1292. }
  1293.  
  1294.  
  1295. - setFontsize: (int) anInt;
  1296. {
  1297.     if ((s_fontsize != anInt) && (anInt > 0)) {
  1298.     s_fontsize = anInt;
  1299.     [self reportSettingsChange:self];
  1300.     return self;
  1301.     } else
  1302.     return nil;
  1303. }
  1304.  
  1305.  
  1306. - (int) fontsize
  1307. {
  1308.     return s_fontsize;
  1309. }
  1310.  
  1311.  
  1312.  
  1313. - setFontname: (const char *) aString
  1314. {
  1315.     [self _copyString:aString to:&s_font];
  1316.     [self reportSettingsChange:self];
  1317.  
  1318.     return self;
  1319. }
  1320.  
  1321.  
  1322. - (const char *) fontname
  1323. {
  1324.     return s_font;
  1325. }
  1326.  
  1327.  
  1328.  
  1329. - setFont:aFont
  1330. {
  1331.     if (aFont)  {
  1332.     [self _copyString:[aFont name] to:&s_font];
  1333.     s_fontsize = [aFont pointSize];
  1334.     [self reportSettingsChange:self];
  1335.     }
  1336.  
  1337.     return self;
  1338. }
  1339.  
  1340.  
  1341.  
  1342. - font
  1343. {
  1344.     if (!s_font)
  1345.     return [Font newFont:DEFAULT_FONT size:s_fontsize];
  1346.     return [Font newFont:s_font size:s_fontsize];
  1347. }
  1348.  
  1349.  
  1350.  
  1351. - setKey:(BOOL) cond
  1352. {
  1353.     if (s_key != cond) {
  1354.     s_key = cond;
  1355.     [self reportSettingsChange:self];
  1356.     }
  1357.  
  1358.     return self;
  1359. }
  1360.  
  1361.  
  1362.  
  1363. - (BOOL) key
  1364. {
  1365.     return s_key;
  1366. }
  1367.  
  1368.  
  1369. - setKeyDefault:(BOOL) cond
  1370. {
  1371.     if (s_key_default != cond) {
  1372.     s_key_default = cond;
  1373.     [self reportSettingsChange:self];
  1374.     }
  1375.  
  1376.     return self;
  1377. }
  1378.  
  1379.  
  1380.  
  1381. - (BOOL) keyDefault
  1382. {
  1383.     return s_key_default;
  1384. }
  1385.  
  1386.  
  1387. - setKeyCoord:(int)coord to:(double)aDouble
  1388. {
  1389.     if (s_keyCoord[coord] != aDouble) {
  1390.     s_keyCoord[coord] = aDouble;
  1391.     [self reportSettingsChange:self];
  1392.     }
  1393.     return self;
  1394. }
  1395.  
  1396.  
  1397. - (double) keyCoord:(int)coord
  1398. {
  1399.     return s_keyCoord[coord];
  1400. }
  1401.  
  1402.  
  1403.  
  1404. - setTime:(BOOL) cond
  1405. {
  1406.     if (s_time != cond) {
  1407.     s_time = cond;
  1408.     [self reportSettingsChange:self];
  1409.     }
  1410.  
  1411.     return self;
  1412. }
  1413.  
  1414.  
  1415.  
  1416. - (BOOL) time
  1417. {
  1418.     return s_time;
  1419. }
  1420.  
  1421.  
  1422. - setTimeDefault:(BOOL) cond
  1423. {
  1424.     if (s_time_default != cond) {
  1425.     s_time_default = cond;
  1426.     [self reportSettingsChange:self];
  1427.     }
  1428.  
  1429.     return self;
  1430. }
  1431.  
  1432.  
  1433.  
  1434. - (BOOL) timeDefault
  1435. {
  1436.     return s_time_default;
  1437. }
  1438.  
  1439.  
  1440. - setTimeCoord:(int)coord to:(int)aDouble
  1441. {
  1442.     if (s_timeCoord[coord] != aDouble) {
  1443.     s_timeCoord[coord] = aDouble;
  1444.     [self reportSettingsChange:self];
  1445.     }
  1446.     return self;
  1447. }
  1448.  
  1449.  
  1450. - (int) timeCoord:(int)coord
  1451. {
  1452.     return s_timeCoord[coord];
  1453. }
  1454.  
  1455.  
  1456.  
  1457. - setSizeProp:(BOOL) cond
  1458. {
  1459.     sizeProp = cond;        /* Don't do anything, just record status */
  1460.     return self;
  1461. }
  1462.  
  1463.  
  1464. - (BOOL)sizeProp
  1465. {
  1466.     return sizeProp;
  1467. }
  1468.  
  1469.  
  1470. /*
  1471.  *  Size of zero means don't change... (e.g. if x=2 and y=0, we change 
  1472.  *  x but not y).
  1473.  */
  1474. - setSizeX:(float) xFloat Y:(float) yFloat
  1475. {
  1476.     if ((xFloat != s_xsize) || (yFloat != s_ysize)) {
  1477.  
  1478.     if (xFloat)
  1479.         s_xsize = xFloat;
  1480.  
  1481.     if (yFloat)
  1482.         s_ysize = yFloat;
  1483.  
  1484.     [self reportSettingsChange:self];
  1485.     }
  1486.  
  1487.     return self;
  1488. }
  1489.  
  1490.  
  1491. - (float) sizeX
  1492. {
  1493.     return s_xsize;
  1494. }
  1495.  
  1496.  
  1497. - (float) sizeY
  1498. {
  1499.     return s_ysize;
  1500. }
  1501.  
  1502.  
  1503.  
  1504. - setRotCoord:(int)coord to:(float)aFloat
  1505. {
  1506.     if (s_rotCoord[coord] != aFloat) {
  1507.     s_rotCoord[coord] = aFloat;
  1508.     [self reportSettingsChange:self];
  1509.     }
  1510.     return self;
  1511. }
  1512.  
  1513.  
  1514.  
  1515. - resetRotation
  1516. {
  1517.     s_rotCoord[X_TAG] = 60.0;
  1518.     s_rotCoord[Z_TAG] = 30.0;
  1519.     [self reportSettingsChange:self];
  1520.     return self;
  1521. }
  1522.  
  1523.  
  1524.  
  1525. - (float)rotCoord:(int)coord
  1526. {
  1527.     return s_rotCoord[coord];
  1528. }
  1529.  
  1530.  
  1531.  
  1532. - setSamplesCoord:(int)coord to:(int)anInt
  1533. {
  1534.     if ((anInt > 0) && (anInt != s_samplesCoord[coord])) {
  1535.     s_samplesCoord[coord] = anInt;
  1536.     if (coord == X_TAG)
  1537.         s_samples = anInt;
  1538.     } else
  1539.     return nil;
  1540.  
  1541.     [self reportSettingsChange:self];
  1542.     return self;
  1543. }
  1544.  
  1545.  
  1546. - (int) samples:(int)coord
  1547. {
  1548.     return s_samplesCoord[coord];
  1549. }
  1550.  
  1551.  
  1552.  
  1553. - setIsoSamplesCoord:(int)coord to:(int)anInt
  1554. {
  1555.     if ((anInt > 0) && (anInt != s_iso_samplesCoord[coord]))
  1556.     s_iso_samplesCoord[coord] = anInt;
  1557.     else
  1558.     return nil;
  1559.  
  1560.     [self reportSettingsChange:self];
  1561.     return self;
  1562. }
  1563.  
  1564.  
  1565. - (int) isoSamples:(int)coord
  1566. {
  1567.     return s_iso_samplesCoord[coord];
  1568. }
  1569.  
  1570.  
  1571.  
  1572. - setAutoscaleCoord:(int)coord isOn:(BOOL)cond
  1573. {
  1574.     if (s_autoscaleCoord[coord] != cond) {
  1575.     s_autoscaleCoord[coord] = cond;
  1576.     [self reportSettingsChange:self];
  1577.     }
  1578.     return self;
  1579. }
  1580.  
  1581.  
  1582. - (BOOL)autoscaleCoord:(int)coord
  1583. {
  1584.     return s_autoscaleCoord[coord];
  1585. }
  1586.  
  1587.  
  1588. - setRangeCoord:(int)coord min:(double)min max:(double)max
  1589. {
  1590.     if ((s_maxCoord[coord] != max) || (s_minCoord[coord] != min)) {
  1591.  
  1592.     s_maxCoord[coord] = max;
  1593.     s_minCoord[coord] = min;
  1594.  
  1595.     [self reportSettingsChange:self];
  1596.  
  1597.     }
  1598.     return self;
  1599. }
  1600.  
  1601. - (double)minCoord:(int)coord
  1602. {
  1603.     return s_minCoord[coord];
  1604. }
  1605.  
  1606. - (double)maxCoord:(int)coord
  1607. {
  1608.     return s_maxCoord[coord];
  1609. }
  1610.  
  1611.  
  1612.  
  1613. - setDegrees:(BOOL)cond;
  1614. {
  1615.     if (degrees != cond) {
  1616.     degrees = cond;
  1617.     if (s_polar)
  1618.         if (degrees)  {        /* Convert radians to degrees    */
  1619.         s_maxCoord[X_TAG] *= 57.2957795131;
  1620.         s_minCoord[X_TAG] *= 57.2957795131;
  1621.         } else {            /* Convert degrees to radians    */
  1622.         s_maxCoord[X_TAG] /= 57.2957795131;
  1623.         s_minCoord[X_TAG] /= 57.2957795131;
  1624.         }    
  1625.  
  1626.     [self reportSettingsChange:self];
  1627.     }
  1628.     return self;
  1629. }
  1630.  
  1631.  
  1632. - (BOOL)degrees
  1633. {
  1634.     return degrees;
  1635. }
  1636.  
  1637.  
  1638.  
  1639. /*
  1640.  *  We plot by assembling a Gnuplot "plot" command from the list of
  1641.  *  FunctionObjects.
  1642.  */
  1643.  
  1644. - buildPlotargs
  1645. {
  1646.     int index = [functions count];
  1647.     const char *aString;
  1648.     FunctionObject *function;
  1649.     int size = 0, counter, anInt, anInt2;
  1650.  
  1651.     /*  
  1652.      *  First, we calculate the total size that will be required for 
  1653.      *  the entire plot command, including commas, etc.
  1654.      */
  1655.     if (counter = index)  {
  1656.  
  1657.     size = isThreeD? 6 : 5;                /* "splot" or "plot" */
  1658.  
  1659.     while (counter--) {
  1660.         function = [functions objectAt:counter];
  1661.  
  1662.         if (aString = [function stringValue])
  1663.         size += strlen (aString);
  1664.  
  1665.         if ([function isDataFile])
  1666.         size += 2;                /* 2 quotation marks */
  1667.  
  1668.         if (aString = [function title])
  1669.         size += (strlen (aString) + 9);        /* " title 'xxx'"    */
  1670.  
  1671.         if (aString = [function styleString])
  1672.         size += (strlen (aString) + 12);    /* " with ??? xx xx" */
  1673.  
  1674.         size += 2;                    /* comma and space   */
  1675.     }
  1676.  
  1677.     /* 
  1678.      *  No comma or space after the last functions    = -2
  1679.      *  Terminating ASCII NULL            = +1
  1680.      *                         ----
  1681.      *                 Total        = -1
  1682.      */
  1683.     
  1684.     size--;
  1685.     }
  1686.  
  1687.     /*  Then we malloc enough space.  */
  1688.  
  1689.     NXZoneFree (zone, s_plotargs);
  1690.     s_plotargs = NXZoneMalloc (zone, size);
  1691.  
  1692.  
  1693.     /*  And finally, assemble the pieces.  */
  1694.     if (index) {
  1695.     if (isThreeD)
  1696.         strcpy (s_plotargs, "splot ");
  1697.     else
  1698.         strcpy (s_plotargs, "plot ");
  1699.  
  1700.     counter = 0;
  1701.     while (counter != index)  {
  1702.         function = [functions objectAt:counter++];
  1703.  
  1704.         if ([function isDataFile])
  1705.         sprintf (index (s_plotargs, '\0'), "'%s'",
  1706.              [function stringValue]);
  1707.         else
  1708.         s_plotargs = strcat (s_plotargs, [function stringValue]);
  1709.  
  1710.         /* 
  1711.          *  We determine which kind of quotation marks to use for 
  1712.          *  the title by checking to see if the title itself 
  1713.          *  contains any quotation marks and using the opposite 
  1714.          *  kind.  Assumption:  that the title does not use both 
  1715.          *  kinds of quotation marks, single and double.
  1716.          */
  1717.         if (aString = [function title]) {
  1718.         if (index (aString, '"'))
  1719.             sprintf (index (s_plotargs, '\0'), " title '%s'", aString);
  1720.         else
  1721.             sprintf(index(s_plotargs, '\0'), " title \"%s\"", aString);
  1722.         }
  1723.  
  1724.         if (aString = [function styleString])  {
  1725.  
  1726.         sprintf (index (s_plotargs, '\0'), " with %s", aString);
  1727.  
  1728.         /* 
  1729.          *  The following logical gymnastics are required 
  1730.          *  because the specific line and point styles may or 
  1731.          *  may not have been specified by the user and may or 
  1732.          *  may not be relevant.  Plus, Gnuplot requires that 
  1733.          *  the line style be specified whenever the point 
  1734.          *  style is specified, even if the function has no 
  1735.          *  lines.  Basically, we specify what we must (based 
  1736.          *  on the user's choices) and let the rest go to the 
  1737.          *  default.
  1738.          */
  1739.         
  1740.         switch ([function style]) {
  1741.         case FUNCTION_LINES:
  1742.             if ((anInt = [function lineStyle]) != LINE_NOSTYLE)
  1743.             sprintf (index (s_plotargs, '\0'), " %d", anInt);
  1744.             break;
  1745.         case FUNCTION_POINTS:
  1746.             if ((anInt = [function pointsStyle]) != POINTS_NOSTYLE)
  1747.             sprintf (index (s_plotargs, '\0'), " 1 %d", anInt);
  1748.             break;
  1749.         case FUNCTION_LINESPOINTS:
  1750.             anInt2 = [function pointsStyle];
  1751.             anInt = [function lineStyle];
  1752.             if ((anInt != LINE_NOSTYLE) || 
  1753.             (anInt2 != POINTS_NOSTYLE)) {
  1754.             sprintf (index (s_plotargs, '\0'), " %d", anInt);
  1755.             if (anInt2 != POINTS_NOSTYLE)
  1756.                 sprintf (index (s_plotargs, '\0'), " %d", anInt2);
  1757.             }
  1758.             break;
  1759.         }
  1760.  
  1761.         }
  1762.         
  1763.         /* If there are more functions, we need a comma */
  1764.         if (counter != index)
  1765.             s_plotargs = strcat (s_plotargs, ", ");
  1766.     }
  1767.     }
  1768.  
  1769.     return self;
  1770. }
  1771.  
  1772.  
  1773. - (const char *) plotargs
  1774. {
  1775.     return s_plotargs;
  1776. }
  1777.  
  1778.  
  1779.  
  1780. - (List *)functions
  1781. {
  1782.     return functions;
  1783. }
  1784.  
  1785.  
  1786. // Shuts up the compiler about unused RCSId
  1787. - (const char *) rcsid
  1788. {
  1789.     return RCSId;
  1790. }
  1791.  
  1792.  
  1793. @end
  1794.  
  1795.  
  1796. @implementation Status (Private)
  1797.  
  1798.  
  1799. - (const char *) _copyString:(const char *)source to:(char **)dest
  1800. {
  1801.     if (dest)  {
  1802.     NXZoneFree (zone, *dest);
  1803.  
  1804.     if (source)
  1805.         *dest = NXCopyStringBufferFromZone (source, zone);
  1806.     else
  1807.         *dest = NULL;
  1808.     }
  1809.  
  1810.     return *dest;
  1811. }
  1812.  
  1813.  
  1814. /*
  1815.  *  This method is nearly identical to load_file in misc.c, except 
  1816.  *  that instead of reading commands from a file, it reads from a 
  1817.  *  string, passing one line at a time to gnuplot.
  1818.  */
  1819. - _doText:(const char *)theText
  1820. {
  1821.     extern char input_line[];        /* Line to be read by do_line()    */
  1822.     extern jmp_buf env;
  1823.     extern int do_line();
  1824.     extern int interactive;
  1825.  
  1826.     int len;                /* The length of a command    */
  1827.     int start, max;            /* Indexes in input_line string    */
  1828.     BOOL more;                /* Is there more of this line?    */
  1829.     BOOL stop;                /* Are we done reading text?    */
  1830.     int inline_num;            /* Text line number...        */
  1831.     int inline_index;            /* ... which begins here    */
  1832.  
  1833.  
  1834.     if (setjmp(env))  {            /*  Gnuplot bails out to here    */
  1835.                     /*  in case of parse error, etc.*/
  1836.     if (s_epsStream) {
  1837.  
  1838.         NXCloseMemory (s_epsStream, NX_FREEBUFFER);
  1839.         s_epsStream = NULL;
  1840.  
  1841.     }
  1842.  
  1843.     return nil;
  1844.  
  1845.     } else {
  1846.  
  1847.     interactive = 0;
  1848.     max = MAX_LINE_LEN;
  1849.     stop = NO;
  1850.     inline_num = inline_index = start = 0;
  1851.  
  1852.     if (s_epsStream)
  1853.         NXCloseMemory (s_epsStream, NX_FREEBUFFER);
  1854.     s_epsStream = NXOpenMemory(NULL, 0, NX_READWRITE);
  1855.  
  1856.     EPSStream = s_epsStream;
  1857.  
  1858.     while (!stop) {                  /* Read every line in theText    */
  1859.  
  1860.         more = YES;            /* Read one command        */
  1861.         while (more) {
  1862.         if (!_get_line (&(input_line[start]), max,
  1863.                 &theText[inline_index])) {
  1864.             stop = YES;        /* End of string        */
  1865.             more = NO;
  1866.         }
  1867.  
  1868.         inline_num++;
  1869.         len = strlen (input_line);
  1870.         inline_index += (len + 1);
  1871.         if (len+1 >= max) {
  1872.             fprintf (stderr, "Input line too long\n");
  1873.             /* todo Bring up a modal panel here or something */
  1874.         }
  1875.  
  1876.                                 /* Continuation line        */
  1877.         if (input_line[len - 1] == '\\') {
  1878.             start = len - 1;
  1879.             max -= start;
  1880.         } else
  1881.             more = NO;
  1882.         }
  1883.  
  1884.         if (strlen (input_line) > 0) {
  1885.         do_line();            /* Parse input_line    */
  1886.         }
  1887.  
  1888.     }
  1889.  
  1890.     NEXTFE_reset();
  1891.  
  1892.     return self;
  1893.     }
  1894. }
  1895.  
  1896.  
  1897.  
  1898. - _setText: (const char *) aString
  1899. {
  1900.     NXZoneFree (zone, text);
  1901.  
  1902.     /* Magic number 100 -- todo be more accurate */
  1903.     text = NXZoneMalloc (zone, strlen (aString) + 130);
  1904.     sprintf (text, "set term nextfe '%s' %d\nset output '/dev/null'\npi = 3.14159265359\n%s",
  1905.          s_font ? s_font : DEFAULT_FONT, s_fontsize, aString);
  1906.  
  1907.     return self;
  1908. }
  1909.  
  1910.  
  1911.  
  1912.  
  1913. @end
  1914.