Compare commits
16 Commits
Abgabe2
...
Abgabe3-Na
Author | SHA1 | Date | |
---|---|---|---|
95a4907dd2
|
|||
dfbdd6dc9d
|
|||
f156da4803
|
|||
cda144aa2a
|
|||
4bb1d6a36c
|
|||
01b2fb8989
|
|||
9925835a1e
|
|||
f24ad9bcaf
|
|||
cf4c1ad9d0
|
|||
8c67e157d5
|
|||
07ef38dab3 | |||
78d70f8a43
|
|||
9ce478b88e
|
|||
e52a1323c7
|
|||
a52a479910 | |||
324626f5eb |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# modified from https://github.com/javaee-samples/javaee8-samples/blob/master/.gitignore
|
# modified from https://github.com/javaee-samples/javaee8-samples/blob/master/.gitignore
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
|
/*.iml
|
||||||
|
|
||||||
# Directories #
|
# Directories #
|
||||||
build/
|
build/
|
||||||
|
50
angabe/Aufgabenblatt3.md
Normal file
50
angabe/Aufgabenblatt3.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Aufgabenblatt 3
|
||||||
|
|
||||||
|
## Allgemeine Anmerkungen
|
||||||
|
|
||||||
|
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 4.4. 11h durch `git commit` und `push` abzugeben. Mit der Angabe werden folgende Dateien mitgeliefert: [Simulation3](../src/Simulation3.java), [BodyLinkedList](../src/BodyLinkedList.java), [BodyForceTreeMap](../src/BodyForceTreeMap.java) und [Aufgabe3Test](../src/Aufgabe3Test.java).
|
||||||
|
Zusätzliche Klassen, Interfaces, Methoden und Variablen dürfen aber eingefügt werden. Wenn Sie zusätzlich zu den gefragten Klassen weitere Klassen definieren, achten Sie darauf, dass die Klassennamen mit `My` beginnen, um Konflikte mit späteren Aufgabenblättern zu vermeiden.
|
||||||
|
|
||||||
|
## Ziel
|
||||||
|
|
||||||
|
Ziel der Aufgabe ist die Implementierung einer Liste für eine lineare und eines Baums für eine assoziative Datenstruktur (siehe Skriptum Seiten 60-69).
|
||||||
|
|
||||||
|
## Beschreibung der gegebenen Dateien
|
||||||
|
|
||||||
|
- [BodyLinkedList](../src/BodyLinkedList.java) ist das Gerüst für eine Implementierung einer linearen Datenstruktur zur
|
||||||
|
Verwaltung von Objekten des Typs `Body`.
|
||||||
|
- [BodyForceTreeMap](../src/BodyForceTreeMap.java) ist das Gerüst für eine Implementierung einer assoziativen Datenstruktur, die einen Himmelskörper mit der auf ihn wirkenden Kraft assoziiert.
|
||||||
|
- [Aufgabe3Test](../src/Aufgabe3Test.java) ist eine vorgegebene Klasse, die Sie zum Testen Ihrer Implementierung verwenden sollten.
|
||||||
|
Bei einer fehlerfreien Implementierung sollten bei der Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful") ausgegeben werden. Sie müssen diese Klasse nicht verändern, können aber eigene Testfälle hinzufügen.
|
||||||
|
- [Simulation3](../src/Simulation3.java) ist ein Gerüst für eine ausführbare Klasse. Hier soll die Simulation analog
|
||||||
|
zur Klasse `Simulation` implementiert werden (damit Sie Ihre [ursprüngliche Datei](../src/Simulation.java)
|
||||||
|
nicht überschreiben müssen).
|
||||||
|
|
||||||
|
## Aufgaben
|
||||||
|
|
||||||
|
Ihre Aufgaben sind folgende:
|
||||||
|
|
||||||
|
1. Vervollständigen Sie die Klassendefinitionen in [BodyLinkedList](../src/BodyLinkedList.java) gemäß der Kommentare in den Dateien. Die Implementierung soll mit Hilfe einer verketteten Liste erfolgen. Sie können selbst entscheiden, ob Sie eine einfach oder doppelt verkettete Liste implementieren wollen. Benutzen Sie keine Arrays oder vorgefertigten Klassen aus dem Java-Collection-Framework!
|
||||||
|
2. Vervollständigen Sie die Klassendefinition in [BodyForceTreeMap](../src/BodyForceTreeMap.java). Die Implementierung
|
||||||
|
soll mit Hilfe eines binären Suchbaums erfolgen, in dem die Himmelskörper nach deren Masse sortiert sind. Die eigentlichen Schlüssel sind somit Objekte vom Typ `Body`, die interne Ordnung im Suchbaum erfolgt jedoch durch deren Masse. Benutzen Sie keine Arrays oder vorgefertigten Klassen aus dem Java-Collection-Framework!
|
||||||
|
3. Vervollständigen Sie die gegebene Klasse [Simulation3](../src/Simulation3.java) unter der Verwendung der Klassen
|
||||||
|
[BodyLinkedList](../src/BodyLinkedList.java) und [BodyForceTreeMap](../src/BodyForceTreeMap.java), so dass sich diese wie die bereits bestehende Klasse
|
||||||
|
[Simulation](../src/Simulation.java) verhält. Kollisionen sollen wieder berücksichtigt werden. Die Zugriffe auf die
|
||||||
|
Himmelskörper der Simulation sollen über Methoden von [BodyLinkedList](../src/BodyLinkedList.java) erfolgen. Die Klasse [BodyForceTreeMap](../src/BodyForceTreeMap.java) soll zur Verwaltung der Kräfte benutzt werden.
|
||||||
|
|
||||||
|
Allgemeiner Hinweis: bei einigen Methoden sind Vorbedingungen (_pre-conditions_) angegeben. Diese Vorbedingungen müssen innerhalb der Methode NICHT überprüft werden, sondern stellen Zusicherungen dar, auf die die Methode sich verlassen kann. Diese Regel gilt allgemein auch für zukünftige Aufgabenblätter.
|
||||||
|
|
||||||
|
### Denkanstöße (ohne Bewertung)
|
||||||
|
|
||||||
|
1. Haben Sie bei der Implementierung darauf geachtet, dass die Zugriffe möglichst effizient
|
||||||
|
erfolgen können (Z.B. ohne die Liste beim Zugriff wiederholt durchlaufen zu müssen)? Was ist in dem Zusammenhang der Vorteil der verketteten Liste?
|
||||||
|
2. Wofür eignen sich eher die Queue-Methoden `addFirst`, `addLast`, `pollFirst` bzw.
|
||||||
|
`pollLast` und wofür eher die List-Methoden `get`?
|
||||||
|
|
||||||
|
#### _Punkteaufteilung_
|
||||||
|
|
||||||
|
- Implementierung von `BodyLinkedList`: 2 Punkte
|
||||||
|
- Implementierung von `BodyForceTreeMap`: 2 Punkte
|
||||||
|
- Implementierung von `Simulation3`: 1 Punkt
|
||||||
|
- Gesamt: 5 Punkte
|
||||||
|
|
12
angaben.iml
12
angaben.iml
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="CodeDraw" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
@ -1,15 +1,17 @@
|
|||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
public class Aufgabe1Test {
|
public class Aufgabe1Test {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
@Test
|
||||||
//test classes Body and Vector3
|
public void testEP2() {
|
||||||
|
|
||||||
// create two bodies
|
// create two bodies
|
||||||
Body sun = new Body(1.989e30,new Vector3(0,0,0),new Vector3(0,0,0));
|
Body sun = new Body(SolSystem.SUN);
|
||||||
Body earth = new Body(5.972e24,new Vector3(-1.394555e11,5.103346e10,0),new Vector3(-10308.53,-28169.38,0));
|
Body earth = new Body(SolSystem.EARTH);
|
||||||
|
|
||||||
testValue(earth.distanceTo(sun), 1.4850000175024106E11);
|
assertEquals(1.4850000175024106E11, earth.distanceTo(sun));
|
||||||
testValue(sun.distanceTo(earth), 1.4850000175024106E11);
|
assertEquals(1.4850000175024106E11, sun.distanceTo(earth));
|
||||||
|
|
||||||
for (int i = 0; i < 3600 * 24; i++) {
|
for (int i = 0; i < 3600 * 24; i++) {
|
||||||
Vector3 f1 = earth.gravitationalForce(sun);
|
Vector3 f1 = earth.gravitationalForce(sun);
|
||||||
@ -20,36 +22,9 @@ public class Aufgabe1Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// a dummy body to check the correct position after 24h of movement
|
// a dummy body to check the correct position after 24h of movement
|
||||||
Body targetPositionEarth = new Body(1, new Vector3(-1.403250141841815E11,
|
Body targetPositionEarth = new Body(1, new Vector3(-1.403250141841815E11, 4.859202658875631E10, 0.0), new Vector3(0, 0, 0));
|
||||||
4.859202658875631E10, 0.0), new Vector3(0,0,0));
|
|
||||||
|
|
||||||
// check distance to target position (should be zero)
|
// check distance to target position (should be zero)
|
||||||
testValue(earth.distanceTo(targetPositionEarth), 0);
|
assertEquals(0, earth.distanceTo(targetPositionEarth));
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,80 +1,51 @@
|
|||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
public class Aufgabe2Test {
|
public class Aufgabe2Test {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
@Test
|
||||||
|
public void testEP2() {
|
||||||
//test classes BodyQueue and BodyForceMap
|
|
||||||
|
|
||||||
// create three bodies
|
// create three bodies
|
||||||
Body sun = new Body(1.989e30,new Vector3(0,0,0),new Vector3(0,0,0));
|
Body sun = new Body(SolSystem.SUN);
|
||||||
Body earth = new Body(5.972e24,new Vector3(-1.394555e11,5.103346e10,0),new Vector3(-10308.53,-28169.38,0));
|
Body earth = new Body(SolSystem.EARTH);
|
||||||
Body mercury = new Body(3.301e23,new Vector3(-5.439054e10,9.394878e9,0),new Vector3(-17117.83,-46297.48,-1925.57));
|
Body mercury = new Body(SolSystem.MERCURY);
|
||||||
|
|
||||||
|
|
||||||
// check basic functions of 'BodyQueue'
|
// check basic functions of 'BodyQueue'
|
||||||
System.out.println("Test1:");
|
|
||||||
|
|
||||||
BodyQueue bq = new BodyQueue(2);
|
BodyQueue bq = new BodyQueue(2);
|
||||||
bq.add(mercury);
|
bq.add(mercury);
|
||||||
bq.add(sun);
|
bq.add(sun);
|
||||||
bq.add(earth);
|
bq.add(earth);
|
||||||
testValue(bq.size(), 3);
|
assertEquals(3, bq.size());
|
||||||
|
|
||||||
testValue(bq.poll(), mercury);
|
assertEquals(mercury, bq.poll());
|
||||||
testValue(bq.poll(), sun);
|
assertEquals(sun, bq.poll());
|
||||||
testValue(bq.poll(), earth);
|
assertEquals(earth, bq.poll());
|
||||||
|
|
||||||
testValue(bq.size(), 0);
|
assertEquals(0, bq.size());
|
||||||
|
|
||||||
bq.add(mercury);
|
bq.add(mercury);
|
||||||
bq.add(sun);
|
bq.add(sun);
|
||||||
testValue(bq.size(), 2);
|
assertEquals(2, bq.size());
|
||||||
|
|
||||||
// check constructor of 'BodyQueue'
|
// check constructor of 'BodyQueue'
|
||||||
BodyQueue bqCopy = new BodyQueue(bq);
|
BodyQueue bqCopy = new BodyQueue(bq);
|
||||||
testComparison(bq, bqCopy, false);
|
assertNotEquals(bq, bqCopy);
|
||||||
testComparison(bq.poll(), bqCopy.poll(), true);
|
assertEquals(bqCopy.poll(), bq.poll());
|
||||||
bq.add(earth);
|
bq.add(earth);
|
||||||
testValue(bq.size(), 2);
|
assertEquals(2, bq.size());
|
||||||
testValue(bqCopy.size(), 1);
|
assertEquals(1, bqCopy.size());
|
||||||
|
|
||||||
// check basic functions of 'BodyForceMap'
|
// check basic functions of 'BodyForceMap'
|
||||||
System.out.println("Test2:");
|
|
||||||
BodyForceMap bfm = new BodyForceMap(5);
|
BodyForceMap bfm = new BodyForceMap(5);
|
||||||
bfm.put(earth, earth.gravitationalForce(sun));
|
bfm.put(earth, earth.gravitationalForce(sun));
|
||||||
bfm.put(sun, sun.gravitationalForce(earth));
|
bfm.put(sun, sun.gravitationalForce(earth));
|
||||||
|
|
||||||
testValue(bfm.get(earth).distanceTo(earth.gravitationalForce(sun)),0);
|
assertEquals(0, bfm.get(earth).distanceTo(earth.gravitationalForce(sun)));
|
||||||
testValue(bfm.get(sun).distanceTo(sun.gravitationalForce(earth)),0);
|
assertEquals(0, bfm.get(sun).distanceTo(sun.gravitationalForce(earth)));
|
||||||
|
|
||||||
bfm.put(earth, new Vector3(0, 0, 0));
|
bfm.put(earth, new Vector3(0, 0, 0));
|
||||||
testValue(bfm.get(earth).distanceTo(new Vector3(0,0,0)), 0);
|
assertEquals(0, bfm.get(earth).distanceTo(new Vector3(0, 0, 0)));
|
||||||
testValue(bfm.get(mercury),null);
|
assertNull(bfm.get(mercury));
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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/Aufgabe3Test.java
Normal file
79
src/Aufgabe3Test.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class Aufgabe3Test {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEP2() {
|
||||||
|
// create five bodies
|
||||||
|
Body sun = new Body(SolSystem.SUN);
|
||||||
|
Body earth = new Body(SolSystem.EARTH);
|
||||||
|
Body mercury = new Body(SolSystem.MERCURY);
|
||||||
|
Body venus = new Body(SolSystem.VENUS);
|
||||||
|
Body mars = new Body(SolSystem.MARS);
|
||||||
|
|
||||||
|
// check basic functions of 'BodyLinkedList'
|
||||||
|
BodyLinkedList bl = new BodyLinkedList();
|
||||||
|
|
||||||
|
bl.addLast(mercury);
|
||||||
|
bl.addLast(sun);
|
||||||
|
bl.addLast(earth);
|
||||||
|
assertEquals(3, bl.size());
|
||||||
|
|
||||||
|
assertEquals(mercury, bl.getFirst());
|
||||||
|
assertEquals(earth, bl.getLast());
|
||||||
|
|
||||||
|
assertEquals(mercury, bl.get(0));
|
||||||
|
assertEquals(sun, bl.get(1));
|
||||||
|
assertEquals(earth, bl.get(2));
|
||||||
|
|
||||||
|
assertEquals(2, bl.indexOf(earth));
|
||||||
|
assertEquals(1, bl.indexOf(sun));
|
||||||
|
assertEquals(0, bl.indexOf(mercury));
|
||||||
|
|
||||||
|
assertEquals(mercury, bl.pollFirst());
|
||||||
|
assertEquals(earth, bl.pollLast());
|
||||||
|
assertEquals(sun, bl.pollFirst());
|
||||||
|
|
||||||
|
assertEquals(0, bl.size());
|
||||||
|
assertNull(bl.getFirst());
|
||||||
|
|
||||||
|
bl.addFirst(earth);
|
||||||
|
bl.addFirst(venus);
|
||||||
|
bl.addFirst(sun);
|
||||||
|
bl.add(1, mercury);
|
||||||
|
bl.add(4, mars);
|
||||||
|
|
||||||
|
assertEquals(5, bl.size());
|
||||||
|
|
||||||
|
assertEquals(sun, bl.get(0));
|
||||||
|
assertEquals(mercury, bl.get(1));
|
||||||
|
assertEquals(venus, bl.get(2));
|
||||||
|
assertEquals(earth, bl.get(3));
|
||||||
|
assertEquals(mars, bl.get(4));
|
||||||
|
|
||||||
|
// check constructor of 'BodyLinkedList'
|
||||||
|
BodyLinkedList blCopy = new BodyLinkedList(bl);
|
||||||
|
assertNotEquals(bl, blCopy);
|
||||||
|
assertEquals(blCopy.pollFirst(), bl.pollFirst());
|
||||||
|
bl.addFirst(sun);
|
||||||
|
assertEquals(5, bl.size());
|
||||||
|
assertEquals(4, blCopy.size());
|
||||||
|
|
||||||
|
// check basic functions of 'BodyForceTreeMap'
|
||||||
|
BodyForceTreeMap bfm = new BodyForceTreeMap();
|
||||||
|
bfm.put(earth, earth.gravitationalForce(sun));
|
||||||
|
bfm.put(sun, sun.gravitationalForce(earth).plus(sun.gravitationalForce(venus)));
|
||||||
|
bfm.put(venus, venus.gravitationalForce(sun));
|
||||||
|
bfm.put(mars, mars.gravitationalForce(sun));
|
||||||
|
bfm.put(mercury, mercury.gravitationalForce(sun));
|
||||||
|
|
||||||
|
assertEquals(0, bfm.get(earth).distanceTo(earth.gravitationalForce(sun)));
|
||||||
|
assertEquals(0, bfm.get(sun).distanceTo(sun.gravitationalForce(earth).plus(sun.gravitationalForce(venus))));
|
||||||
|
|
||||||
|
assertEquals(0, bfm.put(earth, new Vector3(0, 0, 0)).distanceTo(earth.gravitationalForce(sun)));
|
||||||
|
assertEquals(0, bfm.get(mercury).distanceTo(mercury.gravitationalForce(sun)));
|
||||||
|
assertEquals(mercury.gravitationalForce(sun), bfm.get(mercury));
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import codedraw.CodeDraw;
|
|||||||
* This class represents celestial bodies like stars, planets, asteroids, etc...
|
* This class represents celestial bodies like stars, planets, asteroids, etc...
|
||||||
*/
|
*/
|
||||||
public class Body {
|
public class Body {
|
||||||
private double mass;
|
private final double mass;
|
||||||
private Vector3 massCenter; // position of the mass center.
|
private Vector3 massCenter; // position of the mass center.
|
||||||
private Vector3 currentMovement;
|
private Vector3 currentMovement;
|
||||||
|
|
||||||
@ -14,6 +14,12 @@ public class Body {
|
|||||||
this.currentMovement = currentMovement;
|
this.currentMovement = currentMovement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Body(Body other) {
|
||||||
|
this.mass = other.mass;
|
||||||
|
this.massCenter = new Vector3(other.massCenter);
|
||||||
|
this.currentMovement = new Vector3(other.currentMovement);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the distance between the mass centers of this body and the specified body 'b'.
|
* Returns the distance between the mass centers of this body and the specified body 'b'.
|
||||||
*/
|
*/
|
||||||
@ -70,16 +76,20 @@ public class Body {
|
|||||||
return mass;
|
return mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
* 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'.
|
* of the returned body is the sum of the impulses of 'this' and 'b'.
|
||||||
*/
|
*/
|
||||||
public Body merge(Body b) {
|
public Body merge(Body body) {
|
||||||
double mass = this.mass + b.mass;
|
double totalMass = this.mass + body.mass;
|
||||||
return new Body(
|
return new Body(
|
||||||
mass,
|
totalMass,
|
||||||
massCenter.times(this.mass).plus(b.massCenter.times(b.mass)).times(1.0 / mass),
|
this.massCenter.times(this.mass).plus(body.massCenter.times(body.mass)).times(1.0 / totalMass),
|
||||||
currentMovement.times(this.mass).plus(b.currentMovement.times(b.mass)).times(1.0 / mass)
|
this.currentMovement.times(this.mass).plus(body.currentMovement.times(body.mass)).times(1.0 / totalMass)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,9 +110,10 @@ public class Body {
|
|||||||
* mass, position (mass center) and current movement. Example:
|
* 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."
|
* "5.972E24 kg, position: [1.48E11,0.0,0.0] m, movement: [0.0,29290.0,0.0] m/s."
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"%f kg, position: %s m, movement: %s m/s.",
|
"%g kg, position: %s m, movement: %s m/s.",
|
||||||
mass, massCenter.toString(), currentMovement.toString()
|
mass, massCenter.toString(), currentMovement.toString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
155
src/BodyForceTreeMap.java
Normal file
155
src/BodyForceTreeMap.java
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/**
|
||||||
|
* A map that associates a Body with a Vector3 (typically this is the force exerted on the body).
|
||||||
|
* The number of key-value pairs is not limited.
|
||||||
|
*/
|
||||||
|
public class BodyForceTreeMap {
|
||||||
|
private int size = 0;
|
||||||
|
private BodyForceTreeMapItem root = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new key-value association to this map. If the key already exists in this map,
|
||||||
|
* the value is replaced and the old value is returned. Otherwise 'null' is returned.
|
||||||
|
* Precondition: key != null.
|
||||||
|
*/
|
||||||
|
public Vector3 put(Body key, Vector3 value) {
|
||||||
|
if (root == null) {
|
||||||
|
root = new BodyForceTreeMapItem(key, value);
|
||||||
|
size++;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
BodyForceTreeMapItem item = root;
|
||||||
|
while (item != null) {
|
||||||
|
if (item.key() == key) {
|
||||||
|
Vector3 old = item.value();
|
||||||
|
item.setValue(value);
|
||||||
|
return old;
|
||||||
|
} else if (item.key().mass() > key.mass()) {
|
||||||
|
if (item.left() != null) {
|
||||||
|
item = item.left();
|
||||||
|
} else {
|
||||||
|
item.setLeft(new BodyForceTreeMapItem(key, value));
|
||||||
|
size++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item.right() != null) {
|
||||||
|
item = item.right();
|
||||||
|
} else{
|
||||||
|
item.setRight(new BodyForceTreeMapItem(key, value));
|
||||||
|
size++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value associated with the specified key, i.e. the method returns the force vector
|
||||||
|
* associated with the specified key. Returns 'null' if the key is not contained in this map.
|
||||||
|
* Precondition: key != null.
|
||||||
|
*/
|
||||||
|
public Vector3 get(Body key) {
|
||||||
|
BodyForceTreeMapItem item = root;
|
||||||
|
while (item != null) {
|
||||||
|
if (item.key() == key) {
|
||||||
|
return item.value();
|
||||||
|
} else if (item.key().mass() > key.mass()) {
|
||||||
|
item = item.left();
|
||||||
|
} else {
|
||||||
|
item = item.right();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns 'true' if this map contains a mapping for the specified key.
|
||||||
|
*/
|
||||||
|
public boolean containsKey(Body key) {
|
||||||
|
BodyForceTreeMapItem item = root;
|
||||||
|
while (item != null) {
|
||||||
|
if (item.key() == key) {
|
||||||
|
return true;
|
||||||
|
} else if (item.key().mass() > key.mass()) {
|
||||||
|
item = item.left();
|
||||||
|
} else {
|
||||||
|
item = item.right();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toString(BodyForceTreeMapItem item) {
|
||||||
|
String s = "";
|
||||||
|
if (item == null) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
s += this.toString(item.right());
|
||||||
|
s += String.format("{%s: %s}\n", item.key(), item.value());
|
||||||
|
s += this.toString(item.left());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a readable representation of this map, in which key-value pairs are ordered
|
||||||
|
* descending according to the mass of the bodies.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return toString(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BodyForceTreeMapItem {
|
||||||
|
private final Body key;
|
||||||
|
private Vector3 value;
|
||||||
|
private BodyForceTreeMapItem parent;
|
||||||
|
private BodyForceTreeMapItem left;
|
||||||
|
private BodyForceTreeMapItem right;
|
||||||
|
|
||||||
|
public BodyForceTreeMapItem(Body key, Vector3 value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Body key() {
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Vector3 value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 value() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BodyForceTreeMapItem left() {
|
||||||
|
return this.left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BodyForceTreeMapItem right() {
|
||||||
|
return this.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BodyForceTreeMapItem parent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLeft(BodyForceTreeMapItem left) {
|
||||||
|
this.left = left;
|
||||||
|
if (left != null) left.parent = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRight(BodyForceTreeMapItem right) {
|
||||||
|
this.right = right;
|
||||||
|
if (right != null) right.parent = this;
|
||||||
|
}
|
||||||
|
}
|
261
src/BodyLinkedList.java
Normal file
261
src/BodyLinkedList.java
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of bodies implemented as a linked list.
|
||||||
|
* The number of elements of the list is not limited.
|
||||||
|
*/
|
||||||
|
public class BodyLinkedList implements Iterable<Body> {
|
||||||
|
private int size = 0;
|
||||||
|
private BodyLinkedListItem first;
|
||||||
|
private BodyLinkedListItem last;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes 'this' as an empty list.
|
||||||
|
*/
|
||||||
|
public BodyLinkedList() {
|
||||||
|
first = null;
|
||||||
|
last = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes 'this' as an independent copy of the specified list 'list'.
|
||||||
|
* Calling methods of this list will not affect the specified list 'list'
|
||||||
|
* and vice versa.
|
||||||
|
* Precondition: list != null.
|
||||||
|
*/
|
||||||
|
public BodyLinkedList(BodyLinkedList list) {
|
||||||
|
this.size = 0;
|
||||||
|
for (Body b : list) {
|
||||||
|
this.addLast(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the specified element 'body' at the beginning of this list.
|
||||||
|
*/
|
||||||
|
public void addFirst(Body body) {
|
||||||
|
if (first == null) {
|
||||||
|
first = new BodyLinkedListItem(body);
|
||||||
|
last = first;
|
||||||
|
} else {
|
||||||
|
first.setPrev(new BodyLinkedListItem(body));
|
||||||
|
first = first.prev();
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the specified element 'body' to the end of this list.
|
||||||
|
*/
|
||||||
|
public void addLast(Body body) {
|
||||||
|
if (last == null) {
|
||||||
|
last = new BodyLinkedListItem(body);
|
||||||
|
first = last;
|
||||||
|
} else {
|
||||||
|
last.setNext(new BodyLinkedListItem(body));
|
||||||
|
last = last.next();
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last element in this list.
|
||||||
|
* Returns 'null' if the list is empty.
|
||||||
|
*/
|
||||||
|
public Body getLast() {
|
||||||
|
return (last != null) ? last.body() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first element in this list.
|
||||||
|
* Returns 'null' if the list is empty.
|
||||||
|
*/
|
||||||
|
public Body getFirst() {
|
||||||
|
return (first != null) ? first.body() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves and removes the first element in this list.
|
||||||
|
* Returns 'null' if the list is empty.
|
||||||
|
*/
|
||||||
|
public Body pollFirst() {
|
||||||
|
if (first == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Body b = first.body();
|
||||||
|
first = first.next();
|
||||||
|
if (first != null) first.setPrev(null);
|
||||||
|
size--;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves and removes the last element in this list.
|
||||||
|
* Returns 'null' if the list is empty.
|
||||||
|
*/
|
||||||
|
public Body pollLast() {
|
||||||
|
if (last == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Body b = last.body();
|
||||||
|
last = last.prev();
|
||||||
|
if (last != null) last.setNext(null);
|
||||||
|
size--;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the specified element 'body' at the specified position in this list.
|
||||||
|
* Precondition: i >= 0 && i <= size().
|
||||||
|
*/
|
||||||
|
public void add(int i, Body body) {
|
||||||
|
if (first == null || i == 0) {
|
||||||
|
addFirst(body);
|
||||||
|
return;
|
||||||
|
} else if (i == size) {
|
||||||
|
addLast(body);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BodyLinkedListItem item = first;
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
item = item.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
item.prev().setNext(new BodyLinkedListItem(body));
|
||||||
|
item.setPrev(item.prev().next());
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Body removeItem(BodyLinkedListItem item) {
|
||||||
|
if (item == first) {
|
||||||
|
first = item.next();
|
||||||
|
if (first != null) first.setPrev(null);
|
||||||
|
} else if (item == last) {
|
||||||
|
last = item.prev();
|
||||||
|
if (last != null) last.setNext(null);
|
||||||
|
} else {
|
||||||
|
item.next().setPrev(item.prev());
|
||||||
|
}
|
||||||
|
size--;
|
||||||
|
return item.body();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the element at the specified position in this list.
|
||||||
|
* Precondition: i >= 0 && i < size().
|
||||||
|
*/
|
||||||
|
public Body get(int i) {
|
||||||
|
BodyLinkedListItem item;
|
||||||
|
if (i < size / 2) {
|
||||||
|
item = first;
|
||||||
|
for (int j = 0; j < i; j++) {
|
||||||
|
item = item.next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item = last;
|
||||||
|
for (int j = size - 1; j > i; j--) {
|
||||||
|
item = item.prev();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item.body();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the first occurrence of the specified element in this list, or -1 if
|
||||||
|
* this list does not contain the element.
|
||||||
|
*/
|
||||||
|
public int indexOf(Body body) {
|
||||||
|
if (first == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BodyLinkedListItem item = first;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (item.body() == body) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
item = item.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all bodies of this list, which are colliding with the specified
|
||||||
|
* body. Returns a list with all the removed bodies.
|
||||||
|
*/
|
||||||
|
public BodyLinkedList removeCollidingWith(Body body) {
|
||||||
|
BodyLinkedList removed = new BodyLinkedList();
|
||||||
|
for (BodyLinkedListItem item = first; item != null; item = item.next()) {
|
||||||
|
if (body != item.body() && body.collidesWith(item.body())) {
|
||||||
|
removed.addLast(this.removeItem(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bodies in this list.
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Body> iterator() {
|
||||||
|
return new Iterator<>() {
|
||||||
|
BodyLinkedListItem ptr = first;
|
||||||
|
boolean yieldedFirst = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return ptr != null && (!yieldedFirst || ptr.next() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Body next() {
|
||||||
|
if (!yieldedFirst) {
|
||||||
|
yieldedFirst = true;
|
||||||
|
return ptr.body();
|
||||||
|
}
|
||||||
|
ptr = ptr.next();
|
||||||
|
return ptr.body();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BodyLinkedListItem {
|
||||||
|
private final Body body;
|
||||||
|
private BodyLinkedListItem prev;
|
||||||
|
private BodyLinkedListItem next;
|
||||||
|
|
||||||
|
public BodyLinkedListItem(Body body) {
|
||||||
|
this.body = body;
|
||||||
|
this.prev = null;
|
||||||
|
this.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Body body() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BodyLinkedListItem prev() {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrev(BodyLinkedListItem prev) {
|
||||||
|
this.prev = prev;
|
||||||
|
if (prev != null) prev.next = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BodyLinkedListItem next() {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNext(BodyLinkedListItem next) {
|
||||||
|
this.next = next;
|
||||||
|
if (next != null) next.prev = this;
|
||||||
|
}
|
||||||
|
}
|
@ -27,15 +27,15 @@ public class BodyQueue {
|
|||||||
* Initializes this queue as an independent copy of the specified queue.
|
* Initializes this queue as an independent copy of the specified queue.
|
||||||
* Calling methods of this queue will not affect the specified queue
|
* Calling methods of this queue will not affect the specified queue
|
||||||
* and vice versa.
|
* and vice versa.
|
||||||
* Precondition: q != null.
|
* Precondition: other != null.
|
||||||
*/
|
*/
|
||||||
public BodyQueue(BodyQueue q) {
|
public BodyQueue(BodyQueue other) {
|
||||||
this.capacity = q.capacity;
|
this.capacity = other.capacity;
|
||||||
this.head = q.size();
|
this.head = other.size();
|
||||||
this.tail = 0;
|
this.tail = 0;
|
||||||
this.queue = new Body[this.capacity];
|
this.queue = new Body[this.capacity];
|
||||||
for (int i = 0; i < q.size(); i++) {
|
for (int i = 0, j = other.tail; i < this.head; i++, j++) {
|
||||||
this.queue[i] = q.queue[i];
|
this.queue[i] = other.queue[j % other.capacity];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,12 +43,11 @@ public class BodyQueue {
|
|||||||
* Adds the specified body 'b' to this queue.
|
* Adds the specified body 'b' to this queue.
|
||||||
*/
|
*/
|
||||||
public void add(Body b) {
|
public void add(Body b) {
|
||||||
|
if ((head + 1) % capacity == tail) {
|
||||||
|
doubleCapacity();
|
||||||
|
}
|
||||||
queue[head] = b;
|
queue[head] = b;
|
||||||
head = (head + 1) % capacity;
|
head = (head + 1) % capacity;
|
||||||
if (head == tail) {
|
|
||||||
doubleCapacity();
|
|
||||||
head = capacity / 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +56,8 @@ public class BodyQueue {
|
|||||||
*/
|
*/
|
||||||
public Body poll() {
|
public Body poll() {
|
||||||
if (tail == head) {
|
if (tail == head) {
|
||||||
|
tail = 0;
|
||||||
|
head = 0;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Body b = queue[tail];
|
Body b = queue[tail];
|
||||||
@ -77,10 +78,10 @@ public class BodyQueue {
|
|||||||
*/
|
*/
|
||||||
private void doubleCapacity() {
|
private void doubleCapacity() {
|
||||||
Body[] tmp = new Body[capacity * 2];
|
Body[] tmp = new Body[capacity * 2];
|
||||||
for (int i = head, j = 0; i < tail + capacity; i++, j++) {
|
head = size();
|
||||||
tmp[j] = queue[i % capacity];
|
for (int i = 0, j = tail; i < head; i++, j++) {
|
||||||
|
tmp[i] = queue[j % capacity];
|
||||||
}
|
}
|
||||||
head = capacity;
|
|
||||||
tail = 0;
|
tail = 0;
|
||||||
capacity *= 2;
|
capacity *= 2;
|
||||||
queue = tmp;
|
queue = tmp;
|
||||||
|
@ -81,7 +81,7 @@ public class Simulation {
|
|||||||
// merge bodies that have collided
|
// merge bodies that have collided
|
||||||
for (int i = 0; i < bodies.length; i++) {
|
for (int i = 0; i < bodies.length; i++) {
|
||||||
for (int j = i + 1; j < bodies.length; j++) {
|
for (int j = i + 1; j < bodies.length; j++) {
|
||||||
if (bodies[j].distanceTo(bodies[i]) < bodies[j].radius() + bodies[i].radius()) {
|
if (bodies[j].collidesWith(bodies[i])) {
|
||||||
bodies[i] = bodies[i].merge(bodies[j]);
|
bodies[i] = bodies[i].merge(bodies[j]);
|
||||||
Body[] bodiesOneRemoved = new Body[bodies.length - 1];
|
Body[] bodiesOneRemoved = new Body[bodies.length - 1];
|
||||||
for (int k = 0; k < bodiesOneRemoved.length; k++) {
|
for (int k = 0; k < bodiesOneRemoved.length; k++) {
|
||||||
|
74
src/Simulation3.java
Normal file
74
src/Simulation3.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import codedraw.CodeDraw;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates the formation of a massive solar system.
|
||||||
|
*/
|
||||||
|
public class Simulation3 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main simulation method using instances of other classes.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CodeDraw cd = new CodeDraw();
|
||||||
|
BodyLinkedList bodies = new BodyLinkedList();
|
||||||
|
BodyForceTreeMap forceOnBody = new BodyForceTreeMap();
|
||||||
|
|
||||||
|
Random random = new Random(2022);
|
||||||
|
|
||||||
|
for (int i = 0; i < Simulation.NUMBER_OF_BODIES; i++) {
|
||||||
|
bodies.addLast(new Body(
|
||||||
|
Math.abs(random.nextGaussian()) * Simulation.OVERALL_SYSTEM_MASS / Simulation.NUMBER_OF_BODIES,
|
||||||
|
new Vector3(
|
||||||
|
0.2 * random.nextGaussian() * Simulation.AU,
|
||||||
|
0.2 * random.nextGaussian() * Simulation.AU,
|
||||||
|
0.2 * random.nextGaussian() * Simulation.AU
|
||||||
|
),
|
||||||
|
new Vector3(
|
||||||
|
0 + random.nextGaussian() * 5e3,
|
||||||
|
0 + random.nextGaussian() * 5e3,
|
||||||
|
0 + random.nextGaussian() * 5e3
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
long seconds = 0;
|
||||||
|
while (true) {
|
||||||
|
seconds++;
|
||||||
|
|
||||||
|
BodyLinkedList mergedBodies = new BodyLinkedList();
|
||||||
|
for (Body b1 : bodies) {
|
||||||
|
BodyLinkedList colliding = bodies.removeCollidingWith(b1);
|
||||||
|
for (Body b2 : colliding) {
|
||||||
|
b1 = b1.merge(b2);
|
||||||
|
}
|
||||||
|
mergedBodies.addLast(b1);
|
||||||
|
}
|
||||||
|
bodies = mergedBodies;
|
||||||
|
|
||||||
|
for (Body b1 : bodies) {
|
||||||
|
Vector3 force = new Vector3();
|
||||||
|
for (Body b2 : bodies) {
|
||||||
|
if (b1 != b2) {
|
||||||
|
force = force.plus(b1.gravitationalForce(b2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forceOnBody.put(b1, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Body body : bodies) {
|
||||||
|
body.move(forceOnBody.get(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((seconds % 3600) == 0) {
|
||||||
|
cd.clear(Color.BLACK);
|
||||||
|
for (Body body : bodies) {
|
||||||
|
body.draw(cd);
|
||||||
|
}
|
||||||
|
cd.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/SolSystem.java
Normal file
7
src/SolSystem.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
public class SolSystem {
|
||||||
|
public static final Body SUN = new Body(1.989e30, new Vector3(0, 0, 0), new Vector3(0, 0, 0));
|
||||||
|
public static final Body EARTH = new Body(5.972e24, new Vector3(-1.394555e11, 5.103346e10, 0), new Vector3(-10308.53, -28169.38, 0));
|
||||||
|
public static final Body MERCURY = new Body(3.301e23, new Vector3(-5.439054e10, 9.394878e9, 0), new Vector3(-17117.83, -46297.48, -1925.57));
|
||||||
|
public static final Body VENUS = new Body(4.86747e24, new Vector3(-1.707667e10, 1.066132e11, 2.450232e9), new Vector3(-34446.02, -5567.47, 2181.10));
|
||||||
|
public static final Body MARS = new Body(6.41712e23, new Vector3(-1.010178e11, -2.043939e11, -1.591727E9), new Vector3(20651.98, -10186.67, -2302.79));
|
||||||
|
}
|
@ -8,7 +8,6 @@ public class SpaceDraw {
|
|||||||
* where m and r measured in solar units.)
|
* where m and r measured in solar units.)
|
||||||
*/
|
*/
|
||||||
public static double massToRadius(double mass) {
|
public static double massToRadius(double mass) {
|
||||||
|
|
||||||
return Simulation.SUN_RADIUS * (Math.pow(mass / Simulation.SUN_MASS, 0.5));
|
return Simulation.SUN_RADIUS * (Math.pow(mass / Simulation.SUN_MASS, 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ public class SpaceDraw {
|
|||||||
* Returns the approximate color of temperature 'kelvin'.
|
* Returns the approximate color of temperature 'kelvin'.
|
||||||
*/
|
*/
|
||||||
private static Color kelvinToColor(int kelvin) {
|
private static Color kelvinToColor(int kelvin) {
|
||||||
|
|
||||||
double k = kelvin / 100D;
|
double k = kelvin / 100D;
|
||||||
double red = k <= 66 ? 255 : 329.698727446 * Math.pow(k - 60, -0.1332047592);
|
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 green = k <= 66 ? 99.4708025861 * Math.log(k) - 161.1195681661 : 288.1221695283 * Math.pow(k - 60, -0.0755148492);
|
||||||
@ -51,12 +49,15 @@ public class SpaceDraw {
|
|||||||
* A transformation used in the method 'kelvinToColor'.
|
* A transformation used in the method 'kelvinToColor'.
|
||||||
*/
|
*/
|
||||||
private static int limitAndDarken(double color, int kelvin) {
|
private static int limitAndDarken(double color, int kelvin) {
|
||||||
|
|
||||||
int kelvinNorm = kelvin - 373;
|
int kelvinNorm = kelvin - 373;
|
||||||
|
if (color < 0 || kelvinNorm < 0) {
|
||||||
if (color < 0 || kelvinNorm < 0) return 0;
|
return 0;
|
||||||
else if (color > 255) return 255;
|
} else if (color > 255) {
|
||||||
else if (kelvinNorm < 500) return (int) ((color / 256D) * (kelvinNorm / 500D) * 256);
|
return 255;
|
||||||
else return (int) color;
|
} else if (kelvinNorm < 500) {
|
||||||
|
return (int) ((color / 256D) * (kelvinNorm / 500D) * 256);
|
||||||
|
} else {
|
||||||
|
return (int) color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import codedraw.CodeDraw;
|
|||||||
* This class represents vectors in a 3D vector space.
|
* This class represents vectors in a 3D vector space.
|
||||||
*/
|
*/
|
||||||
public class Vector3 {
|
public class Vector3 {
|
||||||
|
|
||||||
private double x;
|
private double x;
|
||||||
private double y;
|
private double y;
|
||||||
private double z;
|
private double z;
|
||||||
@ -23,37 +22,29 @@ public class Vector3 {
|
|||||||
this.z = z;
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector3(Vector3 other) {
|
||||||
|
this(other.x, other.y, other.z);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the sum of this vector and vector 'v'.
|
* Returns the sum of this vector and vector 'v'.
|
||||||
*/
|
*/
|
||||||
public Vector3 plus(Vector3 v) {
|
public Vector3 plus(Vector3 v) {
|
||||||
Vector3 result = new Vector3();
|
return new Vector3(x + v.x, y + v.y, z + v.z);
|
||||||
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'.
|
* Returns the product of this vector and 'd'.
|
||||||
*/
|
*/
|
||||||
public Vector3 times(double d) {
|
public Vector3 times(double d) {
|
||||||
Vector3 result = new Vector3();
|
return new Vector3(x * d, y * d, z * d);
|
||||||
result.x = x * d;
|
|
||||||
result.y = y * d;
|
|
||||||
result.z = z * d;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the sum of this vector and -1*v.
|
* Returns the sum of this vector and -1*v.
|
||||||
*/
|
*/
|
||||||
public Vector3 minus(Vector3 v) {
|
public Vector3 minus(Vector3 v) {
|
||||||
Vector3 result = new Vector3();
|
return new Vector3(x - v.x, y - v.y, z - v.z);
|
||||||
result.x = x - v.x;
|
|
||||||
result.y = y - v.y;
|
|
||||||
result.z = z - v.z;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,22 +76,38 @@ public class Vector3 {
|
|||||||
z /= length;
|
z /= length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getScreenX(CodeDraw cd) {
|
||||||
|
return cd.getWidth() * (this.x + Simulation.SECTION_SIZE / 2) / Simulation.SECTION_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScreenY(CodeDraw cd) {
|
||||||
|
return cd.getWidth() * (this.y + Simulation.SECTION_SIZE / 2) / Simulation.SECTION_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a filled circle with a specified radius centered at the (x,y) coordinates of this vector
|
* 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.
|
* in the canvas associated with 'cd'. The z-coordinate is not used.
|
||||||
*/
|
*/
|
||||||
public void drawAsFilledCircle(CodeDraw cd, double radius) {
|
public void drawAsFilledCircle(CodeDraw cd, double radius) {
|
||||||
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;
|
radius = cd.getWidth() * radius / Simulation.SECTION_SIZE;
|
||||||
cd.fillCircle(x, y, Math.max(radius, 1.5));
|
cd.fillCircle(getScreenX(cd), getScreenY(cd), Math.max(radius, 1.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the coordinates of this vector in brackets as a string
|
* 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]".
|
* in the form "[x,y,z]", e.g., "[1.48E11,0.0,0.0]".
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("[%f,%f,%f]", x, y, z);
|
return String.format("[%g,%g,%g]", x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (other.getClass() != Vector3.class) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Vector3 v = (Vector3) other;
|
||||||
|
return this.x == v.x && this.y == v.y && this.z == v.z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user