This is PlanetView.m in view mode; [Download] [Up]
#import <appkit/NXImage.h> #import <appkit/Panel.h> #import <appkit/appkit.h> #import <dpsclient/wraps.h> #import <libc.h> #import <math.h> #import <appkit/Slider.h> #import "PlanetView.h" #import "Thinker.h" #import "PlanetWraps.h" @implementation PlanetView - createUniverse { int i; float dx, xsum=0, dy, ysum=0; numplanets = initialNumplanets; for (i = 0; i < initialNumplanets; i++) [self newPlanet:&myplanets[i] :bounds.size.width: bounds.size.height]; for (i = 0; i < initialNumplanets-1; i++) { dx = randBetween(-3, 3); dy = randBetween(-3, 3); myplanets[i].xv = dx; myplanets[i].yv = dy; xsum+=dx; ysum+=dy; } // zero out the energy in the universe myplanets[i].xv = -xsum; myplanets[i].yv = -ysum; iterationCount = 0; return self; } - initFrame:(const NXRect *)frameRect { [super initFrame:frameRect]; PLinitPlanetDefs(); initialNumplanets = PLANETS; gfactor = 1; myplanets = (aplanet *) malloc(MAXPLANETS * sizeof(aplanet)); [self createUniverse]; return self; } - setGFactor:sender { gfactor = [sender floatValue]; return self; } - oneStep { int i, j; double xfactor, yfactor; if (++iterationCount > MAXITERATIONS) { [self createUniverse]; [self display]; iterationCount = 0; } for (i=0; i < numplanets; i++) { // erase each PSsetgray(0); PLdrawPlanet(myplanets[i].x, myplanets[i].y, SPACEDIST * sqrt(myplanets[i].gravity)); // move each myplanets[i].x += myplanets[i].xv; myplanets[i].y += myplanets[i].yv; [self constrainPosition:i]; // draw each PSsetgray(1); PLdrawPlanet(myplanets[i].x, myplanets[i].y, SPACEDIST * sqrt(myplanets[i].gravity)); [[self window] flushWindow]; // perturb each for (j = i + 1; j < numplanets; j++) { float dist = sqrt(SQR(deltaX(i, j)) + SQR(deltaY(i, j))) / SPACEDIST; myplanets[i].xv += (xfactor = deltaX(i, j) / (SQR(dist) * dist)) * myplanets[j].gravity * gfactor; myplanets[i].yv += (yfactor = deltaY(i, j) / (SQR(dist) * dist)) * myplanets[j].gravity * gfactor; myplanets[j].xv -= xfactor * myplanets[i].gravity * gfactor; myplanets[j].yv -= yfactor * myplanets[i].gravity * gfactor; // check for collisions if (dist * SPACEDIST < sqrt(myplanets[i].gravity) + sqrt(myplanets[j].gravity)) { [self merge:i :j]; continue; } } } return self; } - constrainPosition:(int)i { if (myplanets[i].x < bounds.origin.x - 20) { myplanets[i].x = bounds.origin.x + bounds.size.width + 10; myplanets[i].xv *= 0.95; } else if (myplanets[i].x > bounds.origin.x + bounds.size.width + 20) { myplanets[i].x = bounds.origin.x - 10; myplanets[i].xv *= 0.95; } if (myplanets[i].y < bounds.origin.y - 20) { myplanets[i].y = bounds.origin.y + bounds.size.height + 10; myplanets[i].yv *= 0.95; } else if (myplanets[i].y > bounds.origin.y + bounds.size.height + 20) { myplanets[i].y = bounds.origin.y - 10; myplanets[i].yv *= 0.95; } return self; } - constrainGravity:(int)i { if (myplanets[i].gravity < 1) myplanets[i].gravity = 1; else if (myplanets[i].gravity > MAXGRAVITY) myplanets[i].gravity = MAXGRAVITY; return self; } - setNumberPlanets:sender { initialNumplanets = numplanets = [sender intValue]; [numplanetTextField setIntValue:numplanets]; [self createUniverse]; [self display]; return self; } - merge:(int)planetA :(int)planetB { float tgrav = myplanets[planetA].gravity + myplanets[planetB].gravity; PSsetgray(0); PLdrawPlanet(myplanets[planetA].x, myplanets[planetA].y, SPACEDIST * sqrt(myplanets[planetA].gravity)); myplanets[planetA].xv = (myplanets[planetA].xv * myplanets[planetA].gravity + myplanets[planetB].xv * myplanets[planetB].gravity) / tgrav; myplanets[planetA].yv = (myplanets[planetA].yv * myplanets[planetA].gravity + myplanets[planetB].yv * myplanets[planetB].gravity) / tgrav; myplanets[planetA].gravity = tgrav; [self constrainGravity:planetA]; PSsetgray(0); PLdrawPlanet(myplanets[planetB].x, myplanets[planetB].y, SPACEDIST * sqrt(myplanets[planetB].gravity)); PSsetgray(1); PLdrawPlanet(myplanets[planetA].x, myplanets[planetA].y, SPACEDIST * sqrt(myplanets[planetA].gravity)); [[self window] flushWindow]; myplanets[planetB] = myplanets[--numplanets]; if ((myplanets[planetA].gravity > ((initialNumplanets * DEFAULTGRAV) * .65)) || ((randBetween(0,1) <= 0.15) && (myplanets[planetA].gravity > ((initialNumplanets * DEFAULTGRAV) * .33)))) [self blowPlanet:planetA]; if (numplanets == 1) iterationCount = MAXITERATIONS - 200; return self; } - newPlanet:(aplanet *) newplanet :(float)width :(float)height { newplanet->x = randBetween(0,width); newplanet->y = randBetween(0, height); newplanet->gravity = DEFAULTGRAV; newplanet->xv = 0; newplanet->yv = 0; return self; } - blowPlanet:(int)planetNum { int i, newplanets, newplanetnum; double newxd, newyd, newradius; float oldgrav = myplanets[planetNum].gravity; float xc, yc; newplanets = MIN(oldgrav, MAXPLANETS-numplanets) - 1; newradius = newplanets * 1.5; newplanetnum = MIN((numplanets + newplanets), MAXPLANETS); for (i = numplanets; i < newplanetnum; i++) { myplanets[i] = myplanets[planetNum]; newxd = (xc = sin(PI * 2 * (i - numplanets) / (newplanets))) * newradius; newyd = (yc = cos(PI * 2 * (i - numplanets) / (newplanets))) * newradius; myplanets[i].x += newxd; myplanets[i].y += newyd; myplanets[i].gravity = oldgrav / (newplanets+1); myplanets[i].xv += xc * SPACEDIST * randBetween(2.85,3.5); myplanets[i].yv += yc * SPACEDIST * randBetween(2.85,3.5); [self constrainGravity:i]; } PSsetgray(0); PLdrawPlanet(myplanets[planetNum].x, myplanets[planetNum].y, SPACEDIST * sqrt(myplanets[planetNum].gravity)); myplanets[planetNum].gravity = oldgrav / (newplanets+1); [self constrainGravity:planetNum]; numplanets = newplanetnum; return self; } - (const char *)windowTitle { return "Orbital Simulation"; } - inspector:sender { char buf[MAXPATHLEN]; if (!inspectorPanel) { sprintf(buf,"%s/planet.nib",[sender moduleDirectory:"Planet"]); [NXApp loadNibFile:buf owner:self withNames:NO]; [numplanetSlider setIntValue:numplanets]; [numplanetTextField setIntValue:numplanets]; } return inspectorPanel; } - sizeTo:(NXCoord)width :(NXCoord)height { [super sizeTo:width :height]; [self createUniverse]; return self; } - drawSelf:(const NXRect *)rects :(int)rectCount { if (!rects || !rectCount) return self; PSsetgray(NX_BLACK); NXRectFill(rects); return self; } - (BOOL) useBufferedWindow; { return YES; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.