15 Commits

Author SHA1 Message Date
35743c64b6 Finish AB4 2022-04-27 23:29:24 +02:00
b3ddcec038 Fix error in JavaDoc 2022-04-27 19:03:09 +02:00
cf188f1b2d Refactor for AB4 2022-04-27 19:00:45 +02:00
60ea5aa6f4 Aufgabenblatt 4 2022-04-25 10:15:53 +00:00
ef01f2a0fc Aufgabenblatt 4 2022-04-25 12:04:51 +02:00
95a4907dd2 Add @Override to toString 2022-04-07 18:08:05 +02:00
dfbdd6dc9d Fix BodyQueue 2022-04-07 18:03:00 +02:00
f156da4803 Refactor tests 2022-04-07 17:52:43 +02:00
cda144aa2a Refactor List and Tree 2022-04-04 12:48:13 +02:00
4bb1d6a36c AB3: Fix toString() 2022-03-31 22:08:42 +02:00
01b2fb8989 AB3: BodyForceTreeMap working 2022-03-31 21:47:53 +02:00
9925835a1e Fix tests... 2022-03-31 21:38:04 +02:00
f24ad9bcaf AB3: BodyLinkedList working 2022-03-31 19:50:10 +02:00
cf4c1ad9d0 Refactor for AB3 2022-03-31 17:49:49 +02:00
8c67e157d5 Rename gpl-3.0.txt to LICENSE 2022-03-31 17:38:49 +02:00
23 changed files with 1194 additions and 305 deletions

View File

@ -61,5 +61,3 @@ Himmelskörpern:
- Implementierung von `BodyForceMap`: 2 Punkte - Implementierung von `BodyForceMap`: 2 Punkte
- Anpassung von `Simulation`: 1 Punkt - Anpassung von `Simulation`: 1 Punkt
- Gesamt: 5 Punkte - Gesamt: 5 Punkte

View File

@ -47,4 +47,3 @@ Allgemeiner Hinweis: bei einigen Methoden sind Vorbedingungen (_pre-conditions_)
- Implementierung von `BodyForceTreeMap`: 2 Punkte - Implementierung von `BodyForceTreeMap`: 2 Punkte
- Implementierung von `Simulation3`: 1 Punkt - Implementierung von `Simulation3`: 1 Punkt
- Gesamt: 5 Punkte - Gesamt: 5 Punkte

122
angabe/Aufgabenblatt4.md Normal file
View File

