Projektarbeit. Thema: Entwicklung einer Modellierungs-Software für. Rotationskörper. (Surface of Revolution) Verfasser: Marc Hugo

Größe: px
Ab Seite anzeigen:

Download "Projektarbeit. Thema: Entwicklung einer Modellierungs-Software für. Rotationskörper. (Surface of Revolution) Verfasser: Marc Hugo"

Transkript

1 Projektarbeit Thema: Entwicklung einer Modellierungs-Software für Rotationskörper (Surface of Revolution) Verfasser: Marc Hugo (Matr. Nr.: ) Christian Kraus (Matr. Nr.: ) Prof. Dr. Michael Stark Fachhochschule Dortmund Fachbereich Informatik Studiengang Allgemeine Informatik November 2003

2 Inhaltsverzeichnis Inhaltsverzeichnis Inhaltsverzeichnis... I Vorwort Einführung Einführung in Java2D Grundobjekte Einführung in Java3D Der Aufbau des Szenengraphen Grundobjekte Oberflächeneigenschaften Beleuchtungsmodell Maussteuerung Einführung in PovRay Rotationskörper Das Programm Bedienoberfläche Menüleiste Schnellstartleiste Bearbeitungsbereich Ansichtsbereich Export und Weiternutzung Export Fenster Nutzung in PovRay Nutzung in VRML Nutzung in Java3D Projektverlauf Planung/Dokumentation Pflichtenheft Geschäftsprozessdiagramm Zustandsautomat OOA Klassendiagramm OOD Klassendiagramm Sequenzdiagramme I

3 Inhaltsverzeichnis 3.2 Eigenschaften der Klassen Hauptfenster (GUI) Ansicht2D Info2D Streckenzug Punkt2D Ansicht3D Kreis3D Dateiverwaltung/Export Probleme und Lösungen Datenstruktur Berechnung der Wandstärke Erstellen eines Rotationsobjektes Normalenvektoren Fazit...84 Anhang...III I Zusätzliche Quelltexte... III II Sachwortverzeichnis (Glossar)...XIII III Literaturverzeichnis...XV IV Abbildungsverzeichnis...XVII II

4 Vorwort Vorwort Das Projekt "Surface of Revolution" befasst sich, dem Namen entsprechend, mit "Rotationskörper". Genauer gesagt mit dem Erstellen eines Solchen. Ein Rotationskörper ist ein dreidimensionales Objekt, welches aus der Rotation einer zweidimensionale Kurve um eine Achse erzeugt wird. Abb. 1 Surface of Revolution (Rotationskörper) Die in [Abb. 1] dargestellten Punkte des linken Objektes definieren die Kurve, welche der Benutzer vorgibt. Dies geschieht in diesem Projekt durch das Klicken mit der Maus in ein 2D-Feld. Die Punkte werden der Reihenfolge entsprechend miteinander verbunden und bilden so den 2D-Streckenzug. Dieser wird dann, wie in [Abb. 1] angedeutet, um die Y-Achse gedreht, wodurch ein 3D-Körper entsteht (rechtes Objekt). Die Koordinaten dieses Körpers können durch dieses Programm direkt als PovRay, VRML oder Java3D- Quelltext entsprechend exportiert werden. Die Motivation ein solches Projekt zu entwickeln entstand während eines Seminars, bei dem ein Spiegellabyrinth mit PovRay erstellt wurde. Bei der Arbeit mit PovRay war zwar bekannt, dass es Rotationsköper gibt, aber durch die Schwierigkeit Objekte damit zu erstellen, konnte die Funktion Rotationskörper nicht benutzt werden. Um dieses Problem zu lösen, wurde in diesem Projekt ein grafischer Editor mit direkter Vorschau entwickelt, der das Erstellen eines Rotationskörpers vereinfacht. Die Schwierigkeit bei der Erstellung eines Rotationskörpers ist, dass man die Koordinaten der einzelnen Punkte des Streckenzuges per Hand angeben muss und selbst bei der besten gedanklich räumlichen Darstellung, fällt es schwer aus bloßen X und Y-Koordinaten einen Streckenzug zu formen, um diesen anschließend noch um eine virtuelle Achse zu drehen. 1

5 Vorwort Um das Erstellen eines solchen Objektes zu vereinfachen, wurde dieses Programm entwickelt. Es zeigt während des Erstellens des zweidimensionalen Streckenzuges bereits das dreidimensionale Objekt an. Man kann die Lage der 2D Punkte im Raum beliebig durch Drag&Drop verändern und sieht zeitgleich die Veränderung an dem dreidimensionalen Objekt. Als zusätzliches Feature existiert eine Funktion mit der man dem Objekt eine Wandstärke/Materialdicke verleihen kann, damit zum Beispiel eine Vase nicht papierdünn dargestellt wird. So eine Funktion muss in den meisten Grafikanwendungen "per Hand" erstellt werden. Besonders hilfreich ist dieses Werkzeug, wenn man quelltextbasierte Grafikwerkzeuge einsetzt, die keine grafische Möglichkeit zum Erstellen eines Rotationskörpers bieten. Mit dem Erzeugnis dieses Projekts kann man nach der Modellierung des 3D Körpers die 2D oder 3D Punkte in eine Textdatei schreiben, um diese in einem anderen Grafikwerkzeug weiter zu benutzen. Zusätzlich ist für PovRay 1, Java3D und VRML eine direkte Exportfunktion eingebaut, welche das gesamtes Objekt anwendungsspezifisch erzeugt. Der nachfolgende Text ist die Dokumentation des gesamten Projektes, welche die Planung, die Umsetzung, die Erstellung und die damit verbunden Schwierigkeiten und Lösungen beschreibt. 1 vgl. [PovRay] 2

6 1. Einleitung 1 Einführung In diesem Kapitel wird eine Einführung in die benutzen Pakete Java2D und Java3D, sowie zu PovRay gegeben. Wofür PovRay dient und was es leistet wird in der dazugehörigen Einführung [1.3 Einführung in PovRay] beschrieben. Zum jetzigen Zeitpunkt reicht das Wissen, dass PovRay ein 3D Raytracingwerkzeug ist, dass Quelltext basiert arbeitet. Um diese Projektdokumentation leicht verständlich zu erläutern, wird nur auf die Funktionen der Pakete eingegangen, die auch wirklich in diesem Projekt verwendet werden. Weiterführende Literatur zu den einzelnen Themen ist im Literaturverzeichnis [III Literaturverzeichnis] zu finden. Das gesamte Projekt wurde in der Programmiersprache Java realisiert. Java ist heutzutage, neben C++, eine der am meisten eingesetzten Sprachen. Sie ist plattformunabhängig und kann so auf allen gängigen Systemen zum Einsatz kommen. Durch Ihren objektorientierten und modularen Aufbau können auch noch nachträglich problemlos Teilbereiche erweitert werden. Java3D ist einer dieser Teilbereiche, welcher erst mit einer späteren Version implementiert worden ist. Dieser bietet aber wesentliche Vorteile gegenüber OpenGL, denn Java3D ist, genau wie Java, vollständig objektorientiert und plattformunabhängig. Java3D ist eine High-Level-API und basiert auf OpenGL oder DirectX, dadurch kann in diesem Projekt die Low-Level-API frei gewählt werden. 1.1 Einführung in Java2D Um überhaupt auf dem Bildschirm zeichnen zu können und nicht nur die in AWT oder Swing enthaltenen Standardkomponenten wie Buttons etc. verwenden zu müssen, benutzt man die Java 2D API. Bei der Java 2D API handelt es sich um eine Menge von Klassen für die zweidimensionale Grafikverarbeitung. Diese Menge von Klassen wird mit dem Standard JDK-Paket (Java Development Kit) ausgeliefert und ist somit auch zusammen mit Java überall nutzbar. Im JDK 1.0 und 1.1 war die Java2D API auch bereits, aber nur sehr primitiv mit wenigen Grafik-Funktionen, enthalten. Es konnten lediglich Linien gezeichnet und Text dargestellt werden. Ab dem JDK 1.2 gab es eine ganze Reihe von Erweiterungen, die das Arbeiten mit Java2D erheblich flexibler machten. Inzwischen gibt es die Möglichkeit neben Linien und Text auch geometrische Objekte, Strichstärken usw. zu benutzen. Die Möglichkeit von Transparenz wurden ebenfalls implementiert. Möglichkeiten von Java2D: - geometrische Formen - Farbkomposition und -zerlegung - verschiedene Pinselstriche, formatierter Text - Füllen von Umrissen mit Farben, Mustern oder Farbverläufen - (affine) geometrische Transformationen von Umrissen - Alpha-Werte (Transparenz) - Rendering-Optionen, z.b. Antialiasing, Clipping - Bildverarbeitung 3

