This is Status.m in view mode; [Download] [Up]
/*
* 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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.