Gravity Simulator

Gravity Simulator

Github repository

Context

Which student in computer science hasn't been tempted to create their own physics engine? In this case I think I've postponed it enough and decided to actually go for it.

Numerous examples of particle engines can be found all over the place. Sincerely I'm not claiming that this is the best possible implementation (or even one that is good to follow). The driver for this post is rather the part I found most difficult of them all, and that's how to transpose simple Trigonometry within the world of a Java program. I've found myself struggling with this problem in the past and I didn't find anyting useful online. One could argue it's to simple a problem to post anything about it.

Let's take a step back and see the Physics behind this simulator. Gravity is the force between two objects and it's decsribed by Issac Newton's Law of Universal Gravitational. Newton had this idea of the attraction between two object but in order for this idea to be captured in a formula there was still somethign missing. It wasn't until later on that Henry Cavendish made the formula possible by experimentally verifying the gravitational constant G. F = G\frac{Mm}{r^2} where G: the Gravitational constant (6.67408 * 10 ^-8 \frac{Nm^2}{kg^2}),
M: the mass of the more massive object (kg),
m: the mass of the less massive object (kg),
r:the distance between the two masses (m)

The nice thing about forces is that they don't interact with each other, so we can simply calculate all the forces between objects and then add them together to find the resulting force of each ojbect at each given time. After we have calculated the force that is acting on an object we can easily calculate the acceleration at each given moment, again thanks to our old friend Newton and his second law of motion. Which gives us a quantitative relationship between the object's mass, acceleration and the net force acting on it.

\vec{F} = m\vec{a}

Here's where I found my first objstacle in the world of Java there is no class that would allow me to add vectors. When I'm talking about vectors, I realise it's a bit of an overloaded term in programming languages (see C++), but in their purely mathematical definition of it. A vector has a magnitude and and a direction. Now all good so far I've got my acceleration ready but how do I tarnslate that into velocity? We have a formula for it.

a = \frac{du}{dt}
Looking at the formula and then the ceiling and the other way around...
So in order to overcome this obstacle of adding vectors in java I decided to use my knowledge from high school and replace the net acceleration with it's constituents in a previously decided 2d plane. So I'd have the acceleration in the axis I called x and the one perpendicluar to it in axis y. So the formulas become a_x = acos(\theta),a_y = asin(\theta), where \theta is the angle that the vector forms with the x axis and a the magnitude of the acceleration (note it doens't have the vector symbol above it). and in order to calculate the constituent velocities we can use v_x = a_{x}t,v_y = a_{y}t, where t the time in seconds. In my case I have assumed one second intervals to make my life easier.

The feeling of success didn't last long because one of my own requirements was that I could also draw all vectors, should ever I want to. The second obstacle was how to go back to the net vector by combining the constituents. In order to find the magnitude (easy part) you can refer back to a few thousand years to our other old friend Pythagoras and his right triangle theorem, which we can use since by definition our two constituents are always parallel. \alpha^2 = \beta^2 + \gamma^2 But what about the resulting angle? I initially thought it wasn't going to be an issue but then i realised that I had little idea of how atan works in java only giving results in the range (-\frac{\pi}{2}, \frac{\pi}{2}). Thanks to my ignorance I went through tons of clauses and cases in order to end up with the simplest one. Then I realised the simplest rule

public double calculateAngle(double x, double y) {
 if( x > 0 ) {
  return - atan( y/x );
 }
 return atan( y/x );
}

I was mindblown by the simlicity of the solution compared to the head-squeezing moments I'd passed through that evening.

Processing visualisation

As this is getting rather big I will not get into deatails as in to how to run Processing scetches as Standalone java apps I have made another post and a bootstrap github project just for that. But I couldn't not put the code here.



//...
final GravitySimulator sim = new GravitySimulator();
final List<Trio<Float>> colours = new ArrayList<>();

@Override
public void settings() {
 size(900, 600);
}

@Override
public void setup() {
 super.setup();
 background(20, 30, 30);

 addParticle(new Particle(100000, -100, 10));
 //... Adding more particles.

}

@Override
public void draw() {
 background(20, 30, 30);

 ellipseMode(CENTER);

 List<Particle> particles = sim.getParticles();
 stroke(200);
 for (int i = 0; i < particles.size(); i++) {
  Trio<Float> colour = colours.get(i);
  fill(colour._1, colour._2, colour._3);
  Particle p = particles.get(i);
  float x = width * .5f + (float) p.x;
  float y = height * .5f + (float) p.y;

  circle(x, y, max((float) p.mass * 0.000001f, 2.0f));
 }

 delay(40);
}

After a bit of trial and error trying to give style to this visualisation I ended up with this...

Sample of the Gravity Simulator output

Comments

Because a blog without feedback would be lifeless, for any ideas corrections or any kind of comment, I'm happy to have your e-mails at hello@nikpappas.com