Compare commits
51 Commits
Abgabe1
...
Abgabe8-Na
Author | SHA1 | Date | |
---|---|---|---|
708515ee4f
|
|||
a951b5c14a
|
|||
150eb7aa49
|
|||
ac40ada302
|
|||
cfba0106a9
|
|||
8f6320e069 | |||
d718ba90e3 | |||
eab0db8e40 | |||
406c9b02f7 | |||
05c52cd3f5 | |||
088fa3cdeb
|
|||
f801a331c2
|
|||
b89fc15602
|
|||
2e14e45bb0 | |||
e311ef3c6b | |||
a62ef91a8a | |||
34c2ac91c6
|
|||
a075544fe2
|
|||
391b389063
|
|||
e7eae474ac
|
|||
6b1f1ecc2a
|
|||
e84bf3bf4a | |||
1e789dba34 | |||
e94d3daeda | |||
35743c64b6
|
|||
b3ddcec038
|
|||
cf188f1b2d
|
|||
60ea5aa6f4 | |||
ef01f2a0fc | |||
95a4907dd2
|
|||
dfbdd6dc9d
|
|||
f156da4803
|
|||
cda144aa2a
|
|||
4bb1d6a36c
|
|||
01b2fb8989
|
|||
9925835a1e
|
|||
f24ad9bcaf
|
|||
cf4c1ad9d0
|
|||
8c67e157d5
|
|||
07ef38dab3 | |||
78d70f8a43
|
|||
9ce478b88e
|
|||
e52a1323c7
|
|||
a52a479910 | |||
324626f5eb | |||
fcacaa8657
|
|||
dca869995a
|
|||
5158aa2cbe
|
|||
f6c662e704 | |||
06d7e6dfaf | |||
322c15576b |
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,5 +1,8 @@
|
||||
# modified from https://github.com/javaee-samples/javaee8-samples/blob/master/.gitignore
|
||||
|
||||
.idea/
|
||||
/*.iml
|
||||
|
||||
# Directories #
|
||||
build/
|
||||
out/
|
||||
|
3
.idea/.gitignore
generated
vendored
3
.idea/.gitignore
generated
vendored
@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
11
.idea/libraries/CodeDraw.xml
generated
11
.idea/libraries/CodeDraw.xml
generated
@ -1,11 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="CodeDraw">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/CodeDraw.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/CodeDraw.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11.0.2" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/angaben.iml" filepath="$PROJECT_DIR$/angaben.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
124
.idea/uiDesigner.xml
generated
124
.idea/uiDesigner.xml
generated
@ -1,124 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -3,7 +3,7 @@
|
||||
## Allgemeine Anmerkungen
|
||||
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 21.3.2022 11:00 Uhr durch `git commit` und `push` abzugeben. Mit der Angabe werden folgende Dateien mitgeliefert, die sie gemäß der Angabe verändern müssen: `Simulation.java`, `Vector3.java`, `Body.java` und zum Testen `Aufgabe1Test.java`. Die zusätzliche Datei `CodeDraw.jar` wird nur zum Zeichnen verwendet und sollte nicht entfernt oder verändert werden. Die zusätzliche Datei `SpaceDraw.java` enthält Methoden, die in der Simulation benötigt werden. Diese Methoden können Sie auch in Ihrer Lösung aufrufen.
|
||||
|
||||
Vorgegebene Programmteile dürfen nur an den Stellen verändert werden, die mit TODO markiert sind. 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.
|
||||
Vorgegebene Programmteile dürfen nur an den Stellen verändert werden, die mit `TODO` markiert sind. 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.
|
||||
|
||||
## Verwendung in IntelliJ
|
||||
Diese Aufgabenstellung ist ein vollständiges IntelliJ-Projekt, das Sie bereits in IntelliJ öffnen können. Sie müssen daher kein eigenes Projekt anlegen. Öffnen Sie nach dem Klonen des Repos in IntelliJ einfach den entsprechenden Ordner. Gegebenenfalls muss noch folgender Schritt ausgeführt werden:
|
||||
|
63
angabe/Aufgabenblatt2.md
Normal file
63
angabe/Aufgabenblatt2.md
Normal file
@ -0,0 +1,63 @@
|
||||
# Aufgabenblatt 2
|
||||
|
||||
## Allgemeine Anmerkungen
|
||||
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 28.3. 11h durch `git commit` und `push`
|
||||
abzugeben. Mit der Angabe werden folgende Dateien mitgeliefert: `BodyQueue.java`, `BodyForceMap.java` und `Aufgabe2Test.java`. Diese Klassen dürfen nur an den Stellen verändert werden, die mit `TODO` markiert sind. 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 linearen und einer assoziativen Datenstruktur (siehe Skriptum Seiten 50-59).
|
||||
|
||||
## Beschreibung der gegebenen Dateien
|
||||
- `BodyQueue` ist das Gerüst für eine Implementierung einer linearen Datenstruktur zur Verwaltung
|
||||
von Objekten des Typs `Body`.
|
||||
- `BodyForceMap` ist das Gerüst für eine Implementierung einer assoziativen Datenstruktur, die
|
||||
einen Himmelskörper mit der auf ihn wirkenden Kraft assoziiert.
|
||||
- `Aufgabe2Test` 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.
|
||||
|
||||
## Aufgaben
|
||||
|
||||
Ihre Aufgaben sind folgende:
|
||||
|
||||
1. Fügen Sie in der Klasse `Body` eine öffentliche Objektmethode `mass()` hinzu, die die Masse des Himmelkörpers zurückliefert.
|
||||
2. Vervollständigen Sie die Klassendefinitionen in `BodyQueue.java` gemäß der Kommentare in den Dateien. Die Implementierung soll mit Hilfe eines Arrays erfolgen. Bei der Erzeugung soll das Array die Länge haben, die im Konstruktor angegeben wird. Diese wird verdoppelt, sobald alle Plätze belegt sind. Benutzen Sie keine vorgefertigten Klassen aus dem Java-Collection-Framework!
|
||||
3. Vervollständigen Sie die Klassendefinition in `BodyForceMap.java`. Die Implementierung soll mit Hilfe eines Arrays erfolgen. Benutzen Sie keine vorgefertigten Klassen aus dem Java-Collection-Framework! Implementieren Sie diese Klasse so, dass die Einträge im Array nach der Masse der Himmelskörper absteigend sortiert sind. Das erhöht zwar den Aufwand beim erstmaligen Eintragen eines Schlüssels-Werte-Paars (Methode `put`), da alle Positionen ab der Einfügeposition verschoben werden müssen, es ermöglicht aber eine schnellere Suche nach dem Schlüssel (Methode `get`) mittels binärer Suche. Folgendes Beispiel zeigt die binäre Suche nach der Einfügeposition in einem absteigend sortierten Array. Mit einer entsprechenden zusätzlichen Überprüfung kann auf diese Weise auch der Schlüssel gefunden werden (z.B. `if (keys[middle] == toFind)` ...). Geordnet sind die Einträge nach der Masse, den Schlüssel bildet aber der Himmelskörper.
|
||||
|
||||
```
|
||||
Body[] keys; // assume descending order according to mass
|
||||
Body toInsert;
|
||||
...
|
||||
|
||||
int left = 0;
|
||||
int right = size - 1;
|
||||
|
||||
while (left <= right) {
|
||||
int middle = left + ((right - left) / 2);
|
||||
if (keys[middle].mass() < toInsert.mass()) {
|
||||
right = middle - 1;
|
||||
} else {
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// index where to insert: right + 1
|
||||
```
|
||||
4. Bauen Sie die bereits bestehende Klasse `Simulation` so um, dass keine Kollisionen von Himmelskörpern mehr berücksichtigt werden. Dadurch soll der Programmcode vereinfacht werden. Die Anzahl der Himmelskörper ändert sich im Laufe der Simulation somit nicht. Testen Sie die Simulation.
|
||||
5. Ändern Sie nun die Klasse `Simulation` so, dass zur Verwaltung der Himmelskörper anstelle des Arrays Objekte der Klassen `BodyQueue` und `BodyForceMap` verwendet werden. Das heißt beispielsweise, dass die Zugriffe auf die Himmelskörper der Simulation über Methoden von `BodyQueue` erfolgen müssen. Anstelle des Arrays `forceOnBody` soll ein Objekt des Typs `BodyForceMap` benutzt werden.
|
||||
6. Testen Sie die Simulation wieder. Das Verhalten der Simulation sollte unverändert sein. Je nach Implementierung der Klassen `BodyQueue` und `BodyForceMap` ist es möglich (und kein Problem), dass die Simulation jetzt langsamer läuft, als nach dem Umbau in Schritt 4.
|
||||
7. (Freiwillige Zusatzaufgabe ohne Bewertung:) Testen Sie die Simulation mit den folgenden fünf
|
||||
Himmelskörpern:
|
||||
```
|
||||
Body sun = new Body(1.989e30,new Vector3(0,0,0),new Vector3(0,0,0));
|
||||
Body earth = new Body(5.972e24,new Vector3(-1.394555e11,5.103346e10,0),new Vector3(-10308.53,-28169.38,0));
|
||||
Body mercury = new Body(3.301e23,new Vector3(-5.439054e10,9.394878e9,0),new Vector3(-17117.83,-46297.48,-1925.57));
|
||||
Body venus = new Body(4.86747e24,new Vector3(-1.707667e10,1.066132e11,2.450232e9),new Vector3(-34446.02,-5567.47,2181.10));
|
||||
Body mars = new Body(6.41712e23,new Vector3(-1.010178e11,-2.043939e11,-1.591727E9),new Vector3(20651.98,-10186.67,-2302.79));
|
||||
```
|
||||
|
||||
#### _Punkteaufteilung_
|
||||
|
||||
- Implementierung von `BodyQueue`: 2 Punkte
|
||||
- Implementierung von `BodyForceMap`: 2 Punkte
|
||||
- Anpassung von `Simulation`: 1 Punkt
|
||||
- Gesamt: 5 Punkte
|
49
angabe/Aufgabenblatt3.md
Normal file
49
angabe/Aufgabenblatt3.md
Normal file
@ -0,0 +1,49 @@
|
||||
# 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
|
122
angabe/Aufgabenblatt4.md
Normal file
122
angabe/Aufgabenblatt4.md
Normal 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
|
102
angabe/Aufgabenblatt5.md
Normal file
102
angabe/Aufgabenblatt5.md
Normal file
@ -0,0 +1,102 @@
|
||||
# Aufgabenblatt 5
|
||||
|
||||
## Allgemeine Anmerkungen
|
||||
|
||||
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 9.5. 11h durch `git commit` und `git push`
|
||||
abzugeben. Mit der Angabe werden die Dateien `Massive.java`, `NamedBody.java`, `MassiveLinkedList.java`,
|
||||
`MassiveForceHashMap.java`, `Simulation5.java` und `Aufgabe5Test.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: Gleichheit und Hash-Werte, Hash-Tabelle
|
||||
(siehe Skriptum Seite 85-91).
|
||||
|
||||
## Beschreibung der gegebenen Dateien
|
||||
|
||||
- [Massive](../src/Massive.java) ist ein Interface, das Himmelskörper (als kohärente Massen)
|
||||
beschreibt. `Massive` ist der gemeinsame Obertyp für verschiedene Klassen von Himmelkörpern. Die
|
||||
meisten spezifizierten Methoden sind mit einer `default`-Implementierung definiert. Dieser
|
||||
Programmcode wird ausgeführt, falls die entsprechende Klasse (`Body` oder `NamedBody`) über keine
|
||||
eigene Definition der Methode verfügt. Verändern Sie diese Datei bitte nicht.
|
||||
- [NamedBody](../src/NamedBody.java) ist das Gerüst einer Klassendefinition. Die Klasse
|
||||
repräsentiert Himmelskörper, die einen Namen haben.
|
||||
- [MassiveLinkedList](../src/MassiveLinkedList.java) ist das Gerüst für eine Implementierung einer
|
||||
verketteten Liste von `Massive`-Objekten. Die Liste unterscheidet sich von `BodyLinkedList`
|
||||
dadurch, dass der Elementtyp statt `Body` der Obertyp `Massive` ist.
|
||||
- [MassiveForceHashMap](../src/MassiveForceHashMap.java) ist das Gerüst für eine Implementierung
|
||||
einer assoziativen Datenstruktur, die ein `Massive`-Objekt mit der auf das Objekt wirkenden Kraft
|
||||
assoziiert.
|
||||
- [Simulation5](../src/Simulation5.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).
|
||||
- [Aufgabe5Test](../src/Aufgabe5Test.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. Implementieren Sie `Massive` in den Klassen `Body` und `NamedBody`.**
|
||||
|
||||
Passen Sie die bestehende Definition von `Body` so an, dass die Klasse `Massive` implementiert wird.
|
||||
Vervollständigen Sie auch `NamedBody` so, dass sie `Massive` implementiert und die vorgegebene
|
||||
Spezifikationen der Methoden erfüllt.
|
||||
|
||||
**2. Überschreiben von `equals` und `hashCode` in `NamedBody`:**
|
||||
|
||||
Überschreiben Sie in `NamedBody` die Methoden `equals` und `hashCode` gemäß der dort angeführten
|
||||
Spezifikation. Achten Sie bei der Implementierung darauf, dass die in der Klasse `Object`
|
||||
beschriebenen Bedingungen für `equals` und `hashCode` eingehalten werden. `equals` und `hashCode`
|
||||
müssen zusammen passen.
|
||||
|
||||
**3. Vervollständigen von `MassiveLinkedList`:**
|
||||
|
||||
Definieren Sie `MassiveLinkedList`. Die Klasse ist wie `BodyLinkedList` aufgebaut, mit dem
|
||||
Unterschied, dass der Elementtyp statt `Body` nun der Typ `Massive` ist. Die Methode `indexOf`
|
||||
vergleicht Objekte mittels `equals`.
|
||||
|
||||
**4. Implementierung von `MassiveForceHashMap`:**
|
||||
|
||||
Vervollständigen Sie die Definition der Klasse `MassiveForceHashMap`, die eine Hash-Tabelle
|
||||
mit Schlüssel vom Typ `Massive` und Wert vom Typ `Vector3` implementiert. Die Klasse ist ähnlich
|
||||
zur Klasse `BodyForceTreeMap`. Die Unterschiede sind:
|
||||
- Der Typ des Schlüssels ist der gemeinsame Obertyp von `Body` und `NamedBody` (`Massive`).
|
||||
Dadurch lassen sich Objekte beider Klassen gemeinsam in der Hash-Tabelle speichern.
|
||||
- Die Schlüssel-Werte-Paare sind nicht nach Masse sortiert. Stattdessen wird der Hash-Wert zur
|
||||
Suche benutzt.
|
||||
- Es gibt eine zusätzliche Methode `keyList()`. Die Methoden `equals` und `hashCode` werden
|
||||
redefiniert.
|
||||
|
||||
**5. Implementierung von `Simulation5`:**
|
||||
|
||||
Implementieren Sie die Simulationsschleife unter Verwendung eines Objekts vom Typ
|
||||
`MassiveForceHashMap`. Die Methode `keyList()` hilft beim Iterieren der Hash-Tabelle.
|
||||
Kollisionen von Himmelskörpern müssen in dieser Simulation nicht berücksichtigt werden.
|
||||
|
||||
### Hinweise:
|
||||
|
||||
- Verwenden Sie bei der Implementierung von `MassiveForceHashMap` eine geeignete Kollisionsbehandlung
|
||||
für gleiche Hash-Werte. Als Vorlage können Sie den Beispielcode aus dem Skriptum nutzen.
|
||||
|
||||
### Denkanstöße (ohne Bewertung)
|
||||
|
||||
1. Wie könnte man vorgehen, wenn man - wie in früheren Simulationen - Himmelskörper im Fall von
|
||||
Kollisionen verschmelzen will?
|
||||
2. Was ändert sich am Verhalten von `MassiveForceHashMap`, wenn man in `Body` die Methoden
|
||||
`equals` und `hashCode` überschreiben würde?
|
||||
|
||||
#### _Punkteaufteilung_
|
||||
|
||||
- Implementierung von `Massive` in `NamedBody`: 1 Punkt
|
||||
- Implementierung von `Massive` in `Body`: 0.5 Punkt
|
||||
- Implementierung von `MassiveForceHashMap`: 2 Punkte
|
||||
- Implementierung von `MassiveLinkedList`: 0.5 Punkte
|
||||
- Implementierung von `Simulation5`: 1 Punkte
|
||||
|
||||
- Gesamt: 5 Punkte
|
75
angabe/Aufgabenblatt6.md
Normal file
75
angabe/Aufgabenblatt6.md
Normal file
@ -0,0 +1,75 @@
|
||||
# Aufgabenblatt 6
|
||||
|
||||
## Allgemeine Anmerkungen
|
||||
|
||||
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 23.5. 11h durch `git commit` und `git push`
|
||||
abzugeben. Mit der Angabe werden die Dateien `MassiveIterable.java`, `MassiveIterator.java`,
|
||||
`MassiveSet.java`, `MassiveForceTreeMap.java`, `Simulation6.java` und `Aufgabe6Test.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: Iterator, Kopie vs. Sichtweise, Sortieren
|
||||
(siehe Skriptum Seite 91-109).
|
||||
|
||||
## Beschreibung der gegebenen Dateien
|
||||
|
||||
- [MassiveIterable](../src/MassiveIterable.java) ist ein Interface, das iterierbare Objekte mit
|
||||
Elementen vom Typ `Massive` spezifiziert. Verändern Sie diese Datei bitte nicht.
|
||||
- [MassiveIterator](../src/MassiveIterator.java) ist ein Interface, das einen Iterator über
|
||||
Elemente vom Typ `Massive` spezifiziert. Verändern Sie diese Datei bitte nicht.
|
||||
- [MassiveSet](../src/MassiveSet.java) ist ein Interface, das iterierbare Mengen mit
|
||||
`Massive`-Elementen spezifiziert. Verändern Sie diese Datei bitte nicht.
|
||||
- [MassiveForceTreeMap](../src/MassiveForceTreeMap.java) ist das Gerüst für eine Implementierung
|
||||
einer assoziativen Datenstruktur, die ein `Massive`-Objekt mit der auf das Objekt wirkenden Kraft
|
||||
assoziiert.
|
||||
- [Simulation6](../src/Simulation6.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).
|
||||
- [Aufgabe6Test](../src/Aufgabe6Test.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. Implementieren Sie die Klasse `MassiveForceTreeMap`.**
|
||||
|
||||
Implementieren Sie die Klasse `MassiveForceTreeMap`. `MassiveForceTreeMap` ist wie
|
||||
`BodyForceTreeMap` aufgebaut, mit dem Unterschied, dass der Typ des Schlüssels statt `Body` nun
|
||||
der Typ `Massive` ist. Weiters soll die Klasse Methode `getKeys()` zur Verfügung stellen,
|
||||
die eine `MassiveSet`-Sichtweise auf die Menge der Schlüssel liefert. Änderungen an dem
|
||||
zurückgelieferten `MassiveSet`-Objekt wirken sich auf das zugrunde
|
||||
liegende `MassiveForceTreeMap`-Objekt aus. Die Methode `toList()` liefert dagegen eine
|
||||
unabhängige Liste (Kopie) mit allen Schlüsseln der Map. Für die Implementierung von
|
||||
`MassiveSet` können Sie einen eigenen Klassennamen beginnend mit `My` wählen. Die Definition kann
|
||||
in einer eigenen Datei oder in der Datei `MassiveForceTreeMap.java` erfolgen.
|
||||
|
||||
**2. Adaptieren Sie die Klasse `HierarchicalSystem`:**
|
||||
|
||||
Die Klasse `HierarchicalSystem` soll so geändert werden, dass sie das gegebene
|
||||
Interface `MassiveIterable` implementiert. Die Reihenfolge der vom Iterator gelieferten
|
||||
Elemente ist nicht festgelegt. Sie dürfen für die Implementierung bei Bedarf Ihren Klassen
|
||||
`NamedBodyForcePair` und `HierarchicalSystem` neue, nicht angegebene Methoden hinzufügen.
|
||||
Die Verwendung von Klassen des Java-Collection-Frameworks (z.B. java.util.Stack) ist erlaubt
|
||||
(aber nicht notwendig).
|
||||
|
||||
**3. Implementierung von `Simulation6`:**
|
||||
|
||||
Implementieren Sie die Simulationsschleife unter Verwendung eines Objekts vom Typ
|
||||
`MassiveForceTreeMap`. Die Methode `getKeys()` hilft beim Iterieren der gespeicherten Schlüssel.
|
||||
Kollisionen von Himmelskörpern müssen in dieser Simulation nicht berücksichtigt werden.
|
||||
|
||||
#### _Punkteaufteilung_
|
||||
|
||||
- Implementierung von `MassiveForceTreeMap`: 3 Punkte
|
||||
- Implementierung von `MassiveIterable` in `HierarchicalSystem`: 1.5 Punkte
|
||||
- Implementierung von `Simulation6`: 0.5 Punkte
|
||||
|
||||
- Gesamt: 5 Punkte
|
152
angabe/Aufgabenblatt8.md
Normal file
152
angabe/Aufgabenblatt8.md
Normal file
@ -0,0 +1,152 @@
|
||||
# Aufgabenblatt 8
|
||||
|
||||
## Allgemeine Anmerkungen
|
||||
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 13.6., 11h durch `git commit` und `git push`
|
||||
abzugeben.
|
||||
Wenn Sie zusätzlich zu den gefragten Klassen und Interfaces weitere Klassen oder
|
||||
Interfaces definieren, achten Sie darauf, dass die Klassennamen mit `My` beginnen, um Konflikte
|
||||
mit späteren Aufgabenblättern zu vermeiden.
|
||||
|
||||
Weiters werden die Dateien `StateFileNotFoundException.java`,
|
||||
`StateFileFormatException.java`, `ReadDataUtil.java`, `Simulation8.java`, `Simulation9.java`,
|
||||
`Aufgabe8Test.java` und das Verzeichnis `states` mit `txt`-Dateien mitgeliefert.
|
||||
|
||||
## Ziel
|
||||
Ziel der Aufgabe ist das Verständnis und die Anwendung der Konzepte: Java-Collections, Eingabe mit
|
||||
Validierung, Exceptions (S. 110-123).
|
||||
|
||||
## Beschreibung der gegebenen Dateien
|
||||
|
||||
- [states](../states) ist ein Verzeichnis, in dem mehrere Dateien mit der Endung `.txt`
|
||||
mitgeliefert werden. Diese enthalten Daten von je einem Himmelskörper sowie dessen Positionen und
|
||||
Geschwindigkeitsvektoren für alle Tage der Jahre 2019-2021. Die Angaben sind wie gewohnt in
|
||||
kartesischen Koordinaten, wobei die Sonne den Ursprung des Koordinatensystems bildet und die
|
||||
Ekliptik die x-y-Ebene darstellt. Die Daten stammen von [https://ssd.jpl.nasa.gov/horizons.cgi#top](https://ssd.jpl.nasa.gov/horizons.cgi#top).
|
||||
|
||||
**ACHTUNG**: Die Werte sind in km bzw. km/sec angegeben!
|
||||
|
||||
- [StateFileNotFoundException](../src/StateFileNotFoundException.java) enthält die Definition
|
||||
der Klasse `StateFileNotFoundException`. Diese sollen Sie vervollständigen.
|
||||
- [StateFileFormatException](../src/StateFileFormatException.java) enthält die Definition
|
||||
der Klasse `StateFileFormatException`. Diese sollen Sie vervollständigen.
|
||||
- [ReadDataUtil](../src/ReadDataUtil.java) ist eine Klasse mit einer statischen Methode zum
|
||||
Einlesen von Position- und Bewegungsvektoren von Himmelskörpern aus Dateien.
|
||||
Diese sollen Sie vervollständigen.
|
||||
- [Simulation8](../src/Simulation8.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).
|
||||
- [Simulation9](../src/Simulation9.java) ist eine leere Datei. Hier soll eine weitere Simulation
|
||||
implementiert werden, die so wie `Simulation8` funktioniert, mit dem Unterschied, dass anstelle
|
||||
der selbst implementierten Datenstrukturen nur vorgefertigte Klassen aus dem
|
||||
Java-Collection-Framework benutzt werden sollen.
|
||||
- [Aufgabe8Test](../src/Aufgabe8Test.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
|
||||
|
||||
1. Ändern Sie Ihre Implementierung, sodass ein `MassiveIterator` eine Exception
|
||||
vom Typ `java.util.NoSuchElementException` wirft, falls `next()` aufgerufen wird,
|
||||
jedoch der Iterator keine weitere Iteration hat (`hasNext()` liefert `false`).
|
||||
|
||||
2. Ändern Sie den Iterator von der von `getKeys()` zurückgelieferten
|
||||
Sichtweise auf `MassiveForceTreeMap` so, dass `remove()` überschrieben wird
|
||||
([siehe API Dokumentation](https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html#remove--)),
|
||||
sodass der Iterator Einträge in Objekten von `MassiveForceTreeMap` löschen kann. Achten Sie
|
||||
darauf, dass hier in bestimmten Fällen eine `java.lang.IllegalStateException` geworfen werden
|
||||
soll. Der Iterator von `HierarchicalSystem` muss nicht geändert werden.
|
||||
|
||||
3. Validierung von Eingabedaten:
|
||||
- Implementieren Sie in der Klasse `ReadDataUtil.java` die Methode `readConfiguration`.
|
||||
Es soll ein gepufferter Stream zum Einlesen genutzt werden (siehe Skriptum Seite 128).
|
||||
Erstellen Sie zum Testen auch Varianten der txt-Dateien mit Formatfehlern.
|
||||
- Fügen Sie der Klasse `NamedBody` bei Bedarf
|
||||
eine Methode `setState(Vector3 position, Vector3 velocity)` zum Setzen der Position
|
||||
und des Geschwindigkeitsvektors des Himmelskörpers hinzu.
|
||||
- Definieren Sie die beiden angegebenen Exceptionklassen in den entsprechenden
|
||||
mitgelieferten Dateien.
|
||||
|
||||
4. Ausnahmebehandlung:
|
||||
In der Klasse `Simulation8` sollen nun die Himmelskörper mit Daten aus den gegebenen
|
||||
txt-Dateien initialisiert werden. Dabei sollen zumindest die Sonne sowie die
|
||||
inneren Planeten
|
||||
Merkur, Venus, Erde und Mars vorkommen. Sie können weitere Himmelskörper (siehe txt-Dateien)
|
||||
hinzufügen. Nutzen Sie die Klasse `MassiveForceTreeMap` und ihre Iteratoren, um die
|
||||
Himmelskörper der Simulation zu verwalten. (Kollisionen von Himmelskörpern müssen nicht
|
||||
berücksichtigt werden.)
|
||||
Ändern Sie die Klasse `Simulation8` so, dass sie zwei Kommandozeilenargumente verarbeitet.
|
||||
Das erste Argument ist ein String mit der Angabe des Pfades zum Verzeichnis, wo die
|
||||
entsprechenden txt-Dateien (z.B. `Venus.txt`,`Mercury.txt`,`Earth.txt`) mit den Konfigurationen
|
||||
der Himmelskörper zu finden sind. Die Dateien haben die Namen der Himmelskörper mit Endung `
|
||||
.txt`. Für die Sonne gibt es keine txt-Datei (es wird die Position (0,0,0) angenommen).
|
||||
Das zweite Argument ist ein String mit einer Datumsangabe der Form YYYY-MMM-DD, also z.B.
|
||||
2020-Dec-04, die den Tag der auszulesenden Position und Bewegungsvektor bestimmt. Die Klasse
|
||||
soll beim Auftreten von Problemen bei der Ausführung entsprechende Fehlermeldungen ausgeben und
|
||||
die Ausführung in bestimmten Fällen beenden. Beispiele für Aufrufe im Kommandozeileninterpreter
|
||||
mit entsprechenden Fehlermeldungen (Sie können zum Ausführen das Terminal in IntelliJ nutzen
|
||||
oder die Programmargumente unter `Edit Configurations` angeben):
|
||||
```
|
||||
$ javac Simulation8.java
|
||||
$ java Simulation8 ../states 2021-May-28
|
||||
Running simulation ...
|
||||
$ java Simulation8 ../states
|
||||
Error: wrong number of arguments.
|
||||
$ java Simulation8 ../states 2025-Dec-12
|
||||
Warning: State not available for Earth.
|
||||
Running simulation without Earth.
|
||||
Warning: State not available for Venus.
|
||||
Running simulation without Venus.
|
||||
...
|
||||
$ java Simulation8 ../states-altered 2021-May-28
|
||||
Warning: File ../states-altered/Venus.txt does not have required format.
|
||||
Running simulation without Venus.
|
||||
Warning: File ../states-altered/Mars.txt not found.
|
||||
Running simulation without Mars.
|
||||
Running simulation ...
|
||||
$ java Simulation8 ../states -17
|
||||
Error: State has wrong format (requires YYYY-MM-DD), aborting.
|
||||
$ java Simulation8 blah 2021-May-28
|
||||
Warning: File blah/Earth.txt not found.
|
||||
Running simulation without Earth.
|
||||
Warning: File blah/Venus.txt not found.
|
||||
Running simulation without Venus.
|
||||
...
|
||||
```
|
||||
|
||||
5. Kopieren Sie den Inhalt der Datei `Simulation8.java` in die Datei `Simulation9.java` und bauen
|
||||
Sie `Simulation9` so um, dass anstelle der selbst implementierten Datenstrukturen nur
|
||||
vorgefertigte Klassen aus dem Java-Collection-Framework benutzt werden.
|
||||
|
||||
6. Freiwillige Zusatzaufgabe (ohne Bewertung):
|
||||
Ändern Sie die Klasse `Simulation8` so um, dass ein drittes optionales Kommandozeilenargument
|
||||
verarbeitet werden kann. Dieses gibt an, wie viele Tage simuliert werden sollen. Beispielsweise
|
||||
kann eine zweite Datumsangabe möglich sein, oder die Anzahl an Tagen.
|
||||
Sobald dieser Zeitpunkt in der Simulation erreicht wurde, können die aktuellen Positionen der
|
||||
Himmelskörper mit den in den txt-Dateien angegebenen Positionen verglichen werden (z.B.
|
||||
durch erneutem Aufruf von `readConfiguration` und `draw`). Wie groß sind die Abweichungen
|
||||
der von NASA errechneten Positionen zu den Positionen, die Ihre Simulation liefert?
|
||||
|
||||
### Denkanstöße (ohne Bewertung)
|
||||
|
||||
1. Haben Sie die remove-Methode des Iterators so implementiert, dass der Aufruf keine
|
||||
zusätzliche Suche nach dem zu löschenden Eintrag benötigt?
|
||||
2. Wie verhalten sich die von der Methode `toList()` der Klasse `MassiveForceTreeMap`
|
||||
zurückgelieferten Listen, wenn deren enthaltene Himmelskörper durch `setState` verändert werden?
|
||||
Werden dadurch die Himmelskörper der ursprünglichen `MassiveForceTreeMap`-Objekte auch geändert?
|
||||
(Anmerkung: diesbezüglich gibt es im Aufgabenblatt 6 keine Vorgaben).
|
||||
3. Wie verhalten sich Ihre Iteratoren, wenn Objekte geändert werden?
|
||||
4. Wie kann man durch Einfügen von Zeichen `,` und newlines (`\n`) aus den `txt`-Dateien eine
|
||||
"fehlerhafte" Datei machen, die trotzdem von der Methode akzeptiert wird? Kann man solche Probleme
|
||||
verhindern?
|
||||
|
||||
#### _Punkteaufteilung_
|
||||
|
||||
- Änderung von `next()` von `MassiveIterator`: 0.5 Punkte
|
||||
- Implementierung der Methode `remove()` im Iterator der `MassiveSet`-Sichtweise
|
||||
von `MassiveForceTreeMap`: 2 Punkte
|
||||
- Implementierung der Exceptionklassen und Implementierung von `readConfiguration`
|
||||
in `ReadDataUtil`: 1.5 Punkte
|
||||
- Implementierung von `Simulation8` und `Simulation9`: 1 Punkt
|
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,19 +1,19 @@
|
||||
import java.awt.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class Aufgabe1Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
//test classes Body and Vector3
|
||||
|
||||
@Test
|
||||
public void testEP2() {
|
||||
// create two bodies
|
||||
Body sun = new Body(1.989e30,new Vector3(0,0,0),new Vector3(0,0,0));
|
||||
Body earth = new Body(5.972e24,new Vector3(-1.394555e11,5.103346e10,0),new Vector3(-10308.53,-28169.38,0));
|
||||
Body sun = new Body(SolSystem.SUN);
|
||||
Body earth = new Body(SolSystem.EARTH);
|
||||
|
||||
testValue(earth.distanceTo(sun), 1.4850000175024106E11);
|
||||
testValue(sun.distanceTo(earth), 1.4850000175024106E11);
|
||||
assertEquals(1.4850000175024106E11, earth.distanceTo(sun));
|
||||
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 f2 = sun.gravitationalForce(earth);
|
||||
|
||||
@ -22,36 +22,9 @@ public class Aufgabe1Test {
|
||||
}
|
||||
|
||||
// a dummy body to check the correct position after 24h of movement
|
||||
Body targetPositionEarth = new Body(1, new Vector3(-1.403250141841815E11,
|
||||
4.859202658875631E10, 0.0), new Vector3(0,0,0));
|
||||
Body targetPositionEarth = new Body(1, new Vector3(-1.403250141841815E11, 4.859202658875631E10, 0.0), new Vector3(0, 0, 0));
|
||||
|
||||
// check distance to target position (should be zero)
|
||||
testValue(earth.distanceTo(targetPositionEarth), 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
assertEquals(0, earth.distanceTo(targetPositionEarth));
|
||||
}
|
||||
}
|
||||
|
51
src/Aufgabe2Test.java
Normal file
51
src/Aufgabe2Test.java
Normal file
@ -0,0 +1,51 @@
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class Aufgabe2Test {
|
||||
|
||||
@Test
|
||||
public void testEP2() {
|
||||
// create three bodies
|
||||
Body sun = new Body(SolSystem.SUN);
|
||||
Body earth = new Body(SolSystem.EARTH);
|
||||
Body mercury = new Body(SolSystem.MERCURY);
|
||||
|
||||
// check basic functions of 'BodyQueue'
|
||||
BodyQueue bq = new BodyQueue(2);
|
||||
bq.add(mercury);
|
||||
bq.add(sun);
|
||||
bq.add(earth);
|
||||
assertEquals(3, bq.size());
|
||||
|
||||
assertEquals(mercury, bq.poll());
|
||||
assertEquals(sun, bq.poll());
|
||||
assertEquals(earth, bq.poll());
|
||||
|
||||
assertEquals(0, bq.size());
|
||||
|
||||
bq.add(mercury);
|
||||
bq.add(sun);
|
||||
assertEquals(2, bq.size());
|
||||
|
||||
// check constructor of 'BodyQueue'
|
||||
BodyQueue bqCopy = new BodyQueue(bq);
|
||||
assertNotEquals(bq, bqCopy);
|
||||
assertEquals(bqCopy.poll(), bq.poll());
|
||||
bq.add(earth);
|
||||
assertEquals(2, bq.size());
|
||||
assertEquals(1, bqCopy.size());
|
||||
|
||||
// check basic functions of 'BodyForceMap'
|
||||
BodyForceMap bfm = new BodyForceMap(5);
|
||||
bfm.put(earth, earth.gravitationalForce(sun));
|
||||
bfm.put(sun, sun.gravitationalForce(earth));
|
||||
|
||||
assertEquals(0, bfm.get(earth).distanceTo(earth.gravitationalForce(sun)));
|
||||
assertEquals(0, bfm.get(sun).distanceTo(sun.gravitationalForce(earth)));
|
||||
|
||||
bfm.put(earth, new Vector3(0, 0, 0));
|
||||
assertEquals(0, bfm.get(earth).distanceTo(new Vector3(0, 0, 0)));
|
||||
assertNull(bfm.get(mercury));
|
||||
}
|
||||
}
|
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));
|
||||
}
|
||||
}
|
110
src/Aufgabe4Test.java
Normal file
110
src/Aufgabe4Test.java
Normal 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()));
|
||||
}
|
||||
}
|
||||
}
|
96
src/Aufgabe5Test.java
Normal file
96
src/Aufgabe5Test.java
Normal file
@ -0,0 +1,96 @@
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class Aufgabe5Test {
|
||||
|
||||
@Test
|
||||
public void testEP2() {
|
||||
//test classes NamedBody and MassiveForceHashMap
|
||||
|
||||
// create 12 named bodies
|
||||
NamedBody sun1, mercury1, venus1, earth1, moon1, mars1, deimos1, phobos1, vesta1, pallas1, hygiea1, ceres1;
|
||||
|
||||
// create a nameless body
|
||||
Body earth2 = new Body(SolSystem4.EARTH);
|
||||
|
||||
// create the same 12 named body-force pairs
|
||||
sun1 = new NamedBody(SolSystem4.SUN_NAMED);
|
||||
earth1 = new NamedBody(SolSystem4.EARTH_NAMED);
|
||||
moon1 = new NamedBody(SolSystem4.MOON_NAMED);
|
||||
mars1 = new NamedBody(SolSystem4.MARS_NAMED);
|
||||
deimos1 = new NamedBody(SolSystem4.DEIMOS_NAMED);
|
||||
phobos1 = new NamedBody(SolSystem4.PHOBOS_NAMED);
|
||||
mercury1 = new NamedBody(SolSystem4.MERCURY_NAMED);
|
||||
venus1 = new NamedBody(SolSystem4.VENUS_NAMED);
|
||||
vesta1 = new NamedBody(SolSystem4.VESTA_NAMED);
|
||||
pallas1 = new NamedBody(SolSystem4.PALLAS_NAMED);
|
||||
hygiea1 = new NamedBody(SolSystem4.HYGIEA_NAMED);
|
||||
ceres1 = new NamedBody(SolSystem4.CERES_NAMED);
|
||||
|
||||
NamedBody sun2 = new NamedBody("Sun", 1.9895E30, new Vector3(0.1, 0.0, 0.0), new Vector3(0.0, 0.0, 0.0));
|
||||
NamedBody earth3 = new NamedBody("Earth", 1, new Vector3(0, 0, 0), new Vector3(0, 0, 0));
|
||||
assertEquals(sun1, sun2);
|
||||
assertEquals(sun2.hashCode(), sun1.hashCode());
|
||||
assertEquals(earth1, earth3);
|
||||
assertEquals(earth3.hashCode(), earth1.hashCode());
|
||||
|
||||
// check basic functions of 'MassiveForceHashMap'
|
||||
MassiveForceHashMap map = new MassiveForceHashMap();
|
||||
map.put(sun1, new Vector3(0, 0, 0));
|
||||
map.put(mercury1, new Vector3(0, 0, 0));
|
||||
map.put(venus1, new Vector3(0, 0, 0));
|
||||
map.put(earth1, new Vector3(0, 0, 0));
|
||||
map.put(moon1, new Vector3(0, 0, 0));
|
||||
map.put(mars1, new Vector3(0, 0, 0));
|
||||
map.put(deimos1, new Vector3(0, 0, 0));
|
||||
map.put(phobos1, new Vector3(0, 0, 0));
|
||||
map.put(vesta1, new Vector3(0, 0, 0));
|
||||
map.put(pallas1, new Vector3(0, 0, 0));
|
||||
map.put(hygiea1, new Vector3(0, 0, 0));
|
||||
map.put(ceres1, new Vector3(0, 0, 0));
|
||||
map.put(mars1, new Vector3(0, 0, 0)); // inserted twice
|
||||
assertEquals(12, map.keyList().size());
|
||||
|
||||
assertTrue(map.toString().contains("Mars"));
|
||||
assertTrue(map.toString().contains("Deimos"));
|
||||
assertTrue(map.toString().contains("Moon"));
|
||||
assertTrue(map.toString().contains("Earth"));
|
||||
|
||||
MassiveLinkedList bl = map.keyList();
|
||||
boolean allThere = true;
|
||||
while (bl.size() > 0) {
|
||||
allThere &= map.containsKey(bl.pollFirst());
|
||||
}
|
||||
assertTrue(allThere);
|
||||
assertFalse(map.containsKey(new Body(0, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
|
||||
assertFalse(map.containsKey(new NamedBody("Omuamua", 0, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
|
||||
|
||||
int hashCode1 = map.hashCode();
|
||||
|
||||
Vector3 f = new Vector3(5, 5, 5);
|
||||
map.put(earth3, f);
|
||||
assertEquals(f, map.get(earth1));
|
||||
assertNull(map.get(earth2));
|
||||
|
||||
int hashCode2 = map.hashCode();
|
||||
assertEquals(map, map);
|
||||
assertEquals(hashCode2, map.hashCode());
|
||||
assertNotEquals(hashCode1, hashCode2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelKey() {
|
||||
MassiveForceHashMap map = new MassiveForceHashMap();
|
||||
NamedBody sun1 = new NamedBody(SolSystem4.SUN_NAMED);
|
||||
NamedBody earth1 = new NamedBody(SolSystem4.EARTH_NAMED);
|
||||
NamedBody moon1 = new NamedBody(SolSystem4.MOON_NAMED);
|
||||
map.put(sun1, new Vector3());
|
||||
map.put(earth1, new Vector3());
|
||||
map.put(moon1, new Vector3());
|
||||
assertNotNull(map.get(sun1));
|
||||
assertNotNull(map.delete(sun1));
|
||||
assertNull(map.get(sun1));
|
||||
assertNull(map.delete(sun1));
|
||||
}
|
||||
}
|
133
src/Aufgabe6Test.java
Normal file
133
src/Aufgabe6Test.java
Normal file
@ -0,0 +1,133 @@
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class Aufgabe6Test {
|
||||
|
||||
@Test
|
||||
public void testEP2() {
|
||||
NamedBody sun1, mercury1, venus1, earth1, moon1, mars1, deimos1, phobos1, vesta1, pallas1, hygiea1, ceres1;
|
||||
|
||||
// create the same 12 named body-force pairs
|
||||
sun1 = new NamedBody(SolSystem4.SUN_NAMED);
|
||||
earth1 = new NamedBody(SolSystem4.EARTH_NAMED);
|
||||
moon1 = new NamedBody(SolSystem4.MOON_NAMED);
|
||||
mars1 = new NamedBody(SolSystem4.MARS_NAMED);
|
||||
deimos1 = new NamedBody(SolSystem4.DEIMOS_NAMED);
|
||||
phobos1 = new NamedBody(SolSystem4.PHOBOS_NAMED);
|
||||
mercury1 = new NamedBody(SolSystem4.MERCURY_NAMED);
|
||||
venus1 = new NamedBody(SolSystem4.VENUS_NAMED);
|
||||
vesta1 = new NamedBody(SolSystem4.VESTA_NAMED);
|
||||
pallas1 = new NamedBody(SolSystem4.PALLAS_NAMED);
|
||||
hygiea1 = new NamedBody(SolSystem4.HYGIEA_NAMED);
|
||||
ceres1 = new NamedBody(SolSystem4.CERES_NAMED);
|
||||
|
||||
// check basic functions of 'MassiveForceHashMap'
|
||||
MassiveForceTreeMap map = new MassiveForceTreeMap();
|
||||
map.put(sun1, new Vector3(0, 0, 0));
|
||||
map.put(mercury1, new Vector3(0, 0, 0));
|
||||
map.put(venus1, new Vector3(0, 0, 0));
|
||||
map.put(earth1, new Vector3(0, 0, 0));
|
||||
map.put(moon1, new Vector3(0, 0, 0));
|
||||
map.put(mars1, new Vector3(0, 0, 0));
|
||||
map.put(deimos1, new Vector3(0, 0, 0));
|
||||
map.put(phobos1, new Vector3(0, 0, 0));
|
||||
map.put(vesta1, new Vector3(0, 0, 0));
|
||||
map.put(pallas1, new Vector3(0, 0, 0));
|
||||
map.put(hygiea1, new Vector3(0, 0, 0));
|
||||
map.put(ceres1, new Vector3(0, 0, 0));
|
||||
map.put(mars1, new Vector3(0, 0, 0)); // inserted twice
|
||||
|
||||
HashSet<Massive> set1 = new HashSet<>();
|
||||
set1.add(sun1);
|
||||
set1.add(mercury1);
|
||||
set1.add(venus1);
|
||||
set1.add(earth1);
|
||||
set1.add(moon1);
|
||||
set1.add(mars1);
|
||||
set1.add(deimos1);
|
||||
set1.add(phobos1);
|
||||
set1.add(vesta1);
|
||||
set1.add(pallas1);
|
||||
set1.add(hygiea1);
|
||||
set1.add(ceres1);
|
||||
|
||||
assertTrue(map.toString().contains("Mars"));
|
||||
assertTrue(map.toString().contains("Deimos"));
|
||||
assertTrue(map.toString().contains("Moon"));
|
||||
assertTrue(map.toString().contains("Earth"));
|
||||
|
||||
assertEquals(12, map.getKeys().size());
|
||||
|
||||
assertTrue(map.getKeys().contains(mars1));
|
||||
assertTrue(map.getKeys().contains(new NamedBody("Mars", 6.41712E23, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
|
||||
assertFalse(map.getKeys().contains(new Body(6.41712E23, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
|
||||
|
||||
HashSet<Massive> set2 = new HashSet<>();
|
||||
for (Massive m : map.getKeys()) {
|
||||
set2.add(m);
|
||||
}
|
||||
|
||||
assertEquals(set1, set2);
|
||||
|
||||
MassiveLinkedList list = map.getKeys().toList();
|
||||
while (list.size() > 0) {
|
||||
set1.remove(list.pollLast());
|
||||
}
|
||||
assertTrue(set1.isEmpty());
|
||||
|
||||
map.getKeys().remove(mars1);
|
||||
assertFalse(map.containsKey(mars1));
|
||||
assertEquals(11, map.getKeys().size());
|
||||
map.getKeys().clear();
|
||||
assertEquals(0, map.getKeys().size());
|
||||
|
||||
NamedBodyForcePair sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2;
|
||||
|
||||
//test classes NamedBody and MassiveForceHashMap
|
||||
|
||||
// create 12 named bodies
|
||||
// create the same 12 named body-force pairs
|
||||
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);
|
||||
|
||||
CosmicSystem earthSystem = new HierarchicalSystem(earth2, moon2);
|
||||
CosmicSystem marsSystem = new HierarchicalSystem(mars2, deimos2, phobos2);
|
||||
HierarchicalSystem solarSystem = new HierarchicalSystem(sun2, mercury2, venus2, earthSystem, marsSystem, vesta2, pallas2, hygiea2, ceres2);
|
||||
|
||||
int count = 0;
|
||||
for (Massive b : solarSystem) {
|
||||
count++;
|
||||
}
|
||||
assertEquals(12, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIterator() {
|
||||
NamedBody sun1, mercury1, venus1;
|
||||
sun1 = new NamedBody(SolSystem4.SUN_NAMED);
|
||||
mercury1 = new NamedBody(SolSystem4.MERCURY_NAMED);
|
||||
venus1 = new NamedBody(SolSystem4.VENUS_NAMED);
|
||||
|
||||
MassiveForceTreeMap map = new MassiveForceTreeMap();
|
||||
|
||||
map.put(sun1, new Vector3());
|
||||
map.put(mercury1, new Vector3());
|
||||
map.put(venus1, new Vector3());
|
||||
for (Massive m : map.getKeys().toList()) {
|
||||
System.out.println(m);
|
||||
}
|
||||
}
|
||||
}
|
50
src/Aufgabe8Test.java
Normal file
50
src/Aufgabe8Test.java
Normal file
@ -0,0 +1,50 @@
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class Aufgabe8Test {
|
||||
|
||||
@Test
|
||||
public void testEP2() {
|
||||
MassiveForceTreeMap map = new MassiveForceTreeMap();
|
||||
NamedBody mars;
|
||||
|
||||
map.put(new NamedBody("Oumuamua", 8e6, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Earth", 5.972E24, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Moon", 7.349E22, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(mars = new NamedBody("Mars", 6.41712E23, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Deimos", 1.8E20, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Phobos", 1.08E20, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Mercury", 3.301E23, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Venus", 4.86747E24, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Vesta", 2.5908E20, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Pallas", 2.14E20, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Hygiea", 8.32E19, new Vector3(), new Vector3()), new Vector3());
|
||||
map.put(new NamedBody("Ceres", 9.394E20, new Vector3(), new Vector3()), new Vector3());
|
||||
|
||||
assertEquals(12, map.size());
|
||||
|
||||
MassiveIterator iterator = map.getKeys().iterator();
|
||||
int count;
|
||||
for (count = 0; iterator.hasNext(); count++) {
|
||||
if (iterator.next().equals(mars)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
assertEquals(12, count);
|
||||
assertEquals(11, map.getKeys().size());
|
||||
assertEquals(11, map.size());
|
||||
assertFalse(map.getKeys().contains(mars));
|
||||
|
||||
assertThrows(NoSuchElementException.class, iterator::next);
|
||||
|
||||
iterator = map.getKeys().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
iterator.remove();
|
||||
}
|
||||
assertEquals(0, map.getKeys().size());
|
||||
}
|
||||
}
|
119
src/Body.java
119
src/Body.java
@ -1,8 +1,10 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
// This class represents celestial bodies like stars, planets, asteroids, etc..
|
||||
public class Body {
|
||||
private double mass;
|
||||
/**
|
||||
* This class represents celestial bodies like stars, planets, asteroids, etc...
|
||||
*/
|
||||
public class Body implements Massive {
|
||||
private final double mass;
|
||||
private Vector3 massCenter; // position of the mass center.
|
||||
private Vector3 currentMovement;
|
||||
|
||||
@ -12,28 +14,55 @@ public class Body {
|
||||
this.currentMovement = currentMovement;
|
||||
}
|
||||
|
||||
// Returns the distance between the mass centers of this body and the specified body 'b'.
|
||||
public Body(Body other) {
|
||||
this.mass = other.mass;
|
||||
this.massCenter = new Vector3(other.massCenter);
|
||||
this.currentMovement = new Vector3(other.currentMovement);
|
||||
}
|
||||
|
||||
public Body(double mass) {
|
||||
this(mass, new Vector3(), new Vector3());
|
||||
}
|
||||
|
||||
public Body() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public void setState(Vector3 position, Vector3 velocity) {
|
||||
this.massCenter = new Vector3(position);
|
||||
this.currentMovement = new Vector3(velocity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the distance between the mass centers of this body and the specified body 'b'.
|
||||
*/
|
||||
public double distanceTo(Body b) {
|
||||
return massCenter.distanceTo(b.massCenter);
|
||||
}
|
||||
|
||||
// Returns a vector representing the gravitational force exerted by 'b' on this body.
|
||||
// The gravitational Force F is calculated by F = G*(m1*m2)/(r*r), with m1 and m2 being the
|
||||
// masses of the objects interacting, r being the distance between the centers of the masses
|
||||
// and G being the gravitational constant.
|
||||
// Hint: see simulation loop in Simulation.java to find out how this is done.
|
||||
/**
|
||||
* Returns a vector representing the gravitational force exerted by 'b' on this body.
|
||||
* The gravitational Force F is calculated by F = G*(m1*m2)/(r*r), with m1 and m2 being the
|
||||
* masses of the objects interacting, r being the distance between the centers of the masses
|
||||
* and G being the gravitational constant.
|
||||
* Hint: see simulation loop in Simulation.java to find out how this is done.
|
||||
*/
|
||||
public Vector3 gravitationalForce(Body b) {
|
||||
if (b == this) return new Vector3();
|
||||
Vector3 direction = b.massCenter.minus(massCenter);
|
||||
double distance = direction.length();
|
||||
if (distance == 0) return new Vector3();
|
||||
direction.normalize();
|
||||
double force = Simulation.G * mass * b.mass / (distance * distance);
|
||||
return direction.times(force);
|
||||
}
|
||||
|
||||
// Moves this body to a new position, according to the specified force vector 'force' exerted
|
||||
// on it, and updates the current movement accordingly.
|
||||
// (Movement depends on the mass of this body, its current movement and the exerted force.)
|
||||
// Hint: see simulation loop in Simulation.java to find out how this is done.
|
||||
/**
|
||||
* Moves this body to a new position, according to the specified force vector 'force' exerted
|
||||
* on it, and updates the current movement accordingly.
|
||||
* (Movement depends on the mass of this body, its current movement and the exerted force.)
|
||||
* Hint: see simulation loop in Simulation.java to find out how this is done.
|
||||
*/
|
||||
public void move(Vector3 force) {
|
||||
// F = m*a -> a = F/m
|
||||
Vector3 newPosition = massCenter.plus(force.times(1.0 / mass)).plus(currentMovement);
|
||||
@ -46,43 +75,65 @@ public class Body {
|
||||
currentMovement = newMovement;
|
||||
}
|
||||
|
||||
// Returns the approximate radius of this body.
|
||||
// (It is assumed that the radius r is related to the mass m of the body by r = m ^ 0.5,
|
||||
// where m and r measured in solar units.)
|
||||
/**
|
||||
* Returns the approximate radius of this body.
|
||||
* (It is assumed that the radius r is related to the mass m of the body by r = m ^ 0.5,
|
||||
* where m and r measured in solar units.)
|
||||
*/
|
||||
public double radius() {
|
||||
return SpaceDraw.massToRadius(mass);
|
||||
}
|
||||
|
||||
// Returns a new body that is formed by the collision of this body and 'b'. The impulse
|
||||
// of the returned body is the sum of the impulses of 'this' and 'b'.
|
||||
public Body merge(Body b) {
|
||||
double mass = this.mass + b.mass;
|
||||
/**
|
||||
* Return the mass of the Body.
|
||||
*/
|
||||
public double 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
|
||||
* of the returned body is the sum of the impulses of 'this' and 'b'.
|
||||
*/
|
||||
public Body merge(Body body) {
|
||||
double totalMass = this.mass + body.mass;
|
||||
return new Body(
|
||||
mass,
|
||||
massCenter.times(this.mass).plus(b.massCenter.times(b.mass)).times(1.0 / mass),
|
||||
currentMovement.times(this.mass).plus(b.currentMovement.times(b.mass)).times(1.0 / mass)
|
||||
totalMass,
|
||||
this.massCenter.times(this.mass).plus(body.massCenter.times(body.mass)).times(1.0 / totalMass),
|
||||
this.currentMovement.times(this.mass).plus(body.currentMovement.times(body.mass)).times(1.0 / totalMass)
|
||||
);
|
||||
}
|
||||
|
||||
// Draws the body to the specified canvas as a filled circle.
|
||||
// The radius of the circle corresponds to the radius of the body
|
||||
// (use a conversion of the real scale to the scale of the canvas as
|
||||
// in 'Simulation.java').
|
||||
// Hint: call the method 'drawAsFilledCircle' implemented in 'Vector3'.
|
||||
/**
|
||||
* Draws the body to the specified canvas as a filled circle.
|
||||
* The radius of the circle corresponds to the radius of the body
|
||||
* (use a conversion of the real scale to the scale of the canvas as
|
||||
* in 'Simulation.java').
|
||||
* Hint: call the method 'drawAsFilledCircle' implemented in 'Vector3'.
|
||||
*/
|
||||
public void draw(CodeDraw cd) {
|
||||
cd.setColor(SpaceDraw.massToColor(mass));
|
||||
massCenter.drawAsFilledCircle(cd, SpaceDraw.massToRadius(mass));
|
||||
}
|
||||
|
||||
// Returns a string with the information about this body including
|
||||
// mass, position (mass center) and current movement. Example:
|
||||
// "5.972E24 kg, position: [1.48E11,0.0,0.0] m, movement: [0.0,29290.0,0.0] m/s."
|
||||
/**
|
||||
* Returns a string with the information about this body including
|
||||
* mass, position (mass center) and current movement. Example:
|
||||
* "5.972E24 kg, position: [1.48E11,0.0,0.0] m, movement: [0.0,29290.0,0.0] m/s."
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"%f kg, position: %s m, movement: %s m/s.",
|
||||
"%g kg, position: %s m, movement: %s m/s.",
|
||||
mass, massCenter.toString(), currentMovement.toString()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
119
src/BodyForceMap.java
Normal file
119
src/BodyForceMap.java
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* A map that associates a body with a force exerted on it. The number of
|
||||
* key-value pairs is not limited.
|
||||
*/
|
||||
public class BodyForceMap {
|
||||
private int size = 0;
|
||||
private int capacity;
|
||||
private Body[] keys;
|
||||
private Vector3[] values;
|
||||
|
||||
public BodyForceMap() {
|
||||
this(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this map with an initial capacity.
|
||||
* Precondition: initialCapacity > 0.
|
||||
*/
|
||||
public BodyForceMap(int initialCapacity) {
|
||||
this.capacity = initialCapacity;
|
||||
this.keys = new Body[this.capacity];
|
||||
this.values = new Vector3[this.capacity];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 force) {
|
||||
if (size == capacity) {
|
||||
doubleCapacity();
|
||||
}
|
||||
|
||||
int left = 0;
|
||||
int right = size - 1;
|
||||
while (left <= right) {
|
||||
int middle = left + (right - left) / 2;
|
||||
if (keys[middle] == key) {
|
||||
Vector3 v = values[middle];
|
||||
values[middle] = force;
|
||||
return v;
|
||||
} else if (keys[middle].mass() < key.mass()) {
|
||||
right = middle - 1;
|
||||
} else {
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int insert = right + 1;
|
||||
|
||||
for (int i = size; i > insert; i--) {
|
||||
keys[i] = keys[i - 1];
|
||||
values[i] = values[i - 1];
|
||||
}
|
||||
size++;
|
||||
keys[insert] = key;
|
||||
values[insert] = force;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value associated with the specified key, i.e. the returns the force vector
|
||||
* associated with the specified body. Returns 'null' if the key is not contained in this map.
|
||||
* Precondition: key != null.
|
||||
*/
|
||||
public Vector3 get(Body key) {
|
||||
int left = 0;
|
||||
int right = size - 1;
|
||||
|
||||
while (left <= right) {
|
||||
int middle = left + ((right - left) / 2);
|
||||
int middleLeft = left + (middle - left) / 2;
|
||||
int middleRight = middle + (right - middle) / 2;
|
||||
|
||||
if (keys[middle] == key) {
|
||||
return values[middle];
|
||||
}
|
||||
|
||||
if (keys[middleLeft].mass() == keys[middle].mass()) {
|
||||
for (int i = middleLeft; i < middle; i++) {
|
||||
if (keys[i] == key)
|
||||
return values[i];
|
||||
}
|
||||
}
|
||||
if (keys[middle].mass() == keys[middleRight].mass()) {
|
||||
for (int i = middle; i < middleRight; i++) {
|
||||
if (keys[i] == key)
|
||||
return values[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (keys[middle].mass() < key.mass()) {
|
||||
right = middle - 1;
|
||||
} else {
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Doubles the capacity of the map.
|
||||
*/
|
||||
private void doubleCapacity() {
|
||||
capacity *= 2;
|
||||
Body[] tmpKeys = new Body[capacity];
|
||||
Vector3[] tmpValues = new Vector3[capacity];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
tmpKeys[i] = keys[i];
|
||||
tmpValues[i] = values[i];
|
||||
}
|
||||
|
||||
keys = tmpKeys;
|
||||
values = tmpValues;
|
||||
}
|
||||
}
|
131
src/BodyForceTreeMap.java
Normal file
131
src/BodyForceTreeMap.java
Normal file
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* 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 Item 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 Item(key, value);
|
||||
size++;
|
||||
return null;
|
||||
}
|
||||
|
||||
Item item = root;
|
||||
while (item != null) {
|
||||
if (item.key == key) {
|
||||
Vector3 old = item.value;
|
||||
item.value = value;
|
||||
return old;
|
||||
} else if (item.key.mass() > key.mass()) {
|
||||
if (item.left != null) {
|
||||
item = item.left;
|
||||
} else {
|
||||
item.setLeft(new Item(key, value));
|
||||
size++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (item.right != null) {
|
||||
item = item.right;
|
||||
} else{
|
||||
item.setRight(new Item(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) {
|
||||
Item 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) {
|
||||
Item 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(Item item) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
if (item == null) {
|
||||
return s.toString();
|
||||
}
|
||||
s.append(this.toString(item.right));
|
||||
s.append(String.format("{%s: %s}\n", item.key, item.value));
|
||||
s.append(this.toString(item.left));
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (root != null) ? toString(root) : "";
|
||||
}
|
||||
|
||||
private static class Item {
|
||||
private final Body key;
|
||||
private Vector3 value;
|
||||
private Item parent;
|
||||
private Item left;
|
||||
private Item right;
|
||||
|
||||
public Item(Body key, Vector3 value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setLeft(Item left) {
|
||||
this.left = left;
|
||||
if (left != null) left.parent = this;
|
||||
}
|
||||
|
||||
public void setRight(Item right) {
|
||||
this.right = right;
|
||||
if (right != null) right.parent = this;
|
||||
}
|
||||
}
|
||||
}
|
246
src/BodyLinkedList.java
Normal file
246
src/BodyLinkedList.java
Normal file
@ -0,0 +1,246 @@
|
||||
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 Item first;
|
||||
private Item 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 Item(body);
|
||||
last = first;
|
||||
} else {
|
||||
first.setPrev(new Item(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 Item(body);
|
||||
first = last;
|
||||
} else {
|
||||
last.setNext(new Item(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;
|
||||
}
|
||||
|
||||
Item item = first;
|
||||
for (int j = 0; j < i; j++) {
|
||||
item = item.next;
|
||||
}
|
||||
|
||||
item.prev.setNext(new Item(body));
|
||||
item.setPrev(item.prev.next);
|
||||
size++;
|
||||
}
|
||||
|
||||
private Body removeItem(Item 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) {
|
||||
Item 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;
|
||||
}
|
||||
|
||||
Item item = first;
|
||||
for (int i = 0; i < size; i++, item = item.next) {
|
||||
if (item.body == body) return i;
|
||||
}
|
||||
|
||||
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 (Item 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<>() {
|
||||
Item ptr = first;
|
||||
boolean yieldedFirst = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return ptr != null && (!yieldedFirst || ptr.next != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Body next() {
|
||||
if (!yieldedFirst) {
|
||||
yieldedFirst = true;
|
||||
} else {
|
||||
ptr = ptr.next;
|
||||
}
|
||||
return ptr.body;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class Item {
|
||||
private final Body body;
|
||||
private Item prev;
|
||||
private Item next;
|
||||
|
||||
public Item(Body body) {
|
||||
this.body = body;
|
||||
this.prev = null;
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
public void setPrev(Item prev) {
|
||||
this.prev = prev;
|
||||
if (prev != null) prev.next = this;
|
||||
}
|
||||
|
||||
public void setNext(Item next) {
|
||||
this.next = next;
|
||||
if (next != null) next.prev = this;
|
||||
}
|
||||
}
|
||||
}
|
89
src/BodyQueue.java
Normal file
89
src/BodyQueue.java
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* A queue of bodies. A collection designed for holding bodies prior to processing.
|
||||
* The bodies of the queue can be accessed in a FIFO (first-in-first-out) manner,
|
||||
* i.e., the body that was first inserted by 'add' is retrieved first by 'poll'.
|
||||
* The number of elements of the queue is not limited.
|
||||
*/
|
||||
public class BodyQueue {
|
||||
private int capacity;
|
||||
private int head = 0;
|
||||
private int tail = 0;
|
||||
private Body[] queue;
|
||||
|
||||
public BodyQueue() {
|
||||
this(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this queue with an initial capacity.
|
||||
* Precondition: initialCapacity > 0.
|
||||
*/
|
||||
public BodyQueue(int initialCapacity) {
|
||||
this.capacity = initialCapacity;
|
||||
this.queue = new Body[this.capacity];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this queue as an independent copy of the specified queue.
|
||||
* Calling methods of this queue will not affect the specified queue
|
||||
* and vice versa.
|
||||
* Precondition: other != null.
|
||||
*/
|
||||
public BodyQueue(BodyQueue other) {
|
||||
this.capacity = other.capacity;
|
||||
this.head = other.size();
|
||||
this.tail = 0;
|
||||
this.queue = new Body[this.capacity];
|
||||
for (int i = 0, j = other.tail; i < this.head; i++, j++) {
|
||||
this.queue[i] = other.queue[j % other.capacity];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified body 'b' to this queue.
|
||||
*/
|
||||
public void add(Body b) {
|
||||
if ((head + 1) % capacity == tail) {
|
||||
doubleCapacity();
|
||||
}
|
||||
queue[head] = b;
|
||||
head = (head + 1) % capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and removes the head of this queue, or returns 'null'
|
||||
* if this queue is empty.
|
||||
*/
|
||||
public Body poll() {
|
||||
if (tail == head) {
|
||||
tail = 0;
|
||||
head = 0;
|
||||
return null;
|
||||
}
|
||||
Body b = queue[tail];
|
||||
queue[tail] = null;
|
||||
tail = (tail + 1) % capacity;
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bodies in this queue.
|
||||
*/
|
||||
public int size() {
|
||||
return (head - tail + capacity) % capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Double the capacity of the queue.
|
||||
*/
|
||||
private void doubleCapacity() {
|
||||
Body[] tmp = new Body[capacity * 2];
|
||||
head = size();
|
||||
for (int i = 0, j = tail; i < head; i++, j++) {
|
||||
tmp[i] = queue[j % capacity];
|
||||
}
|
||||
tail = 0;
|
||||
capacity *= 2;
|
||||
queue = tmp;
|
||||
}
|
||||
}
|
59
src/CosmicSystem.java
Normal file
59
src/CosmicSystem.java
Normal 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
13
src/Drawable.java
Normal 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);
|
||||
}
|
180
src/HierarchicalSystem.java
Normal file
180
src/HierarchicalSystem.java
Normal file
@ -0,0 +1,180 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* 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, MassiveIterable {
|
||||
|
||||
private final NamedBodyForcePair central;
|
||||
private CosmicSystem[] orbit;
|
||||
private 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the system 'cs' at the first place in the orbit of this system.
|
||||
* Precondition: cs != null
|
||||
*/
|
||||
public boolean putFirst(CosmicSystem cs) {
|
||||
CosmicSystem[] old = orbit;
|
||||
orbit = new CosmicSystem[old.length + 1];
|
||||
all = new CosmicSystem[old.length + 2];
|
||||
|
||||
orbit[0] = cs;
|
||||
System.arraycopy(old, 0, orbit, 1, old.length);
|
||||
all[0] = central;
|
||||
System.arraycopy(orbit, 0, all, 1, orbit.length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MassiveIterator iterator() {
|
||||
return new MassiveIterator() {
|
||||
private int i = 0;
|
||||
private MassiveIterator cur = null;
|
||||
|
||||
@Override
|
||||
public Massive next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
if (cur != null && cur.hasNext()) return cur.next();
|
||||
|
||||
while (i < all.length) {
|
||||
CosmicSystem sys = all[i++];
|
||||
if (sys instanceof NamedBodyForcePair m) {
|
||||
return m.getBody();
|
||||
} else if (sys instanceof HierarchicalSystem hs) {
|
||||
cur = hs.iterator();
|
||||
if (cur.hasNext()) {
|
||||
return cur.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (cur != null && cur.hasNext()) return true;
|
||||
|
||||
while (i < all.length) {
|
||||
CosmicSystem sys = all[i];
|
||||
if (sys instanceof NamedBodyForcePair) return true;
|
||||
i++;
|
||||
|
||||
if (sys instanceof HierarchicalSystem hs) {
|
||||
cur = hs.iterator();
|
||||
if (cur.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
73
src/Massive.java
Normal file
73
src/Massive.java
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Represents a coherent mass with a mass center in 3D space. Has two naming schemes for its
|
||||
* methods. Please, do not change this interface definition!
|
||||
*/
|
||||
public interface Massive extends Drawable {
|
||||
|
||||
/**
|
||||
* Returns the mass.
|
||||
*/
|
||||
default double mass() {
|
||||
return getMass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mass center.
|
||||
*/
|
||||
default Vector3 massCenter() {
|
||||
return getMassCenter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mass.
|
||||
*/
|
||||
default double getMass() {
|
||||
return mass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mass center.
|
||||
*/
|
||||
default Vector3 getMassCenter() {
|
||||
return massCenter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the approximate radius of 'this', assuming it is a coherent round mass.
|
||||
* (It is assumed that the radius r is related to the mass m by r = m ^ 0.5,
|
||||
* where m and r measured in solar units.)
|
||||
*/
|
||||
default double getRadius() {
|
||||
return radius();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the approximate radius of 'this', assuming it is a coherent round mass.
|
||||
* (It is assumed that the radius r is related to the mass m by r = m ^ 0.5,
|
||||
* where m and r measured in solar units.)
|
||||
*/
|
||||
default double radius() {
|
||||
return SpaceDraw.massToRadius(mass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a vector representing the gravitational force exerted by 'b' on this mass.
|
||||
* The gravitational Force F is calculated by F = G*(m1*m2)/(r*r), with m1 and m2 being the
|
||||
* masses of the objects interacting, r being the distance between the centers of the masses
|
||||
* and G being the gravitational constant.
|
||||
*/
|
||||
default Vector3 gravitationalForce(Massive b) {
|
||||
Vector3 direction = b.massCenter().minus(this.massCenter());
|
||||
double distance = direction.length();
|
||||
direction.normalize();
|
||||
double force = Simulation.G * this.mass() * b.mass() / (distance * distance);
|
||||
return direction.times(force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Centers this mass at a new position, according to the specified force vector 'force' exerted
|
||||
* on it, and updates the current velocity vector accordingly.
|
||||
* (Velocity depends on the mass of 'this', its current velocity and the exerted force.)
|
||||
*/
|
||||
void move(Vector3 force);
|
||||
}
|
181
src/MassiveForceHashMap.java
Normal file
181
src/MassiveForceHashMap.java
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* A hash map that associates a 'Massive'-object with a Vector3 (typically this is the force
|
||||
* exerted on the object). The number of key-value pairs is not limited.
|
||||
*/
|
||||
public class MassiveForceHashMap {
|
||||
private int size;
|
||||
private Massive[] keys;
|
||||
private Vector3[] values;
|
||||
|
||||
/**
|
||||
* Initializes 'this' as an empty map.
|
||||
*/
|
||||
public MassiveForceHashMap() {
|
||||
this(16);
|
||||
}
|
||||
|
||||
public MassiveForceHashMap(int capacity) {
|
||||
this.size = 0;
|
||||
this.keys = new Massive[capacity];
|
||||
this.values = new Vector3[capacity];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Massive key, Vector3 value) {
|
||||
if (size > keys.length / 2) doubleCapacity();
|
||||
|
||||
int idx = ((key.hashCode() % keys.length) + keys.length) % keys.length;
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
int pos = (idx + i) % keys.length;
|
||||
if (values[pos] == null) {
|
||||
keys[pos] = key;
|
||||
values[pos] = value;
|
||||
size++;
|
||||
return null;
|
||||
} else if (keys[pos].equals(key)) {
|
||||
Vector3 old = values[pos];
|
||||
values[pos] = value;
|
||||
return old;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
private void doubleCapacity() {
|
||||
Massive[] oldKeys = keys;
|
||||
Vector3[] oldValues = values;
|
||||
keys = new Massive[keys.length * 2];
|
||||
values = new Vector3[values.length * 2];
|
||||
size = 0;
|
||||
|
||||
for (int i = 0; i < oldKeys.length; i++) {
|
||||
Massive k = oldKeys[i];
|
||||
Vector3 v = oldValues[i];
|
||||
if (v != null) put(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Massive key) {
|
||||
int pos = find(key);
|
||||
return (pos == -1) ? null : values[pos];
|
||||
}
|
||||
|
||||
private int find(Massive key) {
|
||||
int idx = ((key.hashCode() % keys.length) + keys.length) % keys.length;
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
int pos = (idx + i) % keys.length;
|
||||
if (keys[pos] == null) {
|
||||
break;
|
||||
} else if (keys[pos].equals(key)) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the mapping for the specified key from this map if present.
|
||||
* Returns the previous value associated with key, or null if there was
|
||||
* no mapping for key.
|
||||
* Precondition: key != null
|
||||
*/
|
||||
public Vector3 delete(Massive key) {
|
||||
int pos = find(key);
|
||||
if (pos == -1) return null;
|
||||
|
||||
Vector3 val = values[pos];
|
||||
values[pos] = null;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 'true' if this map contains a mapping for the specified key.
|
||||
*/
|
||||
public boolean containsKey(Massive key) {
|
||||
return this.get(key) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a readable representation of this map, with all key-value pairs. Their order is not
|
||||
* defined.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (size == 0) return "{}";
|
||||
|
||||
StringBuilder sb = new StringBuilder("{");
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
Massive k = keys[i];
|
||||
Vector3 v = values[i];
|
||||
if (k != null && v != null) {
|
||||
sb.append("\n ");
|
||||
sb.append(k);
|
||||
sb.append(": ");
|
||||
sb.append(v);
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append("\n}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares `this` with the specified object for equality. Returns `true` if the specified
|
||||
* `o` is not `null` and is of type `MassiveForceHashMap` and both `this` and `o` have equal
|
||||
* key-value pairs, i.e. the number of key-value pairs is the same in both maps and every
|
||||
* key-value pair in `this` equals one key-value pair in `o`. Two key-value pairs are
|
||||
* equal if the two keys are equal and the two values are equal. Otherwise, `false` is returned.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof MassiveForceHashMap map) || map.size != size)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
Massive k1 = keys[i];
|
||||
Vector3 v1 = values[i];
|
||||
if (k1 == null || v1 == null) continue;
|
||||
Vector3 v2 = map.get(k1);
|
||||
if (!v1.equals(v2)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hashCode of `this`.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
Massive k = keys[i];
|
||||
Vector3 v = values[i];
|
||||
if (k == null || v == null) continue;
|
||||
hash ^= k.hashCode();
|
||||
hash ^= v.hashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the keys in no specified order.
|
||||
*/
|
||||
public MassiveLinkedList keyList() {
|
||||
MassiveLinkedList list = new MassiveLinkedList();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if (keys[i] != null && values[i] != null)
|
||||
list.addLast(keys[i]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
270
src/MassiveForceTreeMap.java
Normal file
270
src/MassiveForceTreeMap.java
Normal file
@ -0,0 +1,270 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A map that associates an object of 'Massive' with a Vector3. The number of key-value pairs
|
||||
* is not limited.
|
||||
*/
|
||||
public class MassiveForceTreeMap implements MassiveSet {
|
||||
private int size = 0;
|
||||
private Item root;
|
||||
|
||||
/**
|
||||
* 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(Massive key, Vector3 value) {
|
||||
if (root == null) {
|
||||
root = new Item(key, value);
|
||||
size++;
|
||||
return null;
|
||||
}
|
||||
|
||||
Item item = root;
|
||||
while (item != null) {
|
||||
if (item.key.equals(key)) {
|
||||
Vector3 old = item.value;
|
||||
item.value = value;
|
||||
return old;
|
||||
} else if (item.key.mass() > key.mass()) {
|
||||
if (item.left != null) {
|
||||
item = item.left;
|
||||
} else {
|
||||
item.setLeft(new Item(key, value));
|
||||
size++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (item.right != null) {
|
||||
item = item.right;
|
||||
} else{
|
||||
item.setRight(new Item(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(Massive key) {
|
||||
Item item = root;
|
||||
while (item != null) {
|
||||
if (item.key.equals(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.
|
||||
* Precondition: key != null
|
||||
*/
|
||||
public boolean containsKey(Massive key) {
|
||||
Item item = root;
|
||||
while (item != null) {
|
||||
if (item.key.equals(key)) {
|
||||
return true;
|
||||
} else if (item.key.mass() > key.mass()) {
|
||||
item = item.left;
|
||||
} else {
|
||||
item = item.right;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String toString(Item item) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
if (item == null) {
|
||||
return s.toString();
|
||||
}
|
||||
s.append(this.toString(item.right));
|
||||
s.append(String.format("{%s: %s}\n", item.key, item.value));
|
||||
s.append(this.toString(item.left));
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a readable representation of this map, in which key-value pairs are ordered
|
||||
* descending according to 'key.getMass()'.
|
||||
*/
|
||||
public String toString() {
|
||||
return (root != null) ? toString(root) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a `MassiveSet` view of the keys contained in this tree map. Changing the
|
||||
* elements of the returned `MassiveSet` object also affects the keys in this tree map.
|
||||
*/
|
||||
public MassiveSet getKeys() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(CodeDraw cd) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public MassiveIterator iterator() {
|
||||
return new MassiveIterator() {
|
||||
private Item last = null;
|
||||
private Item next = root.getLeftLeaf();
|
||||
|
||||
@Override
|
||||
public Massive next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
|
||||
last = next;
|
||||
Item newNext = (next.right != null) ? next.right.getLeftLeaf() : next.parent;
|
||||
|
||||
while (newNext != null && newNext.right == next) {
|
||||
next = newNext;
|
||||
newNext = newNext.parent;
|
||||
}
|
||||
|
||||
next = newNext;
|
||||
return last.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (last == null) throw new IllegalStateException();
|
||||
removeItem(last);
|
||||
last = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Massive element) {
|
||||
return containsKey(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Massive element) {
|
||||
Item item = root;
|
||||
while (item != null) {
|
||||
if (item.key.equals(element)) {
|
||||
removeItem(item);
|
||||
return;
|
||||
} else if (item.key.mass() > element.mass()) {
|
||||
item = item.left;
|
||||
} else {
|
||||
item = item.right;
|
||||
}
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
private void removeItem(Item item) {
|
||||
size--;
|
||||
Item newP = null;
|
||||
|
||||
if (item.left != null) {
|
||||
newP = item.left.getRightLeaf();
|
||||
if (newP != item.left) {
|
||||
newP.parent.setRight(newP.left);
|
||||
newP.setLeft(item.left);
|
||||
}
|
||||
newP.setRight(item.right);
|
||||
} else if (item.right != null) {
|
||||
newP = item.right.getLeftLeaf();
|
||||
if (newP != item.right) {
|
||||
newP.parent.setLeft(newP.right);
|
||||
newP.setRight(item.right);
|
||||
}
|
||||
newP.setLeft(item.left);
|
||||
}
|
||||
|
||||
if (newP == null) {
|
||||
root = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.parent != null) {
|
||||
if (item.parent.left == item) {
|
||||
item.parent.setLeft(newP);
|
||||
} else {
|
||||
item.parent.setRight(newP);
|
||||
}
|
||||
} else {
|
||||
root = newP;
|
||||
newP.parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
size = 0;
|
||||
root = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MassiveLinkedList toList() {
|
||||
MassiveLinkedList list = new MassiveLinkedList();
|
||||
for (Massive m : this) {
|
||||
list.addLast(m);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static class Item {
|
||||
private final Massive key;
|
||||
private Vector3 value;
|
||||
private Item parent;
|
||||
private Item left;
|
||||
private Item right;
|
||||
|
||||
public Item(Massive key, Vector3 value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setLeft(Item left) {
|
||||
this.left = left;
|
||||
if (left != null) left.parent = this;
|
||||
}
|
||||
|
||||
public void setRight(Item right) {
|
||||
this.right = right;
|
||||
if (right != null) right.parent = this;
|
||||
}
|
||||
|
||||
public Item getLeftLeaf() {
|
||||
Item cur = this;
|
||||
while (cur.left != null) cur = cur.left;
|
||||
return cur;
|
||||
}
|
||||
|
||||
public Item getRightLeaf() {
|
||||
Item cur = this;
|
||||
while (cur.right != null) cur = cur.right;
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
}
|
11
src/MassiveIterable.java
Normal file
11
src/MassiveIterable.java
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Iterable objects with 'Massive' elements.
|
||||
*/
|
||||
public interface MassiveIterable extends Iterable<Massive> {
|
||||
|
||||
/**
|
||||
* Returns an iterator over elements of 'Massive'.
|
||||
*/
|
||||
@Override
|
||||
MassiveIterator iterator();
|
||||
}
|
20
src/MassiveIterator.java
Normal file
20
src/MassiveIterator.java
Normal file
@ -0,0 +1,20 @@
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An iterator over elements of 'Massive'.
|
||||
*/
|
||||
public interface MassiveIterator extends Iterator<Massive> {
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
* (Returns 'null' if the iteration has no more elements.)
|
||||
*/
|
||||
@Override
|
||||
Massive next();
|
||||
|
||||
/**
|
||||
* Returns 'true' if the iteration has more elements.
|
||||
*/
|
||||
@Override
|
||||
boolean hasNext();
|
||||
}
|
220
src/MassiveLinkedList.java
Normal file
220
src/MassiveLinkedList.java
Normal file
@ -0,0 +1,220 @@
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A list of massive objects implemented as a linked list.
|
||||
* The number of elements of the list is not limited.
|
||||
*/
|
||||
public class MassiveLinkedList implements MassiveIterable {
|
||||
private int size = 0;
|
||||
private Item first;
|
||||
private Item last;
|
||||
|
||||
/**
|
||||
* Initializes 'this' as an empty list.
|
||||
*/
|
||||
public MassiveLinkedList() {
|
||||
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 MassiveLinkedList(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(Massive body) {
|
||||
if (first == null) {
|
||||
first = new Item(body);
|
||||
last = first;
|
||||
} else {
|
||||
first.setPrev(new Item(body));
|
||||
first = first.prev;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the specified element 'body' to the end of this list.
|
||||
*/
|
||||
public void addLast(Massive body) {
|
||||
if (last == null) {
|
||||
last = new Item(body);
|
||||
first = last;
|
||||
} else {
|
||||
last.setNext(new Item(body));
|
||||
last = last.next;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element in this list.
|
||||
* Returns 'null' if the list is empty.
|
||||
*/
|
||||
public Massive getLast() {
|
||||
return (last != null) ? last.body : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element in this list.
|
||||
* Returns 'null' if the list is empty.
|
||||
*/
|
||||
public Massive getFirst() {
|
||||
return (first != null) ? first.body : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and removes the first element in this list.
|
||||
* Returns 'null' if the list is empty.
|
||||
*/
|
||||
public Massive pollFirst() {
|
||||
if (first == null) {
|
||||
return null;
|
||||
}
|
||||
Massive m = first.body;
|
||||
first = first.next;
|
||||
if (first != null) first.setPrev(null);
|
||||
size--;
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and removes the last element in this list.
|
||||
* Returns 'null' if the list is empty.
|
||||
*/
|
||||
public Massive pollLast() {
|
||||
if (last == null) {
|
||||
return null;
|
||||
}
|
||||
Massive m = last.body;
|
||||
last = last.prev;
|
||||
if (last != null) last.setNext(null);
|
||||
size--;
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the specified position in this list.
|
||||
* Precondition: i >= 0 && i <= size().
|
||||
*/
|
||||
public void add(int i, Massive m) {
|
||||
if (first == null || i == 0) {
|
||||
addFirst(m);
|
||||
return;
|
||||
} else if (i == size) {
|
||||
addLast(m);
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = first;
|
||||
for (int j = 0; j < i; j++) {
|
||||
item = item.next;
|
||||
}
|
||||
|
||||
item.prev.setNext(new Item(m));
|
||||
item.setPrev(item.prev.next);
|
||||
size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element at the specified position in this list.
|
||||
* Precondition: i >= 0 && i < size().
|
||||
*/
|
||||
public Massive get(int i) {
|
||||
Item 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(Massive m) {
|
||||
if (first == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Item item = first;
|
||||
for (int i = 0; i < size; i++, item = item.next) {
|
||||
if (item.body.equals(m)) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this list.
|
||||
*/
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MassiveIterator iterator() {
|
||||
return new MassiveIterator() {
|
||||
Item ptr = first;
|
||||
boolean yieldedFirst = false;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return ptr != null && (!yieldedFirst || ptr.next != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Massive next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
if (!yieldedFirst) {
|
||||
yieldedFirst = true;
|
||||
} else {
|
||||
ptr = ptr.next;
|
||||
}
|
||||
return ptr.body;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class Item {
|
||||
private final Massive body;
|
||||
private Item prev;
|
||||
private Item next;
|
||||
|
||||
public Item(Massive body) {
|
||||
this.body = body;
|
||||
this.prev = null;
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
public void setPrev(Item prev) {
|
||||
this.prev = prev;
|
||||
if (prev != null) prev.next = this;
|
||||
}
|
||||
|
||||
public void setNext(Item next) {
|
||||
this.next = next;
|
||||
if (next != null) next.prev = this;
|
||||
}
|
||||
}
|
||||
}
|
31
src/MassiveSet.java
Normal file
31
src/MassiveSet.java
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* A collection of 'Massive' objects in which there are no duplicates.
|
||||
*/
|
||||
public interface MassiveSet extends MassiveIterable, Drawable {
|
||||
|
||||
/**
|
||||
* Returns 'true' if the set has the specified element (i.e., has an element equal to the
|
||||
* specified element).
|
||||
*/
|
||||
boolean contains(Massive element);
|
||||
|
||||
/**
|
||||
* Removes the specified element from the set.
|
||||
*/
|
||||
void remove(Massive element);
|
||||
|
||||
/**
|
||||
* Removes all elements from the set.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the set.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Returns an object of 'MassiveLinkedList' with all elements of 'this'.
|
||||
*/
|
||||
MassiveLinkedList toList();
|
||||
}
|
67
src/NamedBody.java
Normal file
67
src/NamedBody.java
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
public class NamedBody extends Body {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Initializes this with name, mass, current position and movement.
|
||||
*/
|
||||
public NamedBody(String name, double mass, Vector3 massCenter, Vector3 currentMovement) {
|
||||
super(mass, massCenter, currentMovement);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NamedBody(String name, double mass) {
|
||||
super(mass);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NamedBody(String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NamedBody(String name, Body body) {
|
||||
super(body);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NamedBody(NamedBody other) {
|
||||
super(other);
|
||||
this.name = other.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the body.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares `this` with the specified object. Returns `true` if the specified `o` is not
|
||||
* `null` and is of type `NamedBody` and both `this` and `o` have equal names.
|
||||
* Otherwise, `false` is returned.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof NamedBody b)) return false;
|
||||
return this.name.equals(b.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hashCode of `this`.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.name.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a readable representation including the name of this body.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getName();
|
||||
}
|
||||
}
|
95
src/NamedBodyForcePair.java
Normal file
95
src/NamedBodyForcePair.java
Normal file
@ -0,0 +1,95 @@
|
||||
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 NamedBody 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(new NamedBody(name, mass, massCenter, currentMovement));
|
||||
}
|
||||
|
||||
public NamedBodyForcePair(String name, Body body) {
|
||||
this(new NamedBody(name, body));
|
||||
}
|
||||
|
||||
public NamedBodyForcePair(NamedBody body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public NamedBodyForcePair(NamedBodyForcePair other) {
|
||||
this(new NamedBody(other.body));
|
||||
}
|
||||
|
||||
public Body getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the body.
|
||||
*/
|
||||
public String getName() {
|
||||
return body.getName();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
127
src/ReadDataUtil.java
Normal file
127
src/ReadDataUtil.java
Normal file
@ -0,0 +1,127 @@
|
||||
import java.io.*;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ReadDataUtil {
|
||||
|
||||
private static final Pattern LINE_FORMAT = Pattern.compile("^\\d+(\\.\\d+)?, *[A-Za-z \\d:.-]+(, *[-+]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?){6}, *$");
|
||||
private static final Pattern DATE_COLUMN_FORMAT = Pattern.compile("^A\\.D\\. (?<year>\\d{4})-(?<month>[A-Z][a-z]{2})-(?<day>[0-3]\\d) \\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$");
|
||||
private static final Pattern DATE_FORMAT_YYYY_MMM_DD = Pattern.compile("^(?<year>\\d{4})-(?<month>[A-Z][a-z]{2})-(?<day>[0-3]\\d)$");
|
||||
|
||||
/**
|
||||
* Reads the position and velocity vector on the specified 'day' from the file with the
|
||||
* specified 'path', and sets position and current velocity of 'b' accordingly. If
|
||||
* successful the method returns 'true'. If the specified 'day' was not found in the file,
|
||||
* 'b' is unchanged and the method returns 'false'.
|
||||
* The file format is validated before reading the state.
|
||||
* Lines before the line "$$SOE" and after the line "$$EOE" the are ignored. Each line of the
|
||||
* file between the line "$$SOE" and the line "$$EOE" is required to have the following format:
|
||||
* JDTDB, TIME, X, Y, Z, VX, VY, VZ
|
||||
* where JDTDB is interpretable as a 'double' value, TIME is a string and X, Y, Z, VX, VY and
|
||||
* VZ are interpretable as 'double' values. JDTDB can be ignored. The character ',' must only
|
||||
* be used as field separator. If the file is not found, an exception of the class
|
||||
* 'StateFileNotFoundException' is thrown. If it does not comply with the format described
|
||||
* above, the method throws an exception of the class 'StateFileFormatException'. Both
|
||||
* exceptions are subtypes of 'IOException'.
|
||||
* Precondition: b != null, path != null, day != null and has the format YYYY-MM-DD.
|
||||
*/
|
||||
public static boolean readConfiguration(NamedBody b, String path, String day) throws IOException {
|
||||
State state = State.Pre;
|
||||
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(path))) {
|
||||
Scanner lines = new Scanner(in);
|
||||
long lineNum = 0;
|
||||
while (lines.hasNextLine() && state != State.Post) {
|
||||
lineNum++;
|
||||
String line = lines.nextLine();
|
||||
State nextState = state.next(line);
|
||||
|
||||
if (state == State.In && nextState == State.In) {
|
||||
Matcher m = LINE_FORMAT.matcher(line);
|
||||
if (!m.matches()) {
|
||||
throw new StateFileFormatException(path, lineNum);
|
||||
}
|
||||
|
||||
String[] rows = line.split(", *");
|
||||
String date;
|
||||
try {
|
||||
date = convertDateColumn(rows[1]);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new StateFileFormatException(path, lineNum);
|
||||
}
|
||||
if (date.equals(day)) {
|
||||
try {
|
||||
double x = Double.parseDouble(rows[2]); // [km]
|
||||
double y = Double.parseDouble(rows[3]); // [km]
|
||||
double z = Double.parseDouble(rows[4]); // [km]
|
||||
double vx = Double.parseDouble(rows[5]); // [km/s]
|
||||
double vy = Double.parseDouble(rows[6]); // [km/s]
|
||||
double vz = Double.parseDouble(rows[7]); // [km/s]
|
||||
b.setState(new Vector3(x * 1000, y * 1000, z * 1000), new Vector3(vx * 1000, vy * 1000, vz * 1000));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new StateFileFormatException(path, lineNum);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
state = nextState;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (e instanceof FileNotFoundException) {
|
||||
throw new StateFileNotFoundException(path);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String convertDateColumn(String column) {
|
||||
Matcher m = DATE_COLUMN_FORMAT.matcher(column);
|
||||
if (!m.matches()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return m.group("year") + "-" + convertMonth(m.group("month")) + "-" + m.group("day");
|
||||
}
|
||||
|
||||
public static String convertDate(String date) {
|
||||
Matcher m = DATE_FORMAT_YYYY_MMM_DD.matcher(date);
|
||||
if (!m.matches()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return m.group("year") + "-" + convertMonth(m.group("month")) + "-" + m.group("day");
|
||||
}
|
||||
|
||||
private static String convertMonth(String month) {
|
||||
return switch (month) {
|
||||
case "Jan" -> "01";
|
||||
case "Feb" -> "02";
|
||||
case "Mar" -> "03";
|
||||
case "Apr" -> "04";
|
||||
case "May" -> "05";
|
||||
case "Jun" -> "06";
|
||||
case "Jul" -> "07";
|
||||
case "Aug" -> "08";
|
||||
case "Sep" -> "09";
|
||||
case "Oct" -> "10";
|
||||
case "Nov" -> "11";
|
||||
case "Dec" -> "12";
|
||||
default -> throw new IllegalArgumentException();
|
||||
};
|
||||
}
|
||||
|
||||
private enum State {
|
||||
Pre, In, Post;
|
||||
|
||||
public State next(String line) {
|
||||
switch (this) {
|
||||
case Pre: if (line.equals("$$SOE")) return In; break;
|
||||
case In: if (line.equals("$$EOE")) return Post; break;
|
||||
case Post: break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,9 @@ import java.util.Random;
|
||||
// 3. Beim Methodenaufruf steht links vom `.` entweder das Objekt, oder die Klasse. In Java beginnen Variablennamen
|
||||
// üblicherweise mit Kleinbuchstaben und Klassennamen üblicherweise mit einem Großbuchstaben.
|
||||
|
||||
// Simulates the formation of a massive solar system.
|
||||
/**
|
||||
* Simulates the formation of a massive solar system.
|
||||
*/
|
||||
public class Simulation {
|
||||
|
||||
// gravitational constant
|
||||
@ -37,18 +39,20 @@ public class Simulation {
|
||||
|
||||
// all quantities are based on units of kilogram respectively second and meter.
|
||||
|
||||
// The main simulation method using instances of other classes.
|
||||
/**
|
||||
* The main simulation method using instances of other classes.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// simulation
|
||||
CodeDraw cd = new CodeDraw();
|
||||
Body[] bodies = new Body[NUMBER_OF_BODIES];
|
||||
Vector3[] forceOnBody = new Vector3[bodies.length];
|
||||
BodyQueue bodies = new BodyQueue();
|
||||
BodyForceMap forceOnBody = new BodyForceMap();
|
||||
|
||||
Random random = new Random(2022);
|
||||
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
bodies[i] = new Body(
|
||||
Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length, // kg
|
||||
for (int i = 0; i < NUMBER_OF_BODIES; i++) {
|
||||
bodies.add(new Body(
|
||||
Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / NUMBER_OF_BODIES, // kg
|
||||
new Vector3(
|
||||
0.2 * random.nextGaussian() * AU,
|
||||
0.2 * random.nextGaussian() * AU,
|
||||
@ -59,19 +63,25 @@ public class Simulation {
|
||||
0 + random.nextGaussian() * 5e3,
|
||||
0 + random.nextGaussian() * 5e3
|
||||
)
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
double seconds = 0;
|
||||
|
||||
// simulation loop
|
||||
while (true) {
|
||||
BodyQueue newBodies = new BodyQueue(bodies);
|
||||
Body[] tmp = new Body[bodies.size()];
|
||||
for (int i = 0; bodies.size() > 0; i++) {
|
||||
tmp[i] = bodies.poll();
|
||||
}
|
||||
seconds++; // each iteration computes the movement of the celestial bodies within one second.
|
||||
|
||||
/*
|
||||
// merge bodies that have collided
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
for (int j = i + 1; j < bodies.length; j++) {
|
||||
if (bodies[j].distanceTo(bodies[i]) < bodies[j].radius() + bodies[i].radius()) {
|
||||
if (bodies[j].collidesWith(bodies[i])) {
|
||||
bodies[i] = bodies[i].merge(bodies[j]);
|
||||
Body[] bodiesOneRemoved = new Body[bodies.length - 1];
|
||||
for (int k = 0; k < bodiesOneRemoved.length; k++) {
|
||||
@ -86,22 +96,23 @@ public class Simulation {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// for each body (with index i): compute the total force exerted on it.
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
forceOnBody[i] = new Vector3(); // begin with zero
|
||||
for (int j = 0; j < bodies.length; j++) {
|
||||
if (i != j) {
|
||||
Vector3 forceToAdd = bodies[i].gravitationalForce(bodies[j]);
|
||||
forceOnBody[i] = forceOnBody[i].plus(forceToAdd);
|
||||
for (Body b1 : tmp) {
|
||||
Vector3 force = new Vector3(); // begin with zero
|
||||
for (Body b2 : tmp) {
|
||||
if (b1 != b2) {
|
||||
force = force.plus(b1.gravitationalForce(b2));
|
||||
}
|
||||
}
|
||||
forceOnBody.put(b1, force);
|
||||
}
|
||||
// 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]);
|
||||
for (Body body : tmp) {
|
||||
body.move(forceOnBody.get(body));
|
||||
}
|
||||
|
||||
// show all movements in the canvas only every hour (to speed up the simulation)
|
||||
@ -110,7 +121,7 @@ public class Simulation {
|
||||
cd.clear(Color.BLACK);
|
||||
|
||||
// draw new positions
|
||||
for (Body body : bodies) {
|
||||
for (Body body : tmp) {
|
||||
body.draw(cd);
|
||||
}
|
||||
|
||||
@ -118,7 +129,7 @@ public class Simulation {
|
||||
cd.show();
|
||||
}
|
||||
|
||||
bodies = newBodies;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
src/Simulation4.java
Normal file
49
src/Simulation4.java
Normal file
@ -0,0 +1,49 @@
|
||||
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++;
|
||||
|
||||
sol.addForceTo(sol);
|
||||
sol.update();
|
||||
|
||||
if ((seconds % 3600) == 0) {
|
||||
cd.clear(Color.BLACK);
|
||||
sol.draw(cd);
|
||||
cd.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
113
src/Simulation5.java
Normal file
113
src/Simulation5.java
Normal file
@ -0,0 +1,113 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Simulates the formation of a massive solar system.
|
||||
*/
|
||||
public class Simulation5 {
|
||||
|
||||
// gravitational constant
|
||||
public static final double G = 6.6743e-11;
|
||||
|
||||
// one astronomical unit (AU) is the average distance of earth to the sun.
|
||||
public static final double AU = 150e9; // meters
|
||||
|
||||
// one light year
|
||||
public static final double LY = 9.461e15; // meters
|
||||
|
||||
// some further constants needed in the simulation
|
||||
public static final double SUN_MASS = 1.989e30; // kilograms
|
||||
public static final double SUN_RADIUS = 696340e3; // meters
|
||||
public static final double EARTH_MASS = 5.972e24; // kilograms
|
||||
public static final double EARTH_RADIUS = 6371e3; // meters
|
||||
|
||||
// set some system parameters
|
||||
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
|
||||
|
||||
public static final int NUMBER_OF_BODIES = 22;
|
||||
public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms
|
||||
|
||||
// all quantities are based on units of kilogram respectively second and meter.
|
||||
|
||||
/**
|
||||
* The main simulation method using instances of other classes.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// simulation
|
||||
CodeDraw cd = new CodeDraw();
|
||||
|
||||
// create solar system with 12 bodies
|
||||
NamedBody sun = new NamedBody(SolSystem4.SUN_NAMED);
|
||||
NamedBody earth = new NamedBody(SolSystem4.EARTH_NAMED);
|
||||
NamedBody moon = new NamedBody(SolSystem4.MOON_NAMED);
|
||||
NamedBody mars = new NamedBody(SolSystem4.MARS_NAMED);
|
||||
NamedBody deimos = new NamedBody(SolSystem4.DEIMOS_NAMED);
|
||||
NamedBody phobos = new NamedBody(SolSystem4.PHOBOS_NAMED);
|
||||
NamedBody mercury = new NamedBody(SolSystem4.MERCURY_NAMED);
|
||||
NamedBody venus = new NamedBody(SolSystem4.VENUS_NAMED);
|
||||
NamedBody vesta = new NamedBody(SolSystem4.VESTA_NAMED);
|
||||
NamedBody pallas = new NamedBody(SolSystem4.PALLAS_NAMED);
|
||||
NamedBody hygiea = new NamedBody(SolSystem4.HYGIEA_NAMED);
|
||||
NamedBody ceres = new NamedBody(SolSystem4.CERES_NAMED);
|
||||
|
||||
// create some additional bodies
|
||||
Body[] bodies = new Body[NUMBER_OF_BODIES];
|
||||
|
||||
Random random = new Random(2022);
|
||||
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
bodies[i] = new Body(
|
||||
Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length,
|
||||
new Vector3(0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU),
|
||||
new Vector3(0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3)
|
||||
);
|
||||
}
|
||||
|
||||
MassiveForceHashMap forceOnBody = new MassiveForceHashMap();
|
||||
forceOnBody.put(sun, new Vector3());
|
||||
forceOnBody.put(earth, new Vector3());
|
||||
forceOnBody.put(moon, new Vector3());
|
||||
forceOnBody.put(mars, new Vector3());
|
||||
forceOnBody.put(deimos, new Vector3());
|
||||
forceOnBody.put(phobos, new Vector3());
|
||||
forceOnBody.put(mercury, new Vector3());
|
||||
forceOnBody.put(venus, new Vector3());
|
||||
forceOnBody.put(vesta, new Vector3());
|
||||
forceOnBody.put(pallas, new Vector3());
|
||||
forceOnBody.put(hygiea, new Vector3());
|
||||
forceOnBody.put(ceres, new Vector3());
|
||||
|
||||
for (Body b : bodies) {
|
||||
forceOnBody.put(b, new Vector3());
|
||||
}
|
||||
|
||||
long seconds = 0;
|
||||
while (true) {
|
||||
seconds++;
|
||||
|
||||
for (Massive b1 : forceOnBody.keyList()) {
|
||||
Vector3 force = new Vector3();
|
||||
for (Massive b2 : forceOnBody.keyList()) {
|
||||
if (b1 != b2) {
|
||||
force = force.plus(b1.gravitationalForce(b2));
|
||||
}
|
||||
}
|
||||
forceOnBody.put(b1, force);
|
||||
}
|
||||
|
||||
for (Massive body : forceOnBody.keyList()) {
|
||||
body.move(forceOnBody.get(body));
|
||||
}
|
||||
|
||||
if ((seconds % 3600) == 0) {
|
||||
cd.clear(Color.BLACK);
|
||||
for (Massive body : forceOnBody.keyList()) {
|
||||
body.draw(cd);
|
||||
}
|
||||
cd.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
113
src/Simulation6.java
Normal file
113
src/Simulation6.java
Normal file
@ -0,0 +1,113 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Simulates the formation of a massive solar system.
|
||||
*/
|
||||
public class Simulation6 {
|
||||
|
||||
// gravitational constant
|
||||
public static final double G = 6.6743e-11;
|
||||
|
||||
// one astronomical unit (AU) is the average distance of earth to the sun.
|
||||
public static final double AU = 150e9; // meters
|
||||
|
||||
// one light year
|
||||
public static final double LY = 9.461e15; // meters
|
||||
|
||||
// some further constants needed in the simulation
|
||||
public static final double SUN_MASS = 1.989e30; // kilograms
|
||||
public static final double SUN_RADIUS = 696340e3; // meters
|
||||
public static final double EARTH_MASS = 5.972e24; // kilograms
|
||||
public static final double EARTH_RADIUS = 6371e3; // meters
|
||||
|
||||
// set some system parameters
|
||||
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
|
||||
|
||||
public static final int NUMBER_OF_BODIES = 22;
|
||||
public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms
|
||||
|
||||
// all quantities are based on units of kilogram respectively second and meter.
|
||||
|
||||
/**
|
||||
* The main simulation method using instances of other classes.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// simulation
|
||||
CodeDraw cd = new CodeDraw();
|
||||
|
||||
// create solar system with 12 bodies
|
||||
NamedBody sun = new NamedBody(SolSystem4.SUN_NAMED);
|
||||
NamedBody earth = new NamedBody(SolSystem4.EARTH_NAMED);
|
||||
NamedBody moon = new NamedBody(SolSystem4.MOON_NAMED);
|
||||
NamedBody mars = new NamedBody(SolSystem4.MARS_NAMED);
|
||||
NamedBody deimos = new NamedBody(SolSystem4.DEIMOS_NAMED);
|
||||
NamedBody phobos = new NamedBody(SolSystem4.PHOBOS_NAMED);
|
||||
NamedBody mercury = new NamedBody(SolSystem4.MERCURY_NAMED);
|
||||
NamedBody venus = new NamedBody(SolSystem4.VENUS_NAMED);
|
||||
NamedBody vesta = new NamedBody(SolSystem4.VESTA_NAMED);
|
||||
NamedBody pallas = new NamedBody(SolSystem4.PALLAS_NAMED);
|
||||
NamedBody hygiea = new NamedBody(SolSystem4.HYGIEA_NAMED);
|
||||
NamedBody ceres = new NamedBody(SolSystem4.CERES_NAMED);
|
||||
|
||||
// create some additional bodies
|
||||
Body[] bodies = new Body[NUMBER_OF_BODIES];
|
||||
|
||||
Random random = new Random(2022);
|
||||
|
||||
for (int i = 0; i < bodies.length; i++) {
|
||||
bodies[i] = new Body(
|
||||
Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length,
|
||||
new Vector3(0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU),
|
||||
new Vector3(0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3)
|
||||
);
|
||||
}
|
||||
|
||||
MassiveForceTreeMap forceOnBody = new MassiveForceTreeMap();
|
||||
forceOnBody.put(sun, new Vector3());
|
||||
forceOnBody.put(earth, new Vector3());
|
||||
forceOnBody.put(moon, new Vector3());
|
||||
forceOnBody.put(mars, new Vector3());
|
||||
forceOnBody.put(deimos, new Vector3());
|
||||
forceOnBody.put(phobos, new Vector3());
|
||||
forceOnBody.put(mercury, new Vector3());
|
||||
forceOnBody.put(venus, new Vector3());
|
||||
forceOnBody.put(vesta, new Vector3());
|
||||
forceOnBody.put(pallas, new Vector3());
|
||||
forceOnBody.put(hygiea, new Vector3());
|
||||
forceOnBody.put(ceres, new Vector3());
|
||||
|
||||
for (Body b : bodies) {
|
||||
forceOnBody.put(b, new Vector3());
|
||||
}
|
||||
|
||||
long seconds = 0;
|
||||
while (true) {
|
||||
seconds++;
|
||||
|
||||
for (Massive b1 : forceOnBody.getKeys()) {
|
||||
Vector3 force = new Vector3();
|
||||
for (Massive b2 : forceOnBody.getKeys()) {
|
||||
if (b1 != b2) {
|
||||
force = force.plus(b1.gravitationalForce(b2));
|
||||
}
|
||||
}
|
||||
forceOnBody.put(b1, force);
|
||||
}
|
||||
|
||||
for (Massive body : forceOnBody.getKeys()) {
|
||||
body.move(forceOnBody.get(body));
|
||||
}
|
||||
|
||||
if ((seconds % 3600) == 0) {
|
||||
cd.clear(Color.BLACK);
|
||||
for (Massive body : forceOnBody.getKeys()) {
|
||||
body.draw(cd);
|
||||
}
|
||||
cd.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
src/Simulation8.java
Normal file
120
src/Simulation8.java
Normal file
@ -0,0 +1,120 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Simulates the solar system.
|
||||
*/
|
||||
public class Simulation8 {
|
||||
|
||||
// gravitational constant
|
||||
public static final double G = 6.6743e-11;
|
||||
|
||||
// one astronomical unit (AU) is the average distance of earth to the sun.
|
||||
public static final double AU = 150e9; // meters
|
||||
|
||||
// set some system parameters
|
||||
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
|
||||
|
||||
// all quantities are based on units of kilogram respectively second and meter.
|
||||
|
||||
// The main simulation method using instances of other classes.
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 2) {
|
||||
System.err.println("Error: wrong number of arguments.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
String statePath = args[0];
|
||||
String date;
|
||||
try {
|
||||
date = ReadDataUtil.convertDate(args[1]);
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("Error: State has wrong format (requires YYYY-MMM-DD), aborting.");
|
||||
System.exit(2);
|
||||
return;
|
||||
}
|
||||
|
||||
// simulation
|
||||
CodeDraw cd = new CodeDraw();
|
||||
|
||||
// create solar system with 13 bodies
|
||||
MassiveForceTreeMap forceOnBody = new MassiveForceTreeMap();
|
||||
|
||||
forceOnBody.put(new NamedBody("Oumuamua", 8e6), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Earth", 5.972E24), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Moon", 7.349E22), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Mars", 6.41712E23), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Deimos", 1.8E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Phobos", 1.08E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Mercury", 3.301E23), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Venus", 4.86747E24), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Vesta", 2.5908E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Pallas", 2.14E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Hygiea", 8.32E19), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Ceres", 9.394E20), new Vector3());
|
||||
|
||||
MassiveIterator iter = forceOnBody.getKeys().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Massive a = iter.next();
|
||||
if (a instanceof NamedBody b) {
|
||||
boolean remove = false;
|
||||
|
||||
try {
|
||||
boolean found = ReadDataUtil.readConfiguration(b, statePath + "/" + b.getName() + ".txt", date);
|
||||
if (!found) {
|
||||
System.err.println("Warning: State not available for " + b.getName() + ".");
|
||||
remove = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (e instanceof StateFileNotFoundException notFound) {
|
||||
System.err.println("Warning: " + notFound.getMessage());
|
||||
} else if (e instanceof StateFileFormatException format) {
|
||||
System.err.println("Warning: " + format.getMessage());
|
||||
} else {
|
||||
System.err.println("Error: " + e.getMessage());
|
||||
System.exit(3);
|
||||
}
|
||||
remove = true;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
System.err.println("Running simulation without " + b.getName());
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add sun after states have been read from files.
|
||||
forceOnBody.put(new NamedBody("Sun", 1.989E30), new Vector3());
|
||||
|
||||
System.out.println("Starting simulation");
|
||||
long seconds = 0;
|
||||
while (true) {
|
||||
seconds++;
|
||||
|
||||
for (Massive b1 : forceOnBody.getKeys()) {
|
||||
Vector3 force = new Vector3();
|
||||
for (Massive b2 : forceOnBody.getKeys()) {
|
||||
if (b1 != b2) {
|
||||
force = force.plus(b1.gravitationalForce(b2));
|
||||
}
|
||||
}
|
||||
forceOnBody.put(b1, force);
|
||||
}
|
||||
|
||||
for (Massive body : forceOnBody.getKeys()) {
|
||||
body.move(forceOnBody.get(body));
|
||||
}
|
||||
|
||||
if ((seconds % 3600) == 0) {
|
||||
cd.clear(Color.BLACK);
|
||||
for (Massive body : forceOnBody.getKeys()) {
|
||||
body.draw(cd);
|
||||
}
|
||||
cd.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
122
src/Simulation9.java
Normal file
122
src/Simulation9.java
Normal file
@ -0,0 +1,122 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Simulates the solar system.
|
||||
*/
|
||||
public class Simulation9 {
|
||||
|
||||
// gravitational constant
|
||||
public static final double G = 6.6743e-11;
|
||||
|
||||
// one astronomical unit (AU) is the average distance of earth to the sun.
|
||||
public static final double AU = 150e9; // meters
|
||||
|
||||
// set some system parameters
|
||||
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
|
||||
|
||||
// all quantities are based on units of kilogram respectively second and meter.
|
||||
|
||||
// The main simulation method using instances of other classes.
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 2) {
|
||||
System.err.println("Error: wrong number of arguments.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
String statePath = args[0];
|
||||
String date;
|
||||
try {
|
||||
date = ReadDataUtil.convertDate(args[1]);
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("Error: State has wrong format (requires YYYY-MMM-DD), aborting.");
|
||||
System.exit(2);
|
||||
return;
|
||||
}
|
||||
|
||||
// simulation
|
||||
CodeDraw cd = new CodeDraw();
|
||||
|
||||
// create solar system with 13 bodies
|
||||
HashMap<Massive, Vector3> forceOnBody = new HashMap<>();
|
||||
|
||||
forceOnBody.put(new NamedBody("Oumuamua", 8e6), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Earth", 5.972E24), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Moon", 7.349E22), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Mars", 6.41712E23), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Deimos", 1.8E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Phobos", 1.08E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Mercury", 3.301E23), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Venus", 4.86747E24), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Vesta", 2.5908E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Pallas", 2.14E20), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Hygiea", 8.32E19), new Vector3());
|
||||
forceOnBody.put(new NamedBody("Ceres", 9.394E20), new Vector3());
|
||||
|
||||
Iterator<Massive> iter = forceOnBody.keySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Massive a = iter.next();
|
||||
if (a instanceof NamedBody b) {
|
||||
boolean remove = false;
|
||||
|
||||
try {
|
||||
boolean found = ReadDataUtil.readConfiguration(b, statePath + "/" + b.getName() + ".txt", date);
|
||||
if (!found) {
|
||||
System.err.println("Warning: State not available for " + b.getName() + ".");
|
||||
remove = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (e instanceof StateFileNotFoundException notFound) {
|
||||
System.err.println("Warning: " + notFound.getMessage());
|
||||
} else if (e instanceof StateFileFormatException format) {
|
||||
System.err.println("Warning: " + format.getMessage());
|
||||
} else {
|
||||
System.err.println("Error: " + e.getMessage());
|
||||
System.exit(3);
|
||||
}
|
||||
remove = true;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
System.err.println("Running simulation without " + b.getName());
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add sun after states have been read from files.
|
||||
forceOnBody.put(new NamedBody("Sun", 1.989E30), new Vector3());
|
||||
|
||||
System.out.println("Starting simulation");
|
||||
long seconds = 0;
|
||||
while (true) {
|
||||
seconds++;
|
||||
|
||||
for (Massive b1 : forceOnBody.keySet()) {
|
||||
Vector3 force = new Vector3();
|
||||
for (Massive b2 : forceOnBody.keySet()) {
|
||||
if (b1 != b2) {
|
||||
force = force.plus(b1.gravitationalForce(b2));
|
||||
}
|
||||
}
|
||||
forceOnBody.put(b1, force);
|
||||
}
|
||||
|
||||
for (Massive body : forceOnBody.keySet()) {
|
||||
body.move(forceOnBody.get(body));
|
||||
}
|
||||
|
||||
if ((seconds % 3600) == 0) {
|
||||
cd.clear(Color.BLACK);
|
||||
for (Massive body : forceOnBody.keySet()) {
|
||||
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));
|
||||
}
|
27
src/SolSystem4.java
Normal file
27
src/SolSystem4.java
Normal 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 NamedBody SUN_NAMED = new NamedBody("Sun", SUN);
|
||||
public static final NamedBody EARTH_NAMED = new NamedBody("Earth", EARTH);
|
||||
public static final NamedBody MOON_NAMED = new NamedBody("Moon", MOON);
|
||||
public static final NamedBody MARS_NAMED = new NamedBody("Mars", MARS);
|
||||
public static final NamedBody DEIMOS_NAMED = new NamedBody("Deimos", DEIMOS);
|
||||
public static final NamedBody PHOBOS_NAMED = new NamedBody("Phobos", PHOBOS);
|
||||
public static final NamedBody MERCURY_NAMED = new NamedBody("Mercury", MERCURY);
|
||||
public static final NamedBody VENUS_NAMED = new NamedBody("Venus", VENUS);
|
||||
public static final NamedBody VESTA_NAMED = new NamedBody("Vesta", VESTA);
|
||||
public static final NamedBody PALLAS_NAMED = new NamedBody("Pallas", PALLAS);
|
||||
public static final NamedBody HYGIEA_NAMED = new NamedBody("Hygiea", HYGIEA);
|
||||
public static final NamedBody CERES_NAMED = new NamedBody("Ceres", CERES);
|
||||
}
|
@ -2,17 +2,20 @@ import java.awt.*;
|
||||
|
||||
public class SpaceDraw {
|
||||
|
||||
// Returns the approximate radius of a celestial body with the specified mass.
|
||||
// (It is assumed that the radius r is related to the mass m of the body by r = m ^ 0.5,
|
||||
// where m and r measured in solar units.)
|
||||
/**
|
||||
* Returns the approximate radius of a celestial body with the specified mass.
|
||||
* (It is assumed that the radius r is related to the mass m of the body by r = m ^ 0.5,
|
||||
* where m and r measured in solar units.)
|
||||
*/
|
||||
public static double massToRadius(double mass) {
|
||||
|
||||
return Simulation.SUN_RADIUS * (Math.pow(mass / Simulation.SUN_MASS, 0.5));
|
||||
}
|
||||
|
||||
// Returns the approximate color of a celestial body with the specified mass. The color of
|
||||
// the body corresponds to the temperature of the body, assuming the relation of mass and
|
||||
// temperature of a main sequence star.
|
||||
/**
|
||||
* Returns the approximate color of a celestial body with the specified mass. The color of
|
||||
* the body corresponds to the temperature of the body, assuming the relation of mass and
|
||||
* temperature of a main sequence star.
|
||||
*/
|
||||
public static Color massToColor(double mass) {
|
||||
Color color;
|
||||
if (mass < Simulation.SUN_MASS / 10) {
|
||||
@ -26,9 +29,10 @@ public class SpaceDraw {
|
||||
return color;
|
||||
}
|
||||
|
||||
// Returns the approximate color of temperature 'kelvin'.
|
||||
/**
|
||||
* Returns the approximate color of temperature 'kelvin'.
|
||||
*/
|
||||
private static Color kelvinToColor(int kelvin) {
|
||||
|
||||
double k = kelvin / 100D;
|
||||
double red = k <= 66 ? 255 : 329.698727446 * Math.pow(k - 60, -0.1332047592);
|
||||
double green = k <= 66 ? 99.4708025861 * Math.log(k) - 161.1195681661 : 288.1221695283 * Math.pow(k - 60, -0.0755148492);
|
||||
@ -41,14 +45,19 @@ 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) {
|
||||
|
||||
int kelvinNorm = kelvin - 373;
|
||||
|
||||
if (color < 0 || kelvinNorm < 0) return 0;
|
||||
else if (color > 255) return 255;
|
||||
else if (kelvinNorm < 500) return (int) ((color / 256D) * (kelvinNorm / 500D) * 256);
|
||||
else return (int) color;
|
||||
if (color < 0 || kelvinNorm < 0) {
|
||||
return 0;
|
||||
} else if (color > 255) {
|
||||
return 255;
|
||||
} else if (kelvinNorm < 500) {
|
||||
return (int) ((color / 256D) * (kelvinNorm / 500D) * 256);
|
||||
} else {
|
||||
return (int) color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
src/StateFileFormatException.java
Normal file
20
src/StateFileFormatException.java
Normal file
@ -0,0 +1,20 @@
|
||||
import java.io.IOException;
|
||||
|
||||
public class StateFileFormatException extends IOException {
|
||||
private final String fileName;
|
||||
private final long lineNum;
|
||||
|
||||
public StateFileFormatException(String fileName, long lineNum) {
|
||||
super("File " + fileName + " has illegal format (line " + lineNum + ")");
|
||||
this.fileName = fileName;
|
||||
this.lineNum = lineNum;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return this.fileName;
|
||||
}
|
||||
|
||||
public long getLineNum() {
|
||||
return this.lineNum;
|
||||
}
|
||||
}
|
14
src/StateFileNotFoundException.java
Normal file
14
src/StateFileNotFoundException.java
Normal file
@ -0,0 +1,14 @@
|
||||
import java.io.IOException;
|
||||
|
||||
public class StateFileNotFoundException extends IOException {
|
||||
private final String fileName;
|
||||
|
||||
public StateFileNotFoundException(String fileName) {
|
||||
super("File " + fileName + " not found.");
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return this.fileName;
|
||||
}
|
||||
}
|
115
src/Vector3.java
115
src/Vector3.java
@ -1,8 +1,9 @@
|
||||
import codedraw.CodeDraw;
|
||||
|
||||
// This class represents vectors in a 3D vector space.
|
||||
/**
|
||||
* This class represents vectors in a 3D vector space.
|
||||
*/
|
||||
public class Vector3 {
|
||||
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
@ -21,35 +22,57 @@ public class Vector3 {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
// Returns the sum of this vector and vector 'v'.
|
||||
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'.
|
||||
*/
|
||||
public Vector3 plus(Vector3 v) {
|
||||
Vector3 result = new Vector3();
|
||||
result.x = x + v.x;
|
||||
result.y = y + v.y;
|
||||
result.z = z + v.z;
|
||||
return result;
|
||||
return new Vector3(x + v.x, y + v.y, z + v.z);
|
||||
}
|
||||
|
||||
// Returns the product of this vector and 'd'.
|
||||
public void add(Vector3 v) {
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
this.z += v.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the product of this vector and 'd'.
|
||||
*/
|
||||
public Vector3 times(double d) {
|
||||
Vector3 result = new Vector3();
|
||||
result.x = x * d;
|
||||
result.y = y * d;
|
||||
result.z = z * d;
|
||||
return result;
|
||||
return new Vector3(x * d, y * d, z * d);
|
||||
}
|
||||
|
||||
// Returns the sum of this vector and -1*v.
|
||||
/**
|
||||
* Returns the sum of this vector and -1*v.
|
||||
*/
|
||||
public Vector3 minus(Vector3 v) {
|
||||
Vector3 result = new Vector3();
|
||||
result.x = x - v.x;
|
||||
result.y = y - v.y;
|
||||
result.z = z - v.z;
|
||||
return result;
|
||||
return new Vector3(x - v.x, y - v.y, z - v.z);
|
||||
}
|
||||
|
||||
// Returns the Euclidean distance of this vector
|
||||
// to the specified vector 'v'.
|
||||
public void sub(Vector3 v) {
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.z -= v.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Euclidean distance of this vector
|
||||
* to the specified vector 'v'.
|
||||
*/
|
||||
public double distanceTo(Vector3 v) {
|
||||
double dX = x - v.x;
|
||||
double dY = y - v.y;
|
||||
@ -57,13 +80,17 @@ public class Vector3 {
|
||||
return Math.sqrt(dX * dX + dY * dY + dZ * dZ);
|
||||
}
|
||||
|
||||
// Returns the length (norm) of this vector.
|
||||
/**
|
||||
* Returns the length (norm) of this vector.
|
||||
*/
|
||||
public double length() {
|
||||
return distanceTo(new Vector3());
|
||||
}
|
||||
|
||||
// Normalizes this vector: changes the length of this vector such that it becomes 1.
|
||||
// The direction and orientation of the vector is not affected.
|
||||
/**
|
||||
* Normalizes this vector: changes the length of this vector such that it becomes 1.
|
||||
* The direction and orientation of the vector is not affected.
|
||||
*/
|
||||
public void normalize() {
|
||||
double length = length();
|
||||
x /= length;
|
||||
@ -71,20 +98,38 @@ public class Vector3 {
|
||||
z /= length;
|
||||
}
|
||||
|
||||
// Draws a filled circle with a specified radius centered at the (x,y) coordinates of this vector
|
||||
// in the canvas associated with 'cd'. The z-coordinate is not used.
|
||||
public 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
|
||||
* in the canvas associated with 'cd'. The z-coordinate is not used.
|
||||
*/
|
||||
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;
|
||||
cd.fillCircle(x, y, Math.max(radius, 1.5));
|
||||
radius = cd.getWidth() * radius / Simulation4.SECTION_SIZE;
|
||||
cd.fillCircle(getScreenX(cd), getScreenY(cd), Math.max(radius, 1.5));
|
||||
}
|
||||
|
||||
// Returns the coordinates of this vector in brackets as a string
|
||||
// in the form "[x,y,z]", e.g., "[1.48E11,0.0,0.0]".
|
||||
/**
|
||||
* 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]".
|
||||
*/
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
1
states/Ceres.txt
Normal file
1
states/Ceres.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Deimos.txt
Normal file
1
states/Deimos.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Earth.txt
Normal file
1
states/Earth.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Hygiea.txt
Normal file
1
states/Hygiea.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Mars.txt
Normal file
1
states/Mars.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Mercury.txt
Normal file
1
states/Mercury.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Moon.txt
Normal file
1
states/Moon.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Oumuamua.txt
Normal file
1
states/Oumuamua.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Pallas.txt
Normal file
1
states/Pallas.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Phobos.txt
Normal file
1
states/Phobos.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Venus.txt
Normal file
1
states/Venus.txt
Normal file
File diff suppressed because one or more lines are too long
1
states/Vesta.txt
Normal file
1
states/Vesta.txt
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user