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.