This is Henon.m in view mode; [Download] [Up]
/* Generated by Interface Builder */ #import "Henon.h" @implementation Henon // This function is called by the timedEntry, every n seconds. The argument // senderObject contains the oject that initiated the timed entry (Henon) void iterate(DPSTimedEntry iter, double now, void *senderObject) { id henonObject; henonObject = (id) senderObject; // Retrieve the Henon object [henonObject iteration]; // And call its method iteration. } - setHenonView:anObject { henonView = anObject; A = 1.4; B = 0.3; speed = 0.25; [[henonView window] setBackgroundGray:0.]; // Sets the background to black return self; } - setMidiControl:anObject { midiControl = anObject; return self; } - setParaCelA:anObject { paraCelA = anObject; [paraCelA setFloatValue:1.4 at:0]; return self; } - setParaCelB:anObject { paraCelB = anObject; [paraCelB setFloatValue:0.3 at:0]; return self; } - setParaSlidA:anObject { paraSlidA = anObject; return self; } - setParaSlidB:anObject { paraSlidB = anObject; return self; } - setA:sender { A = [sender floatValue]; // This method work for both the cell [paraCelA setFloatValue:A at:0]; // and the slider objects. Cool! [paraSlidA setFloatValue:A]; // Make sure the slider and the cell return self; // show the same values! } - setB:sender { B = [sender floatValue]; [paraCelB setFloatValue:B at:0]; // Idem! [paraSlidB setFloatValue:B]; return self; } - start:sender { // This is to adjust the display view, in case we resized the window... [[[henonView window] contentView] getBounds:&viewBounds]; [henonView setFrame:&viewBounds]; if(start) { DPSRemoveTimedEntry(iter); // Stops the timed entry start = 0; return self; } if(display == 0) { iter = DPSAddTimedEntry(speed,iterate,self,20); // Start timed Entry start = 1; // Every speed seconds, iterate will be called if(initSet) // with self as argument (self = Henon object) { // "20" is the priority level initSet = 0; X = x_init; Y = y_init; } [[henonView window] setTitle:"Henon Map; X/Y Plan"]; return self; } if(display) // If we want bifurcation. { [self clear:self]; [[henonView window] setTitle:"Bifurcation Diagram; X/A Plan"]; [self bifurcation]; } return self; } - setInitial:sender { switch([sender tag]) { case 0 : x_init = [sender floatValueAt:0]; break ; case 1 : x_init = [sender floatValueAt:1]; break ; default : printf("Error during initial values setup\n"); break; } initSet = 1; return self; } - setSpeed:sender { speed = [sender floatValue]; if(start) { DPSRemoveTimedEntry(iter); // When you change the speed, you must // replace the timed entry... iter = DPSAddTimedEntry(speed,iterate,self,20); } return self; } - setDisplay:sender { display = [[sender selectedCell] tag]; return self; // if tag==0, Henon map, if tag==1 bifurcation. } - clear:sender { [[[henonView window] contentView] getBounds:&viewBounds]; [henonView setFrame:&viewBounds]; // Readjust the View size... [henonView lockFocus]; // Before any Drawing! PSsetgray(0.) ; // Color = black NXRectFill(&viewBounds); // Fill the view [henonView unlockFocus]; // After the drawing return self; // The window is retained only (see its attributes in Intervace Builder). // If it was buffered, we would need to flush it to actually see what we draw. // This could be done by: [[henonView window] flushWindow] } - stableOnly:sender { stable = [[sender selectedCell] tag]; return self; } - iteration { float aux_x, aux_y; int queueSize; queueSize = [midiControl getSizeOfQueue]; // Retrieve the size of the if(queueSize > 20) return self; // Midi queue. aux_x = Y - A * X * X + 1; aux_y = B * X; X = aux_x; Y = aux_y; [henonView lockFocus]; //Must lockFocus on the view BEFORE any drawing PSsetgray(1.0) ; // or drawing set-up! PSsetlinewidth (1.); PSmoveto(viewBounds.size.width * (X+1.5)/3.,viewBounds.size.height * (Y+.5)); PSlineto(viewBounds.size.width * (X+1.5)/3,viewBounds.size.height * (Y+.5)); PSstroke(); // These are common PS functions, easy to use, but slow. Don't forget to // PSstroke() after you draw! [henonView unlockFocus]; [midiControl send:X:Y:speed]; } -bifurcation { int i,j,N; float aux_x, aux_y; float A_aux,Height; short *data; char *ops; short boundingBox[4] = {0,0,10000,10000}; short dot_loc; NXEvent *stopEvent; // We use the DPSDoUserPath() function to make the drawing really fast. // This encapsulates several PS operations into one, much faster, shot. // We calculate 150 points, put them in the data array, and draw all of them // at the same time. // By the same token, the event record is checked for "mouse down" events for // fast abort... data = (short*)calloc(600,sizeof(short)); // The coordinates array ops = (char*)calloc(300,sizeof(short)); // The PS operators array for(i=0;i<150;i++) { ops[2*i] = dps_moveto; // The PS operator array is simply ops[2*i+1] = dps_lineto; // moveto,lineto,moveto etc... } N = (int) viewBounds.size.width; Height = viewBounds.size.height/3.; [henonView lockFocus]; // Don't forget this! PSsetgray(1.0) ; PSsetlinewidth (1.); if(stable == 0) for(i=0,A_aux=0;i<N;i++,A_aux += 1.4/N) { for(j=0,X=Y=0;j<150;j++) { aux_x = Y - A_aux * X * X + 1; aux_y = B * X; X = aux_x; Y = aux_y; dot_loc = Height * (X+1.5); data[4*j] = data[4*j+2] = i; data[4*j+1] = data[4*j+3] = dot_loc; // The data array contains: x0,y0,x0,y0,x1,y1,x1,y1,etc... // The first couple is for moveto, the second for lineto. We get // then a simple point... } DPSDoUserPath(data,600,dps_short,ops,300,boundingBox,dps_ustroke); stopEvent = [NXApp getNextEvent:(NX_LMOUSEDOWNMASK) waitFor:0. threshold:NX_MODALRESPTHRESHOLD]; // To abort, detect mouse down if(stopEvent != 0) break; // Events and break! } else // Stable display for(i=0,A_aux=0;i<N;i++,A_aux += 1.4/N) { for(j=0,X=Y=0;j<150;j++) { aux_x = Y - A_aux * X * X + 1; aux_y = B * X; X = aux_x; Y = aux_y; } // calculate 150 first points for(j=0;j<150;j++) { aux_x = Y - A_aux * X * X + 1; aux_y = B * X; X = aux_x; Y = aux_y; dot_loc = Height * (X+1.5); data[4*j] = data[4*j+2] = i; // then display the next 150 data[4*j+1] = data[4*j+3] = dot_loc; } DPSDoUserPath(data,600,dps_short,ops,300,boundingBox,dps_ustroke); stopEvent = [NXApp getNextEvent:(NX_LMOUSEDOWNMASK) waitFor:0. threshold:NX_MODALRESPTHRESHOLD]; // To abort, detect mouse down if(stopEvent != 0) break; // Events and break! } [henonView unlockFocus]; // Don't forget that either! return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.