@ -0,0 +1,122 @@
# Aufgabenblatt 4
## Allgemeine Anmerkungen
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 2.5. 11h durch `git commit` und `push`
abzugeben. Mit der Angabe werden die Dateien `CosmicSystem.java`, `Drawable.java`,
`NamedBodyForcePair.java`, `HierarchicalSystem.java`, `Simulation4.java` und `Aufgabe4Test.java`
mitgeliefert.
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 Anwendung der Konzepte: Interfaces, dynamisches Binden, toString()
(siehe Skriptum Seite 75-84).
## Beschreibung der gegebenen Dateien
- [CosmicSystem](../src/CosmicSystem.java) ist ein gegebenes Interface, das von den Klassen
`NamedBodyForcePair` und `HierarchicalSystem` implementiert wird. Mithilfe dieses lässt sich somit eine
Hierarchie von Systemen und Subsystemen beschreiben. Unser Sonnensystem ist ein Beispiel eines Systems,
das mehrere Teilsysteme beinhaltet. Ein solches Teilsystem ist beispielsweise das System Erde und Erdmond.
Ein anderes Teilsystem wäre Jupiter mit seinen Monden. Verändern Sie dieses Interface nicht.
- [Drawable](../src/Drawable.java) wird von `CosmicSystem` verwendet. Verändern Sie dieses Interface
nicht.
- [NamedBodyForcePair](../src/NamedBodyForcePair.java) ist das Gerüst für eine Klassendefinition.
Die Klasse implementiert `CosmicSystem` und repräsentiert einen einzelnen benannten Himmelskörper
(z.B. "Mars") zusammen mit der auf ihn wirkenden Kraft.
- [HierarchicalSystem](../src/HierarchicalSystem.java) ist das Gerüst für eine Klassendefinition.
Die Klasse implementiert `CosmicSystem`und repräsentiert ein System von Himmelskörpern (z.B.
Sonnensystem) bestehend aus einem zentralen Himmelskörper und beliebig vielen Untersystemen in
dessen Orbit. Für alle Himmelskörper werden die Kräfte, die auf diese jeweils wirken, mitverwaltet.
- [Simulation4](../src/Simulation4.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).
- [Aufgabe4Test](../src/Aufgabe4Test.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. Entfernen Sie die Kommentarzeichen, um diese Klasse verwenden zu können. Sie
müssen diese Klasse nicht weiter verändern, können aber eigene Testfälle hinzufügen.
## Aufgaben
Ihre Aufgaben sind folgende:
**1. Implementierung von `CosmicSystem` in `NamedBodyForcePair`:**
Fügen Sie in der Klasse `Body` eine öffentliche Methode `massCenter()` hinzu, die die
Position des Himmelskörpers liefert.
Definieren Sie die Klasse `NamedBodyForcePair` so, dass sie das Interface `CosmicSystem`
implementiert. Die Methoden `getMass()` und `getMassCenter()` geben lediglich die Masse bzw.
Position des Himmelskörpers zurück.
**2. Implementierung von `CosmicSystem` in `HierarchicalSystem`:**
Definieren Sie die Klasse `HierarchicalSystem` so, dass sie das Interface `CosmicSystem` implementiert.
Die Klasse repräsentiert ein hierarchisch aufgebautes kosmisches System von Himmelskörpern.
Ein solches System besteht aus einem zentralen Himmelskörper und beliebig vielen weiteren
kosmischen Systemen, die sich im Orbit um diesen zentralen Himmelskörper befinden. Neben der
Spezifikationen in `CosmicSystem` beachten Sie bitte folgende spezielle Anforderungen und Hinweise
für die Implementierung:
- `toString()`: diese Methode soll eine textuelle Beschreibung der Hierarchie von Himmelskörpern
und Subsystemen liefern. Dafür wird der Namen des zentralen Himmelskörpers eines Systems
gefolgt von den Objekten im Orbit jeweils in {}-Klammern repräsentiert. Beispiel:
`"Sun {Mercury, Venus, Earth {Moon} , Mars {Deimos, Phobos} , Vesta, Pallas, Hygiea, Ceres}"`
- `numberOfBodies()`: diese Methode liefert die Gesamtanzahl aller Himmelskörper (nicht Systeme)
im System bzw. Himmelskörper, das heißt alle Objekte vom Typ `NamedBodyForcePair`. Das oben genannte
Beispiel-System besteht z.B. aus 12 Himmelskörpern, das Mars-System im Orbit der Sonne jedoch nur
aus 3.
- `getMass()`: diese Methode liefert die Summe der Massen aller Himmelskörper im System.
- `getMassCenter()`: diese Methode liefert den Schwerpunkt aller Himmelskörper im System. Dieser
entspricht dem mit den Massen gewichteten Mittelwert aller Positionen, es müssen daher alle Positionen
mit der jeweiligen Masse multipliziert und aufsummiert werden und das Resultat durch die Summe aller
Massen dividiert werden. Nutzen Sie dafür die bereits implementierten Rechenoperationen in `Vector3`.
- `addForceFrom(Body b)` aktualisiert für jedes `NamedBodyForcePair`-Objekt in `this` die Kraft,
indem die von `b` auf das `NamedBodyForcePair`-Objekt ausgeübte Kraft zur Kraft hinzuaddiert wird.
- `addForceTo(CosmicSystem cs)` aktualisiert für jedes `NamedBodyForcePair`-Objekt in `cs` die
Kraft, indem alle Kräfte die von Körpern aus `this` auf das `NamedBodyForcePair`-Objekt
ausgeübt werden, zur Kraft im Objekt hinzuaddiert werden. Beispiel: Die
Anweisung `cs.addForce(cs)` aktualisiert alle wechselseitigen im System `cs` wirkenden Kräfte.
- `update()` führt auf Basis der gespeicherten Kräfte alle Bewegungen im System `this` durch und
setzt danach alle Kräfte wieder auf den null-Vektor zurück.
- `getBodies()` liefert eine Liste (Typ: `BodyLinkedList`) mit allen Himmelskörpern aus `this`.
**3. Implementierung von `Simulation4`:**
Implementieren Sie die Simulationsschleife unter Verwendung eines Objekts vom Typ
`HierachicalSystem`. Alle Berechnungen sollen mittels Methoden von `CosmicSystem` durchgeführt
werden.
### Hinweise: ###
- Nutzen Sie für die Implementierung dieser Methoden Rekursion sowie das Konzept des _dynamischen Bindens_.
Da `NamedBodyForcePair` und `HierarchicalSystem` Untertypen von `CosmicSystem` sind, haben sie
jeweils eine eigene Implementierung der in `CosmicSystem` definierten Methoden und es wird zur
Laufzeit entschieden, von welchem dynamischen Typ ein Objekt ist und welche Methode somit ausgeführt
wird. Sie dürfen hier keine Typumwandlungen (Casts) und auch nicht die Methoden `getClass()` und
`instanceOf()` verwenden.
- Es ist möglich, aber nicht verlangt, `addForceTo(CosmicSystem cs)` ohne Verwendung von
`getBodies()` zu implementieren. Dazu kann in `addForceTo(CosmicSystem cs)` der Zugriff auf
die einzelnen Körper in `cs` dadurch erreicht werden, dass `this` für alle seine Himmelskörper
und Untersysteme `addForceTo(cs)` aufruft. Wird beim rekursiven Abstieg ein einzelner Himmelskörper
erreicht (Blattknoten) ruft dieser `cs.addForceFrom(this)` auf.
- Achten Sie bei der Berechnung der Kräfte in `addForceFrom(Body b)` darauf, dass die Kraft nicht
verändert wird, wenn `this` und `b` derselbe Himmelskörper sind.
#### _Punkteaufteilung_
- Implementierung von `CosmicSystem` in `NamedBodyForcePair`: 1.5 Punkte
- Implementierung von `CosmicSystem` in `HierarchicalSystem`: 2.5 Punkte
- Implementierung von `Simulation4`: 1 Punkte
- Gesamt: 5 Punkte

View File

@ -1,17 +1,19 @@
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);
Vector3 f2 = sun.gravitationalForce(earth); Vector3 f2 = sun.gravitationalForce(earth);
@ -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);
}
} }
} }

