home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-12 | 33.5 KB | 1,732 lines |
- /*
- * Copyright (C) 1993 Robert Davis
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of Version 2, or any later version, of
- * the GNU General Public License as published by the Free Software
- * Foundation.
- */
-
- static char RCSId[] = "$Id: Status.m,v 1.18 1993/05/30 09:10:15 davis Exp $";
-
-
- #import <appkit/Font.h>
- #import <appkit/nextstd.h> /* NX_FREE */
-
- #import <objc/hashtable.h> /* NXCopyStringBufferFromZone() */
- #import <objc/List.h>
- #import <objc/zone.h>
-
- #import <ctype.h> /* isspace() */
- #import <setjmp.h> /* setjmp() */
- #import <stdio.h>
- #import <strings.h> /* strcat(), strcpy(), index() */
-
- #import "FunctionObject.h"
- #import "GnuplotPlot.h"
- #import "Status.h"
-
- #import "StatusContour.h" /* Status categories */
- #import "StatusTics.h"
-
-
- @interface Status (Private)
- - _grabFunctionsFrom: (char *)aString isThreeD:(BOOL)aCond;
- - _buildPlotargs;
- - _buildUsing:(char *)aString forFunction:(FunctionObject *)aFunction;
- - (const char *) _copyString:(const char *)source to:(char **)dest;
- - _doText:(const char *)theText;
- - _setText:(const char *) aString;
- @end
-
-
- /*
- * The class remembers which Status object was the last to issue a
- * plot command to Gnuplot. We need to know this when we set our
- * instance variables to the corresponding Gnuplot values -- see
- * -grabCurrent.
- */
- static id lastplot = nil;
-
-
- #define MAX_LINE_LEN 1024 /* Same as in plot.h */
- #define DEFAULT_FONT "Helvetica"
-
- #define POLAR 0 /* Two sets of range information */
- #define CARTESIAN 1
-
-
- /*
- * All instance variables begin with s_ to avoid confusion with the
- * variables defined in gnuplot .c files.
- *
- * gnuplot Variable (setshow.c) Status Instance Variable
- * ---------------------------- ------------------------
- */
- extern char nextfe_font[]; /* s_font */
- extern int nextfe_fontsize; /* s_fontsize */
- extern int nextfe_solid; // unused
- extern char title[]; /* s_title */
- extern char xlabel[]; /* s_labelCoord[] */
- extern char ylabel[];
- extern char zlabel[];
- extern char dummy_var[][51]; /* s_dummy_var[] */
- extern int parametric; /* s_parametric */
- extern int polar; /* s_polar */
- extern int draw_border; /* s_border */
- extern int draw_surface; /* s_draw_surface */
- extern int grid; /* s_grid */
- extern int xzeroaxis; /* s_zeroaxis[] */
- extern int yzeroaxis;
- extern int is_log_x, is_log_y, is_log_z;/* s_isLogCoord[],s_isLogPol... */
-
- extern double base_log_x, base_log_y, /* Currently unused by Status */
- base_log_z; //
- extern double log_base_log_x,
- log_base_log_y,
- log_base_log_z;
-
- extern int key; /* s_key */
- extern double key_x, key_y, key_z; /* s_keyCoord[] */
- extern int timedate; /* s_time */
- extern int time_xoffset, time_yoffset; /* s_timeCoord[] */
- extern float xsize, ysize; /* s_xsize, s_ysize */
- extern float surface_rot_x; /* s_rot_x */
- extern float surface_rot_z; /* s_rot_z */
- extern int hidden3d; /* s_hidden3d */
- extern int autoscale_x; /* s_autoscaleCoord[][] */
- extern int autoscale_y;
- extern int autoscale_z;
- extern int autoscale_r;
- extern double xmin, xmax; /* s_minCoord[][],s_maxCoord[][]*/
- extern double ymin, ymax;
- extern double zmin, zmax;
- extern double rmin, rmax;
- extern int angles_format; /* degrees */
- extern int samples; /* s_samples */
- extern int samples_1; /* s_samplesCoord */
- extern int samples_2;
- extern int iso_samples_1; /* s_iso_samplesCoord */
- extern int iso_samples_2;
- extern char replot_line[]; /* s_plotargs */
- extern NXStream *EPSStream; /* s_epsStream (terminal) */
- extern int nextfe_halve; /* (GnuplotPlot preference) */
- extern NEXTFE_reset(); /* Appends PS Trailer to stream */
-
-
- /*
- * Removes leading blanks and tabs.
- */
- static char *_removeLeadingBlanks (char *aString)
- {
- if (aString && *aString) {
- char *cur = aString;
-
- while (*cur && (isspace(*cur)))
- cur++;
-
- strcpy (aString, cur);
- }
-
- return aString;
- }
-
-
- /*
- * Stores the first line, up to max characters, from the multi-line
- * string source in dest and returns a pointer to it. It replaces
- * the newline with a null character. If the line was the last in
- * the string, it returns NULL.
- */
- static char *_get_line (char *dest, int max, const char *source)
- {
- char *returnVal = dest;
-
- if (source && dest) {
- while ((*source != '\n') && (*source != '\0') && (max > 0)) {
- *dest = *source;
- dest++;
- source++;
- max--;
- }
-
- *dest = '\0';
-
- if (*source == '\n')
- return returnVal;
- } /* NULL is returned if line is */
- /* too long or end of source */
- return NULL; /* or dest string is reached. */
- }
-
-
- /*
- * Finds the end of the first function in string containing arguments
- * to gnuplot's plot command.
- */
- static char *_endFunction(char *aString)
- {
- char delim[MAX_LINE_LEN];
- char *cur = aString;
- int number = 0;
-
- while (cur && *cur) {
-
- switch (*cur) {
- case '\'':
- case '"':
- if (number && delim[number - 1] == *cur)
- number--;
- else
- delim[number++] = *cur;
- break;
-
- case '(':
- case ')':
- if (number && delim[number - 1] == ((*cur == '(')? ')' : '('))
- number --;
- else
- delim[number++] = *cur;
- break;
-
- case ',':
- if (!number)
- return cur;
- }
-
- cur++;
- }
-
- return NULL;
- }
-
-
- const char *makeOneQuoteType (char *aString)
- {
- char *c, quote = '\0';
-
- /*
- * Make sure at most one kind of quotation marks is used in the
- * string -- change all quotation marks to match the first one.
- */
- for (c = aString; c && *c; c++)
- if ((*c == '\'') || (*c == '"')) {
- if (quote && (*c != quote))
- *c = quote;
- else
- quote = *c;
- }
-
- return aString;
- }
-
-
-
- @implementation Status
-
- + lastplot
- {
- return lastplot;
- }
-
-
- + setHalvePlot:(BOOL)condition
- {
- nextfe_halve = condition;
- return self;
- }
-
-
- - init
- {
- int counter;
-
- [super init];
- zone = [self zone];
-
- report = YES;
-
- /*
- * Set all pointers to NULL or nil so -resetCurrent
- * doesn't try to free them.
- */
- s_epsStream = NULL;
-
- text = s_title = s_plotargs = s_font = appendix =
- s_dummy_var[0] = s_dummy_var[1] = NULL;
-
- for (counter = 0 ; counter < 3 ; counter++)
- s_labelCoord[counter] = NULL;
-
- [self initTics];
- [self initContour];
-
- [self resetCurrent];
-
- return self;
- }
-
-
- - free
- {
- int counter;
-
- if (s_epsStream)
- NXCloseMemory (s_epsStream, NX_FREEBUFFER);
-
- /*
- * NXZoneFree() doesn't bomb if you give it a NULL pointer, so we
- * don't bother to check the pointer.
- */
- NXZoneFree (zone, text);
- NXZoneFree (zone, appendix);
- NXZoneFree (zone, s_title);
- NXZoneFree (zone, s_font);
- NXZoneFree (zone, s_dummy_var[X_TAG]);
- NXZoneFree (zone, s_dummy_var[Y_TAG]);
-
- for (counter = 0 ; counter < 3 ; counter++)
- NXZoneFree (zone, s_labelCoord[counter]);
-
- NXZoneFree (zone, s_plotargs);
-
- if (functions)
- [[functions freeObjects] free];
-
- [self freeTics];
- [self freeContour];
-
- if (lastplot == self)
- lastplot = nil;
-
- return [super free];
- }
-
-
- - setReport:(BOOL)cond
- {
- report = cond;
- return self;
- }
-
-
- - (BOOL)report
- {
- return report;
- }
-
-
- - setDelegate: anObject
- {
- if ([anObject respondsTo:@selector(settingsDidChange:)]) {
- delegate = anObject;
- return self;
- } else
- return nil;
- }
-
-
- - delegate
- {
- return delegate;
- }
-
-
- - (NXStream *)stream
- {
- return s_epsStream;
- }
-
-
-
- - (BOOL)canPlot
- {
- int count = 0, index;
- int total = [functions count];
-
- /* Count the number of functions */
- index = total;
- while (index--)
- count += ([[functions objectAt:index] isDataFile]) ? 0 : 1;
-
- /*
- * We can plot iff
- *
- * 1) there is an appendix
- *
- * or
- *
- * 2) there is at least one FunctionObject and
- * 3) if the plot is parametric then
- * a) we have pairs of functions (two-dimensional),
- * b) or we have triplets of functions (3-dimens.)
- *
- */
-
- return ((appendix && *appendix) ||
- (total &&
- (s_parametric? (isThreeD? !(count % 3)
- : (!(count % 2) && (total == count)))
- :YES)));
-
- }
-
-
- - plot
- {
- [self applyCurrent];
- lastplot = self;
-
- if (areSettingsEdited && !appendix) {
- [self _buildPlotargs];
- [self _setText:s_plotargs];
-
- areSettingsEdited = NO;
- }
-
- if (appendix && *appendix)
- [self _setText:appendix]; /* Appendix overrides current plot */
-
- return [self _doText:text];
- }
-
-
-
- - saveToFile:(const char *)filename
- {
- char *copy, *line, *cur;
- id returnVal;
-
- /*
- * Gnuplot sometimes drops characters off the end of long
- * pathnames given to the "save" command, a bug that seems to
- * have been introduced between 3.1 and 3.2. We work around it
- * by cd'ing to the directory first and then saving the file.
- */
- copy = NXCopyStringBufferFromZone (filename, zone);
-
- if (cur = rindex (copy, '/')) {
- *(cur++) = '\0';
- line = NXZoneMalloc (zone, 15 + strlen (filename));
- sprintf (line, "cd '%s'\nsave '%s'\n", copy, cur);
- } else {
- line = NXZoneMalloc (zone, 9 + strlen (filename));
- sprintf (line, "save '%s'\n", filename);
- }
-
- returnVal = [self _doText:line]? self : nil;
- NXZoneFree (zone, copy);
- NXZoneFree (zone, line);
-
- return returnVal;
- }
-
-
-
- - reportSettingsChange:sender
- {
- areSettingsEdited = YES;
- if (lastplot == self)
- lastplot = nil; /* Last valid plot is no longer valid */
-
- if (delegate && report)
- [delegate settingsDidChange:self];
-
- return self;
- }
-
-
-
- /*
- * Resets all the instance variables to their default values.
- */
- - resetCurrent
- {
- int counter;
-
- if (functions)
- [functions freeObjects];
- else
- functions = [[List allocFromZone:zone] init];
-
- NXZoneFree (zone, text);
- text = NULL;
-
- NXZoneFree (zone, s_title);
- s_title = NULL;
-
- NXZoneFree (zone, s_dummy_var[0]);
- s_dummy_var[0] = NULL;
-
- NXZoneFree (zone, s_dummy_var[1]);
- s_dummy_var[1] = NULL;
-
- for (counter = 0 ; counter < 3 ; counter++) {
- NXZoneFree (zone, s_labelCoord[counter]);
- s_labelCoord[counter] = NULL;
- s_minCoord[counter][CARTESIAN] = -10.0;
- s_maxCoord[counter][CARTESIAN] = 10.0;
- s_minCoord[counter][POLAR] = -10.0;
- s_isLogCoord[counter][CARTESIAN] = NO;
- s_isLogCoord[counter][POLAR] = NO;
- }
-
- degrees = NO;
- /* These not set in for loop above */
- s_minCoord[X_TAG][POLAR] = s_minCoord[R_TAG][POLAR] = 0.0;
- s_maxCoord[X_TAG][POLAR] = degrees? 360 :6.283186;
- s_maxCoord[Y_TAG][POLAR] = s_maxCoord[Z_TAG][POLAR]
- = s_maxCoord[R_TAG][POLAR] = 10.0;
-
- NXZoneFree (zone, s_plotargs);
- s_plotargs = NULL;
-
- NXZoneFree (zone, s_font);
- s_font = NULL;
-
- NXZoneFree (zone, appendix);
- appendix = NULL;
-
- s_fontsize = 16;
-
- isThreeD = NO;
- s_parametric = NO;
- s_polar = NO;
- s_border = YES;
- s_draw_surface = YES;
-
- [self resetCurrentContour];
- [self resetCurrentTics];
-
- s_hidden3d = NO;
- s_grid = NO;
- s_zeroaxis[X_TAG] = s_zeroaxis[Y_TAG] = YES;
-
- s_key = YES; /* Plot has a key, in default location */
- s_key_default = YES;
-
- s_time = NO; /* Don't show time/date */
- s_time_default = YES;
-
- for (counter = 0 ; counter < 4 ; counter++) {
- s_autoscaleCoord[counter][CARTESIAN] = 1;
- s_autoscaleCoord[counter][POLAR] = 1;
- }
-
- sizeProp = YES; /* Keep x, y, z proportional */
- s_xsize = s_ysize = 1.0;
- s_samples = s_samplesCoord[X_TAG] = s_samplesCoord[Y_TAG] = 100;
- s_iso_samplesCoord[X_TAG] = s_iso_samplesCoord[Y_TAG] = 10;
-
- s_rotCoord[X_TAG] = 60.0;
- s_rotCoord[Z_TAG] = 30.0;
-
- areSettingsEdited = NO;
-
- return self;
- }
-
-
-
-
-
- /* Sets the current gnuplot settings to the Status instance variables. */
- - applyCurrent
- {
- int type;
-
- nextfe_solid = NO;//
-
- if (s_font)
- strcpy (nextfe_font, s_font);
- else
- strcpy (nextfe_font, DEFAULT_FONT);
-
- nextfe_fontsize = s_fontsize;
-
- if (s_title)
- strcpy (title, s_title);
- else
- strcpy (title, "");
-
- if (s_dummy_var[0])
- strcpy (dummy_var[0], s_dummy_var[0]);
- else
- strcpy (dummy_var[0], "x");
-
- if (s_dummy_var[1])
- strcpy (dummy_var[1], s_dummy_var[1]);
- else
- strcpy (dummy_var[1], "y");
-
- if (s_labelCoord[X_TAG])
- strcpy (xlabel, s_labelCoord[X_TAG]);
- else
- strcpy (xlabel, "");
-
- if (s_labelCoord[Y_TAG])
- strcpy (ylabel, s_labelCoord[Y_TAG]);
- else
- strcpy (ylabel, "");
-
- if (s_labelCoord[Z_TAG])
- strcpy (zlabel, s_labelCoord[Z_TAG]);
- else
- strcpy (zlabel, "");
-
- parametric = s_parametric;
- polar = s_polar;
- draw_border = s_border;
- draw_surface = s_draw_surface;
-
- [self applyCurrentContour];
- [self applyCurrentTics];
-
- hidden3d = s_hidden3d;
- grid = s_grid;
- xzeroaxis = s_zeroaxis[X_TAG];
- yzeroaxis = s_zeroaxis[Y_TAG];
-
- /*
- * We have to sets of ranges, depending on whether the plot is
- * cartesian or polar. Set the correct ones.
- */
- type = s_polar? POLAR:CARTESIAN;
-
- xmin = s_minCoord[X_TAG][type];
- xmax = s_maxCoord[X_TAG][type];
- ymin = s_minCoord[Y_TAG][type];
- ymax = s_maxCoord[Y_TAG][type];
- zmin = s_minCoord[Z_TAG][type];
- zmax = s_maxCoord[Z_TAG][type];
- is_log_x = s_isLogCoord[X_TAG][type];
- is_log_y = s_isLogCoord[Y_TAG][type];
- is_log_z = s_isLogCoord[Z_TAG][type];
- autoscale_x = s_autoscaleCoord[X_TAG][type];
- autoscale_y = s_autoscaleCoord[Y_TAG][type];
- autoscale_z = s_autoscaleCoord[Z_TAG][type];
- autoscale_r = s_autoscaleCoord[R_TAG][type];
-
- base_log_x = base_log_y = base_log_z = 10.0;
- log_base_log_x = log_base_log_y = log_base_log_z = log(10.0);
-
- angles_format = degrees? ANGLES_DEGREES :ANGLES_RADIANS;
-
- key = s_key? (s_key_default? -1 :1) :0;
- key_x = s_keyCoord[X_TAG];
- key_y = s_keyCoord[Y_TAG];
- key_z = s_keyCoord[Z_TAG];
-
- timedate = s_time? 1 :0;
- time_xoffset = (s_time_default? 0 :s_timeCoord[X_TAG]);
- time_yoffset = (s_time_default? 0 :s_timeCoord[Y_TAG]);
-
- xsize = s_xsize;
- ysize = s_ysize;
-
- surface_rot_x = s_rotCoord[X_TAG];
- surface_rot_z = s_rotCoord[Z_TAG];
-
- samples = s_samples;
- samples_1 = s_samplesCoord[X_TAG];
- samples_2 = s_samplesCoord[Y_TAG];
- iso_samples_1 = s_iso_samplesCoord[X_TAG];
- iso_samples_2 = s_iso_samplesCoord[Y_TAG];
-
- return self;
- }
-
-
-
- /*
- * Resets all the instance variables to the current gnuplot settings,
- * all of which pertain to the most recent plot:
- */
- - grabCurrent
- {
- char *cur;
- int type;
-
- NXZoneFree (zone, s_font);
- s_font = NXCopyStringBufferFromZone (nextfe_font, zone);
-
- s_fontsize = nextfe_fontsize;
-
- NXZoneFree (zone, s_title);
- s_title = NXCopyStringBufferFromZone (title, zone);
-
- NXZoneFree (zone, s_dummy_var[0]);
- s_dummy_var[0] = NXCopyStringBufferFromZone (dummy_var[0], zone);
-
- NXZoneFree (zone, s_dummy_var[1]);
- s_dummy_var[1] = NXCopyStringBufferFromZone (dummy_var[1], zone);
-
- NXZoneFree (zone, s_labelCoord[X_TAG]);
- s_labelCoord[X_TAG] = NXCopyStringBufferFromZone (xlabel, zone);
-
- NXZoneFree (zone, s_labelCoord[Y_TAG]);
- s_labelCoord[Y_TAG] = NXCopyStringBufferFromZone (ylabel, zone);
-
- NXZoneFree (zone, s_labelCoord[Z_TAG]);
- s_labelCoord[Z_TAG] = NXCopyStringBufferFromZone (zlabel, zone);
-
- /*
- * If the last plot command was "splot," as opposed to "plot,"
- * it is three dimensional.
- */
- isThreeD = (*(_removeLeadingBlanks(replot_line)) == 's');
-
- s_parametric = parametric;
- s_polar = polar;
- s_border = draw_border;
- s_draw_surface = draw_surface;
-
- [self grabCurrentContour];
- [self grabCurrentTics];
-
- s_hidden3d = hidden3d;
- s_grid = grid;
- s_zeroaxis[X_TAG] = xzeroaxis;
- s_zeroaxis[Y_TAG] = yzeroaxis;
-
- type = polar? POLAR:CARTESIAN;
- s_minCoord[X_TAG][type] = xmin;
- s_maxCoord[X_TAG][type] = xmax;
- s_minCoord[Y_TAG][type] = ymin;
- s_maxCoord[Y_TAG][type] = ymax;
- s_minCoord[Z_TAG][type] = zmin;
- s_maxCoord[Z_TAG][type] = zmax;
- s_isLogCoord[X_TAG][type] = is_log_x;
- s_isLogCoord[Y_TAG][type] = is_log_y;
- s_isLogCoord[Z_TAG][type] = is_log_z;
- s_autoscaleCoord[X_TAG][type] = autoscale_x;
- s_autoscaleCoord[Y_TAG][type] = autoscale_y;
- s_autoscaleCoord[Z_TAG][type] = autoscale_z;
- s_autoscaleCoord[R_TAG][type] = autoscale_r;
-
- degrees = (angles_format == ANGLES_DEGREES);
-
- s_key = ((key == -1) || (key == 1));
- s_key_default = (key == -1);
- s_keyCoord[X_TAG] = key_x;
- s_keyCoord[Y_TAG] = key_y;
- s_keyCoord[Z_TAG] = key_z;
-
- s_time = timedate;
- s_time_default = (time_xoffset == 0.0) && (time_yoffset == 0.0);
- s_timeCoord[X_TAG] = time_xoffset;
- s_timeCoord[Y_TAG] = time_yoffset;
-
- s_xsize = xsize;
- s_ysize = ysize;
-
- s_samples = samples;
- s_samplesCoord[X_TAG] = samples_1;
- s_samplesCoord[Y_TAG] = samples_2;
- s_iso_samplesCoord[X_TAG] = iso_samples_1;
- s_iso_samplesCoord[Y_TAG] = iso_samples_2;
-
- s_rotCoord[X_TAG] = surface_rot_x;
- s_rotCoord[Z_TAG] = surface_rot_z;
-
- NXZoneFree (zone, s_plotargs);
- if (cur = index (replot_line, ' ')) { /* todo What about tabs? */
- s_plotargs = NXZoneMalloc (zone, strlen (replot_line) + 1);
- strcpy (s_plotargs, cur + 1);
- } else
- s_plotargs = NULL;
-
- /* Break plotargs into separate functions */
- [self _grabFunctionsFrom:s_plotargs isThreeD:isThreeD];
- [self _buildPlotargs];
-
- [self _setText: s_plotargs];
- areSettingsEdited = YES;
-
- return self;
- }
-
-
- - setThreeD:(BOOL) aCondition
- {
-
- if (isThreeD != aCondition) {
- int i;
-
- isThreeD = aCondition;
-
- for (i = [functions count] - 1; i >= 0; i--)
- [[functions objectAt:i] setThreeD:isThreeD];
-
- if (s_parametric) {
- if (isThreeD) {
- [self _copyString:"u" to:&(s_dummy_var[X_TAG])];
- [self _copyString:"v" to:&(s_dummy_var[Y_TAG])];
- } else
- [self _copyString:"t" to:&(s_dummy_var[X_TAG])];
- }
-
- [self reportSettingsChange:self];
- }
- return self;
- }
-
-
- - (BOOL) isThreeD
- {
- return isThreeD;
- }
-
-
-
- - setParametric:(BOOL) cond
- {
- if (s_parametric != cond) {
-
- s_parametric = cond;
-
- if (cond) {
- if (isThreeD) {
- [self _copyString:"u" to:&(s_dummy_var[X_TAG])];
- [self _copyString:"v" to:&(s_dummy_var[Y_TAG])];
- } else
- [self _copyString:"t" to:&(s_dummy_var[X_TAG])];
- } else {
- [self _copyString:"x" to:&(s_dummy_var[X_TAG])];
- [self _copyString:"y" to:&(s_dummy_var[Y_TAG])];
- }
-
- [self reportSettingsChange:self];
-
- }
- return self;
- }
-
-
- - (BOOL) parametric
- {
- return s_parametric;
- }
-
-
-
- - setPolar:(BOOL) cond
- {
- if (s_polar != cond) {
- s_polar = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (BOOL) isPolar
- {
- return s_polar;
- }
-
-
-
- - setBorder:(BOOL) cond
- {
- if (s_border != cond) {
- s_border = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (BOOL) border
- {
- return s_border;
- }
-
-
-
- - setSurface:(BOOL) cond
- {
- if (s_draw_surface != cond) {
- s_draw_surface = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (BOOL) surface
- {
- return s_draw_surface;
- }
-
-
-
- - setHiddenThreeD:(BOOL) cond
- {
- if (s_hidden3d != cond) {
- s_hidden3d = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (BOOL) hiddenThreeD
- {
- return s_hidden3d;
- }
-
-
-
- - setGrid:(BOOL) cond
- {
- if (s_grid != cond) {
- s_grid = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (BOOL) grid
- {
- return s_grid;
- }
-
-
-
- - setAxisCoord:(int)coord on:(BOOL)cond
- {
- if (s_zeroaxis[coord] != cond) {
- s_zeroaxis[coord] = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (BOOL) axisCoord:(int)coord
- {
- return s_zeroaxis[coord];
- }
-
-
-
- - setIsLogCoord:(int)coord isOn:(BOOL)isOn
- {
- int type = s_polar? POLAR:CARTESIAN;
-
- if (s_isLogCoord[coord][type] != isOn) {
- s_isLogCoord[coord][type] = isOn;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
-
- - (BOOL) isLogCoord:(int)coord
- {
- return s_isLogCoord[coord][s_polar? POLAR:CARTESIAN];
- }
-
-
-
- - setTitle:(const char *) aString
- {
- [self _copyString:aString to:&s_title];
- makeOneQuoteType (s_title);
- [self reportSettingsChange:self];
-
- return self;
- }
-
-
- - (const char *) title
- {
- return s_title;
- }
-
-
- - setLabelCoord:(int)coord to:(const char *) aString
- {
- [self _copyString:aString to:&(s_labelCoord[coord])];
- makeOneQuoteType (s_labelCoord[coord]);
- [self reportSettingsChange:self];
-
- return self;
- }
-
-
-
- - (const char *) labelCoord:(int) coord
- {
- return s_labelCoord[coord];
- }
-
-
- - setDummyVar:(int)coord to:(const char *)aString
- {
- [self _copyString:aString to:&(s_dummy_var[coord])];
- [self reportSettingsChange:self];
- return self;
- }
-
-
- - (const char *)dummyVar:(int)coord
- {
- if (!s_dummy_var[coord])
- switch (coord) {
- case X_TAG:
- return "x";
- break;
- case Y_TAG:
- return "y";
- break;
- }
-
- return s_dummy_var[coord];
- }
-
-
- - setAppendix: (const char *) aString
- {
- NXZoneFree (zone, appendix);
-
- if (aString)
- appendix = NXCopyStringBufferFromZone (aString, zone);
- else
- appendix = NULL;
-
- return self;
- }
-
-
- - setFontsize: (int) anInt;
- {
- if ((s_fontsize != anInt) && (anInt > 0)) {
- s_fontsize = anInt;
- [self reportSettingsChange:self];
- return self;
- } else
- return nil;
- }
-
-
- - (int) fontsize
- {
- return s_fontsize;
- }
-
-
-
- - setFontname: (const char *) aString
- {
- [self _copyString:aString to:&s_font];
- [self reportSettingsChange:self];
-
- return self;
- }
-
-
- - (const char *) fontname
- {
- return s_font;
- }
-
-
-
- - setFont:aFont
- {
- if (aFont) {
- [self _copyString:[aFont name] to:&s_font];
- s_fontsize = [aFont pointSize];
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
-
- - font
- {
- if (!s_font)
- return [Font newFont:DEFAULT_FONT size:s_fontsize];
- return [Font newFont:s_font size:s_fontsize];
- }
-
-
-
- - setKey:(BOOL) cond
- {
- if (s_key != cond) {
- s_key = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
-
- - (BOOL) key
- {
- return s_key;
- }
-
-
- - setKeyDefault:(BOOL) cond
- {
- if (s_key_default != cond) {
- s_key_default = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
-
- - (BOOL) keyDefault
- {
- return s_key_default;
- }
-
-
- - setKeyCoord:(int)coord to:(double)aDouble
- {
- if (s_keyCoord[coord] != aDouble) {
- s_keyCoord[coord] = aDouble;
- [self reportSettingsChange:self];
- }
- return self;
- }
-
-
- - (double) keyCoord:(int)coord
- {
- return s_keyCoord[coord];
- }
-
-
-
- - setTime:(BOOL) cond
- {
- if (s_time != cond) {
- s_time = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
-
- - (BOOL) time
- {
- return s_time;
- }
-
-
- - setTimeDefault:(BOOL) cond
- {
- if (s_time_default != cond) {
- s_time_default = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
-
- - (BOOL) timeDefault
- {
- return s_time_default;
- }
-
-
- - setTimeCoord:(int)coord to:(int)aDouble
- {
- if (s_timeCoord[coord] != aDouble) {
- s_timeCoord[coord] = aDouble;
- [self reportSettingsChange:self];
- }
- return self;
- }
-
-
- - (int) timeCoord:(int)coord
- {
- return s_timeCoord[coord];
- }
-
-
-
- - setSizeProp:(BOOL) cond
- {
- sizeProp = cond; /* Don't do anything, just record status */
- return self;
- }
-
-
- - (BOOL)sizeProp
- {
- return sizeProp;
- }
-
-
- /*
- * Size of zero means don't change... (e.g. if x=2 and y=0, we change
- * x but not y).
- */
- - setSizeX:(float) xFloat Y:(float) yFloat
- {
- if ((xFloat != s_xsize) || (yFloat != s_ysize)) {
-
- if (xFloat)
- s_xsize = xFloat;
-
- if (yFloat)
- s_ysize = yFloat;
-
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (float) sizeX
- {
- return s_xsize;
- }
-
-
- - (float) sizeY
- {
- return s_ysize;
- }
-
-
-
- - setRotCoord:(int)coord to:(float)aFloat
- {
- if (s_rotCoord[coord] != aFloat) {
- s_rotCoord[coord] = aFloat;
- [self reportSettingsChange:self];
- }
- return self;
- }
-
-
-
- - resetRotation
- {
- s_rotCoord[X_TAG] = 60.0;
- s_rotCoord[Z_TAG] = 30.0;
- [self reportSettingsChange:self];
- return self;
- }
-
-
-
- - (float)rotCoord:(int)coord
- {
- return s_rotCoord[coord];
- }
-
-
-
- - setSamplesCoord:(int)coord to:(int)anInt
- {
- if ((anInt >= 2) && (anInt != s_samplesCoord[coord])) {
- s_samplesCoord[coord] = anInt;
- if (coord == X_TAG)
- s_samples = anInt;
- } else
- return nil;
-
- [self reportSettingsChange:self];
- return self;
- }
-
-
- - (int) samples:(int)coord
- {
- return s_samplesCoord[coord];
- }
-
-
-
- - setIsoSamplesCoord:(int)coord to:(int)anInt
- {
- if ((anInt >= 2) && (anInt != s_iso_samplesCoord[coord]))
- s_iso_samplesCoord[coord] = anInt;
- else
- return nil;
-
- [self reportSettingsChange:self];
- return self;
- }
-
-
- - (int) isoSamples:(int)coord
- {
- return s_iso_samplesCoord[coord];
- }
-
-
-
- - setAutoscaleCoord:(int)coord isOn:(BOOL)cond
- {
- int type = s_polar? POLAR:CARTESIAN;
-
- if (s_autoscaleCoord[coord][type] != cond) {
- s_autoscaleCoord[coord][type] = cond;
- [self reportSettingsChange:self];
- }
-
- return self;
- }
-
-
- - (BOOL)autoscaleCoord:(int)coord
- {
- return s_autoscaleCoord[coord][s_polar? POLAR:CARTESIAN];
- }
-
-
- - setRangeCoord:(int)coord min:(double)min max:(double)max
- {
- int type = s_polar? POLAR:CARTESIAN;
-
- if ((s_maxCoord[coord][type] != max) || (s_minCoord[coord][type] != min)) {
-
- s_maxCoord[coord][type] = max;
- s_minCoord[coord][type] = min;
-
- [self reportSettingsChange:self];
-
- }
-
- return self;
- }
-
- - (double)minCoord:(int)coord
- {
- return s_minCoord[coord][s_polar? POLAR:CARTESIAN];
- }
-
- - (double)maxCoord:(int)coord
- {
- return s_maxCoord[coord][s_polar? POLAR:CARTESIAN];
- }
-
-
-
- - setDegrees:(BOOL)cond;
- {
- if (degrees != cond) {
- degrees = cond;
- if (s_polar)
- if (degrees) { /* Convert radians to degrees */
- s_maxCoord[X_TAG][POLAR] *= 57.2957795131;
- s_minCoord[X_TAG][POLAR] *= 57.2957795131;
- } else { /* Convert degrees to radians */
- s_maxCoord[X_TAG][POLAR] /= 57.2957795131;
- s_minCoord[X_TAG][POLAR] /= 57.2957795131;
- }
-
- [self reportSettingsChange:self];
- }
- return self;
- }
-
-
- - (BOOL)degrees
- {
- return degrees;
- }
-
-
-
- - (List *)functions
- {
- return functions;
- }
-
-
- // Shuts up the compiler about unused RCSId
- - (const char *) rcsid
- {
- return RCSId;
- }
-
-
- @end
-
-
- @implementation Status (Private)
-
-
- /*
- * We use a list of FunctionObjects to store each function (a
- * "function" is a mathematical expression that gnuplot will evaluate
- * at certain points or a file containing data that gnuplot will
- * plot.) We create these objects by parsing the plot arguments.
- */
- - _grabFunctionsFrom: (char *)aString isThreeD:(BOOL)aCond;
- {
- FunctionObject *aFunction;
- char *src;
- BOOL done;
-
- [functions freeObjects];
-
- if (!aString)
- return nil;
-
- /* Skip any range specifications */
- src = aString;
- while (isspace (*src))
- src++;
- while (*src == '[') {
- while (*src != ']')
- src++;
- src++;
- while (isspace (*src))
- src++;
- }
-
- /* Copy them to the strings list */
-
- done = NO;
- while (!done) {
- char *end;
-
- if (end = _endFunction(src))
- *end = '\0';
- else
- done = YES;
-
- aFunction = [[FunctionObject allocFromZone:zone]
- initFromString: _removeLeadingBlanks (src) isThreeD:aCond];
- [functions addObject:aFunction];
-
- if (!done) {
- *end = ',';
- src = ++end;
- }
- }
-
- return self;
- }
-
-
-
-
- /*
- * We plot by assembling a Gnuplot "plot" command from the list of
- * FunctionObjects.
- */
-
- - _buildPlotargs
- {
- int index = [functions count];
- const char *aString;
- FunctionObject *function;
- int size = 0, counter, anInt, anInt2;
-
- /*
- * First, we calculate the total size that will be required for
- * the entire plot command, including commas, etc.
- */
- if (counter = index) {
-
- size = isThreeD? 6 : 5; /* "splot" or "plot" */
-
- while (counter--) {
- function = [functions objectAt:counter];
-
- if (aString = [function stringValue])
- size += strlen (aString);
-
- if ([function isDataFile])
- size += 2; /* 2 quotation marks */
-
- if (aString = [function title])
- size += (strlen (aString) + 9); /* " title 'xxx'" */
-
- if (aString = [function styleString])
- size += (strlen (aString) + 12); /* " with ??? xx xx" */
-
- size += 2; /* comma and space */
- size += 255; /* "using" clause */
- }
-
- /*
- * No comma or space after the last functions = -2
- * Terminating ASCII NULL = +1
- * ----
- * Total = -1
- */
-
- size--;
- }
-
- /* Then we malloc enough space. */
-
- NXZoneFree (zone, s_plotargs);
- s_plotargs = NXZoneMalloc (zone, size);
-
-
- /* And finally, assemble the pieces. */
- if (index) {
- if (isThreeD)
- strcpy (s_plotargs, "splot ");
- else
- strcpy (s_plotargs, "plot ");
-
- counter = 0;
- while (counter != index) {
- function = [functions objectAt:counter++];
-
- if ([function isDataFile]) {
- char using[255];
-
- [self _buildUsing:using forFunction:function];
- sprintf (index (s_plotargs, '\0'), "'%s' %s",
- [function stringValue], using);
- } else
- s_plotargs = strcat (s_plotargs, [function stringValue]);
-
- /*
- * We determine which kind of quotation marks to use for
- * the title by checking to see if the title itself
- * contains any quotation marks and using the opposite
- * kind. Assumption: that the title does not use both
- * kinds of quotation marks, single and double.
- */
- if (aString = [function title]) {
- if (index (aString, '"'))
- sprintf (index (s_plotargs, '\0'), " title '%s'", aString);
- else
- sprintf(index(s_plotargs, '\0'), " title \"%s\"", aString);
- }
-
- if (aString = [function styleString]) {
-
- sprintf (index (s_plotargs, '\0'), " with %s", aString);
-
- /*
- * The following logical gymnastics are required
- * because the specific line and point styles may or
- * may not have been specified by the user and may or
- * may not be relevant. Plus, Gnuplot requires that
- * the line style be specified whenever the point
- * style is specified, even if the function has no
- * lines. Basically, we specify what we must (based
- * on the user's choices) and let the rest go to the
- * default.
- */
-
- switch ([function style]) {
- case FUNCTION_LINES:
- if ((anInt = [function lineStyle]) != LINE_NOSTYLE)
- sprintf (index (s_plotargs, '\0'), " %d", anInt);
- break;
- case FUNCTION_POINTS:
- if ((anInt = [function pointsStyle]) != POINTS_NOSTYLE)
- sprintf (index (s_plotargs, '\0'), " 1 %d", anInt);
- break;
- case FUNCTION_LINESPOINTS:
- anInt2 = [function pointsStyle];
- anInt = [function lineStyle];
- if ((anInt != LINE_NOSTYLE) ||
- (anInt2 != POINTS_NOSTYLE)) {
- sprintf (index (s_plotargs, '\0'), " %d", anInt);
- if (anInt2 != POINTS_NOSTYLE)
- sprintf (index (s_plotargs, '\0'), " %d", anInt2);
- }
- break;
- }
-
- }
-
- /* If there are more functions, we need a comma */
- if (counter != index)
- s_plotargs = strcat (s_plotargs, ", ");
- }
- }
-
- return self;
- }
-
-
- - _buildUsing:(char *)aString forFunction:(FunctionObject *)aFunction
- {
- struct coldat *d = [aFunction columnData];
-
- *aString = '\0';
-
- if (!d->isOn) /* No using clause */
- return self;
-
- if (isThreeD) {
-
- if (d->useX)
- sprintf (aString, " using %d:%d:%d", d->x, d->y, d->z);
- else
- sprintf (aString, " using %d", d->z);
-
- } else {
-
- if (!d->useX)
- sprintf (aString, " using %d", d->y);
-
- else if (d->useX) {
-
- sprintf (aString, "using %d:%d", d->x, d->y);
- if (d->useYDelta)
- sprintf (aString, "%s:%d", aString, d->yDelta);
- else if (d->useYLow) {
- sprintf (aString, "%s:%d:%d", aString, d->yLow, d->yHigh);
-
- if (d->useBoxWidth)
- sprintf (aString, "%s:%d", aString, d->boxWidth);
- } else if (d->useBoxWidth)
- sprintf (aString, "%s:%d:%d:%d",aString,d->y,d->y,d->boxWidth);
-
- }
- }
-
- return self;
- }
-
-
-
- - (const char *) _copyString:(const char *)source to:(char **)dest
- {
- if (dest) {
- NXZoneFree (zone, *dest);
-
- if (source)
- *dest = NXCopyStringBufferFromZone (source, zone);
- else
- *dest = NULL;
- }
-
- return *dest;
- }
-
-
- /*
- * This method is nearly identical to load_file in misc.c, except
- * that instead of reading commands from a file, it reads from a
- * string, passing one line at a time to gnuplot.
- */
- - _doText:(const char *)theText
- {
- extern char input_line[]; /* Line to be read by do_line() */
- extern jmp_buf env;
- extern int do_line();
- extern int interactive;
-
- int len; /* The length of a command */
- int start, max; /* Indexes in input_line string */
- BOOL more; /* Is there more of this line? */
- BOOL stop; /* Are we done reading text? */
- int inline_num; /* Text line number... */
- int inline_index; /* ... which begins here */
-
-
- if (setjmp(env)) { /* Gnuplot bails out to here */
- /* in case of parse error, etc.*/
- if (s_epsStream) {
-
- NXCloseMemory (s_epsStream, NX_FREEBUFFER);
- s_epsStream = NULL;
-
- }
-
- return nil;
-
- } else {
-
- interactive = 0;
- max = MAX_LINE_LEN;
- stop = NO;
- inline_num = inline_index = start = 0;
-
- if (s_epsStream)
- NXCloseMemory (s_epsStream, NX_FREEBUFFER);
- s_epsStream = NXOpenMemory(NULL, 0, NX_READWRITE);
-
- EPSStream = s_epsStream;
-
- while (!stop) { /* Read every line in theText */
-
- more = YES; /* Read one command */
- while (more) {
- if (!_get_line (&(input_line[start]), max,
- &theText[inline_index])) {
- stop = YES; /* End of string */
- more = NO;
- }
-
- inline_num++;
- len = strlen (input_line);
- inline_index += (len + 1);
- if (len+1 >= max) {
- fprintf (stderr, "Input line too long\n");
- /* todo Bring up a modal panel here or something */
- }
-
- /* Continuation line */
- if (input_line[len - 1] == '\\') {
- start = len - 1;
- max -= start;
- } else
- more = NO;
- }
-
- if (strlen (input_line) > 0) {
- do_line(); /* Parse input_line */
- }
-
- }
-
- NEXTFE_reset();
-
- return self;
- }
- }
-
-
-
- - _setText: (const char *) aString
- {
- NXZoneFree (zone, text);
-
- /* Magic number 100 -- todo be more accurate */
- text = NXZoneMalloc (zone, strlen (aString) + 130);
- sprintf (text, "set term _nextfe '%s' %d\nset output '/dev/null'\n%s",
- s_font ? s_font : DEFAULT_FONT, s_fontsize, aString);
-
- return self;
- }
-
-
-
-
- @end
-