// Gravity2019A A. Kozma, T. Lichtenberg, D. Parson // FPDC-funded research project, interactive gravity simulator // for planetarium dome, initial rough draft. import java.lang.Math ; // use double for precision import java.util.LinkedList ; // collection of planets. Should they sort() for display? // Use unitCircle to compute ellipses for planetary orbits. // Stretch space using scale(X,Y) and rotate(angularOffset), // followed by modelX() and modelY(), to find points in an // elliptical orbit. Enclose all of that it pushMatrix()/ // popMatrix(). Use doubles for precision. // for a demo of how this works. int stepsInUnitCircle = 1440 ; // for now. Angles are in radians. double [] unitCircleX = new double [ stepsInUnitCircle ]; double [] unitCircleY = new double [ stepsInUnitCircle ]; int xcenterOfOrbits, ycenterOfOrbits ; // default width/2, height/2 LinkedList bodies = new LinkedList(); void setup() { fullScreen(P3D); // Use P3D for modelX(), modelY() to work. xcenterOfOrbits = width/2 ; ycenterOfOrbits = height/2 ; background(0); rectMode(CENTER); // align all possibilities to center ellipseMode(CENTER); imageMode(CENTER); shapeMode(CENTER); colorMode(HSB, 360, 100, 100, 100); // saturate for the dome for (int unitstep = 0 ; unitstep < unitCircleX.length ; unitstep++) { double angle = unitstep * TWO_PI / unitCircleX.length ; // sin(angle) = y / hypotenuse = y / 1.0 for unit circle // cos(angle) = x / hypotenuse = x / 1.0 for unit circle unitCircleX[unitstep] = Math.cos(angle); unitCircleY[unitstep] = Math.sin(angle); // println("SETUP angle " + angle + ", unitCircleX[unitstep] " + unitCircleX[unitstep] + ", unitCircleY[unitstep] = " + unitCircleY[unitstep]); } /* Planet(int Hue, int Sat, int Bright, float mass, float size, float speed, float directionx, float directiony, float locationx, float locationy, boolean isInOrbit, int stepInOrbit, float xOrbitDistanceFromSun, float yOrbitDistanceFromSun, float orbitAngle) { */ // make them dark to test the ellipse show-thru bug. bodies.add(new Planet(60, 50, 50, 1.0, 20.0, 2.0, 1.0, 1.0, 1.0, 1.0, true, 0, width/6, height/8, HALF_PI / -10.0)); bodies.add(new Planet(180, 50, 50, 1.0, 32.0, -.75, 1.0, 1.0, 1.0, 1.0, true, stepsInUnitCircle/4, width/4, height/5, HALF_PI / -20.0)); } void draw() { background(0); pushMatrix(); translate(xcenterOfOrbits, ycenterOfOrbits); // 0,0 is at the heart of the sun // Normally, do real application stuff here. for (SolarBody body : bodies) { body.display(); body.move(); } popMatrix(); // Apply clipping circle, then end of draw() } // Maybe the models as a Planet? Leave open options for alternatives. interface SolarBody { // Show it in its trajectory or orbit. void display() ; // Advance it in its trajectory or orbit. void move(); } class Planet implements SolarBody { int H, S, B ; // Document unit of measure for these in a later version that does real orbits. float mass ; float size ; // size is a function of mass & density. Compute density? float speed ; // pixels per draw() for now. Will change to app units later. float directionx ; // when approaching an orbit in a line float directiony ; // when approaching an orbit in a line float locationx ; // when approaching an orbit in a line OR already in orbit float locationy ; // when approaching an orbit in a line OR already in orbit boolean isInOrbit ; float stepInOrbit ; // step in unitCircle[0..unitCircle.length-1], with fractional part float xOrbitDistanceFromSun ; float yOrbitDistanceFromSun ; float orbitAngle ; // When it attains orbit, speed is in steps within orbital ellipse, should be an int? Planet(int hue, int saturation, int brightness, float mass, float size, float speed, float directionx, float directiony, float locationx, float locationy, boolean isInOrbit, int stepInOrbit, float xOrbitDistanceFromSun, float yOrbitDistanceFromSun, float orbitAngle) { H = hue ; S = saturation ; B = brightness ; this.mass = mass ; this.size = size ; this.speed = speed ; this.directionx = directionx ; this.directiony = directiony ; this.locationx = locationx ; this.locationy = locationy ; this.isInOrbit = isInOrbit ; this.stepInOrbit = stepInOrbit ; this.xOrbitDistanceFromSun = xOrbitDistanceFromSun ; this.yOrbitDistanceFromSun = yOrbitDistanceFromSun ; this.orbitAngle = orbitAngle ; if (isInOrbit) { int sio = (int)(stepInOrbit); pushMatrix(); rotate(orbitAngle); // Must rotate before scale to warp space. scale(xOrbitDistanceFromSun, yOrbitDistanceFromSun); translate((float)unitCircleX[sio], (float)unitCircleY[sio]); this.locationx = modelX(0, 0, 0) /*- xcenterOfOrbits*/ ; // model() is in global coord this.locationy = modelY(0, 0, 0) /*- ycenterOfOrbits*/ ; // our 0,0 is middle of display popMatrix(); } } void display() { colorMode(HSB, 360, 100, 100, 100); pushMatrix(); pushMatrix(); // trace orbit around center of display // orbit shows up within planet circle unless you move it back a little translate(0, 0, -2); rotate(orbitAngle); // Must rotate before scale to warp space. scale(xOrbitDistanceFromSun, yOrbitDistanceFromSun); noFill(); stroke(0,0,99,50); strokeWeight(4.0/min(xOrbitDistanceFromSun, yOrbitDistanceFromSun)); ellipse(0, 0, 2, 2); popMatrix(); translate(locationx, locationy); // x,y location relative to the star fill(H,S,B,99); // test half brightness // fill(H, 50, 50, 99); noStroke(); circle(0, 0, size); // sphere(size); popMatrix(); strokeWeight(1); } void move() { if (isInOrbit) { if (speed >= 0) { stepInOrbit = stepInOrbit+speed ; } else { stepInOrbit = stepInOrbit+unitCircleX.length+speed ; // step backwards } // Since stepInOrbit is a float, we cannot just use % for wraparound. while (stepInOrbit >= unitCircleX.length) { stepInOrbit -= unitCircleX.length ; } while (stepInOrbit < 0) { stepInOrbit += unitCircleX.length ; } int sio = int(stepInOrbit); pushMatrix(); rotate(orbitAngle); // Must rotate before scale to warp space. scale(xOrbitDistanceFromSun, yOrbitDistanceFromSun); translate((float)unitCircleX[sio], (float)unitCircleY[sio]); locationx = modelX(0, 0, 0) - xcenterOfOrbits ; // model() is in global coord locationy = modelY(0, 0, 0) - ycenterOfOrbits ; // our 0,0 is middle of display //println("DEBUG stepInOrbit = " + stepInOrbit + ", unitCircleX[stepInOrbit] = " + unitCircleX[stepInOrbit] + ", unitCircleY[stepInOrbit] " + unitCircleX[stepInOrbit]); popMatrix(); } else { println("Non-orbiting trajectories not yet supported."); exit(); } } }