home *** CD-ROM | disk | FTP | other *** search
- #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
-