import codedraw.CodeDraw; /** * This class represents celestial bodies like stars, planets, asteroids, etc... */ public class Body { private double mass; private Vector massCenter; // position of the mass center. private Vector currentMovement; public Body(double mass, Vector massCenter, Vector currentMovement) { this.mass = mass; this.massCenter = massCenter; this.currentMovement = currentMovement; } public Body(double mass, Vector massCenter) { this(mass, massCenter, new Vector()); } public Body(Body other) { this(other.mass, new Vector(other.massCenter), new Vector(other.currentMovement)); } /** * Returns the distance between the mass centers of this body and the specified body 'b'. */ public double distanceTo(Body b) { return massCenter.distanceTo(b.massCenter); } /** * Returns a vector representing the gravitational force exerted by 'b' on this body. * The gravitational Force F is calculated by F = G*(m1*m2)/(r*r), with m1 and m2 being the * masses of the objects interacting, r being the distance between the centers of the masses * and G being the gravitational constant. * Hint: see simulation loop in Simulation.java to find out how this is done. */ public Vector gravitationalForce(Body b) { Vector direction = b.massCenter.minus(massCenter); double distance = direction.length(); if (distance == 0) return new Vector(); direction.normalize(); double force = Simulation.G * mass * b.mass / (distance * distance); return direction.times(force); } /** * Moves this body to a new position, according to the specified force vector 'force' exerted * on it, and updates the current movement accordingly. * (Movement depends on the mass of this body, its current movement and the exerted force.) * Hint: see simulation loop in Simulation.java to find out how this is done. */ public void move(Vector force) { // F = m*a -> a = F/m Vector newPosition = massCenter.plus(force.times(1.0 / mass)).plus(currentMovement); // new minus old position. Vector newMovement = newPosition.minus(massCenter); // update body state massCenter = newPosition; currentMovement = newMovement; } /** * Returns the approximate radius of this body. * (It is assumed that the radius r is related to the mass m of the body by r = m ^ 0.5, * where m and r measured in solar units.) */ public double radius() { return SpaceDraw.massToRadius(mass); } /** * Return the mass of the Body. */ public double mass() { return mass; } public Vector massCenter() { return massCenter; } public void update(Body b) { double combinedMass = this.mass + b.mass; this.massCenter = this.massCenter.times(this.mass / combinedMass).plus(b.massCenter.times(b.mass / combinedMass)); this.mass = combinedMass; } public boolean collidesWith(Body body) { return this.distanceTo(body) < this.radius() + body.radius(); } /** * Returns a new body that is formed by the collision of this body and 'b'. The impulse * of the returned body is the sum of the impulses of 'this' and 'b'. */ public Body merge(Body body) { double totalMass = this.mass + body.mass; return new Body( totalMass, this.massCenter.times(this.mass).plus(body.massCenter.times(body.mass)).times(1.0 / totalMass), this.currentMovement.times(this.mass).plus(body.currentMovement.times(body.mass)).times(1.0 / totalMass) ); } /** * Draws the body to the specified canvas as a filled circle. * The radius of the circle corresponds to the radius of the body * (use a conversion of the real scale to the scale of the canvas as * in 'Simulation.java'). * Hint: call the method 'drawAsFilledCircle' implemented in 'Vector'. */ public void draw(CodeDraw cd) { cd.setColor(SpaceDraw.massToColor(mass)); massCenter.drawAsFilledCircle(cd, SpaceDraw.massToRadius(mass)); } /** * Returns a string with the information about this body including * mass, position (mass center) and current movement. Example: * "5.972E24 kg, position: [1.48E11,0.0,0.0] m, movement: [0.0,29290.0,0.0] m/s." */ @Override public String toString() { return String.format( "%g kg, position: %s m, movement: %s m/s.", mass, massCenter.toString(), currentMovement.toString() ); } }