From 155dc7400171f48c62967e03878f47fd555353d6 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Thu, 17 Mar 2022 13:53:41 +0100 Subject: [PATCH] Finished AB 1 --- src/Aufgabe1Test.java | 5 -- src/Body.java | 61 ++++++++------ src/Simulation.java | 183 +++++++----------------------------------- src/Vector3.java | 74 ++++++++++------- 4 files changed, 107 insertions(+), 216 deletions(-) diff --git a/src/Aufgabe1Test.java b/src/Aufgabe1Test.java index 7fbcbb1..5a1f465 100644 --- a/src/Aufgabe1Test.java +++ b/src/Aufgabe1Test.java @@ -6,8 +6,6 @@ public class Aufgabe1Test { //test classes Body and Vector3 - /* TODO: remove this line - // create two bodies Body sun = new Body(1.989e30,new Vector3(0,0,0),new Vector3(0,0,0)); Body earth = new Body(5.972e24,new Vector3(-1.394555e11,5.103346e10,0),new Vector3(-10308.53,-28169.38,0)); @@ -29,9 +27,6 @@ public class Aufgabe1Test { // check distance to target position (should be zero) testValue(earth.distanceTo(targetPositionEarth), 0); - - // TODO: remove this line */ - } public static void testComparison(Object first, Object second, boolean expected) { diff --git a/src/Body.java b/src/Body.java index 55996a2..6a37e5b 100644 --- a/src/Body.java +++ b/src/Body.java @@ -1,22 +1,20 @@ import codedraw.CodeDraw; -import java.awt.*; - // This class represents celestial bodies like stars, planets, asteroids, etc.. public class Body { + private double mass; + private Vector3 massCenter; // position of the mass center. + private Vector3 currentMovement; - //TODO: change modifiers. - public double mass; - public Vector3 massCenter; // position of the mass center. - public Vector3 currentMovement; - - //TODO: define constructor. + public Body(double mass, Vector3 massCenter, Vector3 currentMovement) { + this.mass = mass; + this.massCenter = massCenter; + this.currentMovement = currentMovement; + } // Returns the distance between the mass centers of this body and the specified body 'b'. public double distanceTo(Body b) { - - //TODO: implement method. - return 0; + return massCenter.distanceTo(b.massCenter); } // Returns a vector representing the gravitational force exerted by 'b' on this body. @@ -25,9 +23,11 @@ public class Body { // and G being the gravitational constant. // Hint: see simulation loop in Simulation.java to find out how this is done. public Vector3 gravitationalForce(Body b) { - - //TODO: implement method. - return null; + Vector3 direction = b.massCenter.minus(massCenter); + double distance = direction.length(); + 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 @@ -35,25 +35,33 @@ public class Body { // (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(Vector3 force) { + // F = m*a -> a = F/m + Vector3 newPosition = massCenter.plus(force.times(1.0 / mass)).plus(currentMovement); - //TODO: implement method. + // new minus old position. + Vector3 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() { - - //TODO: implement method. - return 0d; + return SpaceDraw.massToRadius(mass); } // 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 b) { - - //TODO: implement method. - return null; + double mass = this.mass + b.mass; + return new Body( + mass, + massCenter.times(this.mass).plus(b.massCenter.times(b.mass)).times(1.0 / mass), + currentMovement.times(this.mass).plus(b.currentMovement.times(b.mass)).times(1.0 / mass) + ); } // Draws the body to the specified canvas as a filled circle. @@ -62,17 +70,18 @@ public class Body { // in 'Simulation.java'). // Hint: call the method 'drawAsFilledCircle' implemented in 'Vector3'. public void draw(CodeDraw cd) { - - //TODO: implement method. + 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." public String toString() { - - //TODO: implement method. - return ""; + return String.format( + "%f kg, position: %s m, movement: %s m/s.", + mass, massCenter.toString(), currentMovement.toString() + ); } } diff --git a/src/Simulation.java b/src/Simulation.java index 531190a..8cc8449 100644 --- a/src/Simulation.java +++ b/src/Simulation.java @@ -3,7 +3,14 @@ import codedraw.CodeDraw; import java.awt.*; import java.util.Random; -// TODO: insert answers to questions (Zusatzfragen) in 'Aufgabenblatt1.md' as comment. +// 1. Datenkapselung: Zusammenfassen von Methoden und Variablen zu Einheit. +// Die `static` Methoden von `Simulation` nach `Body` oder `Vector3` verschieben. + +// 2. Data Hiding: Verstecken vor Zugriffen von außen. +// Attribute von `Body` und `Vector3` auf `private` setzen. + +// 3. Beim Methodenaufruf steht links vom `.` entweder das Objekt, oder die Klasse. In Java beginnen Variablennamen +// üblicherweise mit Kleinbuchstaben und Klassennamen üblicherweise mit einem Großbuchstaben. // Simulates the formation of a massive solar system. public class Simulation { @@ -32,9 +39,6 @@ public class Simulation { // The main simulation method using instances of other classes. public static void main(String[] args) { - - //TODO: change implementation of this method according to 'Aufgabenblatt1.md'. - // simulation CodeDraw cd = new CodeDraw(); Body[] bodies = new Body[NUMBER_OF_BODIES]; @@ -43,18 +47,19 @@ public class Simulation { Random random = new Random(2022); for (int i = 0; i < bodies.length; i++) { - bodies[i] = new Body(); - bodies[i].mass = Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length; // kg - bodies[i].massCenter = new Vector3(); - bodies[i].currentMovement = new Vector3(); - bodies[i].massCenter.x = 0.2 * random.nextGaussian() * AU; - bodies[i].massCenter.y = 0.2 * random.nextGaussian() * AU; - bodies[i].massCenter.z = 0.2 * random.nextGaussian() * AU; - - bodies[i].currentMovement.x = 0 + random.nextGaussian() * 5e3; - bodies[i].currentMovement.y = 0 + random.nextGaussian() * 5e3; - bodies[i].currentMovement.z = 0 + random.nextGaussian() * 5e3; - + bodies[i] = new Body( + Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length, // kg + new Vector3( + 0.2 * random.nextGaussian() * AU, + 0.2 * random.nextGaussian() * AU, + 0.2 * random.nextGaussian() * AU + ), + new Vector3( + 0 + random.nextGaussian() * 5e3, + 0 + random.nextGaussian() * 5e3, + 0 + random.nextGaussian() * 5e3 + ) + ); } double seconds = 0; @@ -66,9 +71,8 @@ public class Simulation { // merge bodies that have collided for (int i = 0; i < bodies.length; i++) { for (int j = i + 1; j < bodies.length; j++) { - if (distance(bodies[j].massCenter, bodies[i].massCenter) < - SpaceDraw.massToRadius(bodies[j].mass) + SpaceDraw.massToRadius(bodies[i].mass)) { - bodies[i] = merge(bodies[i], bodies[j]); + if (bodies[j].distanceTo(bodies[i]) < bodies[j].radius() + bodies[i].radius()) { + bodies[i] = bodies[i].merge(bodies[j]); Body[] bodiesOneRemoved = new Body[bodies.length - 1]; for (int k = 0; k < bodiesOneRemoved.length; k++) { bodiesOneRemoved[k] = bodies[k < j ? k : k + 1]; @@ -88,8 +92,8 @@ public class Simulation { forceOnBody[i] = new Vector3(); // begin with zero for (int j = 0; j < bodies.length; j++) { if (i != j) { - Vector3 forceToAdd = gravitationalForce(bodies[i], bodies[j]); - forceOnBody[i] = plus(forceOnBody[i], forceToAdd); + Vector3 forceToAdd = bodies[i].gravitationalForce(bodies[j]); + forceOnBody[i] = forceOnBody[i].plus(forceToAdd); } } } @@ -97,7 +101,7 @@ public class Simulation { // for each body (with index i): move it according to the total force exerted on it. for (int i = 0; i < bodies.length; i++) { - move(bodies[i], forceOnBody[i]); + bodies[i].move(forceOnBody[i]); } // show all movements in the canvas only every hour (to speed up the simulation) @@ -107,7 +111,7 @@ public class Simulation { // draw new positions for (Body body : bodies) { - draw(cd, body); + body.draw(cd); } // show new positions @@ -117,137 +121,4 @@ public class Simulation { } } - - //TODO: remove static methods below. - - // Draws a body in the 'cd' canvas showing a projection onto the (x,y)-plane. The body's mass - // center coordinates and its radius are transformed into canvas coordinates. The color of - // the body corresponds to the temperature of the body, assuming the relation of mass and - // temperature of a main sequence star. - // The canvas is assumed to show a quadratic SECTION_SIZE x SECTION_SIZE - // section of space centered arround (x, y) = (0, 0). - public static void draw(CodeDraw cd, Body b) { - - cd.setColor(SpaceDraw.massToColor(b.mass)); - drawAsFilledCircle(cd, b.massCenter, SpaceDraw.massToRadius(b.mass)); - - } - - // Draws a filled circle in the 'cd' canvas unsing the (x,y)-coordinates of 'center' - // Coordinates and 'radius' are transformed into canvas coordinates. The canvas is assumed - // to show a quadratic SECTION_SIZE x SECTION_SIZE projection of space centered arround (x, y) = - // (0, 0). - public static void drawAsFilledCircle(CodeDraw cd, Vector3 center, double radius) { - double x = cd.getWidth() * (center.x + Simulation.SECTION_SIZE / 2) / Simulation.SECTION_SIZE; - double y = cd.getWidth() * (center.y + Simulation.SECTION_SIZE / 2) / Simulation.SECTION_SIZE; - radius = cd.getWidth() * radius / Simulation.SECTION_SIZE; - cd.fillCircle(x, y, Math.max(radius, 1.5)); - } - - // Returns a vector representing the gravitational force exerted by body 'b2' on body 'b1'. - // 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. - // To calculate the force exerted on b1, simply multiply the normalized vector pointing from b1 to b2 with the - // calculated force. - public static Vector3 gravitationalForce(Body b1, Body b2) { - - Vector3 direction = minus(b2.massCenter, b1.massCenter); - double distance = length(direction); - normalize(direction); - double force = G * b1.mass * b2.mass / (distance * distance); - return times(direction, force); - } - - // Returns a new body that is formed by the collision of 'b1' and 'b2'. The impulse - // of the returned body is the sum of the impulses of 'b1' and 'b2'. - public static Body merge(Body b1, Body b2) { - - Body result = new Body(); - result.mass = b1.mass + b2.mass; - result.massCenter = times(plus(times(b1.massCenter, b1.mass), times(b2.massCenter, - b2.mass)), - 1 / result.mass); - result.currentMovement = - times(plus(times(b1.currentMovement, b1.mass), times(b2.currentMovement, b2.mass)), - 1.0 / result.mass); - return result; - } - - // Move the body 'b' according to the 'force' excerted on it. - public static void move(Body b, Vector3 force) { - Vector3 newPosition = plus( - plus(b.massCenter, - times(force, 1 / b.mass) - // F = m*a -> a = F/m - ), - b.currentMovement - ); - - // new minus old position. - Vector3 newMovement = minus(newPosition, b.massCenter); - - // update body state - b.massCenter = newPosition; - b.currentMovement = newMovement; - } - - // Returns the norm of v1-v2. - public static double distance(Vector3 v1, Vector3 v2) { - - double dX = v1.x - v2.x; - double dY = v1.y - v2.y; - double dZ = v1.z - v2.z; - - return Math.sqrt(dX * dX + dY * dY + dZ * dZ); - } - - // Returns v1+v2. - public static Vector3 plus(Vector3 v1, Vector3 v2) { - - Vector3 result = new Vector3(); - result.x = v1.x + v2.x; - result.y = v1.y + v2.y; - result.z = v1.z + v2.z; - - return result; - } - - // Returns v1-v2. - public static Vector3 minus(Vector3 v1, Vector3 v2) { - - Vector3 result = new Vector3(); - result.x = v1.x - v2.x; - result.y = v1.y - v2.y; - result.z = v1.z - v2.z; - - return result; - } - - // Returns v*d. - public static Vector3 times(Vector3 v, double d) { - - Vector3 result = new Vector3(); - result.x = v.x * d; - result.y = v.y * d; - result.z = v.z * d; - - return result; - } - - // Returns the norm of 'v'. - public static double length(Vector3 v) { - - return distance(v, new Vector3()); // distance to origin. - } - - // Normalizes the specified vector 'v': changes the length of the vector such that its length - // becomes one. The direction and orientation of the vector is not affected. - public static void normalize(Vector3 v) { - - double length = length(v); - v.x /= length; - v.y /= length; - v.z /= length; - } - } diff --git a/src/Vector3.java b/src/Vector3.java index 3ed8f45..61228a4 100644 --- a/src/Vector3.java +++ b/src/Vector3.java @@ -1,73 +1,89 @@ import codedraw.CodeDraw; -import java.awt.*; - // This class represents vectors in a 3D vector space. public class Vector3 { - //TODO: change modifiers. - public double x; - public double y; - public double z; + private double x; + private double y; + private double z; - //TODO: define constructor. + public Vector3() { + this(0); + } + + public Vector3(double v) { + this(v, v, v); + } + + public Vector3(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } // Returns the sum of this vector and vector 'v'. public Vector3 plus(Vector3 v) { - - //TODO: implement method. - return null; + Vector3 result = new Vector3(); + result.x = x + v.x; + result.y = y + v.y; + result.z = z + v.z; + return result; } // Returns the product of this vector and 'd'. public Vector3 times(double d) { - - //TODO: implement method. - return null; + Vector3 result = new Vector3(); + result.x = x * d; + result.y = y * d; + result.z = z * d; + return result; } // Returns the sum of this vector and -1*v. public Vector3 minus(Vector3 v) { - - //TODO: implement method. - return null; + Vector3 result = new Vector3(); + result.x = x - v.x; + result.y = y - v.y; + result.z = z - v.z; + return result; } // Returns the Euclidean distance of this vector // to the specified vector 'v'. public double distanceTo(Vector3 v) { - - //TODO: implement method. - return -1d; + double dX = x - v.x; + double dY = y - v.y; + double dZ = z - v.z; + return Math.sqrt(dX * dX + dY * dY + dZ * dZ); } // Returns the length (norm) of this vector. public double length() { - - //TODO: implement method. - return 0; + return distanceTo(new Vector3()); } // Normalizes this vector: changes the length of this vector such that it becomes 1. // The direction and orientation of the vector is not affected. public void normalize() { - - //TODO: implement method. + double length = length(); + x /= length; + y /= length; + z /= length; } // Draws a filled circle with a specified radius centered at the (x,y) coordinates of this vector // in the canvas associated with 'cd'. The z-coordinate is not used. public void drawAsFilledCircle(CodeDraw cd, double radius) { - - //TODO: implement method. + double x = cd.getWidth() * (this.x + Simulation.SECTION_SIZE / 2) / Simulation.SECTION_SIZE; + double y = cd.getWidth() * (this.y + Simulation.SECTION_SIZE / 2) / Simulation.SECTION_SIZE; + radius = cd.getWidth() * radius / Simulation.SECTION_SIZE; + cd.fillCircle(x, y, Math.max(radius, 1.5)); } // Returns the coordinates of this vector in brackets as a string // in the form "[x,y,z]", e.g., "[1.48E11,0.0,0.0]". public String toString() { - - //TODO: implement method. - return ""; + return String.format("[%f,%f,%f]", x, y, z); } }