View File

@ -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);
}
} }
} }

View File

@ -1,73 +1,67 @@
import java.util.Objects; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class Aufgabe3Test { public class Aufgabe3Test {
public static void main(String[] args) { @Test
public void testEP2() {
//test classes BodyLinkedList and BodyForceTreeMap
// create five bodies // create five 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);
Body venus = new Body(4.86747e24, new Vector3(-1.707667e10, 1.066132e11, 2.450232e9), new Vector3(-34446.02, -5567.47, 2181.10)); Body venus = new Body(SolSystem.VENUS);
Body mars = new Body(6.41712e23, new Vector3(-1.010178e11, -2.043939e11, -1.591727E9), new Vector3(20651.98, -10186.67, -2302.79)); Body mars = new Body(SolSystem.MARS);
// check basic functions of 'BodyLinkedList' // check basic functions of 'BodyLinkedList'
System.out.println("Test1:");
BodyLinkedList bl = new BodyLinkedList(); BodyLinkedList bl = new BodyLinkedList();
bl.addLast(mercury); bl.addLast(mercury);
bl.addLast(sun); bl.addLast(sun);
bl.addLast(earth); bl.addLast(earth);
testValue(bl.size(), 3); assertEquals(3, bl.size());
testValue(bl.getFirst(), mercury); assertEquals(mercury, bl.getFirst());
testValue(bl.getLast(), earth); assertEquals(earth, bl.getLast());
testValue(bl.get(0), mercury); assertEquals(mercury, bl.get(0));
testValue(bl.get(1), sun); assertEquals(sun, bl.get(1));
testValue(bl.get(2), earth); assertEquals(earth, bl.get(2));
System.out.println("Test2:"); assertEquals(2, bl.indexOf(earth));
testValue(bl.indexOf(earth), 2); assertEquals(1, bl.indexOf(sun));
testValue(bl.indexOf(sun), 1); assertEquals(0, bl.indexOf(mercury));
testValue(bl.indexOf(mercury), 0);
System.out.println("Test3:"); assertEquals(mercury, bl.pollFirst());
testValue(bl.pollFirst(), mercury); assertEquals(earth, bl.pollLast());
testValue(bl.pollLast(), earth); assertEquals(sun, bl.pollFirst());
testValue(bl.pollFirst(), sun);
testValue(bl.size(), 0); assertEquals(0, bl.size());
testValue(bl.getFirst(), null); assertNull(bl.getFirst());
System.out.println("Test4:");
bl.addFirst(earth); bl.addFirst(earth);
bl.addFirst(venus); bl.addFirst(venus);
bl.addFirst(sun); bl.addFirst(sun);
bl.add(1, mercury); bl.add(1, mercury);
bl.add(4, mars); bl.add(4, mars);
testValue(bl.size(), 5); assertEquals(5, bl.size());
testValue(bl.get(0), sun); assertEquals(sun, bl.get(0));
testValue(bl.get(1), mercury); assertEquals(mercury, bl.get(1));
testValue(bl.get(2), venus); assertEquals(venus, bl.get(2));
testValue(bl.get(3), earth); assertEquals(earth, bl.get(3));
testValue(bl.get(4), mars); assertEquals(mars, bl.get(4));
// check constructor of 'BodyLinkedList' // check constructor of 'BodyLinkedList'
BodyLinkedList blCopy = new BodyLinkedList(bl); BodyLinkedList blCopy = new BodyLinkedList(bl);
testComparison(bl, blCopy, false); assertNotEquals(bl, blCopy);
testComparison(bl.pollFirst(), blCopy.pollFirst(), true); assertEquals(blCopy.pollFirst(), bl.pollFirst());
bl.addFirst(sun); bl.addFirst(sun);
testValue(bl.size(), 5); assertEquals(5, bl.size());
testValue(blCopy.size(), 4); assertEquals(4, blCopy.size());
// check basic functions of 'BodyForceTreeMap' // check basic functions of 'BodyForceTreeMap'
System.out.println("Test5:");
BodyForceTreeMap bfm = new BodyForceTreeMap(); BodyForceTreeMap bfm = new BodyForceTreeMap();
bfm.put(earth, earth.gravitationalForce(sun)); bfm.put(earth, earth.gravitationalForce(sun));
bfm.put(sun, sun.gravitationalForce(earth).plus(sun.gravitationalForce(venus))); bfm.put(sun, sun.gravitationalForce(earth).plus(sun.gravitationalForce(venus)));
@ -75,38 +69,11 @@ public class Aufgabe3Test {
bfm.put(mars, mars.gravitationalForce(sun)); bfm.put(mars, mars.gravitationalForce(sun));
bfm.put(mercury, mercury.gravitationalForce(sun)); bfm.put(mercury, mercury.gravitationalForce(sun));
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).plus(sun.gravitationalForce(venus))), 0); assertEquals(0, bfm.get(sun).distanceTo(sun.gravitationalForce(earth).plus(sun.gravitationalForce(venus))));
testValue(bfm.put(earth, new Vector3(0, 0, 0)).distanceTo(earth.gravitationalForce(sun)), 0); assertEquals(0, bfm.put(earth, new Vector3(0, 0, 0)).distanceTo(earth.gravitationalForce(sun)));
testValue(bfm.get(earth).distanceTo(new Vector3(0, 0, 0)), 0); assertEquals(0, bfm.get(mercury).distanceTo(mercury.gravitationalForce(sun)));
testValue(bfm.get(mercury), mercury.gravitationalForce(sun)); assertEquals(mercury.gravitationalForce(sun), 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);
}
} }
} }

