This is NXYController.m in view mode; [Download] [Up]
/* Generated by Interface Builder */ #import "NXYController.h" #import "NXYView.h" /* only for initializeLegendBox */ /* will get warning message from compiler if preceding line is commented out */ #import <appkit/OpenPanel.h> #import <appkit/Matrix.h> #import <appkit/Cell.h> #import <math.h> #define ALLOCSIZE 2048 /* used in malloc in readData */ @implementation NXYController - (NXCoord *)xdata { return x;} - (NXCoord **)ydata { return y;} - (int)nPoints { return npoints;} - (int)nCurves { return ncurves;} - (const char *)provideXtitle {return [xTitle stringValueAt:0];} - (const char *)provideYtitle {return [yTitle stringValueAt:0];} - (const char *)provideMaintitle {return [mainTitle stringValueAt:0];} - (const char *)provideCurveTitle:(int)aCurve { return [legendForm stringValueAt:aCurve]; } - (const char *)provideLegendTitle { return [legendTitle stringValueAt:0]; } - (BOOL) shouldDrawLegend { if ( [legendOnOff state] ) return YES; else return NO; } - (BOOL) shouldDrawLegendBox { if ( [legendBoxOnOff state] ) return YES; else return NO; } - (BOOL) shouldDrawGrid { if ( [gridOnOff state] ) return YES; else return NO; } - (BOOL) shouldDrawBox { if ( [borderBoxOnOff state] ) return YES; else return NO; } - (BOOL) shouldMoveLegend { if ( [legendMove state] ) return YES; else return NO; } - (BOOL) doZoom { if ( [zoomOnOff state] ) return YES; else return NO; } - (BOOL) xaxisLog { if ( [xLinLog state] ) return YES; else return NO; } - forceXaxisLinear { [xLinLog setState:0]; [xLinLog display]; return self; } - (BOOL) yaxisLog { if ( [yLinLog state] ) return YES; else return NO; } - forceYaxisLinear { [yLinLog setState:0]; [yLinLog display]; return self; } - (int)providelinestyle:(int)aCurve { int row; int cellstate; for (row=0; row<N_LINE_STYLES; row++) { cellstate = [ [lineMatrix cellAt:row :aCurve] state]; if (cellstate == 1) return row; } return 0; /* for safety */ } - (int)providesymbolstyle:(int)aCurve { int row; int cellstate; for (row=0; row<N_SYMBOL_STYLES; row++) { cellstate = [ [symbolMatrix cellAt:row :aCurve] state]; if (cellstate == 1) return row; } return 0; /* for safety */ } - (int)providesymbolsize{ return [symbolSize selectedCol];} - (int)providelinethickness{ return [lineThickness selectedCol];} - (float)provideXmin {return [xMin floatValueAt:0];} - (float)provideXmax {return [xMax floatValueAt:0];} - (float)provideXinc {return [xInc floatValueAt:0];} - (float)provideYmin {return [yMin floatValueAt:0];} - (float)provideYmax {return [yMax floatValueAt:0];} - (float)provideYinc {return [yInc floatValueAt:0];} - resetXmin:(float)aNum { [xMin setFloatValue:aNum at:0]; return self; } - resetXmax:(float)aNum { [xMax setFloatValue:aNum at:0]; return self; } - resetXinc:(float)aNum { [xInc setFloatValue:aNum at:0]; return self; } - resetYmin:(float)aNum { [yMin setFloatValue:aNum at:0]; return self; } - resetYmax:(float)aNum { [yMax setFloatValue:aNum at:0]; return self; } - resetYinc:(float)aNum { [yInc setFloatValue:aNum at:0]; return self; } - resetMinMax:sender { [xMin setFloatValue:datamin.x at:0]; [xMax setFloatValue:datamax.x at:0]; [xInc setFloatValue:(datamax.x - datamin.x)/5.0 at:0]; [yMin setFloatValue:datamin.y at:0]; [yMax setFloatValue:datamax.y at:0]; [yInc setFloatValue:(datamax.y - datamin.y)/5.0 at:0]; return self; } - drawPlotButton:(int)state { if (state==0) { [plotButton highlight:NO]; /* will display normal title */ } if (state==1) { [plotButton highlight:YES]; /* will display alternate title */ } return self; } - drawPlot:sender { if (!x) return self; [self drawPlotButton:1]; /* display "Plotting" */ [canvas display]; [self drawPlotButton:0]; /* display "Plot" */ return self; } // Allocate enough memory and read the data points /* * WARNING: This code will go into an infinite loop if there is illegal * crud in the data file (such as a comma, for example). The culprit is * the "fscanf" below; we will put up with this for now, but we should * make this more robust. */ - (int) readData:(FILE *)aDataStream { BOOL inword = NO; char c; int j, size = ALLOCSIZE; int oldncurves = ncurves; /* for linestyle matrix column deleting */ /* set plot button title "Reading" */ [plotButton setAltTitle:"Reading"]; [plotButton highlight:YES]; NXPing(); /* force plotButton redraw */ /* First, free x and y here if there's already data in them */ if (x) { free( (void *)x ); for (j = 0; j < ncurves; j++) { free( (void *)(*(y+j)) ); } free( (void *)y ); } /* Figure out the number of curves in the file by reading characters */ /* until a newline is encountered; the number of curves is one less */ /* than the number of words found. */ /* For now we assume the input file is an ascii file. */ ncurves = -1; while (1) { c = getc(aDataStream); if (c == '\n') { break; /* breaks out of while loop */ } if ((inword==NO) && !(c==' ' || c=='\t')) { ncurves++; inword = YES; } if ((inword==YES) && (c==' ' || c=='\t')) { inword = NO; } } if (ncurves == -1) { /* couldn't find "\n", give up */ return 0; } /* Now read the data into memory */ rewind(aDataStream); y = (NXCoord **)malloc( ncurves * sizeof(NXCoord *) ); x = (NXCoord *)malloc( size * sizeof(NXCoord) ); for (j = 0; j < ncurves; j++) { *(y+j) = (NXCoord *)malloc( size * sizeof(NXCoord) ); } npoints = 0; while(1) { if( (fscanf(aDataStream, "%f", x+npoints)) == EOF ) { break; /* breaks out of the while loop */ } for (j = 0; j < ncurves; j++) { fscanf(aDataStream, "%f", *(y+j)+npoints); } npoints++; if (npoints == size) { /* get more memory */ size += ALLOCSIZE; x = (NXCoord *)realloc(x, size * sizeof(NXCoord)); for (j = 0; j < ncurves; j++) { *(y+j) = (NXCoord *)realloc( *(y+j), size * sizeof(NXCoord) ); } } } /* Adjust the lineMatrix, symbolMatrix, and legendForm */ [self adjustPanels:oldncurves :ncurves]; /* reset plot button */ [plotButton setAltTitle:"Plotting"]; [plotButton highlight:NO]; return npoints; } /* Might want to make sure INLINE_MATH is defined when math.h is included */ - checkLinLog { /* Check x and y axes -- do a heuristic test for log/lin. * The test employed comes from M. Merriam and xyplot. */ double scale, linsum, logsum; register double tmp; int i, j; /* First test x axis. */ if (datamax.x > 0.0 && datamin.x > 0.0 && datamax.x != datamin.x) { scale = fabs( (double)datamax.x - (double)datamin.x ); linsum = 0.0; for (j=1; j<npoints; j++) { tmp = ( (double)x[j]-(double)x[j-1] )/(double)scale; /* avoid overflow */ linsum += tmp*tmp; } scale = log10( (double)datamax.x/(double)datamin.x ); /* what if datamax.x<datamin.x? */ logsum = 0.0; for (i=1; i<npoints; i++) { tmp = log10( (double)x[i]/(double)x[i-1] ) / scale; logsum += tmp*tmp; } if (linsum < logsum) { [xLinLog setState:0]; /* linear axis */ } else { [xLinLog setState:1]; /* logarithmic axis */ } } else { [xLinLog setState:0]; /* linear */ } /* Now test y axis */ if (datamax.y > 0.0 && datamin.y > 0.0 && datamax.y != datamin.y) { scale = fabs( (double)datamax.y - (double)datamin.y ); linsum = 0.0; for (j=0; j<ncurves; j++) { for (i=1; i<npoints; i++) { tmp = ( (double)*(*(y+j)+i) - (double)*(*(y+j)+i-1) ) / scale; /* avoid overflow */ linsum += tmp*tmp; } } scale = log10((double)datamax.y/(double)datamin.y); /* what if datamax.y<datamin.y? */ logsum = 0.0; for (j=0; j<ncurves; j++) { for (i=1; i<npoints;i++) { tmp = log10( (double)*(*(y+j)+i)/(double)*(*(y+j)+i-1) ) / scale; logsum += tmp*tmp; } } if (linsum < logsum) { [yLinLog setState:0]; /* linear axis */ } else { [yLinLog setState:1]; /* logarithmic axis */ } } else { [yLinLog setState:0]; /* linear */ } [xLinLog display]; [yLinLog display]; return self; } - adjustPanels:(int)oldn :(int)newn { /* * Resize the linestyle matrix, the symbolstyle matrix, and * the legend form. * Also arrange to select and highlight only the top button in * each column of the linestyle and symbolstyle matrices. * This code could stand to be cleaned up. */ char formtitle[80]; int j, k; if (oldn >= newn) { /* have to delete some columns and revise the remaining */ for (j=oldn-1; j>=newn; j--) { [lineText removeColAt:j andFree:YES]; /* Titles on Columns */ [symbolText removeColAt:j andFree:YES]; /* Titles on Columns */ [lineMatrix removeColAt:j andFree:YES]; [symbolMatrix removeColAt:j andFree:YES]; [legendForm removeEntryAt:j]; } for (j=0; j<newn; j++) { if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */ [ [lineMatrix cellAt:0 :j] setState:1]; if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */ [ [symbolMatrix cellAt:0 :j] setState:1]; for (k=1; k<N_LINE_STYLES; k++) { [ [lineMatrix cellAt:k :j] setState:0]; } for (k=1; k<N_SYMBOL_STYLES; k++) { [ [symbolMatrix cellAt:k :j] setState:0]; } sprintf(formtitle, "Curve %d", j+1); [legendForm setStringValue:formtitle at:j]; [legendForm drawCellAt:j]; sprintf(formtitle, "%d", j+1); [[lineText cellAt:0 :j] setStringValue:formtitle]; [[symbolText cellAt:0 :j] setStringValue:formtitle]; } [legendTitle setStringValue:"Legend" at:0]; [lineText sizeToCells]; /* Titles on Columns */ [symbolText sizeToCells]; /* Titles on Columns */ [lineMatrix sizeToCells]; [symbolMatrix sizeToCells]; [legendForm sizeToFit]; [ [lineText window] display]; /* Titles on Columns*/ [ [symbolText window] display]; /* Titles on Columns*/ [ [lineMatrix window] display]; /* redraw the whole window so extra */ [ [symbolMatrix window] display]; /* columns get erased */ [ [legendForm window] display]; } if ( (oldn == 0) && (newn > 1) ) { /* can only happen first time */ for (j=1; j<newn; j++) { [lineText addCol]; [symbolText addCol]; [lineMatrix addCol]; if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */ [ [lineMatrix cellAt:0 :j] setState:1]; /* highlight 1st row new column -- this occurs automatically */ [symbolMatrix addCol]; if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */ [ [symbolMatrix cellAt:0 :j] setState:1]; /* highlighting of 1st row new column occurs automatically */ sprintf(formtitle, "Curve %d:", j+1); [legendForm addEntry:formtitle]; sprintf(formtitle, "Curve %d", j+1); [legendForm setStringValue:formtitle at:j]; [legendForm drawCellAt:j]; sprintf(formtitle, "%d", j+1); [[lineText cellAt:0 :j] setStringValue:formtitle]; [[symbolText cellAt:0 :j] setStringValue:formtitle]; } [lineText sizeToCells]; /* Titles on Columns */ [symbolText sizeToCells]; /* Titles on Columns */ [lineMatrix sizeToCells]; [symbolMatrix sizeToCells]; [legendForm sizeToFit]; [lineText display]; [symbolText display]; [lineMatrix display]; /* don't need to redraw the window here */ [symbolMatrix display]; [legendForm display]; } if ( (oldn != 0) && (oldn < newn) ) { /* must add columns */ for (j=0; j<oldn; j++) { if ( [ [lineMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */ [ [lineMatrix cellAt:0 :j] setState:1]; if ( [ [symbolMatrix cellAt:0 :j] state ] != 1 ) /* seems necessary */ [ [symbolMatrix cellAt:0 :j] setState:1]; for (k=1; k<N_LINE_STYLES; k++) { [ [lineMatrix cellAt:k :j] setState:0]; } for (k=1; k<N_SYMBOL_STYLES; k++) { [ [symbolMatrix cellAt:k :j] setState:0]; } sprintf(formtitle, "Curve %d", j+1); [legendForm setStringValue:formtitle at:j]; [legendForm drawCellAt:j]; sprintf(formtitle, "%d", j+1); [[lineText cellAt:0 :j] setStringValue:formtitle]; [[symbolText cellAt:0 :j] setStringValue:formtitle]; } for (j=oldn; j<newn; j++) { [lineText addCol]; [symbolText addCol]; [lineMatrix addCol]; [ [lineMatrix cellAt:0 :j] setState:1]; /* highlighting of 1st row new column occurs automatically */ [symbolMatrix addCol]; [ [symbolMatrix cellAt:0 :j] setState:1]; /* highlighting of 1st row new column occurs automatically */ sprintf(formtitle, "Curve %d:", j+1); [legendForm addEntry:formtitle]; sprintf(formtitle, "Curve %d", j+1); [legendForm setStringValue:formtitle at:j]; [legendForm drawCellAt:j]; sprintf(formtitle, "%d", j+1); [[lineText cellAt:0 :j] setStringValue:formtitle]; [[symbolText cellAt:0 :j] setStringValue:formtitle]; } [legendTitle setStringValue:"Legend" at:0]; [lineText sizeToCells]; /* Titles on Columns */ [symbolText sizeToCells]; /* Titles on Columns */ [lineMatrix sizeToCells]; [symbolMatrix sizeToCells]; [legendForm sizeToFit]; [lineText display]; /* Titles on Columns */ [symbolText display]; /* Titles on Columns */ [lineMatrix display]; /* don't need to redraw the window here */ [symbolMatrix display]; [legendForm display]; } [lineThickness setState:1 at:0:0]; /* reset line thickness to thin */ [symbolSize setState:1 at :0:2]; /* reset symbol size to medium */ [symbolSize display]; [lineThickness display]; return self; } // Go through the data set and find values for datamin.x, // datamax.x, datamin.y, datamax.y - findMinAndMax { if (x) { int i, j; datamin.x = datamax.x = x[0]; for (i = 1; i < npoints; i++) { if (x[i] < datamin.x) datamin.x = x[i]; else if (x[i] > datamax.x) datamax.x = x[i]; } datamin.y = datamax.y = *(*(y+0)+0); for (j = 0; j < ncurves; j++) { for (i = 0; i < npoints; i++) { if (*(*(y+j)+i) < datamin.y) datamin.y = *(*(y+j)+i); else if (*(*(y+j)+i) > datamax.y) datamax.y = *(*(y+j)+i); } } } // reset min and max here (may want to change the placement of this) [self resetXmin:datamin.x]; [self resetXmax:datamax.x]; [self resetXinc:(datamax.x - datamin.x)/5.0]; [self resetYmin:datamin.y]; [self resetYmax:datamax.y]; [self resetYinc:(datamax.y - datamin.y)/5.0]; return self; } // Use the OpenPanel object to get a filename - open:sender { char const *fileTypes[2] = {0,0}; // this type is all ASCII files (?) // char const *fileTypes[2] = {"xyp",0}; // this would be only files with an xyp extension char fname[1024]; id openPanel = [OpenPanel new]; if ([openPanel runModalForTypes:fileTypes]) { strncpy(fname, [openPanel filename], 1024); [self openFile:fname]; } return self; } - openFile:(char *)dataFile { FILE *dataStream; if ((dataStream = fopen(dataFile, "r")) == NULL) { NXRunAlertPanel("Open", "Cannot open %s", "OK", NULL, NULL, dataFile); return self; } if ([self readData:dataStream] == 0) { NXRunAlertPanel("Read", "Couldn't read any data from %s", "OK", NULL, NULL, dataFile); fclose(dataStream); return self; } fclose(dataStream); [canvas initializeLegendBox]; [self findMinAndMax]; /* Check for linear or log on x and y axes */ [self checkLinLog]; [self drawPlot:self]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.