Simulation und Visualisierung eines Vogelschwarms Hausarbeit zum Fach Systemprogrammierung WS 2005 / 2006 Holger Rohde 618928 [email protected] Inhaltsverzeichnis 1 2 3 4 5 Projektbeschreibung ................................................................................................................ 4 1.1 Projektthema.................................................................................................................... 4 1.2 Ziele ................................................................................................................................. 4 Benutzerdokumentation .......................................................................................................... 5 2.1 Übersetzen und Ausführen .............................................................................................. 5 2.2 Simulationssteuerung ...................................................................................................... 5 2.3 Informationsbereich ........................................................................................................ 7 2.4 Animationsansicht ........................................................................................................... 8 Detaildokumentation ............................................................................................................... 8 3.1 Algorithmus ..................................................................................................................... 8 3.2 Parallelisierung .............................................................................................................. 10 3.2.1 Sequentielle Implementierung............................................................................... 11 3.2.2 Parallele Implementierung .................................................................................... 13 3.3 Programmoberfläche ..................................................................................................... 17 3.4 Animation ...................................................................................................................... 19 3.4.1 Licht ...................................................................................................................... 19 3.4.2 Umgebung ............................................................................................................. 20 3.4.3 Vögel ..................................................................................................................... 21 3.4.4 Hindernisvermeidung ............................................................................................ 22 3.5 Leistungsvergleich ........................................................................................................ 23 Fazit ....................................................................................................................................... 27 Anhang .................................................................................................................................. 27 5.1 Quellenverzeichnis ........................................................................................................ 27 5.2 Quellcode ...................................................................................................................... 28 5.2.1 Packet ani .............................................................................................................. 28 5.2.1.1 AbstractFlock.java ............................................................................................ 28 5.2.1.2 AbstractFlockManager.java .............................................................................. 34 5.2.1.3 AniPanel.java .................................................................................................... 37 5.2.1.4 Bird.java ............................................................................................................ 40 5.2.1.5 BirdModel.java .................................................................................................. 45 5.2.1.6 FlockManagerSeq.java ..................................................................................... 47 5.2.1.7 FlockManagerThr.java ..................................................................................... 48 5.2.1.8 FlockSeq.java .................................................................................................... 50 5.2.1.9 FlockThr.java .................................................................................................... 52 5.2.1.10 GlobalLight.java ........................................................................................... 55 5.2.1.11 Obstacle.java ................................................................................................. 56 5.2.1.12 World.java ..................................................................................................... 58 5.2.2 Packet gui .............................................................................................................. 61 5.2.2.1 ControlPanel.java ............................................................................................. 61 5.2.2.2 InfoPanel.java ................................................................................................... 70 5.2.2.3 MainFrame.java ................................................................................................ 72 5.2.3 Packet i18n ............................................................................................................ 77 5.2.3.1 Messages.java ................................................................................................... 77 5.2.3.2 MessagesBundle_en_US.properties .................................................................. 79 5.2.3.3 MessagesBundle.properties............................................................................... 80 5.2.4 Packet util .............................................................................................................. 81 5.2.4.1 AppSetup.java .................................................................................................... 81 5.2.4.2 BirdList.java ...................................................................................................... 83 5.2.4.3 ExtScrollBar,java .............................................................................................. 84 5.2.4.4 FlockList.java .................................................................................................... 87 5.2.4.5 ParameterSet.java ............................................................................................. 88 5.2.4.6 Timer.java ......................................................................................................... 94 5.2.5 Skripte zum Übersetzen und Ausführen................................................................ 96 5.2.5.1 benchmark.bat ................................................................................................... 96 5.2.5.2 benchmark.sh..................................................................................................... 97 5.2.5.3 compile.bat ........................................................................................................ 97 5.2.5.4 compile.sh .......................................................................................................... 97 5.2.5.5 run.bat ............................................................................................................... 98 5.2.5.6 run.sh ................................................................................................................. 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 4 von 98 1 Projektbeschreibung 1.1 Projektthema Als Thema für diese Hausarbeit wurde die Simulation des Schwarmverhaltens von Vögeln gewählt. Als Basis für diese Simulation diente ein von Craig Reynolds 1987 veröffentlichtes Model zur Erzeugung von Schwarmverhalten [1], [2]. Dieses beschreibt Methoden zur realitätsnahen Simulation des Verhaltens verschiedener Tierarten in Schwärmen und wurde mittlerweile in zahlreichen Ausarbeitungen behandelt. Auch bei der Produktion bekannter Filme wurde es bereits eingesetzt. So zum Beispiel im Film Batman Returns von 1992 zur Animation von Fledermaus- und Pinguinschwärmen1. 1.2 Ziele Neben der Erläuterung und Implementierung des Verfahrens zur Simulation des für Vögel und andere Tierarten typischen Schwarmverhaltens, war es Ziel dieser Projektarbeit die Parallelisierbarkeit des zum Einsatz kommenden Algorithmus zu Betrachten. Bei entsprechenden Ergebnissen dieser Betrachtung sollte eine parallele Variante umgesetzt werden und diese mit der zuvor erstellten sequentiellen Variante auf verschiedenen Rechnern bezüglich der Leistung verglichen werden. Da eine Simulation in diesem Bereich ohne eine entsprechende Visualisierung wenig sinnvoll ist, war die Animation des Schwarmverhaltens mittels Java3D eins der weiteren Ziele. Darüber hinaus wurden weitere optionale Ziel definiert. Dies waren die Integration von zu umfliegenden Hindernissen sowie die Verbesserung der Visualisierung im Bereich der Vogel- und Umgebungsdarstellung. Ein weiteres optionales Ziel war die Steuerung der Simulationsparameter. Hier stellte sich jedoch schnell heraus, dass ohne dieses Merkmal ein sinnvoller Leistungsvergleich nicht möglich sein würde, weshalb dieser Punkt zu einem festen Teil der Arbeit wurde. 1 Information entnommen aus [2] Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 5 von 98 2 Benutzerdokumentation 2.1 Übersetzen und Ausführen Das Programm benötigt eine installierte Java-Laufzeitumgebung2 der Firma Sun in der Version 1.4 oder höher. Andere Versionen sollten prinzipiell Funktionieren wurden jedoch nicht getestet. Zusätzlich wird eine installierte Version der Java3D-Bibliothek3 für die Animation benötigt. Entwickelt und getestet wurde die Anwendung mit Version 1.3.2. Andere Versionen sollten jedoch auch hier funktionieren. Um das Übersetzen und Ausführen des Quellcode zu erleichtern werden entsprechende Skripte4 für Windows und Unix bereitgestellt. Falls andere Argumente an das Programm übergeben werden sollen, können diese entsprechend angepasst werden. Informationen hierzu sind in den einzelnen Skripten enthalten. Die beim Programmstart möglichen Optionen werden später auch noch genauer erläutert. 2.2 Simulationssteuerung Die Steuerung des entwickelten Programms kann auf zwei verschiedenen Ebenen erfolgen. Die Programmoberfläche ermöglicht die Variation der für die Simulation relevanten Faktoren über Schieberegler und einige die Animation betreffende Einstellungen über ein Menü (Abb. 2). Zusätzlich können der Anwendung beim Start eine Reihe von Argumenten übergeben werden. Die in der Programmoberfläche zur Verfügung stehenden Schieberegler sind in vier Gruppen gegliedert, die jeweils eine Schaltfläche zum Zurücksetzen auf die im Programm vorgegebenen Standardwerte bieten. Die ersten drei Gruppen beziehen sich auf die Parameter des Algorithmus und sind jeweils nochmals nach den für den Algorithmus relevanten Kräften „Zusammenhalt“, „Vermeidung“ und „Ausrichtung“ unterteilt. Die letzte Gruppe beinhaltet die Regler für die maximale Geschwindigkeit, die maximale Kraft und die Anzahl der Vögel. Mit den in der ersten Gruppe enthaltenen Schiebereglern kann der Sichtwinkel des Vogels beeinflusst werden (Abb. 2a). Dieser kann für alle Kräfte zwischen einem und hundertachtzig Grad liegen, wobei letzteres dazu führt, dass der Vogel einen Rundumblick besitzt. Der tatsächliche Sichtwinkel ist also doppelt so hoch wie die Einstellung für den Algorithmus. Die zweite Gruppe steuert die maximale Distanz die Vögel besitzen dürfen um sich gegenseitig als Nachbarn zu betrachten (Abb. 2b). Mit der dritten Schiebereglergruppe kann die Gewichtung der einzelnen Kräfte variiert werden (Abb. 2.1c). Sollen die Vögel also zum Beispiel einen größeren 2 http://w ww.java.com/ https://java3d.dev.java.net/binary-builds.html 4 compile.bat, compile.sh, run.bat und run.sh im Projektverzeichnis 3 Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 6 von 98 Abstand einhalten, könnte der Regler für die „Vermeidung“ höher und der Regler für den „Zusammenhalt“ niedriger eingestellt werden. Die letzte Gruppe ermöglicht die Steuerung verschiedener Parameter (Abb. 2.1d). Der erste Regler legt die maximale Kraft fest die auf den Vogel wirken darf. Die Kraft beeinflusst den Vogel bezüglich seiner Beweglichkeit. Er würde es bei einer sehr niedrigen Kraft zum Beispiel nicht schaffen seine Richtung vor dem erreichen der Begrenzung schnell genug zu ändern was zur Folge hätte das er die Welt kurzzeitig verläst. Der zweite Regler dieser Gruppe steuert die maximale Geschwindigkeit des Vogels. Geschwindigkeit und Kraft sollten immer in einem entsprechenden Verhältnis stehen. Eine hohe Geschwindigkeit erfordert auch eine höhere Kraft und umgekehrt. Mit dem letzen Regler kann die Anzahl der Vögel gesteuert werden. Jeder Schwarm der Simulation besitzt immer die gleiche Anzahl an Vögeln die dem Wert des Reglers entspricht. Eine weitere Möglichkeit Einfluss auf die Animation zu nehmen bietet das Menü des Programms (Abb. 2e). Neben dem Beenden bietet es drei weitere Einstellungsmöglichkeiten. Mittels des ersten Punkts (Vogel Begrenzung), kann der das Vogelmodell umgebende Würfel ein- und ausgeschaltet werden. Dieser dient der Visualisierung eines imaginären Felds das den Vogel umgibt und diesen beim Auftreffen auf ein Hindernis informiert. Dies wird durch das rote (Weltbegrenzung) bzw. gelbe (Hindernisse) Aufleuchten der Box dargestellt. Der zweite Punkt ermöglicht das Ein- und Ausschalten der Weltbegrenzungen. Diese sind zwar weiter vorhanden und hindern den Vogel am davon fliegen, werden aber nicht mehr durch den Quader dargestellt. Der letzte Menüpunkt ermöglicht das Einund Ausschalten der durch die Säulen dargestellten Hindernisse. Anders als bei der Weltbegrenzung wird mit dieser Option auch das Umfliegen der Hindernisse an sich ausgeschaltet. Zusätzlich zu den Reglern, Schaltflächen und Menüs können Einstellungen des Programms über Argumente beim Programmstart (am einfachsten durch Abändern der zur Verfügung gestellten Startskripte) vorgenommen werden. Folgende Parameter stehen zur Verfügung: -d: Einschalten von Statusausgaben auf der Konsole -b: Anzahl der Vögel pro Schwarm / Anzahl muss ohne Leerzeichen an den Parameter angehängt werden -t: Testmodus zur Leistungsmessung aktivieren -p: Parallele Berechnung der Simulationsdaten / es wird ein Thread pro Schwarm genutzt -f: Anzahl der Vogelschwärme / Anzahl muss ohne Leerzeichen an den Parameter angehängt werden Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 7 von 98 Abbildung 2.1: Die Programmoberfläche 2.3 Informationsbereich Unterhalb des Menüs der Anwendung befindet sich der Informationsbereich der Simulation. Hier werden die aktuellen Messwerte des Algorithmus angezeigt. Es können die folgenden, den Algorithmus betreffenden, Werte abgelesen werden: Rechenzeit der aktuellen Iteration in Millisekunden Durchschnittszeit aller Iterationen in Millisekunden Gesamtrechenzeit in Millisekunden Anzahl der durchlaufenen Iterationen Die Informationen werden alle 5 Iterationen aktualisiert. Holger Rohde WS 2005/2006 Seite 8 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 2.4 Animationsansicht Um einen besseren Überblick über die Animation zu ermöglichen, kann die komplette Welt mit der linken Maustaste gedreht werden. 3 Detaildokumentation Hinweis: Die in diesem Kapitel enthalten Klassendiagramme sollen einen Überblick über die jeweiligen Zusammenhänge bieten. Um dies zu erleichtern wurden alle für das Verständnis nicht relevanten Attribute, Methoden und Assoziationen ausgeblendet! 3.1 Algorithmus Wie bereits in der Projektbeschreibung angesprochen, basiert der in dieser Arbeit verwendete Algorithmus auf dem von Craig Reynolds 1987 veröffentlichten Model zur Simulation von Schwarmverhalten. Dieses sieht eine einzelne Betrachtung aller Vögel eines Schwarms und nicht des Schwarms als Ganzes vor. Um das typische Verhalten nachzuahmen werden für jeden Vogel Regeln definiert die dieser für die Vögel in seiner direkten Umgebung zu beachten hat. So versucht der Vogel einerseits in der Nähe der anderen Vögel zu bleiben, gleichzeitig achtet er aber darauf nicht mit diesen zusammen zu stoßen. Des Weiteren versucht der Vogel sich der Flugrichtung seiner Nachbarn anzupassen. Um dieses Verhalten der Vögel zu erreichen, müssen für jeden Vogel drei Kräfte berechnet werden. Diese von Reynolds mit „cohesion“, „alignment“, und „seperation“ bezeichneten Kräfte (in der deutschen Version des Programms „Zusammenhalt“, „Ausrichtung“ und „Vermeidung“) sollen nun anhand eines Vogels und seiner Nachbarn erläutert werden. Die Kraft „cohesion“ sorgt für den Zusammenhalt des Vogelschwarms. Sie zieht den Vogel zur mittleren Position seiner Nachbarn (Abb. 3.1a). Die Kraft „seperation“ verhindert ein Kollidieren der Vögel. Zu diesem Zweck wird eine von den anderen Vögeln wegführende Kraft bestimmt und addiert (Abb. 3.1b). Die Kraft „alignment“ schließlich sorgt davor, dass der Vogel sich der Flugrichtung seiner Nachbarn anpasst. Zu diesem Zweck wird die mittlere Richtung der anderen Vögel bestimmt und auf die Richtung des Vogels addiert (Abb. 3.1c). Holger Rohde WS 2005/2006 Seite 9 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. (a) cohesion (b) seperation (c) alignment Abbildung 3.1: Kräfte durch die der Vogel beeinflusst wird Da jeder Vogel nur auf seine Nachbarn reagieren soll, benötigt man noch eine Methode um diese zu bestimmen. Nach Reynolds ist ein Vogel genau dann ein Nachbar wenn er nicht weiter als eine vorgegebene Distanz entfernt ist und zusätzlich in einem durch einen Winkel begrenzten Bereich liegt (Abb. 3.2). Dieser Winkel definiert das Sichtfeld des Vogels ausgehend von seiner aktuellen Flugrichtung. Distanz Winkel Winkel Abbildung 3.2: Sichtbereich des Vogels Jede Iteration des Algorithmus erfordert also für jeden Vogel eine Überprüfung welche Vögel sich in seinem Umfeld befinden. Für jeden Nachbarvogel werden dann die oben beschriebenen Kräfte berechnet und auf den Vogel angewendet. Die konkreten Berechnungen der einzelnen Kräfte und die Bestimmung der Nachbarn wurden anhand des oben beschrieben Models und zweier Ausarbeitungen zum Thema von Andrew Davison und Olaf Schnapauff entwickelt [3], [4]. Diese befinden sich im Quelltext in den Methoden seperation(), cohesion() und alignment() der Klasse AbstractFlock sowie in isNeighbor() der Klasse Bird. Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 10 von 98 3.2 Parallelisierung 5 wird mit steigender Vogelzahl eine erhebliche Aufgrund der Komplexität von O n 2 Rechenzeit benötigt. Deshalb erschien es als durchaus sinnvoll über eine parallele Variante des Algorithmus nachzudenken. Betrachtet wurden nur Lösungen die auf Threads basieren. Um das Problem parallel berechnen zu können muss zuerst geklärt werden, ob die Aufgabe in Teilaufgaben zerlegt werden kann. Dies scheint auf den ersten Blick kein Problem darzustellen, da für jeden Vogel eine separate Berechnung durchzuführen ist. Hierbei muss man jedoch beachten, dass für jede Berechnung eines Vogels, die Daten der anderen Vögel nötig sind. Dieses Problem kann jedoch durch eine einfache Anpassung des Ablaufs gelöst werden. Der Algorithmus wird dazu in zwei Teile zerlegt. Im ersten Schritt werden für jeden Vogel die entsprechenden Kräfte bestimmt und zwischengespeichert. Erst nach Beendigung der Berechung werden diese Kräfte dann auf die Vögel angewendet. Dadurch können die im ersten Schritt anfallenden Berechnungen parallel ablaufen ohne sich gegenseitig zu beeinflussen. Nachdem klar ist, dass die Aufgabe aufteilbar ist, gilt es noch die Frage zu klären wie die Zerlegung in Teilaufgaben erfolgen kann. Ein möglicher Ansatz ist die Verwendung eines Threads pro Vogel. Die dadurch entstehende große Anzahl an Threads würde das Programm aber durch die für die Erstellung und den Wechsel zwischen den einzelnen Threads benötigte Zeit unnötig verlangsamen. Es ist daher sinnvoller die Vögel auf eine bestimmte Anzahl von Threads aufzuteilen. So könnten zum Beispiel für n Vögel m Threads erstellt werden, wobei jeder Thread im Durchschnitt n Vögel berechnet. Die Vögel könnte man dann entweder jeweils vor m Beginn der Berechnung komplett auf die zur Verfügung stehenden Threads aufteilen, oder nacheinander an jeweils rechenwillige Threads übergeben. In diesem Fall würde das Hauptprogramm die Vögel anhand einer bestimmten Strategie aufteilen, im einfachsten Fall immer eine konstante Anzahl. Ein anderer Ansatz ist es, die Vögel von vornherein in gleich große Gruppen einzuteilen die unabhängig voneinander sind. Man würde also aus einem Vogelschwarm mehrere unabhängige Vogelschwärme machen. Dies hätte zwar zur Folge, dass sich die einzelnen Schwärme untereinander nicht beachten, würde die Komplexität des 5 n := Anzahl Vögel Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 11 von 98 n 26 verringern. In diesem Fall könnte man pro Algorithmus aber auch von O n 2 auf O m Schwarm einfach einen Thread verwenden und die Aufteilung der Vögel einsparen. Unabhängig von der für die Aufteilung der Aufgabe verwendeten Strategie sollten die Threads für die gesamte Laufzeit des Programms existieren, da das ständige Erzeugen von neuen Threads zu aufwendig wäre. Dies macht es für jede der Varianten erforderlich, eine Steuerung zu realisieren, die es dem Hauptprogramm ermöglicht die Berechnung innerhalb des Threads zu starten. Der Thread muss wiederum das Hauptprogramm informieren wenn er mit der Berechnung fertig ist. In der Programmiersprache Java bietet sich hierfür die Verwendung der Methoden wait() und notify() aus der Klasse Object an. Anmerkung: Weitere sehr interessant erscheinende Ansätze sind die Java-Implementierungen des Message Passing Interface (MPI)7 bzw. der Parallel Virtual Machine (PVM)8. Diese konnten in der zur Verfügung stehenden Zeit aber leider nicht weiter verfolgt werden. 3.2.1 Sequentielle Implementierung Die sequentielle Variante des Algorithmus wurde in den Klassen FlockManagerSeq, FlockSeq und Bird umgesetzt. Die Klassen FlockManagerSeq und FlockSeq sind Erweiterungen der Klassen AbstractFlockManager und AbstractFlock. Diese beiden abstrakten Klassen bilden die Schnittmenge der sequentiellen und parallelen Variante. Zur Vereinfachung wurden die Klassen BirdList und FlockList erstellt. Diese ermöglichen die Ablage der Vogel und Schwarmobjekte und erweitern die Klasse ArrayList um Methoden zum Abrufen dieser Objekte ohne Typumwandlung von Object (Rückgabetyp der Methode get() aus ArrayList) zu Bird oder FlockSeq bzw. FlockThr. Der umgesetzte Algorithmus hat vereinfacht folgenden Aufbau: 6 n := Anzahl Vögel, m := Anzahl Schwärme http://www.hpjava.org/mpiJava.html 8 http://www.cs.virginia.edu/~ajf2j/jpvm.html 7 Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 12 von 98 FOR each flock FOR each bird in flock COMPUTE forces STORE forces END FOR FOR each bird in flock UPDATE bird END FOR END FOR Wie im Pseudocode abzulesen ist, wurde auch bei der sequentiellen Implementierung die Aufteilung des Algorithmus in zwei Teile übernommen. Dadurch sind die beiden Varianten besser vergleichbar und die Implementierung wurde vereinfacht. Angestoßen wird der dargestellte Ablauf in der Klasse FlockManagerSeq. Zu diesem Zweck erweitert diese die Klasse Behavior der Java3D-Biliothek. Diese Vorgehensweise wurde in Anlehnung an eine Umsetzung des Modells von Andrew Davison angewendet [3]. Behavior ermöglicht es auf bestimmte Ereignisse im Ablauf der Animation zu reagieren und diese dadurch zu beeinflussen. Klassen die Behavior erweitern müssen die Methoden initialize() und processStimulus() überschreiben. Die Methode initialize() legt das erste Ereignis fest über das die Anwendung informiert wird. Im Falle der Klasse FlockManagerSeq ist dies der Ablauf einer in der Anwendung festgelegten Zeit. Ist diese Zeit verstrichen, wird die Methode processStimulus() automatisch aufgerufen. Hier können nun Veränderungen an der Animation vorgenommen werden die anschließend dargestellt werden. Bei der entwickelten Anwendung ist dies der oben dargestellte Algorithmus zur Berechnung der Vogelbewegung. Damit dieser Ablauf nicht schon nach dem ersten Ereignis unterbrochen wird, wird in der Methode processStimulus() immer wieder das nächste Ereignis festgelegt welches den Aufruf zur Folge haben soll. Dies ist hier die Darstellung eines Bildes der Animation. Die Simulationsdaten werden also nach jedem dargestellten Bild aktualisiert. Bevor dies jedoch alles beginnt werden im Konstuktor der Klasse die einzelnen Vogelschwärme erstellt und in einer Liste vom Typ FlockList abgelegt. Diese erzeugen wiederum die benötigte Anzahl an Vögeln als Objekte vom Typ Bird die ebenfalls in einer Liste vom Typ BirdList gespeichert werden. Jedes Mal wenn nun die Methode processStimulus() durchlaufen wird werden, wie im Pseudocode dargestellt, alle Schwärme zur Aktualisierung ihrer Vögel aufgefordert. Dies geschieht durch den Aufruf der Methode updateFlock(). Diese berechnet für jeden einzelnen Vogel die nötigen Kräfte und speichert das Ergebnis als Vektor im Vogel. Die Überprüfung ob ein Vogel ein Nachbar ist wird beim Berechnen der Kräfte durch den Aufruf der Methode isNeighbor() der Klasse Bird Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 13 von 98 durchgeführt. Die Kräfte selbst werden durch die Methoden seperation(), cohesion() und alignment() in der Klasse FlockSeq bestimmt. Wurden alle Berechnungen beendet, folgt die Aktualisierung der Position, Richtung und Geschwindigkeit der Vögel durch den Aufruf der Methode update(). Mit diesem Schritt endet der Durchlauf des Algorithmus. Auf Basis der aktualisierten Daten wird nun ein neues Bild gezeichnet und der Ablauf beginnt von vorn. Einen Überblick über die am sequentiellen Ablauf beteiligten Klassen und deren für den Algorithmus relevante Methoden und Attribute bietet das folgende Klassendiagramm (Abb. 3.3). Abbildung 3.3: Klassen der sequentiellen Implementierung 3.2.2 Parallele Implementierung Da für die sequentielle Implementierung bereits eine Aufteilung der Vögel in mehrere Schwärme durchgeführt wurde, bot es sich an für die Parallelisierung jeweils einen Thread pro Schwarm einzusetzen. Dies erforderte nur geringfügige Änderungen am bestehenden Quellcode. Es wurden die beiden Klassen FlockManagerThr und FlockThr erstellt und Anpassungen in den Klassen AniPanel, AppSetup, FlockList und MainFrame vorgenommen. Diese sind jedoch für das Verständnis der parallelen Implementierung nicht wichtig und werden deshalb hier nicht besprochen. Falls erforderlich können die Anpassungen im Quellcode nachvollzogen werden. Die eigentliche Erzeugung der Parallelität geschieht in den beiden neuen Klassen FlockManagerThr und FlockThr. Die Klasse FlockThr implementiert die Schnittstelle Runnable Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 14 von 98 und ermöglicht dadurch die Ausführung des Schwarms als eigenständigen Thread. Eine Erweiterung der Klasse Thread war nicht möglich, da die Klasse FlockThr bereits AbstractFlock erweitert und Java die Mehrfachvererbung nicht unterstützt. Der so erzeugte Thread führt folgenden Ablauf aus: WHILE true FOR each bird in flock COMPUTE forces STORE forces END FOR FOR each bird in flock UPDATE bird END FOR SIGNAL flockManager WAIT END WHILE Die Berechnung erfolgt analog zur sequentiellen Implementierung. Neu sind lediglich die äußere Endlosschleife und die Verwendung der Methoden signal() und wait(). Die Klasse FlockManagerThr überschreibt genau wie die sequentielle Variante die Methode processStimulus(). Diese führt folgenden Ablauf aus: FOR each flock SIGNAL flock END FOR FOR each flock WAIT END FOR Die Methode wait() stammt aus der Klasse Object und bewirkt, dass der aufrufende Thread solange blockiert wird, bis die Methode notify() oder notifyAll() des Objekts aufgerufen wird. Sie wird hier benutzt um einerseits den durch die Klasse FlockThr erzeugten Thread solange zu blockieren bis eine Berechnung durchgeführt werden soll und um in der Klasse Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 15 von 98 FlockManagerThr auf das Ende aller Berechnungen zu warten. Da die Methode notify() nicht von einem anderen Thread aus direkt aufgerufen werden kann wurde der Aufruf durch die öffentliche Methode signal() beider Klassen gekapselt. Im Folgenden der entsprechende Auszug aus der Klasse FlockManagerThr: public synchronized void processStimulus (Enumeration arg0) { … /* Berechnung fuer jeden Schwarm starten for (int i = 0; i < flocks.size (); i++) { ((FlockThr) flocks.get (i)).signal (); }; /* Warten bis alle Schwaerme mit der Berechnung fertig sind try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); }; … } public synchronized void signal () { sigCount++; /* Warten bis alle Threads mit der Berechnung fertig sind if (sigCount == AppSetup.flock_count) { sigCount = 0; this.notify (); }; } Holger Rohde */ */ */ WS 2005/2006 Seite 16 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Der zugehörige Ablauf aus der Klasse FlockThr: public synchronized void run () { while (true) { Bird b = null; /* Thread nicht beenden */ for (int i = 0; i < birds.size (); i++) { … /* Kraefte berechnen und zwischenspeichern */ b.addForce (seperation (b)); b.addForce (cohesion (b)); b.addForce (alignment (b)); … }; /* Vogeldaten anhand der berechneten Kräfte aktualisieren */ for (int i = 0; i < birds.size (); i++) { b = birds.getBird (i); b.update (parameter); }; manager.signal (); /* Ende der Berechnung melden */ /* Warten bis zum naechsten Durchlauf */ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); }; } } public synchronized void signal () { this.notify (); } Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 17 von 98 Der Aufbau der parallelen Variante ist in folgendem Klassendiagramm verdeutlicht (Abb. 3.4). Abbildung 3.4: Klassen der parallelen Implementierung (Nur die Klassen FlockManagerThr und FlockThr sind hier neu) 3.3 Programmoberfläche Zur Steuerung der Simulation und als Container für die Animation wurde eine einfache SwingOberfläche entwickelt. Zentraler Punkt dieser Oberfläche ist die Klasse MainFrame. Diese enthält nicht nur alle anderen Komponenten sondern auch die Methode main() und ist somit Startpunkt der Anwendung. Erzeugt wird je eine Instanz der Klassen AniPanel, ControlPanel, InfoPanel, FrameMenu und Messages. Die Klassen AniPanel, ControlPanel und InfoPanel enthalten die einzelnen Komponenten des Hauptfensters. Die innere Klasse FrameMenu Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 18 von 98 realisiert das Menü der Anwendung über das einige bereits in der Benutzerdokumentation besprochene Einstellungen vorgenommen werden können. Eine gesonderte Rolle nimmt die Klasse Messages ein. Über diese wurde die Internationalisierung der Anwendung realisiert. Alle Beschriftungen und Namen der Anwendung werden aus separaten Dateien anhand eines Schlüssels ausgelesen. Dabei wird immer automatisch die zum aktuellen Standort passende Internationalisierungsdatei gewählt. Im Umfang der Anwendung ist eine solche Datei für die Sprachen Deutsch und Englisch enthalten. Bei Bedarf kann der Standort und damit auch die Sprache in der Klasse AppSetup geändert werden. Die Klasse ControlPanel enthält die in der Benutzerdokumentation angesprochnen Schieberegler zur Steuerung der Simulationsparameter. Die an deren Erzeugung beteiligten Klassen wurden in einem Diagramm zusammengefasst (Abb. 3.6). Die Darstellung der Messwerte des Algorithmus wird in der Klasse InfoPanel durchgeführt. Sie enthält lediglich einige Felder zur Ausgabe der Werte und eine Methode um diese zu aktualisieren (Abb. 3.8). Die letzte Klasse am Aufbau der Oberfläche beteiligte Klasse ist AniPanel. Dort wird die Animation des Schwarmverhaltens aufgebaut und in einen Container verpackt. Der Gesamtaufbau der Oberfläche wurde zur Verdeutlichung wieder in einem Klassendiagramm dargestellt (Abb. 3.5). Abbildung 3.5: Klassen für die Programmoberfläche Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 19 von 98 Abbildung 3.6: Klassen der unteren Steuerelemente 3.4 Animation Die Zentrale Klasse der Java3D-Animation ist AniPanel. Dort werden die einzelnen für den Aufbau und Ablauf der Animation benötigten Komponenten erzeugt und zu einem Szenengraph zusammengesetzt. Diese sind in Abbildung 3.7 dargestellt. Als Quelle für die benötigten Kenntnisse diente ein Tutorial von Sun [5] und ein weiteres Tutorial von Christopher Schnell und Sascha Strasser [6]. 3.4.1 Licht Die Lichtquellen der Anwendung wurden in der Klasse GlobalLight platziert. Aufgrund der einfachen Darstellung des Schwarmverhaltens beschränkt sich das Licht auf eine Quelle für ambientes Licht und eine weitere Quelle für direktionales Licht. Diese werden ohne weitere Anpassungen über den Standard-Konstruktor erzeugt. Lediglich der Einflussbereich des Lichts wurde so weit ausgedehnt das dieses die komplette Welt beeinflusst. Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 20 von 98 import javax.media.j3d.AmbientLight; import javax.media.j3d.BoundingBox; import javax.media.j3d.DirectionalLight; … DirectionalLight directional = new DirectionalLight (); AmbientLight ambient = new AmbientLight (); BoundingBox bounds = new BoundingBox (); /* Licht wirkt auf jedes Objekt in diesem Bereich bounds.setLower (-10.0 ,-10.0, -10.0); bounds.setUpper (10.0 , 10.0, 10.0); */ directional.setInfluencingBounds (bounds); ambient.setInfluencingBounds (bounds); … Da in Java3D nur Objekte mit einen festgelegtem Oberflächenmaterial auf Lichtquellen reagieren, beeinflusst das verwendete Licht nur das Escheinungsbild der Vögel. Alle anderen Objekte besitze eine festgelegte Farbe. 3.4.2 Umgebung Die Umgebung in der sich die Vögel befinden, wird in der Klasse World erzeugt. Sie besteht aus einem Boden der durch einen Quader dargestellt wird und den Begrenzungen der Welt. Diese werden ebenfalls durch einen Quader dargestellt, dessen Polygone aber nur als Linien zu sehen sind. Zusätzlich zur Visualisierung der Grenzen besitzt die Welt eine Instanz der Java3D-Klasse BoundingBox. Dieses in der Animation nicht sichtbare Objekt besitzt die gleiche Größe wie der zur Darstellung der Grenzen verwendete Quader und bietet über die Methode intersect() die Möglichkeit eine Überschneidung des Objekts mit anderen Objekten vom Typ BoundingBox oder BoundingSphere zu erkennen. Es wird dadurch möglich festzustellen ob sich die Vögel innerhalb der Welt befinden oder im Begriff sind davon zu fliegen. Die Vögel haben eine Instanz der Klasse BoundingSphere. Diese Kugel umgibt jeden Vogel und ist ebenfalls nicht sichtbar. In den Klassen FlockSeq und FlockThr wird zu Beginn jeder Iteration des Algorithmus geprüft ob sich der Vogel außerhalb der Welt befindet. Ist dies der Fall werden nicht die für das Schwarmverhalten erforderlichen Kräfte berechnet, sondern eine Kraft bestimmt die den Vogel zurück in die Welt zwingt. Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 21 von 98 Hier der entsprechende Auszug aus der Klasse FlockSeq: public void updateFlock () { Bird b = null; for (int i = 0; i < birds.size (); i++) { b = birds.getBird (i); /* * der Vogel muss umkehren wenn er die Begrenzung der Welt * erreicht hat */ if (!b.getBs ().intersect (world.getBs ())) { Vector3f turn = new Vector3f (-b.getPosition ().x, -b.getPosition ().y, -b.getPosition ().z); b.addForce (turn); … } else { /* Kraefte berechnen und zwischenspeichern … }; */ }; … } 3.4.3 Vögel Die Darstellung der Vögel wird in den Klassen Bird und BirdModel realisiert. Die Klasse Bird enthält neben den für die Simulation benötigten Methoden und Variablen eine Instanz der Klasse BoundingSphere, die wie bereits im Zusammenhang mit der Umgebung erklärt dazu verwendet wird, den Vogel innerhalb der Welt fest zu halten. Analog zur Welt besitzt auch der Vogel einen Quader der dessen Grenzen visualisiert. Über diesen Quader wird auch angezeigt ob ein Vogel gerade von den Grenzen der Welt zurückgeworfen wird (Quader ist rot), einem Hindernis ausweicht (Quader ist gelb) oder normal innerhalb der Welt fliegt (Quader ist weiß). Die eigentliche Darstellung des Vogels enthält die Klasse BirdModel. in Form eines um 90 Grad gedrehten Kegels. Durch diese Trennung der Darstellung und der eigentlichen Eigenschaften sollte es möglich werden, das Modell des Vogels jederzeit unkompliziert austauschen zu können. Auch die Verwendung verschiedener Modelle für zum Beispiel verschiedene Vogelarten war angedacht. Da eine Erweiterung der Darstellung im Rahmen des Projekts aber nicht mehr möglich war, kam es nicht dazu. Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 22 von 98 3.4.4 Hindernisvermeidung Als Hindernisse wurden drei Zylinder in der Welt platziert. Die Klasse Obstacle realisiert jeweils einen solchen Zylinder. Das Umfliegen basiert auf dem gleichen Konzept durch das die Vögel in der Welt gehalten werden. Jedes Hindernis besitzt eine Instanz der Klasse BoundingBox. Dieser Quader umgibt den Zylinder wobei er etwas breiter und tiefer als der Zylinder selbst ist. Dies soll den Vögeln etwas Zeit verschaffen um ein Ausweichmanöver durchzuführen bevor sie auf den Zylinder auftreffen. Die Kollisionsüberprüfung wird für die Hindernisse ebenfalls in den Klassen FlockSeq und FlockThr durchgeführt. Genauso wie bei den Weltgrenzen wird hier bei Überschneidung der Grenzen des Vogels mit denen eines Hindernis eine Kraft bestimmt die denn Vogel vom Hindernis wegführen soll. Dies funktioniert in der aktuellen Version der Anwendung aber leider nicht in jedem Fall. Unter bestimmten Umständen fliegen die Vögel durch die Hindernisse hindurch. Für eine weitere Betrachtung dieses Problems stand keine Zeit mehr zur Verfügung. Abbildung 3.7: Struktur der Animation Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 23 von 98 3.5 Leistungsvergleich Da eine Implementierung verschiedener Varianten eines Algorithmus ohne einen entsprechenden Vergleich wenig Sinn macht, wurde in das Programm eine Leistungsmessung integriert. Diese ermöglicht die Bestimmung der Rechenzeit des Algorithmus und somit den Vergleich der sequentiellen und parallelen Variante. Die Leistungsmessung wurde auf Basis der freien Bibliothek JAMon9 realisiert. Diese ist zwar eigentlich für den Einsatz im J2EE-Umfeld gedacht, eignet sich aber auch gut für Zeitmessungen in anderen Anwendungen. Lediglich die von der Bibliothek gelieferten Ergebnisse mussten an die Anforderungen des Programms angepasst werde. Zu diesem Zweck wurde die Klasse Timer erstellt, die den Zugriff auf die Daten und Methoden der Bibliothek kapselt. Da die Ergebnisse der Zeitmessung nur als eine Zeichenkette zur Verfügung stehen war es notwendig diese zu zerlegen. Zu diesem Zweck wurde die private Methode getTokens() implementiert, die bei jedem Aufruf der Methode stop() die erforderlichen Daten aus der Zeichenkette extrahiert und die Variablen der Klasse aktualisiert. Die dadurch auftretende Leistungsminderung des Programms wurde in Kauf genommen, da es nicht Ziel der Arbeit war eine besonders effiziente Simulation zu entwickeln. In diesem Fall hätte die Zeitmessung anders realisiert werden müssen. Die eigentliche Messung erfolgt in den Klassen FlockManagerSeq und FlockManagerThr. Diese nutzen eine Instanz der Klasse Timer und starten die Messung jeweils vor Beginn der Berechnung durch den Aufruf der Methode start() und stoppen sie nach dem Beenden durch den Aufruf der Methode stop() des Timer-Objekts. Nach dem Stoppen der Messung sorgen diese Klassen auch für die Aktualisierung der Messwerte in der Programmoberfläche. Befindet sich das Programm im Testmodus werden die Ergebnisse nach dem Durchlaufen aller Iterationen durch die Methode print() des Timer-Objekts auf der Konsole ausgegeben und das Programm wird beendet. 9 http://jamonapi.com/ Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 24 von 98 In der Klasse FlockManagerSeq sieht dies folgendermaßen aus: public void processStimulus (Enumeration arg0) { timer.start (); /* Zeitmessung starten /* Berechnung fuer alle Schwaerme durchfuehren … timer.stop (); /* Zeitmessung stoppen info.updateTime (timer); /* Infopanel aktualisieren /* Im Testmodus die Iterationen zaehlen if (AppSetup.benchmark == true) { iterations++; }; /* Im Testmodus nach der eingestellten Anzahl Iterationen beenden if (iterations < AppSetup.BENCH_ITERATIONS) { … } else { timer.print (); /* Messergebnisse ausgeben System.exit (0); }; */ */ */ */ */ */ */ Zur Verdeutlichung der Zusammenhänge wurden die an der Leistungsmessung beteiligten Klassen und ihre Beziehungen in einem Diagramm zusammengefasst (Abb. 3.8). Abbildung 3.8: An der Leistungsmessung beteiligte Klassen Holger Rohde WS 2005/2006 Seite 25 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Die sequentielle und parallele Variante wurden auf verschiedenen Rechnern gegenübergestellt. Diese Aufgabe wurde mit Skripten10 automatisiert die das Programm mit den jeweiligen Parametern aufrufen und das Ergebnis in eine Datei umleiten. Die so gewonnen Ergebnisse sollen im Folgenden vorgestellt werden. Der erste Test erfolgte auf einem Einprozessorsystem (Abb. 3.9). Wie nicht anders zu erwarten war, zeigte sich, dass die parallele Variante hier keinen Boden gut machen konnte. Sie war sogar etwas langsamer, da zusätzlich zur eigentlichen Berechnung Wechsel zwischen den einzelnen Threads durchgeführt werden müssen. Mit zunehmenden Rechenzeiten verstärkte sich dieser Effekt. Athlon XP 2400+ / Windows XP / 250 Iterationen / 3 Schwärme 200000 180000 160000 Gesamtzeit (ms) 140000 120000 sequentiell 100000 parallel 80000 60000 40000 20000 0 10 20 40 sequentiell 311 597 1.486 4.049 12.670 42.858 160.263 80 160 320 640 parallel 482 753 2.303 5.398 15.517 52.982 187.477 Vögel pro Schwarm Abbildung 3.9: Einprozessorsystems Anders verlief der Test auf einem System mit 2 Prozessoren (Abb. 3.10). Auf diesem war die parallele Variante insbesondere für hohe Vogelzahlen deutlich schneller. Erstaunlich war der Unterschied zum Einprozessorsystem. Obwohl beide Systeme pro Prozessor 2Ghz besitzen benötigte das Einprozessorsystem erheblich weniger Zeit für die Berechnungen. Sogar die parallele Variante war auf dem Doppelprozessorsystem langsamer. Woran dies lag konnte jedoch nicht festgestellt werden. 10 benchmark.bat und benchmark.sh im Projektverzeichnis Holger Rohde WS 2005/2006 Seite 26 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Dual Xeon 2 Ghz / Windows XP / 250 Iterationen / 3 Schwärme 600000 500000 Gesamtzeit (ms) 400000 sequentiell 300000 parallel 200000 100000 0 10 20 40 80 160 320 640 sequentiell 422 1.131 2.574 10.706 35.725 127.034 488.311 parallel 559 1.066 2.206 7.052 19.206 62.973 227.423 Vögel pro Schwarm Abbildung 3.10: Doppelprozessorsystems Als letztes wurde die Simulation auf einem System mit vier Prozessoren getestet (Abb. 3.11). Die Ergebnisse waren hier denen des Doppelprozessorsystems sehr ähnlich. Die parallele Variante benötigte im Durchschnitt wieder ca. die hälfte der Zeit. Trotz Verdopplung der Prozessorzahl konnte also im Rahmen des Tests keine weitere Steigerung erzielt werden. Holger Rohde WS 2005/2006 Seite 27 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Sun Fire V480 / Solaris / 250 Iterationen / 3 Schwärme 350000 300000 Gesamtzeit (ms) 250000 200000 sequentiell parallel 150000 100000 50000 0 10 20 40 80 160 320 640 sequentiell 939 1.446 2.750 6.584 20.497 70.832 295.975 parallel 795 1.106 1.999 3.981 10.833 35.401 131.877 Vögel pro Schwarm Abbildung 3.11: System mit 4 Prozessoren 4 Fazit Die für das Projekt festgesetzten Ziele wurden alle erreicht. Das verwendete Verfahren wurde erläutert und dessen Parallelisierbarkeit betrachtet. Darauf basierend konnten eine sequentielle und eine parallele Umsetzung der Simulation realisiert und bezüglich der Leistungsfähigkeit verglichen werden. Auch die Visualisierung der Simulation mit Java3D und die Steuerung der Simulationsparameter konnten umgesetzt werden. Von den optionalen Zielen wurde die Integration der Hindernisse teilweise umgesetzt. Leider stand keine Zeit mehr zur Verfügung um die in diesem Zusammenhang noch bestehenden Probleme zu lösen. Die Verbesserung der Visualisierung bezüglich der Vögel und deren Umgebung musste leider komplett gestrichen werden. 5 Anhang 5.1 Quellenverzeichnis [1] Boid-Modell von Craig Reynolds http://www.cs.toronto.edu/~dt/siggraph97-course/cwr87/ [2] Boid-Modell von Craig Reynolds Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 28 von 98 http://www.red3d.com/cwr/boids/ [3] Java Implementierung des Boid Modell von Andrew Davison http://fivedots.coe.psu.ac.th/~ad/jg/ch13/index.html [4] Ausarbeitung zum Boid-Modell von Olaf Schnapauff http://www.sc.cs.tu-bs.de/pare/projekte/olaf/papers/voegel.ps.gz [5] Sun Java3D Tutorial http://java.sun.com/developer/onlineTraining/java3d/ [6] Java3D Tutorial von Schnell und Strasser http://java3d.j3d.org/downloads/Java3D_schnell_tutorial.pdf 5.2 Quellcode 5.2.1 Packet ani 5.2.1.1 AbstractFlock.java /* * Klasse(n): AbstractFlock * Bemerkungen: * * Datei: AbstractFlock.java Autor: Holger Rohde * Datum: 03.11.05 Version: 0.6 * * Historie: * * 26.12.05 - Farbe fuer Signalisierung des Auftreffen auf Hindernisse * als Konstante hinzugefuegt. * 25.12.05 - Methode "protected void switchBirdBounds ()" zum Ein- und * Ausschalten der Visualisierung der Vogelgrenzen * hinzugefuegt. * 17.12.05 - Farbe fuer Signalisierung des Auftreffen auf Weltgrenzen * als Konstante hinzugefuegt. * 08.12.05 - Methoden "protected Vector3f getFlockPosition ()" und * "protected Vector3f getFlockDirection ()" hinzugefuegt * um neue Voegel in die Mitte des Schwarms zu setzen. / * Methode "protected void updateParameter * (ParameterSet updParamter)" entsprechend angepasst. * 07.12.05 - ParameterSet und Methode "protected void updateParameter * (ParameterSet updParamter)" zur Steuerung der Parameter * des Algorithmus hinzugefuegt. */ package ani; Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. import import import import import Seite 29 von 98 java.util.Random; javax.media.j3d.BranchGroup; javax.media.j3d.ColoringAttributes; javax.vecmath.Color3f; javax.vecmath.Vector3f; import util.BirdList; import util.ParameterSet; /* * Realisierung eines Vogelschwarms. Dieser verwaltet eine Liste seiner * Voegel, und berechnet die Kraefte anhand einstellbarer Parameter. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * world - Referenz auf die Instanz der Klasse World * birdColor - Die Farbe der Voegel dieses Schwarms * birds - Die Liste mit allen Voegeln des Schwarms * parameter - Die aktuell gueltigen Parameter fuer die Berechnungen * * oeffentliche Methoden: * ---------------------* * keine * * private Methoden: * ---------------------* * seperation * cohesion * alignment * updateParameter * getFlockPostion * getFlockDirection * switchBirdBounds * randomVector * */ public abstract class AbstractFlock extends BranchGroup { protected static ColoringAttributes WORLD_HIT_CA = new ColoringAttributes ( new Color3f (0.9F, 0.0F, 0.0F), ColoringAttributes.NICEST); protected static ColoringAttributes OBS_HIT_CA = new ColoringAttributes (new Color3f (0.9F, 0.9F, 0.0F), ColoringAttributes.NICEST); protected protected protected protected Holger Rohde World world = null; Color3f birdColor = null; BirdList birds = new BirdList (); ParameterSet parameter = new ParameterSet (); WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 30 von 98 protected AbstractFlock (Color3f birdColor, World world, int range) { this.world = world; this.birdColor = birdColor; this.setCapability (BranchGroup.ALLOW_CHILDREN_WRITE); this.setCapability (BranchGroup.ALLOW_CHILDREN_EXTEND); for (int i = 0; i < parameter.getBirdCount (); i++) { Bird b = new Bird (birdColor, randomVector (range), randomVector (range)); birds.add (b); this.addChild (b); }; } /* * Berechnung der Kraft "seperation". Fuer alle Nachbarvoegel wird * der Vektor zwischen der Position des Vogel und der des Nachbarn * bestimmt und auf das Ergebnis addiert. Vor dem zurueckgeben wird * das Ergenbnis gemittelt und anhand der in der Programmoberflaeche * eingestellten Staerke gewichtet. * * Eingabeparameter: Bird b * Ausgabeparameter: Vector3f result * Fehlerausgaenge: */ protected Vector3f seperation (Bird b) { int neighbors = 0; Bird otherBird = null; Vector3f result = new Vector3f (); Vector3f difference = new Vector3f (); for (int i = 0; i < birds.size (); i++) { otherBird = birds.getBird (i); /* nur fuer Nachbarn durchfuehren und sich selbst ueberspringen if (!b.equals (otherBird) && b.isNeighbor (otherBird, parameter.getSepDistance (), parameter.getSepAngleCos ())) { neighbors++; difference.set (b.getPosition ()); /* Vektor von der eigenen Position zum Nachbar bestimmen difference.sub (otherBird.getPosition ()); /* Vektor auf Ergebnis addieren */ result.add (difference); } ; } ; if (neighbors > 0) { result.scale (1.0F / neighbors); /* Mittel bestimmen result.normalize (); /* Kraft gewichten result.scale (parameter.getSepStrength ()); } ; Holger Rohde */ */ */ */ WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 31 von 98 return result; } /* * Berechnung der Kraft "cohesion". Es werden alle Positionen der * Nachbarvoegel aufaddiert und vor dem Zurueckgeben gemittelt und * gewichtet. * * Eingabeparameter: Bird b * Ausgabeparameter: Vector3f result * Fehlerausgaenge: */ protected Vector3f cohesion (Bird b) { int neighbors = 0; Bird otherBird = null; Vector3f result = new Vector3f (); for (int i = 0; i < birds.size (); i++) { otherBird = birds.getBird (i); /* nur fuer Nachbarn durchfuehren und sich selbst ueberspringen if (!b.equals (otherBird) && b.isNeighbor (otherBird, parameter.getCohDistance (), parameter.getCohAngleCos ())) { neighbors++; /* Die einzelnen Positionsvektoren aufaddieren result.add (otherBird.getPosition ()); }; }; if (neighbors > 0) { result.scale (1.0F / neighbors); /* Mittel bestimmen result.sub (b.getPosition ()); /* Kraft zum Mittelpunkt result.normalize (); /* Kraft gewichten result.scale (parameter.getCohStrength ()); }; return result; */ */ */ */ */ } /* * Berechnung der Kraft "alignment". Es werden alle Richtungen der * Nachbarvoegel aufaddiert und vor dem Zurueckgeben gemittelt und * gewichtet. * * Eingabeparameter: Bird b * Ausgabeparameter: Vector3f result * Fehlerausgaenge: */ protected Vector3f alignment (Bird b) { int neighbors = 0; Bird otherBird = null; Vector3f result = new Vector3f (); for (int i = 0; i < birds.size (); i++) { otherBird = birds.getBird (i); Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 32 von 98 /* nur fuer Nachbarn durchfuehren und sich selbst ueberspringen */ if (!b.equals (otherBird) && b.isNeighbor (otherBird, parameter.getAlignDistance (), parameter.getAlignAngleCos ())) { neighbors++; /* Die einzelnen Richtungsvektoren aufaddieren */ result.add (otherBird.getDirection ()); }; }; if (neighbors > 0) { result.scale (1.0F / neighbors); /* Mittel bestimmen result.normalize (); /* Kraft gewichten result.scale (parameter.getAliStrength ()); }; return result; */ */ } /* * Einstellungen aus dem Kontrollpanel uebernehmen. * * Eingabeparameter: ParameterSet updParamter * Ausgabeparameter: * Fehlerausgaenge: CloneNotSupportedException */ protected void updateParameter (ParameterSet updParamter) { int diff = updParamter.getBirdCount () - parameter.getBirdCount (); if (diff > 0) { for (int i = 0; i < diff; i++) { /* neuen Vogel in die Mitte des Schwarms setzen Bird b = new Bird (birdColor, getFlockPosition (), getFlockDirection ()); */ birds.add (b); this.addChild (b); }; } else if (diff < 0) { for (int i = 0; i < -diff; i++) { /* letzen Vogel in der Liste entfernen */ this.removeChild ((BranchGroup) birds.get (birds.size () - 1)); birds.remove (birds.size () - 1); }; }; /* lokale Parameter mit neuen Parametern ueberschreiben */ try { parameter = updParamter; parameter = (ParameterSet) updParamter.clone (); } catch (CloneNotSupportedException ce) { Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 33 von 98 ce.printStackTrace (); }; } /* * Aktuelle mittlere Position des Schwarms bestimmen. * * Eingabeparameter: * Ausgabeparameter: Vector3f result * Fehlerausgaenge: */ protected Vector3f getFlockPosition () { Vector3f result = new Vector3f (); for (int i = 0; i < birds.size (); i++) { result.add (birds.getBird (i).getPosition ()); }; result.scale (1.0F / birds.size ()); result.normalize (); return result; } /* * Aktuelle mittlere Richtung des Schwarms bestimmen. * * Eingabeparameter: * Ausgabeparameter: Vector3f result * Fehlerausgaenge: */ private Vector3f getFlockDirection () { Vector3f result = new Vector3f (); for (int i = 0; i < birds.size (); i++) { result.add (birds.getBird (i).getDirection ()); }; result.scale (1.0F / birds.size ()); result.normalize (); return result; } /* * Aus- oder Einschalten der Visualisierung der Grenzen fuer alle * Voegel. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ protected void switchBirdBounds () { for (int i = 0; i < birds.size (); i++) { birds.getBird (i).switchBounds (); }; } Holger Rohde WS 2005/2006 Seite 34 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. /* * Zufallsvektor in verschiedenen Quadranten der Koordinatensystems * bestimmen. * * Eingabeparameter: int range * Ausgabeparameter: Vector3f result * Fehlerausgaenge: */ private Vector3f randomVector (int range) { Random random = new Random (); Vector3f result = new Vector3f (random.nextFloat () * 1.3F, random.nextFloat () * 1.3F, random.nextFloat () * 1.3F); switch (range) { case 0: break; case 1: result.x = result.y = break; case 2: result.x = result.z = break; case 3: result.y = result.z = break; default: break; }; return result; /* Auswahl des Quadrant */ -result.x; -result.y; -result.x; -result.z; -result.y; -result.z; } } 5.2.1.2 AbstractFlockManager.java /* * Klasse(n): AbstractFlockManager * Bemerkungen: * * Datei: AbstractFlockManager.java Autor: Holger Rohde * Datum: 03.11.05 Version: 0.5 * * Historie: * * 26.12.05 - Variable "iterations" fuer den Testmodus hinzugefuegt. * 25.12.05 - Methode "protected void switchBirdBounds ()" hinzugefuegt. * 18.12.05 - Objekt "timer" fuer die Zeitmessung hinzugefuegt. / * Referenz auf InfoPanel hinzugefuegt. * 07.12.05 - Methode "protected void updateFlocks * (ParameterSet parameter)" hinzugefuegt. * */ package ani; import java.util.Enumeration; import javax.media.j3d.Behavior; import javax.media.j3d.BoundingSphere; Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 35 von 98 import javax.media.j3d.WakeupOnElapsedTime; import javax.vecmath.Color3f; import import import import import gui.InfoPanel; util.AppSetup; util.FlockList; util.ParameterSet; util.Timer; /* * Klasse zur Verwaltung der Schwaerme und das Starten der Berechnung. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * iterations - Zaehervariable fuer die durchlaufenen Iterationen * world - Referenz auf die Instanz der Klasse World * info - Referenz auf die Instanz der Klasse InfoPanel * timer - Instanz der Klasse Timer fuer die Zeitmessung * flocks - Liste der Schwaerme * flockCol - Feld mit verschiedenen Farben fuer die Schwaerme * * oeffentliche Methoden: * ---------------------* * initialize * * private Methoden: * ---------------------* * switchBirdBounds * updateFlocks * processStimulus - abstract * */ public abstract class AbstractFlockManager extends Behavior { protected long iterations = 0; protected World world = null; protected InfoPanel info = null; protected Timer timer = new Timer (); protected FlockList flocks = new FlockList (); protected Color3f flockCol [] = {new Color3f (0.4F, 0.0F, 0.0F), new Color3f (0.0F, 0.0F, 0.4F), new Color3f (0.0F, 0.4F, 0.0F)}; protected AbstractFlockManager (World world, InfoPanel info) { this.world = world; this.info = info; /* noetig damit ein Ereignis ausgeloest wird this.setSchedulingBounds (new BoundingSphere ()); } */ /* Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 36 von 98 * Legt fest nach welchem Ereignis die Methode processStimulus das * erste mal aufegerufen wird. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void initialize () { this.wakeupOn (new WakeupOnElapsedTime (AppSetup.INIT_WAKEUP)); } /* * Ein- und Ausschalten der Visualisierung der Vogelgrenzen an * die Schwaerme weiter geben. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ protected void switchBirdBounds () { for (int i = 0; i < flocks.size (); i++) { if (this instanceof FlockManagerSeq) { flocks.getFlock (i).switchBirdBounds ( ); } else if (this instanceof FlockManagerThr) { flocks.getFlockThr (i).switchBirdBounds ( ); }; }; } /* * Aktualisierte Parameter von den Kontrollen an die Schwaerme * weiterreichen. * * Eingabeparameter: ParameterSet parameter * Ausgabeparameter: * Fehlerausgaenge: */ protected void updateFlocks (ParameterSet parameter) { for (int i = 0; i < flocks.size (); i++) { if (this instanceof FlockManagerSeq) { flocks.getFlock (i).updateParameter (parameter); } else if (this instanceof FlockManagerThr) { flocks.getFlockThr (i).updateParameter (parameter); }; }; } public abstract void processStimulus (Enumeration arg0); } Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 37 von 98 5.2.1.3 AniPanel.java /* * Klasse(n): AniPanel * Bemerkungen: * * Datei: AniPanel.java Autor: Holger Rohde * Datum: 01.11.05 Version: 1.1 * * Historie: * * 26.12.05 - Methode "public void switchObstacles ()" zum Ein- und * Ausschalten der Hindernisse aus dem Menue hinzugefuegt. * 25.12.05 - Methode "public void switchBirdBounds ()" fuer die * Menuesteuerung hinzugefuegt. * 23.12.05 - Erstellung des FlockManger abhaengig von Parameter * AppSetup.use_threads als FlockManagerSeq oder * FlockManagerThr. * 21.12.05 - Rand um das Panel gelegt. * 20.12.05 - Kameraposition angepasst. Methode "public void * "public void switchWorldBounds ()" fuer die Menuesteuerung * hinzugefuegt. * 17.12.05 - Hintergrundfarbe der Animation gesetzt. * 07.12.05 - Methode "public void updateFlockManager * (ParameterSet parameter)" hinzugefuegt um Aktualisierungen * aus dem ControlPanel an den FlockMangager weiterzuleiten. * 18.11.05 - Licht hinzugefuegt. * 05.11.05 - Rotieren der Animation mittels der Maus hinzugefuegt. * 03.11.05 - Erstellung des FlockManagers hinzugefuegt. */ package ani; import import import import import import import import import import import import import import java.awt.GraphicsConfiguration; javax.media.j3d.Background; javax.media.j3d.BoundingSphere; javax.media.j3d.BranchGroup; javax.media.j3d.Canvas3D; javax.media.j3d.Transform3D; javax.media.j3d.TransformGroup; javax.swing.JPanel; javax.swing.border.BevelBorder; javax.vecmath.Color3f; javax.vecmath.Point3d; javax.vecmath.Vector3d; com.sun.j3d.utils.behaviors.mouse.MouseRotate; com.sun.j3d.utils.universe.SimpleUniverse; import gui.InfoPanel; import util.AppSetup; import util.ParameterSet; /* * * * * * * * * * Container der Java3D Animation. oeffentliche Daten: ---------------------keine private Daten: ---------------------- Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 38 von 98 * * serialVersionUID - Da JPanel das Interace Serializable * implementiert ist diese Variable notwendig (hat * hier aber keine weitere Funktion) * world - Instanz der Klasse World die die Umgebung der * Voegel aufbaut * light - Instanz der Klasse GlobalLight die der Szene * Lichtquelle hinzufuegt * flockManager - Instanz der Klasse FlockManagerSeq oder * FlockManagerThr zur Verwaltung der Schwaerme * info - Referez auf die Instanz des Infopanel * * oeffentliche Methoden: * ---------------------* * updateFlockManager * switchBirdBounds * switchWorldBounds * switchObstacles * * private Methoden: * ---------------------* * keine * */ public class AniPanel extends JPanel { private static Color3f BG_COLOR = new Color3f (0.6F, 0.6F, 0.6F); private private private private private static final long serialVersionUID = 1; World world = new World (); GlobalLight light = new GlobalLight (); AbstractFlockManager flockManager = null; InfoPanel info = null; public AniPanel (InfoPanel info) { this.info = info; GraphicsConfiguration gc = SimpleUniverse.getPreferredConfiguration (); Canvas3D canvas = new Canvas3D (gc); canvas.setPreferredSize(AppSetup.animationSize); SimpleUniverse universe = new SimpleUniverse (canvas); BranchGroup rootGroup = new BranchGroup (); TransformGroup tg = new TransformGroup (); /* * Erzeugung des flockManager-Objekt fuer parallele oder * seqeuntielle Berechnung. */ if (AppSetup.use_threads == true) { flockManager = new FlockManagerThr (world, info); } else { Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 39 von 98 flockManager = new FlockManagerSeq (world, info); }; /* Sicht auf die Szenen anpassen Transform3D view= new Transform3D (); view.lookAt (new Point3d (0.0, 5.0, 5.0), new Point3d (0.0, -0.5, 0.0), new Vector3d (0.0, 1.0, 0.0)); view.invert (); universe.getViewingPlatform().getViewPlatformTransform(). setTransform (view); */ Background aniBackground = new Background (BG_COLOR); aniBackground.setApplicationBounds (new BoundingSphere ()); /* Rotieren der Szene mit der linken Maustaste MouseRotate mouseRotate = new MouseRotate (); mouseRotate.setTransformGroup (tg); mouseRotate.setSchedulingBounds (new BoundingSphere ()); */ tg.setCapability (TransformGroup.ALLOW_TRANSFORM_WRITE); tg.setCapability (TransformGroup.ALLOW_TRANSFORM_READ); this.setBorder (new BevelBorder (BevelBorder.LOWERED)); this.add (canvas); tg.addChild (flockManager); tg.addChild (light); tg.addChild (world); rootGroup.addChild (tg); rootGroup.addChild(aniBackground); rootGroup.addChild (mouseRotate); rootGroup.compile(); /* optimieren des Szenengraph */ universe.addBranchGraph(rootGroup); } /* * Aktuelle Parameter zur Instanz der Klasse * FlockManagerSeq oder FlockManagerThr weiterreichen. * * Eingabeparameter: ParameterSet parameter * Ausgabeparameter: * Fehlerausgaenge: */ public void updateFlockManager (ParameterSet parameter) { flockManager.updateFlocks (parameter); } /* * Ein- und Auschalten Vogelbegrenzungen zur Instanz der Klasse * FlockManagerSeq oder FlockManagerThr weiterreichen. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void switchBirdBounds () { flockManager.switchBirdBounds (); } Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 40 von 98 /* * Ein- und Auschalten Weltbegrenzungen zur Instanz der Klasse * World weiterreichen. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void switchWorldBounds () { world.switchBounds (); } /* * Ein- und Auschalten der Hindernisse zur Instanz der Klasse World * weiterreichen. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void switchObstacles () { world.switchObstacles (); } } 5.2.1.4 Bird.java /* * Klasse(n): Bird * Bemerkungen: * * Datei: Bird.java Autor: Holger Rohde * Datum: 01.11.05 Version: 0.4 * * Historie: * * 25.12.05 - Methode "public void switchBounds ()" zum Ein- und * der Anzeige der Grenzen hinzugefuegt. * 17.12.05 - Methode "public void setBoundsColoringAttributes * (ColoringAttributes ca)" zum Setzen der Farbe der Grenzen * hinzugefuegt. * 07.12.05 - Methode "public void update (ParameterSet parameter)" auf * Nutzung des ParamterSet umgestellt. */ package ani; import javax.media.j3d.Appearance; import javax.media.j3d.BoundingSphere; import javax.media.j3d.BranchGroup; Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. import import import import import import import import Seite 41 von 98 javax.media.j3d.ColoringAttributes; javax.media.j3d.PolygonAttributes; javax.media.j3d.Transform3D; javax.media.j3d.TransformGroup; javax.media.j3d.TransparencyAttributes; javax.vecmath.Color3f; javax.vecmath.Point3d; javax.vecmath.Vector3f; import com.sun.j3d.utils.geometry.Box; import util.AppSetup; import util.ParameterSet; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Klasse zur Nachbildung eines Vogels. oeffentliche Daten: ---------------------keine private Daten: ---------------------position direction velocity forces - birdModel - boundsAp - tg bounds boundsBox boundsGroup - Vektor zur Speicherung der Position des Vogels Vektor zur Speicherung der Flugrichtung des Vogels Vektor zur Speicherung der Geschwindigkeit des Vogels Vektor zur Zwischenspeicherung der Kraefte die auf den Vogel wirken ein einfaches Modell zur Darstellung des Vogels in der Animation Erscheinungsbild der Visualisierung der Grenzen des Vogels Tranformationsgruppe fuer die Bewegung des Vogels Die imaginaeren Grenzen um den Vogel Visualisierung der Grenzen mit einem Quader BranchGroup fuer das Objekt boundsBox oeffentliche Methoden: ---------------------update isNeighbor switchBounds setBoundsColoringAttributes addForce Getter / Setter: getPosition getDirection getVelocity getBs private Methoden: ---------------------move Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 42 von 98 */ public class Bird extends BranchGroup { private Vector3f position = new Vector3f (); private Vector3f direction = new Vector3f (); private Vector3f velocity = new Vector3f (AppSetup.speed_def, AppSetup.speed_def, 0.0F); private Vector3f forces = new Vector3f (); private private private private BirdModel birdModel = null; Appearance boundsAp = new Appearance (); TransformGroup tg = new TransformGroup (); BoundingSphere bounds = new BoundingSphere (); /* * Nur Gruppen koennen bei laufender Animation hinzugefuegt und * entfernt werden. Deshalb benoetigten wir eine extra Gruppe fuer * den Grenzquader. */ private BranchGroup boundsGroup = new BranchGroup (); public Bird (Color3f birdColor, Vector3f position, Vector3f direction) { this.direction = direction; this.position = position; PolygonAttributes pa = new PolygonAttributes (); TransparencyAttributes ta = new TransparencyAttributes (); birdModel = new BirdModel (birdColor); Box boundsBox = new Box (AppSetup.BIRD_SIZE * 2, AppSetup.BIRD_SIZE * 2, AppSetup.BIRD_SIZE * 2, boundsAp); tg.setCapability (TransformGroup.ALLOW_TRANSFORM_WRITE); tg.setCapability (TransformGroup.ALLOW_TRANSFORM_READ); tg.setCapability (TransformGroup.ALLOW_CHILDREN_WRITE); tg.setCapability (TransformGroup.ALLOW_CHILDREN_EXTEND); boundsAp.setCapability (Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE); boundsGroup.setCapability (BranchGroup.ALLOW_DETACH); this.setCapability (BranchGroup.ALLOW_DETACH); bounds.setRadius (AppSetup.BIRD_SIZE); pa.setPolygonMode (PolygonAttributes.POLYGON_LINE); ta.setTransparencyMode (TransparencyAttributes.FASTEST); ta.setTransparency (0.7F); boundsAp.setTransparencyAttributes (ta); boundsAp.setPolygonAttributes (pa); boundsBox.setAppearance (boundsAp); tg.addChild (birdModel); boundsGroup.addChild (boundsBox); if (AppSetup.bird_bounds == true) { tg.addChild (boundsGroup); }; this.addChild(tg); this.move (); } /* Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 43 von 98 * Aktualisierung der Position, Richtung und Geschwindigkeit anhand * der gespeicherten Kräfte. * * Eingabeparameter: ParameterSet parameter * Ausgabeparameter: * Fehlerausgaenge: */ public void update (ParameterSet parameter) { if (forces.length () > parameter.getMaxForce () ) { forces.scale (parameter.getMaxForce () / forces.length ()); }; velocity.add (forces); if (velocity.length () > parameter.getMaxSpeed ()) { velocity.scale (parameter.getMaxSpeed () / velocity.length ()); }; position.add (velocity); if (velocity.length () > 0) { direction.set (velocity); direction.normalize (); }; forces.set (0.0F, 0.0F, 0.0F); this.move (); } /* * Bewegt den Vogel in der Animation zur aktuellen Position und dreht * ihn in die Flugrichtung. Die Drehung ueber die Methode atan2 * wurde aus einer Veroeffentlichung zum Schwarmverhalten von * Andrew Davison uebernommen * (http://fivedots.coe.psu.ac.th/~ad/jg/ch13/index.html). * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ private void move () { Transform3D move = new Transform3D (); move.rotY (Math.atan2 (velocity.x, velocity.z)); move.setTranslation (position); tg.setTransform (move); /* Grenzen des Vogels auch auf neue Position setzen */ bounds.setCenter (new Point3d (position.x, position.y, position.z)); } /* * * * * * * * * * Bestimmt ob ein Vogel Nachbar dieses Vogels ist. Dazu wird die Distanz zwischen den beiden Voegeln ermittelt und mit dem vorgegebenen Wert verglichen. Zur Ueberpruefung ob sich der Vogel im Sichtwinkel befindet wird das Skalarprodukt der Flugrichtung und des Vektors zum anderen Vogel ermittelt. Da der Betrag der Richtungsvektoren 1 betraegt erhaelt man so den Winkel zwischen den Vektoren. Eingabeparameter: Holger Rohde Bird b WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 44 von 98 * double distance * double angle * Ausgabeparameter: boolean ret * Fehlerausgaenge: */ public boolean isNeighbor (Bird b, double distance, double angle) { boolean ret = false; Vector3f birdDistance = new Vector3f (); birdDistance.set (b.getPosition ()); birdDistance.sub (position); /* Abstand ermitteln if (birdDistance.length () < distance) { birdDistance.normalize (); /* Sichtwinkel ueberpruefen ret = birdDistance.dot (direction) > angle; }; return ret; */ */ } /* * Visualisierung der Vogelbegrenzungen ein- und ausschalten. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void switchBounds () { /* Grenzen werden gerade angezeigt if (boundsGroup.isLive () == true) { AppSetup.bird_bounds = false; tg.removeChild (boundsGroup); } else { AppSetup.bird_bounds = true; tg.addChild (boundsGroup); }; } */ /* * Farbe der Visualisierung der Vogelgrenzen setzen. * * Eingabeparameter: ColoringAttributes ca * Ausgabeparameter: * Fehlerausgaenge: */ public void setBoundsColoringAttributes (ColoringAttributes ca) { boundsAp.setColoringAttributes (ca); } /* * Eine fuer den Vogel berechnete Kraft zwischenspeichern. * * Eingabeparameter: Vector3f force * Ausgabeparameter: - Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 45 von 98 * Fehlerausgaenge: */ public void addForce (Vector3f force) { forces.add (force); } public Vector3f getPosition () { return position; } public Vector3f getDirection () { return direction; } public Vector3f getVelocity () { return velocity; } /* * Rueckgabe der Grenzen des Vogels zur Ueberpruefung ob er die Welt * verlassen hat oder mit einem Hindernis kolidiert. * * Eingabeparameter: * Ausgabeparameter: BoundingSphere bounds * Fehlerausgaenge: */ public BoundingSphere getBs () { return bounds; } } 5.2.1.5 BirdModel.java /* * Klasse(n): BirdModel * Bemerkungen: * * Datei: BirdModel.java Autor: Holger Rohde * Datum: 01.11.05 Version: 0.3 * * Historie: * * 24.12.05 - Die bisher zur Darstellung des Vogels verwendete Kugel * durch einen um 90 Grad gedrehten Kegel ersetzt. * 20.11.05 - Auf Licht reagierendes Material statt einfacher * Objektfarbe. * */ package ani; import javax.media.j3d.Appearance; Holger Rohde WS 2005/2006 Seite 46 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. import import import import import import javax.media.j3d.BranchGroup; javax.media.j3d.Material; javax.media.j3d.Transform3D; javax.media.j3d.TransformGroup; javax.vecmath.Color3f; com.sun.j3d.utils.geometry.Cone; import util.AppSetup; /* * Ein einfaches Modell zur Visualisierung des Vogels. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * keine * * oeffentliche Methoden: * ---------------------* * keine * * private Methoden: * ---------------------* * keine * */ public class BirdModel extends BranchGroup { public BirdModel (Color3f birdColor) { Appearance ap = new Appearance (); Material mat = new Material (); TransformGroup tg = new TransformGroup (); Transform3D coneTrans = new Transform3D (); Cone cone = new Cone (AppSetup.BIRD_SIZE, AppSetup.BIRD_SIZE * 3, ap); coneTrans.rotX (Math.PI / 2); /* Drehung um 90 Grad */ tg.setCapability (TransformGroup.ALLOW_TRANSFORM_READ); tg.setCapability (TransformGroup.ALLOW_TRANSFORM_WRITE); tg.setTransform (coneTrans); mat.setDiffuseColor (birdColor); mat.setAmbientColor (birdColor); mat.setShininess (50F); ap.setMaterial (mat); tg.addChild (cone); this.addChild (tg); } } Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 47 von 98 5.2.1.6 FlockManagerSeq.java /* * Klasse(n): FlockManagerSeq * Bemerkungen: * * Datei: FlockManagerSeq.java Autor: Holger Rohde * Datum: 03.11.05 Version: 0.3 * * Historie: * * 26.12.05 - Beenden und Ausgabe der Messwerte im Testmodus * hinzugefuegt. * 18.12.05 - Zeitmessung ergaenzt. * */ package ani; import java.util.Enumeration; import javax.media.j3d.WakeupOnElapsedFrames; import gui.InfoPanel; import util.AppSetup; /* * Klasse erweitert AbstractFlockManager um die fuer die sequentielle * Berechnung benoetigen Eigenschaften. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * keine * * oeffentliche Methoden: * ---------------------* * processStimulus * * private Methoden: * ---------------------* * keine * */ public class FlockManagerSeq extends AbstractFlockManager { public FlockManagerSeq (World world, InfoPanel info) { super (world, info); for (int i = 0; i < AppSetup.flock_count; i++) { FlockSeq f = new FlockSeq (flockCol [i % flockCol.length], world, i % 4); flocks.add (f); world.addChild (f); Holger Rohde WS 2005/2006 Seite 48 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. }; } /* * Startet nach jedem Bild der Animation eine neue Berechnung der * Kraefte. * * Eingabeparameter: Enumeration arg0 * Ausgabeparameter: * Fehlerausgaenge: InterruptedException */ public void processStimulus (Enumeration arg0) { timer.start (); /* Zeitmessung starten /* Berechnung fuer alle Schwaerme durchfuehren for (int i = 0; i < flocks.size (); i++) { flocks.getFlock (i).updateFlock (); }; timer.stop (); /* Zeitmessung stoppen info.updateTime (timer); /* Infopanel aktualisieren /* Im Testmodus die Iterationen zaehlen if (AppSetup.benchmark == true) { iterations++; }; /* Im Testmodus nach der eingestellten Anzahl Iterationen beenden if (iterations < AppSetup.BENCH_ITERATIONS) { /* erneuter Aufruf nach Anzeige des naechsten Bilds wakeupOn (new WakeupOnElapsedFrames (1)); } else { timer.print (); /* Messergebnisse ausgeben System.exit (0); }; } */ */ */ */ */ */ */ */ } 5.2.1.7 FlockManagerThr.java /* * Klasse(n): FlockManagerThr * Bemerkungen: * * Datei: FlockManagerThr.java * Datum: 23.12.05 * * Historie: * * keine Aenderungen * */ package ani; Autor: Holger Rohde Version: 0.1 import java.util.Enumeration; import javax.media.j3d.WakeupOnElapsedFrames; Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 49 von 98 import gui.InfoPanel; import util.AppSetup; /* * Klasse erweitert AbstractFlockManager um die fuer die parallele * Berechnung benoetigen Eigenschaften. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * sigCount - Zaehlvariable fuer Signalisierung durch Threads * * oeffentliche Methoden: * ---------------------* * processStimulus * signal * * private Methoden: * ---------------------* * keine * */ public class FlockManagerThr extends AbstractFlockManager { private int sigCount = 0; public FlockManagerThr (World world, InfoPanel info) { super (world, info); for (int i = 0; i < AppSetup.flock_count; i++) { FlockThr f = new FlockThr (flockCol [i % flockCol.length], world, this, i % 4); flocks.add (f); new Thread (f).start (); world.addChild (f); if (AppSetup.debug == true) { System.out.println ("thread " + i + " started"); }; }; } /* * Startet nach jedem * Kraefte. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ Holger Rohde Bild der Animation eine neue Berechnung der Enumeration arg0 InterruptedException WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 50 von 98 public synchronized void processStimulus (Enumeration arg0) { timer.start (); /* Zeitmessung starten /* Berechnung fuer jeden Schwarm starten for (int i = 0; i < flocks.size (); i++) { ((FlockThr) flocks.get (i)).signal (); }; /* Warten bis alle Schwaerme mit der Berechnung fertig sind try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); }; timer.stop (); /* Zeitmessung stoppen info.updateTime (timer); /* Infopanel aktualisieren /* Im Testmodus die Iterationen zaehlen if (AppSetup.benchmark == true) { iterations++; }; /* Im Testmodus nach der eingestellten Anzahl Iterationen beenden if (iterations < AppSetup.BENCH_ITERATIONS) { /* erneuter Aufruf nach Anzeige des naechsten Bilds wakeupOn (new WakeupOnElapsedFrames (1)); } else { timer.print (); /* Messergebnisse ausgeben System.exit (0); }; } */ */ */ */ */ */ */ */ */ /* * Kapselt den Aufruf der Methode notify(). Ermoeglicht deren Aufruf * durch einen anderen Thread. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public synchronized void signal () { sigCount++; /* Warten bis alle Threads mit der Berechnung fertig sind */ if (sigCount == AppSetup.flock_count) { sigCount = 0; this.notify (); }; } } 5.2.1.8 FlockSeq.java /* * Klasse(n): Holger Rohde FlockSeq WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 51 von 98 * Bemerkungen: * * Datei: FlockSeq.java Autor: Holger Rohde * Datum: 03.11.05 Version: 0.3 * * Historie: * * 26.12.05 - Umfliegen der Hindernisse hinzugefuegt. * 17.12.05 - Signalisierung fuer Auftreffen auf die Weltgrenzen * hinzugefuegt */ package ani; import javax.vecmath.Color3f; import javax.vecmath.Vector3f; import util.AppSetup; /* * Klasse erweitert AbstractFlock um die fuer die sequentielle * Berechnung benoetigen Eigenschaften. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * keine * * oeffentliche Methoden: * ---------------------* * updateFlock * * private Methoden: * ---------------------* * keine * */ public class FlockSeq extends AbstractFlock { public FlockSeq (Color3f birdColor, World world, int range) { super (birdColor, world, range); } /* * Berechnung der Kraefte und Erkennung von Hindernissen fuer jeden * Vogel des Schwarms * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void updateFlock () { Holger Rohde WS 2005/2006 Seite 52 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Bird b = null; for (int i = 0; i < birds.size (); i++) { b = birds.getBird (i); /* * der Vogel muss umkehren wenn er die Begrenzung der Welt * erreicht hat */ if (!b.getBs ().intersect (world.getBs ())) { Vector3f turn = new Vector3f (-b.getPosition ().x, -b.getPosition ().y, -b.getPosition ().z); b.addForce (turn); /* * Wenn der Vogel die Weltbegrenzung erreicht hat soll dies * durch eine Veraenderung der Farbe signalisiert werden */ if (AppSetup.world_bounds == true) { b.setBoundsColoringAttributes (WORLD_HIT_CA); }; } /* Wenn der Vogel auf ein Hindernis trifft soll er umdrehen else if (AppSetup.obstacles && world.intersectObstacle (b)) { Vector3f turn = new Vector3f (-b.getPosition ().x, 0, -b.getPosition ().z); b.addForce (turn); /* Signalisieren der Hindernisserkennung b.setBoundsColoringAttributes (OBS_HIT_CA); */ } else { /* Kraefte berechnen und zwischenspeichern b.addForce (seperation (b)); b.addForce (cohesion (b)); b.addForce (alignment (b)); /* Farbe zuruecksetzen wenn der Vogel im normalen Raum ist b.setBoundsColoringAttributes (null); }; }; /* Vogeldaten anhand der berechneten Kräfte aktualisieren for (int i = 0; i < birds.size (); i++) { b = birds.getBird (i); b.update (parameter); }; */ */ */ */ } } 5.2.1.9 FlockThr.java /* * * * * * Klasse(n): FlockThr Bemerkungen: Datei: Datum: Holger Rohde FlockThr.java 23.12.05 Autor: Holger Rohde Version: 0.2 WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 53 von 98 * * Historie: * * 26.12.05 - Umfliegen der Hindernisse hinzugefuegt. */ package ani; import javax.vecmath.Color3f; import javax.vecmath.Vector3f; import util.AppSetup; /* * Klasse erweitert AbstractFlock um die fuer die parallele Berechnung * benoetigen Eigenschaften. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * manager - Referenz auf das FlockManagerThr-Objekt fuer den Aufruf * der Methode signal() * * oeffentliche Methoden: * ---------------------* * run * signal * * private Methoden: * ---------------------* * keine * */ public class FlockThr extends AbstractFlock implements Runnable { private FlockManagerThr manager = null; public FlockThr (Color3f birdColor, World world, FlockManagerThr manager, int range) { super (birdColor, world, range); this.manager = manager; } /* * Berechnung der Kraefte und Erkennung von Hindernissen fuer jeden * Vogel des Schwarms * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: InterruptedException */ public synchronized void run () { Holger Rohde WS 2005/2006 Seite 54 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. while (true) { Bird b = null; /* Thread nicht beenden */ for (int i = 0; i < birds.size (); i++) { b = birds.getBird (i); /* * der Vogel muss umkehren wenn er die Begrenzung der Welt * erreicht hat */ if (!b.getBs ().intersect (world.getBs ())) { Vector3f turn = new Vector3f (-b.getPosition ().x, -b.getPosition ().y, -b.getPosition ().z); b.addForce (turn); /* * Wenn der Vogel die Weltbegrenzung erreicht hat soll dies * durch eine Veraenderung der Farbe signalisiert werden */ if (AppSetup.world_bounds == true) { b.setBoundsColoringAttributes (WORLD_HIT_CA); }; } /* Wenn der Vogel auf ein Hindernis trifft soll er umdrehen */ else if (AppSetup.obstacles && world.intersectObstacle (b)) { /* Funktioniert so nicht immer / Fallunterscheidung noetig */ Vector3f turn = new Vector3f (-b.getPosition ().x, 0, -b.getPosition ().z); b.addForce (turn); /* Signalisieren der Hindernisserkennung b.setBoundsColoringAttributes (OBS_HIT_CA); */ } else { /* Kraefte berechnen und zwischenspeichern b.addForce (seperation (b)); b.addForce (cohesion (b)); b.addForce (alignment (b)); /* Farbe zuruecksetzen wenn der Vogel im normalen Raum ist b.setBoundsColoringAttributes (null); }; */ */ }; /* Vogeldaten anhand der berechneten Kräfte aktualisieren */ for (int i = 0; i < birds.size (); i++) { b = birds.getBird (i); b.update (parameter); }; manager.signal (); /* Ende der Berechnung melden */ /* Warten bis zum naechsten Durchlauf */ try { this.wait(); } catch (InterruptedException e) Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 55 von 98 { e.printStackTrace(); }; } } /* * Kapselt den Aufruf der Methode notify(). Ermoeglicht deren Aufruf * durch einen anderen Thread. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public synchronized void signal () { this.notify (); } } 5.2.1.10 GlobalLight.java /* * Klasse(n): GlobalLight * Bemerkungen: * * Datei: GlobalLight.java Autor: Holger Rohde * Datum: 18.11.05 Version: 0.2 * * Historie: * * 20.11.05 - Einflussbereich des Lichts erweitert * */ package ani; import import import import /* * * * * * * * * * * * * * * * * * * * javax.media.j3d.AmbientLight; javax.media.j3d.BoundingBox; javax.media.j3d.BranchGroup; javax.media.j3d.DirectionalLight; Licht fuer jedes Objekt der Szene das ein Material besitzt. oeffentliche Daten: ---------------------keine private Daten: ---------------------keine oeffentliche Methoden: ---------------------keine private Methoden: ---------------------- Holger Rohde WS 2005/2006 Seite 56 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. * * keine * */ public class GlobalLight extends BranchGroup { public GlobalLight () { DirectionalLight directional = new DirectionalLight (); AmbientLight ambient = new AmbientLight (); BoundingBox bounds = new BoundingBox (); /* Licht wirkt auf jedes Objekt in diesem Bereich bounds.setLower (-10.0 ,-10.0, -10.0); bounds.setUpper (10.0 , 10.0, 10.0); */ directional.setInfluencingBounds (bounds); ambient.setInfluencingBounds (bounds); this.addChild (directional); this.addChild (ambient); } } 5.2.1.11 Obstacle.java /* * Klasse(n): Obstacle * Bemerkungen: * * Datei: Obstacle.java * Datum: 26.12.05 * * Historie: * * keine Aenderungen * */ package ani; import import import import import import import import import import /* * * * * * * * * * * Autor: Holger Rohde Version: 0.1 javax.media.j3d.Appearance; javax.media.j3d.BoundingBox; javax.media.j3d.BranchGroup; javax.media.j3d.PolygonAttributes; javax.media.j3d.Transform3D; javax.media.j3d.TransformGroup; javax.media.j3d.TransparencyAttributes; javax.vecmath.Point3d; javax.vecmath.Vector3f; com.sun.j3d.utils.geometry.Cylinder; Gruppe realisiert ein einfaches aus einem Zylinder bestehendes Hindernis und dessen Grenzen für die Kollisionserkennung. oeffentliche Daten: ---------------------keine private Daten: ---------------------- Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 57 von 98 * * bounds - Die imaginaeren Grenzen des Hindernis * * oeffentliche Methoden: * ---------------------* * Getter / Setter: * * getBs * * private Methoden: * ---------------------* * keine * */ public class Obstacle extends BranchGroup { private BoundingBox bounds = new BoundingBox (); public Obstacle (Vector3f position, float size) { Appearance obstacleAp = new Appearance (); TransparencyAttributes obstacleTa = new TransparencyAttributes (); PolygonAttributes obstaclePa = new PolygonAttributes (); TransformGroup ostacleTg = new TransformGroup (); Transform3D translation = new Transform3D (); Cylinder obstacleCylinder = new Cylinder (size, 2F); /* Hindernis auf uebergebene Position schieben translation.setTranslation (position); ostacleTg.setTransform (translation); */ /* * die Grenzen sollen groesser als das Objekt an sich sein damit * die Voegel etwas Spielraum zum Ausweichen haben */ size = size * 2.1F; bounds.setUpper (new Point3d (position.x + size, 1, position.z + size)); bounds.setLower (new Point3d (position.x - size, -1, position.z - size)); obstaclePa.setPolygonMode (PolygonAttributes.POLYGON_LINE); obstacleTa.setTransparencyMode (TransparencyAttributes.NICEST); obstacleTa.setTransparency (0.8F); obstacleAp.setPolygonAttributes (obstaclePa); obstacleAp.setTransparencyAttributes(obstacleTa); obstacleCylinder.setAppearance (obstacleAp); ostacleTg.addChild(obstacleCylinder); this.addChild(ostacleTg); } /* * Gibt die Grenzen des Hindernis zurueck. * * Eingabeparameter: - Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 58 von 98 * Ausgabeparameter: BoundingBox bounds * Fehlerausgaenge: */ public BoundingBox getBs () { return bounds; } } 5.2.1.12 World.java /* * Klasse(n): World * Bemerkungen: * * Datei: World.java Autor: Holger Rohde * Datum: 01.11.05 Version: 0.4 * * Historie: * * 26.12.05 - Hindernisse mit Gruppe hinzugefuegt / Methoden "public * void switchObstacles ()" und "public boolean * intersectObstacle (Bird b)" hinzugefuegt. * 23.12.05 - Farbe der Bodenplatte veraendert. * 20.12.05 - Methode "public void switchBounds ()" und extra Gruppe * fuer den Quader der Begrenzung hinzugefuegt. * */ package ani; import import import import import import import import import import import import com.sun.j3d.utils.geometry.Box; javax.media.j3d.Appearance; javax.media.j3d.BoundingBox; javax.media.j3d.BranchGroup; javax.media.j3d.ColoringAttributes; javax.media.j3d.PolygonAttributes; javax.media.j3d.Transform3D; javax.media.j3d.TransformGroup; javax.media.j3d.TransparencyAttributes; javax.vecmath.Color3f; javax.vecmath.Point3d; javax.vecmath.Vector3f; import util.AppSetup; /* * * * * * * * * * * * * * * * Die Umgebung der Voegel. Besteht aus den Hindernissen, den Grenzen und einer Bodenplatte. oeffentliche Daten: ---------------------keine private Daten: ---------------------obstacle1 obstacle2 obstacle3 obstacleGroup boundsGroup Holger Rohde - Hindernis hinten links Hindernis vorne links Hindernis hinten mitte BranchGroup fuer die Hindernisse BranchGroup fuer die Anzeige Weltbegrenzung WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 59 von 98 * bounds - Die imaginaeren Grenzen der Welt * * oeffentliche Methoden: * ---------------------* * intersectObstacle * switchBounds * switchObstacles * * Getter / Setter: * * getBs * * private Methoden: * ---------------------* * keine * */ public class World extends BranchGroup { private Obstacle obstacle1 = new Obstacle ( new Vector3f (-1.5F, 0.0F, -1.3F), 0.2F); private Obstacle obstacle2 = new Obstacle ( new Vector3f (-1.2F, 0.0F, 1.2F), 0.3F); private Obstacle obstacle3 = new Obstacle ( new Vector3f (0.0F, 0.0F, -1.7F), 0.2F); private BoundingBox bounds = new BoundingBox (); /* * Nur Gruppen koennen bei laufender Animation hinzugefuegt und * entfernt werden. Deshalb benoetigten wir eine extra Gruppe fuer * die Hindernisse und den Quader der Weltbegrenzung. Die Hindernisse * sind zwar jeweils selbst eine Gruppe sollen aber immer alle * entfernt oder hinzugefuegt werden. Deshalb werden sie nochmal in * einer Gruppe zusammengefasst. */ private BranchGroup obstacleGroup = new BranchGroup (); private BranchGroup boundsGroup = new BranchGroup (); public World () { Appearance groundAp = new Appearance (); Appearance boundsAp = new Appearance (); PolygonAttributes boundsPa = new PolygonAttributes (); TransformGroup tg = new TransformGroup (); Transform3D move = new Transform3D (); Color3f groundColor = new Color3f (0.25F, 0.25F, 0.25F); Box boundsBox = new Box (2.0F, 1.0F, 2.0F, boundsAp); Box groundBox = new Box (2.0F, 0.05F, 2.0F, groundAp); this.setCapability (BranchGroup.ALLOW_CHILDREN_WRITE); this.setCapability (BranchGroup.ALLOW_CHILDREN_EXTEND); tg.setCapability (TransformGroup.ALLOW_TRANSFORM_READ); tg.setCapability (TransformGroup.ALLOW_TRANSFORM_WRITE); obstacleGroup.setCapability (BranchGroup.ALLOW_DETACH); boundsGroup.setCapability (BranchGroup.ALLOW_DETACH); Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 60 von 98 groundAp.setColoringAttributes (new ColoringAttributes (groundColor, ColoringAttributes.NICEST)); boundsAp.setTransparencyAttributes (new TransparencyAttributes ( TransparencyAttributes.NICEST, 0.8F)); /* Groesse der Welt festlegen bounds.setLower (new Point3d (-2, -1, -2)); bounds.setUpper (new Point3d (2, 1, 2)); */ /* nur Linien der Begrenzung anzeigen boundsPa.setPolygonMode (PolygonAttributes.POLYGON_LINE); boundsPa.setCullFace (PolygonAttributes.CULL_NONE); boundsAp.setPolygonAttributes (boundsPa); boundsBox.setAppearance (boundsAp); */ /* Bodenplatte nach unten verschieben und hinzufuegen move.setTranslation (new Vector3f (0.0F, -1.4F, 0.0F)); tg.setTransform(move); tg.addChild(groundBox); this.addChild (tg); */ boundsGroup.addChild (boundsBox); obstacleGroup.addChild (obstacle1); obstacleGroup.addChild (obstacle2); obstacleGroup.addChild (obstacle3); if (AppSetup.obstacles == true) { this.addChild (obstacleGroup); }; if (AppSetup.world_bounds == true) { this.addChild (boundsGroup); }; } /* * Ermitteln ob der Kollisionsbereich des Vogels eine Ueberschneidung * mit den Kollisionsbereichen der Hindernisse besitzt. * * Eingabeparameter: Bird b * Ausgabeparameter: boolean ret * Fehlerausgaenge: */ public boolean intersectObstacle (Bird b) { boolean ret; ret = b.getBs().intersect(obstacle1.getBs()) || b.getBs().intersect(obstacle2.getBs()) || b.getBs().intersect(obstacle3.getBs()); return ret; } /* * Visualisierung der Weltbegrenzungen ein- und ausschalten. * * Eingabeparameter: * Ausgabeparameter: - Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. * Fehlerausgaenge: */ public void switchBounds () { /* Grenzen werden gerade angezeigt if (boundsGroup.isLive () == true) { AppSetup.world_bounds = false; this.removeChild (boundsGroup); } else { AppSetup.world_bounds = true; this.addChild (boundsGroup); }; } /* * Visualisierung der Hindernisse ein- und ausschalten. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void switchObstacles () { /* Hindernisse werden gerade angezeigt if (obstacleGroup.isLive () == true) { AppSetup.obstacles = false; this.removeChild (obstacleGroup); } else { AppSetup.obstacles = true; this.addChild (obstacleGroup); }; } Seite 61 von 98 */ */ /* * Rueckgabe der Grenzen der Welt zur Ueberpruefung ob ein Vogel diese * ueberschritten hat. * * Eingabeparameter: * Ausgabeparameter: BoundingBox bounds * Fehlerausgaenge: */ public BoundingBox getBs () { return bounds; } } 5.2.2 Packet gui 5.2.2.1 ControlPanel.java /* * Klasse(n): ControlPanel * Bemerkungen: Enthaelt die inneren Klassen AngleControl, Holger Rohde WS 2005/2006 Seite 62 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. * * * Datei: * Datum: * * Historie: * * 21.12.05 * 10.12.05 * * 08.12.05 * */ package gui; DistanceControl, MiscControl und StrengthControl. ControlPanel.java 07.12.05 Rand um das Panel gelegt. Ausgabe der aktuellen Einstellungen bei Aufruf von "public void updateAnimation ()" und aktivem Debugging. 15 Pixel Abstand zwischen den einzelnen Kontrollbereichen gesetzt. import import import import import import import import java.awt.GridLayout; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.awt.event.AdjustmentEvent; java.awt.event.AdjustmentListener; javax.swing.JButton; javax.swing.JPanel; javax.swing.border.BevelBorder; import import import import import i18n.Messages; util.AppSetup; util.ExtScrollBar; util.ParameterSet; ani.AniPanel; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * Autor: Holger Rohde Version: 0.4 Das oberste Panel der unteren Kontrollelemente. Die Kontrollen werden ueber veschiedene innere Klassen zusammengebaut. oeffentliche Daten: ---------------------keine private Daten: ---------------------FAC - Standardfaktor fuer die Umrechnung der Ganzzahlen der Schieberegler in Gleitkommazahlen FAC_FORCE - Faktor fuer die Umrechnung des Schiebereglers maxForce FAC_ANGLE - Faktor fuer die Umrechnung der Schieberegler fuer Winkel serialVersionUID - Da JPanel das Interace Serializable implementiert ist diese Variable notwendig (hat hier aber keine weitere Funktion) messages - Referenz auf die Internationalisierungsklasse aniPanel - Referenz auf die Animation parameter - Die aktuell eingestellten Werte der Kontrollen defParameter - Standardwerte zum Zuruecksetzen der Kontrollen oeffentliche Methoden: ---------------------- Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 63 von 98 * updateAnimation * * private Methoden: * ---------------------* * keine * */ public class ControlPanel extends JPanel { private static int FAC = 100; private static int FAC_FORCE = 1000; private static int FAC_ANGLE = 1; private private private private private static final long serialVersionUID = 1; Messages messages = null; AniPanel aniPanel = null; ParameterSet parameter = new ParameterSet (); ParameterSet defParameter = new ParameterSet (); public ControlPanel (Messages messages, AniPanel aniPanel) { this.messages = messages; this.aniPanel = aniPanel; GridLayout grid = new GridLayout (1, 4); grid.setHgap (15); this.setLayout (grid); this.setBorder (new BevelBorder (BevelBorder.LOWERED)); this.add (new AngleControl ()); this.add (new DistanceControl ()); this.add (new StrengthControl ()); this.add (new MiscControl ()); } /* * Ubergeben geaenderter Werte an die Animation. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void updateAnimation () { aniPanel.updateFlockManager (parameter); if (AppSetup.debug == true) { System.out.println (parameter); }; } /* * * * * * * * Kontrollelemente fuer die Winkelparamter des Algorithmus. oeffentliche Daten: ---------------------keine Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 64 von 98 * private Daten: * ---------------------* * serialVersionUID - Da JPanel das Interace Serializable * implementiert ist diese Variable notwendig (hat * hier aber keine weitere Funktion) * reset - Button zum Zuruecksetzen der Werte * alignAngle - Schieberegler fuer die Kraft "alignment" * cohAngle - Schieberegler fuer die Kraft "cohesion" * sepAngle - Schieberegler fuer die Kraft "seperation" * actListener - Listener fuer die Zuruecksetzen-Funktion * adjListener - Listener fuer die Schieberegler * * oeffentliche Methoden: * ---------------------* * keine * * private Methoden: * ---------------------* * keine * */ private class AngleControl extends JPanel { private static final long serialVersionUID = 1; private JButton reset = null; private ExtScrollBar alignAngle = null; private ExtScrollBar cohAngle = null; private ExtScrollBar sepAngle = null; private AngleControl () { GridLayout grid = new GridLayout (4, 1); reset = new JButton (messages.getString ("reset_angle")); /* Schieberegler fuer die Winkel jeweils mit Min 1 und Max 180 */ alignAngle = new ExtScrollBar (messages.getString ( "alignment_angle"), (int) parameter.getAlignAngle (), 1, 180); cohAngle = new ExtScrollBar (messages.getString ( "cohesion_angle"), (int) parameter.getCohAngle (), 1, 180); sepAngle = new ExtScrollBar (messages.getString ( "seperation_angle"), (int) parameter.getSepAngle (), 1, 180); reset.addActionListener (actListener); alignAngle.addAdjustmentListener (adjListener); cohAngle.addAdjustmentListener (adjListener); sepAngle.addAdjustmentListener (adjListener); this.setLayout (grid); this.add (cohAngle); this.add (sepAngle); this.add (alignAngle); this.add (reset); } private ActionListener actListener = new ActionListener () Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 65 von 98 { public void actionPerformed (ActionEvent e) { alignAngle.setFloatValue (FAC_ANGLE, defParameter.getAlignAngle ()); cohAngle.setFloatValue (FAC_ANGLE, defParameter.getCohAngle ()); sepAngle.setFloatValue (FAC_ANGLE, defParameter.getSepAngle ()); updateAnimation (); } }; private AdjustmentListener adjListener = new AdjustmentListener () { public void adjustmentValueChanged (AdjustmentEvent e) { alignAngle.updateToolTip (); cohAngle.updateToolTip (); sepAngle.updateToolTip (); parameter.setAlignAngle ( alignAngle.getFloatValue (FAC_ANGLE)); parameter.setCohAngle (cohAngle.getFloatValue (FAC_ANGLE)); parameter.setSepAngle (sepAngle.getFloatValue (FAC_ANGLE)); updateAnimation (); } }; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Kontrollelemente fuer die Distanzparamter des Algorithmus. oeffentliche Daten: ---------------------keine private Daten: ---------------------serialVersionUID - Da JPanel das Interace Serializable implementiert ist diese Variable notwendig (hat hier aber keine weitere Funktion) reset - Button zum Zuruecksetzen der Werte alignDistance - Schieberegler fuer die Kraft "alignment" cohDistance - Schieberegler fuer die Kraft "cohesion" sepDistance - Schieberegler fuer die Kraft "seperation" actListener - Listener fuer die Zuruecksetzen-Funktion adjListener - Listener fuer die Schieberegler oeffentliche Methoden: ---------------------keine private Methoden: ---------------------keine Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 66 von 98 */ private class DistanceControl extends JPanel { private static final long serialVersionUID = 1; private JButton reset = null; private ExtScrollBar alignDistance = null; private ExtScrollBar cohDistance = null; private ExtScrollBar sepDistance = null; private DistanceControl () { GridLayout grid = new GridLayout (4, 1); reset = new JButton (messages.getString ("reset_distance")); /* Schieberegler fuer die Distanz jeweils mit Min 1 und Max 200 */ alignDistance = new ExtScrollBar (messages.getString ( "alignment_distance"), (int) (parameter.getAlignDistance () * FAC), 1, 200); cohDistance = new ExtScrollBar (messages.getString ( "cohesion_distance"), (int) (parameter.getCohDistance () * FAC), 1, 200); sepDistance = new ExtScrollBar (messages.getString ( "seperation_distance"), (int) (parameter.getSepDistance () * FAC), 1, 200); reset.addActionListener (actListener); alignDistance.addAdjustmentListener (adjListener); cohDistance.addAdjustmentListener (adjListener); sepDistance.addAdjustmentListener (adjListener); this.setLayout (grid); this.add (cohDistance); this.add (sepDistance); this.add (alignDistance); this.add (reset); } private ActionListener actListener = new ActionListener () { public void actionPerformed (ActionEvent e) { alignDistance.setFloatValue (FAC, defParameter.getAlignDistance ()); cohDistance.setFloatValue (FAC, defParameter.getCohDistance ()); sepDistance.setFloatValue (FAC, defParameter.getSepDistance ()); updateAnimation (); } }; private AdjustmentListener adjListener = new AdjustmentListener () { public void adjustmentValueChanged (AdjustmentEvent e) { alignDistance.updateToolTip (); cohDistance.updateToolTip (); sepDistance.updateToolTip (); Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 67 von 98 parameter.setAlignDistance ( alignDistance.getFloatValue (FAC)); parameter.setCohDistance (cohDistance.getFloatValue (FAC)); parameter.setSepDistance (sepDistance.getFloatValue (FAC)); updateAnimation (); } }; } /* * Kontrollelemente fuer allgemeine Parameter der Simualtion. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * serialVersionUID - Da JPanel das Interace Serializable * implementiert ist diese Variable notwendig (hat * hier aber keine weitere Funktion) * reset - Button zum Zuruecksetzen der Werte * maxForce - Schieberegler fuer die maximale Kraft die auf * Voegel einwirken darf * maxSpeed - Schieberegler fuer die maximale Geschwindigkeit * der Voegel * birdCount - Schieberegler fuer die Anzahl der Voegel pro * Schwarm * actListener - Listener fuer die Zuruecksetzen-Funktion * adjListener - Listener fuer die Schieberegler * * oeffentliche Methoden: * ---------------------* * keine * * private Methoden: * ---------------------* * keine * */ private class MiscControl extends JPanel { private JButton reset = null; private ExtScrollBar maxForce = null; private ExtScrollBar maxSpeed = null; private ExtScrollBar birdCount = null; private static final long serialVersionUID = 1; private MiscControl () { GridLayout grid = new GridLayout (4, 1); reset = new JButton (messages.getString ("reset_misc")); /* Schieberegler fuer die Distanz jeweils mit Min 1 und Max 50 maxForce = new ExtScrollBar (messages.getString ("max_force"), Holger Rohde */ WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 68 von 98 (int) (parameter.getMaxForce () * FAC_FORCE), 1, 50); maxSpeed = new ExtScrollBar (messages.getString ("max_speed"), (int) (parameter.getMaxSpeed () * FAC), 1, 20); birdCount = new ExtScrollBar (messages.getString ("bird_count"), parameter.getBirdCount (), 1, AppSetup.bird_count_max); reset.addActionListener (actListener); maxForce.addAdjustmentListener (adjListener); maxSpeed.addAdjustmentListener (adjListener); birdCount.addAdjustmentListener (adjListener); this.setLayout (grid); this.add (maxForce); this.add (maxSpeed); this.add (birdCount); this.add (reset); } private ActionListener actListener = new ActionListener () { public void actionPerformed (ActionEvent e) { maxForce.setFloatValue (FAC_FORCE, defParameter.getMaxForce ()); maxSpeed.setFloatValue (FAC, defParameter.getMaxSpeed ()); birdCount.setFloatValue (1, defParameter.getBirdCount ()); updateAnimation (); } }; private AdjustmentListener adjListener = new AdjustmentListener () { public void adjustmentValueChanged (AdjustmentEvent e) { maxForce.updateToolTip (); maxSpeed.updateToolTip (); birdCount.updateToolTip (); parameter.setMaxForce (maxForce.getFloatValue (FAC_FORCE)); parameter.setMaxSpeed (maxSpeed.getFloatValue (FAC)); parameter.setBirdCount (birdCount.getValue ()); updateAnimation (); } }; } /* * * * * * * * * * * * * Kontrollelemente fuer die Gewichtung der Paramter des Algorithmus. oeffentliche Daten: ---------------------keine private Daten: ---------------------serialVersionUID - Da JPanel das Interace Serializable implementiert ist diese Variable notwendig (hat Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 69 von 98 * hier aber keine weitere Funktion) * reset - Button zum Zuruecksetzen der Werte * alignStrength - Schieberegler fuer die Kraft "alignment" * cohStrength - Schieberegler fuer die Kraft "cohesion" * sepStrength - Schieberegler fuer die Kraft "seperation" * actListener - Listener fuer die Zuruecksetzen-Funktion * adjListener - Listener fuer die Schieberegler * * oeffentliche Methoden: * ---------------------* * keine * * private Methoden: * ---------------------* * keine * */ private class StrengthControl extends JPanel { private static final long serialVersionUID = 1; private JButton reset = null; private ExtScrollBar alignStrength = null; private ExtScrollBar cohStrength = null; private ExtScrollBar sepStrength = null; private StrengthControl () { GridLayout grid = new GridLayout (4, 1); reset = new JButton (messages.getString ("reset_strength")); /* Schieberegler fuer die Distanz jeweils mit Min 1 und Max 100 */ alignStrength = new ExtScrollBar (messages.getString ( "alignment"), (int) (parameter.getAliStrength () * FAC)); cohStrength = new ExtScrollBar (messages.getString ("cohesion"), (int) (parameter.getCohStrength () * FAC)); sepStrength = new ExtScrollBar (messages.getString ( "seperation"), (int) (parameter.getSepStrength () * FAC)); reset.addActionListener (actListener); alignStrength.addAdjustmentListener (adjListener); cohStrength.addAdjustmentListener (adjListener); sepStrength.addAdjustmentListener (adjListener); this.setLayout (grid); this.add (cohStrength); this.add (sepStrength); this.add (alignStrength); this.add (reset); } private ActionListener actListener = new ActionListener () { public void actionPerformed (ActionEvent e) { alignStrength.setFloatValue (FAC, Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 70 von 98 defParameter.getAliStrength ()); cohStrength.setFloatValue (FAC, defParameter.getCohStrength ()); sepStrength.setFloatValue (FAC, defParameter.getSepStrength ()); updateAnimation (); } }; private AdjustmentListener adjListener = new AdjustmentListener () { public void adjustmentValueChanged (AdjustmentEvent e) { alignStrength.updateToolTip (); cohStrength.updateToolTip (); sepStrength.updateToolTip (); parameter.setAliStrength (alignStrength.getFloatValue (FAC)); parameter.setCohStrength (cohStrength.getFloatValue (FAC)); parameter.setSepStrength (sepStrength.getFloatValue (FAC)); updateAnimation (); } }; } } 5.2.2.2 InfoPanel.java /* * Klasse(n): InfoPanel * Bemerkungen: * * Datei: InfoPanel.java Autor: Holger Rohde * Datum: 17.12.05 Version: 0.2 * * Historie: * * 26.12.05 - Aktualisierungsrate einstellbar ueber Konstante. */ package gui; import java.awt.GridLayout; import javax.swing.JLabel; import javax.swing.JPanel; import i18n.Messages; import util.Timer; /* * * * * * * * * * * * * * Erweiterung der Klasse JPanel zur Anzeige der Simulationsmesswerte. Die Werte werden ueber Labels ausgegeben. oeffentliche Daten: ---------------------keine private Daten: ---------------------UPD_ITR - Aktualisierungsrate des Panels serialVersionUID - Da JPanel das Interace Serializable implementiert ist diese Variable notwendig (hat Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 71 von 98 * hier aber keine weitere Funktion) * messages - Referenz auf die Internationalisierungsklasse * timeValue - JLabel zur Anzeige der Rechenzeit * avgValue - JLabel zur Anzeige der Durchschnittszeit * hitsValue - JLabel zur Anzeige der durlaufenen Iterationen * totalValue - JLabel zur Anzeige der Gesamtzeit * updateIter - Hilfsvariable fuer die Aktualisierungsrate * * oeffentliche Methoden: * ---------------------* * getString * * private Methoden: * ---------------------* * keine * */ public class InfoPanel extends JPanel { private static int UPD_ITR = 5; private private private private private private private static final long serialVersionUID = 1; Messages messages = null; JLabel timeValue = new JLabel ("0"); JLabel avgValue = new JLabel ("0"); JLabel hitsValue = new JLabel ("0"); JLabel totalValue = new JLabel ("0"); int updateIter = 0; public InfoPanel (Messages messages) { this.messages = messages; JLabel timeLabel = new JLabel (messages.getString ("info_time") + ":"); JLabel avgLabel = new JLabel (messages.getString ("info_avg") + ":"); JLabel hitsLabel = new JLabel (messages.getString ("info_frames") + ":"); JLabel totalLabel = new JLabel (messages.getString ("info_total") + ":"); this.setLayout (new GridLayout ()); this.add (new JLabel ()); this.add (timeLabel); this.add (timeValue); this.add (avgLabel); this.add (avgValue); this.add (totalLabel); this.add (totalValue); this.add (hitsLabel); this.add (hitsValue); } /* * Aktualisierung der Werte des Panel. * * Eingabeparameter: Timer timer Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. * Ausgabeparameter: * Fehlerausgaenge: */ public void updateTime (Timer timer) { updateIter++; /* Aktualisierung nur nach jeweils UPD_ITR Aufrufen if (updateIter == UPD_ITR) { updateIter = 0; timeValue.setText (timer.getTime ()); avgValue.setText (timer.getAvg ()); hitsValue.setText (timer.getHits ()); totalValue.setText (timer.getTotal ()); }; } Seite 72 von 98 */ } 5.2.2.3 MainFrame.java /* * Klasse(n): MainFrame * Bemerkungen: Enthaelt die innere Klasse FrameMenu. * * Datei: MainFrame.java Autor: Holger Rohde * Datum: 01.11.05 Version: 1.1 * * Historie: * * 28.12.05 - JMenuItem im Einstellungsmenue in JCheckBoxMenuItem * geaendert. * 27.12.05 - Das Ueberlagern des Menu durch die Animation behoben * (http://forum.java.sun.com/thread.jspa?threadID=595810& * messageID=3887806). * 26.12.05 - Menuepunkt "Hindernisse" hinzugefuegt. / Parameter -t zur * Aktivierung des Testmodus hinzugefuegt. * 25.12.05 - Menuepunkt "Vogel Begrenzung" hinzugefuegt. * 23.12.05 - Parameter -p zur Aktivierung der parallelen Variante in * die Auswertung der Argumente hinzugefuegt. * 22.12.05 - Groessenanpassung des Anwendungsfensters deaktiviert. * 20.12.05 - Menuepunkt "Welt Begrenzung" hinzugefuegt. * 19.12.05 - Innere Klasse FrameMenu hinzugefuegt. * 17.12.05 - InfoPanel hinzugefuegt. * 07.12.05 - ControlPanel hinzugefuegt. */ package gui; import import import import import import import import import import import java.awt.BorderLayout; java.awt.event.ActionEvent; java.awt.event.ActionListener; javax.swing.JCheckBoxMenuItem; javax.swing.JFrame; javax.swing.JMenu; javax.swing.JMenuBar; javax.swing.JMenuItem; javax.swing.SwingUtilities; javax.swing.UIManager; javax.swing.UnsupportedLookAndFeelException; import i18n.Messages; import util.AppSetup; Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 73 von 98 import ani.AniPanel; /* * Oberstes Fenster der Anwendung und main-Methode. * * oeffentliche Daten: * ---------------------* keine * * private Daten: * ---------------------* * BENCH_FORCE - Maximale Kraft die auf die Voegel im Testmodus * einwirkt * BENCH_SPEED - Geschwindigkeit der Voegel im Testmodus * BENCH_MAX_BIRDS - Die maximale Vogel-Anzahl im Testmodus * serialVersionUID - Da JFrame das Interace Serializable * implementiert ist diese Variable notwendig (hat * hier aber keine weitere Funktion) * messages - Klasse mit gekapseltem Zugriff auf die * Internationalisierungsdatei * info - Das Panel mit den aktuellen Messwerten des * Algorithmus * ani - Das Panel mit der Java3D Animation * control - Das Panel mit den Kontrollelementen zur * Steuerung der Simulationsparameter * * * oeffentliche Methoden: * ---------------------* * main * * private Methoden: * ---------------------* * keine * */ public class MainFrame extends JFrame { private static float BENCH_FORCE = 0.05F; private static float BENCH_SPEED = 0.2F; private static int BENCH_MAX_BIRDS = 1000; private private private private private static final long serialVersionUID = 1; Messages messages = new Messages (); InfoPanel info = new InfoPanel (messages); AniPanel ani = new AniPanel (info); ControlPanel control = new ControlPanel (messages, ani); public MainFrame () { this.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); this.setTitle (messages.getString ("title")); this.setLayout (new BorderLayout ()); this.setJMenuBar (new FrameMenu ()); this.setResizable (false); Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 74 von 98 this.add (info, BorderLayout.NORTH); this.add (ani, BorderLayout.CENTER); this.add (control, BorderLayout.SOUTH); this.pack (); this.setVisible (true); } /* * Startpunkt der Anwendung. Die uebergebenen Argumente werden * ausgewertet und das Fenster erzeugt. * * Eingabeparameter: String[] args * Ausgabeparameter: * Fehlerausgaenge: NumberFormatException * ClassNotFoundException * InstantiationException * IllegalAccessException * UnsupportedLookAndFeelException */ public static void main (String[] args) { for (int i = 0; i < args.length; i++) { if ("-d".equals (args[i])) /* Statusmeldungen ausgeben { AppSetup.debug = true; } /* Anzahl der Voegel else if ("-b".equals (args[i].substring (0, 2))) { try { AppSetup.bird_count = Integer .parseInt (args[i].substring (2)); } catch (NumberFormatException e) { e.printStackTrace (); }; } else if ("-t".equals (args[i])) /* Testmodus { AppSetup.benchmark = true; AppSetup.force_def = BENCH_FORCE; AppSetup.speed_def = BENCH_SPEED; AppSetup.bird_count_max = BENCH_MAX_BIRDS; } else if ("-p".equals (args[i])) /* Parallele Variante nutzen { AppSetup.use_threads = true; } /*Anzahl Vogelschwaerme else if ("-f".equals (args[i].substring (0, 2))) { try { AppSetup.flock_count = Integer.parseInt (args[i] .substring (2)); } Holger Rohde */ */ */ */ */ WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 75 von 98 catch (NumberFormatException e) { e.printStackTrace (); }; }; }; /* Funktioniert nur vor der ersten Erstellung eines Frames try { UIManager.setLookAndFeel (UIManager .getSystemLookAndFeelClassName ()); } catch (ClassNotFoundException e) { e.printStackTrace (); } catch (InstantiationException e) { e.printStackTrace (); } catch (IllegalAccessException e) { e.printStackTrace (); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace (); }; /* Ausfuehrung durch den Event-Dispatching Thread SwingUtilities.invokeLater (new Runnable () { public void run () { MainFrame mf = new MainFrame (); } }); */ */ } /* * * * * * * * * * * * * * * * * * * * * Menu fuer die Anwendung. oeffentliche Daten: ---------------------keine private Daten: ---------------------serialVersionUID - Da JMenuBar das Interace Serializable implementiert ist diese Variable notwendig (hat hier aber keine weitere Funktion) menu_01 - Menuepunkt "Beenden" menu_11 - Menuepunkt "Vogel Begrenzung" menu_12 - Menuepunkt "Welt Begrenzung" menu_13 - Menuepunkt "Hindernisse" menuListener - Listener fuer Ereignisse im Menue oeffentliche Methoden: ---------------------- Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 76 von 98 * * keine * * private Methoden: * ---------------------* * keine * */ private class FrameMenu extends JMenuBar { private static final long serialVersionUID = 1; private JMenuItem menu_01 = null; private JCheckBoxMenuItem menu_11 = null; private JCheckBoxMenuItem menu_12 = null; private JCheckBoxMenuItem menu_13 = null; private FrameMenu () { JMenu menu_0 = new JMenu (messages.getString ("menu_0")); JMenu menu_1 = new JMenu (messages.getString ("menu_1")); menu_01 menu_11 menu_12 menu_13 = = = = new new new new JMenuItem (messages.getString ("menu_01")); JCheckBoxMenuItem (messages.getString ("menu_11")); JCheckBoxMenuItem (messages.getString ("menu_12")); JCheckBoxMenuItem (messages.getString ("menu_13")); menu_01.addActionListener (menuListener); menu_0.add (menu_01); menu_11.addActionListener (menuListener); menu_12.addActionListener (menuListener); menu_13.addActionListener (menuListener); menu_1.add (menu_11); menu_1.add (menu_12); menu_1.add (menu_13); /* Ueberlagerung der Menues verhindern menu_0.getPopupMenu ().setLightWeightPopupEnabled (false); menu_1.getPopupMenu ().setLightWeightPopupEnabled (false); */ menu_11.setSelected (AppSetup.bird_bounds); menu_12.setSelected (AppSetup.world_bounds); menu_13.setSelected (AppSetup.obstacles); this.add (menu_0); this.add (menu_1); } private ActionListener menuListener = new ActionListener () { public void actionPerformed (ActionEvent e) { /* Ausgabe des aufgerufenen Menuepunkts if (AppSetup.debug == true) { System.out.println (e); }; /* Menuepunkt Datei->Beenden if (menu_01.equals (e.getSource ())) Holger Rohde */ */ WS 2005/2006 Seite 77 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. { System.exit (0); } /* Menuepunnkt Einstellungen->Welt Begrenzungen else if (menu_11.equals (e.getSource ())) { ani.switchWorldBounds (); } /* Menuepunnkt Einstellungen->Vogel Begrenzungen else if (menu_12.equals (e.getSource ())) { ani.switchBirdBounds (); */ */ } /* Menuepunnkt Einstellungen->Hindernisse else if (menu_13.equals (e.getSource ())) { ani.switchObstacles (); }; */ } }; } } 5.2.3 Packet i18n 5.2.3.1 Messages.java /* * Klasse(n): * Bemerkungen: * * Datei: * Datum: * * Historie: * * 15. November * */ package i18n; Messages AppSetup.java 01.11.05 Autor: Holger Rohde Version: 0.2 2005 - Ausnahmebehandlung in "public String getString (String key)" erweitert. import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import util.AppSetup; /* * * * * * * * * * * * Klasse bestimmt die zum aktuellen Standort passende Internationalisierungsdatei und ermoeglicht den Zugriff auf diese. oeffentliche Daten: ---------------------keine private Daten: ---------------------- Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 78 von 98 * locale - Der aktuelle Standord aus der Klasse AppSetup * resMessages - Die zum Standort passende Internationalisierungsdatei * * oeffentliche Methoden: * ---------------------* * getString * * private Methoden: * ---------------------* * keine * */ public class Messages { private Locale locale = AppSetup.locale; private ResourceBundle resMessages = ResourceBundle.getBundle ( "i18n/MessagesBundle", locale); /* * Rueckgabe des zum Schluessel passenden Text aus dem aktuellen * ResourceBundle. * * Eingabeparameter: String key * Ausgabeparameter: String string * Fehlerausgaenge: MissingResourceException * NullPointerException * ClassCastException */ public String getString (String key) { String string = null; try { string = resMessages.getString (key); } catch (MissingResourceException e) { e.printStackTrace (); string = "MISSING RESSOURCE"; } catch (NullPointerException e) { e.printStackTrace (); string = "KEY IS NULL"; } catch (ClassCastException e) { e.printStackTrace (); string = "KEY MUST BE A STRING"; }; return string; } } Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 79 von 98 5.2.3.2 MessagesBundle_en_US.properties /* * Klasse(n): * Bemerkungen: Lokalisierungsdatei Englisch * * Datei: MessagesBundle_en_US.properties Autor: Holger Rohde * Datum: 01.11.05 Version: 0.7 * * Historie: * * 26.12.05 - Text menu_13 fuer das Anwendungsmenue hinzugefuegt. * 25.12.05 - Text menu_12 fuer das Anwendungsmenue hinzugefuegt. * 20.12.05 - Text menu_11 fuer das Anwendungsmenue hinzugefuegt. * 19.12.05 - Texte menu_0, menu_01 und menu_1 fuer das Anwendungsmenue * hinzugefuegt. * 17.12.05 - Texte info_time, info_avg, info_frames und info_total * fuer die Anzeige im Infopanel hinzugefuegt. * 07.12.05 - Texte reset_strength, reset_angle, reset_distance und * reset_misc fuer die Kotrollelemente hinzugefuegt. */ title = Flocking seperation = Seperation cohesion = Cohesion alignment = Alignment seperation_distance = Seperation Distance cohesion_distance = Cohesion Distance alignment_distance = Alignment Distance seperation_angle = Seperation Angle cohesion_angle = Cohesion Angle alignment_angle = Alignment Angle max_force = maximum Force max_speed = maximum Speed bird_count = Birds reset_strength = reset reset_angle = reset reset_distance = reset reset_misc = reset info_time = calculation time(ms) info_avg = average(ms) info_frames = iterations info_total = total time(ms) menu_0 = File menu_01 = Exit menu_1 menu_11 menu_12 menu_13 = = = = Settings World Bounds Bird Bounds Obstacles Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 80 von 98 5.2.3.3 MessagesBundle.properties /* * Klasse(n): * Bemerkungen: Standard Lokalisierungsdatei * * Datei: MessagesBundle.properties Autor: Holger Rohde * Datum: 01.11.05 Version: 0.7 * * Historie: * * 26.12.05 - Text menu_13 fuer das Anwendungsmenue hinzugefuegt. * 25.12.05 - Text menu_12 fuer das Anwendungsmenue hinzugefuegt. * 20.12.05 - Text menu_11 fuer das Anwendungsmenue hinzugefuegt. * 19.12.05 - Texte menu_0, menu_01 und menu_1 fuer das Anwendungsmenue * hinzugefuegt. * 17.12.05 - Texte info_time, info_avg, info_frames und info_total * fuer die Anzeige im Infopanel hinzugefuegt. * 07.12.05 - Texte reset_strength, reset_angle, reset_distance und * reset_misc fuer die Kotrollelemente hinzugefuegt. */ title = Schwarmverhalten seperation = Vermeidung cohesion = Zusammenhalt alignment = Ausrichtung seperation_distance = Vermeidungsdistanz cohesion_distance = Zusammenshaltdistanz alignment_distance = Ausrichtungsdistanz seperation_angle = Vermeidungswinkel cohesion_angle = Zusammenhaltswinkel alignment_angle = Ausrichtungswinkel max_force = maximale Kraft max_speed = maximale Geschwindigkeit bird_count = Vögel reset_strength = zurücksetzen reset_angle = zurücksetzen reset_distance = zurücksetzen reset_misc = zurücksetzen info_time = Rechenzeit(ms) info_avg = Durchschnitt(ms) info_frames = Iterationen info_total = Gesamtzeit(ms) menu_0 = Datei menu_01 = Beenden menu_1 menu_11 menu_12 menu_13 = = = = Einstellungen Welt Begrenzung Vogel Begrenzung Hindernisse Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 81 von 98 5.2.4 Packet util 5.2.4.1 AppSetup.java /* * Klasse(n): AppSetup * Bemerkungen: * * Datei: AppSetup.java Autor: Holger Rohde * Datum: 01.11.05 Version: 0.4 * * Historie: * * * 26.12.05 - Hinzufuegen der Varaiblen bechmark, BENCH_ITERATIONS und * obstacles. * 25.12.05 - Hinzufuegen der Variablen bird_bounds. * 23.12.05 - Hinzufuegen der Variablen "use_threads". */ package util; import java.awt.Dimension; import java.util.Locale; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Globale Variablen zur Anpassung der Simulation und des Programms. oeffentliche Daten: ---------------------locale animationSize use_threads debug benchmark BENCH_ITERATIONS world_bounds bird_bounds obstacles flock_count bird_count bird_count_max speed_def force_def INIT_WAKEUP BIRD_SIZE COH_ANGLE_DEF Holger Rohde - Aktueller Standort fuer die Internationalisierung - Groesse der Animation - Parallele Implementierung nutzen - Statusausgaben auf die Konsole schreiben - Spezieller Modus fuer die Leistungsmessung - Anzahl Iterationen fuer einen Testlauf (Anwendung wird nach Durchlaufen der Iterationen beendet und Ergebnis wird ausgegeben) - Anzeige der Grenzen der Vogelwelt - Anzeige des Kollisionsbereichs um den Vogel - Anzeige und Umfliegen von Hindernissen - Anzahl der Vogelschwaerme - Anzahl Voegel pro Schwarm - Im Kontrollbereich maximal einstellbare Vogelzahl - Maximale Geschwindigkeit des Vogels (0 < speed <= 0.2) - Maximale Kraft die auf den Vogel wirkt (0 < force <= 0.05) - Zeit in Millisekunden nach der die Simulation startet - Groesse des Vogelmodells - Blickwinkel des Vogels fuer Kraft "cohesion" (0 < angle <= 179) WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 82 von 98 * SEP_ANGLE_DEF - Blickwinkel des Vogels fuer Kraft "seperation" * (0 < angle <= 179) * ALIGN_ANGLE_DEF - Blickwinkel des Vogels fuer Kraft "alignment" * (0 < angle <= 179) * COH_DISTANCE_DEF - Distanz zu den Nachbarvoegeln fuer Kraft * "cohesion" (0 < distance <= 2) * SEP_DISTANCE_DEF - Distanz zu den Nachbarvoegeln fuer Kraft * "seperation" (0 < distance <= 2) * ALIGN_DISTANCE_DEF - Distanz zu den Nachbarvoegeln fuer Kraft * "alignment" (0 < distance <= 2) * COH_STRENGTH_DEF - Staerke der Kraft "cohesion" * (0 < strength <= 1) * SEP_STRENGTH_DEF - Staerke der Kraft "seperation" * (0 < strength <= 1) * ALIGN_STRENGTH_DEF - Staerke der Kraft "alignment" * (0 < strength <= 1) * * private Daten: * ---------------------* * keine * * oeffentliche Methoden: * ---------------------* * keine * * private Methoden: * ---------------------* * keine * */ public class AppSetup { // public static Locale locale = new Locale ("en", "US"); public static Locale locale = Locale.getDefault (); public static Dimension animationSize = new Dimension (1024, 768); public static boolean use_threads = true; public static boolean debug = false; public static boolean benchmark = false; public static int BENCH_ITERATIONS = 250; public static boolean world_bounds = true; public static boolean bird_bounds = true; public static boolean obstacles = true; public public public public public static static static static static int flock_count = 3; int bird_count = 20; int bird_count_max = 100; float speed_def = 0.03F; float force_def = 0.003F; public static long INIT_WAKEUP = 1; public static float BIRD_SIZE = 0.02F; public static float COH_ANGLE_DEF = 30; public static float SEP_ANGLE_DEF = 45; public static float ALIGN_ANGLE_DEF = 80; Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 83 von 98 public static float COH_DISTANCE_DEF = 1.0F; public static float SEP_DISTANCE_DEF = 1.0F; public static float ALIGN_DISTANCE_DEF = 1.5F; public static float COH_STRENGTH_DEF = 0.9F; public static float SEP_STRENGTH_DEF = 1.0F; public static float ALIGN_STRENGTH_DEF = 0.6F; } 5.2.4.2 BirdList.java /* * Klasse(n): BirdList * Bemerkungen: * * Datei: BirdList.java Autor: Holger Rohde * Datum: 03.11.05 Version: 0.2 * * Historie: * * 17.11.05 - Fehlerbehandlung in den Methoden ergaenzt. */ package util; import java.util.ArrayList; import ani.Bird; /* * Erweiterung der Klasse ArrayList zur Ablage von Objekten vom Typ * Bird. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * serialVersionUID - Da ArrayList das Interace Serializable * implementiert ist diese Variable notwendig (hat * hier aber keine weitere Funktion) * * oeffentliche Methoden: * ---------------------* * getBird * * private Methoden: * ---------------------* * keine * */ public class BirdList extends ArrayList { /* ArrayList implementiert Serializable */ Holger Rohde WS 2005/2006 Seite 84 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. private static final long serialVersionUID = 1; /* * Rueckgabe des Elements an der Stelle i und Typumwandlung zu * Bird. * * Eingabeparameter: int index * Ausgabeparameter: Bird ret * Fehlerausgaenge: ArrayIndexOutOfBoundsException */ public Bird getBird (int index) { Bird ret = null; try { ret = (Bird) get (index); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace (); }; return ret; } } 5.2.4.3 ExtScrollBar,java /* * Klasse(n): ExtScrollBar * Bemerkungen: * * Datei: ExtScrollBar.java * Datum: 06.12.05 * * Historie: * * 08.12.05 - Auf die Werte fuer das Maximum * uebergebenen Werte eingestellt * 07.12.05 - Verschiedene Konstruktoren zur * Standardwerten hinzugefuegt. */ package util; import import import import import /* * * * * * * * * * * Autor: Holger Rohde Version: 0.3 1 addiert damit die werden koennen. Erzeugung mit java.awt.GridLayout; java.awt.event.AdjustmentListener; javax.swing.JLabel; javax.swing.JPanel; javax.swing.JScrollBar; Erweiterung der Klasse JPanel. Das so erzeugte Panel enthaelt eine ScrollBar und ein Label fuer die Beschriftung. Die wichtigsten Methoden der ScrollBar werden durch eigene Methoden nach Aussen weitergegeben. Methoden zum Setzen und Abfragen von Gleitkommazahlen werden ergaenzt. oeffentliche Daten: ---------------------keine Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 85 von 98 * * private Daten: * ---------------------* * serialVersionUID - Da JPanel das Interace Serializable * implementiert ist diese Variable notwendig (hat * hier aber keine weitere Funktion) * MIN_DEF - Standard Minimum der ScrollBar * MAX_DEF - Standard Maximum der ScrollBar * EXT_DEF - Standard Schrittweite der ScrollBar * bar - Die interne ScrollBar * * oeffentliche Methoden: * ---------------------* * addAdjustmentListener - Listener zur internen ScrollBar * hinzufuegen * removeAdjustmentListener - Listener von der internen ScrollBar * entfernen * getValue - Wert der internen ScrollBar zurueckgeben * setValue - Wert der internen ScrollBar setzen * getFloatValue * setFloatValue * updateToolTip - Setzen des ToolTip der internen ScrollBar * setEnabled - Aktivieren oder Deaktivieren der internen * ScrollBar * * private Methoden: * ---------------------* * keine * */ public class ExtScrollBar extends JPanel { private static int MIN_DEF = 0; private static int MAX_DEF = 100; private static int EXT_DEF = 1; /* JPanel implementiert Serializable private static final long serialVersionUID = 1; private JScrollBar bar = null; */ public ExtScrollBar (String name, int val, int ext, int min, int max) { /* max + 1 da ansonsten nur max - 1 eingestellt werden koennte */ bar = new JScrollBar (JScrollBar.HORIZONTAL, val, ext, min, max + 1); JLabel label = new JLabel (name); GridLayout grid = new GridLayout (1, 2); this.updateToolTip (); this.setLayout (grid); this.add (label); this.add (bar); } public ExtScrollBar (String name, int value) { Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 86 von 98 this (name, value, EXT_DEF, MIN_DEF, MAX_DEF); } public ExtScrollBar (String name, int value, int min, int max) { this (name, value, EXT_DEF, min, max); } public void addAdjustmentListener (AdjustmentListener listener) { bar.addAdjustmentListener (listener); } public void removeAdjustmentListener (AdjustmentListener listener) { bar.removeAdjustmentListener (listener); } public int getValue () { return bar.getValue (); } public void setValue (int val) { bar.setValue (val); bar.setToolTipText (String.valueOf (val)); } /* * Zurueckgeben des aktuellen Werts der ScrollBar als Gleitkommazahl * nach Umrechnung anhand des uebergebenen Faktors. * * Eingabeparameter: int factor * Ausgabeparameter: float value * Fehlerausgaenge: */ public float getFloatValue (int factor) { float value = ((float) bar.getValue ()) / factor; return value; } /* * Setzen der ScrollBar auf die uebergebene Gleitkommazahl nach * Umrechnung zur Ganzzahl anhand des Faktors. * * Eingabeparameter: int factor, float value * Ausgabeparameter: * Fehlerausgaenge: */ public void setFloatValue (int factor, float value) { int val = (int) (value * factor); bar.setValue (val); bar.setToolTipText (String.valueOf (val)); } Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 87 von 98 public void updateToolTip () { bar.setToolTipText (String.valueOf (bar.getValue ())); } public void setEnabled (boolean val) { bar.setEnabled (val); } } 5.2.4.4 FlockList.java /* * Klasse(n): FlockList * Bemerkungen: * * Datei: FlockList.java Autor: Holger Rohde * Datum: 03.11.05 Version: 0.3 * * Historie: * * 23.12.05 - Hinzufuegen der Methode "public FlockThr getFlockThr * (int index)" fuer die paralle Berechnung der Simulation. * 17.11.05 - Fehlerbehandlung in den Methoden ergaenzt. */ package util; import java.util.ArrayList; import ani.FlockSeq; import ani.FlockThr; /* * Erweiterung der Klasse ArrayList zur Ablage von Objekten vom Typ * FlockSeq und FlockThr. * * oeffentliche Daten: * ---------------------* * keine * * private Daten: * ---------------------* * serialVersionUID - Da ArrayList das Interace Serializable * implementiert ist diese Variable notwendig (hat * hier aber keine weitere Funktion) * * oeffentliche Methoden: * ---------------------* * getFlock * getFlockThr * * private Methoden: * ---------------------* * keine * */ Holger Rohde WS 2005/2006 Seite 88 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. public class FlockList extends ArrayList { /* ArrayList implementiert Serializable private static final long serialVersionUID = 1; */ /* * Rueckgabe des Elements an der Stelle i und Typumwandlung zu * FlockSeq. * * Eingabeparameter: int index * Ausgabeparameter: FlockSeq ret * Fehlerausgaenge: ArrayIndexOutOfBoundsException */ public FlockSeq getFlock (int index) { FlockSeq ret = null; try { ret = (FlockSeq) get (index); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace (); }; return ret; } /* * Rueckgabe des Elements an der Stelle i und Typumwandlung zu * FlockThr. * * Eingabeparameter: int index * Ausgabeparameter: FlockThr ret * Fehlerausgaenge: ArrayIndexOutOfBoundsException */ public FlockThr getFlockThr (int index) { FlockThr ret = null; try { ret = (FlockThr) get (index); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace (); }; return ret; } } 5.2.4.5 ParameterSet.java /* * * * * * * Klasse(n): ParameterSet Bemerkungen: Datei: Datum: Holger Rohde ParameterSet.java 06.12.05 Autor: Holger Rohde Version: 0.3 WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 89 von 98 * Historie: * * 10.12.05 - Methode "public String toString ()" zur Ausgabe der * aktuellen Werte ueberschrieben. * 07.12.05 - Implementierung des Interface Cloneable. */ package util; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Zusammenfassung der fuer die Berechnung des Schwarmverhaltens benoetigten Daten um einen einfacheren Austausch von Aenderungen zwischen den Kontrollelementen und den Animationsklassen zu Ermoeglichen. oeffentliche Daten: ---------------------keine private Daten: ---------------------birdCount maxSpeed maxForce - Anzahl der Voegel - Maximale Geschwindigkeit eines Vogels - Maximale Kraft die in einer Iteration auf einen Vogel wirken kann cohAngle - Blickwinkel des Vogels fuer Kraft "cohesion" sepAngle - Blickwinkel des Vogels fuer Kraft "seperation" alignAngle - Blickwinkel des Vogels fuer Kraft "alignment" cohDistance - Distanz zu den Nachbarvoegeln fuer Kraft "cohesion" sepDistance - Distanz zu den Nachbarvoegeln fuer Kraft "seperation" alignDistance - Distanz zu den Nachbarvoegeln fuer Kraft "alignment" cohStrength - Staerke der Kraft "cohesion" sepStrength - Staerke der Kraft "seperation" aliStrength - Staerke der Kraft "alignment" oeffentliche Methoden: ---------------------clone toString getAlignAngleCos getCohAngleCos getSepAngleCos Getter / Setter: getAlignAngle setAlignAngle getAlignDistance setAlignDistance getAliStrength setAliStregth getBirdCount setBirdCount getCohAngle setCohAngle Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 90 von 98 * getCohDistance * setCohDistance * getCohStrength * setCohStrength * getMaxForce * setMaxForce * getMaxSpeed * setMaxSpeed * getSepAngle * setSepAngle * getSepDistance * setSepDistance * getSepStrength * setSepStrength * * private Methoden: * ---------------------* * keine * */ public class ParameterSet implements Cloneable { private int birdCount = AppSetup.bird_count; private float maxSpeed = AppSetup.speed_def; private float maxForce = AppSetup.force_def; private float cohAngle = AppSetup.COH_ANGLE_DEF; private float sepAngle = AppSetup.SEP_ANGLE_DEF; private float alignAngle = AppSetup.ALIGN_ANGLE_DEF; private float cohDistance = AppSetup.COH_DISTANCE_DEF; private float sepDistance = AppSetup.SEP_DISTANCE_DEF; private float alignDistance = AppSetup.ALIGN_DISTANCE_DEF; private float cohStrength = AppSetup.COH_STRENGTH_DEF; private float sepStrength = AppSetup.SEP_STRENGTH_DEF; private float aliStrength = AppSetup.ALIGN_STRENGTH_DEF; /* * Implementierung aus Interface Cloneable zur Erzeugung einer Kopie * der Klasse. * * Eingabeparameter: * Ausgabeparameter: Object clone * Fehlerausgaenge: */ public Object clone () throws CloneNotSupportedException { Object clone = super.clone (); return clone; } /* * Darstellung der Klassenvariablen als Zeichenkette durch * Ueberschreiben der Methode in Klasse Object. * * Eingabeparameter: * Ausgabeparameter: String string * Fehlerausgaenge: */ public String toString () { Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 91 von 98 StringBuffer string = new StringBuffer (); string.append string.append string.append string.append string.append string.append string.append string.append string.append string.append string.append string.append string.append string.append ("------------ParameterSet------------\n"); ("birdCount: " + birdCount + "\n"); ("maxSpeed: " + maxSpeed + "\n"); ("maxForce: " + maxForce + "\n"); ("cohAngle: " + cohAngle + "\n"); ("sepAngle: " + sepAngle + "\n"); ("alignAngle: " + alignAngle + "\n"); ("cohDistance: " + cohDistance + "\n"); ("sepDistance: " + sepDistance + "\n"); ("alignDistance: " + alignDistance + "\n"); ("cohStrength: " + cohStrength + "\n"); ("sepStrength: " + sepStrength + "\n"); ("aliStrength: " + aliStrength + "\n"); ("------------------------------------\n"); return string.toString (); } public float getAlignAngle () { return alignAngle; } public void setAlignAngle (float alignAngle) { this.alignAngle = alignAngle; } /* * Cosinus von alignAngle bestimmen und zurueckgeben. * * Eingabeparameter: * Ausgabeparameter: float alignAngleCos * Fehlerausgaenge: */ public float getAlignAngleCos () { /* Umrechnung in Bogenmass und Ermitteln des Cosinus float alignAngleCos = (float) Math.cos ( (alignAngle / 180F) * Math.PI); */ return alignAngleCos; } public float getAlignDistance () { return alignDistance; } public void setAlignDistance (float alignDistance) { this.alignDistance = alignDistance; } public float getAliStrength () { return aliStrength; } Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 92 von 98 public void setAliStrength (float aliStrength) { this.aliStrength = aliStrength; } public int getBirdCount () { return birdCount; } public void setBirdCount (int birdCount) { this.birdCount = birdCount; } public float getCohAngle () { return cohAngle; } public void setCohAngle (float cohAngle) { this.cohAngle = cohAngle; } /* * Cosinus von cohAngle bestimmen und zurueckgeben. * * Eingabeparameter: * Ausgabeparameter: float cohAngleCos * Fehlerausgaenge: */ public float getCohAngleCos () { /* Umrechnung in Bogenmass und Ermitteln des Cosinus float cohAngleCos = (float) Math.cos ( (cohAngle / 180F) * Math.PI); */ return cohAngleCos; } public float getCohDistance () { return cohDistance; } public void setCohDistance (float cohDistance) { this.cohDistance = cohDistance; } public float getCohStrength () { return cohStrength; } public void setCohStrength (float cohStrength) { this.cohStrength = cohStrength; Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 93 von 98 } public float getMaxForce () { return maxForce; } public void setMaxForce (float maxForce) { this.maxForce = maxForce; } public float getMaxSpeed () { return maxSpeed; } public void setMaxSpeed (float maxSpeed) { this.maxSpeed = maxSpeed; } public float getSepAngle () { return sepAngle; } public void setSepAngle (float sepAngle) { this.sepAngle = sepAngle; } /* * Cosinus von sepAngle bestimmen und zurueckgeben. * * Eingabeparameter: * Ausgabeparameter: float sepAngleCos * Fehlerausgaenge: */ public float getSepAngleCos () { /* Umrechnung in Bogenmass und Ermitteln des Cosinus float sepAngleCos = (float) Math.cos ( (sepAngle / 180F) * Math.PI); */ return sepAngleCos; } public float getSepDistance () { return sepDistance; } public void setSepDistance (float sepDistance) { this.sepDistance = sepDistance; } public float getSepStrength () Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 94 von 98 { return sepStrength; } public void setSepStrength (float sepStrength) { this.sepStrength = sepStrength; } } 5.2.4.6 Timer.java /* * Klasse(n): Timer * Bemerkungen: Nutzt die JAMon-Bibliothek aus "lib/JAMon.jar". * * Datei: Timer.java Autor: Holger Rohde * Datum: 18.12.05 Version: 0.2 * * Historie: * * 25.12.05 - Methode "public void print ()" zur Ausgabe der aktuellen * Werte der Messung hinzugefuegt. */ package util; import java.util.StringTokenizer; import com.jamonapi.Monitor; import com.jamonapi.MonitorFactory; /* * * * * * * * * * * * * * * * * * * * * * * * Implementierung einer Zeitmessung unter Verwendung der Bibliothek JAMon (http://jamonapi.com/). Es werden Methoden zum Starten und Stoppen der Zeitmessung und den Zugriff auf die Ergebnisse zur Verfuegung gestellt. Die durch die Bibliotheksfunktionen gelieferten Ergebnisse werden an die Anforderungen des Programms angepasst. oeffentliche Daten: ---------------------keine private Daten: ---------------------monitor - Instanz der Monitor-Klasse aus Bibliothek JAMon ueber die die Zeitmessung realisiert wird time - Zeit der letzen Messung avg - Durchschnittszeit aller Messsungen hits - Anzahl der durchgefuehrten Messungen total - Gesamtzeit aller durchgefuehrten Messungen oeffentliche Methoden: ---------------------- Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 95 von 98 * * start * stop * print * * Getter / Setter: * * getAvg * getHits * getTime * getTotal * * private Methoden: * ---------------------* * getTokens * */ public class Timer { private Monitor monitor = null; private String time = ""; private String avg = ""; private String hits = ""; private String total = ""; /* * Starten der Zeitmessung. Durch den ersten Aufruf wird eine neue * Instanz der Klasse Monitor erzeugt. Weitere Aufrufe nutzen die alte * Instanz. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void start () { monitor = MonitorFactory.start ("monitor"); } /* * Stoppen der Zeitmessung und Aufruf der internen Ergebissanpassung. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void stop () { monitor.stop (); this.getTokens (); } /* * * * * * * Auslesen der relevanten Werte des Monitor-Objekt und Aktualisierung der entsprechenden Variablen. Die Ergebnisse liegen als Zeichenkette vor und werden mit der Klasse StringTokenizer zerlegt. Eingabeparameter: Ausgabeparameter: Holger Rohde - WS 2005/2006 Seite 96 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. * Fehlerausgaenge: */ private void getTokens () { StringTokenizer tok = new StringTokenizer (monitor.toString ()); time = tok.nextToken (); tok.nextToken (); hits = tok.nextToken (); hits = hits.substring (6); avg = tok.nextToken (); avg = avg.substring (4); tok.nextToken (); total = tok.nextToken (); total = total.substring (6); /* Ueberspringen eines Tokens */ /* Ueberspringen eines Tokens */ } /* * Ausgabe der aktuellen Messwerte und der Vogel- und Schwarmanzahl * auf die Konsole. * * Eingabeparameter: * Ausgabeparameter: * Fehlerausgaenge: */ public void print () { System.out.print (AppSetup.bird_count + "\t"); System.out.print (AppSetup.flock_count + "\t"); System.out.print (avg + "\t"); System.out.print (total + "\t"); System.out.println (hits); } public String getAvg () { return avg; } public String getHits () { return hits; } public String getTime () { return time; } public String getTotal () { return total; } } 5.2.5 Skripte zum Übersetzen und Ausführen 5.2.5.1 benchmark.bat ::Tests ohne Threads Holger Rohde WS 2005/2006 Seite 97 von 98 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. java java java java java java java -cp -cp -cp -cp -cp -cp -cp lib/JAMon.jar;bin lib/JAMon.jar;bin lib/JAMon.jar;bin lib/JAMon.jar;bin lib/JAMon.jar;bin lib/JAMon.jar;bin lib/JAMon.jar;bin gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame -t -t -t -t -t -t -t -f3 -f3 -f3 -f3 -f3 -f3 -f3 -b10 > bench.log -b20 >> bench.log -b40 >> bench.log -b80 >> bench.log -b160 >> bench.log -b320 >> bench.log -b640 >> bench.log ::Tests mit je einem Thread pro Schwarm java -cp lib/JAMon.jar;bin gui.MainFrame java -cp lib/JAMon.jar;bin gui.MainFrame java -cp lib/JAMon.jar;bin gui.MainFrame java -cp lib/JAMon.jar;bin gui.MainFrame java -cp lib/JAMon.jar;bin gui.MainFrame java -cp lib/JAMon.jar;bin gui.MainFrame java -cp lib/JAMon.jar;bin gui.MainFrame -t -t -t -t -t -t -t -f3 -f3 -f3 -f3 -f3 -f3 -f3 -b10 -p > bench_thr.log -b20 -p >> bench_thr.log -b40 -p >> bench_thr.log -b80 -p >> bench_thr.log -b160 -p >> bench_thr.log -b320 -p >> bench_thr.log -b640 -p >> bench_thr.log 5.2.5.2 benchmark.sh #/bin/sh #Tests ohne Threads java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame -t -t -t -t -t -t -t -f3 -f3 -f3 -f3 -f3 -f3 -f3 -b10 > bench.log -b20 >> bench.log -b40 >> bench.log -b80 >> bench.log -b160 >> bench.log -b320 >> bench.log -b640 >> bench.log #Tests mit je einem Thread java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin java -cp lib/JAMon.jar:bin pro Schwarm gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame gui.MainFrame -t -t -t -t -t -t -t -f3 -f3 -f3 -f3 -f3 -f3 -f3 -b10 -p > bench_thr.log -b20 -p >> bench_thr.log -b40 -p >> bench_thr.log -b80 -p >> bench_thr.log -b160 -p >> bench_thr.log -b320 -p >> bench_thr.log -b640 -p >> bench_thr.log 5.2.5.3 compile.bat ::Uebersetzen der Anwendung ::alle Warnungen aktiviert javac -Xlint:all -target 1.4 -source 1.4 -cp lib/JAMon.jar;src -d bin src/i18n/*.java src/util/*.java src/gui/*.java src/ani/*.java ::Die Internationalisierungsdateien muessen manuell kopiert werden copy /y src\i18n\*.properties bin\i18n pause 5.2.5.4 compile.sh #/bin/sh #Uebersetzen der Anwendung #alle Warnungen aktiviert javac -Xlint:all -target 1.4 -source 1.4 -cp lib/JAMon.jar:src -d bin src/i18n/*.java src/util/*.java src/gui/*.java src/ani/*.java Holger Rohde WS 2005/2006 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Seite 98 von 98 #Die Internationalisierungsdateien muessen manuell kopiert werden cp src/i18n/*.properties bin/i18n 5.2.5.5 run.bat :: :: :: :: :: :: :: :: :: :: :: :: :: Moegliche Argumente: -d Ausgabe von Statusmeldungen -b Anzahl der Voegel z.B. -b40 -t Testmodus zur Leistungsmessung -p Anwendung nutzt einen Thread pro Schwarm -f Anzahl der Schwaerme z.B. -f3 Beispiel (3 Schwaerme mit jeweils 50 Voegeln und ein Thread pro Schwarm): java -cp lib/JAMon.jar;bin gui.MainFrame -p -f3 -b50 java -cp lib/JAMon.jar;bin gui.MainFrame 5.2.5.6 run.sh # # # # # # # # # # # # # Moegliche Argumente: -d -b -t -p -f Ausgabe von Statusmeldungen Anzahl der Voegel z.B. -b40 Testmodus zur Leistungsmessung Anwendung nutzt einen Thread pro Schwarm Anzahl der Schwaerme z.B. -f3 Beispiel (3 Schwaerme mit jeweils 50 Voegeln und ein Thread pro Schwarm): java -cp lib/JAMon.jar;bin gui.MainFrame -p -f3 -b50 java -cp lib/JAMon.jar:bin gui.MainFrame Holger Rohde WS 2005/2006