110
src/Aufgabe4Test.java Normal file
View File

@ -0,0 +1,110 @@
import java.util.HashSet;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class Aufgabe4Test {
private NamedBodyForcePair sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2;
public void resetBodies() {
sun2 = new NamedBodyForcePair(SolSystem4.SUN_NAMED);
earth2 = new NamedBodyForcePair(SolSystem4.EARTH_NAMED);
moon2 = new NamedBodyForcePair(SolSystem4.MOON_NAMED);
mars2 = new NamedBodyForcePair(SolSystem4.MARS_NAMED);
deimos2 = new NamedBodyForcePair(SolSystem4.DEIMOS_NAMED);
phobos2 = new NamedBodyForcePair(SolSystem4.PHOBOS_NAMED);
mercury2 = new NamedBodyForcePair(SolSystem4.MERCURY_NAMED);
venus2 = new NamedBodyForcePair(SolSystem4.VENUS_NAMED);
vesta2 = new NamedBodyForcePair(SolSystem4.VESTA_NAMED);
pallas2 = new NamedBodyForcePair(SolSystem4.PALLAS_NAMED);
hygiea2 = new NamedBodyForcePair(SolSystem4.HYGIEA_NAMED);
ceres2 = new NamedBodyForcePair(SolSystem4.CERES_NAMED);
}
@Test
public void testEP2() {
//test classes HierarchicalSystem and NamedBodyForcePair
Body sun1 = new Body(SolSystem4.SUN);
Body earth1 = new Body(SolSystem4.EARTH);
Body moon1 = new Body(SolSystem4.MOON);
Body mars1 = new Body(SolSystem4.MARS);
Body deimos1 = new Body(SolSystem4.DEIMOS);
Body phobos1 = new Body(SolSystem4.PHOBOS);
Body mercury1 = new Body(SolSystem4.MERCURY);
Body venus1 = new Body(SolSystem4.VENUS);
Body vesta1 = new Body(SolSystem4.VESTA);
Body pallas1 = new Body(SolSystem4.PALLAS);
Body hygiea1 = new Body(SolSystem4.HYGIEA);
Body ceres1 = new Body(SolSystem4.CERES);
Body[] bodies = new Body[]{sun1, mercury1, venus1, earth1, moon1, mars1, deimos1, phobos1, vesta1, pallas1, hygiea1, ceres1};
Vector3[] forceOnBody = new Vector3[bodies.length];
resetBodies();
NamedBodyForcePair[] pairs = new NamedBodyForcePair[]{sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2};
// check basic functions of 'HierarchicalSystem'
CosmicSystem earthSystem = new HierarchicalSystem(earth2, moon2);
CosmicSystem marsSystem = new HierarchicalSystem(mars2, deimos2, phobos2);
CosmicSystem solarSystem = new HierarchicalSystem(sun2, mercury2, venus2, earthSystem, marsSystem, vesta2, pallas2, hygiea2, ceres2);
assertEquals(2, earthSystem.numberOfBodies());
assertEquals(12, solarSystem.numberOfBodies());
System.out.println(solarSystem);
assertTrue(solarSystem.toString().contains("Mars"));
assertTrue(solarSystem.toString().contains("Deimos"));
assertTrue(solarSystem.toString().contains("Moon"));
assertTrue(earthSystem.toString().contains("Moon"));
assertTrue(earthSystem.toString().contains("Earth"));
assertEquals(1.9890118865556799E30, solarSystem.getMass());
BodyLinkedList bl = solarSystem.getBodies();
assertEquals(12, bl.size());
HashSet<Body> set = new HashSet<>();
while (bl.size() > 0) {
set.add(bl.pollFirst());
}
assertEquals(12, set.size());
for (int seconds = 0; seconds < 50000; seconds++) {
// 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(0, 0, 0); // begin with zero
for (int j = 0; j < bodies.length; j++) {
if (i != j) {
pairs[i].addForceTo(pairs[j]);
Vector3 forceToAdd = bodies[i].gravitationalForce(bodies[j]);
forceOnBody[i] = forceOnBody[i].plus(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++) {
bodies[i].move(forceOnBody[i]);
pairs[i].update();
}
}
for (int i = 0; i < bodies.length; i++) {
assertEquals(0, bodies[i].massCenter().distanceTo(pairs[i].getMassCenter()));
}
resetBodies();
pairs = new NamedBodyForcePair[]{sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2};
HierarchicalSystem hs = new HierarchicalSystem(sun2, mercury2, venus2, new HierarchicalSystem(earth2, moon2), new HierarchicalSystem(mars2, deimos2, phobos2), vesta2, pallas2, hygiea2, ceres2);
for (int seconds = 0; seconds < 50000; seconds++) {
hs.addForceTo(hs);
hs.update();
}
for (int i = 0; i < bodies.length; i++) {
assertEquals(0, bodies[i].massCenter().distanceTo(pairs[i].getMassCenter()));
}
}
}

View File

@ -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'.
*/ */
@ -29,8 +35,10 @@ public class Body {
* Hint: see simulation loop in Simulation.java to find out how this is done. * Hint: see simulation loop in Simulation.java to find out how this is done.
*/ */
public Vector3 gravitationalForce(Body b) { public Vector3 gravitationalForce(Body b) {
if (b == this) return new Vector3();
Vector3 direction = b.massCenter.minus(massCenter); Vector3 direction = b.massCenter.minus(massCenter);
double distance = direction.length(); double distance = direction.length();
if (distance == 0) return new Vector3();
direction.normalize(); direction.normalize();
double force = Simulation.G * mass * b.mass / (distance * distance); double force = Simulation.G * mass * b.mass / (distance * distance);
return direction.times(force); return direction.times(force);
@ -70,16 +78,24 @@ public class Body {
return mass; return mass;
} }
public Vector3 massCenter() {
return massCenter;
}
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 +116,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()
); );
} }

