/** * Simulate.java -- Simulate a set of moons * * By Bob Jenkins, July 1998 * Permission granted to use, reuse, rewrite this without notifying me. * * Enhancement requests: * -- There are two types of simulation problems: taking too big a step, * and a jitter that repeats every 8 points. * - If the step size is too big for an accurate simulation, cut the * step size in half. Preserve position, velocity, energy. I don't * know how to do this. * - If the jitter gets big, use a irreversible step function that * smooths out the jitter. Use a step function that is the average of * two symmetric step functions. I don't know how to detect that this * needs to be done, as opposed to needing to reduce the step size. * -- Provide an interface that reports the positions of objects at a given * time. Feed the positions of the planets as parameters, and provide * a service giving the position of the planets at such-and-such a time. * -- Add relativity. C should be a parameter. * -- Add a solar wind (for specified objects). * -- Allow the camera position to be on some object. * -- Allow the screen to fill your monitor. * -- Add controls. Right-mouse button? Menus on mouse-down? Control panel? * -- Add controls for powered objects, like spacecraft. To accomplish an * instantaneous acceleration of x at time i, add 1/8th of x when * calculating positions i through i+7. That's exact. * -- Add everything you need to simulate spacecraft orbits accurately. * -- Speed up the simulation when there are many objects, but preserve the * accuracy. * - 3D multipole method? Reportedly very slow, but accurate. * - Barnes-Hut octtree? Reportedly very inaccurate. * - Different simulation speed for different objects? For the solar * system and spacecraft, this seems most promising to me. */ import java.awt.*; import java.lang.Math; import java.util.*; public final class Simulate { Moon luna[]; // the set of moons being simulated Moon showluna[]; // same moons, but in display order Point temp; // working memory; int counter; // how many iterations have we done? int display_count; // how many displays have we done? int work; // how much work to do per step int firstmass; // first moon with mass double inc; // how big a step to take double init_energy; // initial total energy of the system double display_num; // number being displayed boolean display_energy; // should energy error be displayed? boolean no_perspective; // should we not display perspective? double energy; // total energy of the system, should be constant // some big local variables used by every moon BVector polyIn; BVector poly; Point polyAccel[]; Point polyPosition[]; // initialize the simulation public Simulate(Moon luna[], double inc, int work, boolean energy, boolean noperspective) { this.temp = new Point(0.0, 0.0, 0.0); this.luna = luna; this.counter = 0; this.work = work; this.inc = inc; this.display_energy = energy; this.no_perspective = noperspective; this.poly = new BVector(Moon.dejit.length); this.polyIn = new BVector(Moon.dejit.length); this.polyAccel = new Point[Moon.dejit.length]; this.polyPosition = new Point[Moon.dejit.length+2]; for (int i=0; i luna[j].m) { Moon luna2 = luna[i]; luna[i] = luna[j]; luna[j] = luna2; } } } // find the first moon with mass for (firstmass = 0; firstmass < luna.length && luna[firstmass].m == 0; ++firstmass) ; // initialize the moons for display this.showluna = new Moon[luna.length]; for (int i=0; i q.history) counter = q.history; // fill nblah array with the reverse of the blah array // we would have to negate velocity if we tracked it for (int j=0; j Moon.history) counter = Moon.history; // make up the new history for (int i=0; i da*inc*inc/256.0 && da != 0.0) { // System.out.println("dejitter "+q.id+" "+dp/(da*inc*inc)+" "+ // q.ov[q.head]+" "+q.ov[q.head+1]); q.dejitter(rescale, inc, polyIn, poly, polyAccel, polyPosition); } } } // move all moons forward by one time increment final public void move() { for (int i=0; i 2) { bg.fillOval(luna[i].screenx, luna[i].screeny, q, q); } else { bg.fillRect(luna[i].screenx, luna[i].screeny, luna[i].screenx+q, luna[i].screeny+q); } } } // draw new moons public void draw(Graphics bg, Eye camera) { ++display_count; // Find new positions in screen coordinates for (int i=0; i q.r) { int r = (int)(camera.magnification*q.r/e.z); if (r < 1) r = 1; q.screenr = r; q.screenx = camera.mapx(e)-r/2; q.screeny = camera.mapy(e)-r/2; if (q.screenx+r < 0 || q.screeny+r < 0 || q.screenx > camera.centerx+camera.centerx || q.screeny > camera.centery+camera.centery) { q.screenx = q.screeny = q.screenr = 0; } } else { q.screenx = q.screeny = q.screenr = 0; } } // sort so closest moons are drawn last // this is about linear, not quadratic, because already about ordered for (int i=showluna.length; --i > 0;) { for (int j=i+1; --j > 0 && showluna[j].peye.z > showluna[j-1].peye.z; ) { Moon q = showluna[j]; showluna[j] = showluna[j-1]; showluna[j-1]=q; } } // draw the moons if (display_energy) { bg.setColor(Color.black); bg.drawString(display_count-1+" "+display_num, 2, 12); if ((display_count & 0x3f) == 0) { display_num = (FindEnergy() - init_energy)/init_energy; } bg.setColor(Color.white); bg.drawString(display_count+" "+display_num, 2, 12); } for (int i=0; i 2) { bg.setColor(showluna[i].c); bg.fillOval(showluna[i].screenx, showluna[i].screeny, q, q); } else if (q > 0) { bg.setColor(showluna[i].c); bg.fillRect(showluna[i].screenx, showluna[i].screeny, q, q); } } } }