This is CubeView.m in view mode; [Download] [Up]
/* Generated by Interface Builder */ #import "CubeView.h" #import "dotAt.h" #import <stdlib.h> #import <strings.h> #import <stdio.h> #import <dpsclient/wraps.h> #import <dpsclient/dpsNeXT.h> #import <appkit/graphics.h> #import <appkit/Control.h> #import <appkit/Form.h> #import <appkit/OpenPanel.h> #import <appkit/Pasteboard.h> #import <appkit/Application.h> #import <math.h> #define MAXLINE 1000 #define MAXNUM 10000 #define rad_to_deg (180./M_PI) extern id NXApp; @implementation CubeView + newFrame:(const NXRect *) frameRect { self = [super newFrame: frameRect]; [self initialize]; return self; } + new; { self = [super new]; [self initialize]; return self; } static char angle_buffer[20]; - showError:(char *)errorMessage { NXRunAlertPanel("Error", errorMessage, "OK", NULL, NULL); } - initialize { toshow = (datapoints **) calloc(100, sizeof(datapoints *)); max_path = 200; path = (float *) calloc(100, sizeof(float)); dot_offset[0] = 2.5 * 2 / bounds.size.width; dot_offset[1] = 2.5 * 2 / bounds.size.height; [self setDrawSize:(NXCoord) 2:(NXCoord) 2]; [self setDrawOrigin:(NXCoord) -1:(NXCoord) -1]; showCube = YES; PSonly = NO; vm = [AzimuthMat new]; openReq = [OpenPanel new]; // establish the ops array and // bounding box for DPSDoUserPath() ops[0] = dps_moveto; ops[1] = 32 + 15; ops[2] = dps_lineto; boundingBox[0] = bounds.origin.x; boundingBox[1] = bounds.origin.y; boundingBox[2] = bounds.origin.x + bounds.size.width; boundingBox[3] = bounds.origin.y + bounds.size.height; // create the template plotting dot dot = [Bitmap newFromMachO:"cubedot.tiff"]; dotgstate = [[dot window] gState]; // force a rescaling [self reScale:self]; } - printPSCode:sender { PSonly = YES; [self display]; [super printPSCode:self]; PSonly = NO; [self display]; } - copy:sender /* code contributed by Dan McCreary of NeXT */ { id pb = [NXApp pasteboard]; /* global Pasteboard object */ NXStream *st; /* stream to collect data in */ char *data; /* actual data buffer */ int length; /* length of data */ int maxLength; /* (not used here) */ /* To see how to use the pasteboard */ /* see page 10-33 of the SysRefMan */ PSonly = YES; [self display]; /* declare that we will supply a */ /* single type of data: PostScript */ [pb declareTypes:&NXPostScriptPboard num:1 owner:self]; /* get a stream which writes to memory */ st = NXOpenMemory( NULL, 0, NX_WRITEONLY ); /* write PostScript code for this view into the stream */ [self copyPSCodeInside:NULL to:st]; /* get actual data buffer from stream */ NXGetMemoryBuffer( st, &data, &length, &maxLength ); /* write PostScript data to pasteboard */ [pb writeType:NXPostScriptPboard data:data length:length]; /* deallocate stream, including its buffer */ NXCloseMemory( st, NX_FREEBUFFER ); PSonly = NO; [self display]; return self; } -(BOOL)acceptsFirstResponder { /* make this view accept first */ return YES; /* responder so it will understand copy */ } -resignFirstResponder { return self; } - setAngleDisplay:anObject { AngleDisplay = anObject; return self; } - setDistanceSlider:anObject { DistanceSlider = anObject; return self; } - setThetaSlider:anObject { ThetaSlider = anObject; return self; } - setPhiSlider:anObject { PhiSlider = anObject; return self; } - Reset:sender { [vm setTheta:0.]; [ThetaSlider setFloatValue:0.]; [vm setPhi:0.]; [PhiSlider setFloatValue:0.]; [vm setdist:2.0]; [DistanceSlider setFloatValue:-1/2.]; [self ShowAngles:sender]; [self display]; return self; } - ShowAngles:sender { sprintf(angle_buffer, "%6.2f", rad_to_deg*[vm getTheta:self]); [AngleDisplay setStringValue:angle_buffer at:0]; sprintf(angle_buffer, "%6.2f", -rad_to_deg*[vm getPhi:self]); [AngleDisplay setStringValue:angle_buffer at:1]; sprintf(angle_buffer, "%6.2f", [vm getdist:self]); [AngleDisplay setStringValue:angle_buffer at:2]; } - setTheta:sender { [vm setTheta:[sender floatValue]]; [self display]; return self; } - setPhi:sender { [vm setPhi:-[sender floatValue]]; [self display]; return self; } - setdist:sender { float dist; dist = [sender floatValue]; if (dist < 1.8) { [self showError: "Distance must be greater than 1.8"]; return self; } [vm setdist:dist]; [DistanceSlider setFloatValue:-1./dist]; [self display]; return self; } - setinvdist:sender { [vm setinvdist:-[sender floatValue]]; [self display]; return self; } - setTheta_degrees:sender { float angle = [sender floatValue]/rad_to_deg; [vm setTheta:angle]; [ThetaSlider setFloatValue:angle]; [self display]; return self; } - setPhi_degrees:sender { float angle = [sender floatValue]/rad_to_deg; [vm setPhi:-angle]; [PhiSlider setFloatValue:angle]; [self display]; return self; } - toggleCube:sender { showCube = showCube ? NO : YES; [self display]; return self; } - toggleAxes:sender { showAxes = showAxes ? NO : YES; [self display]; return self; } - reScale:sender { float maxval[3], minval[3], limits[6], *fpt; datapoints **all_lines = toshow, *thisline; short int i, count; if (*all_lines == (datapoints *) NULL) { /* no data - set to defaults */ limits[0] = limits[1] = limits[2] = 0.; limits[3] = limits[4] = limits[5] = 1.; [self setlimits:limits]; return self; } for(i = 0; i < 3; i++) minval[i] = maxval[i] = *((*all_lines)->displayed[i]); while (thisline = *all_lines++) { for(i = 0; i < 3; i++) { count = thisline->npts; fpt = thisline->displayed[i]; while (count--) { if (*fpt < minval[i]) minval[i] = *fpt; if (*fpt > maxval[i]) maxval[i] = *fpt; fpt++; } } } for(i = 0; i < 3; i++) { if (minval[i] >= maxval[i]) minval[i] = maxval[i] - 1; limits[i] = minval[i] - 0.035*(maxval[i] - minval[i]); limits[i + 3] = maxval[i] + 0.035*(maxval[i] - minval[i]); } [self setlimits:limits]; return self; } - openData:sender { const char *fileName; const char *const ext[4] = {"dat", "data", "3d", NULL}; if([openReq runModalForTypes:ext] && (fileName = [openReq filename])) [self readData:fileName]; else [self showError:"No file chosen or could not open file"]; return self; } static void float_copy (register int n, register float * to, register int to_inc, register float * from, register int from_inc) { if (n > 0) while (n--) { *to = *from; to += to_inc; from += from_inc; } } - (BOOL) readData:(const char *)filename { FILE *input; float *scratch, *fpt; char thisline[MAXLINE], *cpt, c; long int count, ncols, nchars, nlines, expected_cols; datapoints **all_data = toshow, *thesedata; scratch = (float *) calloc(MAXNUM, sizeof(float)); if((input = fopen(filename, "r")) == NULL) { sprintf(thisline, "Unable to open file %s", filename); [self showError:thisline]; return NO; } /* release existing data */ while ((thesedata = *all_data) != (datapoints *) NULL) { free(thesedata->displayed); count = 0; while(thesedata->all[count] != (float *) NULL) { free(thesedata->all[count]); count++; } free(thesedata->all); free(thesedata); *all_data++ = (datapoints *) NULL; } all_data = toshow; /* read new data */ fgets(thisline, MAXLINE, input); while (!feof(input)) { if(!sscanf(thisline, " %1s ", &c)) { sprintf(thisline, "Unable to read a specification from %s", filename); [self showError:thisline]; return NO; } switch(c) { case 'N': case 'n': case 'L': case 'l': case 'P': case 'p': case 'B': case 'b': fgets(thisline, MAXLINE, input); /* load a new line */ break; default: sprintf(thisline, "the beginning of %s doesn't look like a specification", filename); [self showError:thisline]; return NO; } cpt = thisline; fpt = scratch; ncols = 0; while(sscanf(cpt, "%f %n", fpt, &nchars) == 1) { cpt += nchars; ncols++; fpt++; } if (ncols == 0) { sprintf(thisline, "First line of %s does not contain numeric data", filename); [self showError:thisline]; return NO; } /* digest the rest of the lines */ expected_cols = ncols; nlines = 1; while(fgets(thisline, MAXLINE, input) != NULL) { cpt = thisline; ncols = 0; while(sscanf(cpt, "%f %n", fpt, &nchars) == 1) { cpt += nchars; ncols++; fpt++; } if (!ncols) break; nlines++; if (ncols != expected_cols) { sprintf(thisline, "Expected %d values but got %d values at line %d\n", expected_cols, ncols, nlines); [self showError:thisline]; return NO; } } /* create the datapoints structure and */ /* store the values */ thesedata = *all_data++ = (datapoints *) malloc(sizeof(datapoints)); switch(c) { case 'N': case 'n': thesedata->type = NEITHER; break; case 'L': case 'l': thesedata->type = LINES; break; case 'P': case 'p': thesedata->type = POINTS; break; case 'B': case 'b': thesedata->type = BOTH; break; } thesedata->all = (float **)calloc((size_t) expected_cols + 1, (size_t) sizeof(float *)); for(ncols = 0; ncols < expected_cols; ncols++) { thesedata->all[ncols] = (float *)calloc((size_t) nlines, sizeof(float)); float_copy(nlines, thesedata->all[ncols], 1, scratch + ncols, expected_cols); } thesedata->all[expected_cols] = (float *)NULL; /* make sure path is large enough */ if (2*nlines > max_path) realloc(path, (2*nlines)*sizeof(float)); thesedata->npts = nlines; memmove(thesedata->displayed = (float **) calloc(3, sizeof(float *)), thesedata->all, 3 * sizeof(float *)); } [self reScale:self]; free(scratch); fclose(input); [self display]; return YES; } static int x_seq[] = {0,3,3,0,0,0,3,3,0,0,3,3,3,3,0,0}; static int y_seq[] = {1,1,4,4,1,1,1,4,4,1,1,1,4,4,4,4}; static int z_seq[] = {2,2,2,2,2,5,5,5,5,5,5,2,2,5,5,2}; -setlimits:(float *)newlimits { int i, n, tickdir; float tick, width; for (n = 0; n < 16; n++) { /* create cube */ cube[0][n] = newlimits[x_seq[n]]; cube[1][n] = newlimits[y_seq[n]]; cube[2][n] = newlimits[z_seq[n]]; } for (n = 0; n < 54; n++) { /* create axes */ axes[0][n] = newlimits[0]; axes[1][n] = newlimits[1]; axes[2][n] = newlimits[2]; } for (i = 0; i < 3; i++) { tickdir = (i == 0) ? 1 : 0; tick = 0.03 * (newlimits[tickdir + 3] - newlimits[tickdir]); width = newlimits[i + 3] - newlimits[i]; n = 18 * i; axes[i][n+1] = axes[i][n+2] = axes[i][n+3] = axes[i][n+4] = newlimits[i] + 0.25 * width; axes[i][n+5] = axes[i][n+6] = axes[i][n+7] = axes[i][n+8] = newlimits[i] + 0.5 * width; axes[i][n+9] = axes[i][n+10] = axes[i][n+11] = axes[i][n+12] = newlimits[i] + 0.75 * width; axes[i][n+13] = axes[i][n+17] = newlimits[i] + 0.87 * width; axes[i][n+14] = axes[i][n+16] = newlimits[i] + 0.84 * width; axes[i][n+15] = newlimits[i] + width; axes[tickdir][n+2] = axes[tickdir][n+6] = axes[tickdir][n+10] = axes[tickdir][n+14] = newlimits[tickdir] + tick; axes[tickdir][n+3] = axes[tickdir][n+7] = axes[tickdir][n+11] = axes[tickdir][n+16] = newlimits[tickdir] - tick; } [vm setlimits:newlimits]; [self Reset:self]; return self; } - drawSelf:(NXRect*)r :(int)c { int n; float *fpt; datapoints **all_lines = toshow, *thisline; NXEraseRect(&bounds); PSsetgray(NX_BLACK); PSsetlinewidth(0.0); if (showCube) { ops[1] = 32 + 16 - 1; DPSDoUserPath ([vm as_DPSpath :16 :cube[0] :cube[1] :cube[2] :path], 32, dps_float, ops, 3, boundingBox, dps_ustroke); } if (showAxes) { ops[1] = 32 + 54 - 1; DPSDoUserPath ([vm as_DPSpath :54 :axes[0] :axes[1] :axes[2] :path], 108, dps_float, ops, 3, boundingBox, dps_ustroke); } while((thisline = *all_lines++) != (datapoints *) NULL) { if (thisline->type & 0x1) { /* draw the line */ ops[1] = thisline->npts + 32 - 1; DPSDoUserPath([vm as_DPSpath :thisline->npts :(thisline->displayed)[0] :(thisline->displayed)[1] :(thisline->displayed)[2] :path], 2*(thisline->npts), dps_float, ops, 3, boundingBox, dps_ustroke); } if (thisline->type & 0x2) { /* draw points */ if (PSonly) dotAtPSonly([vm as_DPSpath :thisline->npts :(thisline->displayed)[0] :(thisline->displayed)[1] :(thisline->displayed)[2] :path], 2 *(thisline->npts), *dot_offset); else dotAt([vm as_DPSpath :thisline->npts :(thisline->displayed)[0] :(thisline->displayed)[1] :(thisline->displayed)[2] :path offset:dot_offset], 2 * (thisline->npts), dotgstate); } } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.