View File

@ -1,40 +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. * 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 { public class BodyForceTreeMap {
private int size = 0;
private BodyForceTreeMapItem root = null;
//TODO: declare variables. /**
* Adds a new key-value association to this map. If the key already exists in this map,
// 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.
// the value is replaced and the old value is returned. Otherwise 'null' is returned. * Precondition: key != null.
// Precondition: key != null. */
public Vector3 put(Body key, Vector3 value) { 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;
}
}
}
//TODO: implement method.
return null; 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. * Returns the value associated with the specified key, i.e. the method returns the force vector
// Precondition: key != null. * associated with the specified key. Returns 'null' if the key is not contained in this map.
* Precondition: key != null.
*/
public Vector3 get(Body key) { public Vector3 get(Body key) {
BodyForceTreeMapItem item = root;
//TODO: implement method. 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; return null;
} }
// Returns 'true' if this map contains a mapping for the specified key. /**
* Returns 'true' if this map contains a mapping for the specified key.
*/
public boolean containsKey(Body key) { public boolean containsKey(Body key) {
BodyForceTreeMapItem item = root;
//TODO: implement method. 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; return false;
} }
// Returns a readable representation of this map, in which key-value pairs are ordered public int size() {
// descending according to the mass of the bodies. 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() { public String toString() {
return toString(root);
//TODO: implement method. }
return null; }
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;
} }
} }

View File