7 1. Einleitung Für die Neuerungen muss man allerdings einen Preis bezahlen, denn sie bringen Performanceeinbußen. Diese sind aber zu verkraften, wenn man nicht gerade alle Effekte zeitgleich benutzt. An der Performance von Java wird noch immer mit Hochdruck gearbeitet, so bleibt für die Zukunft zu hoffen, dass sich die Leistungsfähigkeit weiter verbessert. Ab dem JDK 1.2 brachte ein neues Rendering-Konzept die Veränderungen und neuen Funktionen von Java2D. Dieses Rendering-Konzept ist eine Erweiterung des Rendering-Konzeptes des AWT Pakets mit dem man zum Beispiel einfache Figuren zeichnen, sowie die Figuren mit Farbe füllen konnte. Hierfür war in den vorherigen JDK-Versionen die Klasse java.awt.graphics zuständig. Sie hielt die dementsprechenden Möglichkeiten bereit. Der paint()- Methode der einzelnen Komponenten Component wurde das Graphics-Objekt übergeben und manipuliert. Durch die Generalisierung von Java2D ist es dann ab dem JDK 1.2 möglich nicht mehr nur einfache Figuren, sondern auch beliebig komplexe Formen zu zeichnen. Zu dem ist das Verarbeiten von Texturen oder das Verändern der Strichstärke hinzu gekommen. Die neuen Methoden können mit Hilfe der Klasse Graphics2d, die von der alten Klasse Graphics abgeleitet ist, benutzt werden. Da aber die Methode paint() nach wie vor ein Graphic Parameter übergeben bekommt, muss am Methodenanfang von paint() dieser Parameter mit einer Typ-Konvertierung umgewandelt werden. public void paint(graphics g) { Graphics2D g2 = (Graphics2D) g;... Die Java2D API ist über mehrere Klassen verteilt und nennt folgende Pakete ihr Eigen: - java.awt Benutzerschnittstelle und Grafikwerkzeuge - java.awt.color - Farben - java.awt.font - Schriftarten - java.awt.geom Geometrie - java.awt.print - Druckerunterstützung - java.awt.image Bildunterstützung - java.awt.image.renderable Bildverarbeitung 2 Innerhalb von Java2D werden zwei Koordinaten-Systeme unterschieden: User Space- Koordinaten, und Device Space-Koordinaten. Devices sind dabei Bildschirme, Drucker und Bild-Puffer. Der große Vorteil an der Java2D API ist, dass man sich um die Umwandlung zwischen den Koordinatensystemen nicht selbst kümmern muss, da dies die Rendering-Engine erledigt. Der User-Space in Java erstreckt sich von der linken oberen Ecke des Fensters zur rechten unteren Ecke, d.h. die obere linke Ecke hat die Koordinaten (0,0). Positive x-werte liegen weiter rechts, positive y-werte weiter unten. 2 vgl. [Dietsch] 4

8 1. Einleitung Koordinatensystem Ursprung (0,0) X+ Das Koordinatensystem von Java2D ist also identisch mit dem Koordinatensystem des Fenstersystems. Somit bekommt man dann, wenn man die Mausposition abfragt, auch Daten die dem Java2D Koordinatensystem entsprechen. Diese so erhaltenen Werte müssen anschließend noch umgerechnet werden, so dass diese dem "normalen" (kartesischen) Koordinatensystem entsprechen. Mehr Informationen dazu finden sie im Kapitel [3.2.5 Punkt2D]. 3 Y+ Abb. 2 Koordinatensystem Java2D Grundobjekte Zeichnen kann man auf allen Komponenten die eine paint() Methode besitzen, da diese Methode, wie schon im Kapitel [1.1 Einführung in Java2D] erwähnt, überschrieben bzw. erweitert werden muss, um die jeweilige Komponente zu beeinflussen. Man kann also auch auf Buttons oder anderen Elementen der Benutzeroberfläche zeichnen und somit seine "eigenen" Komponenten erstellen. Meistens wird jedoch ein Canvas oder ein JPanel verwendet, da diese Objekte als Container dienen, und somit eine freie Zeichenfläche zur Verfügung stellen. Werden Swing-Objekte benutzt, sollte man auch als Zeichenfläche eine Swing Komponente, zum Beispiel das JPanel, nehmen. Wird dies nicht beachtet, kann es zu Problemen mit Überdeckungen anderer Komponenten führen, siehe [Abb. 3]. Abb. 3 Beispiel Überdeckung von Swing durch AWT Komponenten 3 vgl. [Bablok] 5

9 1. Einleitung Es muss folglich die paint() Methode (AWT) oder die paintcomponent() Methode (Swing) überschrieben werden, um in Komponenten zeichnen zu können. Allerdings sollte man in der veränderten paint() bzw. paintcomponent() -Methode die ursprüngliche Methode über super.paintcomponent() aufrufen, um die Komponente zuerst zeichnen zu lassen bevor man sie verändert! Java2D funktioniert wie viele andere Grafik API`s auch (z.b. OpenGL) wie ein Zustandsautomat, mit einigen globalen Variablen. Möchte man zum Beispiel die Zeichenfarbe verändern, muss die dazugehörige globale Variable verändert werden. Die Zeichenfarbe bleibt so lange eingestellt, bis die globale Variable für die Zeichenfarbe wieder verändert wird. Da das Geheimnissprinzip in Java gewahrt bleibt, verändert man die globalen Variablen über get- und set-methoden, wie z.b. über setcolor(color.blue); die Zeichenfarbe. Als Parameter nimmt die Methode entweder die Standardfarben als vorgefertigte Konstanten mit Color.blue oder Color.red entgegen, oder es kann alternativ auf zwei weitere Arten eine Farbe definiert werden. Zum einen übergibt man der Methode drei int Werte, welche jeweils RGB repräsentieren und von definiert sind. Zum Anderen können der Methode drei float Werte, die zwischen 0 und 1 liegen, übergeben werden. Hält man sich nicht an diese Vorgaben wird die Ausnahme IllegalArgument- Exception ausgelöst. Mit Hilfe von Exemplaren, die sich um die Formatierungen kümmern, kann die Strichstärke, die Schriftfarbe etc. eingestellt werden. Strichstärke: BasicStroke staerke2 = new BasicStroke(5.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND); g2.setstroke(staerke2); Im obigen Beispiel wird ein neues Exemplar vom Typ BasicStroke erzeugt, welches die Strichstärke und andere Parameter einstellt. Wird dieses Exemplar mit g2.setstroke(staerke2); an die Zeichenfläche übergeben, erscheinen alle danach gezeichneten Striche in der vom Exemplar bestimmten Strichstärke. Schriftart: Font f = new Font("Dialog", Font.BOLD + Font.ITALIC, 24); g2.setfont(f); Auch bei der Schrift werden die Attribute wie Schriftart, Schriftgröße usw. durch dafür erzeugte Exemplare, die der Zeichenfläche übergeben werden, verändert. 6

10 1. Einleitung Es gibt eine Reihe von vorgefertigten Methoden, die das Zeichnen von 2D- Grundobjekten in vielerlei Hinsicht einfach gestalten. 4 Punkt 2 Punkt 1 Abb. 4 Definition einer Linie durch 2 Punkte Um zum Beispiel eine Linie zu zeichnen, gibt es die Methode drawline(int,int,int,int);, welche, wie man im Methodenaufruf sieht, vier int- Werte erwartet. Dies sind die X und Y Koordinaten von 2 Punkten, nämlich die Werte des Anfangs- und des Endpunktes der Strecke, welche man zeichnen möchte. Angegeben wird zuerst die X-, gefolgt von der Y-Koordinate des ersten Punktes. Dies geschieht analog für den zweiten Punkt. Höhe Um einen gefüllten Kreis oder eine Ellipse zu zeichnen, bedient man sich der Methode filloval(int,int,int,int);, welche vier Parameter erwartet. Die ersten beiden int Werte sind X-Koordinate und Y-Koordinate des Mittelpunktes. Der dritte Parameter ist die X- Ausdehnung, also der Durchmesser in X- Richtung. Der vierte Parameter verhält sich analog für die Y-Richtung. Abb. 5 Breite Definition einer Ellipse Möchte man also anstelle einer Ellipse einen runden Kreis zeichnen müssen der dritte und vierte Parameter gleich groß sein! 4 vgl. [Lemay] 7

11 1. Einleitung Im unten stehenden Bild erkennt man die zuvor angesprochenen Java2D Funktionalitäten. Der Button wurde zum Beispiel ein wenig verändert. Der Quelltext zu diesem Beispiel befindet sich im Anhang [I Zusätzliche Quelltexte] Abb. 6 Java2D Beispiel 8

12 1. Einleitung 1.2 Einführung in Java3D Genauso wie Java2D ist auch Java3D eine Klassenbibliothek, die den Funktionsumfang von Java beträchtlich erweitert. Erst durch Java3D ist es möglich, realwirkende 3D Figuren über einfache Befehle darzustellen. Java3D bietet eine Datenstruktur mit der man virtuelle 3D Objekte oder ganze 3D Welten erstellen kann. Java3D ist im Gegensatz zu Java2D nicht standardmäßig in dem JDK 1.4 Paket enthalten. Dadurch muss jeder, der Java3D nutzen möchte, dieses als separates Zusatzpaket von der Java-Sun Seite herunter laden. Die API ist für alle gängigen Betriebssysteme verfügbar und mit der jeweiligen heruntergeladenen Version wird entschieden, ob OpenGL oder DirectX als Low-API benutzten werden soll. Die OpenGL Variante ist allerdings aus performancetechnischen Gesichtspunkten entpfehlenswerter. Java3D bietet eindeutige Vorteile gegenüber anderen 3D-Sprachen. Es ist Teil einer richtigen Programmiersprache und dadurch universeller einsetzbar und auch plattformunabhängig. Es beinhaltet sehr umfangreiche Vektor- und Matrizen- Operationen, sowie Sound, ist zudem objektorientiert, so dass sich auch komplexe Anwendungen relativ einfach durch den modularen Aufbau realisieren lassen. Es besitzt eine gute Schnittstelle für Interaktion und zur photorealistischen Darstellung, eine Datenbankanbindung ist auch leicht möglich. Es ist absolut kostenlos und besitz Loader-Bibliotheken für andere Grafikdefinitionen, z.b. VRML. Ein weiterer Vorteil ist, dass es auf asynchron arbeitenden Threads basiert, so dass das Graphikrendering, die Soundberechnung und Animation, sowie die Steuerung über die Eingabegeräte parallel verarbeitet werden können! Selbstverständlich existieren auch einige Nachteile. Java3D ist relativ komplex und benötigt eine gewisse Einarbeitungszeit. Zudem ist es sehr umfangreich, so dass wohl die passende Lösung existiert, aber man diese, wie die Nadel im Heuhaufen, erst einmal finden muss! Für Transformationen und Matrizenmultiplikationen sind Lineare Algebra Kenntnisse empfehlenswert. Es ist nicht abwärtskompatibel und die Spezifikationen sind an sehr vielen Stellen noch nicht fertiggestellt oder können sich schnell ändern. Das aber wohl größte Manko ist, dass es nicht standardmäßig mit installiert wird und jeder Benutzer es erst herunterladen und installieren muss. 5 5 vgl. [Buschmann] 9

13 1. Einleitung Der Aufbau des Szenengraphen Der Szenengraph bildet das Grundgerüst der 3D-Szene. Um die Funktionsweise zu verstehen, ist es von Vorteil bereits VRML zu kennen. Es existieren zwar Unterschiede, aber viel mehr Gemeinsamkeiten als zu OpenGL. Der Szenengraph beschreibt in Java3D den kompletten Aufbau der virtuellen Welt. Dies geschieht mit Hilfe einer Baumstruktur, welche aus Knoten und Kanten besteht. Die Knoten können 3D-Objekte, Kameras, Lichtquellen, Sound und das Verhalten von Objekten beinhalten. Die Kanten stellen entweder Eltern-Kind-Beziehungen oder Referenzen da. Der Szenengraph beschreibt jedoch nicht die Renderreihenfolge! Java3D arbeitet den Szenengraph nicht von oben nach unten oder von rechts nach links ab. Java 3D legt die Renderreihenfolge selbst fest, optimiert dabei den Renderprozess und ermöglicht auch parallele Prozesse. Der Szenengraph beschreibt lediglich den Inhalt der Szene! Zum Erstellen auch nur eines einfachen 3D Models werden eine ganze Menge an Klassen bzw. Objekten benötigt. Das Paket java.media.j3d enthält alle grundlegenden Klassen die man zum Erstellen eines Szenengraphen braucht. 10

14 1. Einleitung Vgl. [Finlayson] Abb. 7 Java3D Klassen Hierarchie 11

15 1. Einleitung Die Abbildung 7 zeigt, dass zum Beispiel Licht, Sound und 3D-Objekte (3Dshape) von der selben Oberklasse erben und dadurch alle als gleichwertige Objekte in einen Baum eingefügt werden können. Zum Beispiel existiert dort auch die Klasse Geometry (unter NodeComponent). Aus Ihr werden alle Objekte abgeleitet, die zum Erstellen einer Geometry benötigt werden. Diese Objekt müssen immer einem Shape3D untergeordnet werden. In diesem Programm wurde zur Darstellung der Geometry der TriangleStripArray benutzt, auf den aber noch im nächsten Kapitel [1.2.2 Grundobjekte] näher eingegangen wird. Neben diesem ganzen Bündel an Klassen zum Definieren einer 3D-Umgebung, besitzt Java aber noch einige Klassen mehr, die das Arbeiten im 3D Bereich vereinfachen sollen. Dies sind zum Beispiel die Klassen in dem Paket: javax.vecmath.*, welche 2D und 3D Vektorklassen und Vektoroperationen zu Verfügung stellt. Aber auch Klassen aus dem Paket com.sun.j3d.utils.behaviors.mouse.*, welche zum Beispiel einen Behavior: MouseRotate bereit stellt, über den eine einfache Rotation des 3D-Models oder auch eines einzelnen Teilknotens über die Maus ermöglicht wird. Mehr über die Funktionalität der Steuerung erfahren Sie in Kapitel [2.5 Ansichtsbereich ]. Auf die programmiertechnischen Gesichtpunkte wird in Kapitel [1.2.5 Maussteuerung] eingegangen. Doch zunächst das Erstellen des Szenengraphs denn bevor etwas gesteuert wird, muss dies erstellt werden. In einem Szenengraph bildet VirtualUniverse die oberste Klasse. Ein Programm kann durchaus mehrere Objekte dieser Klasse besitzen, aber jedes erstellte Java3D Objekt kann immer nur in einem Universum existieren bzw. einem zugeordnet werden. Jedes Universum besitzt null bis theoretisch unendlich viele Objekt vom Typ Locale, welche wiederum einen oder mehrere Szenengraphen beinhalten. Die in Locale referenzierten Objekte, zum Beispiel der Szenengraph, sind listenähnlich strukturiert, werden aber automatisch so angeordnet, dass der Rechner die Szene besser und schneller abbilden kann. Anders als bei anderen bekannten 3D Definitionen beinhaltet Java3D keine Welt-Klasse, da diese Funktionen von VirtualUniverse und Locale übernommen werden. Locale gibt die Möglichkeit mehrere Szenengraphen (z.b. verschiedene Orte) parallel abzuspeichern und so größere Strukturen, zwischen denen in der Ansicht hin und her gesprungen werden kann, geordnet abbilden zu können. Die SceneGraph-Klasse ist für dieses Programm eine eher uninteressante Oberklasse, wie [Abb. 7] zeigt. Wichtiger sind deren Unterklassen, wie zum Beispiel die Klasse Node. Diese repräsentiert entweder Group oder Leaf -Objekte. Group- Objekte können mehrere Kinder besitzen. Leaf-Objekte hingegen nur Referenzen. 12

16 1. Einleitung Die folgende Abbildung deutet den Aufbau eines Szenengraphen an. VirtualUniverse Locale Inhaltszweig Betrachtungszweig BG BG Branchgroup TG TG Transformgroup S. 3D VP View Canvas3D Screen3D Appearance Geometry Physical Body Physical Environment Abb. 8 Beispielhafter Aufbau eines Szenengraphen Wie die [Abb. 8] zeigt, unterteilt sich der Szenengraph in zwei Teile, in den Inhaltszweig und in den Betrachtungszweig. Der grobe Aufbau des Inhaltszweig wurde im vorherigen Abschnitt bereits behandelt und das Erstellen von Objekte wird im Folgenden noch beschrieben. Daher an dieser Stelle einige Worte über den Betrachtungszweig. Der Bertachtungszweig sieht bei den meisten Java3D Anwendungen immer gleich aus. Dies bezieht sich nicht nur auf den Aufbau, sondern auch auf die vordefinierten Werte. Der Betrachtungszweig beschreibt die komplette Betrachtungsumgebung, aber nicht den Inhalt! Um die sich meist recht stark ähnelnden Umgebungen nicht immer wieder mühselig per Hand definieren zu müssen, existiert die Klasse SimpleUniverse. Ein von dieser Klasse gebildetes Objekt enthält ein komplett vorgefertigtes rechtsdrehendes Universum, inklusive dem oben aufgezeigten Betrachtungszweig. In den meisten Fällen ist es nicht nötig Änderungen daran vorzunehmen. Die bei diesem Programm vorgenommenen, werden spätern an den entsprechenden Abb. 9 Koordinatensystem Stellen erläutert. von Java3D 13

17 1. Einleitung GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); //Setze Standardkonfiguration canvas3d = new Canvas3D (config); //Erzeugt ein Canvas3d Objekt mit der Standardkonfiguration universe = new SimpleUniverse(canvas3d); //Erstelle ein Standarduniversum, welches das Canvas3D-Feld referenziert Der Quelltext zeigt das Erstellen eines Universums mit Hilfe der SimpleUniverse- Klasse. Im Mittelpunkt des Betrachtungszweiges steht die Klasse View. Das von ihr gebildete Objekt ist das Hauptobjekt, wenn es um die Kontrolle der 3D Umgebung geht. Es beinhaltet alle Daten zum Erstellen dieser. Der View enthält eine Liste von Canvas3D-Objekten in dem die Ansicht gerendert wird. Er existiert außerhalb des Szenengraphen, hängt aber an einem Viewplattform Unterknoten. Zudem enthält der View, wie auch [Abb. 8] zeigt, Referenzen des Typs PhysicalBody und PhysicalEnvironment. Im View wird zum Beispiel spezifiziert, ob die Ausgabe auf einem normalen Bildschirm oder einem HeadMountedDisplay (HMD) angezeigt werden soll, oder ob es sich um eine Zentral- oder Parallelprojektion handelt. Alle grundlegenden Daten für die Ansicht werden im View spezifiziert. PhysicalBody enthält alle Daten über den Körper des Benutzer, über den Avatar. So wird dort zum Beispiel der Augenabstand und deren Abstand zum Boden gespeichert. Im PhysikalEnvironment hingegen werden alle Ein- und Ausgabegeräte aufgeführt, wie zum Beispiel Informationen über die Audioquellen oder über das verwendete HeadMountedDisplay. Während das Canvas3D-Objekt die Lage des Anzeigebereiches innerhalb der Applikation bestimmt, enthält das Screen3D Objekt Informationen über die Art des Bildschirms, wie zum Beispiel die Breite und Höhe. Das ViewPlattform Objekt, an welchem auch der View hängt und welches in dem Szenengraph implementiert sein muss, gibt die Position, Skalierung und Orientierung des Avatars wieder. Die Navigation des Avatars geschieht durch die Manipulation der der Viewplattform übergeordneten Transformationsmatrix. Somit wird der Betrachtungszweig in dem Szenengraph eingegliedert. Dies sorgt für eine übersichtliche und getrennte Darstellung zwischen dem Inhalt und der Betrachtung. 6 Der Inhaltszweig enthält immer mindestens ein oder mehrere Objekte vom Typ Branchgroup, da dies der einzige Objekttyp ist, welcher in Locale referenziert werden kann. Branchgroups dienen dazu, den Szenengraph zu strukturieren. Branchgroup- Objekten können mehrere komplexe Objekte untergeordnet werden, z.b. ein Wagenrad inklusive Schrauben und Felge. Dies hat den Vorteil, dass dieses komplexe Objekt insgesamt kopiert werden kann. Alternativ ist es auch möglich darauf zu verweisen, um keine Kopie erstellen zu müssen und Speicher zu sparen. Branchgroups haben aber neben der Gruppierungsfunktion noch andere Aufgaben. 6 vgl. [Barrilleaux] 14

18 1. Einleitung So ist es möglich, komplette Objekte aus dem Szenengraphen zu entfernen oder hinzuzufügen, auszublenden oder vorkompilieren zu lassen, um diese schneller zu zeichnen. 7 Neben der wichtigen Stellung von BranchGroup existiert noch die TransformGroup, die, wie der Name schon sagt, dafür eingesetzt wird, Objekte zu transformieren, sprich zu skalieren, zu rotieren oder zu positionieren. In diesem Projekt wurde dies unter anderem für die Skalierung des gesamten Drehkörpers benutzt, wie der folgende Codeausschnitt verdeutlichen soll. objtrans = new TransformGroup(); //Erzeugen einer TransformGroup Transform3D matrix = new Transform3D(); //Erzeugen einer Transformationsmatrix matrix.setscale(actuzoom); //Aufruf der Methode, um die Skalierung zu verändern objtrans.settransform(matrix); //Zuweisen der Transformationsmatrix der TransformGroup objtrans.addchild(make3dmodel()); //Anhängen des Objektes an die TransformGroup Die erzeugte BranchGroup, welche das komplette 3D Modell beinhaltet, wird von der Methode make3dmodel() entsprechend dem Wert von actuzoom skaliert. Der Wert von actuzoom kann in dem Programm über die Zoombuttons im Hauptfenster verändert werden Grundobjekte Nachdem in den vorangegangenen Kapiteln erläutert wurde, wie ein Szenengraph aussieht und welche Funktion er hat, geht es in diesem Kapitel um das Erstellen von Objekten innerhalb eines Szenengraphs. Jeder Körper in Java3D benötigt ein Objekt der Klasse Shape3D zur Anbindung an den Szenengraph. Ein Shape3D-Objekt enthält zwei Referenzen, eine vom Typ Geometry und eine andere vom Typ Appearance. Während Geometry die Form des Objektes beschreibt, beinhaltet Apperance Informationen über die Oberflächenbeschaffenheit, wie zum Beispiel Farbe und Reflektion. Im nachfolgenden wird der Geometry-Zweig erläutert. Die Beschreibung des Appearance Objektes befindet sich in Kapitel [1.2.3 Oberflächen]. 7 vgl. [Haller] 15

19 1. Einleitung Abb. 10 Ausgabe des Beispiels Java3D beinhaltet von Hause aus keine Grundkörper, sondern nur Klassen für die Erstellung von Flächen, welche bei der richtigen Anordnung dann einen Körper bilden. Um dem Abhilfe zu schaffen, existiert von Sun eine Bibliothek, welche die grundlegenden Flächenfunktionen von Java nutzt und darüber hinaus Klassen für die Erstellung von Körpern anbietet. Um auf diese Klassen zugreifen zu können, muss das Paket com.sun.j3d.utils.geometry.*; importiert werden. Dadurch stehen die Klassen mit den Namen Box, Cone, Cylinder und Sphere, welche die entsprechenden Körper erstellen, zu Verfügung. Im Folgenden ein einfaches Beispiel als erste Anwendung für eine Java3D Umgebung. Zuerst wird wie im vorangegangen Kapitel beschrieben, das Universum erstellt. Den größten Teil der Arbeit übernimmt hierbei die Klasse SimpleUniverse. GraphicsConfiguration config= SimpleUniverse.getPreferredConfiguration(); Canvas3D canvas3d = new Canvas3D (config); add(canvas3d); SimpleUniverse universe = new SimpleUniverse(canvas3d); universe.getviewingplatform().setnominalviewingtransform(); Nachdem dadurch der komplette Betrachtungszweig erzeugt wurde, wird der Inhaltszweiges erstellt. In diesem einfachen Beispiel soll nur ein Würfel und eine halbdurchsichtige Kugel angezeigt werden. ColorCube colorcube = new ColorCube(0.4); Transform3D transform3d = new Transform3D(); transform3d.roty (Math.toRadians(30)); TransformGroup transformgroup = new TransformGroup(transform3d); transformgroup.addchild(colorcube); Zuerst wird von der Klasse ColorCube ein Objekt erstellt. Diese Klasse bildet über die Klasse QuadArray aus dem Java3D-Paket einen Würfel mit unterschiedlich farbigen Außenseiten. Um kenntlich zu machen, dass es sich um einen Würfel handelt, wird dieser um 30 gedreht. Dies geschieht über eine TransformGroup, welche die Transformationsmatrix mit dem entsprechenden Eintrag für die Rotation beinhaltet. Die TransformGroup wird in der Hierarchie des Szenengraphes dem ColorCube übergeordnet und beeinflusst diesen dadurch. 16

20 1. Einleitung Sphere s = new Sphere(0.5f); s.setappearance(app()); Eine Kugel wird über die Klasse Sphere gebildet. Wie aus dem Quelltext hervorgeht besitzt sie einen Durchmesser von 0,5. Durch das Setzen der Appearance nimmt man Einfluss auf das Aussehen des Körpers. In diesem Beispiel wurde der Kugel die Farbe Rot zugewiesen und diese halbtransparent gemacht. ColoringAttributes ca = new ColoringAttributes(); ca.setcolor (1.0f,0f,0); //die Farbe wird auf rot gesetzt TransparencyAttributes ta = new TransparencyAttributes(); ta.settransparency(0.5f); //halbdurchsichtig Der komplette Quelltext des Beispiels ist im Anhang [I Zusätzliche Quelltexte] aufgeführt. VirtualUniverse Locale bg Betrachtungszweig S. 3D sphere tg transformgroup Appearance Geometry cc colorcube Abb. 11 Aufbau des Szenengraphen Möchte man allerdings komplexere Modelle erstellen, reichen diese einfachen Grundkörper bei weitem nicht und es muss doch auf die Java3D-Klassen zurückgreifen werden. Die Gesamtübersicht des Klassenmodels von Java3D haben Sie bereits in 17

21 1. Einleitung [Abb. 7] gesehen. In [Abb. 12] nun noch einmal den hier relevanten Ausschnitt in gegliederter Form. Abb. 12 Geometryklassen von Java3D Wie man in der [Abb. 12] erkennt, wurden die gängigen Funktionalitäten zum Erstellen eines 3D-Körpers auch in Java3D übernommen, welche somit jenen von OpenGL oder VRML ähneln. Das einfachste Geometry-Objekt besteht aus einer Ansammlung von Punkten, die in einem Array gespeichert sind, dem PointArray. Die Position der Punkte im Array und auf dem Bildschirm besitzen allerdings keinerlei Zusammenhang! Abb. 13 PointArray Anders verhält sich dies bei dem LineArray. Immer zwei aufeinander folgende Punkte werden durch eine Strecke verbunden. So zum Beispiel 0 mit 1 und 2 mit 3. Die Punkte in der Grafik dienen nur der Symbolisierung des Starts und des Endes. Sie werden nicht mit erstellt! Abb. 15 TriangleArray Den ersten automatisch geschlossenen Polygonzug kann man mit dem TriangleArray erzeugen. Hierbei werden automatisch immer drei aufeinander folgende Punkte, beginnend bei 0, zu einem Dreieck verbunden. Allerdings wirkt sich sogar die Lage im Raum auf dessen Orientierung aus. Bei Ansicht des Polygons müssen die Punkte im Uhrzeigersinn durchnummeriert sein, um dessen Oberseite zu sehen. Andersherum ist dementsprechend dessen Rückseite sichtbar. [Abb. 15] zeigt von dem oberen Dreieck die Vorderseite und von dem Unteren die Rückseite. Dies ist wichtig zu wissen, da standardmäßig das BackfaceCulling aktiviert ist und daher die Rückseite nicht gerendert wird. So könnte man sich also eventuell wundern, warum dass unten erstellte Polygon nicht angezeigt wird. Abb. 14 LineArray 18

22 1. Einleitung Abb. 16 QuadArray Alternativ zum Dreieck ist es auch möglich ein Viereck zu erstellen. Dies erfolgt über das QuadArray und geschieht analog zu dem vorangegangenen Beispiel. Vier aufeinander folgende Punkte des Array, beginnend bei 0, werden miteinander verbunden. Das erstellte Objekt muss allerdings kein Quadrat bilden, wie der Name vielleicht zuerst vermuten lässt. Es muss noch nicht mal ein Rechteck sein, die einzige Bedingung, die zu Grunde liegt, ist, dass es aus 4 Punkten besteht. Die Definition von Vorderund Rückseite geschieht analog zu den vorangegangenen. Dementsprechend wird auch wieder durch eine Anordnung im Uhrzeigersinn die Vorderseite definiert. Als Unterklassen von GeometryStripArray existieren die Klassen LineStripArray, TriangleStripArray und TriangleFanArray. Alle damit gebildeten Objekte lassen sich auch mit den vorangegangenen Techniken erstellen, aber diese Klassen wurden für den jeweiligen, öfters vorkommenden, Spezialfall erstellt und sollten eingesetzt werden, da sie weniger Speicher benötigen und einfacher in der Handhabung sind. So kann man, bei einem Polygonzug, um nicht alle Punkte doppelt angeben und abspeichern zu müssen, den LineStripArray benutzen. Die Punkte werden dort, entsprechend der Reihenfolge im Array, miteinander verbunden, so dass sich ein Linienzug ergibt. Abb. 17 LineStripArray Möchte man ein Objekt erstellen, welches aus vielen aneinanderhängenden Dreiecken besteht, bietet es sich an den TriangleStripArray zu wählen. Dort werden jeweils die zwei vorangegangenen Punkte des zuvor erstellten Dreiecks mit für das neue Dreieck genutzt. Dies bietet eine sehr effiziente Datenspeicherung. Das TriangleStripArray wurde auch in diesem Programm benutzt, da es genau die Funktionalität zu Verfügung stellt, die benötigt wurde. Das Vorgehen zum Erstellen eines Rotationskörpers wird in Kapitel [3.3.3 Erstellen eines Rotationsobjektes] beschrieben. Abb. 18 TrianlgeStripArray Neben dem TriangleStripArray existiert noch das TriangleFanArray, welches auch mehrere Dreiecke erstellt. Allerdings verbindet es nicht die zwei zuvor erstellten Punkte, sondern immer den Ersten und den Vorangegangenen mit dem Aktuellen. Dadurch ergibt sich eine Form, die einem Fächer ähnelt, wie auch [Abb. 19] zeigt. Abb. 19 TrianlgeFanArray 19

23 1. Einleitung Zudem gibt es noch, wie in [Abb. 12] dargestellt, alle Klassen mit dem Zusatz Indexed. Dies bedeutet, dass die Reihenfolge im Array über ein zusätzliches Array beschrieben wird und nicht festgelegt ist! Dadurch gewinnt man den Vorteil, dass, falls bei einem Objekt Punkte doppelt genutzt werden, die Koordinaten nicht doppelt abgespeichert werden müssen, sondern stattdessen auf die alten Koordinaten referenziert wird. In diesem Programm werden einige Koordinaten von bis zu 4 angrenzenden Dreiecken benutzt. Es wäre daher, vielleicht auf den ersten Blick, sinnvoll gewesen das IndexedTriangleStripArray zu benutzten. Der große Nachteil, der dabei entstanden wäre, hätte aber zur Folge gehabt, dass alle Koordinaten in einem Array gespeichert werden müssten. Dies wäre sehr unübersichtlich gewesen, da die Anzahl der Koordinaten variabel gehalten ist und somit die Grenzen für die einzelnen Objekte in einem Array sich bei jeder Änderung verschoben hätte. Damit die Übersicht erhalten bleibt, wurde das TriangleStripArray benutzt und die leichte unnötige Datenvervielfälltigung in Kauf genommen Oberflächeneigenschaften Da in Java3D jedes dargestellte Objekt der Oberklasse Shape3D angehören muss, wie auch [Abb. 8] verdeutlicht, besitzt diese Klasse auch die Methoden zum zuweisen des Appearance-Attributes. Dies geschieht über shape3dobjekt.setappearance(appearanceobjekt);. Ein Appearance -Objekt kann sehr viele unterschiedliche Informationen beinhalten, da es das komplette Erscheinungsbild des gerenderten Objektes beschreibt! Es enthält selbst keine Daten, sondern Referenzen auf folgenden Klassen: ColoringAttributes Beschreibt die Farbe und den Shading-Algorithmus (Flat oder Gouraud) Standard ist Weiß und Gouraud. LineAttributes Beschreibt das Aussehen der Linie, die Zeichenart (gepunktet, gestrichelt usw.) die Breite und die Benutzung von Antialiasing. Standard ist eine durchgehende Linie mit einer Breite von 1 ohne Antialiasing. PointAttributes Beschreibt die Darstellung eines Punktes, dessen Größe und ob Antialiasing benutzt werden soll. Standard ist 1 Pixel ohne Antialiasing. PolygonAttributes Enthält Angaben über die Darstellung eines Polygons. So können Polygone nur über die Eckpunkte, oder die Verbindungslinien (Drahtgittermodell) oder aber über die Flächen dargestellt werden. Bei letzterem kann noch angeben werden, ob BackFace oder FrontFace-Culling aktiviert sein soll. Alle diese Einstellungen bestimmen erheblich die Wiedergaberate, da sie sehr stark die Performance beeinflussen. RenderingAttributes Definiert grundlegende Eigenschaften des Rendervorganges, wie die Handhabung von Alphaeffekten, das Darstellen von unsichtbaren Objekten oder zum Beispiel das Verhalten des Tiefenpuffers. 20

24 1. Einleitung TransparencyAttributes Hier kann Einfluss auf das Verhalten der Transparenz des Objektes genommen werden. Es wird über einen Wert zwischen 0 und 1 die Durchsichtigkeit angegeben. Zusätzlich kann noch das verwendete Berechnungsverfahren gewählt werden. Ein Beispiel zur Nutzung dieses Attributes finden sie im Anhang [I Zusätzliche Quelltexte]. Material Beschreibt die Materialeigenschaften: Ambient color, Diffuse color, Specular color, Emissiv color und Shininess. Texture Wird benutzt um einem Objekt eine Textur zuzuweisen, beinhaltet sehr viele Parameter für deren Spezifikation, von der Angabe der Grenzen und Skalierung bis zum Verhalten beim LOD oder MIPmapping (mehrere Texturen auf ein Objekt). TextureAttributes Beschreibt das Verhalten von Textur und Umgebungslicht. Nimmt Einfluss auf die Textur und deren Reflexionsverhalten. TexCoordGeneration Generiert automatisch die Texturkoordinaten für ein vorgebendes Objekt. TextureUnitState Definiert das Zusammenspiel mehrer Texturen und enthält wiederum Referenzen auf Texture, TextureAttributes und TexCoordGeneration. Jede Textur wird jeweils über den entsprechenden Index angesprochen. In dem Programm wurden nicht alle aufgeführten Klassen benutzt. Das Color-Attribut kam zum Beispiel zum Einsatz, um die Linien des Drahtgittermodells grün zu färben. //Eigenschaften für Drahtgittermodell, Linien grün und doppelseitig private Appearance app4 () { Appearance app4 = new Appearance(); ColoringAttributes c_att = new ColoringAttributes(); c_att.setcolor(new Color3f(0.0f, 1.0f, 0.0f)); app4.setcoloringattributes(c_att); PolygonAttributes polyatt = new PolygonAttributes(); polyatt.setcullface(polygonattributes.cull_none); app4.setpolygonattributes(polyatt); return app4; Zusätzlich musste noch über die PolygonAttribute das BackfaceCulling ausgeschaltet werden, damit von dem Gitter gegebenenfalls auch die Rückseite eingeblendet wird. Für das Programm wurde neben der Eigenschaften zur Färbung des Gitters noch ein Appearance-Objekt mit Material benötigt, um so auch Glanzlichteffekte darzustellen. 21

25 1. Einleitung Benutzt wurde der Standardkonstruktor der Materialklasse, welcher ein Material mit den folgenden Eigenschaften erzeugt: ambient color : (0.2, 0.2, 0.2) emmisive color : (0.0, 0.0, 0.0) diffuse color : (1.0, 1.0, 1.0) specular color : (1.0, 1.0, 1.0) // Grundmaterial nur Vorderseite private Appearance app3o () { Appearance app3 = new Appearance(); app3.setmaterial(new Material()); return app3; Alternativ dazu, falls die Wandstärke deaktiviert ist, existiert noch einmal ein Material mit den gleichen Eigenschaften, bei welchem über die PolygonAttributs das BackfaceCulling deaktiviert ist, um so auch offene Objekte darstellen zu können. Das BackfaceCulling wird im jeweiligen Fall aktiviert, um eine bessere Performance zu erreichen. Als weitere Alternative existiert auch noch die Umstellung des Standardshading Verfahrens von gouraud auf flat, welches über folgende Zeilen erfolgt. Der integer Wert in dem Konstruktoraufruf übernimmt hierbei die Definition: 2 für flat, 3 für goroud. ColoringAttributes c_att = new ColoringAttributes(new Color3f(0.4f, 0.4f, 0.4f), (int) 2); app3.setcoloringattributes(c_att); Beleuchtungsmodell Die Berechnung des Beleuchtungsmodell ist eines der komplexesten Themen in der Computergrafik, welche wohl den größten Teil der Rechenleistung für sich beansprucht. Um einen Beleuchtungseffekt zu erzielen, muss man in Java3D zuerst eine Lichtquelle erzeugen, die Grenzen dieser festlegen und sie dem Szenengraphen hinzufügen. Das beleuchtete Objekt muss sich innerhalb dieser Grenzen befinden, muss Normalenvektoren besitzen und ein Appearance-Objekt mit Materialeigenschaften sein eigen nennen. Über die Materialeigenschaften wird beschrieben, wie das Objekt auf die verschiedenen Lichttypen reagiert. Ein Objekt kann gleichzeitig maximal von 8 Lichtquellen beleuchtet werden. Bei der Lichtberechnung werden aber keine Schatten oder Lichteffekte zwischen Objekten berechnet. 22

26 1. Einleitung Java3D unterstützt vier verschiedene Lichtquellen. Ambient Light Ist das Umgebungslicht und erhellt somit jedes Objekt der Szene. Im folgenden der Code aus unserem Programm, bei dem ein eher dezenteres Umgebungslicht erzeugt wird. Color3f ambientcolor = new Color3f(0.1f, 0.1f, 0.1f); AmbientLight ambientlightnode = new AmbientLight(ambientColor); ambientlightnode.setinfluencingbounds(bounds); hg.addchild(ambientlightnode); Directional Light Stellt das Licht einer sehr weit entfernten Lichtquelle dar. In einigen Programmen wird es auch als ParallelLight geführt. Es kann z.b. zur Simulation des Sonnenlichts benutzt werden. Zuerst bestimmt man den Einfallwinkel und die Farbe des Lichtes: Color3f light1color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1direction = new Vector3f(1.0f, 1.0f, 1.0f); Color3f light2color = new Color3f(1.0f, 1.0f, 1.0f); Vector3f light2direction = new Vector3f(-1.0f, -1.0f, -1.0f); Anschließend kann man die Lichter erstellen und ihnen einen Einflussbereich zuweisen. Zuletzt werden diese dann in den Szenengraph eingefügt. DirectionalLight light1 = new DirectionalLight(light1Color, light1direction); light1.setinfluencingbounds(bounds); addchild(light1); DirectionalLight light2 = new DirectionalLight(light2Color, light2direction); light2.setinfluencingbounds(bounds); hg.addchild(light2); Point Light Das Punktlicht sendet von einem Punkt im 3D-Raum seine Strahlen aus, wobei die Intensität je nach Entfernung auch abnimmt. Spot Light Das Spotlight ist eine modifizierte Form des Punktlichtes, so können hier noch der Austrittswinkel so wie Lichtkegeldurchmesser gesetzt werden. Mit dem Spotlight kann man den Lichtausfall von Scheinwerfern oder Taschenlampen nachstellen. Damit die Beleuchtung für ein Objekt auch berechnet werden kann, muss dieses Normalenvektoren besitzen. Erzeugt man Grundobjekte, erweist sich die Angabe der Normalenvektoren als unproblematisch, da es für diese vorgefertigte Vektoren gibt. Hier ein Beispiel für eine Kugel: scene.addchild(new Sphere(0.5f, Sphere.GENERATE_NORMALS,app5()); Wurde allerdings ein selbst erstelltes, komplexes Polygonnetz entworfen, müssen die Normalenvektoren selbst berechnet werden. Welche Algorithmen dafür zugrunde liegen, wird in Kapitel [3.3.4 Normalenvektoren] erläutert. 23

27 1. Einleitung Maussteuerung In Java3D gibt es die verschiedensten Möglichkeiten die Mausposition abzufragen, um damit ein Objekt zu steuern. Das meist eingesetzte Mittel sind die Behavior-Klassen aus dem com.sun.j3d.utils.behaviors.mouse-paket. Mit diesen kann man auf einfachem Wege eine Maussteuerung einer Java3D-Umgebung erreichen. // Rotation MouseRotate behavior = new MouseRotate(); behavior.settransformgroup(objtrans); objtrans.addchild(behavior); behavior.setschedulingbounds(bounds); // Skalierung MouseZoom behavior2 = new MouseZoom(); behavior2.settransformgroup(objtrans); objtrans.addchild(behavior2); behavior2.setschedulingbounds(bounds); // Verschiebung MouseTranslate behavior3 = new MouseTranslate(); behavior3.settransformgroup(objtrans); objtrans.addchild(behavior3); behavior3.setschedulingbounds(bounds); In diesem Projekt wurde allerdings der OrbitBehavior aus dem Paket com.sun.j3d.utils.behaviors.vp.* benutzt, welcher direkt über dem Viewport des canvas3d referenziert wird, und welcher dafür sorgt, dass die Ansicht (die Kamera) über die Maus komplett gesteuert werden kann! Der entsprechende Quelltext sieht wie folgt aus: import com.sun.j3d.utils.behaviors.vp.*; //Import der Klasse für die Steuerung des ViewPorts private OrbitBehavior orbit; //Erstellen einer Referenz vom Typ OrbitBehavior orbit = new OrbitBehavior(canvas3d, OrbitBehavior.REVERSE_ALL); // Erzeugen eines Objektes von OrbitBehavior orbit.setschedulingbounds(bounds); //Ruft die Methode auf, die OrbitBehavior von Behavior geerbt hat, um die darüber die Grenzen zu setzen, wodurch eine zeitliche Planung im Bezug auf das Verhalten der aktiven Knoten ermöglicht wird viewingplatform.setviewplatformbehavior(orbit); //setz den ViewPlatformBehavior, welcher auf der Viewplatform agiert Während im ersten Beispiel die Behavior der Maus benutzt werden, um darüber eine TransformGroup zu manipulieren und so Einfluss auf die Ansicht des 3D-Objektes zu erlangen, wird im unteren Beispiel der Behavior der Viewplattform benutzt und direkt der Viewport manipuliert. Die zuletzt vorgestellte Methode bietet neben dem großen Vorteil der einfacheren Implementierung, auch viel mehr Funktionalität! Bei ersterem Beispiel wäre nur ein Skalieren, Rotieren und Verschieben über die Maus möglich, hingegen bietet die unteren Variante auch noch eine Steuerung über die Tastatur an! Mehr dazu in Kapitel [2.5 Ansichtsbereich ] 24

28 1. Einleitung 1.3 Einführung in PovRay PovRay steht für Persistence Of Vision Raytracer und ist ein Renderer, welcher das RayTracing-Verfahren zur Abbildung von dreidimensionalen Szenen auf ein zweidimensionales Bild benutzt. Der große Vorteil dabei ist, dass Lichteffekte jeglicher Art sehr realitätsnah wirken. So werden Glanzeffekte, Schatten, Spiegelungen oder gar Lichtbrechung sehr fotorealistisch berechnet! Allerdings ist PovRay textbasiert. Daher gibt man alle Befehle, wie bei einer Programmiersprache, ein. Die Szene wird durch die Scene Description Language beschrieben. Diese Tatsache macht es sehr schwierig eigene dreidimensionale Objekte zu erstellen. Trotzdem sollte man dieses Programm nicht unterschätzen, denn der große Vorteil liegt auch darin, dass es Freeware ist und zahlreiche Anleitungen und Tutorials im Internet dazu erhältlich sind. Die geschriebenen Szenen werden im Format *.pov abgespeichert und anschließend über den Renderer mit dem jeweiligen Attribut aufgerufen, um das entsprechende Bild zu erzeugen. Povray bietet dabei von Hause aus eine kleine, leicht zu bedienende Entwicklungsumgebung. Abb. 20 PovRay-Entwicklungsumgebung [Abb. 20] zeigt ein Menü mit alle verfügbaren Befehlen. Diese sind direkt abrufbar und werden so elegant verallgemeinert in den Quelltext eingefügt, um sie anschließend zu spezifizieren. PovRay ist objektorientiert, so werden alle benutzten Körper als einzelne Objekte erstellt, welche sich alle vom grundlegenden Aufbau her gleichen. Mit einem reinen Rotationskörper alleine kann man allerdings wenig anfangen, da zum Rendern eine umgebende Welt nötig ist. Daher kann unser Programm gegebenenfalls eine Testumgebung mit erzeugen. Der erzeugte Quelltext einer Testumgebung ist mit 25

29 1. Einleitung in Kapitel [I Zusätzliche Quelltexte] aufgeführt. Dort wird über den Befehl #include "export.inc" der erstellte Rotationskörper in die Testumgebung importiert und über object{rotation erstellt Rotationskörper Möchte man einen Rotationskörper in Povray selbst erstellen, ist dies nicht leicht, da man die Koordinaten der Kontur per Hand eingeben müsste und nur die Wenigsten dürften erkennen, dass es sich, wie im folgenden Beispiel, um ein Weinglas handelt. <1.48, >, <0.24, >, <0.22, 2.96>, <0.84, 3.1>, <1.04, >, <1.22, 3.5>, <1.34, 3.94>, <1.4, 4.24> Dieses Programm ist darauf spezialisiert Rotationsköper zu erstellen, wegen dem naheliegenden Manko von PovRay wurde daher auch zu diesem Programm eine Exportfunktion implementiert. In PovRay existieren zwei Befehle, welche beide ein Rotationskörper ähnliches Objekt erstellen. Sie heißen sor und lathe. sor steht für Surface of Revolution, lathe hingegen bedeutet grob übersetzt Drehbank. Bei beiden wird eine Punktmenge zur Definition der Kontur angegeben, welche später um die Y-Achse gedreht wird. Allerdings kann man zusätzlich bei dem Lathe-Objekt angeben, wie die Punkte verbunden werden sollen: linear, quadratisch oder kubisch. Der größte Nachteil des sor-objektes ist, dass sich die Punkte längs der Y-Achse nicht überschneiden dürfen. Dies würde passieren wenn die Kontur eine 180 Kurve beinhaltet, zum Beispiel beim Erstellen eines Donuts. Das erstellte Programm beherrscht aber auch komplexere Objekte, daher musste der lathe-befehl benutzt werden. Dies ist allerdings nicht wirklich nachteilhaft, außer dass dieser Befehl geringfügig mehr Rechenzeit beim rendern benötigt. Den Quelltext eines erstellten Rotationskörpers finden sie im Anhang unter [I Zusätzliche Quelltexte]. 8 8 vgl. [PovRay-G] 26

30 2. Das Programm 2 Das Programm Das Programm hat den Namen "Surface of Revolution", dies bedeutet soviel wie "Rotationskörper". Wie schon im Vorwort besprochen, dient es zur einfachen Erstellung von Rotationskörpern, die in andere Formate exportiert und anschließend in den entsprechenden Programmen weiterverarbeitet werden können. An dieser Stelle wird zuerst in die Bedienung des Programms eingeführt, und die Nutzung der exportierten Daten in den jeweiligen Werkzeugen wie z.b. PovRay, Java3D oder VRML erläutert. 2.1 Bedienoberfläche Die Benutzeroberfläche des Programms ist in zwei Hauptbereiche eingeteilt, dem Bearbeitungsbereich und dem Ansichtsbereich. Im Bearbeitungsbereich befindet sich das Koordinatensystem, welches zum Erstellen der Kontrollpunkte des Rotationskörpers dient. Alle in diesem Bereich befindlichen Buttons und Steuerelemente haben lediglich auf die Punkte im zugehörigen Koordinatensystem Einfluss. Gleiches gilt für den Ansichtsbereich, in dem der Rotationskörper ausschließlich betrachtet und die eigentliche Kontur nicht verändert werden kann. Über den beiden Bereichen befindet sich die Schnellstartleiste, auf der die wichtigsten Funktionen als Buttons hinterlegt sind. Dies erleichtert die Benutzersteuerung. Sollten die Icons nicht selbsterklärend sein, bekommt man, bei längerem verweilen des Mauszeigers auf den jeweiligen Icons, einen entsprechenden Tooltip mit erläuternden Informationen. Wie in jedem Standard-Windowssystem, ist zur Steuerung des Programms eine Menüleiste mit allen in der Schnellstartleiste aufgeführten, sowie weiteren Funktionen, am oberen Bildrand des Programms verankert. Abb. 21 Die Bereiche des Programms 27

31 2. Das Programm 2.2 Menüleiste Die Menüleiste im oberen Teil des Hauptfensters, beinhaltet mehr Funktionen, als die der Schnellstartleiste. Da später noch auf die Schnellstartleiste und somit auf deren Funktionen eingegangen wird, besprechen wir jetzt erst einmal ausschließlich die Möglichkeiten, die nur über die Menüleiste zu erreichen sind. Die Menüleiste besteht aus drei Teilen, File, Look&Feel und About. Abb. 22 Menüleisten Steuerung Wie es in Windows standard ist, kann die Menüleiste auch ohne Maus, durch drücken der ALT-Taste und dem unterstrichenen Buchstaben des gewünschten Menüs, bedient werden. In [Abb. 22] zum Beispiel Alt+F, um das Menü File zu öffnen. Unter dem Menüpunkt File kann man, zusätzlich zu den in der Schnellstartleiste befindlichen Funktionen, das Programm beenden oder die geöffnete Datei mit dem Menüpunkt saveas unter einem anderen Namen abspeichern. Der Menüpunkt Look&Feel erlaubt dem Benutzer das Aussehen des Programms zu ändern. Es stehen folgende Look&Feel-Komponenten zur Verfügung: Windows (Windows 95 und NT Standard Look) Motif-X (Motif-X-Window-System Look) Metal (Plattformübergreifendes Java-Swing Look) Über das Menü About erreicht man ein Informations-Fenster, in dem die Version des Programms, sowie die Namen und Adressen der Entwickler hinterlegt sind. Abb. 23 About Fenster 28

32 2. Das Programm 2.3 Schnellstartleiste Die Schnellstartleiste befindet sich, wie schon im Kapitel [2.1 Bedienoberfläche] erwähnt, direkt unter der Menüleiste. Mit Hilfe dieser Leiste ist es möglich die wichtigsten Funktionen besonders schnell zu erreichen und dadurch effizienter zu arbeiten. Abb. 24 Schnellstartleiste Das erste Symbol von links in der Schnellstartleiste ist das Symbol Neu, mit dem man eine neue Kontur erstellen kann. Die aktuelle Kontur wird dadurch aus dem Koordinatensystem entfernt und alle Einstellungen im Bearbeitungs- und Ansichtsbereich werden auf den Standard zurückgesetzt. Man sollte also vor dem Anklicken des Symbols Neu die aktuelle Kontur speichern. Wird dies vergessen, weißt eine Sicherheitsabfrage darauf hin, dass alle Daten verloren gehen. Als nächstes findet man das Symbol Öffnen in der Schnellstartleiste. Hier kann, wie der Name schon sagt, eine vorhandene Kontur zum Bearbeiten oder Exportierten geöffnet werden. Aber auch vor dem Öffnen einer neuen Kontur, sollte die Vorhandene, falls eine existiert, gespeichert werden. Alle Einstellungen des Bearbeitungs- und Ansichtsbereichs werden aus der geöffneten Datei übernommen. Das Symbol Speichern hat als einziges Symbol in der Schnellstartleiste zwei Funktionen. Ist die Kontur neu erstellt worden und noch nicht abgespeichert, hat dieses Symbol die Save as -Funktion, die es ermöglicht einen Dateinamen und Speicherort auszuwählen. Ist die Kontur jedoch geöffnet oder bereits gespeichert, besitzt dieses Symbol die Save -Funktion, welche ohne weiteres Nachfragen beim betätigen, die Kontur mit dem bereits vergebenen Namen abspeichert. Rechts befindet sich das Symbol Export, mit dem man das Export-Fenster öffnet. Darauf wird später aber, im Kapitel [2.6.1 Export Fenster] eingegangen. 2.4 Bearbeitungsbereich Im Bearbeitungsbereich, der sich im linken Teil des Programmfensters befindet, wird die Kontur des 3D Körpers erstellt. Dort werden Punkte in das Koordinatensystem eingefügt, wodurch sich die Kontur ergibt. Durch Drehung dieser um die Y-Achse entsteht dann der 3D Körper. Um die Punkte in das Koordinatensystem einzufügen oder zu bearbeiten, befinden sich auf der linken Seite die Symbole Pfeil und Kreuz. Siehe [Abb. 25] Das obere Symbol Pfeil hat, wie das Symbol Abb. 25 Bearbeitungswerkzeuge Save, eine doppelte Funktionalität. Die Handhabung ist aber etwas anders. Diese Symbole sind nicht, wie die in der Schnellstartleiste, einfache Buttons, sondern Schalter, die entweder ein oder ausgeschaltet sein können. Sie sind demzufolge zustandsbehaftet und es kann immer nur ein Symbol zu einer Zeit aktiv sein. Welches Symbol aktiv ist, erkennt man durch eine graue Untermalung, wie z.b. in [Abb. 25] das Symbol Pfeil. Um Punkte zum Koordinatensystem hinzuzufügen, muss das Symbol Pfeil aktiviert werden. Danach kann man durch klicken mit der Maus in das Koordinatensystem Punkte einfügen, die automatisch als Kontur verbunden werden. 29

33 2. Das Programm Beim Erstellen einer Kontur ist zu beachten, dass der Abstand zwischen zwei Punkten mindestens einen Radius von vier Pixeln haben muss. Ist das Symbol Pfeil ausgewählt und beträgt der Abstand des Mauszeigers zu einem Punkt weniger als 4 Pixel, ist die zweite Belegung dieses Symbols, nämlich die Funktion Verschieben, automatisch aktiviert. Diese zweite Belegung ist durch einen roten Kreis um den zu verschiebenden Punkt gekennzeichnet. Ist der rote Kreis sichtbar, kann man keinen neuen Punkt an dieser Stelle einfügen, sondern stattdessen den aktuellen Punkt mit gedrückter Maustaste verschieben. Abb. 26 Verschiebungs-Funktion Das zweite Symbol links neben dem Koordinaten-System, ist das Symbol Kreuz und es dient zum Löschen eines Punktes. Nach dem Aktivieren dieses Symbols, erscheint, wenn sich der Mauszeiger über dem zu löschenden Punkt befindet, ein rotes Kreuz. Drückt man, während das rote Kreuz zu sehen ist, eine Maustaste, wird der aktuelle Punkt entfernt. Abb. 27 Lösch-Funktion Unter dem Koordinatensystem befindet sich ein Schieberegler, über den die Wandstärken-Funktion aktivierbar ist. Diese Funktion ermöglicht es, der gezeichneten Kontur eine Wandstärke zu verleihen, indem man den Schieberegler nach rechts schiebt, bis die gewünschte Wandstärke erreicht ist. Die Wandstärke wird im Koordinatensystem, zusätzlich zur Kontur, in grau dargestellt. Natürlich können die Wandstärke-Punkte nicht verschoben werden, da sie automatisch errechnet werden und im Bezug mit den Original- Punkten der Kontur stehen. Verschiebt oder löscht man einen Punkt, verschiebt oder löscht sich auch der errechnete Wandpunkt. Abb. 28 Wandstärke einstellen 30

34 2. Das Programm 2.5 Ansichtsbereich Im rechten Teil des Programms befindet sich der 3D-Ansichtsbereich, siehe auch [Abb. 21]. oder [Abb. 29]. Durch klicken mit der linken Maustaste in diesem Bereich wird die Kameraposition im Raum verändert und es entsteht der Eindruck als ob sich das Objekt drehen würde. Über die mittlere Maustaste bewegt man die Kamera auf einer direkten Bahn, näher zum Mittelpunkt hin oder davon weg, wodurch ein Zoom-Effekt entsteht. Mit der rechten Maustaste kann man die Kamera im Raum verschieben. Für den Fall, dass ein Benutzer keine mittlere Maustaste besitzt, existiert die Möglichkeit, die Funktionalität dieser durch halten der Alt-Taste auf die linke Maustaste umzulegen. Wem das Drücken der ALT- Abb. 29 3D-Ansichtsbereich Taste zu umständlich erscheint, kann einen Zoom auch durch die links unterhalb der 3D-Ansicht angebrachten Buttons ausführen. Abb. 30 Gouraud-Shading Abb. 31 Flat-Shading Abb. 32 No-Shading Abb. 33 Drahtgittermodell Rechts neben diesen Buttons befindet sich eine Dropdownbox. Über diese kann man die Anzeigeeigenschaften des Objektes beeinflussen, zwischen Gouraud-Shading, Flat- Shading, No Shading und Empty. Mit dem rechts daneben liegenden Button, wird die Drahtgitterstruktur des Objektes Ein- oder Ausgeblendet. Noch weiter rechts befindet sich ein Schieberegler über den die Anzahl der verwendeten Dreiecke des Objektes eingestellt werden kann. Ist die Auswahlbox Auto set aktiviert, wird die Anzahl automatisch gesetzt. Hierzu mehr im Kapitel [3.3 Probleme und Lösungen]. 31

35 2. Das Programm 2.6 Export und Weiternutzung Hat man eine Kontur erstellt und ist mit dem Aussehen des 3D-Körpers im Ansichtsbereich zufrieden, möchte man diesen Körper meist in einem anderen Grafikformat bzw. Grafikwerkzeug benutzen. Hierfür wurde eine Export-Funktion implementiert. Diese Funktion unterstützt die vier Formate: PovRay, VRML, Java3D und Textdatei. Die Kontur kann anschließend zum Beispiel in PovRay weiter bearbeitet werden. Dies wird im Kapitel [2.6.2 Nutzung in PovRay] weiter erläutert. Die Nutzung und Weiterbearbeitung in einer VRML-Datei wird im Kapitel [2.6.3 Nutzung in VRML] beschrieben. Ist das Format, in das der 3D-Körper exportiert werden soll, im Programm nicht implementiert, kann man sich eine Textdatei erstellen lassen, in der die X- und Y- Koordinaten der einzelnen Punkte angegeben werden. Mit Hilfe dieser Textdatei kann dann die Kontur in anderen Grafikwerkzeugen, die Rotationskörper unterstützen, leicht eingefügt und weiter verwendet werden Export Fenster Um den Exportdialog zu öffnen, kann man entweder über die Menüleiste (Kapitel [2.2 Menüleiste]) File/Export, oder über die Schnellstartleiste (Kapitel [2.3 Schnellstartleiste]) den grünen Pfeil, gehen. Wichtig ist, dass mehr als zwei Punkte gezeichnet sein müssen, ansonsten öffnet sich das Export-Fenster nicht, da ein Export keinen Sinn ergeben würde. Mit weniger als zwei Punkten kann kein 3D Körper beschrieben werden. Im Export-Dialog wird zuerst der Pfad ausgewählt, unter dem der 3D Körper gespeichert werden soll. Standardmäßig ist der Pfad auf das Verzeichnis in dem sich das Programm befindet gesetzt. Wurde bereits eine Datei exportiert, wird der Pfad der vorherigen Datei vorgeschlagen. Soll der Pfad verändert werden, drückt man auf den Button... neben der Pfadangabe. Dadurch öffnet sich ein Standard-Dialog in dem der Pfad verändert werden kann. Anschließend wird unten in der Drop-Down-Liste das Abb. 34 Export-Dialog gewünschte Format ausgewählt, nimmt man das PovRay oder Java3D Format, kann zusätzlich noch entschieden werden, ob eine Testumgebung generiert werden soll. Darauf wird im Kapitel [2.6.2 Nutzung in PovRay] weiter eingegangen. Bei anderen Formaten ist die Auswahl der Testumgebung nicht möglich und dieser Menüpunkt wird grau hinterlegt. Nachdem der Button Export gedrückt wurde, wird der 3D Körper exportiert. Dieser kann dann in anderen Grafikwerkzeugen weiter bearbeitet werden. Die Nutzung des VRML-Formats wird im Kapitel [2.6.3 Nutzung in VRML] genauer erläutert. Wichtig ist nur, dass die Einstellung Anzahl-Dreiecke im Ansichtsbereich, die im Kapitel [2.5 Ansichtsbereich] beschrieben wurde, vernünftig gesetzt ist. Denn diese Option bestimmt in der exportieren VRML-Datei, aus wie vielen Punkten der Kreis des Rotationskörpers besteht. Bei einem Export in Java3D spielen alle Einstellungen unter dem 3D-Ansichtsbereich eine Rolle für die exportierte Datei. 32

36 2. Das Programm Nutzung in PovRay Das, von dem Programm exportierte, 3D-Objekt kann einfach in eine 3D-Umgebung in PovRay eingebunden werden. Zuerst muss man die entsprechende Datei über #include "export.inc" einbinden, um danach über object{rotation ein Objekt davon erstellen zu können. Das erstellte Objekt wird dabei wie folgt abgespeichert: #include "colors.inc" declare rotation = lathe { linear_spline 8, <1.48, >, <0.24, >, <0.22, 2.96>, <0.84, 3.1>, <1.04, >, <1.22, 3.5>, <1.34, 3.94>, <1.4, 4.24> pigment {Red Abb. 35 Ein mit PovRay gerendertes Bild des Rotationskörpers 33

37 2. Das Programm Nutzung in VRML VRML (Virtuell Reality Markup Language) ist eine textbasierte Sprache, um dreidimensionale Welten und Objekte im Internet darzustellen. Da VRML wie zum Beispiel HTML, textbasiert ist, kann eine VRML-Datei in jedem Editor erzeugt werden. Der Browser in dem die VRML-Datei angezeigt werden soll, muss allerdings durch eines der vielen VRML-PlugIns erweitert werden. Wir empfehlen das Cortona PlugIn, welches unter der Adresse cortona/download 9 heruntergeladen und installiert werden kann. In VRML wird die virtuelle Umgebung in Form eines Szenengraphs beschrieben, der außer der Ereignissteuerung, eine Baumstruktur hat. Das Bild entsteht durch einen Durchlauf durch den Szenengraph, wobei die Geometrie, Position, Orientierung und das Aussehen jedes Objekts der Szene berechnet wird. 10 Das exportierte 3D-Objekt kann leicht weiter bearbeitet oder in schon bestehende VRML-Welten eingefügt werden. Es muss dafür lediglich der gesamte Knoten, aus der vom Programm generierten Datei, in eine andere VRML-Datei eingefügt werden. In [Abb. 36] ist ein Beispielobjekt zu sehen, dessen Quelltext vom Programm erzeugt wurde und im Anhang [I Zusätzliche Quelltexte] aufgeführt ist. Um z.b. Abb. 36 VRML-Beispiel dieses Objekt in eine andere VRML- Welt/Datei einzufügen, kann der gesamte Quelltext des Shape-Knoten in die andere Datei kopiert werden. Oder es besteht die Möglichkeit, die gesamte, vom Programm erzeugte, VRML-Datei mittels des Befehls inline in die neue VRML-Datei eingeladen werden. Möchte man in der VRML-Welt das 3D-Objekt mehrmals benutzen, muss nicht der gesamte Shape-Knoten kopiert werden, oder die Datei noch einmal geladen werden. Für diesen Fall wurde dem 3D-Objekt mittels DEF Rotationskörper der Name Rotationskörper zugeordnet. Dadurch kann überall in der VRML-Datei, mit dem Befehl USE Rotationskörper das Objekt abermals erzeugt werden. Zu beachten ist aber, das dieser Befehl an einer Stelle benutzt wird, an der auch ein Shape-Knoten stehen darf! Auch dieses Beispiel, wie der Befehl Use benutzt wird, ist im Anhang [I Zusätzliche Quelltexte] aufgeführt Soll in dem erzeugten 3D-Objekt die Farbe oder ein anderes Attribut verändert werden, muss allerdings in der vom Programm erzeugten VRML-Datei Hand angelegt werden. 9 vgl. [Cortona] 10 [Stark VU2] 34

38 2. Das Programm Nutzung in Java3D Der Export nach Java3D ist die komplexeste Ausgabe des Programms, da im Gegensatz zu den vorangegangen Exportfunktionen nicht nur ein 2D-Zug exportiert wird, sondern das komplette 3D-Objekt Punkt für Punkt. Abgespeichert werden diese Punkte in einem zweidimensionalen Array. Die Abbildung des Quelltextes ist gekürzt. Die Punkte symbolisieren, dass dort noch weitere Koordinaten folgen würden. static Point3f Kreispunkte[][]={ { new Point3f(0.0f, f, 0.0f), new Point3f(0.0f, f, 0.304f),..., { new Point3f(0.0f, f, 0.304f), new Point3f(0.0f, -0.57f, 0.332f),...), { new Point3f(0.0f, -0.57f, 0.332f), new Point3f(0.0f, f, 0.352f),...)... ; Die erstellte Datei lässt sich mit einem Javacompiler compilieren und starten. Wurde eine Testumgebung mit generiert, kann das 3D-Objekt direkt in einer Java3D- Umgebung getestet werden. Die Ausgabe könnte wie in [Abb. 37] aussehen. Zu bemerken ist noch, dass die Ausgabe entsprechend den im Programm vorgenommen Parametern erfolgt. Wurde das Gitternetz aktiviert, wird dieses auch mit exportiert. Wurde das Shadingverfahren auf No Shading gestellt, werden auch keine Normalenvektoren mit exportiert. Möchte man das exportierte Objekt in seine eigene, erstellte Java3D-Welt einbinden, muss nur die static Methode get3dobjekt() der generierten Klasse aufgerufen werden. Diese gibt das komplette Objekt Abb. 37 Ausgabe des Java3D Objektes innerhalb einer Branchgroup zurück. Wurde die erstellte Testumgebung benutzt, sind einige Funktionen zur Steuerung mit implementiert, so dass eine genau Betrachtung des exportierten Objektes möglich ist. Die Testumgebung enthält 2 Lichtquellen und einen Behavior über den das Objekt gedreht, skaliert und transponiert werden kann. 35

39 3. Projektverlauf 3 Projektverlauf Im folgenden Kapitel wird näher auf die Umsetzung und Programmierung des Programms eingegangen. Es werden die Planung, die Programmierungsdetails, sowie Probleme und Lösungen, dargestellt. Im Kapitel [3.3 Probleme und Lösungen] werden unter anderem die mathematischen Funktionen und Formeln, die benutzt wurden, erläutert. 3.1 Planung/Dokumentation In der Planungsphase wurde die UML (Unified Modeling Language) benutzt, da sich diese als grafische Standartnotation für die objektorientierte Analyse und den objektorientierten Entwurf auf dem Markt etabliert hat. Wie es zur Zeit Standard ist, wird in diesem Projekt ein objektorientiertes Konzept verwendet und dementsprechend die Planung und Analyse durchgeführt Pflichtenheft Das Pflichtenheft wurde ganz am Anfang der Planungsphase erstellt. Während der Analyse und Implementierungsphase wurde es trotzdem oft ergänzt und konkretisiert, denn viele Dinge sind erst während der Implementierung aufgefallen. 1.Zielbestimmung 2. Einsatz 1.1 Muß-Kriterien Angabe der Kontur eines Objektes durch Punkte, automatisches erstellen eines 3D-Rotationskörpers Generierung des PovRay-Quelltextes für den Rotationskörper 1.2 Kann-Kriterien Drehen, Wenden, Kippen und skalieren des 3D-Objektes Eventuell Unterstützung anderer Formate wie z.b. VRML Echtzeit Generierung des 3D-Objektes Eingabe von Maßstäben für PovRay Vergrößerbare Ansicht beim Konturfenster (Zoom) 1.3 Abgrenzungskriterien Keine Verbindung zu PovRay, keine Vorschau durch PovRay-Renderer Ausschließlich für Rotationskörpererzeugung 2.1 Anwendungsbereiche Zusatztool zum Erstellen von 3D-Rotationskörpern 11 [Balzert] 36

40 3. Projektverlauf 2.2 Zielgruppen Benutzer von 3D-Modelierungssystemen 2.3 Betriebsbedingungen 3. Umgebung Stand-alone-System 3.1 Software Windows NT / 2000 / XP 3.2 Hardware beliebiger Windows NT / 2000 / XP Rechner 3.3 Orgware keine 4. Funktionalität 5. Daten 6. Leistungen Als erster Arbeitsschritt erfolgt die Eingabe der Kontur durch Angabe von Punkten Alternative Arbeitsmöglichkeiten o Öffnen o Speichern o Exportieren o Verwerfen Evt. versetzen der Konturpunkte Es werden Konturkoordinaten sowie der Maßstab verarbeitet Erzeugung einer 3D-Ansicht nach den Konturpunkten Erzeugung eines PovRay Quelltextes 7. Benutzungsoberfläche Es wird eine objektorientierte grafische Oberfläche mit weitgehend intuitiver Menüsteuerung erstellt. 8. Qualitätsziele Hohe Benutzerfreundlichkeit Intuitive Benutzungsoberfläche 37

41 3. Projektverlauf Geschäftsprozessdiagramm Abb. 38 Geschäftsprozessdiagramm Der zentrale Geschäftsprosses befasst sich mit dem Erstellen eines Rotationskörpers Geschäftsprosses: Ziel: Vorbedingung: Nachbedingung Erfolg: Akteure: Auslösendes Ereignis: Beschreibung: Rotationskörpererstellung Modellierung eines Rotationskörpers nach vorgegebener Kontur keine 3D-Rotationskörper modelliert Benutzer Benutzer gibt Konturpunkte an 1. Angabe der Konturpunkte 2. 3D-Rotationsmodell erstellen 3. 3D-Modell exportieren Erweiterungen: 1a 1b 3a 3b 3c Ändern der Konturpunkte Speichern der Konturpunkte Exportieren als PovRay-Quelltext Exportieren als VRML-Quelltext Eventuell Unterstützung anderer Formate 38

42 3. Projektverlauf Zustandsautomat löscht zeichnet verschiebt Benutzer klickt auf Punkt Programm löscht Punkt Benutzer klickt in 2D Feld Programm zeichnet Punkt Benutzer bewegt Maus Programm verschiebt Punkt if(auswahl==zeichnen && ispunkt==false) Löschmodus (Auswahl = Löschen) Benutzer wählt ZeichnenButton Zeichnenmodus (Auswahl = Zeichnen) Benutzer klickt auf einen Punkt Verschiebemodus if(auswahl==zeichnen && ispunkt==true) Benutzer wählt LöschButton Benutzer lässt Maustaste wieder los (Auswahl = null) Abb. 39 Zustandsautomat 39

43 3. Projektverlauf In dem Zustandsdiagramm [Abb. 39] sind die möglichen Zustände dargestellt, die das Programm annehmen kann. Um nicht künstlich eine Klasse einzuführen und damit das Ganze zu verkomplizieren, wurde eine Zustandsvariable Auswahl benutzt. Beim Programmstart, der im Diagramm unten mit dem schwarzen Punkt gekennzeichnet ist, ist diese Zustandsvariable noch auf null gesetzt. Erst im Konstruktor der Hauptklasse bekommt diese Variable dann den Wert Zeichnen zugewiesen, da noch keinerlei Punkte vorhanden sind die gelöscht oder verschoben werden könnten. Durch betätigen der Maustaste im 2D Koordinatensystem wird dort ein Punkt gezeichnet und anschließend wieder in den Zustand Zeichnen zurück gegangen. Wird im 2D Koordinatensystem ein bereits gezeichneter Punkt angeklickt, geht das Programm in den Verschiebemodus über, welcher beim Loslassen der Maustaste durch den Zeichnenmodus ersetzt wird. Wenn, wie im Kapitel [2.4 Bearbeitungsbereich] besprochen, das Symbol Kreuz betätigt wird, wechselt das Programm in den Lösch -Modus. In diesem Modus können die gezeichneten Punkte der Kontur entfernt werden. Soll dieser Zustand verlassen werden, um in den Zeichnen -, oder Verschiebe -Modus zu gelangen, muss das Symbol Pfeil, wie im Diagramm dargestellt, ausgewählt werden OOA Klassendiagramm Punkt2D Kreis3D Punkt3D x y Anzahl getiswall() movepoint() 1 1 AnzahlPunkte Normals 1 1..* berechnenormal() 2 berechnekreis() x y z 1..* 1..* 1 1 PolygonZug2D KurvenZug3D DreieckZug3D actu start ende 1 1 actu start ende DreieckeproKreis addpoint() delpoint() search() addpoint() delpoint() search() setcoordinates() setnormals() setzedreiecke() Abb. 40 OOA Klassendiagramm 40

44 3. Projektverlauf Ein Klassendiagramm beschreibt das Zusammenspiel der Klassen eines Projektes. Zusammenhängende Klassen werden durch Assoziationen mit den dazugehörigen Kardinalitäten gekennzeichnet. Zusätzlich werden wichtige Variablen und Methoden im Klassendiagramm aufgeführt. Auch Vererbungsstrukturen sind im Klassendiagramm dargestellt. Die [Abb. 40] zeigt das Klassendiagramm der objektorientierten Analyse. Die Klasse Punkt2D beinhaltet die zweidimensionalen Koordinaten der Punkte des Streckenzuges. Wird also ein neuer Punkt im Koordinatensystem des Programms erzeugt, werden dessen Koordinaten in einem neuen Exemplar der Klasse Punkt2D gespeichert. Die Trennung zwischen der Klasse Kreis3D und der Klasse Punkt2D, obwohl eine 1:1 Beziehung besteht, wurde zur besseren Strukturierung eingeführt. Zudem findet die Berechnung des Kreises im Dreidimensionalen statt, und gehört somit auch nicht mit in die Klasse Punkt2D. In der Klasse Kreis3D wird aus den Koordinaten der Klasse Punkt2D ein dreidimensionaler Kreis errechnet, aus dem später das Objekt entsteht. Dazu aber im Kapitel [3.2.7 Kreis3D] mehr. Dieser dreidimensionale Kreis besteht aus einer, im Programm festgelegten, Anzahl von dreidimensionalen Punkten der Klasse Punkt3D. Diese ist wieder wie das Klassendiagramm zeigt, durch eine Komposition mit einer 1:1..* Kardinalität mit der Klasse Kreis3D verbunden. Hier findet man das Analysemuster Liste wieder, welches durch die Komposition und der 1..* Kardinalität erkannt wird. Ein dreidimensionaler Kreis besteht aus einzelnen gleichartigen Teilen, nämlich Punkt3D Objekten. Um aus den Daten der Klassen Kreis3D und Punkt3D einen 3D Körper zu erstellen, müssen diese durch Flächen verbunden werden. Dazu werden Dreiecke erstellt, die dann die einzelnen Abschnitte des dreidimensionalen Rotationskörpers aufbauen. Um das Ganze zu verwalten und zu steuern befindet sich im Klassendiagramm die Klasse DreieckZug3D. Diese Klasse bildet aus zwei dreidimensionalen Kreisen einen Dreieckszug, da aber Kreise benutzt werden, entsteht im Endeffekt ein geschlossenes Objekt. Durch die Koordinaten, die in den Exemplaren der Klasse Punkt2D gespeichert sind und der Reihenfolge deren Eingabe, ergibt sich dann ein Polygonzug. Dieser Polygonzug wird durch die Klasse PolygonZug2D repräsentiert. Auch an dieser Stelle kommt das Analysemuster Liste zum Einsatz, da ebenfalls viele gleichartige Teile, also die 2D Punkte diesem Polygonzug zugeordnet sind. Durch die 3D Kreise, die von den Koordinaten der 2D Punkte erzeugt werden, entsteht auch ein 3D Kurvenzug, der in der Klasse KurvenZug3D widergespiegelt wird. Dieser ist wieder über das Analysemuster Liste mit der Klasse Kreis3D verbunden. Die Klasse PolygonZug2D und KurvenZug3D sind, da sie im Bezug zueinander stehen, mit einer 1:1 Kardinalität verbunden. Diese beiden Klassen werden im objektorientierten Design zu einer Klasse zusammengezogen, weil es keinen Sinn machen würde einen 3D Kurvenzug zu erstellen, der schon eindeutig durch den 2D Kurvenzug (PolygonZug2D) und den dazugehörigen Klassen Kreis3D und Punkt3D beschrieben wird. Weiteres zum objektorientierten Entwurf wird im Kapitel[3.1.5 OOD Klassendiagramm] beschrieben. 41

45 3. Projektverlauf OOD Klassendiagramm 1 1 Hauptfenster - Auswahl: JToggleButton + VERSION: String + Mousepressed() + Mousemoved() + Mousedragged() + Mousereleased() 1 innere Klassen implementieren: - ActionListener - MouseMotionAdapter - MouseAdapter 1 * * Info2D - MausX: float - MausY: float - wall: float + movemouse(float x,float y) + setwall(float wall) + reset(float x, float y) Ansicht3D - Dreickeprokreis: int + redrawall() - make3dmodel() - makesurface3d (Punkt2d prev, Punkt2d actu) * 1 Ansicht2D - zeichnegraph (Graphics2D g2) + paintcomponent (Graphics g) Controller + addpoint() + delpoint() + movepoint(float x, float y) + deleteall(float xkor, float ykor) + movemouse(float x, float y) + mouseonpoint() + zoomin() + zoomout() + anzdreiecke(int anzahl) + laden(jframe Fenster) + speichern(jframe Fenster, Streckenzug pointlist) 1 + setwallwidth(float wall) + export(jframe Fenster) StreckenZug - wallwidth: float - wallende: Elem - wallstart: Elem - addv(punkt2d p1, Punkt2d p2) - scalarmulti(double w,punkt2d p) - normalenv(punkt2d p1, Punkt2d p2) - aufeins(punkt2d p) - richtungswinkel(punkt2d p1, Punkt2d p2) - Winkel(double[] a1, double[] a2) - errechnewpunkt(punkt2d actu, prev, next) + drawwall(streckenzug pointlist) + berechnewallneu(punkt2d actu, Streckenzug pointlist) + delete(int x, int y) + search(int x, int y) + addnew(object Element) TriangleStripArray //DreieckZug3D + setcoordinates(int index, Point3f[] coordinates) + setnormals(int index, float[] normals) 1 1 Export + exportwrl(file datei) + exportinc(file datei) + exporttxt(file datei) + exportj3d(file datei) 1 Dateiverwaltung + speichern(streckenzug) + laden(streckenzug) + save(streckenzug) Elem - Element: Object - next: Elem - prev: Elem Abb. 41 OOD Klassendiagramm 0..* 1 Liste <<abstract>> # start: Elem # actu: Elem # ende: Elem + go_get_next() + getnextelem() + clear() Punkt2D - x: int - y: int - Anzahl: int 1..* + getiswall() + movepoint() 1 Kreis3D 2 - AnzahlPunkte: int 1 + getnormal (int nr, Punkt2d prev, Punkt2d next) + berechnekreis() 1 1..* + x: float + y: float + z: float Point3f //Java3D Klasse 42

46 3. Projektverlauf Die [Abb. 41] zeigt das Klassendiagramm des objektorientierten Entwurfs. Neben den hinzugekommenen Klassen, hat sich auch die Struktur der Klassen aus dem OOA- Klassendiagramm verändert. Die beiden Klassen PolygonZug2D und KurvenZug3D wurden, wie im vorherigen Kapitel [3.1.4 OOA Klassendiagramm] bereits erwähnt, zusammen gezogen, weil ansonsten eine redundante Speicherung der Informationen entstanden wäre. Aus der Reihenfolge der erstellten 2D Punkte, die jetzt in der Klasse Streckenzug enthalten sind, und den Koordinaten der 2D Punkte, die in der Klasse Punkt2D gespeichert sind, ergibt sich bereits ein eindeutiger Rotationskörper. Außerdem liegt zwischen den beiden Klassen PolygonZug2D und KurvenZug3D eine 1:1 Beziehung vor, welche zusätzlich die Vereinigung dieser Klassen zur jetzigen Klasse Streckenzug rechtfertigt. Eine weitere Änderung zur objektorientierten Analyse ist die Entfernung der Assoziation zwischen Kreis3D und Streckenzug. Da die Verbindung zur Klasse Streckenzug bereits durch einen Umweg über die Klasse Punkt2D besteht, konnte die Assoziation zwischen Kreis3D und Streckenzug entfernt werden. Die Klassen DreiecksZug3D (TriangleStripArray) und Punkt3D (Point3f) mussten nicht realisiert werden, da diese schon in der Java3D-API zur Verfügung standen. Hinzugekommen sind die Klassen Liste und Elem. Die Klasse Streckenzug erbt von der abstrakten Klasse Liste, mit der sich eine vereinfachte, generalisierte Listenstruktur erzeugen lässt. Diese vereinfachte Listenstruktur wird durch die Klasse Streckenzug erweitert. An der Klasse Liste hängt durch die Generalisierung bedingt noch eine weitere Klasse Elem, mehr dazu ist im Kapitel [3.3.1 Datenstruktur] aufgeführt. Es wurde in diesem Projekt eine strenge Drei-Schichten- Architektur eingehalten. In [Abb. 41] durch die gestrichelten Linien zu erkennen. Die GUI-Schicht befindet sich im Klassendiagramm auf der linken Seite oben und beinhaltet alle Klassen der Benutzeroberfläche (Dialogführung, Präsentation usw.). Abb. 42 Drei-Schichten-Architektur Quelle: [Balzert] In der Mitte des Klassendiagramms ist die Fachkonzept- Schicht zu erkennen, welche aus der Objekt orientierten- Analyse entstanden ist. Ganz rechts steht die Datenerhaltungsschicht, die die dauerhafte Speicherung der Daten, in dem jeweiligem Format, verwaltet. In [Abb. 41] die strenge Drei-Schichten-Architektur zu sehen. Jeder Übergang von Assoziationen über eine gestrichelte Linie zeigt den Übergang in eine andere Schicht. Da aber ausschließlich zwischen den nebeneinanderliegenden Schichten Übergänge vorhanden sind, ist dies eine strenge Drei-Schichten-Architektur, die in [Abb. 42] aufgeführt ist. Würde es noch Assoziationen zwischen der GUI- und der Datenerhaltungsschicht geben, wäre eine flexible Drei-Schichten-Architektur vorhanden. 43

47 3. Projektverlauf Um die im Projekt eingehaltene strenge Drei-Schichten-Architektur zu realisieren, wurde ein Model-View-Controller Konzept erstellt. Der Controller befindet sich in der Fachkonzeptschicht und vermittelt zwischen den Schichten. Der Controller beinhaltet zu allen Ereignissen, die ausgelöst werden können, entsprechende Methoden. Mit Hilfe dieser Methoden wird der Controller angewiesen, was dieser bei einem Ereignis erledigen soll. Beispielsweise findet man folgende Methode im Controller wieder: public void addpoint() { univ.redrawall(); canvas2d.repaint(); inf2d.repaint(); Die Methode addpoint() wird durch das Hauptfenster, bzw. durch einen Mausklick auf das Koordinatensystem, ausgelöst. Der Controller ist jetzt angewiesen die nachfolgenden drei Aktionen auszuführen. Mit univ.redrawall() wird das 3D Objekt im Ansichtsbereich mit den dazu gekommenen Daten neu gezeichnet. Durch canvas2d.repaint() wird im 2D-Koordinatensystem der neue Punkt eingezeichnet. Und schließlich mit inf2d.repaint() der Informationsbereich unter dem 2D- Koordinatensystem aktualisiert. Der Controller ist also die Schnittstelle zwischen den Schichten, die dadurch getrennt voneinander realisiert werden konnten. Bei Veränderungen in einer Schicht mussten daher während der Realisierungsphase lediglich die Methoden im Controller angepasst oder neue Methoden erstellt werden. Auch für die Zukunft ist dieses Konzept wichtig, denn sollten später noch andere Funktionen im Programm realisiert werden, ist durch das Model-View-Controller Konzept ein einfacher Weg zur Integrierung gegeben. 44

48 3. Projektverlauf Sequenzdiagramme Sequenzdiagramme zeigen die wichtigsten Aktionen eines Programms, sie spiegeln die zeitlichen und klassenübergreifenden Tätigkeiten des Programms wieder. Hierbei ist aber zu beachten, dass, um die Diagramme nicht zu unübersichtlich zu gestalten, nur die wichtigsten Aktionen aufgezeigt werden. Sequenzdiagramm Punkt einfügen In [Abb. 43] wird zur Aktion Punkt einfügen das Sequenzdiagramm dargestellt. Es beschäftigt sich mit den Aktionen die ausgeführt werden, wenn der Benutzer einen Punkt, durch drücken der Maustaste auf das 2D Koordinatensystem, einfügt. Hierbei wird, wie das Diagramm zeigt, zuerst geprüft ob an dieser Stelle bereits ein Punkt vorhanden ist. Ist dies nicht der Fall und steht die Zustandsvariable Auswahl des Programms (siehe Kapitel [3.1.3 Zustandsautomat]) auf Zeichnen und wird der Mausklick innerhalb des 2D Koordinatensystems getätigt [Koordinaten in 2D Feld && Auswahl==Einfügen && ispoint==false], werden die restlichen Aktionen zum Einfügen eines Punktes ausgeführt. Es wird ein neues Exemplar der Klasse Punkt2D angelegt, welches automatisch ein neues Objekt der Klasse Kreis3D erzeugt. Diese Klasse Kreis3D erzeugt wiederum Exemplare der Java3D Klasse Point3f. Weiterhin wird das neu erzeugte Objekt von Punkt2D in den Streckenzug eingetragen und dem Controller mitgeteilt, dass ein neuer Punkt eingefügt wurde. Der Controller weist dann die einzelnen View`s (Ansicht3D, Ansicht2D und Info2D) an, sich mit den neun Daten zu aktualisieren. Sequenzdiagramm Punkt verschieben Die [Abb. 44] zeigt das Sequenzdiagramm Punkt verschieben, welches in vier Teile aufgeteilt ist. Will der Benutzer einen Punkt verschieben, muss er mindestens drei Aktionen durchführen. Zuerst wird die Maustaste gedrückt. In [Abb. 44] ist zu sehen, wie durch drücken der Maustaste mouse pressed die Methode ispunkt(koordinaten) der Klasse Streckenzug aufgerufen wird. Diese Methode prüft ob die Maustaste über einen bereits bestehenden Punkt gedrückt wurde. Ist dies der Fall, liefert die Methode true zurück. Anschließend wird durch Aufruf der Methode search(koordinaten) der entsprechende Punkt gesucht und durch eine globale Variable actu referenziert. An dieser Stelle ist eine globale Übergabevariable actu von Nöten, da der MotionAdapter beim draggen (verschieben des Mauszeigers bei gedrückter Maustaste) eine andere Methode aufruft, der keine Parameter übergeben werden können. Im zweiten Schritt, verschiebt der Benutzer den Punkt mit gedrückter Maustaste an eine beliebige Stelle. Dies ist im Sequenzdiagramm durch mouse dragged gekennzeichnet. Wurde die Maustaste dann im 2D-Koordinatensystem gedrückt und steht die Zustandsvariable Auswahl auf Zeichnen, wird die Methode movepoint(koordinaten) mit den aktuellen Koordinaten aufgerufen. Diese Methode aktualisiert die Daten des Punktes und berechnet den Rotationskörper, durch die Methode berechnekreis() der Klasse Kreis3D, neu. Anschließend wird dem Controller durch die Methode movepoint() mitgeteilt, das sich ein Punkt verändert hat und die View`s (Ansicht3D, Ansicht2D und Info2D) sich aktualisieren sollen. 45

49 3. Projektverlauf Lässt der Benutzer die Maustaste wieder los, ist das Ende der Aktion Punkt verschieben erreicht. Dies wird im Sequenzdiagramm durch mouse released gekennzeichnet und bewirkt, dass die Übergabevariable actu wieder auf null gesetzt wird. Der vierte Teil des Sequenzdiagramms hat nur indirekt etwas mit dem Verschieben eines Punktes zu tun. Hier wird dargestellt, wie beim Verschieben des Mauszeigers, dessen Position an den Infobereich des Programms übermittelt wird. Sequenzdiagramm Punkt löschen Alle Aktionen die ausgeführt werden müssen, wenn der Benutzer einen Punkt löscht, werden in [Abb. 45] dargestellt. Es wird überprüft, ob die Zustandsvariable Auswahl auf Löschen steht und ob der Mausklick im 2D-Koordinatensystem stattgefunden hat. Trifft dies zu, wird die Methode delete(koordinaten) der Klasse Streckenzug mit den aktuellen Mauskoordinaten aufgerufen. Die Methode searchelem(koordinaten) sucht den Punkt mit den entsprechenden Koordinaten. Findet die Methode einen Punkt, wird dieser durch delete(koordinaten) entfernt und der Durchlauf beendet. Anschließend lässt der Controller durch Aufruf der Methode delpoint(), alle View`s (Ansicht3D, Ansicht2D und Info2D) aktualisieren. Sequenzdiagramm new Button drücken Der Button new im Programm bewirkt, dass die Zeichenfläche und das Ansichtsfenster geleert werden. Die dafür auszuführenden Aktionen werden im Sequenzdiagramm [Abb. 46] gezeigt. Die statische Variable Anzahl der Klasse Punkt2D, wird auf 0 gesetzt. Anschließend die Methode clear() der Klasse Streckenzug aufgerufen, welche alle Elemente aus der verketteten Liste löscht. Dies geschieht, indem alle Referenzen (actu, start, ende) auf Null gesetzt werden, das physische Löschen der Exemplare erledigt der Garbage Collector. Wie bei den vorherigen Aktionen kümmert sich der Controller durch Aufruf der Methode clearall() darum, dass alle View`s (Ansicht3D, Ansicht2D und Info2D) auf den aktuellen Stand gebracht werden. Sequenzdiagramm Wandstärke einstellen Wird durch Verschieben des Wandstärke-Sliders, selbige verändert, müssen alle Wandpunke neu berechnet werden. Dies ist im Sequenzdiagramm [Abb. 47] abgebildet. Hier erledigt der Controller, durch Aufruf der Methode setwallwidth(float) die anstehenden Aufgaben. Zuerst wird die neue Wandstärke dem Infobereich, Klasse Info2D, und der Punkteliste Klasse Streckenzug übergeben. Danach die Methode drawwall() aufgerufen, welche die neuen Wandpunkte errechnet und in die Punkteliste einträgt. Abschließend veranlasst der Controller, ein aktualisieren der View`s (Ansicht3D, Ansicht2D und Info2D). 46

50 3. Projektverlauf : Hauptfenster : Streckenzug : Controller : Ansicht3D : Ansicht2D : Info2D Akteur mouse pressed if ( istpunkt(koordinaten) ) ispoint : Bool new(koordinaten) : Punkt2D : Kreis3D new(koordinaten) [Koordinaten in 2DFeld && Auswahl==Zeichnen && ispoint==false] berechnekreis(koordinaten) *[i=1..anzahldreiecke] new(koordinaten) : Point3f //Java3D Klasse addpoint2d(punkt2d) new() : Elem addpoint() redrawall() setzedreiecke() addchild() repaint() repaint() Abb. 43 Sequenzdiagramm (Punkt einfügen) 47

51 3. Projektverlauf : Hauptfenster : Streckenzug : Punkt2D : Kreis3D : Controller : Ansicht3D : Ansicht2D : Info2D Akteur mouse pressed istpunkt(koordinaten) [Koordinaten im 2DFeld && Auswahl==Einfügen && ispoint==true ] search(koordinaten) searchelem(koordinaten) *[ i=0; i<anzahl; i++ ] equal() mouse dragged [Koordinaten im 2DFeld && Auswahl==Zeichnen ] movepoint(koordinaten) berechnekreis() *[ i=1..anzahldreiecke] new(koordinaten) : Point3f //Java3D Klasse movepoint() redrawall() make3dmodel() makesurface3d() repaint() actu=null; mouse released move mouse movemouse(koordinaten) movemouse(koordinaten) Abb. 44 Sequenzdiagramm (Punkt verschieben) 48

52 3. Projektverlauf : Hauptfenster : Streckenzug : Elem : Controller : Ansicht3D : Info2D : Ansicht2D Akteur mouse pressed delete(koordinaten) SearchElem(Koordinaten) delete(koordinaten) [Koordinaten im 2DFeld && Auswahl==Löschen ] setanzahl(anzahl-1) delpoint() redrawall() make3dmodell() makesurface3d() repaint() repaint() Abb. 45 Sequenzdiagramm (Punkt löschen) 49

53 3. Projektverlauf : Hauptfenster : Punkt2D : Streckenzug : Elem : Controller : Ansicht3D : Ansicht2D : Info2D Akteur "new"-button drücken setanzahl(0) clear() actu=null; start=null; ende=null; *[i=1..anzahl] deleteall() redrawall() make3dmodell() makesurface3d() startansicht() repaint() reset() Abb. 46 Sequenzdiagramm (new Button drücken) 50

54 3. Projektverlauf : Hauptfenster : Controller : Info2D : Streckenzug : Ansicht3D : Ansicht2D : Info2D Akteur Wandstärke Slider verschieben setwallwidth(float) setwall(wall/10) setwallwidth((wall/10)*50) drawwall() *[i=0..anzahl] errechnewpunkt(actu,prev,next) *[i=0..anzahl] erstellewandpunkt(punkt2d,streckenzug) : Punkt2D new(koordinaten) addw() redrawall() make3dmodel() makesurface3d() repaint() repaint() Abb. 47 Sequenzdiagramm (Wandstärke einstellen) 51

55 3. Projektverlauf 3.2 Eigenschaften der Klassen In diesem Kapitel wird näher auf die einzelnen Aufgaben der Klassen des Programms eingegangen. Es werden wichtige Methoden und der Zusammenhang mit anderen Klassen erläutert. Da die Klassen alle aufeinander aufbauen (siehe Klassendiagramm [3.1.4 OOA Klassendiagramm]), ist die Reihenfolge der Klassen so gewählt, dass deren Zusammenspiel leicht verständlich dargestellt wird Hauptfenster (GUI) Die Klasse Hauptfenster realisiert die Benutzeroberfläche (GUI) des Programms. In dieser Klasse befindet sich auch die Start-Methode main, durch die das Programm ausgeführt werden kann. Die Methode main erzeugt ein Exemplar der Klasse Hauptfenster und speichert deren Referenz in der globalen statischen Variable Fenster, was im nachfolgenden Quelltext zu sehen ist. Diese Referenz wird benötigt, um das Fenster zum Beispiel beim Look&Feel-Wechsel zu aktualisieren. public static void main(string[] a) {... Fenster = new Hauptfenster("3D - surface of revolution "+VERSION); Der Codeausschnitt zeigt, das die Klasse Hauptfenster von der Klasse JFrame erbt, und die Klassen ComponentListener und ChangeListener implementiert. Die Klasse JFrame, von der geerbt wird, erzeugt das Aussehen des Fensters, welches durch die Klasse Hauptfenster erweitert und verändert wird. Deshalb muss im Konstruktor der Klasse Hauptfenster auch der Konstruktor der Oberklasse JFrame aufrufen werden, der dann das Fenster erzeugt. public class Hauptfenster extends JFrame implements ComponentListener, ChangeListener {... Hauptfenster(String Titel) { super(titel);... Durch die Implementierung der abstrakten Klasse ComponentListener, müssen folgende Methoden überschrieben werden: - componentresized (wird bei Größenänderung des Fensters aufgerufen) - componentmoved (wird beim Verschieben des Fensters aufgerufen) - componentshown (wird beim Anzeigen des Fensters aufgerufen) - componenthidden (wird beim Entfernen des Fensters aufgerufen) 52

56 3. Projektverlauf Da für dieses Projekt die Methode componentresized wichtig ist, wurden die anderen Methoden mit leeren Rümpfen überschrieben. Die Methode componentresized, die unten dargestellt ist, sorgt dafür, dass das Fenster nicht kleiner als die Mindesthöhe und Mindestbreite wird. Die Mindesthöhe und Mindestbreite wird durch die Konstanten MIN_WIDTH und MIN_HEIGHT der Klasse Hauptfenster bestimmt. public void componentresized(componentevent e) { int width = getwidth(); int height = getheight(); boolean resize = false; if (width < MIN_WIDTH) { resize = true; width = MIN_WIDTH; if (height < MIN_HEIGHT) { resize = true; height = MIN_HEIGHT; if (resize) { setsize(width, height); Die Implementierung der Klasse ChangeListener verlangt die Überschreibung einer Methode. Dies ist die Methode statechanged, die aufgerufen wird, wenn Änderungen einer Komponente vorliegen. Die Methode achtet auf Veränderungen der Schieberegler des Hauptfensters und reagieren darauf. Um die Ereignissteuerung, zum Beispiel das Betätigen eines Buttons abzufragen, muss das Hauptfenster noch folgende innere Klassen besitzen: MeinAktionLauscher, der die Klasse ActionListener implementiert. Hierdurch kann auf alle Ereignisse des Fensters, zum Beispiel das Betätigen eines Buttons oder anderer Elemente der Benutzeroberfläche, reagiert werden. Tritt solch ein Ereignis ein, wird die Methode actionperformed aufgerufen, die dann auf diese Aktionen reagiert. MeinMotionAdapter, der die Klasse MouseMotionAdapter erbt. Diese Klasse reagiert auf Mausereignisse, die durch Bewegungen ausgelöst werden. Das Bewegen des Mauszeigers, der die Methode mousemoved aufruft, oder das Draggen, durch das die Methode mousedragged aufgerufen wird. MeinMausAdapter, der die Klasse MouseAdapter erbt. Diese Klasse kümmert sich um Mausereignisse die nichts mit der Mausbewegung zu tun haben. Also das Drücken der Maustaste, das die Methode mousepressed ausgelöst oder das Loslassen der Maustaste, welches die Methode mousereleased aufruft. 53

57 3. Projektverlauf Die Hauptaufgabe der Klasse Hauptfenster ist die Darstellung der Benutzeroberfläche (GUI). Die Benutzeroberfläche besteht im Allgemeinen, wie bereits im Kapitel [2.1 Bedienoberfläche] erwähnt, aus dem Bearbeitungsbereich und dem Ansichtsbereich. Der Bearbeitungsbereich wird durch die Klassen Ansicht2D und Info2D realisiert, auf die in den nachfolgenden Kapiteln eingegangen wird. In [Abb. 48] wird gezeigt, welche JPanel in der Klasse Hauptfenster benutzt werden und welche Layoutmanager diese verwenden, um die Benutzeroberfläche so anzuordnen. Alle JPanel haben feste Ausdehnungswerte, wie im Quelltextbeispiel gezeigt. Ausschließlich das JPanel für den 3D-Ansichtsbereich ist dynamisch gestaltet, so dass bei einer Vergrößerung des Fensters nur dieser Ansichtsbereich größer wird und die anderen JPanel ihre Ausdehnung beibehalten. JPanel zusammen2d = new JPanel(new BorderLayout()); zusammen2d.setminimumsize(new Dimension(20,500)); zusammen2d.setpreferredsize(new Dimension(20,500)); zusammen2d.setmaximumsize(new Dimension(20,500)); ProgammMenüLinks (GridLayout 2Spalten, 1Zeile) //Pmenu LinkeSeite (BorderLayout) //LinksPanel Rand Mitte //mitte RechteSeite (BorderLayout) //RechtsPanel Rand Rechts //rechtsseite LinkeSeite (BorderLayout) //LinksPanel Rand Linksoben //linksoben Koordinatensystem (BorderLayout) //zusammen2d Rand Rechtsoben //rechtsoben 3D Ansichtsbereich (BorderLayout) //can3d MenüLinksUnten //menulinksunten MenüRechtsUnten (FlowLayout [LEFT]) //rechtsunten RandLinksUnten //linksunten Abb. 48 Aufbau der Benutzeroberfläche 54

58 3. Projektverlauf Ansicht2D Die Klasse Ansicht2D ist für die Darstellung des 2D-Koordinatensystems zuständig. Sie erbt von der Klasse JPanel, und stellt dadurch eine leere Grundfläche zum Zeichnen dar. Zum Zeichnen ist die Methode paintcomponent(), welche die Oberklassenmethode überschreibt, ausschlaggebend. Weitere Informationen zum Zeichnen mit Java2D sind im Kapitel [1.1 Einführung in Java2D] aufgeführt. Diese Methode wird automatisch bei Bedarf durch den Fenstermanager aufgerufen. Zusätzlich kann die Methode durch Aufruf der Methode repaint(), die in der Oberklasse JPanel existiert, aufgerufen werden. Diese Möglichkeit wird durch den Controller genutzt, um die Klasse Ansicht2D zum aktualisieren aufzufordern Neben dem Zeichnen des Koordinatensystems, besitzt diese Klasse noch eine Methode zeichnegraph(), die alle in der Klasse Streckenzug befindlichen Punkte ausliest und ins Koordinatensystem einzeichnet. Auf die Klasse Streckenzug wird später eingegangen. Das Einzeichnen der Punkte ins Koordinatensystem läuft folgendermaßen ab. Abb. 49 Ansicht2D- Streckenzug einzeichnen - Die Koordinaten des ersten Punktes werden ausgelesen und in der Variablen temp1 gespeichert. - Parallel geschieht dies mit den Koordinaten des zweiten Punktes, welche in der Variablen temp2 gespeichert werden. - Dadurch wird die Strecke in [Abb. 49] zwischen Punkt 1 und 2 gezeichnet. - Anschließend wird der eigentliche Punkt 1 gezeichnet. - Danach muss die Variable temp2 nach temp1 kopiert werden und in temp2 die Koordinaten des nächsten Punktes eingetragen. - Nachdem die Strecke zwischen Punkt 2 und Punkt 3 gezeichnet wurde, wird der eigentliche Punkt 2 gezeichnet. 1 2 Der ganze Algorithmus in Quelltextform befindet sich in Kapitel [I Zusätzliche Quelltexte]. Dieser Algorithmus wird benötigt, da ansonsten entweder die gezeichneten Strecken über die Punkte gezeichnet werden würden (siehe [Abb. 50]), oder die Punkteliste zweimal durchlaufen werden müsste. Einmal um alle Strecken einzuzeichnen und ein zweites mal, um die dazugehörigen Punkte an den Streckenenden zu zeichnen. Abb. 50 Fehler beim Einzeichnen des Streckenzuges 55

59 3. Projektverlauf Info2D Die Klasse Info2D befindet sich unterhalb der Klasse Ansicht2D. Dadurch ist die Trennung des Bearbeitungsbereichs (Ansicht2D) und des Infobereichs (Info2D) für den Benutzer nicht sichtbar. Die Klasse Info2D erbt, wie schon die Klasse Ansicht2D, von JPanel und stellt somit einen leeren Bereich zum Zeichnen dar. Die Klasse Info2D zeigt Statusinformationen, wie die Mausposition, die Anzahl der Punkte oder die eingestellte Wandstärke an. Wie auch in [Abb. 51] zu sehen ist. Abb. 51 Infobereich (Info2D) Um die Mausposition oder die Größe der Wandstärke gut lesbar formatiert auszugeben, wird das Paket java.text.* importiert. Dieses Paket stellt die Klasse DecimalFormat zur Verfügung, durch deren Methoden die float Zahlen vernünftig formatiert werden können. DecimalFormat df = new DecimalFormat( "0.00" );... g2.drawstring("x: "+df.format((mausx-50)/50)... Wie im Quelltext zu sehen, muss ein neues Exemplar der Klasse DecimalFormat erstellt werden. Dem Konstruktor des Objekts wird die gewünschte Formatierung, sozusagen als Vorlage, mitgegeben, hier 0.00 für zwei Nachkommastellen. In [Abb. 52] werden alle Formatierungsanweisungen der Klasse DecimalFormat aufgelistet. 0 Repräsentiert eine Ziffer. # Eine Ziffer; Ist an dieser Stelle keine angegeben, bleibt die Stelle leer.. Trennt Vor- und Nachkommastellen., Gruppiert die Ziffern (eine Gruppe ist so groß wie der Abstand von ',' zu '.'). ; Trennzeichen für mehrere Formate - Das Standardzeichen für das Negativpräfix % Die Zahl wird mit 100 multipliziert und als Prozentwert ausgewiesen. %% Genau wie % nur mit Promille X ' Alle anderen Zeichen können ganz normal benutzt werden. Ausmarkieren von speziellen Symbolen im Präfix oder Suffix Abb. 52 Formatierungsanweisungen DecimalFormat Quelle: [JavaInsel] 56

60 3. Projektverlauf Streckenzug Die Klasse Streckenzug dient zur Speicherung der 2D-Koordinaten der Konturpunkte. Diese Klasse erbt von der Klasse Liste und realisiert eine verkettete Liste. Die im Streckenzug aufgeführten Methoden erweitern zum einen die Funktionalität der Liste und dienen zum anderen zur Berechnung der Wandpunkte. Auf die verkettete Liste wird im Kapitel [3.3.1 Datenstruktur] eingegangen. Die Berechnung der Wandpunkte wird im Kapitel [3.3.2 Berechnung der Wandstärke] beschrieben. Gespeichert werden in der Liste Objekte vom Typ Punkt2D, die die Koordinaten der gezeichneten Wandpunkte enthalten Punkt2D Die Klasse Punkt2D speichert die Koordinaten eines zweidimensionalen Punktes. Hierbei gibt es zwei verschiedene Arten von Punkten. Zum einen die Punkte, welche der Benutzer durch Mausklick einfügt. Zum anderen die errechneten Wandpunkte, die von dem Wert des Schiebereglers für die Wandstärke auf der Benutzeroberfläche abhängig sind. Näheres zu den Wandpunkten finden sie im Kapitel [3.3.2 Berechnung der Wandstärke]. Zur Unterscheidung der zwei verschiedenen Punkte wurde der Klasse Punkt2D eine Variable iswall hinzugefügt, die den Wert 0 oder 1 annehmen kann. Besitzt diese Variable den Wert 0, ist der jeweilige Punkt kein Wandpunkt, wenn die Variable den Wert 1 annimmt, handelt es sich um einen Wandpunkt. Diese Unterscheidung ist hauptsächlich für das 2D-Koordinatensystem wichtig, denn Wandpunkte können weder verschoben noch gelöscht werden. Die Festlegung, ob der Punkt ein Wandpunkt ist oder nicht, wird bereits während der Erstellung des Exemplares durch den Konstruktor bestimmt. Punkt2d (float XPos, float YPos, int XK, int YK, int wert) { Anzahl++; X_Pos=XPos; Y_Pos=YPos; XKor = XK; YKor = YK; iswall=wert; kreis = new Kreis3D((float)(X_Pos/5),(float)((Y_Pos-4)/5),this); Wie im Quelltextauszug zu sehen ist, wird beim Aufruf des Konstruktors durch den letzten Parameter bestimmt, ob dieser Punkt ein Wandpunkt ist (wert=1) oder nicht (wert=0). Die restlichen übergebenen Werte werden in den Variablen der Klasse gespeichert und noch ein Exemplar der Klasse Kreis3D erzeugt. Die übergebenen Parameter werden symmetrisch skaliert, um das gesamt Objekt zu verkleinern und die Y-Werte werden auf 0 zentriert, so dass der Wertebereich von 4 bis 4 reicht und nicht von 0-8 geht. Auf die Klasse Kreis3D wird im Kapitel [3.2.7 Kreis3D] eingegangen. Wie man im Aufruf des Konstruktors der Klasse Punkt2D sieht, werden zwei X und Y Koordinaten übergeben. Die ersten beiden Werte, XPos und YPos, sind die Koordinaten, die der Fenstermanager, bei Abfrage der Mausposition in der Methode mousepressed() der Klasse Hauptfenster, preis gibt. 57

61 3. Projektverlauf Die anderen beiden Koordinaten müssen so umgerechnet werden, dass sie mit dem 2D-Koordinatensystem der Benutzeroberfläche überein stimmen. Um diese Umrechnung nicht ständig neu zu machen, werden diese Werte zusätzlich in der Klasse Punkt2D gespeichert. In [Abb. 53] ist zu sehen, wie das Koordinatensystem der Benutzeroberfläche aufgebaut ist. Vom äußeren Rand bis zur Koordinatenachse sind je 50 Pixel Platz. Jede Einheit auf den Koordinatenachsen ist 50 Pixel von der nächsten Einheit entfernt. a b 50 Pixel 50 Pixel 250 Pixel Um die Koordinaten der Mausposition für die X-Achse so umzurechnen, dass sie dem gezeigten Koordinatensystem gerecht werden, müssen folgende Berechnungen ausgeführt werden. Die Mausposition muss um 50 Pixel weiter nach links verschoben werden, um den Rand zwischen Fenster und der X-Achse zu entfernen. Dies ist in der Abbildung jeweils mit a bezeichnet. Anschließend wird dieser Wert durch 50 geteilt, weil der Abstand jeder Einheit 50 Pixel beträgt. Dies wird in der Abbildung mit b gekennzeichnet. Die gesamte Rechenformel lautet dann ((xkor-50)/50), wenn xkor die X-Mausposition beinhaltet. Abb. 53 Umrechnung der Fensterkoordinaten Da das Fenstersystem den Nullpunkt in der linken oberen Ecke sieht, muss für die Y- Koordinate noch eine weitere Umrechnung durchgeführt werden. Neben der Umrechnung, die schon für die X-Koordinate durchgeführt wurde ((ykor- 50)/50) muss der hier erhaltene Wert noch durch 8 dividiert werden, da die Y-Achse maximal 8 Einheiten anzeigt. Dies ist durch c in der Abbildung deutlich gemacht. Die Umrechnung für die Y-Koordinate sieht wie folgt aus (8-((ykor-50)/50)). Punkt2d temp = new Punkt2d(((xkor-50)/50), (8-((ykor-50)/50)), m_xpos, m_ypos,0); 58

62 3. Projektverlauf Im Quelltextauszug wird dargestellt, wie ein Exemplar der Klasse Punkt2D erzeugt wird. Hierfür sind folgende Parameter zu übergeben: umgerechneter x-wert, umgerechneter y-wert, x-mausposition, y-mausposition, Wandstärke (0/1). Wie die Klasse Punkt2D im einzelnen durch die Klasse Streckenzug verwaltet und gespeichert wird, ist im Kapitel [3.3.1 Datenstruktur] näher erläutert Ansicht3D Die Klasse Ansicht3D übernimmt die komplette Darstellung der Java3D-Umgebung. Dem Konstruktor der Klasse wird der 2D-Streckenzug übergeben, welcher in dem canvas3d dargestellt werden soll. VirtualUniverse Locale hg Betrachtungszweig light1 light2 ambient- LightNode gbnode Changer objtrans rkoerper BG BG BG... S. 3D S. 3D S. 3D Appearance Geometry Abb. 54 Aufbau des Inhaltszweiges des Szenengraphen 59

63 3. Projektverlauf scene = make3dmodel(); Als erstes wird der Szenengraph über die Methode make3dmodell() erzeugt. Die Methode gibt zu Beginn ein leeres Branchgroup-Objekt zurück, da noch kein 2Dstreckenzug existiert. Danach erfolgt die Erstellung eines canvas3d und eines SimpleUniverse-Objektes, so wie eines viewingplatform und orbit -Objektes. GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); canvas3d = new Canvas3D (config); universe = new SimpleUniverse(canvas3d); ViewingPlatform viewingplatform = universe.getviewingplatform(); viewingplatform.setnominalviewingtransform(); orbit = new OrbitBehavior(canvas3d, OrbitBehavior.REVERSE_ALL); Das canvas3d-objekt wird zur Darstellung des Java3D-Bereiches auf dem Bildschirm benötigt. Das simpleuniverse und das ViewingPlatform Objekt realisieren den Betrachtungszweig, siehe auch [1.2.1 Der Aufbau des Szenengraphen]. Das Objekt der Klasse orbit wird zur einfachen Steuerung der 3D-Umgebung benutzt. Diese wurde in Kapitel [1.2.5 Maussteuerung] beschrieben. BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0); hg=new BranchGroup(); hg.setcapability(branchgroup.allow_detach); Color3f bgcolor = new Color3f(0.9f, 0.9f, 0.99f); Background bgnode = new Background(bgColor); bgnode.setapplicationbounds(bounds); hg.addchild(bgnode); Die Klasse BoundingSphere setzt eine maximale Grenze für die Szene fest, welche unter anderem für die Lichtberechnung benutzt wird. Das anschließend erzeugte Objekt der Klasse Banchgroup, dient zur Gruppierung der Hintergrundinformationen der Java3D-Szene. So wird dort die Hintergrundfarbe und, wie im Nachfolgenden erkennbar, auch das Licht, abgelegt. Color3f ambientcolor = new Color3f(0.1f, 0.1f, 0.1f); AmbientLight ambientlightnode = new AmbientLight(ambientColor); ambientlightnode.setinfluencingbounds(bounds); hg.addchild(ambientlightnode); Color3f light1color = new Color3f(1.0f, 1.0f, 0.9f); Vector3f light1direction = new Vector3f(1.0f, 1.0f, 1.0f); Color3f light2color = new Color3f(1.0f, 1.0f, 1.0f); Vector3f light2direction = new Vector3f(-1.0f, -1.0f, -1.0f); 60

64 3. Projektverlauf DirectionalLight light1 = new DirectionalLight(light1Color, light1direction); light1.setinfluencingbounds(bounds); hg.addchild(light1); DirectionalLight light2 = new DirectionalLight(light2Color, light2direction); light2.setinfluencingbounds(bounds); hg.addchild(light2); Zuerst wurde ein Umgebungslicht erzeugt, dass die gesamte Szene gleichmäßig erhellt, danach folgen zwei gerichtete Lichtquellen. objtrans = new TransformGroup(); Transform3D matrix = new Transform3D(); matrix.settranslation(new Vector3f(0.0f, 0.0f, 0.0f)); matrix.setscale(0.5); objtrans.settransform(matrix); objtrans.addchild(scene); Um den gesamten Rotationskörper verkleinern und vergrößern zu können, wurde diesem eine Transformgroup übergeordnet. changer=new BranchGroup(); changer.setcapability(branchgroup.allow_detach); changer.addchild(objtrans); hg.addchild(changer); universe.addbranchgraph(hg); Das BranchGroup-Objekt changer wurde erzeugt, um den Szenengraph gegen einen neu gezeichneten Szenengraph austauschen zu können. Es muss die Eigenschaft ALLOW_DETACH gesetzt werden, um dieses wieder aus einem BranchGroup-Knoten ausfügen zu können. In der letzten Zeile wird der Hintergrundknoten, mit dem kompletten Inhalt an das universe angehangen. Dadurch wird der Szenengraph auch als live angesehen und auf dem Bildschirm angezeigt. orbit.setschedulingbounds(bounds); viewingplatform.setviewplatformbehavior(orbit); Als letzter Schritt wird noch dem OrbitBehavior-Objekt eine Referenz auf die in bounds eingestellten Grenzen der Szene übergeben, wodurch eine optimierte Berechnung bei der zeitlichen Planung von Animationen oder dem Verhalten von Objekten möglich ist. Über setviewplatformbehavior wird der Viewplatform der OrbitBehavior zugewiesen, so dass der OrbitBehavior dadurch die Ansicht der Szene beeinflussen kann. Das Erstellen des Rotationskörpers wird in Kapitel [3.3.3 Erstellen eines Rotationsobjektes] beschrieben. 61

65 3. Projektverlauf Kreis3D Die Klasse Kreis3D stellt in dem Programm die Speicherung der Werte für eine dreidimensionale Kreisebene zur Verfügung. Dabei werden alle Punkte auf einer Ebene in einem Objekt dieser Klasse über das Array pointr referenziert. Die Methode public void berechnekreis()wird bei der Initialisierung eines neuen Objektes aufgerufen und errechnet über die 2D-Kordinaten eines Wandpunktes alle 3D-Koordinaten der Punkte einer Kreisbahn. public void berechnekreis(float x, float y) { pointr = new Point3f[anzahl]; normals = new Vector3f[anzahl]; for(int i=0;i<this.anzahl;i++){ float Xzu1 =(float)math.sin(((float)i)/(float)(anzahl- 1)*360*Math.PI / 180) ; float Zzu1 = (float)math.cos(((float)i)/(float)(anzahl- 1)*360*Math.PI / 180) ; pointr[i] = new Point3f(Xzu1 * x,y,zzu1 * x); Die Funktionalität dieser Methode wird genauer in Kapitel [3.3.3 Erstellen eines Rotationsobjektes] beschrieben. Neben dem Berechnen der 3D-Koordinanten existiert in der Klasse noch die Methode public Vector3f getnormal(), die die Normalenvektoren berechnet. Diese Berechnung wird ausführlich im Kapitel [3.3.4 Normalenvektoren] beschrieben Dateiverwaltung/Export Die Klassen Dateiverwaltung und Export sind für die Datenerhaltung dieses Projektes zuständig. Die Klasse Dateiverwaltung ist für die Speicherung und Wiederherstellung des Streckenzuges, welcher mit dem Programm erzeugt wurde, zuständig. Die Klasse Export ist für das Exportieren des Streckenzuges in andere Formate zuständig. Dateiverwaltung Um den gezeichneten Streckenzug in einer Datei zu speichern, gibt es zwei Möglichkeiten. In der ersten Methode speichert man die wirklich relevanten Daten, hier jeweils die X- und Y-Koordinaten der Streckenzugspunkte, und erzeugt daraus beim Laden dann wieder die gesamte Datenstruktur. Diese Methode ist sehr aufwändig und würde mehr Zeit beim Speichern und Laden benötigen. Die zweite Möglichkeit ist die Serialisierung von Java zu benutzen. Hierbei muss jede Klasse, die gespeichert werden soll, die abstrakte Klasse Serializable implementieren, also zum Beispiel: public class Punkt2d implements Serializable{... 62

66 3. Projektverlauf Diese Klasse besitzt allerdings keine Methoden, so dass in der zu implementierenden Klasse keine Methoden überschrieben werden müssen. Die Serialisierung übernimmt die komplette Speicherung der Klassen in Dateien, wobei alle Assoziationen oder ähnliches erhalten bleiben. Um die Klassen später wieder in den Speicher zu laden, werden diese dann deserialisiert, wobei der Zustand dieser Klassen nicht verändert wird. Dabei wird aber mehr Speicherplatz benötigt, so dass die serialisierte Datei größer ausfällt, da die komplette Datenstruktur (siehe auch [3.3.1 Datenstruktur]) gespeichert wird. In diesem Projekt wurde, um das Rad nicht neu zu erfinden, die in Java enthaltene Methode der Serialisierung gewählt und somit eine etwas größere Datei in Kauf genommen. Um die Auswahl des Dateinamens bei der Speicherung oder beim Laden nicht zu kompliziert zu machen, ist eine Vorfilterung der Dateien implementiert worden. Es werden beim Laden oder Speichern nur die Dateien angezeigt, die im Format des Programms vorliegen und somit die Endung *.sor besitzen. Um dies zu realisieren, benötigt man eine innere Klasse filefilter, die von der Klasse FileFilter erbt und deren Methoden accept() und getdescription() überschreibt. Dabei werden die zu überschreibenden Methoden entsprechend der Dateifilterung angepasst, wie es im nachfolgenden Quelltextauszug zu sehen ist. private static class filefilter extends FileFilter { public boolean accept( File f) { return f.isdirectory() f.getname().tolowercase().endswith(".sor"); public String getdescription() { return "surface-of-revolution-files"; Um die zu ladende oder zu speichernde Datei in einer grafischen Benutzeroberfläche auszuwählen, wurde die Klasse JFileChooser benutzt. Diese Klasse besitzt bereits die Eigenschaften und ist in Java vorhanden. Dieser Klasse JFileChooser muss jetzt noch ein Exemplar der Klasse filefilter übergeben werden, damit diese aktiv wird. Dies geschieht wie folgt: filechooser.setfilefilter(filefilter);. Damit der Benutzer jederzeit weiß, welche Datei er geladen hat oder unter welcher Datei bereits gespeichert wurde, wird der Dateiname in der Titelleiste des Programmfensters angezeigt. Um dies zu bewerkstelligen, holt sich die Klasse Hauptfenster, nachdem eine Datei geladen wurde, deren Referenz vom Controller (im Quelltextauszug als C1 bezeichnet). Dies muss so gemacht werden, da beim Aufruf der Methode Laden die Punkteliste zurück gegeben wird und nicht die Referenz auf die Datei. Aus der angefragten Referenz kann dann die Klasse Hauptfenster den Dateinamen extrahieren und diesen in der Titelleiste anzeigen. Beim Speichern einer Datei wird die Referenz dieser Datei gleich an die Klasse Hauptfenster übergeben, da hier die Punkteliste nicht zurück geliefert werden muss. 63

67 3. Projektverlauf if((datei=c1.getdatei())!=null) { Fenster.setTitle("3D - surface of revolution "+VERSION+" - "+Datei.getName()); Export Die Klasse Export wird benötigt, um den gezeichneten Streckenzug in andere Formate zu exportieren. Dadurch kann der gezeichnete Rotationskörper in anderen Programmen, wie auch im Kapitel [2.6 Export und Weiternutzung] besprochen, genutzt werden. Wie schon bei der Klasse Dateiverwaltung erwähnt, benutzt auch die Klasse Export verschiedene FileFilter, um die Dateien, die im Export-Dialog angezeigt werden, zu filtern. Es gibt zu jedem exportierbarem Format genau eine Klasse FileFilter, die, wie auch schon bei der Dateiverwaltung, als innere Klassen realisiert sind. - filefilterj3d: Filtert Java3D *.java Dateien - filefilterinc: Filtert PovRay *.inc Dateien - filefiltertxt: Filtert Textdateien *.txt - filefilterwrl: Filtert VRML *.wrl Nachdem der Benutzer das gewünschte Format im Export-Dialog (siehe Kapitel [2.6.1 Export Fenster]) ausgewählt hat, wird eine der dazugehörigen Export-Methoden aufgerufen. Diese Methoden (exportj3d(), exportinc(), exporttxt(), exportwrl()) durchlaufen die Punkteliste und erstellen die exportierte Datei. Um in Dateien zu schreiben, muss das Paket java.io.*; importiert werden. Dieses Paket stellt dann die Klasse FileWriter und PrintWriter zur Verfügung. try { FileWriter ausgabestrom = new FileWriter(datei); PrintWriter ausgabe = new PrintWriter(ausgabestrom);... ausgabe.println("exportierte Werte");... ausgabe.close(); catch(ioexception error) { System.err.println(error.toString()); Wie im Quelltextausschnitt zu sehen ist, wird zuerst ein Exemplar der Klasse FileWriter erzeugt, welches den Dateinamen als String übergeben bekommt. Anschließend wird ein Exemplar der Klasse PrintWriter erstellt, dem das Objekt der Klasse FileWriter übergeben werden muss. Jetzt kann mit der Methode println() der Klasse PrintWriter in die Datei geschrieben werden. Nachdem alles in die Datei geschrieben wurde, wird die Ausgabe mit der Methode close() beendet und die Datei geschlossen. Der ganze Block, bei dem in Dateien geschrieben wird, muss in einer try/catch-anweisung stehen, da während des Schreibens in Dateien Fehler auftreten könnten. Das Abfangen der Fehler durch einen try/catch-block wird bereits vom Compiler verlangt. Tritt ein Fehler auf, wird der catch-block ausgeführt, damit das Abbrechen des Programms durch eine Exception abgefangen wird. 64

68 3. Projektverlauf 3.3 Probleme und Lösungen Probleme gab es unter anderem bei der Erstellung der Benutzeroberfläche. Beim Mischen der Swing Komponenten und der Java3D Zeichenfläche Canvas3D traten einige Fehler auf. Zum einen gab es dasselbe Problem, welches schon im Kapitel [1.1.1 Grundobjekte] besprochen wurde, und beim mischen von Swing und AWT Komponenten auftrat. Die Überdeckungen wurden nicht richtig angezeigt. Beim Zusammenspiel von Java3D Komponenten und Swing Elementen, gab es genau das selbe Problem. Die Java3D Komponenten wurden immer im Vordergrund gezeichnet! Zum anderen gab es Probleme beim Einfügen von mehreren Elementen. Sollten z.b. neben der Java3D Zeichenfläche noch weitere Elemente, wie z.b. Buttons oder ähnliches eingefügt werden, verschwand die Java3D Zeichenfläche einfach. Auf der Webseite wurde dann geraten, das Canvas3D in ein JPanel zu packen und es somit in eine Swing Oberfläche einzuarbeiten. Trotzdem muss diesem JPanel entweder kein LayoutManager zugeordnet werden, oder es besteht die Möglichkeit das BorderLayout zu benutzen. Wird das BorderLayout benutzt, muss das Canvas3D aber in die Mitte, also mit Center, eingefügt werden. Befolgt man dies nicht, verschwindet das Canvas3D und man sieht nichts von der erzeugten Java3D Szene. Wieso das so ist oder wie man dieses Problem anders lösen könnte, ist nicht bekannt. Es wurde lediglich herausgefunden, das die Canvas3D als AWT Komponente behandelt wird. Diese Komponenten sind heavyweight (schwergewichtige) Komponenten, welche vom Betriebssystem direkt einen Bildschirmbereich, auf dem sie sich selbst zeichnen, zugewiesen bekommen. Die Swing-Komponenten jedoch leihen sich den Bildschirmbereich von der jeweils übergeordneten Komponente. Die übergeordnete Komponente berücksichtigt die Anordnung der Komponenten hintereinander. Dadurch können Swing-Komponenten sich gegenseitig überlappen und werden somit als lightweight (leichtgewichtig) bezeichnet. Bei der Kombinierung von schwergewichtigen und leichtgewichtigen Komponenten funktioniert diese Überlappung nicht mehr richtig, denn schwergewichtige Komponenten zeichnen sich immer direkt auf dem Bildschirm und überlappen dadurch alles andere. 12 In diesem Projekt wurde zumindest dieses Überlappungs-Problem durch geschickte Anordnung der Komponenten umgangen. Die Inkompatibilität zwischen Swing und Java3D Komponenten ist zwar nicht beseitigt, aber fällt dem Benutzer durch das Design nicht weiter auf. 12 vgl. Hofmann 65

69 3. Projektverlauf Ein weiteres Problem, welches aber nicht gelöst werden konnte, tritt auf, wenn der Benutzer das Hauptfenster verkleinert. Und zwar wenn das Hauptfenster kleiner gezogen wird als das Java3D Ansichtsfenster. Nach dem automatischen Resize, welches im Programm implementiert ist und im Kapitel [3.2.1 Hauptfenster (GUI)] erklärt wird, ist der Java3D Ansichtsbereich verschwunden. Dieses Problem tritt allerdings ausschließlich auf, wenn die Low-API DirectX benutzt wird. Es wird auch nicht als normale Java Exception behandelt, sonders es ist ein Fehler, der außerhalb der JavaRuntime Umgebung auftritt. Dieser Fehler wird zusätzlich in einer Textdatei festgehalten, welche im Anhang [I Zusätzliche Quelltexte] aufgeführt ist. Zu diesem Problem wurden keinerlei Lösungsansätze gefunden. Lediglich auf der Webseite wurde dieser Fehler als Bug ID aufgeführt. Die dort erwähnten Ansätze zur Lösung des Problems hatten allerdings keinerlei Wirkung. Beim Studium der Methode removechild(int index) der Klasse Group fällt auf, dass eine Indizierung der einzelnen Branchgroups vorliegt, aber keinerlei Dokumentation vorhanden ist, wie die Indizierung realisiert wurde. Auch existieren keinerlei Beispiele zu dieser Methode auf der Seite von Sun, genauso wie dort nicht auf das Anhängen oder Löschen von Teilbäumen eingegangen wird. Als Alternative zu der nicht ausführlich dokumentierten removechild-methode existiert noch die Methode detach() in der Klasse BranchGroup. Der Aufruf dieser Methode setzt allerdings eine existierende Referenz auf die BranchGroup voraus, welche, falls nicht vorhanden, wieder über den nicht dokumentierten Index der Klasse Group über die Methode getchild(int index) zu erhalten ist. Da in diesem Projekt sehr viele BranchGroups erzeugt werden, ist eine aktive Referenzerhaltung innerhalb eines zusätzlichen Arrays sehr aufwändig. Ein Vergleich der Geschwindigkeit, zwischen dem Neuzeichnen eines Teilbaumes und dem Neuzeichnen des gesamtem Objektes ergaben keinen messbaren Unterschied, so dass in diesem Projekt auf den Umstand des entfernens eines Teilbaumes verzichtet wurde und das gesamte Objekt ersetzt wird. Abb. 55 Fehler in Java3D bei DirectX Desweiteren erwies sich DirectX bei der Darstellung von sehr vielen Objekten als unzuverlässig. So scheint es: Wird eine bestimmte Anzahl an Objekten überschritten, wird der Rest nicht dargestellt. Daher handelt es sich bei dem in [Abb. 55] gezeigten Programmausschnitt nicht um ein Bild, das beim Aufbau des Objektes erstellt wurde, sondern um das fertig gerenderte Objekt. Da heute Grafikkarten problemlos zwischen 15 und 100 Millionen Dreiecke darstellen können, liegt die Vermutung nahe, dass es sich um einen Implementationsfehler der DirectX - Schnittstelle in Java3D handelt. Da dieser Fehler auf die Programmstabilität keinerlei Einfluss nimmt, wurde dieser so akzeptiert und nicht versucht zu umgehen, zudem die Alternativlösung mit OpenGL auch diesbezüglich keinerlei Probleme aufzeigt vgl. [ToMMT] 66

70 3. Projektverlauf Die bekannte schlechte Performance von Java3D machte sich natürlich auch in diesem Projekt bemerkbar, so wurde das gesamte Programm sehr langsam, wenn zu viele Dreiecke in dem Java3D Fenster dargestellt werden sollten. Um dieses Problem zu umgehen, existiert die Funktion AutoSet. So wird dort, je nach Anzahl der Punkte, die Darstellungsqualität verringert. Dies geschieht über eine Verminderung der Anzahl der Dreiecke pro Kreis. Die Berechnung erfolgt über die Expotentialfunktion, wie die [Abb. 56 Reduzierung der Darstellung] zeigt. Es entsteht ein Wert, dessen Asymptote gegen x=0 läuft und dessen y-wert im Intervall 0 bis 1 liegt. Dieser Wert wird mit der minimalen und maximalen Anzahl von Dreiecken so verrechnet, dass ein stetiger Übergang entsteht. Abb. 56 Reduzierung der Darstellung if(pointlist.getwallwidth()>0){ wert = Math.exp(-0.1 * Punkt2d.getAnzahl()/2 ); else{ wert = Math.exp(-0.1 * Punkt2d.getAnzahl() ); wert2= maxdrei * wert+ mindrei* (1-wert); 67

71 3. Projektverlauf Datenstruktur Als Datenstruktur wurde in diesem Projekt eine doppelt verkette Liste benutzt. Diese hat den Vorteil, dass die Liste durchlaufen werden kann und somit der Zugriff auf alle Punkte schnell möglich ist. Es gibt keinen Direktzugriff auf einzelne Punkte der Liste, wie es etwa bei einem Array möglich gewesen wäre. Dafür verursacht ein Array, beim Löschen eines Punktes aus dem Streckenzug, Fragmentierungen. Diese Fragmentierungen entstehen bei einer doppelt verketteten Liste nicht, da das zu löschende Objekt aus der Liste entfernt wird, und deren Vor- und Nachfolger anschließend aufeinander zeigen. Um die Wiederverwendbarkeit zu verstärken, wurde eine Oberklasse Liste realisiert, die alle Grundmethoden und Variablen besitzt, welche eine doppelt verkettete Liste benötigt. Zudem wurden in dieser Oberklasse alle Methoden, die noch implementiert werden müssen, aber wegen der Wiederverwendbarkeit noch nicht in der Oberklasse eingeführt werden können, abstrakt gemacht, um diese in der erbenden Klasse Streckenzug auszufüllen. Um die Wiederverwendbarkeit zusätzlich noch zu stärken, wurde die verkettete Liste so angelegt, dass die Liste selber nur die Klasse Elem verwalten kann. In dieser Klasse existiert eine Variable Element, welche den Typ Object besitzt. Dadurch kann an dieser Klasse Elem jede beliebige andere Klasse angehangen werden, die dann in der Liste eingefügt wird. In diesem Projekt werden 2D-Punkte verwaltet und somit die Klasse Punkt2D an dieser Stelle angehangen. In [Abb. 57] ist dargestellt, wie die Liste aufgebaut ist. Lediglich in den Klassen, wo die in der Liste befindlichen Elemente benötigt werden, muss eine Typumwandlung durchgeführt werden, wie im Quelltextauszug zu sehen ist. actu = (Punkt2d)pointlist.go_get_next(); Streckenzug start actu ende next X Elem Elem Elem X next prev prev Punkt2D Punkt2D Punkt2D Abb. 57 Datenstruktur verkettete Liste 68

72 3. Projektverlauf In diesem Projekt können, wie im Kapitel [3.3.2 Berechnung der Wandstärke] beschrieben wird, noch zusätzlich zu den gezeichneten Punkten, deren Wandpunkte eingefügt werden. Diese errechneten Wandpunkte werden in der selben Liste wie die normalen Punkte verwaltet und sind nur durch den Wert der Variablen iswall in der Klasse Punkt2D zu unterscheiden. Näheres zur Unterscheidung der Wandpunkte von den normalen Punkten wird im Kapitel [3.2.5 Punkt2D] erläutert. In [Abb. 58] wird, durch die senkrechte, gestrichelte Linie angedeutet, gezeigt, wie die normalen Punkte und die Wandpunkte voneinander getrennt sind. Wird ein Punkt, zum Beispiel der in der Abbildung mit der Nummer 7 gekennzeichnete, eingefügt, muss dieser am Ende der normalen Punkte eingefügt werden. Der dazu errechnete Wandpunkt muss aber am Anfang der Wandpunkte eingefügt werden. Um dies zu bewerkstelligen muss das Element mit der Nummer 3 seine Verbindung zum Element 4 lösen und sich mit Element 7 verbinden. Das Element 7 verbindet sich mit Element 8 und das wiederum mit Element 4. Geschieht dies, sind die beiden Punkte richtig in die Liste eingefügt worden. Ein weiterer Vorteil der verketteten Liste ist das schnelle entfernen vieler nacheinander folgender Punkte. Wird z.b. die Wandstärke vom Benutzer ausgeschaltet, werden keine Wandpunkte in der Liste mehr benötigt. Hier muss dann lediglich die Referenz next des letzten normalen Punktes auf null gesetzt werden, weiter müssen die Referenzen wallstart und wallende auch auf null gesetzt werden. Hiermit werden dann alle Wandpunkte aus der Liste entfernt und vom Garbage Collector physisch gelöscht. Um einen einzelnen Punkt zu löschen (Element 2), muss die Referenz next des vorherigen Punktes (Element 1) auf den Nachfolgenden (Element 3) zeigen. Außerdem muss die Referenz prev des nachfolgenden Punktes (Element 3) auf den Vorgänger (Element 1) des zu löschenden (Element 2) zeigen. Den Rest, also das physikalische Löschen, übernimmt wiederum der Garbage Collector. Streckenzug start actu ende wallstart wallende next next next next next X Elem Elem Elem Elem Elem Elem X prev prev prev prev prev next Elem Elem 7 prev 8 neu einzufügende Punkte gezeichnete "normale" Punkte errechnete Wandpunkte Abb. 58 Wandpunkte in der verketteten Liste 69

73 3. Projektverlauf Berechnung der Wandstärke Das Berechnen der grau gezeichneten Wandpunkte in dem Programm ist wohl jene Funktion gewesen, welche am meisten mathematisches Hintergrundwissen benötigt. Für die Erstellung der Wandpunkte kann man nicht einfach nur die Originalkontur nehmen und diese um x Pixel in eine Richtung verschieben oder diese skalieren. Wie man in der [Abb. 59] erkennen kann, werden die Wandpunkte immer im gleichen Abstand zu den Originalpunkten gesetzt. Der Winkel ist dabei abhängig von den zwei benachbarten Punkten. Bei einem Endpunkt natürlich nur von einem benachbarten Punkt, so dass ein 90 Winkel zwischen Strecke und Endwand entsteht. Im folgenden wird anhand des Quellcodes einmal die exakte Berechnung eines Punktes erläutert. Abb. 59 Ansicht der Wandpunkte 70

74 3. Projektverlauf Um alle Wandpunkte berechnen und zeichnen zu lassen, wird die Methode drawwall() aufgerufen, welche innerhalb einer for-schleife alle 2D-Punkte der Liste durchläuft. Dabei wird für jeden Punkt zuerst die Methode errechnewpunkt() aufgerufen, welche die Position des Wandpunktes berechnet und das Ergebnis an erstellewandpunkt() weiterleitet, um den entsprechenden Wandpunkt auf den Bildschirm zu zeichnen. for(int i=0;i < Punkt2d.getAnzahl() && actu.getiswall()==0;i++){ Punkt2d temp; temp=errechnewpunkt(actu,prev,next); erstellewandpunkt(temp,pointlist); actu = (Punkt2d)pointlist.go_get_next(); prev = (Punkt2d)pointlist.getprev(actu); next = (Punkt2d)pointlist.getnext(actu); Die Methode errechnewpunkt() nimmt als Parameter immer drei Punkte entgegen: den Aktuellen, zu welchem der Wandpunkt berechnet werden soll, den Vorgänger und den Nachfolger. Für die Berechnung wird unterschieden, ob es sich um den Anfangspunkt if(prev==null){, um den Endpunkt else if(next==null next.getiswall()==1){ oder einem Punkt aus der Mitte handelt. In den ersten beiden Fällen muss man nur einen Normalenvektor berechnen, im anderen Fall zwei Normalenvektoren, welche anschließend addiert werden. Ein Normalenvektor steht immer senkrecht zu der Strecke. Er wird errechnet durch das Subtrahieren der zwei Punkte und das anschließende Umkehren der X und Y Position im Ergebnis. Je nach dem, in welche Richtung dieser Vektor zeigen soll, kann man noch das Vorzeichen des Y-Wertes negieren. Dies wurde in diesem Programm getan. Dadurch wird eine Wand erzeugt, welche rechtsliegend ist. Die Berechnungsmethode für den Normalenvektor heißt normalenv() und sieht wie folgt aus: Abb. 60 Normalenvektoren private Punkt2d normalenv(punkt2d p1, Punkt2d p2){ Punkt2d ergv=new Punkt2d((float)((p1.getYtemp()-p2.getYtemp())*(- 1)),(float)(p1.getXtemp()-p2.getXtemp())); aufeins(ergv); return ergv; 71

75 3. Projektverlauf Falls ein Endpunkte berechnet wird, kann direkt der Normalenvektor benutzen werden. Für den Fall, dass es sich aber um keinen Endpunkt handelt, muss man die zwei anliegenden Normalenvektoren berechnen und diese addieren. Dies bewerkstelligt die Methode addv(). private Punkt2d addv(punkt2d p1, Punkt2d p2){ Punkt2d ergv=new Punkt2d( (p1.getxtemp()+p2.getxtemp()),(p1.getytemp()+p2.getytemp())); return ergv; Das Addieren der zwei Vektoren ist logisch, da Vektoren ortsunabhängig im Raum liegen. Wenn beide Vektoren addiert werden, erhält man einen Vektor, der die Winkel der einzelnen Normalenvektoren mittelt. In [Abb. 61] ist der Ergebnisvektor in hellgrau dargestellt, die anderen beiden Vektoren sind zum besseren Verständnis im Raum verschoben worden. Abb. 61 Normalenvektorenaddition Nach der Errechnung des jeweiligen Normalenvektors oder deren Addition muss man diesen noch auf die Einheitslänge 1 bringen. Die dafür erstellte Methode heißt aufeins(). Die Rechnung wird im folgenden beschrieben. Zuerst wird ein Wert errechnet, welcher sich aus den quadrierten, addierten und anschließend radizierten X- und Y-Werten des Vektors ergibt. Dieser Wert wird dann als Quotient für die X und Y Werte benutzt, wodurch der Vektor auf die Länge 1 gebracht wird. private void aufeins(punkt2d p){ double w0 = Math.sqrt(p.getXtemp()*p.getXtemp() + p.getytemp()*p.getytemp() ); p.setxtemp(((float)(p.getxtemp()/w0))); p.setytemp(((float)(p.getytemp()/w0))); Danach wird der Normalenvektor auf die entsprechende Länge der Wandstärke gebracht. Bei dem Anfangs- und Endpunkt gestaltet sich dies noch relativ unproblematisch, da der Normalenvektor dort immer in einem 90 Winkel zur Strecke abgebildet ist und man dies deshalb durch eine einfache Skalamultiplikation errechen kann. private void scalarmulti(double w,punkt2d p){ p.setxtemp(((float)(p.getxtemp()*w))); p.setytemp(((float)(p.getytemp()*w))); 72

76 3. Projektverlauf Wird allerdings ein Wandpunkt aus der Mitte des Streckenzuges berechnet, steht das Ergebnis der addierten Normalenvektoren in den seltensten Fällen noch senkrecht zu der Strecke, siehe auch [Abb. 61]. Damit man in diesem Fall die Dicke der Wandstärke abbildet, muss man zuerst die Länge des Vektors bestimmt. Dies geht über eine Winkelberechnung. Abb. 62 Winkelberechnung X ist die gesuchte Länge L ist die gegebene Wandstärke a der Winkel zwischen den zwei Strecken Wie man der Skizze entnehmen kann, ergibt sich so für die Länge der Strecke X, welche das zu multiplizierende Skalar für den errechneten Vektor darstellt, die Formel: 2*L / sin a. Grundlegendes Problem dabei ist aber, dass der Winkel a zwischen den zwei Strecken noch gar nicht bekannt ist. Daher muss dieser zuerst bestimmt werden. Dafür muss man aber zuerst den Richtungsvektor errechnen. private double[] richtungswinkel(punkt2d p1, Punkt2d p2){ double erg[] = new double[3]; erg[1]= p1.getxkor()-p2.getxkor(); erg[2]= p1.getykor()-p2.getykor(); //Sonderfallbehandlung falls Senkrechte (Division durch 0) if(erg[1]==0){ erg[0] =0;//Winkel ist 0 bei einer Senkrechten! else{ erg[0] = Math.atan( (erg[1]/erg[2]) ); return erg; 73

77 3. Projektverlauf Der Richtungs- oder auch Steigungswinkel ist der Winkel zwischen dem Vektor und einer Senkrechten. Allerdings erhält man immer den kleinsten Winkel zu der Senkrechten, so das dieser immer zwischen 45 und 45 liegt. Dadurch lässt sich zwar die Lage des Vektors im Raum festlegen, aber nicht wie die Strecke im Raum liegt, da für deren Definition immer eine Winkelangabe zu zwei Definitionen passt. Abb. 63 Richtungswinkel [Abb. 63] soll die Berechnung noch einmal verdeutlichen. Ausgangspunkt der Strecke ist der schwarze Punkt in der Mitte des Kreises. Am Rand des Kreises sind entsprechend die errechneten Winkel (zum besseren Verständnis in Grad) aufgetragen. Die zwei eingezeichneten Strecken sollen das grundlegende Problem verdeutlichen. Ist der schwarze Punkt jeweils der Ausgangspunkt der Strecken, liegen diese genau entgegengesetzt im Raum, da die Berechnung aber auf dem Vektor der Strecken basiert, verfällt diese Angabe und man erhält nur den Winkel des Vektors. Dadurch das also nur der Richtungsvektor der Strecke bekannt ist und nicht der eigentliche Winkel der Strecke, erschwert sich die Berechnung des Winkels zwischen zwei Strecken enorm, da man für alle möglichen Kombinationen der Strecken zueinander, eine extra Fallunterscheidung treffen muss. Der errechnete Richtungswinkel sagt über die Lage der Strecke im Raum nichts aus, dies ist aber relevant für den Algorithmus, daher muss dieser direkt auf den Streckenkoordinaten arbeiten. In unserem Fall auf dem Richtungsvektor der Strecke. Ausgehend von dem Punkt den beide Strecken teilen, wird ein imaginäres Koordinatensystem errichtet, auf dem die Fallunterscheidungen getroffen werden. Anhand der Vorzeichenausprägungen des Richtungsvektors lässt sich eindeutig zuordnen in welchem Quadranten die Strecke liegt. Liegt sie in Quadrant 1 sind beide Vorzeichen positiv, genau umgekehrt im Quadranten 3, siehe [Abb. 64]. Abb. 64 Imaginäres Koordinatensystem 74

78 3. Projektverlauf Bei zwei Strecken in einem Koordinatensystem gibt es insgesamt 16 verschiedene Möglichkeiten diese zu positionieren. Für die Berechnung existieren zu Beginn jeweils vier klar erkennbare Kombinationen. Die vier Muster differenzieren das Problem schon stark, so dass innerhalb des jeweiligen Falls nur noch unterschieden werden muss, welche Strecke oberhalb liegt. Wichtig hierbei ist, dass man immer das selbe Schema anwendet, so dass zum Beispiel immer der von Strecke 1 links liegende Winkel berechnet wird. Ansonsten würde man einmal den Innen- und beim anderen Fall den Außenwinkel berechnen. Fall 1: Die Strecken teilen sich den selben Quadranten. Der Winkel ist kleiner als 90 Da die errechneten Richtungswinkel das gleiche Vorzeichen besitzen, kann man diese in allen aufgeführten Varianten einfach voneinander abziehen und erspart sich so eine zusätzliche Fallunterscheidung! Falls man falsch subtrahiert, erkennt man dies am negativen Ergebnis und kann durch eine Addition von 360 wieder den richtigen Wert ermitteln. if ( nxor(a1[1],a2[1]) && nxor(a1[2],a2[2]) ){ winkel=(a1[0]-a2[0]); if(winkel <0){ winkel= 2*Math.PI+winkel; Fall 2: Der X-Wert der Strecken hat das gleiche Vorzeichen, das Vorzeichen des Y- Wertes unterscheidet sich aber. Der Winkel liegt zwischen 90 und 180 Die Errechnung des Winkels zwischen den Strecken erschwert sich hier, da die Vorzeichen der Winkelangaben immer genau entgegengesetzt sind. Da man von beiden Strecken jeweils den entgegengesetzten Winkel benötigt, müssen beide Winkel von 90 differenziert werden. Da ein Winkel schon negativ ist, wird dieser addiert. 75

79 3. Projektverlauf Alternativer Ansatzpunkt wäre, den Gesamtradius von 180 zu nehmen und beide Winkel davon abzuziehen. Der erstere Ansatz wurde programmiert. Für den Fall, dass die Strecken umgekehrt liegen, wurde das Ergebnis einfach von 360 subtrahiert. else if (nxor(a1[1],a2[1]) &&!nxor(a1[2],a2[2]) ){ if(a1[0]<0 a2[0]==0){ winkel=((math.pi/2+ a1[0]) +Math.PI/2-a2[0] ); else{ winkel=(2*math.pi-((math.pi/2- a1[0]) +Math.PI/2+a2[0] )); Fall 3: Der Y-Wert der Strecken hat das gleiche Vorzeichen, das Vorzeichen des X- Wert unterscheidet sich aber. Der Winkel liegt zwischen 90 und 180 Auch in diesem Fall unterscheidet sich wieder das Vorzeichen der zwei errechneten Richtungswinkel, da aber beide errechneten Winkel innenliegend sind, können diese einfach addiert oder bei Vorzeichendifferenz entsprechend subtrahiert werden. Falls nicht der innenliegende Winkel, sondern der Äußere erwünscht ist, wird das Ergebnis von 360 subtrahiert. else if (!nxor(a1[1],a2[1]) && nxor(a1[2],a2[2]) ){ if(a2[0]<0){ winkel=( a1[0] -a2[0] ); else{ winkel=2*math.pi+( a1[0] -a2[0] ); 76

80 3. Projektverlauf Fall 4: Der Y- und X-Wert der Strecken hat ein unterschiedliches Vorzeichen. Sie befinden sich immer in den genau entgegengesetzten Quadranten. Der Winkel liegt zwischen 90 und 180 Das Vorzeichen des Richtungswinkels der zwei Strecken ist gleich. Dies hilft aber in diesem Fall nicht mehr eine Fallunterscheidung zu sparen, da die Strecken in den entgegengesetzten Quadranten liegen und keine weiteren identischen Kombinationen existieren. So muss einer der Richtungswinkel von 90 subtrahiert werden, um den gegenüberliegenden Winkel zu errechnen. Um dann den Gesamtwinkel zu erhalten, muss man zu der Summer beider Winkel noch 90 addieren. Für den Fall, dass der größere Winkel benötigt wird, wurde der Winkel der anderen Strecke zu Beginn von 90 subtrahiert. else if (!nxor(a1[1],a2[1]) &&!nxor(a1[2],a2[2]) ){ if(a1[0]>=0){ winkel=( a1[0] +(Math.PI/2-a2[0])+Math.PI/2 ); else{ winkel=( (Math.PI/2+a1[0]) +(-a2[0])+math.pi/2 ); Nachdem man, nach der etwas längeren Rechnung, den Wert des Winkels zwischen den zwei Strecken kennt, kann nun über die Winkelberechnung aus [Abb. 62] die Länge des Vektors bestimmt werden. double laenge=wallwidth/math.sin(winkel ( richtungswinkel(actu,prev), richtungswinkel(actu,next))/2); scalarmulti(laenge,temp); Als letzter Schritt wird der errechnete Vektor auf den Koordinatenpunkt addiert und der Wandpunkt an den Aufrufer zurückgegeben, wodurch der entsprechende Wandpunkt gezeichnet wird. Punkt2d WandpunktV = addv(temp,actu); return WandpunktV; 77

81 3. Projektverlauf Erstellen eines Rotationsobjektes y 1 y 1 y = sin x sinus x -1 0 a 1 x cosinus a Pi/2 Pi 3 Pi/2 2 Pi -1-1 Abb. 65 Herleitung der Sinusfunktion über den Einheitskreis In dem Programm wird durch die Angabe eines zweidimensionalen Streckenzuges ein dreidimensionales Objekt erzeugt. Eine zweidimensionale Koordinate enthält im späteren dreidimensionalen Raum die Informationen für die Höhe, dementsprechend den y-wert und den Radius des Objektes an jener Stelle. Der Radius wird aus der X- Position abgeleitet. Über die Rückrechnung der jeweiligen Funktion zum Einheitskreis kann man die Koordinaten auf einer Kreisbahn errechnen. Durch eine Schleife, die über die Anzahl der Dreiecke läuft, werden die Koordinaten für alle Punkte berechnet. for(int i=0;i<this.anzahl;i++){ float Xzu1 =(float)math.sin(((float)i)/(float)(anzahl- 1)*360*Math.PI / 180) ; float Zzu1 = (float)math.cos(((float)i)/(float)(anzahl- 1)*360*Math.PI / 180) ; pointr[i] = new Point3f(Xzu1 * x,y,zzu1 * x); y Anordnung gegen den Uhrzeigersinn x Die Punkte werden dadurch auf einer Kreisbahn um den Mittelpunkt angeordnet. Durch die Multiplikation der X- und Z- Koordinate mit dem X-Wert des 2D-Punktes erhält der Kreis den entsprechenden Durchmesser. Sind die Koordinaten einmal berechnet, werden diese in einem Point3f Array innerhalb des jeweiligen Kreis3D-Objektes abgelegt. Abb. 66 Erstellung der Punkte einer Kreisebene 78

82 3. Projektverlauf Nachdem die Punkte errechnet und abgespeichert wurden, wird über den Controller aus der Klasse Ansicht3D ein neuzeichnen des 3D-Objektes veranlasst. Es wird überprüft, ob mindestens zwei 2D-Punkte bzw. analog zwei 3D-Kreisebenen existieren und wenn dies der Fall ist, werden die Koordinaten der 3D-Punkte der ersten beiden Kreisebenen abwechselnd in dem Array kegelstumpf gespeichert. for(int i =0,j=0,k=0; i<dreickeprokreis+2;i++){ if((i)%2==0){ //Änderung der Laufrichtung für Innen und Aussen Kreispunkte[Kegelnr][i] =kegelstumpf[i] = prev.getkreis().getpoint(j); if(material<2) Normalenvektoren[Kegelnr][i]=normals[i] = prev.getkreis().getnormal(j,(punkt2d)pointlist.getprev(prev),(punkt2d)poi ntlist.getnext(prev)); j++; else{ Kreispunkte[Kegelnr][i]=kegelstumpf[i] = actu.getkreis().getpoint(k); if(material<2) Normalenvektoren[Kegelnr][i]=normals[i] = actu.getkreis().getnormal(k,(punkt2d)pointlist.getprev(actu),(punkt2d)poi ntlist.getnext(actu)); k++; Dies muss so realisiert werden, da das TriangleStripArray ein Array mit allen darzustellenden Punkten benötigt. Durch die Übergabe des Arrays an das TriangleStripArray wird jeweils aus drei aufeinanderfolgenden Punkten ein Dreieck gebildet. Dabei ist die Speicherreihenfolge der Punkte im übergebenen Array relevant, da diese über die Innen- und Außenseite bestimmt. TriangleStripArray mantel = new TriangleStripArray(Dreickeprokreis+2,TriangleStripArray.COORDINATES Trian glestriparray.normals, stripzahl); mantel.setcoordinates(0, kegelstumpf); Fügt man das erstellte TriangleStripArray-Objekt in einen entsprechenden Szenengraphen ein, könnte die Ausgabe wie in [Abb. 67] aussehen. Die Ansicht wurde natürlich durch mehrere Linienzüge erzeugt und soll an dieser Stelle nur darstellen, wie die Aufteilung des Rotationskörpers in Dreiecke aussieht. Bei der richtigen Darstellung eines TriangleStripArrays ist diese so nicht sichtbar! Abb. 67 Modell eines TriangelStripArrays 79

83 3. Projektverlauf Das Erstellen eines solchen TriangleStripArrays geschieht in der Methode makesurface3d() in der Klasse Ansicht3D. Diese Methode wird innerhalb einer for-schleife aufgerufen, welche über die Anzahl der 2D-Punkte läuft. Dadurch wird die benötigte Anzahl an TriangleStripArrays erzeugt, wodurch der Rotationskörper entsteht. Abb. 68 Modell eines Rotationskörpers for(int ii=0;ii < Punkt2d.getAnzahl()-1;ii++){ prev=actu; actu = (Punkt2d) pointlist.go_get_next(); objwurzel.addchild( makesurface3d(prev,actu,ii) ); 80

84 3. Projektverlauf Normalenvektoren Normalenvektoren werden von Java3D benötigt um die Glanzeffekte bei den Shadingverfahren gouraud und flat zu berechnen. Abb. 69 Skizze über die Darstellung von vier Normalenvektoren Ein Normalenvektor steht immer senkrecht zu einer Fläche. Der erstellte Rotationskörper besteht aus sehr vielen einzelnen Dreiecken. Jedes dieser Dreiecke besitzt genau 3 Normalenvektoren, nämlich genau an dessen Eckpunkten. Um einen realen Eindruck bei der Schattierungsberechnung zu erzielen, müssen alle Normalenvektoren richtig ausgerichtet sein. Ein Rotationskörper hat den Vorteil, dass alle Normalenvektoren eines Kreises auf einer Ebene liegen und so in dem Programm die gleiche Y-Position besitzen. Dazu sind diese kreisförmig um die Mittelpunktachse des Objektes angeordnet. Nimmt man die Position des entsprechenden Punktes mit hinzu, liegt dieser über dem Vektor auf einer Linie mit dem Mittelpunkt. Werden also die Normalenvektoren im Raum entsprechend der zugehörigen Punkte angeordnet, ergibt sich aus der Sicht von oben ein Bild wie [Abb. 70] zeigt. Abb. 70 Anordnung der Normalenvektoren Die Berechnung dieser Werte verhält sich analog zu der in Kapitel [3.3.3 Erstellen eines Rotationsobjektes] vorgestellten Technik. So werden auch hier über den Einheitskreis die Koordinaten für die X- und Z- Ebene bestimmt. float Xzu1 =(float)math.sin(((float)nr)/(float)(anzahl-1)*360*math.pi / 180) ; float Zzu1 = (float)math.cos(((float)nr)/(float)(anzahl-1)*360*math.pi / 180) ; Werden daraus die Werte der Vektoren gebildet, kommt man zu einem falschen Ergebnis, da der Y-Wert nicht berechnet wurden. Siehe [Abb. 61]. Abb. 71 Normalenvektoren mit unberechneter Y-Koordinate 81

85 3. Projektverlauf Die Y-Koordinate des Normalenvektors ergibt sich analog zu der Wandpunktberechnung, aus den Werten des Vorgängers und Nachfolgers sowie des aktuellen Punktes. Bei dieser Berechnung wird auch zuerst eine Fallunterscheidung getroffen, ob es der Anfangsoder Endpunkt ist, oder es sich um einen Punkt aus der Mitte handelt. Bei den ersten beiden Fällen ist die Rechnung wesentlich einfacher, da keine Vektoraddition vorgenommen werden muss. Abb. 72 Normalenvektoren Über das Kreuzprodukt kann man einen Vektor der senkrecht zu einer Strecke liegt errechnen. Da der Y-Wert der Senkrechten mit der des Normalenvektors übereinstimmt, kann dieser direkt übernommen werden. if(prev==null){ vy = getpoint(nr).x * next.getkreis().getpoint(nr).z-getpoint(nr).z * next.getkreis().getpoint(nr).x; normals[nr] = aufeins(new Vector3f( Xzu1, vy,zzu1 )); else if(next==null){ vy = getpoint(nr).x * prev.getkreis().getpoint(nr).z - getpoint(nr).z * prev.getkreis().getpoint(nr).x; normals[nr] = aufeins(new Vector3f( Xzu1,vy,Zzu1 )); Der errechnete Vektor muss auf die Länge 1 gebracht werden. Diese Aufgabe erfüllt die Methode aufeins(). private Vector3f aufeins(vector3f v){ Vector3f v2 = new Vector3f(); double w0 = Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z); v2.x=(((float)(v.x/w0))); v2.y=(((float)(v.y/w0))); v2.z=(((float)(v.z/w0))); return v2; Für den Fall, dass es sich um einen Punkte aus der Mitte handelt, müssen für beide anliegenden Strecken die Vektoren berechnet werden, um diese anschließend zu addieren. 82

86 3. Projektverlauf else{ vy1 = prev.getkreis().getpoint(nr).x * getpoint(nr).zprev.getkreis().getpoint(nr).z * getpoint(nr).x ; vy2 = getpoint(nr).x * next.getkreis().getpoint(nr).zgetpoint(nr).z * next.getkreis().getpoint(nr).x ; vy=vy1+vy2; vx=xzu1; vz=zzu1; normals[nr] = aufeins(new Vector3f( vx,vy,vz)); Auf diese Weise, kann man zu jedem Punkt des Rotationskörpers den Normalenvektor berechnen. Erst durch richtig errechnete Normalenvektoren entsteht ein realistischer Eindruck. Die benutzte Berechnungsart wird auch bei DirectX eingesetzt und hat den Vorteil, Kanten zu glätten und dadurch realistischer wirkende Rundungen zu erstellen. Der Nachteil ist, dass alle Kanten geglättet erscheinen. Dies war aber bei der Erstellung eines Rotationskörpers irrelevant. In [Abb. 73] erkennt man die Unterschiede, so erscheinen die Flächenkonturen des rechten Objektes viel prägnanter. 14 Abb. 73 Normalenvektoren, mit und ohne Ausrichtung, Quelle [ToMMT] 14 vgl. [ToMMT] 83

Einführung - Was ist Java3D?

Einführung - Was ist Java3D? Einführung - Was ist Java3D? - Java Package für interaktive 3D Grafik - High-level 3D Grafik API - Programmieren von interaktiven Anwendungen mit dreidimensionalen Inhalten - Nahtlose Integration in Java

Mehr

Java 3D. Linien, Flächen und Objekte Axel Bartsch, Okt. 2002

Java 3D. Linien, Flächen und Objekte Axel Bartsch, Okt. 2002 Java 3D Linien, Flächen und Objekte Axel Bartsch, Okt. 2002 Virtual World Koordinaten System Grundlagen zur Definition visueller Objekte Shape3D Unterklasse der Leaf-Klasse Eigenschaften des visuellen

Mehr

Einführung - Was ist Java3D?

Einführung - Was ist Java3D? Einführung - Was ist Java3D? - Java Package für interaktive 3D Grafik - High-level 3D Grafik API - Programmieren von interaktiven Anwendungen mit dreidimensionalen Inhalten - Nahtlose Integration in Java

Mehr

Kapitel X - Zeichnen mit Java2D

Kapitel X - Zeichnen mit Java2D Kapitel X - Zeichnen mit Java2D SWT I Sommersemester 2010 Walter F. Tichy, Andreas Höfer, Korbinian Molitorisz IPD Tichy, Fakultät für Informatik KIT die Kooperation von Forschungszentrum Karlsruhe GmbH

Mehr

Universität Karlsruhe (TH)

Universität Karlsruhe (TH) Universität Karlsruhe (TH) Forschungsuniversität gegründet 1825 Kapitel X Zeichnen mit Java2D SWT I Sommersemester 2009 Prof. Walter F. Tichy David Meder Literatur Informationen zu Java2D finden Sie in

Mehr

Einige weitere Fähigkeiten und Anwendungsbeispiele

Einige weitere Fähigkeiten und Anwendungsbeispiele Java3D Eine Einführung Was ist Java3D Ansicht (Viewing Model) Sichtbare Objekte Animationen und Interaktionen Einfaches Beispielprogram Einige weitere Fähigkeiten und Anwendungsbeispiele Was ist Java3D?

Mehr

Einführung in Java3D

Einführung in Java3D Einführung in Java3D SS05 Ashraf Abu Baker baker@gdv.cs.uni-frankfurt.de Varrentrappstr. 40-42 60486 Frankfurt am Main Raum 218 Java 3D ist eine high level Interaktive 3D Graphik-API (Application Programming

Mehr

Newtek Lightwave Grundlagen der 3D-Vektorgrafik

Newtek Lightwave Grundlagen der 3D-Vektorgrafik Newtek Lightwave Grundlagen der 3D-Vektorgrafik Form und Oberfläche Punkte und Polygone (mindestens 3-seitige Verbindungen zwischen Punkten) sind die Grundlage der Darstellung dreidimensionaler Objekte

Mehr

Der Szenegraph. Im Folgenden eine kurze Beschreibung der wichtigsten Knoten des Szenegraphen:

Der Szenegraph. Im Folgenden eine kurze Beschreibung der wichtigsten Knoten des Szenegraphen: Java 3d Java3D ist eine Bibliothek von Java Klassen zur Darstellung dreidimensionaler Graphik innerhalb von Java Applikationen und Applets. Die Struktur der darzustellenden Szene wird durch das Aufbauen

Mehr

3D Rendering mit PHP. Die neue PEAR-Klasse Image_3D bietet die Möglichkeit nur mit PHP5 3DGrafiken zu rendern

3D Rendering mit PHP. Die neue PEAR-Klasse Image_3D bietet die Möglichkeit nur mit PHP5 3DGrafiken zu rendern 3D Rendering mit PHP Die neue PEAR-Klasse Image_3D bietet die Möglichkeit nur mit PHP5 3DGrafiken zu rendern Speaker Kore Nordmann Studiert Informatik an der Universität Dortmund Arbeitet als Software

Mehr

Szenengraphen. Codruţa Cosma. Universität Ulm Sommersemester 2005

Szenengraphen. Codruţa Cosma. Universität Ulm Sommersemester 2005 Szenengraphen Codruţa Cosma Universität Ulm Sommersemester 2005 Übersicht Einführung VRML OpenSceneGraph Java3D vs. VRML OpenGL vs. Java3D und VRML Zusammenfassung 2/26 Was sind Szenengraphen? Datenstruktur

Mehr

Beleuchtungsmodelle und Shading

Beleuchtungsmodelle und Shading Beleuchtungsmodelle und Shading Andreas Spillner Computergrafik, WS 2018/2019 Ziel der Modellierung von Beleuchtung Baut auf dem Kapitel zu Licht und Farben auf. In die 3D-Szene werden Lichtquellen eingebracht.

Mehr

Drucken. Programmieren II. Martin Schultheiß. Hochschule Darmstadt Sommersemester 2011

Drucken. Programmieren II. Martin Schultheiß. Hochschule Darmstadt Sommersemester 2011 Programmieren II Martin Schultheiß Hochschule Darmstadt Sommersemester 2011 1 Drucken Grundlagen In Java wird zum Drucken die Java Printing API verwendet. Die entsprechenden Klassen und Schnittstellen

Mehr

Computergrafik Universität Osnabrück, Henning Wenke,

Computergrafik Universität Osnabrück, Henning Wenke, Computergrafik Universität Osnabrück, Henning Wenke, 2012-05-14 Kapitel V: Modeling Transformation & Vertex Shader 5.1 Vertex Definitionen: Vertex Vertex Computergrafik Mathematischer Punkt auf einer Oberfläche

Mehr

TEXTEFFEKTE TEXTFELDER VERWENDUNG VON TEXTFELDERN. Markieren Sie den Text, und klicken Sie in der Registerkarte Start auf das

TEXTEFFEKTE TEXTFELDER VERWENDUNG VON TEXTFELDERN. Markieren Sie den Text, und klicken Sie in der Registerkarte Start auf das TEXTEFFEKTE Markieren Sie den Text, und klicken Sie in der Registerkarte Start auf das Symbol Texteffekte auswählen.. Der Katalog klappt auf, und Sie können einen Effekt Über Kontur, Schatten, Spiegelung

Mehr

Schlussendlich geben wir die Listen aus. Es kommt zu folgender Ausgabe:

Schlussendlich geben wir die Listen aus. Es kommt zu folgender Ausgabe: Musterlösung Übung 7 Aufgabe 1 Sehen wir uns zu allererst das gegebene Forth Programm an: 0 3 new - list constant list1 list1 5 new - list constant list2 list1 6 new - list constant list3 list2 2 new -

Mehr

Zellaufbau Java 3D Verteilungsalgorithmus

Zellaufbau Java 3D Verteilungsalgorithmus Zellaufbau Java 3D Verteilungsalgorithmus Christina Ander & Regina Bisdorf Universität Bielefeld 06.12.2007 C. Ander & R. Bisdorf (Universität Bielefeld) Zellaufbau Java 3D Verteilungsalgorithmus 06.12.2007

Mehr

Durch die Möglichkeit, Ein- und Ausgaben auf der Konsole durchzuführen, kann man auch systematisch das Verhalten von Klassen analysieren.

Durch die Möglichkeit, Ein- und Ausgaben auf der Konsole durchzuführen, kann man auch systematisch das Verhalten von Klassen analysieren. Durch die Möglichkeit, Ein- und Ausgaben auf der Konsole durchzuführen, kann man auch systematisch das Verhalten von Klassen analysieren. 267 Das hier skizzierte Problem basiert auf der strategischen Entscheidung

Mehr

03. übung. InDesign. medienwerkstatt // seite 1

03. übung. InDesign. medienwerkstatt // seite 1 InDesign medienwerkstatt // seite 1 03.01. gesetz der prägnanz cmd + n = neues Dokument 1. dokument einrichten Format Doppelseitig / Einseitig Seitenränder Menüleiste: Datei > Neu > Dokument Doppelseite

Mehr

Übungsblatt 10: Klausurvorbereitung

Übungsblatt 10: Klausurvorbereitung Übungsblatt 10: Klausurvorbereitung Abgabe: Dieses spezielle Übungsblatt hat keine Abgabefrist und wird auch nicht korrigiert. Die Lösung gibt es wie immer auf der Homepage der Vorlesung oder in den Übungen

Mehr

ÜBUNGEN ZUR OBJEKTORIENTIERTEN MODELLIERUNG

ÜBUNGEN ZUR OBJEKTORIENTIERTEN MODELLIERUNG ÜBUNGEN ZUR OBJEKTORIENTIERTEN MODELLIERUNG Unter objektorientierter Modellierung versteht man das detailgetreue Darstellen einer zu programmierenden Szene durch Skizzen in UML. UML steht für Unified Modelling

Mehr

GrafikprograntmiBtung

GrafikprograntmiBtung Matthias und Roland Oberdorfer GrafikprograntmiBtung unter Windows und Windows NT 2D und 3D-Grafik, Animationen, Lichteffekte, Echtzeitgrafik, Beispiele auf CD Mit 64 Abbildungen Franzis 1 Einführung 15

Mehr

ANIMATION - GRUNDLAGEN

ANIMATION - GRUNDLAGEN ANIMATION - GRUNDLAGEN Bei CAD-Programmen gibt es meist folgende Verfahren zur Erzeugung von : Festlegung von Schlüsselszenen, aus denen das Programm automatisch Zwischenbilder generiert ( Keyframing )

Mehr

Universität Augsburg, Institut für Informatik Sommersemester 2001 Prof. Dr. Martin Ester 08. Oktober Klausur II

Universität Augsburg, Institut für Informatik Sommersemester 2001 Prof. Dr. Martin Ester 08. Oktober Klausur II Universität Augsburg, Institut für Informatik Sommersemester 2001 Prof. Dr. Martin Ester 08. Oktober 2001 Stefan Holland Informatik II Hinweise: Klausur II Verwenden Sie für Ihre Lösungen ausschließlich

Mehr

TEXTEFFEKTE TEXTFELDER VERWENDUNG VON TEXTFELDERN. Markieren Sie den Text, und klicken Sie in der Registerkarte Start auf das Symbol

TEXTEFFEKTE TEXTFELDER VERWENDUNG VON TEXTFELDERN. Markieren Sie den Text, und klicken Sie in der Registerkarte Start auf das Symbol TEXTEFFEKTE Markieren Sie den Text, und klicken Sie in der Registerkarte Start auf das Symbol Texteffekte. Der Katalog klappt auf, und Sie können einen Effekt auswählen. Über Kontur, Schatten, Spiegelung

Mehr

Einleitung 2. 1 Koordinatensysteme 2. 2 Lineare Abbildungen 4. 3 Literaturverzeichnis 7

Einleitung 2. 1 Koordinatensysteme 2. 2 Lineare Abbildungen 4. 3 Literaturverzeichnis 7 Sonja Hunscha - Koordinatensysteme 1 Inhalt Einleitung 2 1 Koordinatensysteme 2 1.1 Kartesisches Koordinatensystem 2 1.2 Polarkoordinaten 3 1.3 Zusammenhang zwischen kartesischen und Polarkoordinaten 3

Mehr

Michael Bender Martin Brill. Computergrafik. Ein anwendungsorientiertes Lehrbuch. 2., überarbeitete Auflage HANSER

Michael Bender Martin Brill. Computergrafik. Ein anwendungsorientiertes Lehrbuch. 2., überarbeitete Auflage HANSER Michael Bender Martin Brill Computergrafik Ein anwendungsorientiertes Lehrbuch 2., überarbeitete Auflage HANSER Inhaltsverzeichnis Vorwort XI 1 Einleitung 1 1.1 Die Entwicklung der Computergrafik 1 1.2

Mehr

Shader. Computer Graphics: Shader

Shader. Computer Graphics: Shader Computer Graphics Computer Graphics Shader Computer Graphics: Shader Inhalt Pipeline Memory Resources Input-Assembler Vertex-Shader Geometry-Shader & Stream-Output Rasterizer Pixel-Shader Output-Merger

Mehr

11. GUI-Programmierung mit SWING Überblick

11. GUI-Programmierung mit SWING Überblick 11. GUI-Programmierung mit SWING Überblick 11.1 Einführung 11.2 Einfache Swing Komponenten 11.3 Ereignisbehandlung und Adapterklassen 11.4 Zeichnen 11.5 Dialoge 11.6 Layout Manager 11.7 Komplexere Swing

Mehr

CLB Simulator. Inhaltsverzeichnis. Marcel Viehmeier. 30. Oktober Version 1.0.1

CLB Simulator. Inhaltsverzeichnis. Marcel Viehmeier. 30. Oktober Version 1.0.1 CLB Simulator Marcel Viehmeier 30. Oktober 2012 Version 1.0.1 Inhaltsverzeichnis 1 Einleitung 2 1.1 Hintergrund................................. 2 1.2 Technischer Hintergrund..........................

Mehr

Grafik-Programmierung

Grafik-Programmierung Grafik-Programmierung In dieser Übung beschäftigen wir uns zunächst mit elementaren Grundlagen der Grafikprogrammierung. In der nächsten Übung werden wir dies auf Spiele anwenden. Aufgabe 1: Einfache Grafik:

Mehr

Polymorphie und UML Klassendiagramme

Polymorphie und UML Klassendiagramme Polymorphie und UML Klassendiagramme Prof. Dr.-Ing. Thomas Schwotzer 1 Einführung Vererbung hat einen sehr interessanten und effektiven Effekt: die Polymorphie. Darum geht es in dieser Veranstaltung. 2

Mehr

MEDT (2. Jahrgang): 1. Übung für Schwerpunkt 3D-Modellierung

MEDT (2. Jahrgang): 1. Übung für Schwerpunkt 3D-Modellierung Blender Einstieg MEDT (2. Jahrgang): 1. Übung für Schwerpunkt 3D-Modellierung Inhalt 1 Zielsetzung... 1 1.1 Bewertung... 1 2 Grundlagen... 2 2.1 Allgemeines... 2 2.2 GUI... 3 2.3 Bedienung... 5 2.4 Objekte

Mehr

4.4 Glättung von Kanten

4.4 Glättung von Kanten 4.4 Glättung von Kanten Es wurden verschiedene Aspekte zur Beleuchtung von Modellen und Szenen vorgestellt. Es gibt zwei Arten von Licht, das Hintergrundlicht und Licht von Lichtquellen, wobei hier zu

Mehr

Ein erstes "Hello world!" Programm

Ein erstes Hello world! Programm OOP Henrik Horstmann 14. September 2014 Inhaltsverzeichnis Inhaltsverzeichnis 1 Bedeutung der Symbole...1 2 Die Benutzer Oberfläche von HOOPLU...2 2.1 Projekte öffnen und speichern...2 2.2 Die Klasse Program

Mehr

Computergrafik. Michael Bender, Manfred Brill. Ein anwendungsorientiertes Lehrbuch ISBN Inhaltsverzeichnis

Computergrafik. Michael Bender, Manfred Brill. Ein anwendungsorientiertes Lehrbuch ISBN Inhaltsverzeichnis Computergrafik Michael Bender, Manfred Brill Ein anwendungsorientiertes Lehrbuch ISBN 3-446-40434-1 Inhaltsverzeichnis Weitere Informationen oder Bestellungen unter http://www.hanser.de/3-446-40434-1 sowie

Mehr

Inhaltsverzeichnisse. 1. Überschriften zuweisen. 2. Seitenzahlen einfügen. 3. Einen Seitenwechsel einfügen

Inhaltsverzeichnisse. 1. Überschriften zuweisen. 2. Seitenzahlen einfügen. 3. Einen Seitenwechsel einfügen Inhaltsverzeichnisse 1. Überschriften zuweisen Formatieren Sie die Überschriften mit Hilfe der integrierten Formatvorlagen als Überschrift. Klicken Sie dazu in die Überschrift und dann auf den Drop- Down-Pfeil

Mehr

Einführung in Geonext

Einführung in Geonext Einführung in Geonext von Konrad Brunner Downloadquelle: Regionale Lehrerfortbildung Neue Unterrichtsmethoden im Mathematikunterricht Termin: Ort: 27.03.2003 von 09.30 Uhr bis 16.00 Uhr Städtische Rudolf-Diesel-Realschule,

Mehr

Java 3D Einstiegs-Tutorial Teil 1

Java 3D Einstiegs-Tutorial Teil 1 Java 3D Einstiegs-Tutorial Teil 1 Computergrafik - Übungen W. Kurth, E. Roth WS 2001/02 Java 3D: Application Programming Interface (API) für Java Erweiterung von Java um Klassenbibliotheken, die als Interface

Mehr

Darstellungsarten für 3D-Körper. Boundary Representation (BRep):

Darstellungsarten für 3D-Körper. Boundary Representation (BRep): Darstellungsarten für 3D-Körper Boundary Representation (BRep): Darstellung eines (verallgemeinerten) Polyeders durch das System seiner Ecken, Kanten und Facetten Abspeichern durch (Teilgraphen des) vef-graphen

Mehr

Handbuch für die Erweiterbarkeit

Handbuch für die Erweiterbarkeit Handbuch für die Erweiterbarkeit Inhalt Pakete für die Erweiterbarkeit... 2 Actions... 2 Items... 2 Itemset... 2 Die UseCaseNewAction... 3 Eigene Shapes... 4 Der Shape Container... 5 User Objects... 6

Mehr

EAD II Übung 5. Graphische Benutzungsoberfläche mit BlueJ

EAD II Übung 5. Graphische Benutzungsoberfläche mit BlueJ EAD II Übung 5 Graphische Benutzungsoberfläche mit BlueJ Graphische Benutzungsoberfläche (GUI) Fenster, das weitere Komponenten zur Darstellung und Interaktion enthält spezielle Standardbibliotheken erforderlich,

Mehr

3.1 Motivation. - Mit (mehreren) Koordinatentransformationen wird das Objektsystem in das Gerätesystem transformiert.

3.1 Motivation. - Mit (mehreren) Koordinatentransformationen wird das Objektsystem in das Gerätesystem transformiert. 3.1 Motivation Wichtige Grundlage der Bildwiedergabe auf dem Bildschirm oder anderen Ausgabegeräten sind Koordinatensysteme und Koordinatentransformationen im IR 2 und IR 3. Im allgemeinen unterscheidet

Mehr

Anleitung zum Applet

Anleitung zum Applet Taylor-Entwicklung von Funktionen 1 Anleitung zum Applet Taylor-Entwicklung von Funktionen Bearbeitung von: Denis Schneider SS 2008 Studiengang Elektronik und Informationstechnik Betreuung durch: Prof.

Mehr

Grundlagen der Spieleprogrammierung

Grundlagen der Spieleprogrammierung Grundlagen der Spieleprogrammierung Teil I: 3D-Graphik Kapitel 3: Das Ideal - Photorealistisch Peter Sturm Universität Trier Outline 1. Übersicht und Motivation 2. Mathematische Grundlagen 3. Das Ideal:

Mehr

Benutzerhandbuch Koala Editor

Benutzerhandbuch Koala Editor Benutzerhandbuch Koala Editor Inhalt Einführung, Allgemeine Hinweise... 2 Installation... 2 Allgemeine Funktionen... 3 Neu... 3 Öffnen und Speichern... 4 Modulfunktionen... 5 Klassisches Zustandsdiagramm...

Mehr

Adobe Illustrator 01. Turorial_Übung_03. Darstellungsmethoden WS 2013/ Neues Dokument. 1.2 Formatgröße bestimmen 1.3 Ebenen

Adobe Illustrator 01. Turorial_Übung_03. Darstellungsmethoden WS 2013/ Neues Dokument. 1.2 Formatgröße bestimmen 1.3 Ebenen Adobe Illustrator 01 1. Neues Dokument 1.1 Neues Dokument 1.2 Formatgröße bestimmen 1.3 Ebenen 2. Hintergrund erstellen 2.1 Rechteck zeichnen 2.2 Skalieren 3. Bild platzieren 3.1 Bild skalieren 3.2 Objekte

Mehr

Objektorientierte Modellierung (1)

Objektorientierte Modellierung (1) Objektorientierte Modellierung (1) Die objektorientierte Modellierung verwendet: Klassen und deren Objekte Beziehungen zwischen Objekten bzw. Klassen Klassen und Objekte Definition Klasse Eine Klasse ist

Mehr

9. Digitale Verarbeitung 3-dimensionaler Darstellungen

9. Digitale Verarbeitung 3-dimensionaler Darstellungen 9. Digitale Verarbeitung 3-dimensionaler Darstellungen 9.1 Grundlagen der 3D-Computergrafik 9.2 3D-Modellierung am Beispiel VRML 9.3 Interaktion in 3-dimensionalen Darstellungen 9.4 3D-Grafik-Programmierung

Mehr

Objekte für Train Simulator 2013 mit Blender 2.65 erstellen. (Teil1)

Objekte für Train Simulator 2013 mit Blender 2.65 erstellen. (Teil1) TS 2013 Community http://ts2013.yooco.de Objekte für Train Simulator 2013 mit Blender 2.65 erstellen. (Teil1) Vorwort: Wir haben uns hier mal an die Arbeit gemacht, ein Dokument zu erstellen, welches euch

Mehr

INHALTSVERZEICHNIS. Einleitung Allgemeines

INHALTSVERZEICHNIS. Einleitung Allgemeines Einleitung Allgemeines INHALTSVERZEICHNIS 1 Einleitung...3 1.1 Allgemeines...3 1.2 Starten der Planzusammenstellung...3 1.3 Plansichten und Planteile...4 2 Die Planzusammenstellung...5 2.1 Anlegen einer

Mehr

Transformation Allgemeines Die Lage eines Punktes kann durch einen Ortsvektor (ausgehend vom Ursprung des Koordinatensystems

Transformation Allgemeines Die Lage eines Punktes kann durch einen Ortsvektor (ausgehend vom Ursprung des Koordinatensystems Transformation - 1 1. Allgemeines 2. Zwei durch eine Translation verknüpfte gleichartige Basissysteme 3. Zwei durch eine Translation verknüpfte verschiedenartige Basissysteme (noch gleiche Orientierung)

Mehr

3. Die Datenstruktur Graph

3. Die Datenstruktur Graph 3. Die Datenstruktur Graph 3.1 Einleitung: Das Königsberger Brückenproblem Das Königsberger Brückenproblem ist eine mathematische Fragestellung des frühen 18. Jahrhunderts, die anhand von sieben Brücken

Mehr

Projektarbeit Java. 4-Gewinnt. Berner Fachhochschule. 2004, Labor für Technische Informatik

Projektarbeit Java. 4-Gewinnt. Berner Fachhochschule. 2004, Labor für Technische Informatik Berner Fachhochschule Hochschule für Technik und Informatik, HTI Fachbereich Elektro- und Informatik Labor für technische Informatik Projektarbeit Java 4-Gewinnt 2004, Labor für Technische Informatik Dateiname:

Mehr

Grafik - wozu? GUI Grafische Benutzungsschnittstellen. Gehört zum Standardumfang des JDK. 2 Varianten: AWT und Swing

Grafik - wozu? GUI Grafische Benutzungsschnittstellen. Gehört zum Standardumfang des JDK. 2 Varianten: AWT und Swing Grafik - wozu? Grafik - wozu? GUI Grafische Benutzungsschnittstellen Gehört zum Standardumfang des JDK 2 Varianten: AWT und Swing Konzeptuell sind beide Varianten gleich Heute: Beispiel für AWT Zeichnen,

Mehr

Zuerst brauchen Sie einen Hintergrund. Dieses Bild sollte nicht zu klein sein. Die Größe, die wir benutzt haben, sehen Sie hier:

Zuerst brauchen Sie einen Hintergrund. Dieses Bild sollte nicht zu klein sein. Die Größe, die wir benutzt haben, sehen Sie hier: 3D-Text erstellen In diesem kurzen Tutorial möchten wir gern die Grundlagen der 3D-Textgestaltung in Photoshop erklären. Versuchen Sie einmal dieses Bild nachzustellen. Zuerst brauchen Sie einen Hintergrund.

Mehr

Neben der Verwendung von Klassen ist Vererbung ein wichtiges Merkmal objektorientierter

Neben der Verwendung von Klassen ist Vererbung ein wichtiges Merkmal objektorientierter Kapitel 1 Der vierte Tag 1.1 Vererbung Neben der Verwendung von Klassen ist Vererbung ein wichtiges Merkmal objektorientierter Sprachen. Unter Vererbung versteht man die Möglichkeit, Eigenschaften vorhandener

Mehr

Die Welt der Shader. Fortgeschrittene Techniken III

Die Welt der Shader. Fortgeschrittene Techniken III Die Welt der Shader Fortgeschrittene Techniken III Universität zu Köln WS 14/15 Softwaretechnologie II (Teil 1) Prof. Dr. Manfred Thaller Referent: Lukas Kley Gliederung 1. Was ist ein Shader? 2. Verschiedene

Mehr

7. Arrays. Beim Deklarieren und Initialisieren der Liste bräuchte man oft zueinander sehr ähnlichen Code:

7. Arrays. Beim Deklarieren und Initialisieren der Liste bräuchte man oft zueinander sehr ähnlichen Code: 7. Arrays Gelegentlich braucht man für ein Programm mehrere Attribute desselben Datentyps oder derselben Klasse. Beispiel: In der Highscore-Liste eines Spiels werden von den 10 besten Spielern die Namen

Mehr

Übungsstunde 7 zu Computergrafik 1

Übungsstunde 7 zu Computergrafik 1 Institut für Computervisualistik Universität Koblenz 10. und 11. Dezember 2012 Inhaltsverzeichnis 1 Licht und Material Licht in OpenGL Material in OpenGL 2 in C++ Licht in OpenGL Lichtquellen In OpenGL

Mehr

Der Ball kann angezeigt werden: anzeigen( ) {... } Der Ball kann z.b. seine Größe verändern: groesseaendern(int veraenderung) {... } usw.

Der Ball kann angezeigt werden: anzeigen( ) {... } Der Ball kann z.b. seine Größe verändern: groesseaendern(int veraenderung) {... } usw. Objekt-Orientierung Die ersten objektorientierten Sprachen wurden ab 1967 entwickelt (Simula, Smalltalk). Die Grundidee besteht darin, Objekte der realen Welt abzubilden. Java-Programme bestehen aus Klassen.

Mehr

Kurzanleitung Hama Photokalender v

Kurzanleitung Hama Photokalender v Inhalt 1. Vorwort / Installation 2. Software- / Druckereinstellungen 3. Symbole und Objekte 1. Vorwort / Installation Hama Photokalender ist ein einfaches, leicht anzuwendendes Programm zum erstellen individueller

Mehr

Parallele und funktionale Prog. Wintersemester 2012/ Übung Abgabe bis , 10:00 Uhr

Parallele und funktionale Prog. Wintersemester 2012/ Übung Abgabe bis , 10:00 Uhr 9. Übung Abgabe bis 07.01.2013, 10:00 Uhr Aufgabe 9.1: Zeigerverdopplung Ermitteln Sie an folgendem Beispiel den Rang für jedes Listenelement sequentiell und mit dem in der Vorlesung vorgestellten parallelen

Mehr

Objekte. Theorieteil. Inhaltsverzeichnis. Begriffe. Programmieren mit Java Modul 5. 1 Modulübersicht 3

Objekte. Theorieteil. Inhaltsverzeichnis. Begriffe. Programmieren mit Java Modul 5. 1 Modulübersicht 3 Programmieren mit Java Modul 5 Objekte Theorieteil Inhaltsverzeichnis 1 Modulübersicht 3 2 Klassen und Objekte 3 2.1 Klassen.................................... 4 2.2 Objektvariablen und Methoden.......................

Mehr

User & System. Dokumentation

User & System. Dokumentation User & System Dokumentation Technische Details Hardware: Samsung Wave 1 Betriebssystem: Game Engine: Bada (C++) XiS (selbst entwickelt) Entwicklungsumgebung: Bada IDK 1.0 Verwendete Programme: Autodesk

Mehr

Objektorientierte Programmierung (OOP)

Objektorientierte Programmierung (OOP) orientierte Programmierung (OOP) 1. Motivation Die objektorientierte Sichtweise der Welt Als Motivation für die OOP sieht man sich am besten die reale Welt an: Die reale Welt besteht aus "en", z. B.: Gegenstände,

Mehr

Rendering: Lighting and Shading

Rendering: Lighting and Shading Rendering: Lighting and Shading Hauptseminar: How to make a Pixar Movie Inhalt Einführung Was ist Rendering Was ist Reflexionsmodelle Lighting Shading Globale Beleuchtungsmodelle Zusammenfassung 2/53 Inhalt

Mehr

Aufgabe 2 (Musterlösung) CorelDRAW

Aufgabe 2 (Musterlösung) CorelDRAW Aufgabe 2 (Musterlösung) CorelDRAW Seite 1 von 9 Aufgabe 2 (Musterlösung) CorelDRAW Inhaltsverzeichnis Einleitung... 2 Musterlösung... 2 Nachtrag... 9 Abbildungsverzeichnis Abb. 1: Linie und Dreieck (vorher

Mehr

Komplexpraktikum Graphische Datenverarbeitung im WS 04/05

Komplexpraktikum Graphische Datenverarbeitung im WS 04/05 Komplexpraktikum Graphische Datenverarbeitung im WS 04/05 von Enrico Leonhardt 28 45 669 TU Dresden Medieninformatik 29. März 2005 Graphische Datenverarbeitung WS 04/05 Einführung Dieser Raytracer entstand

Mehr

Formulare. Datenbankanwendung 113

Formulare. Datenbankanwendung 113 Formulare Wenn Sie mit sehr umfangreichen Tabellen arbeiten, werden Sie an der Datenblattansicht von Access nicht lange Ihre Freude haben, sind dort doch immer zu wenig Felder gleichzeitig sichtbar. Um

Mehr

Inhalt. Installieren Projekt erstellen UI Bedienen Objekte importieren Blueprints C++

Inhalt. Installieren Projekt erstellen UI Bedienen Objekte importieren Blueprints C++ Eine Einführung Inhalt Installieren Projekt erstellen UI Bedienen Objekte importieren Blueprints C++ Installieren Launcher Engine Visual Studio Registrieren Epic Launcher herunterladen (www.unrealengine.com)

Mehr

Institut für Programmierung und Reaktive Systeme. GUIs mit Swing. Markus Reschke

Institut für Programmierung und Reaktive Systeme. GUIs mit Swing. Markus Reschke GUIs mit Swing Markus Reschke 28.08.2014 Beispiel: Ein einfaches GUI-Programm Siehe Painter.java Markus Reschke GUIs mit Swing 2 GUI Frameworks in Java AWT war das erste GUI-Framework, welches mit Java

Mehr

Einführung in die Programmierung für Nebenfach Medieninformatik. Beat Rossmy, Michael Kirsch

Einführung in die Programmierung für Nebenfach Medieninformatik. Beat Rossmy, Michael Kirsch Einführung in die Programmierung für Nebenfach Medieninformatik Beat Rossmy, Michael Kirsch Direct Feedback - Socrative Eure Mitarbeit ist uns wichtig! Installiert euch dazu die kostenlose App Socrative

Mehr

Kleines Einführungstutorial zu DAZ-Studio

Kleines Einführungstutorial zu DAZ-Studio Kleines Einführungstutorial zu DAZ-Studio Spätestens mit dem Kauf und der Installation von Bryce 5.5 wird man mit dem DAZ- Studio konfrontiert. Mit Hilfe von DAZ-Studio wird der Import von Poserfiguren

Mehr

Verkettete Datenstrukturen: Listen

Verkettete Datenstrukturen: Listen Verkettete Datenstrukturen: Listen 2 Listen Formal: Liste = endliche Folge von Elementen [a 1, a 2,..., a n ]. Spezialfall: leere Liste [ ]. Länge einer Liste = Anzahl der Elemente (bei leerer Liste: 0).

Mehr

Tutorial - Übung: UML Klassendiagramm

Tutorial - Übung: UML Klassendiagramm Tutorial - Übung: UML Klassendiagramm Das UML-Klassendiagramm In dieser Lerneinheit sollen Sie die in dem Vorlesungstutorial erlernten Grundlagen zum UML- Klassendiagramm praktisch anwenden Einführung

Mehr

Inhaltsverzeichnisse

Inhaltsverzeichnisse Inhaltsverzeichnisse Überschriften zuweisen Formatieren Sie die Überschriften mit Hilfe der integrierten Formatvorlagen als Überschrift. Klicken Sie dazu in die jeweilige Überschrift und dann auf der Registerkarte

Mehr

Einführung in die Programmierung für Nebenfach Medieninformatik. Beat Rossmy, Michael Kirsch

Einführung in die Programmierung für Nebenfach Medieninformatik. Beat Rossmy, Michael Kirsch Einführung in die Programmierung für Nebenfach Medieninformatik Beat Rossmy, Michael Kirsch Direct Feedback - Socrative Eure Mitarbeit ist uns wichtig! Installiert euch dazu die kostenlose App Socrative

Mehr

CorelDRAW 2017 Ebenen

CorelDRAW 2017 Ebenen Hochschulrechenzentrum Justus-Liebig-Universität Gießen CorelDRAW 2017 Ebenen Ebenen in CorelDRAW Seite 1 von 7 Inhaltsverzeichnis Einleitung... 2 Der Objekt-Manager... 2 Mit Ebenen arbeiten... 3 Ebenen

Mehr

BlendaX Grundlagen der Computergrafik

BlendaX Grundlagen der Computergrafik BlendaX Grundlagen der Computergrafik Beleuchtungsmodelle (Reflection Models) 16.11.2007 BlendaX Grundlagen der Computergrafik 1 Rendering von Polygonen Der Renderingprozess lässt sich grob in folgende

Mehr

Kurzanleitung. 2016, Hundesportverein Swisttal e.v., Dirk Lippmann, Alle Rechte vorbehalten.

Kurzanleitung. 2016, Hundesportverein Swisttal e.v., Dirk Lippmann, Alle Rechte vorbehalten. Kurzanleitung Wichtige Informationen vorab - Der Parcoursplaner läuft in allen Browsern, welche HTML5 unterstützen. Ich beschränke mich hier auf die Anleitung für Google Chrome. Einige Dinge weichen in

Mehr

Gerichtsvollzieher Briefbogen

Gerichtsvollzieher Briefbogen Gerichtsvollzieher Briefbogen erstellen, verändern, neugestalten und mit anderen tauschen Workshop Software GmbH Siemensstr. 21 47533 Kleve 02821 / 731 20 02821 / 731 299 www.workshop-software.de Verfasser:

Mehr

Einstieg in die Informatik mit Java

Einstieg in die Informatik mit Java 1 / 18 Einstieg in die Informatik mit Java Applets Gerd Bohlender Institut für Angewandte und Numerische Mathematik Gliederung 2 / 18 1 Einführung 2 Sicherheits-Maßnahmen 3 Ereignisgesteuerte Programmierung

Mehr

Java 3D Einstiegs-Tutorial Teil 3

Java 3D Einstiegs-Tutorial Teil 3 Navigation mit der Maus Java 3D Einstiegs-Tutorial Teil 3 Computergrafik - Übungen W. Kurth, E. Roth WS 2001/02 Java 3D eröffnet mehrere Möglichkeiten, sich mittels Maus- Eingaben im virtuellen Raum zu

Mehr

7 Die ersten Modelle. 7.1 Verschiedene Möglichkeiten führen zum Ziel

7 Die ersten Modelle. 7.1 Verschiedene Möglichkeiten führen zum Ziel Nach den Kapiteln über die Desktop-Strukturen von AutoCAD 2007 und dem Einrichten einer Projektumgebung mit eigenen Prototypblättern sollen nun praktische Lerneinheiten mit einfachen Grundkörpern folgen.

Mehr

Vektorobjekte auf der Formebene zeichnen. Form-Werkzeug wählen und über die Optionsleiste die Formeigenschaften festlegen

Vektorobjekte auf der Formebene zeichnen. Form-Werkzeug wählen und über die Optionsleiste die Formeigenschaften festlegen Vektorobjekte Besonderheiten von Vektorobjekten Was sind Vektorobjekte? Vektorobjekte bestehen aus Linien oder Kurven, die mathematisch berechnet werden. Die Konturen von Vektorobjekten werden als Pfade

Mehr

Featurebasierte 3D Modellierung

Featurebasierte 3D Modellierung 1 Featurebasierte 3D Modellierung Moderne 3D arbeiten häufig mit einer Feature Modellierung. Hierbei gibt es eine Reihe von vordefinierten Konstruktionen, die der Reihe nach angewandt werden. Diese Basis

Mehr

Objektorientierte Programmierung

Objektorientierte Programmierung Unterlagen zur Veranstaltung Einführung in die Objektorientierte Programmierung Mit Processing Alexis Engelke Sommer 2012 Alexis Engelke Inhalt Level 1: Geometrie Hintergrundfarben Punkte, Linien und deren

Mehr

Schattenwurf mit Perspective Shadow Maps

Schattenwurf mit Perspective Shadow Maps 16. April 2010 Xpiriax Software Wer wir sind und was wir machen Hobby-Entwicklerteam, zur Zeit 6 Personen gegründet Anfang 2008 Schwerpunkte: Spiele- & 3D-Engine-Programmierung Ziele: Erfahrung, Arbeitsproben,

Mehr

In Version 6 gibt es separate Editoren für das Erstellen und Bearbeiten von Strukturen, Funktionsnetzen und Fehlernetzen.

In Version 6 gibt es separate Editoren für das Erstellen und Bearbeiten von Strukturen, Funktionsnetzen und Fehlernetzen. Graph-Editor In Version 6 gibt es separate Editoren für das Erstellen und Bearbeiten von Strukturen, Funktionsnetzen und Fehlernetzen. Im Zusammenhang mit der Mechatronik-FMEA und der Funktionalen Sicherheit

Mehr

Arbeitsblatt 6: Programmierung geometrischer Figuren

Arbeitsblatt 6: Programmierung geometrischer Figuren Arbeitsblatt 6: Programmierung geometrischer Figuren Die Karten, auf denen die Lärmmessungen dargestellt werden, bestehen aus einer Vielzahl geometrischer Formen. Diese geometrischen Formen ergeben zusammen

Mehr

Kantengraphen und Planare Graphen. Seminararbeit

Kantengraphen und Planare Graphen. Seminararbeit Kantengraphen und Planare Graphen Seminararbeit in Mathematisches Seminar für LAK 621.378 SS 2018 vorgelegt von Anna Maria Gärtner bei: Baur, Karin, Univ.-Prof. Dr.phil. Graz, 2018 Inhaltsverzeichnis 1

Mehr

1 Benutzeroberfläche von Chart2D

1 Benutzeroberfläche von Chart2D 1 Benutzeroberfläche von Chart2D Autor: Lars Seckler Diplomarbeit FH- Lübeck Juni 2011 Da es sich bei Chart2D um eine Komponente und nicht um ein eigenständig lauffähiges Programm handelt, muss diese unter

Mehr

Softwaretechnik (Medieninformatik): GUIs mit Swing Überblick

Softwaretechnik (Medieninformatik): GUIs mit Swing Überblick Softwaretechnik (Medieninformatik): GUIs mit Swing Überblick 1 Einführung 2 Einfache Swing Komponenten 3 Ereignisbehandlung und Adapterklassen 4 Zeichnen 5 Layout Manager 6 Komplexere Swing Komponenten

Mehr

Objektorientierte und Funktionale Programmierung SS 2014

Objektorientierte und Funktionale Programmierung SS 2014 Objektorientierte und Funktionale Programmierung SS 2014 6 Objektorientierte Entwurfsmuster 1 6 Objektorientierte Entwurfsmuster Lernziele Einige wichtige Entwurfsmuster kennen und verstehen Einsatzmöglichkeiten

Mehr