home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Modules / BackSpaceModules / Source / PlanetView / PlanetView.m < prev    next >
Encoding:
Text File  |  1992-08-05  |  6.4 KB  |  290 lines

  1. #import <appkit/NXImage.h>
  2. #import <appkit/Panel.h>
  3.  
  4. #import <appkit/appkit.h>
  5. #import <dpsclient/wraps.h>
  6. #import <libc.h>
  7. #import <math.h>
  8. #import <appkit/Slider.h>
  9.  
  10. #import "PlanetView.h"
  11. #import "Thinker.h"
  12. #import "PlanetWraps.h"
  13.  
  14. @implementation PlanetView
  15.  
  16. - createUniverse
  17. {
  18.     int i;
  19.     float dx, xsum=0, dy, ysum=0;
  20.  
  21.     numplanets = initialNumplanets;
  22.     for (i = 0; i < initialNumplanets; i++)
  23.         [self newPlanet:&myplanets[i] :bounds.size.width: bounds.size.height];
  24.  
  25.     for (i = 0; i < initialNumplanets-1; i++)
  26.     {
  27.         dx = randBetween(-3, 3);
  28.         dy = randBetween(-3, 3);
  29.         myplanets[i].xv = dx;
  30.         myplanets[i].yv = dy;
  31.         xsum+=dx;
  32.         ysum+=dy;
  33.     }
  34.  
  35.     // zero out the energy in the universe
  36.     myplanets[i].xv = -xsum;
  37.     myplanets[i].yv = -ysum;
  38.  
  39.     iterationCount = 0;
  40.     return self;
  41. }
  42.  
  43. - initFrame:(const NXRect *)frameRect
  44. {
  45.     [super initFrame:frameRect];
  46.  
  47.     PLinitPlanetDefs();
  48.  
  49.     initialNumplanets = PLANETS;
  50.     gfactor = 1;
  51.     myplanets = (aplanet *) malloc(MAXPLANETS * sizeof(aplanet));
  52.  
  53.     [self createUniverse];
  54.  
  55.     return self;
  56. }
  57.  
  58. - setGFactor:sender
  59. {
  60.     gfactor = [sender floatValue];
  61.     return self;
  62. }
  63.  
  64. - oneStep
  65. {
  66.     int i, j;
  67.     double xfactor, yfactor;
  68.  
  69.     if (++iterationCount > MAXITERATIONS)
  70.     {
  71.         [self createUniverse];
  72.         [self display];
  73.         iterationCount = 0;
  74.     }
  75.  
  76.     for (i=0; i < numplanets; i++)
  77.     {
  78.         // erase each
  79.         PSsetgray(0);
  80.         PLdrawPlanet(myplanets[i].x, myplanets[i].y,
  81.             SPACEDIST * sqrt(myplanets[i].gravity));
  82.  
  83.         // move each
  84.         myplanets[i].x += myplanets[i].xv;
  85.         myplanets[i].y += myplanets[i].yv;
  86.  
  87.         [self constrainPosition:i];
  88.  
  89.         // draw each
  90.         PSsetgray(1);
  91.         PLdrawPlanet(myplanets[i].x, myplanets[i].y,
  92.             SPACEDIST * sqrt(myplanets[i].gravity));
  93.  
  94.          [[self window] flushWindow];
  95.  
  96.         // perturb each
  97.         for (j = i + 1; j < numplanets; j++)
  98.         {
  99.             float dist = sqrt(SQR(deltaX(i, j)) + SQR(deltaY(i, j))) / SPACEDIST;
  100.  
  101.             myplanets[i].xv += (xfactor = deltaX(i, j) / 
  102.                 (SQR(dist) * dist)) * myplanets[j].gravity * gfactor;
  103.             myplanets[i].yv += (yfactor = deltaY(i, j) / 
  104.                 (SQR(dist) * dist)) * myplanets[j].gravity * gfactor;
  105.  
  106.             myplanets[j].xv -= xfactor * myplanets[i].gravity * gfactor;
  107.             myplanets[j].yv -= yfactor * myplanets[i].gravity * gfactor;
  108.  
  109.             // check for collisions
  110.             if (dist * SPACEDIST < sqrt(myplanets[i].gravity)
  111.                     + sqrt(myplanets[j].gravity))
  112.             {
  113.                 [self merge:i :j];
  114.                 continue;
  115.             }
  116.         }
  117.     }
  118.  
  119.     return self;
  120. }
  121.  
  122. - constrainPosition:(int)i
  123. {
  124.     if (myplanets[i].x < bounds.origin.x - 20)
  125.     {
  126.         myplanets[i].x = bounds.origin.x + bounds.size.width + 10;
  127.         myplanets[i].xv *= 0.95;
  128.     }
  129.     else if (myplanets[i].x > bounds.origin.x + bounds.size.width + 20)
  130.     {
  131.         myplanets[i].x = bounds.origin.x - 10;
  132.         myplanets[i].xv *= 0.95;
  133.     }
  134.  
  135.     if (myplanets[i].y < bounds.origin.y - 20)
  136.     {
  137.         myplanets[i].y = bounds.origin.y + bounds.size.height + 10;
  138.         myplanets[i].yv *= 0.95;
  139.     }
  140.     else if (myplanets[i].y > bounds.origin.y + bounds.size.height + 20)
  141.     {
  142.         myplanets[i].y = bounds.origin.y - 10;
  143.         myplanets[i].yv *= 0.95;
  144.     }
  145.     return self;
  146. }
  147.  
  148. - constrainGravity:(int)i
  149. {
  150.     if (myplanets[i].gravity < 1) myplanets[i].gravity = 1;
  151.     else if (myplanets[i].gravity > MAXGRAVITY) myplanets[i].gravity = MAXGRAVITY;
  152.     return self;
  153. }
  154.  
  155. - setNumberPlanets:sender
  156. {
  157.     initialNumplanets = numplanets = [sender intValue];
  158.  
  159.     [numplanetTextField setIntValue:numplanets];
  160.  
  161.     [self createUniverse];
  162.     [self display];
  163.  
  164.     return self;
  165. }
  166.  
  167. - merge:(int)planetA :(int)planetB
  168. {
  169.     float tgrav = myplanets[planetA].gravity + myplanets[planetB].gravity;
  170.     PSsetgray(0);
  171.     PLdrawPlanet(myplanets[planetA].x, myplanets[planetA].y,
  172.             SPACEDIST * sqrt(myplanets[planetA].gravity));
  173.  
  174.     myplanets[planetA].xv = (myplanets[planetA].xv * myplanets[planetA].gravity + 
  175.         myplanets[planetB].xv * myplanets[planetB].gravity) / tgrav;
  176.     myplanets[planetA].yv = (myplanets[planetA].yv * myplanets[planetA].gravity + 
  177.         myplanets[planetB].yv * myplanets[planetB].gravity) / tgrav;
  178.  
  179.     myplanets[planetA].gravity = tgrav;
  180.     [self constrainGravity:planetA];
  181.  
  182.     PSsetgray(0);
  183.     PLdrawPlanet(myplanets[planetB].x, myplanets[planetB].y,
  184.             SPACEDIST * sqrt(myplanets[planetB].gravity));
  185.     PSsetgray(1);
  186.     PLdrawPlanet(myplanets[planetA].x, myplanets[planetA].y,
  187.             SPACEDIST * sqrt(myplanets[planetA].gravity));
  188.     [[self window] flushWindow];
  189.  
  190.     myplanets[planetB] = myplanets[--numplanets];
  191.  
  192.     if ((myplanets[planetA].gravity > ((initialNumplanets * DEFAULTGRAV) * .65))
  193.         || ((randBetween(0,1) <= 0.15) && 
  194.         (myplanets[planetA].gravity > ((initialNumplanets * DEFAULTGRAV) * .33))))
  195.         [self blowPlanet:planetA];
  196.  
  197.     if (numplanets == 1) iterationCount = MAXITERATIONS - 200;
  198.  
  199.     return self;
  200.  
  201.  
  202. }
  203.  
  204. - newPlanet:(aplanet *) newplanet :(float)width :(float)height
  205. {
  206.     newplanet->x = randBetween(0,width);
  207.     newplanet->y = randBetween(0, height);
  208.     newplanet->gravity = DEFAULTGRAV;
  209.     newplanet->xv = 0;
  210.     newplanet->yv = 0;
  211.     return self;
  212. }
  213.  
  214. - blowPlanet:(int)planetNum
  215. {
  216.     int      i, newplanets, newplanetnum;
  217.     double   newxd, newyd, newradius;
  218.     float oldgrav = myplanets[planetNum].gravity;
  219.     float xc, yc;
  220.  
  221.     newplanets = MIN(oldgrav, MAXPLANETS-numplanets) - 1;
  222.     newradius = newplanets * 1.5;
  223.     newplanetnum = MIN((numplanets + newplanets), MAXPLANETS);
  224.  
  225.     for (i = numplanets; i < newplanetnum; i++)
  226.     {
  227.         myplanets[i] = myplanets[planetNum];
  228.         newxd = (xc = sin(PI * 2 * (i - numplanets) / (newplanets))) * newradius;
  229.         newyd = (yc = cos(PI * 2 * (i - numplanets) / (newplanets))) * newradius;
  230.  
  231.         myplanets[i].x += newxd;
  232.         myplanets[i].y += newyd;
  233.         myplanets[i].gravity = oldgrav / (newplanets+1);
  234.         myplanets[i].xv += xc * SPACEDIST * randBetween(2.85,3.5);
  235.         myplanets[i].yv += yc * SPACEDIST * randBetween(2.85,3.5);
  236.         [self constrainGravity:i];
  237.     }
  238.  
  239.     PSsetgray(0);
  240.     PLdrawPlanet(myplanets[planetNum].x, myplanets[planetNum].y,
  241.             SPACEDIST * sqrt(myplanets[planetNum].gravity));
  242.  
  243.     myplanets[planetNum].gravity = oldgrav / (newplanets+1);
  244.     [self constrainGravity:planetNum];
  245.     numplanets = newplanetnum;
  246.     return self;
  247.  
  248. }
  249.  
  250. - (const char *)windowTitle
  251. {    return "Orbital Simulation";
  252. }
  253.  
  254. - inspector:sender
  255. {
  256.     char buf[MAXPATHLEN];
  257.     
  258.     if (!inspectorPanel)
  259.     {
  260.         sprintf(buf,"%s/planet.nib",[sender moduleDirectory:"Planet"]);
  261.         [NXApp loadNibFile:buf owner:self withNames:NO];
  262.  
  263.         [numplanetSlider setIntValue:numplanets];
  264.         [numplanetTextField setIntValue:numplanets];
  265.     }
  266.     return inspectorPanel;
  267. }
  268.  
  269. - sizeTo:(NXCoord)width :(NXCoord)height
  270. {
  271.     [super sizeTo:width :height];
  272.     [self createUniverse];
  273.     return self;
  274. }
  275.  
  276. - drawSelf:(const NXRect *)rects :(int)rectCount
  277. {
  278.     if (!rects || !rectCount) return self;
  279.     
  280.     PSsetgray(NX_BLACK);
  281.     NXRectFill(rects);
  282.     return self;
  283. }
  284.  
  285. - (BOOL) useBufferedWindow;
  286. {    return YES;
  287. }
  288.  
  289. @end
  290.