@ -1,103 +1,261 @@
// A list of bodies implemented as a linked list. import java.util.Iterator;
// The number of elements of the list is not limited.
public class BodyLinkedList {
//TODO: declare variables. /**
* 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. /**
* Initializes 'this' as an empty list.
*/
public BodyLinkedList() { public BodyLinkedList() {
first = null;
//TODO: define constructor. 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' * Initializes 'this' as an independent copy of the specified list 'list'.
// and vice versa. * Calling methods of this list will not affect the specified list 'list'
// Precondition: list != null. * and vice versa.
* Precondition: list != null.
*/
public BodyLinkedList(BodyLinkedList list) { public BodyLinkedList(BodyLinkedList list) {
this.size = 0;
//TODO: define constructor. for (Body b : list) {
this.addLast(b);
}
} }
// Inserts the specified element 'body' at the beginning of this list. /**
* Inserts the specified element 'body' at the beginning of this list.
*/
public void addFirst(Body body) { public void addFirst(Body body) {
if (first == null) {
//TODO: implement method. 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. /**
* Appends the specified element 'body' to the end of this list.
*/
public void addLast(Body body) { public void addLast(Body body) {
if (last == null) {
//TODO: implement method. 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. * Returns the last element in this list.
* Returns 'null' if the list is empty.
*/
public Body getLast() { public Body getLast() {
return (last != null) ? last.body() : null;
//TODO: implement method.
return null;
} }
// Returns the first element in this list. /**
// Returns 'null' if the list is empty. * Returns the first element in this list.
* Returns 'null' if the list is empty.
*/
public Body getFirst() { public Body getFirst() {
return (first != null) ? first.body() : null;
//TODO: implement method.
return null;
} }
// Retrieves and removes the first element in this list. /**
// Returns 'null' if the list is empty. * Retrieves and removes the first element in this list.
* Returns 'null' if the list is empty.
*/
public Body pollFirst() { public Body pollFirst() {
if (first == null) {
//TODO: implement method. return 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. * Retrieves and removes the last element in this list.
* Returns 'null' if the list is empty.
*/
public Body pollLast() { public Body pollLast() {
if (last == null) {
//TODO: implement method. return 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(). * Inserts the specified element 'body' at the specified position in this list.
* Precondition: i >= 0 && i <= size().
*/
public void add(int i, Body body) { public void add(int i, Body body) {
if (first == null || i == 0) {
addFirst(body);
return;
} else if (i == size) {
addLast(body);
return;
}
//TODO: implement method. 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++;
} }
// Returns the element at the specified position in this list. private Body removeItem(BodyLinkedListItem item) {
// Precondition: i >= 0 && i < size(). 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) { public Body get(int i) {
BodyLinkedListItem item;
//TODO: implement method. if (i < size / 2) {
return null; 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. * 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) { public int indexOf(Body body) {
if (first == null) {
return -1;
}
//TODO: implement method. BodyLinkedListItem item = first;
return -2; for (int i = 0; i < size; i++) {
} if (item.body() == body) {
return i;
}
item = item.next();
}
// 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) {
//TODO: implement method.
return null;
}
// Returns the number of bodies in this list.
public int size() {
//TODO: implement method.
return -1; 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;
}
} }

View File

@ -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;

59
src/CosmicSystem.java Normal file
View File

@ -0,0 +1,59 @@
/**
* A representation of a system of bodies with associated forces. Provides methods
* for computing current mutual forces, updating the positions of bodies and drawing
* the bodies in a CodeDraw object.
*/
public interface CosmicSystem extends Drawable {
/**
* Returns a readable representation of this system.
*/
String toString();
/**
* Returns the mass center of this system.
*/
Vector3 getMassCenter();
/**
* Returns the overall mass of this system.
*/
double getMass();
/**
* Returns the overall number of bodies contained in this system.
*/
int numberOfBodies();
/**
* Returns the distance between the mass centers of 'this' and the specified system.
* Precondition: cs != null
*/
double distanceTo(CosmicSystem cs);
/**
* Adds the force that the specified body exerts on each of this systems bodies to each of this
* systems bodies.
* Precondition: b != null
*/
void addForceFrom(Body b);
/**
* Adds the force that this system exerts on each of the bodies of 'cs' to the bodies in 'cs'.
* For exact computations this means that for each body of 'this' its force on each body of
* 'cs' is added to this body of 'cs'.
* Precondition: cs != null
*/
void addForceTo(CosmicSystem cs);
/**
* Returns a list with all the bodies of 'this'. The order is not defined.
*/
BodyLinkedList getBodies();
/**
* Moves each of the bodies of 'this' according to the previously accumulated forces and
* resets all forces to zero.
*/
void update();
}

13
src/Drawable.java Normal file
View File

@ -0,0 +1,13 @@
import codedraw.CodeDraw;
/**
* An object that can be drawn in a CodeDraw canvas.
*/
public interface Drawable {
/**
* draws the object into the canvas 'cd'
* Precondition: cd != null
*/
void draw(CodeDraw cd);
}

113
src/HierarchicalSystem.java Normal file
View File

@ -0,0 +1,113 @@
import codedraw.CodeDraw;
/**
* A cosmic system that is composed of a central named body (of type 'NamedBodyForcePair')
* and an arbitrary number of subsystems (of type 'CosmicSystem') in its orbit.
* This class implements 'CosmicSystem'.
*/
public class HierarchicalSystem implements CosmicSystem {
private final NamedBodyForcePair central;
private final CosmicSystem[] orbit;
private final CosmicSystem[] all;
/**
* Initializes this system with a name and a central body.
*/
public HierarchicalSystem(NamedBodyForcePair central, CosmicSystem... inOrbit) {
this.central = central;
this.orbit = inOrbit;
this.all = new CosmicSystem[this.orbit.length + 1];
this.all[0] = central;
System.arraycopy(this.orbit, 0, this.all, 1, this.orbit.length);
}
@Override
public Vector3 getMassCenter() {
double mass = this.getMass();
Vector3 massCenter = new Vector3();
for (CosmicSystem sys : all) {
massCenter.add(sys.getMassCenter().times(sys.getMass() / mass));
}
return massCenter;
}
@Override
public double getMass() {
double mass = 0;
for (CosmicSystem sys : all) {
mass += sys.getMass();
}
return mass;
}
@Override
public int numberOfBodies() {
int num = 0;
for (CosmicSystem sys : all) {
num += sys.numberOfBodies();
}
return num;
}
@Override
public double distanceTo(CosmicSystem cs) {
return this.getMassCenter().distanceTo(cs.getMassCenter());
}
@Override
public void addForceFrom(Body b) {
for (CosmicSystem sys : all) {
sys.addForceFrom(b);
}
}
@Override
public void addForceTo(CosmicSystem cs) {
for (CosmicSystem sys : all) {
sys.addForceTo(cs);
}
}
@Override
public BodyLinkedList getBodies() {
BodyLinkedList list = new BodyLinkedList();
for (CosmicSystem sys : all) {
for (Body b : sys.getBodies()) {
list.addFirst(b);
}
}
return list;
}
@Override
public void update() {
for (CosmicSystem sys : all) {
sys.update();
}
}
@Override
public void draw(CodeDraw cd) {
for (CosmicSystem sys : all) {
sys.draw(cd);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(central.getName());
sb.append(" {");
boolean first = true;
for (CosmicSystem sys : orbit) {
if (!first) sb.append(", ");
sb.append(sys.toString());
first = false;
}
sb.append("}");
return sb.toString();
}
}

View File

@ -0,0 +1,93 @@
import codedraw.CodeDraw;
/**
* A body with a name and an associated force. The leaf node of
* a hierarchical cosmic system. This class implements 'CosmicSystem'.
*/
public class NamedBodyForcePair implements CosmicSystem {
private final String name;
private final Body body;
private final Vector3 force = new Vector3();
/**
* Initializes this with name, mass, current position and movement. The associated force
* is initialized with a zero vector.
*/
public NamedBodyForcePair(String name, double mass, Vector3 massCenter, Vector3 currentMovement) {
this(name, new Body(mass, massCenter, currentMovement));
}
public NamedBodyForcePair(String name, Body b) {
this.body = b;
this.name = name;
}
public NamedBodyForcePair(NamedBodyForcePair other) {
this(other.name, new Body(other.body));
}
public Body getBody() {
return body;
}
/**
* Returns the name of the body.
*/
public String getName() {
return name;
}
@Override
public String toString() {
return this.getName();
}
@Override
public Vector3 getMassCenter() {
return body.massCenter();
}
@Override
public double getMass() {
return body.mass();
}
@Override
public int numberOfBodies() {
return 1;
}
@Override
public double distanceTo(CosmicSystem cs) {
return getMassCenter().distanceTo(cs.getMassCenter());
}
@Override
public void addForceFrom(Body b) {
force.add(body.gravitationalForce(b));
}
@Override
public void addForceTo(CosmicSystem cs) {
cs.addForceFrom(body);
}
@Override
public BodyLinkedList getBodies() {
BodyLinkedList list = new BodyLinkedList();
list.addFirst(body);
return list;
}
@Override
public void update() {
body.move(force);
force.set(0);
}
@Override
public void draw(CodeDraw cd) {
body.draw(cd);
}
}

View File

@ -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++) {

View File

@ -1,11 +1,74 @@
// Simulates the formation of a massive solar system. import codedraw.CodeDraw;
//
import java.awt.*;
import java.util.Random;
/**
* Simulates the formation of a massive solar system.
*/
public class Simulation3 { public class Simulation3 {
// The main simulation method using instances of other classes. /**
* The main simulation method using instances of other classes.
*/
public static void main(String[] args) { public static void main(String[] args) {
CodeDraw cd = new CodeDraw();
BodyLinkedList bodies = new BodyLinkedList();
BodyForceTreeMap forceOnBody = new BodyForceTreeMap();
//TODO: change implementation of this method according to 'Aufgabenblatt3.md'. 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();
}
}
} }
} }

51
src/Simulation4.java Normal file
View File

@ -0,0 +1,51 @@
import codedraw.CodeDraw;
import java.awt.*;
/**
* Simulates the formation of a massive solar system.
*/
public class Simulation4 {
public static final double SECTION_SIZE = 10 * Simulation.AU;
/**
* The main simulation method using instances of other classes.
*/
public static void main(String[] args) {
CodeDraw cd = new CodeDraw();
NamedBodyForcePair sun = new NamedBodyForcePair(SolSystem4.SUN_NAMED);
NamedBodyForcePair earth = new NamedBodyForcePair(SolSystem4.EARTH_NAMED);
NamedBodyForcePair moon = new NamedBodyForcePair(SolSystem4.MOON_NAMED);
NamedBodyForcePair mars = new NamedBodyForcePair(SolSystem4.MARS_NAMED);
NamedBodyForcePair deimos = new NamedBodyForcePair(SolSystem4.DEIMOS_NAMED);
NamedBodyForcePair phobos = new NamedBodyForcePair(SolSystem4.PHOBOS_NAMED);
NamedBodyForcePair mercury = new NamedBodyForcePair(SolSystem4.MERCURY_NAMED);
NamedBodyForcePair venus = new NamedBodyForcePair(SolSystem4.VENUS_NAMED);
NamedBodyForcePair vesta = new NamedBodyForcePair(SolSystem4.VESTA_NAMED);
NamedBodyForcePair pallas = new NamedBodyForcePair(SolSystem4.PALLAS_NAMED);
NamedBodyForcePair hygiea = new NamedBodyForcePair(SolSystem4.HYGIEA_NAMED);
NamedBodyForcePair ceres = new NamedBodyForcePair(SolSystem4.CERES_NAMED);
CosmicSystem earthSystem = new HierarchicalSystem(earth, moon);
CosmicSystem marsSystem = new HierarchicalSystem(mars, deimos, phobos);
CosmicSystem sol = new HierarchicalSystem(sun, mercury, venus, earthSystem, marsSystem, vesta, pallas, hygiea, ceres);
long seconds = 0;
while (true) {
seconds++;
for (Body b : sol.getBodies()) {
sol.addForceFrom(b);
}
sol.update();
if ((seconds % 3600) == 0) {
cd.clear(Color.BLACK);
sol.draw(cd);
cd.show();
}
}
}
}

7
src/SolSystem.java Normal file
View 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));
}

27
src/SolSystem4.java Normal file
View File

@ -0,0 +1,27 @@
public class SolSystem4 {
public static final Body SUN = new Body(1.989E30, new Vector3(0.0, 0.0, 0.0), new Vector3(0.0, 0.0, 0.0));
public static final Body EARTH = new Body(5.972E24, new Vector3(-6.13135922534815E10, -1.383789852227691E11, 2.719682263474911E7), new Vector3(26832.720535473603, -11948.23168764519, 1.9948243075997851));
public static final Body MOON = new Body(7.349E22, new Vector3(-6.132484773775896E10, -1.387394951280871E11, 1.701046736294776E7), new Vector3(27916.62329282941, -12020.39526008238, -94.89703264508708));
public static final Body MARS = new Body(6.41712E23, new Vector3(-1.7923193702925848E11, 1.726665823982123E11, 7.991673845249474E9), new Vector3(-15925.78496403673, -15381.16179928219, 68.67560910598857));
public static final Body DEIMOS = new Body(1.8E20, new Vector3(-1.792255010450533E11, 1.726891122683271E11, 7.990659337380297E9), new Vector3(-17100.476719804457, -15020.348656808, 631.2927851249581));
public static final Body PHOBOS = new Body(1.08E20, new Vector3(-1.792253482539647E11, 1.72661109673625E11, 7.987848354800322E9), new Vector3(-14738.203714241401, -13671.17675223948, -411.0012490555253));
public static final Body MERCURY = new Body(3.301E23, new Vector3(-5.167375560011926E10, -4.217574885682655E10, 1.14808913958168E9), new Vector3(21580.25398577148, -34951.03632847389, -4835.225596525241));
public static final Body VENUS = new Body(4.86747E24, new Vector3(-3.123150865740532E10, 1.0395568504115701E11, 3.173401325838074E9), new Vector3(-33748.180519629335, -10014.25141045021, 1809.94488874165));
public static final Body VESTA = new Body(2.5908E20, new Vector3(-3.337493557929893E11, -4.7147908276077385E10, 4.1923010146878105E10), new Vector3(4440.54247538484, -19718.49074006637, 48.06573124543601));
public static final Body PALLAS = new Body(2.14E20, new Vector3(4.3452066613895575E11, -2.057319365171432E11, 1.0549957423213101E11), new Vector3(5058.947582097117, 11184.45711782372, -8183.524138259704));
public static final Body HYGIEA = new Body(8.32E19, new Vector3(-3.983943433707043E11, 2.325833000024021E11, -2.233667695713672E10), new Vector3(-6931.864585548552, -15686.8108598699, -690.5791992347208));
public static final Body CERES = new Body(9.394E20, new Vector3(3.781372641419032E11, 1.96718960466285E11, -6.366459168068592E10), new Vector3(-8555.324226752316, 14718.33755980907, 2040.230135060142));
public static final NamedBodyForcePair SUN_NAMED = new NamedBodyForcePair("Sun", SUN);
public static final NamedBodyForcePair EARTH_NAMED = new NamedBodyForcePair("Earth", EARTH);
public static final NamedBodyForcePair MOON_NAMED = new NamedBodyForcePair("Moon", MOON);
public static final NamedBodyForcePair MARS_NAMED = new NamedBodyForcePair("Mars", MARS);
public static final NamedBodyForcePair DEIMOS_NAMED = new NamedBodyForcePair("Deimos", DEIMOS);
public static final NamedBodyForcePair PHOBOS_NAMED = new NamedBodyForcePair("Phobos", PHOBOS);
public static final NamedBodyForcePair MERCURY_NAMED = new NamedBodyForcePair("Mercury", MERCURY);
public static final NamedBodyForcePair VENUS_NAMED = new NamedBodyForcePair("Venus", VENUS);
public static final NamedBodyForcePair VESTA_NAMED = new NamedBodyForcePair("Vesta", VESTA);
public static final NamedBodyForcePair PALLAS_NAMED = new NamedBodyForcePair("Pallas", PALLAS);
public static final NamedBodyForcePair HYGIEA_NAMED = new NamedBodyForcePair("Hygiea", HYGIEA);
public static final NamedBodyForcePair CERES_NAMED = new NamedBodyForcePair("Ceres", CERES);
}

View File

@ -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;
}
} }
} }

View File

@ -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,51 @@ public class Vector3 {
this.z = z; this.z = z;
} }
public Vector3(Vector3 other) {
this(other.x, other.y, other.z);
}
public void set(double v) {
set(v, v, v);
}
public void set(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = 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; public void add(Vector3 v) {
return result; this.x += v.x;
this.y += v.y;
this.z += v.z;
} }
/** /**
* 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; public void sub(Vector3 v) {
return result; this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
} }
/** /**
@ -85,22 +98,38 @@ public class Vector3 {
z /= length; z /= length;
} }
public double getScreenX(CodeDraw cd) {
return cd.getWidth() * (this.x + Simulation4.SECTION_SIZE / 2) / Simulation4.SECTION_SIZE;
}
public double getScreenY(CodeDraw cd) {
return cd.getWidth() * (this.y + Simulation4.SECTION_SIZE / 2) / Simulation4.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; radius = cd.getWidth() * radius / Simulation4.SECTION_SIZE;
double y = cd.getWidth() * (this.y + Simulation.SECTION_SIZE / 2) / Simulation.SECTION_SIZE; cd.fillCircle(getScreenX(cd), getScreenY(cd), Math.max(radius, 1.5));
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 * 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;
} }
} }