Aufgabenblatt 1

This commit is contained in:
Anton Ertl
2022-03-14 11:12:15 +01:00
commit 9951270420
17 changed files with 1537 additions and 0 deletions

62
src/Aufgabe1Test.java Normal file
View File

@ -0,0 +1,62 @@
import java.awt.*;
public class Aufgabe1Test {
public static void main(String[] args) {
//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));
testValue(earth.distanceTo(sun), 1.4850000175024106E11);
testValue(sun.distanceTo(earth), 1.4850000175024106E11);
for(int i = 0; i < 3600*24; i++) {
Vector3 f1 = earth.gravitationalForce(sun);
Vector3 f2 = sun.gravitationalForce(earth);
earth.move(f1);
sun.move(f2);
}
// a dummy body to check the correct position after 24h of movement
Body targetPositionEarth = new Body(1, new Vector3(-1.403250141841815E11,
4.859202658875631E10, 0.0), new Vector3(0,0,0));
// 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) {
boolean real = first == second;
if (real == expected) {
System.out.println("Successful comparison");
} else {
System.out.println("Comparison NOT successful! Expected value: " + expected + " / Given value: " + real);
}
}
public static void testValue(Object given, Object expected) {
if (given == expected) {
System.out.println("Successful test");
} else {
System.out.println("Test NOT successful! Expected value: " + expected + " / Given value: " + given);
}
}
public static void testValue(double given, double expected) {
if (given < expected + (expected+1)/1e12 && given > expected - (expected+1)/1e12) {
System.out.println("Successful test");
} else {
System.out.println("Test NOT successful! Expected value: " + expected + " / Given value: " + given);
}
}
}

79
src/Body.java Normal file
View File

@ -0,0 +1,79 @@
import codedraw.CodeDraw;
import java.awt.*;
// This class represents celestial bodies like stars, planets, asteroids, etc..
public class Body {
//TODO: change modifiers.
public double mass;
public Vector3 massCenter; // position of the mass center.
public Vector3 currentMovement;
//TODO: define constructor.
// 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;
}
// 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 Vector3 gravitationalForce(Body b) {
//TODO: implement method.
return null;
}
// 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(Vector3 force) {
//TODO: implement method.
}
// 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;
}
// 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;
}
// 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 'Vector3'.
public void draw(CodeDraw cd) {
//TODO: implement method.
}
// 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 "";
}
}

253
src/Simulation.java Normal file
View File

@ -0,0 +1,253 @@
import codedraw.CodeDraw;
import java.awt.*;
import java.util.Random;
// TODO: insert answers to questions (Zusatzfragen) in 'Aufgabenblatt1.md' as comment.
// Simulates the formation of a massive solar system.
public class Simulation {
// gravitational constant
public static final double G = 6.6743e-11;
// one astronomical unit (AU) is the average distance of earth to the sun.
public static final double AU = 150e9; // meters
// one light year
public static final double LY = 9.461e15; // meters
// some further constants needed in the simulation
public static final double SUN_MASS = 1.989e30; // kilograms
public static final double SUN_RADIUS = 696340e3; // meters
public static final double EARTH_MASS = 5.972e24; // kilograms
public static final double EARTH_RADIUS = 6371e3; // meters
// set some system parameters
public static final double SECTION_SIZE = 2 * AU; // the size of the square region in space
public static final int NUMBER_OF_BODIES = 22;
public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms
// all quantities are based on units of kilogram respectively second and meter.
// 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];
Vector3[] forceOnBody = new Vector3[bodies.length];
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;
}
double seconds = 0;
// simulation loop
while (true) {
seconds++; // each iteration computes the movement of the celestial bodies within one second.
// 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]);
Body[] bodiesOneRemoved = new Body[bodies.length - 1];
for (int k = 0; k < bodiesOneRemoved.length; k++) {
bodiesOneRemoved[k] = bodies[k < j ? k : k + 1];
}
bodies = bodiesOneRemoved;
// since the body index i changed size there might be new collisions
// at all positions of bodies, so start all over again
i = -1;
j = bodies.length;
}
}
}
// for each body (with index i): compute the total force exerted on it.
for (int i = 0; i < bodies.length; i++) {
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);
}
}
}
// now forceOnBody[i] holds the force vector exerted on body with index i.
// 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]);
}
// show all movements in the canvas only every hour (to speed up the simulation)
if (seconds % (3600) == 0) {
// clear old positions (exclude the following line if you want to draw orbits).
cd.clear(Color.BLACK);
// draw new positions
for (Body body : bodies) {
draw(cd, body);
}
// show new positions
cd.show();
}
}
}
//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;
}
}

54
src/SpaceDraw.java Normal file
View File

@ -0,0 +1,54 @@
import java.awt.*;
public class SpaceDraw {
// Returns the approximate radius of a celestial body with the specified mass.
// (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 static double massToRadius(double mass) {
return Simulation.SUN_RADIUS * (Math.pow(mass / Simulation.SUN_MASS, 0.5));
}
// Returns the approximate color of a celestial body with the specified mass. The color of
// the body corresponds to the temperature of the body, assuming the relation of mass and
// temperature of a main sequence star.
public static Color massToColor(double mass) {
Color color;
if (mass < Simulation.SUN_MASS / 10) {
// not a star-like body below this mass
color = Color.LIGHT_GRAY;
} else {
// assume a main sequence star
color = SpaceDraw.kelvinToColor((int) (5500 * mass / Simulation.SUN_MASS));
}
return color;
}
// Returns the approximate color of temperature 'kelvin'.
private static Color kelvinToColor(int kelvin) {
double k = kelvin / 100D;
double red = k <= 66 ? 255 : 329.698727446 * Math.pow(k - 60, -0.1332047592);
double green = k <= 66 ? 99.4708025861 * Math.log(k) - 161.1195681661 : 288.1221695283 * Math.pow(k - 60, -0.0755148492);
double blue = k >= 66 ? 255 : (k <= 19 ? 0 : 138.5177312231 * Math.log(k - 10) - 305.0447927307);
return new Color(
limitAndDarken(red, kelvin),
limitAndDarken(green, kelvin),
limitAndDarken(blue, kelvin)
);
}
// A transformation used in the method 'kelvinToColor'.
private static int limitAndDarken(double color, int kelvin) {
int kelvinNorm = kelvin - 373;
if (color < 0 || kelvinNorm < 0) return 0;
else if (color > 255) return 255;
else if (kelvinNorm < 500) return (int) ((color / 256D) * (kelvinNorm / 500D) * 256);
else return (int) color;
}
}

74
src/Vector3.java Normal file
View File

@ -0,0 +1,74 @@
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;
//TODO: define constructor.
// Returns the sum of this vector and vector 'v'.
public Vector3 plus(Vector3 v) {
//TODO: implement method.
return null;
}
// Returns the product of this vector and 'd'.
public Vector3 times(double d) {
//TODO: implement method.
return null;
}
// Returns the sum of this vector and -1*v.
public Vector3 minus(Vector3 v) {
//TODO: implement method.
return null;
}
// Returns the Euclidean distance of this vector
// to the specified vector 'v'.
public double distanceTo(Vector3 v) {
//TODO: implement method.
return -1d;
}
// Returns the length (norm) of this vector.
public double length() {
//TODO: implement method.
return 0;
}
// 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.
}
// 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.
}
// 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 "";
}
}