21.02.2013 Aufrufe

Computerholographie - der Fam. Partheil aus Biedenkopf-Wallau

Computerholographie - der Fam. Partheil aus Biedenkopf-Wallau

Computerholographie - der Fam. Partheil aus Biedenkopf-Wallau

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

Städtisches Gymnasium Bad Laasphe<br />

<strong>Computerholographie</strong><br />

Facharbeit<br />

von Michael <strong>Partheil</strong><br />

im Leistungskurs Physik<br />

Fachlehrer: Herr Bernsh<strong>aus</strong>en<br />

Abgabetermin: 01.03.2005<br />

Schuljahr 2004/2005


Vorwort<br />

Zum Thema Holographie ist bereits viel geschrieben worden: Jugend-Forscht-<br />

Arbeiten, Facharbeiten, Bücher für interessierte Laien, uvm. Wer sich mit<br />

herkömmlicher Holographie beschäftigen möchte, findet hierzu einiges an<br />

Material.<br />

Diese Facharbeit spezialisiert sich deshalb auf ein Untergebiet <strong>der</strong> Holographie,<br />

zu dem noch nicht sehr viel publiziert worden ist: die <strong>Computerholographie</strong>.<br />

Dies ist allerdings nicht <strong>der</strong> einzige Grund, warum ich mich gegen eine Arbeit<br />

über „normale“ Holographie entschieden habe: Es ist zwar ein sehr schönes<br />

Hobby, Hologramme selber anzufertigen, aber auch ein sehr kostspieliges und<br />

umständliches: Man benötigt spezielles holographisches Filmmaterial sowie<br />

einen leistungsstarken Laser, beides ist nicht nur teuer, son<strong>der</strong>n auch schwer<br />

zu beschaffen. <strong>Computerholographie</strong> hingegen kommt mit einem<br />

herkömmlichen Dokumentenfilm, einem Computer und einer Kamera <strong>aus</strong>.<br />

Das Hauptproblem war einmal, dass ich kein geeignetes Programm zur<br />

Berechnung <strong>der</strong> Hologramme finden konnte, und zum an<strong>der</strong>en, dass ich<br />

keinerlei Erfahrung mit <strong>der</strong> Entwicklung von Filmen hatte.<br />

Das erste Problem habe ich gelöst, indem ich selber ein solches Programm<br />

entwickelt habe. Zum Thema Filmentwicklung habe ich mich mithilfe von<br />

Literatur informiert, sowie Tipps von „Profis“ bekommen, und nach einigen<br />

Fehlversuchen hat die Entwicklung dann auch geklappt. Für die Herstellung von<br />

Computerhologrammen sind also keinerlei Vorkenntnisse nötig!<br />

2


Inhalt<br />

1 Einführung 5<br />

1.1 Geschichte <strong>der</strong> Holographie 5<br />

1.2 Unterschiedliche Hologramm-Arten 6<br />

1.2.1 Transmissionshologramme 6<br />

1.2.2 Weißlichtreflexionshologramme 7<br />

1.2.3 Regenbogenhologramme 7<br />

2 Physik <strong>der</strong> Holographie 8<br />

2.1 Aufnahme und Betrachtung von<br />

Transmissionshologrammen 8<br />

2.2 Funktionsweise an Beispielen erklärt 10<br />

2.2.1 Aufnahme eines Hologramms 10<br />

2.2.2 Rekonstruktion eines Hologramms 12<br />

2.2.3 Pseudoskopische Bil<strong>der</strong> 15<br />

2.3 Mathematische Erklärung 16<br />

2.3.1 Aufnahme eines Hologramms 16<br />

2.3.2 Rekonstruktion eines Hologramms 19<br />

3 <strong>Computerholographie</strong> 20<br />

3.1 Grundlagen <strong>der</strong> <strong>Computerholographie</strong> 21<br />

3.2 Probleme bei <strong>der</strong> <strong>Computerholographie</strong> 21<br />

3.3 Berechnung von Computerhologrammen 22<br />

3.3.1 Zufallsphasen 23<br />

3.3.2 Kontrasterhöhung 24<br />

3.4 Fotoarbeiten 24<br />

Anhang A: Beigefügte Materialien 26<br />

Anhang B: Bedienung des CGH-Programms 27<br />

Anhang C: Literaturverzeichnis 29<br />

Anhang D: Selbstständigkeitserklärung 30<br />

Anhang E: Quelltext des CGH-Programms 31<br />

AuswahlListener.java 31<br />

BerechnungsFortschrittListener.java 31<br />

CGHMain.java 31<br />

DynamicHelpListener.java 32<br />

EigenschaftenEditorControl.java 33<br />

ErgebnisDialog.java 34<br />

3


HelpViewer.java 38<br />

HologrammEditor.java 39<br />

InterferenzMuster.java 47<br />

MainShell.java 51<br />

NullEditor.java 59<br />

ObjektEditor.java 60<br />

ObjektPunkt.java 60<br />

ObjektPunktEditor.java 61<br />

ObjektPunktPosListener.java 65<br />

Photo.java 65<br />

Simulation.java 66<br />

SimulationEditor.java 67<br />

SWTUtils.java 72<br />

TextInputDialog.java 72<br />

TextPseudoObjekt.java 76<br />

VollBildDialog.java 76<br />

4


1 Einführung<br />

Das Wort „Hologramm“ besteht <strong>aus</strong> den zwei Silben „holo“ und „gramm“. Sie<br />

sind eine Anlehnung an die griechischen Wörter hólo „ganz, völlig“ und grámma<br />

„Nachricht“. Übersetzt bedeutet „Hologramm“ also „Ganze Nachricht“. Und dies<br />

beschreibt die Holographie auch schon sehr gut. Im Gegensatz zur normalen<br />

Photographie können mit ihr nämlich nicht nur zweidimensionale son<strong>der</strong>n<br />

dreidimensionale Bil<strong>der</strong> aufgenommen werden. In einem Hologramm sind alle<br />

Informationen, die bei <strong>der</strong> Aufnahme verfügbar waren, also auch die Tiefe,<br />

gespeichert. Deshalb kann ein Hologramm mit gutem Gewissen als „ganzes“<br />

Abbild beschrieben werden.<br />

Diese Dreidimensionalität wird dadurch erreicht, dass nicht wie bei <strong>der</strong><br />

herkömmlichen Photographie die Intensität des vom aufzunehmenden Objekt<br />

kommenden Lichtes aufgezeichnet wird, son<strong>der</strong>n mithilfe eines speziellen<br />

Aufnahmeverfahrens auch die Richtung des Lichtstrahles. Bei <strong>der</strong> Wie<strong>der</strong>gabe<br />

werden alle bei <strong>der</strong> Aufnahme gespeicherten Lichtstrahlen rekonstruiert und<br />

ihre Summe bildet dann das holographische Bild. Da beide Augen des<br />

Betrachters ein etwas gegeneinan<strong>der</strong> versetztes Bild liefern, kann das Gehirn<br />

so die Tiefe berechnen. Ein Hologramm ist somit keine optische Täuschung,<br />

son<strong>der</strong>n eine reale Rekonstruktion des aufgenommenen Gegenstandes.<br />

1.1 Geschichte <strong>der</strong> Holographie<br />

Die Grundlagen <strong>der</strong> Holographie wurden im Jahr 1948 von dem am 5. Juni<br />

1900 in Budapest geborenen, aber später nach Großbritannien emigrierten<br />

Physiker Dennis Gabor (Abbildung 1) entdeckt.<br />

Er suchte nach einer Möglichkeit, die damals noch unbedeutende<br />

Elektronenmikroskopie zu verbessern und wollte dazu zunächst eine Methode<br />

entwickeln, um alle Informationen eines Lichtstrahles, d.h. sowohl seine<br />

Intensität als auch Phase, speichern zu können. Diesem Verfahren gab er den<br />

Namen Holographie. Aufgrund fehlen<strong>der</strong> Lichtquellen mit großer Kohärenzlänge<br />

fand seine Entdeckung allerdings kaum Anwendung: Sie taugte we<strong>der</strong> zur<br />

Verbesserung von Elektronenmikroskopen noch zur Aufnahme von<br />

dreidimensionalen Bil<strong>der</strong>n. Seine Entdeckung gewann erst 1962 mit <strong>der</strong><br />

Erfindung des Lasers an Bedeutung, da <strong>der</strong> Laser im Gegensatz zu normalen<br />

5


Lichtquellen eine große Kohärenzlänge besitzt und sich damit für die Aufnahme<br />

von Hologrammen eignet.<br />

Dennis Gabor erhielt 1971 für die Erfindung <strong>der</strong> Holographie den Nobelpreis für<br />

Physik.<br />

Abbildung 1: Dennis Gabor (1900-1979) entdeckte das Prinzip <strong>der</strong> Holographie (<strong>aus</strong><br />

[HE95])<br />

1.2 Unterschiedliche Hologramm-Arten<br />

Im Laufe <strong>der</strong> Zeit haben Forscher verschiedene Variationen des ursprünglichen<br />

Verfahrens zur Holographie entwickelt. Mittlerweile gibt es eine ganze Reihe<br />

von verschiedenen Arten von Hologrammen. Drei davon sollen im Folgenden<br />

kurz vorgestellt werden.<br />

1.2.1 Transmissionshologramme<br />

Ein Laserlichttransmissionshologramm ist eine leicht lichtdurchlässige Platte<br />

o<strong>der</strong> Folie. Bei <strong>der</strong> Betrachtung des Hologramms wird es von <strong>der</strong> einen Seite<br />

mit einem aufgeweiteten Laserstrahl beschienen, <strong>der</strong> Beobachter befindet sich<br />

6


auf <strong>der</strong> gegenüberliegenden Seite. Der Strahl dringt durch das Hologramm und<br />

erzeugt auf <strong>der</strong> an<strong>der</strong>en Seite das rekonstruierte Bild. In <strong>der</strong> Optik wird <strong>der</strong><br />

Durchgang von Licht durch eine Substanz als Transmission bezeichnet. Daher<br />

kommt <strong>der</strong> Name dieser Art von Hologramm.<br />

Der Nachteil von Transmissionshologrammen ist die Schwierigkeit bei <strong>der</strong><br />

Betrachtung: Sie können nur mithilfe eines geeigneten Lasers betrachtet<br />

werden. Trotz dieses Nachteils sind Transmissionshologramme in Forschung<br />

und Technik weit verbreitet, da sie eine sehr große Schärfentiefe aufweisen.<br />

1.2.2 Weißlichtreflexionshologramme<br />

Wegen <strong>der</strong> komplizierten Beleuchtung von Transmissionshologrammen findet<br />

man in Ausstellungen meistens Weißlichtreflexionshologramme. Dieser<br />

Hologrammtyp kann mit normalem, d.h. weißem Licht rekonstruiert werden. Der<br />

Betrachter und die Lichtquelle befinden sich dabei auf <strong>der</strong>selben Seite des<br />

Hologramms.<br />

Dieser Hologrammtyp wurde 1963 von dem russischen Wissenschaftler Yurii N.<br />

Denisyuk erfunden und wird deshalb auch manchmal als „Denisyuk-<br />

Hologramm“ bezeichnet.<br />

1.2.3 Regenbogenhologramme<br />

Ein Regenbogenhologramm kann, genau wie das Weißlicht-<br />

reflexionshologramm, mit weißem Licht betrachtet werden. Der Unterschied ist,<br />

dass ein Regenbogenhologramm keine Tiefe besitzt. Bewegt man das<br />

Hologramm, sieht man nicht den Gegenstand von <strong>der</strong> Seite, son<strong>der</strong>n es än<strong>der</strong>t<br />

sich die Farbe des Gegenstandes entsprechend <strong>der</strong> Farbfolge des<br />

Regenbogens.<br />

Regenbogenhologramme wurden erstmals im Jahr 1969 von dem<br />

amerikanischen Forscher S. Benton hergestellt.<br />

7


2 Physik <strong>der</strong> Holographie<br />

Die Funktionsweise von Hologrammen ist recht einfach zu erklären. Dazu<br />

werden keine komplizierten physikalischen Sachverhalte benötigt; als einzige<br />

Vorkenntnisse werden das Prinzip <strong>der</strong> Interferenz und die Beugung von Licht<br />

am Doppelspalt vor<strong>aus</strong>gesetzt.<br />

Alle folgenden Beschreibungen beziehen sich auf das Transmissionshologramm,<br />

da es quasi <strong>der</strong> „Urvater“ aller Hologramme ist. Alle an<strong>der</strong>en<br />

Hologrammtypen funktionieren nach demselben Prinzip.<br />

Zunächst wird beschrieben, wie Transmissionshologramme auf herkömmliche<br />

Art und Weise aufgenommen werden können. Hierbei soll lediglich das Prinzip<br />

verdeutlicht werden, auf praktische Beson<strong>der</strong>heiten wird nicht eingegangen. In<br />

Kapitel 2.2 folgt dann eine von mathematischen Formeln losgelöste<br />

Beschreibung <strong>der</strong> Grundlagen <strong>der</strong> Holographie anhand von Beispielen. Diese<br />

Zusammenhänge können allerdings nicht nur in Experimenten beobachtet<br />

werden, son<strong>der</strong>n auch mathematisch korrekt bewiesen und erklärt werden. Dies<br />

ist <strong>der</strong> Inhalt von Kapitel 2.3.<br />

2.1 Aufnahme und Betrachtung von<br />

Transmissionshologrammen<br />

Das Prinzip <strong>der</strong> Aufnahme eines Transmissionshologramms ist in Abbildung 2<br />

dargestellt:<br />

Der Strahl eines Lasers, typischerweise ein roter Helium-Neon-Laser mit 1 mW<br />

bis 5 mW Leistung wird durch eine Linse aufgeweitet und mithilfe eines<br />

Strahlenteilers in zwei Strahlen geteilt. Der eine Strahl beleuchtet das<br />

aufzunehmende Objekt und wird deshalb Objektstrahl genannt. Der zweite<br />

Strahl wird direkt auf den Film geleitet und heißt Referenzstrahl. Seine Funktion<br />

wird in den folgenden Kapiteln näher erläutert.<br />

In <strong>der</strong> Praxis wird <strong>der</strong> beschriebene Aufbau so heutzutage nicht mehr benutzt,<br />

da die Verwendung des Strahlenteilers Stabilitätsprobleme mit sich bringt.<br />

8


Abbildung 2: Aufnahme eines Transmissionshologramms<br />

Die Wie<strong>der</strong>gabe des Hologramms beschreibt Abbildung 3.<br />

Bei <strong>der</strong> Wie<strong>der</strong>gabe strahlt <strong>der</strong> aufgeweitete Laserstrahl durch das Hologramm<br />

hindurch und erzeugt auf <strong>der</strong> an<strong>der</strong>en Seite des Films das rekonstruierte Bild.<br />

Es ist darauf zu achten, dass <strong>der</strong> bei <strong>der</strong> Wie<strong>der</strong>gabe verwendete Laser<br />

dieselbe Wellenlänge besitzt wie <strong>der</strong> bei <strong>der</strong> Aufnahme benutzte Laser.<br />

Abbildung 3: Wie<strong>der</strong>gabe eines Transmissionshologramms<br />

9


2.2 Funktionsweise an Beispielen erklärt<br />

2.2.1 Aufnahme eines Hologramms<br />

Bei <strong>der</strong> Aufnahme eines Hologramms treffen sowohl Referenz- als auch die<br />

Objektwelle auf das Filmmaterial. Die Objektwelle ist dabei <strong>der</strong> Strahl, <strong>der</strong> von<br />

dem aufzunehmenden Objekt reflektiert wird. Er beinhaltet also die<br />

Informationen, die in dem Hologramm gespeichert und später wie<strong>der</strong>gegeben<br />

werden sollen. Der Referenzstrahl hingegen trifft immer gleichmäßig <strong>aus</strong><br />

demselben Winkel unverän<strong>der</strong>t auf den Film. Er beinhaltet somit als einzige<br />

Information die Phase des Strahls des verwendeten Lasers. Wie wir im<br />

Folgenden sehen werden, ist diese Information, die in <strong>der</strong> herkömmlichen<br />

Photographie nicht vorhanden ist, sehr wichtig für die Funktion des<br />

Hologramms. Natürlich ist die Phase <strong>der</strong> Referenzwelle nicht zwingend dieselbe<br />

wie die des Objektstrahles, da die Weglängen normalerweise nicht identisch<br />

sind, was allerdings kein Problem darstellt.<br />

Bei <strong>der</strong> Aufnahme interferieren nun <strong>der</strong> Objekt- und <strong>der</strong> Referenzstrahl<br />

miteinan<strong>der</strong> und bilden ein Interferenzmuster. Dieses Muster wird auf dem Film<br />

gespeichert. Es ist sehr fein, nämlich im Bereich <strong>der</strong> Wellenlänge des<br />

verwendeten Lasers, also nur wenige Nanometer. Deshalb muss für<br />

herkömmliche Holographie auch spezielles Filmmaterial verwendet werden, da<br />

selbst hochauflösende Dokumentenfilme wie z.B. <strong>der</strong> Technical Pan von Kodak<br />

nur eine Auflösung von 300 bis 400 Linienpaare pro Millimeter (Lp/mm)<br />

besitzen, holographisches Filmmaterial wie <strong>der</strong> Holotest-Film von Agfa<br />

hingegen kann bis zu 6.000 Lp/mm abbilden.<br />

In Abbildung 4 ist eine Momentaufnahme dargestellt, wenn gerade ein<br />

Wellenberg <strong>der</strong> Referenzwelle auf den Film trifft. Die Wellen sind hier<br />

näherungsweise als Geraden dargestellt. Die Objektwelle trifft mit einem relativ<br />

großen Winkel auf den Film. Überall dort, wo auch ein Wellenberg <strong>der</strong><br />

Objektwelle auf den Film trifft, wird <strong>der</strong> Film stark belichtet, da <strong>der</strong> Berg durch<br />

den Berg <strong>der</strong> Referenzwelle sogar noch verstärkt wird. Trifft hingegen ein<br />

Wellental <strong>der</strong> Objektwelle auf den Film, bleibt er dort unbelichtet, weil ein<br />

Wellental <strong>der</strong> Objektwelle und ein Wellenberg <strong>der</strong> Referenzwelle Dunkelheit<br />

ergeben.<br />

10


Auf dem Film entsteht also eine Abfolge von hellen und dunklen Stellen. Wichtig<br />

für die Holographie ist nun <strong>der</strong> Abstand zwischen den unbelichteten,<br />

lichtdurchlässigen Stellen.<br />

Abbildung 4: Momentaufnahme bei <strong>der</strong> Aufnahme eins Hologramms (Wellenberge sind<br />

Linien; Täler gestrichelt) (<strong>aus</strong> [HE95])<br />

In Abbildung 5 ist dieselbe Situation dargestellt wie in Abbildung 4, allerdings<br />

trifft die Objektwelle jetzt mit einem kleineren Winkel auf den Film. Wie man<br />

sieht, ist hier <strong>der</strong> Abstand zwischen den unbelichteten Stellen größer als bei<br />

einem Objektstrahl, <strong>der</strong> mit großem Winkel auftrifft. Man könnte also folgende<br />

These aufstellen: Je kleiner <strong>der</strong> Winkel zwischen <strong>der</strong> Objektwelle und dem Film<br />

ist, desto größer ist <strong>der</strong> Abstand zwischen den lichtdurchlässigen Stellen.<br />

Es könnte noch eingewendet werden, dass bei <strong>der</strong> Aufnahme ja nicht immer ein<br />

Wellenberg <strong>der</strong> Referenzwelle auf den Film trifft, da Licht ja eine Schwingung<br />

ist. Eine halbe Wellenlänge später würde beispielsweise ein Wellental auf den<br />

Film treffen.<br />

Man muss allerdings beachten, dass sich die Phase <strong>der</strong> Objektwelle ja auch<br />

än<strong>der</strong>t und zwar mit <strong>der</strong>selben Geschwindigkeit wie die <strong>der</strong> Referenzwelle. Trifft<br />

nun eine halbe Wellenlänge nach <strong>der</strong> dargestellten Situation ein<br />

Referenzwellental auf den Film, so ist an den Stellen, wo vorher ein Tal <strong>der</strong><br />

Objektwelle war nun ein Berg. Ein Referenzwellental und ein Objektwellenberg<br />

ergeben allerdings genau wie vorher Dunkelheit und damit eine unbelichtete<br />

Stelle.<br />

11


Abbildung 5: Momentaufnahme, die Objektwelle trifft mit einem kleineren Winkel auf den<br />

Film als in Abbildung 4 (<strong>aus</strong> [HE95])<br />

Im Folgenden wird nun gezeigt, dass bei <strong>der</strong> Wie<strong>der</strong>gabe <strong>der</strong>selbe<br />

Zusammenhang zwischen dem Winkel <strong>der</strong> Objektwelle und dem Abstand <strong>der</strong><br />

lichtdurchlässigen Stellen gilt. Damit wäre gezeigt, dass ein Objektstrahl bei <strong>der</strong><br />

Wie<strong>der</strong>gabe den Film mit genau demselben Winkel verlässt, in dem er bei <strong>der</strong><br />

Aufnahme auf den Film getroffen ist. Natürlich gibt es bei einem richtigen<br />

Hologramm nicht nur eine Objektwelle son<strong>der</strong>n sehr viele. Das Hologramm<br />

vermag es aber, alle Objektstrahlen in genau dem <strong>der</strong> Aufnahme<br />

entsprechenden Winkel wie<strong>der</strong> abzugeben. Bei <strong>der</strong> Wie<strong>der</strong>gabe wird also die<br />

komplette Welle, die vom Objekt <strong>aus</strong>geht, rekonstruiert.<br />

2.2.2 Rekonstruktion eines Hologramms<br />

Ein belichtetes Hologramm ist im Grunde ein mehr o<strong>der</strong> weniger enges Muster<br />

<strong>aus</strong> durchsichtigen und undurchsichtigen Linien. Wird das Hologramm bei <strong>der</strong><br />

Wie<strong>der</strong>gabe von <strong>der</strong> einen Seite mit Licht bestrahlt, so bilden sich nach dem<br />

Huygensschen Prinzip hinter je<strong>der</strong> <strong>der</strong> lichtdurchlässigen Öffnungen<br />

kreisförmige Elementarwellen (siehe auch Abbildung 6).<br />

Bei <strong>der</strong> Wie<strong>der</strong>gabe entstehen also im Takt mit den auf das Hologramm<br />

treffenden Strahlen hinter je<strong>der</strong> lichtdurchlässigen Stelle Elementarwellen.<br />

Diese Elementarwellen interferieren nun miteinan<strong>der</strong>. Dabei gibt es mehrere<br />

Möglichkeiten: Es können sich Elementarwellen überlagern, die alle <strong>aus</strong> <strong>der</strong><br />

selben Welle entstanden sind (0. Maximum). Dies ist allerdings uninteressant,<br />

da die entstehende Wellenfront genau parallel zum Hologramm wegläuft, also<br />

genau eine Rekonstruktion des Belichtungsstrahls darstellt.<br />

12


Interessanter ist es, wenn Elementarwellen interferieren, die von Öffnung zu<br />

Öffnung jeweils um einen Takt des Belichtungsstrahls später entstanden sind<br />

(1. Maximum). Die entstehenden Wellen sind in Abbildung 6 dargestellt.<br />

Natürlich gibt es auch noch weitere Maxima (2. Maximum, 3. Maximum, usw.),<br />

diese spielen in <strong>der</strong> Holographie jedoch nur eine geringe Rolle.<br />

Abbildung 6: Wie<strong>der</strong>gabe eines Musters mit geringem Spaltabstand: Die Strahlen gehen<br />

mit einem großen Winkel ab (<strong>aus</strong> [HE95])<br />

In Abbildung 7 ist nun dieselbe Situation gezeigt, allerdings ist hier <strong>der</strong><br />

Spaltabstand größer als in Abbildung 6. Man sieht: Die rekonstruierte Welle<br />

verlässt das Hologramm mit einem kleineren Winkel. Man könnte also<br />

vermuten: Je größer <strong>der</strong> Spaltabstand ist, desto kleiner ist <strong>der</strong> Winkel <strong>der</strong><br />

rekonstruierten Welle, die das Hologramm verlässt.<br />

13


Abbildung 7: Wie<strong>der</strong>gabe eines Musters mit großem Spaltabstand: Die Strahlen gehen<br />

mit einem kleinen Winkel ab (<strong>aus</strong> [HE95])<br />

Wir erinnern uns nun an Kapitel 2.2.1: Dort wurde über den Zusammenhang<br />

zwischen Objektwelle und Spaltabstand bei <strong>der</strong> Aufnahme gesagt, dass <strong>der</strong><br />

Spaltabstand größer wird, je kleiner <strong>der</strong> Winkel <strong>der</strong> Objektwelle ist. Bei <strong>der</strong><br />

Wie<strong>der</strong>gabe sorgt ein großer Spaltabstand auch wie<strong>der</strong>um für einen kleinen<br />

Winkel.<br />

Dies macht pl<strong>aus</strong>ibel, dass ein Hologramm die Objektwelle <strong>der</strong> Aufnahme bei<br />

<strong>der</strong> Wie<strong>der</strong>gabe komplett rekonstruiert.<br />

14


2.2.3 Pseudoskopische Bil<strong>der</strong><br />

In Kapitel 2.2.2 wurde gesagt, dass die ursprüngliche Objektwelle durch den<br />

Zusammenschluss von Elementarwellen zustande kommt, <strong>der</strong>en Radien von<br />

Spalt zu Spalt größer werden (von links nach rechts gesehen).<br />

Genaugenommen schließen sich aber auch die Wellen zusammen, <strong>der</strong>en<br />

Radien von links nach rechts kleiner werden (siehe Abbildung 8). Dieser<br />

Zusammenschluss ergibt ein „umgestülptes“ Bild, ähnlich einem Gipsabdruck.<br />

Dieses Bild nennt man „pseudoskopisch“.<br />

In <strong>der</strong> Praxis versucht man, durch geeignete Positionierung des Objektes zu<br />

erreichen, dass die rekonstruierten Objektwellen das Hologramm mit einem<br />

möglichst großen Winkel verlassen, damit sich das „richtige“ und das<br />

pseudoskopische Bild bei <strong>der</strong> Betrachtung nicht überlagern.<br />

Abbildung 8: Entstehung des pseudoskopischen Bilds (<strong>aus</strong> [HE95])<br />

15


2.3 Mathematische Erklärung<br />

In Kapitel 2.2 wurde die grundlegende Funktionsweise von Hologrammen<br />

anhand von Beispielen erläutert. In diesem Kapitel soll nun gezeigt werden,<br />

dass die aufgestellten Vermutungen nicht nur in unseren Beispielen bestätigt<br />

wurden, son<strong>der</strong>n auch mathematisch bewiesen werden können.<br />

Die Gesetzmäßigkeiten werden an dem Hologramm eines Punktes gezeigt, ein<br />

komplexeres Objekt stellt man sich als Zusammensetzung mehrere Punkte vor,<br />

ähnlich einem Rasterbild in einer Zeitung. Das Hologramm eines Punktes wird<br />

auch „Fresnelsche Zonenplatte“ genannt (Abbildung 9).<br />

Abbildung 9: Fresnelsche Zonenplatte<br />

2.3.1 Aufnahme eines Hologramms<br />

Wie in Kapitel 2.2.1 beschrieben, interferieren bei <strong>der</strong> Aufnahme Objekt- und<br />

Referenzwelle miteinan<strong>der</strong> und bilden so ein Muster von lichtdurchlässigen und<br />

lichtundurchlässigen Linien. Wichtig ist <strong>der</strong> Abstand zwischen den<br />

lichtdurchlässigen Linien. Dieser wird im folgenden mit dem Buchstaben b<br />

16


ezeichnet. Des weiteren wird <strong>der</strong> Winkel, den Referenz- und Objektstrahl an<br />

<strong>der</strong> Fotoplatte einschließen, α genannt.<br />

Es wird zunächst davon <strong>aus</strong>gegangen, dass <strong>der</strong> aufzunehmende Punkt sehr<br />

weit entfernt ist, die Strahlen verlaufen also (näherungsweise) parallel.<br />

Aus Abbildung 10 kann man nun folgenden Zusammenhang zwischen dem<br />

Winkel α und b ablesen:<br />

sin( α ) =<br />

λ<br />

b<br />

Stellt man diese Formel nach b um, so erhält man:<br />

λ<br />

b =<br />

sin(α )<br />

Da die Wellenlänge immer konstant ist, ist <strong>der</strong> Spaltabstand b also umgekehrt<br />

proportional zum Sinus von α.<br />

Abbildung 10: Winkelzusammenhänge bei <strong>der</strong> Aufnahme eines Hologramms mit weit<br />

entferntem Objekt (parallele Wellenfronten) (nach [FO00])<br />

17


In Abbildung 11 ist nun dargestellt, was passiert, wenn ein nahes Objekt<br />

aufgenommen wird, die Objektwellenfronten also kreisförmig auf den Film<br />

treffen. Auch hier gilt <strong>der</strong> oben erkannte Zusammenhang, nur ist α für jeden<br />

Punkt des Filmes an<strong>der</strong>s. Deshalb ergibt sich kein regelmäßiges Muster mit<br />

immer demselben b wie in Abbildung 10, son<strong>der</strong>n ein ständig an<strong>der</strong>er<br />

Spaltabstand. Dadurch wird auch die Tiefe des Objektes gespeichert.<br />

Abbildung 11: Aufnahme bei kreisförmigen Objektwellen (nahes Objekt) (nach [FO00])<br />

18


2.3.2 Rekonstruktion eines Hologramms<br />

Ein belichtetes Hologramm besteht <strong>aus</strong> lichtdurchlässigen und<br />

lichtundurchlässigen Linien, es besteht also im Grunde <strong>aus</strong> sehr vielen<br />

Doppelspalten (optisches Gitter). Hinter jedem dieser Doppelspalte mit dem<br />

jeweiligen Spaltabstand b interferieren nun die entstehenden Elementarwellen<br />

und bilden ein Interferenzmuster mit mehreren Maxima. In <strong>der</strong> Holographie hat<br />

nur das 1. Maximum eine Bedeutung.<br />

Der Winkel β des Strahles, <strong>der</strong> ein Maximum darstellt, steht nun in folgen<strong>der</strong><br />

Beziehung zum Spaltabstand b, wobei k eine natürliche Zahl größer o<strong>der</strong> gleich<br />

0 ist und die Ordnung des Maximums beschreibt, in unserem Fall also 1:<br />

k * λ<br />

sin( β ) = (Formel für Maxima bei <strong>der</strong> Interferenz am Doppelspalt)<br />

b<br />

Um einen bestimmten Winkel β bei <strong>der</strong> Rekonstruktion zu erreichen, muss <strong>der</strong><br />

Spaltabstand b also die folgende Länge besitzen:<br />

λ<br />

b =<br />

sin( β )<br />

Diese Gleichung setzt man nun mit <strong>der</strong> in Kapitel 2.3.1 für die Aufnahme<br />

aufgestellten Formel gleich:<br />

λ λ<br />

=<br />

sin( α)<br />

sin( β )<br />

Die Wellenlänge sowie <strong>der</strong> Sinus kürzen sich weg, es bleibt: α = β<br />

Der Winkel bei <strong>der</strong> Aufnahme entspricht also dem Winkel bei <strong>der</strong><br />

Rekonstruktion, wenn <strong>der</strong> Spaltabstand b <strong>der</strong>selbe ist.<br />

Das Pseudoskopische Bild kann damit erklärt werden, dass sich bei <strong>der</strong><br />

Rekonstruktion das 1. Maximum nicht nur mit dem Winkel β, son<strong>der</strong>n auch noch<br />

mit -β bildet.<br />

19


3 <strong>Computerholographie</strong><br />

Nachdem im vorigen Kapitel erklärt wurde, wie Hologramme aufgenommen<br />

werden und wie sie funktionieren, stellt sich nun vielleicht die Frage, wofür<br />

Hologramme überhaupt gut sind. Als „normaler“ Mensch kommt man meist nur<br />

in Ausstellungen mit Hologrammen in Kontakt. In <strong>der</strong> Industrie wird Holographie<br />

hauptsächlich für zwei Zwecke genutzt. Der erste ist die sogenannte<br />

Interferometrie, ein Verfahren, um Materialverformungen im Nanometer-Bereich<br />

messen zu können. Der zweite Verwendungszweck sind holographischoptische<br />

Elemente (HOEs). Dahinter steht folgende Idee: Im vorherigen Kapitel<br />

wurde das Hologramm eines Punktes behandelt. Dieses Hologramm ist im<br />

Grunde eine Sammellinse, <strong>der</strong>en Brennpunkt genau an <strong>der</strong> Stelle des Punktes<br />

liegt. Mithilfe <strong>der</strong> Holographie kann man nun Linsen erzeugen, die mit normalen<br />

optischen Mittel nur sehr schwer o<strong>der</strong> gar nicht herzustellen wären, z.B. eine<br />

Linse mit zehn verschiedenen Brennpunkten an völlig unterschiedlichen Stellen<br />

mit jeweils unterschiedlichen Brennweiten. Solche HOEs sind z.B. in<br />

Strichcode-Lesern in Supermärkten o<strong>der</strong> auch in CD-Spielern und Brennern.<br />

Für die Herstellung von HOEs, die in <strong>der</strong> Industrie und Forschung eine sehr<br />

wichtige Rolle spielen, wird heutzutage hauptsächlich <strong>Computerholographie</strong><br />

eingesetzt.<br />

Im Folgenden werden die in <strong>Computerholographie</strong>-Programmen verwendeten<br />

Algorithmen erklärt, und beschrieben, wie man <strong>aus</strong> dem berechneten<br />

Interferenzmuster ein „richtiges“ und funktionierendes Hologramm herstellen<br />

kann. Diese Arbeit beschreibt nur sogenannte Fresnelhologramme, da diese die<br />

zugrundeliegende Physik am klarsten zeigen und zudem auch von den<br />

optischen Eigenschaften her sehr gut sind. An<strong>der</strong>e Hologrammtypen wie z.B.<br />

Detourphasen-Hologramme o<strong>der</strong> Fourierhologramme sind lediglich<br />

Abwandelungen des Prinzips <strong>der</strong> Fresnelhologramme, um Probleme wie<br />

schlechte Bildschirme o.ä. zu umgehen.<br />

20


3.1 Grundlagen <strong>der</strong> <strong>Computerholographie</strong><br />

Um ein computergeneriertes Hologramm (engl. „Computer Generated<br />

Hologram“: CGH) herzustellen, muss als erstes ein Objekt vorhanden sein,<br />

welches holographiert werden soll. Man rastert hierzu das Objekt in einzelne<br />

Punkte auf, ähnlich den Bil<strong>der</strong>n in Zeitungen. Der Computer berechnet dann,<br />

was sich auf <strong>der</strong> Filmplatte für ein Interferenzmuster bilden würde, wenn <strong>der</strong><br />

Referenzstrahl und alle Objektstrahlen von den zugehörigen Objektpunkten<br />

miteinan<strong>der</strong> interferieren. Das Interferenzmuster wird nun auf dem Bildschirm<br />

angezeigt und mithilfe einer Kamera auf einen Film übertragen. 1 Hierbei wird<br />

das Muster auch gleichzeitig photographisch verkleinert, damit es feiner ist und<br />

somit eine stärkere Beugung ermöglicht. Der Film kann dann genau wie ein<br />

herkömmliches Transmissionshologramm betrachtet werden.<br />

3.2 Probleme bei <strong>der</strong> <strong>Computerholographie</strong><br />

Das Problem bei <strong>der</strong> <strong>Computerholographie</strong> liegt nicht bei <strong>der</strong> Berechnung <strong>der</strong><br />

Hologramme; heutige Computer sind so leistungsfähig, dass selbst komplexe<br />

Objekte innerhalb weniger Minuten berechnet werden können.<br />

Das Problem ist, dass das Interferenzmuster bei Hologrammen sehr fein ist. Bei<br />

<strong>der</strong> normalen Holographie werden deshalb hochauflösende Spezialfilme mit bis<br />

zu 6.000 Linienpaaren pro Millimeter (Lp/mm) verwendet. Bei <strong>der</strong><br />

<strong>Computerholographie</strong> ist allerdings nicht das Filmmaterial das Problem,<br />

son<strong>der</strong>n die geringe Auflösung des Bildschirms. Es sollte also vor dem<br />

photographieren des Hologramms vom Bildschirm die größte Auflösung<br />

eingestellt werden. 2 Bei <strong>der</strong> <strong>Computerholographie</strong> ist es deshalb auch nicht<br />

nötigt, teuren Spezialfilm zu verwenden, normales Filmmaterial wie <strong>der</strong> Kodak<br />

Technical Pan (300 bis 400 Lp/mm) reichen völlig <strong>aus</strong>.<br />

Ein weiteres Problem ist folgendes: Um die Berechnung zu vereinfachen und zu<br />

beschleunigen, wählt man den Referenzstrahl so, dass er auf dem kompletten<br />

Hologramm die Phase Null hat, also genau senkrecht auf den Film trifft.<br />

Befindet sich nun auch das Objekt genau in <strong>der</strong> Mitte des Hologramms, wird es<br />

bei <strong>der</strong> Rekonstruktion vom Beleuchtungsstrahl verdeckt. Bei <strong>der</strong> normalen<br />

Holographie lässt man deshalb den Referenzstrahl immer seitlich auf das<br />

1 In <strong>der</strong> Industrie werden Computerhologramme mithilfe von Laser-Plottern hergestellt.<br />

2 Alle Hologramme, die im Rahmen dieser Arbeit angefertigt wurden, wurden mit einer<br />

Auflösung von 1280 * 1024 Pixel berechnet und angezeigt.<br />

21


Hologramm fallen. Eine solche Anordnung nennt man „Off Axis“. Um trotzdem<br />

nicht auf den rechentechnischen Vorteil eines senkrechten Referenzstrahles<br />

verzichten zu müssen, sollte sich das Objekt am Rand des Hologramms<br />

befinden, aber nicht zu weit, da die Beugungskraft des Hologramms aufgrund<br />

<strong>der</strong> geringen Bildschirmauflösung nicht sehr hoch ist.<br />

3.3 Berechnung von Computerhologrammen<br />

Im Rahmen dieser Facharbeit wurde ein Computerprogramm zur Berechnung<br />

von Computerhologrammen entwickelt. Die folgenden Ausführungen beziehen<br />

sich auf den in diesem Programm implementierten Algorithmus. Auf eine<br />

Optimierung des Berechnungsalgorithmuses wurde absichtlich verzichtet, um<br />

die zugrundeliegenden Prinzipien nicht zu verschleiern. Das Programm stellt<br />

also hinsichtlich <strong>der</strong> Berechnungsgeschwindigkeit sicherlich nicht das „non plus<br />

ultra“ dar.<br />

Um zu verstehen, wie das Programm funktioniert, muss man sich klarmachen,<br />

wie Hologramme in <strong>der</strong> Wirklichkeit entstehen: Auf jeden Punkt des<br />

Hologramms trifft bei <strong>der</strong> Aufnahme <strong>der</strong> Referenzstrahl, sowie von jedem <strong>der</strong><br />

Objektpunkte ein Strahl. Diese Strahlen treffen alle mit einer unterschiedlichen<br />

Phase auf den Schirm, die von <strong>der</strong> Wellenlänge und <strong>der</strong> Entfernung des<br />

Punktes zu <strong>der</strong> entsprechenden Stelle auf dem Hologramm abhängt. Die Phase<br />

wird dargestellt als Winkel im Bogenmaß. Ein Wellenberg hat also die Phase<br />

π 3<br />

, ein Wellental π und die Phase Null ist π o<strong>der</strong> 0. Die Auslenkung bei<br />

2<br />

2<br />

gegebener Phase kann also folgen<strong>der</strong>maßen berechnet werden: Auslenkung =<br />

MaxAmplitude * sin(Phase). Die Auslenkung ist nun ein Wert zwischen<br />

MaxAmplitude und -MaxAmplitude.<br />

Interferenz bedeutet nichts weiter, als dass alle Auslenkungen addiert werden.<br />

Würden beispielsweise zwei Strahlen auf einen Punkt treffen, <strong>der</strong> einen mit<br />

einem Wellenberg und <strong>der</strong> an<strong>der</strong>e mit einem Tal, so würde sich für die<br />

Gesamt<strong>aus</strong>lenkung an dieser Stelle des Films ergeben: Gesamt<strong>aus</strong>lenkung =<br />

MaxAmplitude + (-MaxAmplitude) = 0.<br />

Um die Phase zu berechnen, wird noch die Entfernung des Punktes zur<br />

entsprechenden Stelle auf dem Hologramm benötigt. Hierzu kann folgende, <strong>aus</strong><br />

<strong>der</strong> Geometrie bekannte Formel verwendet werden, wobei X, Y und Z die<br />

22


Koordinaten des Objektpunktes, von dem <strong>der</strong> Strahl <strong>aus</strong>geht, sind, und x und y<br />

die Koordinaten auf dem Film:<br />

Entfernung = − + − +<br />

2<br />

2 2<br />

( x X ) ( y Y)<br />

Z<br />

Die Phase wird nun berechnet mit:<br />

Entfernung<br />

Phase =<br />

* 2 * π<br />

Lambda<br />

Das Programm berechnet nun für jede Stelle des Hologramms die Summe <strong>der</strong><br />

Auslenkungen aller Strahlen, die auf diese Stelle fallen. Der Referenzstrahl<br />

braucht nicht beachtet zu werden, da er auf dem ganzen Hologramm eine<br />

Phase von 0 hat, d.h. senkrecht auf das Hologramm fällt.<br />

Die Berechnung ist in <strong>der</strong> Datei InterferenzMuster.java implementiert (siehe<br />

Anhang E: Quelltext des CGH-Programms).<br />

Dieses berechnete Muster ist allerdings noch nicht auf einem Bildschirm<br />

darstellbar, da dieser nur Werte zwischen 0 (schwarz) und 255 (weiß) anzeigen<br />

kann. Die summierten Auslenkungen müssen also noch auf Werte zwischen 0<br />

und 255 umgerechnet werden, was in <strong>der</strong> Datei Photo.java erfolgt (siehe<br />

Anhang E: Quelltext des CGH-Programms).<br />

3.3.1 Zufallsphasen<br />

In <strong>der</strong> Realität besitzen alle Objekte eine gewisse Oberflächenrauhigkeit.<br />

Dadurch ist die Entfernung zweier Objektpunkte zur Filmplatte selbst bei<br />

Punkten mit <strong>der</strong>selben Tiefe minimal verschieden. Diese Rauhigkeit sorgt für<br />

einen größeren Kontrast bei dem berechneten Hologramm.<br />

Um die Oberflächenrauhigkeit zu simulieren, berechnet das Programm für jeden<br />

Punkt einen zufälligen Phasenwert und addiert diesen zu jedem von dem Punkt<br />

<strong>aus</strong>gehenden Strahl dazu.<br />

23


3.3.2 Kontrasterhöhung<br />

Die berechneten Hologramme weisen häufig einen sehr geringen mittleren<br />

Kontrast auf, sie wirken sehr flau. Das kommt daher, dass die meisten<br />

Helligkeitswerte im Mittelbereich liegen und sich nur wenig voneinan<strong>der</strong><br />

unterscheiden. Die extremen Helligkeitswerte nehmen nur sehr wenige Pixel<br />

an.<br />

Deshalb wurde in das Programm die Möglichkeit eingebaut, den Kontrast <strong>der</strong><br />

Hologramme zu verstärken. Hierzu wird <strong>der</strong> Abstand aller Helligkeitswerte vom<br />

Durchschnittswert um 1,5 vergrößert. Bei Pixeln, die vorher schon bereits sehr<br />

extreme Helligkeitswerte besaßen, kann <strong>der</strong> Helligkeitswert eventuell nicht um<br />

diesen Abstand vergrößert werden, hier findet eine Über- bzw. Unterbelichtung<br />

statt. Dieses „Abschneiden“ von extremen Helligkeitswerten wird auch als<br />

„Clipping“ bezeichnet.<br />

Fresnelhologramme sind relativ unempfindlich gegen Clipping, selbst wenn bis<br />

zu 20 % <strong>der</strong> Pixel betroffen sind 1 .<br />

3.4 Fotoarbeiten<br />

Nachdem das Interferenzmuster nun berechnet worden ist, muss es auf einen<br />

Film übertragen werden, <strong>der</strong> dann holographisch wirken kann.<br />

Hierzu wird das Muster auf dem Bildschirm angezeigt und dann mit einer<br />

Kamera ein Foto von dem Bildschirm gemacht. Der Bildschirm sollte beim<br />

Photographieren auf eine Größe von ungefähr 1 cm Breite und 0,75 cm Höhe<br />

verkleinert werden, damit die Beugungskraft des Musters möglichst groß ist. Bei<br />

einem 50 mm-Objektiv stellt man dazu die Kamera ungefähr 1,5 Meter vom<br />

Bildschirm entfernt auf einem Stativ auf.<br />

Außerdem sollte die Belichtungszeit so lange wie möglich sein, um eine große<br />

Schärfe zu erzielen sowie um Probleme durch Bildschirmflimmern zu umgehen.<br />

Als ideale Belichtungszeit bei kleinster Blende (16) wurde 1 Sekunde ermittelt.<br />

Die Entwicklung des Filmes erfolgt gen<strong>aus</strong>o wie die Entwicklung eines<br />

„normalen“ Photos und muss, zumindest bis zum Fixieren, bei kompletter<br />

Dunkelheit erfolgen.<br />

1 Bei den Hologrammen, die im Rahmen dieser Facharbeit angefertigt wurden, wurde <strong>der</strong><br />

Kontrast so erhöht, dass das Clipping etwa bei 20 % lag.<br />

24


Zum Entwickeln wurde Dokumol (Verdünnung 1+9, Entwicklungszeit ca. 5<br />

Minuten) und zum Fixieren Superfix (Verdünnung 1+7, Fixierzeit ca. 5 Minuten),<br />

beides von <strong>der</strong> Firma Tetenal, verwendet. Danach wird das Hologramm<br />

mindestens 3 Minuten in Wasser geschwenkt, um alle Chemikalien<br />

r<strong>aus</strong>zuwaschen. Am Ende hält man das Negativ noch einige Zeit in eine<br />

Spülmittellösung. Diese Lösung wirkt wie ein Netzmittel, d.h. sie verhin<strong>der</strong>t die<br />

Entstehung von Kalkflecken beim Trocknen.<br />

Das Hologramm kann nun mit <strong>der</strong> in Kapitel 2.1 beschriebenen Methode<br />

betrachtet werden. Setzt man als Laser einen Laserpointer ein, ist es meistens<br />

nicht nötig, den Strahl mit einer Linse aufzuweiten, da <strong>der</strong> Strahl eines<br />

Laserpointers bereits einen sehr großen Durchmesser aufweist.<br />

Abbildung 12: Das "Fotolabor"<br />

25


Anhang A: Beigefügte Materialien<br />

• Drei Hologramme (Filmnegative)<br />

• Eine CD mit folgendem Inhalt:<br />

• Alle verwendeten digitalen Quellen<br />

• Diese Arbeit im Acrobat PDF-Format<br />

• Der Quelltext <strong>der</strong> entwickelten Software<br />

• Das lauffähige Programm (Windows-Version)<br />

• Eine Readme-Datei, in <strong>der</strong> die Installation und <strong>der</strong> Start <strong>der</strong> Software<br />

erläutert werden<br />

• Die Simulationsdateien sowie berechneten Interferenzmuster <strong>der</strong><br />

beigefügten Hologramme<br />

26


Anhang B: Bedienung des CGH-Programms<br />

Abbildung 13: Oberfläche des Programms<br />

Objekteigenschaften<br />

Hologramm-Editor<br />

Hier werden die Eigenschaften des im Hologramm-<br />

Editor <strong>aus</strong>gewählten Punkts angezeigt. Wenn im<br />

Editor kein Punkt selektiert ist, werden die<br />

Eigenschaften <strong>der</strong> Simulation angezeigt.<br />

Der Editor zeigt das zu holographierende<br />

Punktmuster an.<br />

Der <strong>aus</strong>gewählte Punkt ist rot, alle an<strong>der</strong>en schwarz.<br />

Der selektierte Punkt kann mit gedrückter M<strong>aus</strong>taste<br />

verschoben werden.<br />

Die grauen Striche zeigen die Begrenzung <strong>der</strong><br />

Hologrammfläche, es ist allerdings, wie in <strong>der</strong> Grafik,<br />

auch möglich, Buchstaben außerhalb <strong>der</strong><br />

Hologrammfläche zu platzieren.<br />

27


Toolbar<br />

Neu<br />

Öffnen<br />

Speichern<br />

Punkt Hinzufügen<br />

Text Hinzufügen<br />

Punkt Löschen<br />

Berechnen<br />

Info<br />

Beenden<br />

Setzt die Simulation auf<br />

Standardwerte zurück, das<br />

Programm ist nun in dem<br />

selben Zustand wie nach<br />

einem Neustart.<br />

Öffnet eine gespeicherte<br />

Simulation o<strong>der</strong> ein bereits<br />

berechnetes<br />

Interferenzmuster.<br />

Speichert die Simulation in<br />

eine Datei.<br />

Schaltet den Editor in den<br />

Punkt-Eingabe-Modus: An <strong>der</strong><br />

Stelle des nächsten<br />

M<strong>aus</strong>klicks wird ein neuer<br />

Punkt erzeugt.<br />

Öffnet einen Dialog, in dem<br />

man einen Text angeben<br />

kann. An <strong>der</strong> Stelle des<br />

nächsten M<strong>aus</strong>klicks wird <strong>der</strong><br />

Text als Punktmuster<br />

eingefügt.<br />

Löscht den im Editor<br />

<strong>aus</strong>gewählten Punkt.<br />

Berechnet das<br />

Interferenzmuster und zeigt es<br />

in einem neuen Fenster an.<br />

Zeigt eine kurze<br />

Programminfo.<br />

Beendet das Programm. Eine<br />

evtl. noch laufende<br />

Berechnung wird<br />

abgebrochen.<br />

28


Anhang C: Literaturverzeichnis<br />

Bücher<br />

[HE86]: Heiß, Peter: Holographie-Fibel, Hologramme verstehen und<br />

selbermachen; Hückelhoven 1986<br />

[HE95]: Heiß, Peter: Die neue Holographie-Fibel; Hückelhoven 1986, 1995<br />

[ME95]: Meyers Lexikonred. (Hrsg): Schülerduden Physik; Mannheim, Leipzig,<br />

Wien, Zürich, 1995<br />

[WE00]: Weltbild: Der Brockh<strong>aus</strong>; Mannheim 2000<br />

Internet-Quellen<br />

[ME97]: Meyer, Michael: Facharbeit Holographie, Einführung in die<br />

Holographie, Beschreibung <strong>der</strong> Anfertigung von einfachen<br />

Hologrammen; www.holography.de; Stand: Dezember 2004<br />

[FO00]: Fouquier, Alex: Facharbeit Holographie; ap.physik.uni-<br />

konstanz.de/Literatur/mirror/Holographie/Facharbeit_Alex-<br />

Fouquier/Holographie_Facharbeit_Alex-Fouquier.pdf; Stand:<br />

Dezember 2004<br />

[FF97]: Fritz, Haimo/Ferri, Lucilla Croce, Fraunhofer Institut für Graphische<br />

Datenverarbeitung: Erzeugung von computergenerierten Hologrammen<br />

mit Hilfe eines hochauflösenden Laserbelichters;<br />

www.inigraphics.net/ini-ccc/projects/holographie/interfer.pdf, Stand:<br />

Januar 2005<br />

Verwendete Software<br />

Zum Entwickeln des <strong>Computerholographie</strong>programms wurde das Java 2 SDK<br />

Version 1.4.1 verwendet, Copyright 2002 Sun Microsystems, Inc.<br />

Das Programm verwendet für die Graphische Oberfläche das Standard Widget<br />

Toolkit, Copyright (c) 2000, 2004 IBM Corporation and others.<br />

29


Anhang D: Selbstständigkeitserklärung<br />

Ich versichere, dass ich diese Facharbeit selbständig angefertigt habe. Neben<br />

den angegebenen Quellen und Materialien habe ich keine weiteren Hilfsmittel<br />

benutzt.<br />

<strong>Biedenkopf</strong>-<strong>Wallau</strong>, den 19.02.2005<br />

Michael <strong>Partheil</strong><br />

30


Anhang E: Quelltext des CGH-Programms<br />

AuswahlListener.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import java.util.*;<br />

/** Interface für Objekte, die informiert werden wollen, wenn sich die<br />

Auswahl im HologrammEditor geän<strong>der</strong>t hat. Diese Objekte müssen mit<br />

addAuswahlListener dem HologrammEditor hinzugefügt werden */<br />

public interface AuswahlListener extends EventListener<br />

{<br />

/** Diese Methode wird aufgerufen, wenn sich die Auswahl geän<strong>der</strong>t<br />

hat. sen<strong>der</strong> ist <strong>der</strong> HologrammEditor und neueAuswahl die neue<br />

Auswahl, entwe<strong>der</strong> ein Objekt vom Typ ObjektPunkt o<strong>der</strong> vom<br />

Typ Simulation */<br />

public void <strong>aus</strong>wahlGeaen<strong>der</strong>t(Object sen<strong>der</strong>, Object neueAuswahl);<br />

}<br />

BerechnungsFortschrittListener.java<br />

import java.util.*;<br />

/** Implementierende Klassen können sich mit addFortschrittListener<br />

bei einem InterferenzMuster registrieren und werden über den<br />

Fortgang <strong>der</strong> Berechnung informiert */<br />

public interface BerechnungsFortschrittListener extends EventListener<br />

{<br />

public static final int BERECHNUNG_BEENDET = -1;<br />

/** Diese Methode wird aufgerufen, wenn sich <strong>der</strong> Fortschritt <strong>der</strong><br />

Berechnung des InterferenzMusters geän<strong>der</strong>t hat. aktuelleSpalte ist<br />

die Spalte, die gerade berechnet wird o<strong>der</strong> BERECHNUNG_BEENDET,<br />

wenn<br />

die Berechnung fertig ist und gesamtSpalten ist die Zahl <strong>der</strong><br />

Spalten,<br />

die insgesamt zu berechnen sind.<br />

Achtung: Diese Methode läuft in dem Thread, in dem auch die<br />

Berechnung<br />

läuft, also nicht zwangsläufig im GUI-Thread! */<br />

public void berechnungsFortschritt(int aktuelleSpalte, int<br />

gesamtSpalten);<br />

}<br />

CGHMain.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.graphics.*;<br />

import org.eclipse.swt.widgets.*;<br />

/** Hauptklasse, startet das Programm */<br />

public class CGHMain<br />

31


{<br />

/** Das Display dieser Anwendung. Sollte nicht geschrieben werden */<br />

public static Display display;<br />

/** Main-Methode, öffnet eine MainShell und ruft waitForClose() auf.<br />

Evtl. wird Sleak geöffnet, wenn die Eigenschaft cgh.useSleak<br />

gesetzt ist */<br />

public static void main(String[] args)<br />

{<br />

if (System.getProperty("cgh.useSleak") != null)<br />

{<br />

DeviceData data = new DeviceData();<br />

data.tracking = true;<br />

display = new Display(data);<br />

Sleak sleak = new Sleak();<br />

sleak.open();<br />

}<br />

else<br />

display = new Display();<br />

}<br />

}<br />

MainShell mainShell = new MainShell();<br />

if (args.length >= 1)<br />

{<br />

mainShell.open(args[0]);<br />

}<br />

mainShell.waitForClose();<br />

display.dispose();<br />

DynamicHelpListener.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.events.*;<br />

import org.eclipse.swt.widgets.*;<br />

/** Diese Klasse setzt einen Hilfe-Text im HelpViewer, wenn die M<strong>aus</strong><br />

über ein Control bewegt wird, bei dem dieser DynamicHelpListener<br />

mit addMouseTrackListener registriert wurde */<br />

public class DynamicHelpListener extends MouseTrackAdapter<br />

{<br />

private String hilfeText;<br />

private HelpViewer helpViewer;<br />

public static void addToAll(Composite addTo, HelpViewer viewer,<br />

String hilfeText)<br />

{<br />

DynamicHelpListener l = new DynamicHelpListener(viewer,<br />

hilfeText);<br />

Control[] children = addTo.getChildren();<br />

addTo.addMouseTrackListener(l);<br />

for (int i=0; i


}<br />

soll und hilfeText ist <strong>der</strong> Text */<br />

public DynamicHelpListener(HelpViewer viewer, String hilfeText)<br />

{<br />

super();<br />

if (viewer == null || hilfeText == null)<br />

throw new IllegalArgumentException("parameter ist null");<br />

this.hilfeText = hilfeText;<br />

helpViewer = viewer;<br />

}<br />

/** Vorgabe <strong>aus</strong> MouseTrackListener */<br />

public void mouseEnter(MouseEvent evt)<br />

{<br />

helpViewer.setHilfe(hilfeText);<br />

}<br />

/** Vorgabe <strong>aus</strong> MouseTrackListener */<br />

public void mouseExit(MouseEvent evt)<br />

{<br />

helpViewer.setHilfe("");<br />

}<br />

EigenschaftenEditorControl.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.custom.*;<br />

import org.eclipse.swt.widgets.*;<br />

/** GUI-Klasse, die einen Editor für die Auswahl im HologrammEditor<br />

bereitstellt.<br />

Je nach Auswahl wird entwe<strong>der</strong> ein SimulationEditor o<strong>der</strong> ein<br />

ObjektPunktEditor-Objekt<br />

verwendet */<br />

public class EigenschaftenEditorControl extends Composite implements<br />

AuswahlListener<br />

{<br />

private StackLayout layout;<br />

private ObjektEditor nullEditor;<br />

/** Konstruktor. editorFuer ist <strong>der</strong> HologrammEditor, dessen Auswahl<br />

editiert werden<br />

soll. Dieser EigenschaftEditorControl registriert sich automatisch<br />

bei dem HologrammEditor<br />

als AuswahlListener. helpViewer ist <strong>der</strong> HelpViewer <strong>der</strong> Anwendung<br />

*/<br />

public EigenschaftenEditorControl(Composite parent, HologrammEditor<br />

editorFuer, HelpViewer helpViewer)<br />

{<br />

super(parent, SWT.NONE);<br />

layout = new StackLayout();<br />

setLayout(layout);<br />

new SimulationEditor(this, editorFuer, helpViewer);<br />

new ObjektPunktEditor(this, editorFuer, helpViewer);<br />

nullEditor = new NullEditor(this);<br />

33


}<br />

layout.topControl = nullEditor;<br />

setObjekt(null);<br />

editorFuer.addAuswahlListener(this);<br />

/** Vorgabe <strong>aus</strong> AuswahlListener */<br />

public void <strong>aus</strong>wahlGeaen<strong>der</strong>t(Object sen<strong>der</strong>, Object <strong>aus</strong>wahl)<br />

{<br />

setObjekt(<strong>aus</strong>wahl);<br />

}<br />

/** Speichert die Eigenschaften des vorher bearbeiteten Objektes und<br />

startet die Editierung eines neuen Objektes. obj sollte entwe<strong>der</strong><br />

vom<br />

Typ Simulatoin o<strong>der</strong> ObjektPunkt sein o<strong>der</strong> eine an<strong>der</strong>e Klasse, für<br />

die<br />

ein ObjektEditor vorhanden ist. */<br />

public void setObjekt(Object obj)<br />

{<br />

ObjektEditor alterEditor = (ObjektEditor)layout.topControl;<br />

alterEditor.speichereEigenschaften();<br />

}<br />

Control[] editoren = getChildren();<br />

for (int i=0; i


import org.eclipse.swt.widgets.*;<br />

/** Dialog, <strong>der</strong> ein InterferenzMuster anzeigt und Möglichkeiten zum<br />

Verän<strong>der</strong>n<br />

des Kontrastes und zum Speichern anbietet */<br />

public class ErgebnisDialog extends Dialog<br />

{<br />

private Photo photo;<br />

private Image img;<br />

private Image imgIcon;<br />

private ScrolledComposite canvasScroller;<br />

private Canvas canvasAnzeige;<br />

private Button btnVollbild;<br />

private Button btnSpeichern;<br />

private Button btnKontrastErhoehen;<br />

private Button btnSchliessen;<br />

public ErgebnisDialog(Shell parent, Photo photo)<br />

{<br />

super(parent, SWT.NONE);<br />

this.photo = photo;<br />

}<br />

public void open()<br />

{<br />

final Display display = CGHMain.display;<br />

img = new Image(display, photo.getImageData());<br />

final Shell shell = new Shell(getParent(), SWT.DIALOG_TRIM |<br />

SWT.APPLICATION_MODAL | SWT.RESIZE);<br />

shell.setText("Hologramm");<br />

imgIcon = new Image(display,<br />

getClass().getResourceAsStream("ergebnis.ico"));<br />

shell.setImage(imgIcon);<br />

canvasScroller = new ScrolledComposite(shell, SWT.BORDER |<br />

SWT.H_SCROLL | SWT.V_SCROLL);<br />

canvasScroller.setAlwaysShowScrollBars(true);<br />

canvasAnzeige = new Canvas(canvasScroller, SWT.NO_REDRAW_RESIZE);<br />

canvasAnzeige.addPaintListener(new PaintListener()<br />

{<br />

public void paintControl(PaintEvent evt)<br />

{<br />

evt.gc.drawImage(img, 0, 0);<br />

}<br />

} );<br />

canvasAnzeige.setLocation(0, 0);<br />

canvasAnzeige.setSize(img.getBounds().width,<br />

img.getBounds().height);<br />

canvasScroller.setContent(canvasAnzeige);<br />

Composite buttonBar = new Composite(shell, SWT.NONE);<br />

RowLayout layout = new RowLayout(SWT.HORIZONTAL);<br />

layout.spacing = 5;<br />

layout.marginWidth = 5;<br />

layout.marginHeight = 5;<br />

buttonBar.setLayout(layout);<br />

btnVollbild = new Button(buttonBar, SWT.PUSH);<br />

35


tnVollbild.setText("&Vollbildanzeige");<br />

btnSpeichern = new Button(buttonBar, SWT.PUSH);<br />

btnSpeichern.setText("&Speichern");<br />

btnKontrastErhoehen = new Button(buttonBar, SWT.PUSH);<br />

btnKontrastErhoehen.setText("&Kontrast erhöhen");<br />

btnSchliessen = new Button(buttonBar, SWT.PUSH);<br />

btnSchliessen.setText("S&chließen");<br />

shell.setLayout(new FormLayout());<br />

FormData fd;<br />

fd = new FormData(canvasAnzeige.getSize().x,<br />

canvasAnzeige.getSize().y);<br />

fd.left = new FormAttachment(0);<br />

fd.top = new FormAttachment(0);<br />

fd.right = new FormAttachment(100);<br />

fd.bottom = new FormAttachment(buttonBar);<br />

canvasScroller.setLayoutData(fd);<br />

fd = new FormData();<br />

fd.left = new FormAttachment(0);<br />

fd.right = new FormAttachment(100);<br />

fd.bottom = new FormAttachment(100);<br />

buttonBar.setLayoutData(fd);<br />

btnVollbild.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

if (! display.getBounds().equals(img.getBounds()))<br />

{<br />

if (SWTUtils.messageBox(shell, SWT.ICON_QUESTION |<br />

SWT.YES | SWT.NO, "Vollbildanzeige",<br />

"Die Abmessungen des Hologramms (in Pixeln) und die<br />

ihres Bildschirmes sind verschieden.\n"+<br />

"Es empfiehlt sich, ein Hologramm, das vom Bildschirm<br />

abphotografiert werden soll, in <strong>der</strong>\n"+<br />

"selben Auflösung berechnen zu lassen wie die des<br />

Bildschirmes, also z. B. 1024*768 Pixel.\n"+<br />

"Trotzdem anzeigen?") == SWT.NO)<br />

return;<br />

}<br />

VollBildDialog vbd = new VollBildDialog(shell, img);<br />

vbd.open();<br />

}<br />

} );<br />

btnSpeichern.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

FileDialog fd = new FileDialog(shell, SWT.SAVE);<br />

fd.setFilterExtensions(new String[]{ "*.bmp", "*.gif",<br />

"*.*" });<br />

fd.setFilterNames(new String[]{ "Windows Bitmap (*.bmp)",<br />

"Compuserve GIF-Bild (*.gif)", "Alle Dateien" });<br />

fd.setText("Hologramm als Bild speichern");<br />

String filename = null;<br />

if ((filename = fd.open()) != null)<br />

36


}<br />

} );<br />

{<br />

}<br />

int format = SWT.IMAGE_BMP;<br />

if (filename.toUpperCase().endsWith(".GIF"))<br />

format = SWT.IMAGE_GIF;<br />

ImageLoa<strong>der</strong> il = new ImageLoa<strong>der</strong>();<br />

il.data = new ImageData[]{ photo.getImageData() };<br />

il.save(filename, format);<br />

btnKontrastErhoehen.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

final float FAKTOR = 1.5f;<br />

int clipping = 0;<br />

ImageData id = photo.getImageData();<br />

double durchschnitt = photo.getDurchschnittsPixel();<br />

for (int x=0; x


}<br />

}<br />

{<br />

if (! display.readAndDispatch())<br />

display.sleep();<br />

}<br />

img.dispose();<br />

imgIcon.dispose();<br />

HelpViewer.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.events.*;<br />

import org.eclipse.swt.layout.*;<br />

import org.eclipse.swt.graphics.*;<br />

import org.eclipse.swt.widgets.*;<br />

/** Control, um einen Hilfetext anzuzeigen */<br />

public class HelpViewer extends Composite<br />

{<br />

private Display display = CGHMain.display;<br />

private Image imgHelp;<br />

private Label lblImage;<br />

private Label lblUeberschrift;<br />

private Label lblHilfe;<br />

public HelpViewer(Composite parent)<br />

{<br />

super(parent, SWT.BORDER);<br />

}<br />

macheGui();<br />

setHilfe(null);<br />

/** Zeigt einen Hilfetext. Ist <strong>der</strong> hilfeText null o<strong>der</strong> "" wird eine<br />

Erklärung<br />

über den HelpViewer selber angezeigt */<br />

public void setHilfe(String hilfeText)<br />

{<br />

if ((hilfeText != null) && (! hilfeText.equals("")))<br />

lblHilfe.setText(hilfeText);<br />

else<br />

lblHilfe.setText("Hier werden nähere Informationen zu dem<br />

Element des Programmes angezeigt, "+<br />

"das sich gerade unter dem M<strong>aus</strong>zeiger befindet.");<br />

}<br />

public String getHilfe()<br />

{<br />

return lblHilfe.getText();<br />

}<br />

private void macheGui()<br />

{<br />

imgHelp = new Image(display,<br />

getClass().getResourceAsStream("help.gif"));<br />

38


lblImage = new Label(this, SWT.NONE);<br />

imgHelp.setBackground(lblImage.getBackground());<br />

lblImage.setImage(imgHelp);<br />

lblUeberschrift = new Label(this, SWT.NONE);<br />

lblUeberschrift.setText("Dynamische Hilfe");<br />

final Font f = new Font(display,<br />

lblUeberschrift.getFont().getFontData()[0].getName(),<br />

lblUeberschrift.getFont().getFontData()[0].getHeight(),<br />

SWT.BOLD);<br />

lblUeberschrift.setFont(f);<br />

lblUeberschrift.addDisposeListener(new DisposeListener()<br />

{<br />

public void widgetDisposed(DisposeEvent evt)<br />

{<br />

f.dispose();<br />

}<br />

} );<br />

}<br />

}<br />

lblHilfe = new Label(this, SWT.WRAP);<br />

lblHilfe.setText("");<br />

GridLayout layout = new GridLayout(2, false);<br />

setLayout(layout);<br />

GridData gd;<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.CENTER;<br />

lblImage.setLayoutData(gd);<br />

gd = new GridData();<br />

lblUeberschrift.setLayoutData(gd);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.verticalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

gd.grabExcessVerticalSpace = true;<br />

gd.horizontalSpan = 2;<br />

lblHilfe.setLayoutData(gd);<br />

HologrammEditor.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.events.*;<br />

import org.eclipse.swt.graphics.*;<br />

import org.eclipse.swt.widgets.*;<br />

import java.util.*;<br />

/** Visuelle Editierung eines Punkmusters (zu holographierendes<br />

Objekt) */<br />

public class HologrammEditor extends Canvas<br />

{<br />

private Simulation simulation;<br />

39


private Object <strong>aus</strong>wahl;<br />

private java.util.List <strong>aus</strong>wahlListeners;<br />

private java.util.List posListeners;<br />

private Display display;<br />

private Point dpcm;<br />

private static final int MODE_SELECT = 1;<br />

private static final int MODE_ADD = 2;<br />

private static final int MODE_MOVE = 3;<br />

private int mode = MODE_SELECT;<br />

private TextPseudoObjekt textObjekt = null;<br />

private static final int BUCHSTABEN_ABSTAND = 3;<br />

private final Point[][] BUCHSTABEN_MUSTER = {<br />

{ new Point(3, 0), new Point(2, 2), new Point(1, 4), new Point(0,<br />

6), new Point(4, 2), new Point(5, 4), new Point(6, 6), new Point(3, 4)<br />

}, // A<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(2, 3), new Point(2, 6), new Point(4,<br />

1), new Point(4, 5) }, // B<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(4, 0), new Point(2, 6), new Point(4, 6)<br />

}, // C<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(3, 2), new Point(3, 4), new Point(2, 6)<br />

}, // D<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(4, 0), new Point(2, 3), new Point(4,<br />

3), new Point(2, 6), new Point(4, 6) }, // E<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(4, 0), new Point(2, 3), new Point(4, 3)<br />

}, // F<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(4, 0), new Point(2, 4), new Point(4,<br />

4), new Point(2, 6), new Point(4, 6) }, // G<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 3), new Point(4, 0), new Point(4, 2), new Point(4,<br />

4), new Point(4, 6) }, // H<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6) }, // I<br />

{ new Point(2, 0), new Point(2, 2), new Point(2, 4), new Point(1,<br />

6), new Point(0, 4) }, // J<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 3), new Point(4, 2), new Point(5, 0), new Point(4,<br />

4), new Point(5, 6) }, // K<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 6), new Point(4, 6) }, // L<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 2), new Point(3, 4), new Point(4, 2), new Point(6,<br />

0), new Point(6, 2), new Point(6, 4), new Point(6, 6) }, // M<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 2), new Point(3, 4), new Point(5, 0), new Point(5,<br />

2), new Point(5, 4), new Point(5, 6) }, // N<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(2, 6), new Point(4, 0), new Point(4,<br />

2), new Point(4, 4), new Point(4, 6) }, // O<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(4, 0), new Point(4, 2), new Point(4,<br />

4), new Point(2, 4) }, // P<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

40


6), new Point(2, 0), new Point(2, 6), new Point(4, 0), new Point(4,<br />

2), new Point(4, 4), new Point(4, 6), new Point(5, 7) }, // Q<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 0), new Point(3, 2), new Point(2, 4), new Point(3, 6)<br />

}, // R<br />

{ new Point(0, 0), new Point(2, 0), new Point(4, 0), new Point(0,<br />

2), new Point(2, 3), new Point(4, 4), new Point(0, 6), new Point(2,<br />

6), new Point(4, 6) }, // S<br />

{ new Point(0, 0), new Point(2, 0), new Point(4, 0), new Point(2,<br />

2), new Point(2, 4), new Point(2, 6) }, // T<br />

{ new Point(0, 0), new Point(0, 2), new Point(0, 4), new Point(0,<br />

6), new Point(2, 6), new Point(4, 0), new Point(4, 2), new Point(4,<br />

4), new Point(4, 6) }, // U<br />

{ new Point(0, 0), new Point(1, 2), new Point(2, 4), new Point(3,<br />

6), new Point(4, 4), new Point(5, 2), new Point(6, 0) }, // V<br />

{ new Point(0, 0), new Point(1, 2), new Point(2, 4), new Point(3,<br />

6), new Point(5, 4), new Point(7, 6), new Point(8, 4), new Point(9,<br />

2), new Point(10, 0) }, // W<br />

{ new Point(0, 0), new Point(1, 2), new Point(1, 4), new Point(0,<br />

6), new Point(4, 0), new Point(3, 2), new Point(3, 4), new Point(4, 6)<br />

}, // X<br />

{ new Point(0, 0), new Point(1, 2), new Point(2, 4), new Point(2,<br />

6), new Point(3, 2), new Point(4, 0) }, // Y<br />

{ new Point(0, 0), new Point(2, 0), new Point(4, 0), new Point(3,<br />

2), new Point(2, 3), new Point(1, 4), new Point(0, 6), new Point(2,<br />

6), new Point(4, 6) } // Z<br />

};<br />

public HologrammEditor(Composite parent, Simulation simulation,<br />

HelpViewer helpViewer)<br />

{<br />

super(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND);<br />

this.simulation = simulation;<br />

<strong>aus</strong>wahl = simulation;<br />

display = CGHMain.display;<br />

Point dpi = display.getDPI();<br />

dpcm = new Point(Math.round(dpi.x / 2.54f), Math.round(dpi.y /<br />

2.54f));<br />

<strong>aus</strong>wahlListeners = new ArrayList();<br />

posListeners = new ArrayList();<br />

addMouseTrackListener(new DynamicHelpListener(helpViewer, "Im<br />

Hologramm-Editor können Sie die einzelnen "+<br />

"Objektpunkte <strong>der</strong> Simulation bearbeiten. Der <strong>aus</strong>gewälte Punkt<br />

ist rot, ist keiner <strong>aus</strong>gewählt, ist "+<br />

"die Auswahl die Simulation. Punkte können mit gedrückter<br />

M<strong>aus</strong>taste verschoben werden."));<br />

addPaintListener(new PaintListener()<br />

{<br />

public void paintControl(PaintEvent evt)<br />

{<br />

HologrammEditor.this.paintControl(evt);<br />

}<br />

});<br />

addMouseListener(new MouseAdapter()<br />

{<br />

public void mouseDown(MouseEvent evt)<br />

{<br />

HologrammEditor.this.mouseDown(evt);<br />

41


}<br />

}<br />

public void mouseUp(MouseEvent evt)<br />

{<br />

HologrammEditor.this.mouseUp(evt);<br />

}<br />

} );<br />

addMouseMoveListener(new MouseMoveListener()<br />

{<br />

public void mouseMove(MouseEvent evt)<br />

{<br />

HologrammEditor.this.mouseMove(evt);<br />

}<br />

} );<br />

/** Schaltet den Editor in den Punkteingabe-Modus.<br />

An <strong>der</strong> Stelle wo als nächstes hingeklickt wird, wird ein PUnkt<br />

eingefügt */<br />

public void startePunktEingabe()<br />

{<br />

mode = MODE_ADD;<br />

textObjekt = null;<br />

}<br />

/** Schaltet den Editor in den Texteingabe-Modus. An <strong>der</strong> Stelle, wo<br />

als nächstes hingeklickt wird, wird <strong>der</strong> Text textObjekt eingefügt<br />

*/<br />

public void starteTextEingabe(TextPseudoObjekt textObjekt)<br />

{<br />

if (textObjekt == null)<br />

throw new IllegalArgumentException("textObjekt ist null");<br />

}<br />

textObjekt.text = textObjekt.text.toUpperCase();<br />

mode = MODE_ADD;<br />

this.textObjekt = textObjekt;<br />

private int buchstabenBreite(char c)<br />

{<br />

c = Character.toUpperCase(c);<br />

if (c == ' ')<br />

return 5;<br />

if (c >= 'A' && c


{<br />

}<br />

<strong>aus</strong>wahlListeners.remove(al);<br />

private void fireAuswahlEvent()<br />

{<br />

for (Iterator it=<strong>aus</strong>wahlListeners.iterator(); it.hasNext(); )<br />

{<br />

AuswahlListener al = (AuswahlListener)it.next();<br />

al.<strong>aus</strong>wahlGeaen<strong>der</strong>t(this, <strong>aus</strong>wahl);<br />

}<br />

}<br />

public void addObjektPunktPosListener(ObjektPunktPosListener l)<br />

{<br />

posListeners.add(l);<br />

}<br />

public void removeObjektPunktPosListener(ObjektPunktPosListener l)<br />

{<br />

posListeners.remove(l);<br />

}<br />

private void fireObjektPunktPosEvent(ObjektPunkt punkt)<br />

{<br />

for (Iterator it=posListeners.iterator(); it.hasNext(); )<br />

{<br />

ObjektPunktPosListener l = (ObjektPunktPosListener)it.next();<br />

l.punktPosGeaen<strong>der</strong>t(this, punkt);<br />

}<br />

}<br />

public void setSimulation(Simulation s)<br />

{<br />

if (simulation == null)<br />

throw new IllegalArgumentException("simulation ist null");<br />

simulation = s;<br />

setAuswahl(simulation);<br />

redraw();<br />

}<br />

public Simulation getSimulation()<br />

{<br />

return simulation;<br />

}<br />

public Object getAuswahl()<br />

{<br />

return <strong>aus</strong>wahl;<br />

}<br />

public void setAuswahl(Object obj)<br />

{<br />

<strong>aus</strong>wahl = obj;<br />

redraw();<br />

fireAuswahlEvent();<br />

}<br />

private void mouseMove(MouseEvent evt)<br />

{<br />

final Point klick = new Point(Math.round(evt.x /<br />

simulation.anzeigeSkalierung),<br />

Math.round(evt.y / simulation.anzeigeSkalierung));<br />

43


selben wie in paintControl:<br />

final int width = Math.round(dpcm.x * simulation.musterBreite);<br />

final int height = Math.round(dpcm.y * simulation.musterHoehe);<br />

final Point rand = new Point(Math.round(dpcm.x*0.25f),<br />

Math.round(dpcm.y*0.25f)); // 1/4 cm Rand<br />

final int imgWidth = width + 2*rand.x;<br />

final int imgHeight = height + 2*rand.y;<br />

}<br />

// ist <strong>der</strong> Klick in <strong>der</strong> Zeichenfläche?<br />

if (klick.x >= imgWidth || klick.y >= imgHeight)<br />

return;<br />

if (mode == MODE_MOVE && <strong>aus</strong>wahl instanceof ObjektPunkt)<br />

{<br />

ObjektPunkt punkt = (ObjektPunkt)<strong>aus</strong>wahl;<br />

punkt.x = (float)(klick.x-rand.x+1) / (float)dpcm.x;<br />

punkt.y = (float)(klick.y-rand.y+1) / (float)dpcm.y;<br />

redraw();<br />

}<br />

private void mouseUp(MouseEvent evt)<br />

{<br />

final Point klick = new Point(Math.round(evt.x /<br />

simulation.anzeigeSkalierung),<br />

Math.round(evt.y / simulation.anzeigeSkalierung));<br />

// selben wie in paintControl:<br />

final int width = Math.round(dpcm.x * simulation.musterBreite);<br />

final int height = Math.round(dpcm.y * simulation.musterHoehe);<br />

final Point rand = new Point(Math.round(dpcm.x*0.25f),<br />

Math.round(dpcm.y*0.25f)); // 1/4 cm Rand<br />

final int imgWidth = width + 2*rand.x;<br />

final int imgHeight = height + 2*rand.y;<br />

// ist <strong>der</strong> Klick in <strong>der</strong> Zeichenfläche?<br />

if (klick.x >= imgWidth || klick.y >= imgHeight)<br />

return;<br />

if (mode == MODE_ADD)<br />

{<br />

if (textObjekt == null)<br />

{<br />

ObjektPunkt punkt = new ObjektPunkt((float)(klick.x-rand.x+1)<br />

/ (float)dpcm.x,<br />

(float)(klick.y-rand.y+1) / (float)dpcm.y, 30.0f);<br />

simulation.punktHinzufuegen(punkt);<br />

setAuswahl(punkt);<br />

redraw();<br />

mode = MODE_SELECT;<br />

}<br />

else<br />

{<br />

String text = textObjekt.text;<br />

float z = textObjekt.startZ;<br />

for (int i=0; i


Point[] muster = BUCHSTABEN_MUSTER[buchstabe-'A'];<br />

for (int j=0; j= imgWidth || klick.y >= imgHeight)<br />

return;<br />

if (mode == MODE_SELECT)<br />

{<br />

// ist da ein Punkt?<br />

for (Iterator it=simulation.objektIterator(); it.hasNext(); )<br />

{<br />

ObjektPunkt punkt = (ObjektPunkt)it.next();<br />

Point pos = new Point(rand.x + Math.round(punkt.x * dpcm.x)-<br />

1, rand.y + Math.round(punkt.y * dpcm.y)-1);<br />

if (klick.equals(pos))<br />

{<br />

// einen punkt gefunden, prüfen, ob <strong>der</strong> bereits gewählt<br />

war, wenn ja, in move-mode schalten,<br />

// ansonnsten den punkt <strong>aus</strong>wählen<br />

if (<strong>aus</strong>wahl == punkt)<br />

{<br />

mode = MODE_MOVE;<br />

45


kein<br />

}<br />

}<br />

}<br />

}<br />

else<br />

setAuswahl(punkt);<br />

return;<br />

}<br />

// wenn wir hier sind, ist <strong>der</strong> Klick zwar auf <strong>der</strong> Fläche, aber<br />

// PUnkt ist dort, also simulation <strong>aus</strong>wählen:<br />

setAuswahl(simulation);<br />

private void paintControl(PaintEvent evt)<br />

{<br />

//setLocation(0, 0);<br />

setSize(computeSize(SWT.DEFAULT, SWT.DEFAULT));<br />

final int width = Math.round(dpcm.x * simulation.musterBreite);<br />

final int height = Math.round(dpcm.y * simulation.musterHoehe);<br />

final Point rand = new Point(Math.round(dpcm.x*0.25f),<br />

Math.round(dpcm.y*0.25f)); // 1/4 cm Rand<br />

final int imgWidth = width + 2*rand.x;<br />

final int imgHeight = height + 2*rand.y;<br />

final Color white = display.getSystemColor(SWT.COLOR_WHITE);<br />

final Color black = display.getSystemColor(SWT.COLOR_BLACK);<br />

final Color red = display.getSystemColor(SWT.COLOR_RED);<br />

final Color gray = display.getSystemColor(SWT.COLOR_GRAY);<br />

Image img = new Image(display, imgWidth, imgHeight);<br />

GC gc = new GC(img);<br />

// hintergrund zeichnen<br />

gc.setBackground(white);<br />

gc.fillRectangle(0, 0, imgWidth, imgHeight);<br />

// "Koordinatensystem" zeichnen<br />

gc.setForeground(gray);<br />

gc.drawLine(0, rand.x-1, imgWidth-1, rand.x-1);<br />

gc.drawLine(0, rand.x+height-1, imgWidth-1, rand.x+height-1);<br />

gc.drawLine(rand.x-1, 0, rand.x-1, imgHeight-1);<br />

gc.drawLine(rand.x+width-1, 0, rand.x+width-1, imgHeight-1);<br />

// Pfeilchen zeichnen<br />

gc.drawLine(imgWidth-1, rand.x-1, imgWidth-3, rand.x-3);<br />

gc.drawLine(imgWidth-1, rand.x-1, imgWidth-3, rand.x+1);<br />

gc.drawLine(imgWidth-3, rand.x-3, imgWidth-3, rand.x+1);<br />

gc.drawLine(rand.x-1, imgHeight-1, rand.x-3, imgHeight-3);<br />

gc.drawLine(rand.x-1, imgHeight-1, rand.x+1, imgHeight-3);<br />

gc.drawLine(rand.x-3, imgHeight-3, rand.x+1, imgHeight-3);<br />

// ObjektPunkte zeichnen<br />

for (Iterator it=simulation.objektIterator(); it.hasNext(); )<br />

{<br />

ObjektPunkt punkt = (ObjektPunkt)it.next();<br />

if (<strong>aus</strong>wahl == punkt)<br />

gc.setForeground(red);<br />

else<br />

gc.setForeground(black);<br />

int x = rand.x + Math.round(punkt.x * dpcm.x) - 1;<br />

46


}<br />

int y = rand.y + Math.round(punkt.y * dpcm.y) - 1;<br />

gc.drawPoint(x, y);<br />

gc.dispose();<br />

evt.gc.drawImage(img, 0, 0, imgWidth, imgHeight,<br />

0, 0, imgWidth*simulation.anzeigeSkalierung,<br />

imgHeight*simulation.anzeigeSkalierung);<br />

img.dispose();<br />

}<br />

public Point computeSize(int wHint, int hHint, boolean changed)<br />

{<br />

// <strong>aus</strong> paintControl etc:<br />

final int width = Math.round(dpcm.x * simulation.musterBreite);<br />

final int height = Math.round(dpcm.y * simulation.musterHoehe);<br />

final Point rand = new Point(Math.round(dpcm.x*0.25f),<br />

Math.round(dpcm.y*0.25f)); // 1/4 cm Rand<br />

final int imgWidth = width + 2*rand.x;<br />

final int imgHeight = height + 2*rand.y;<br />

final Point clientSize = new<br />

Point(imgWidth*simulation.anzeigeSkalierung,<br />

imgHeight*simulation.anzeigeSkalierung);<br />

final Rectangle trim = computeTrim(0, 0, clientSize.x,<br />

clientSize.y);<br />

return new Point(trim.width, trim.height);<br />

}<br />

}<br />

InterferenzMuster.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import java.util.*;<br />

/** InterferenzMuster stellt das Muster dar, welches durch<br />

das Interferieren von Lichtwellen, die von mehreren ObjektPunkten<br />

<strong>aus</strong>gehen, entsteht. */<br />

public class InterferenzMuster<br />

{<br />

private double[][] muster;<br />

private ObjektPunkt[] objekt;<br />

private float breiteVomPixel, hoeheVomPixel;<br />

private double lambda;<br />

private double minAmplitude;<br />

private double maxAmplitude;<br />

private boolean zufallsPhasen;<br />

private List listeners;<br />

/** Neues InterferenzMuster erstellen.<br />

objekt ist das zu holographierende Objekt; zufallsPhasen bestimmt,<br />

ob die<br />

in den ObjektPunkten gespeicherten Zufallsphasen mit berechnet<br />

werden sollen;<br />

lambda ist die Wellenlänge des Lasers; breiteInPixel und<br />

hoeheInPixel geben<br />

(indirekt in Kombination mit musterBreite u. musterHoehe) die<br />

47


Auflösung an<br />

und musterBreite und musterHoehe sind die Abmessungen des Musters<br />

in cm. */<br />

public InterferenzMuster(ObjektPunkt[] objekt, boolean<br />

zufallsPhasen, double lambda,<br />

int breiteInPixel, int hoeheInPixel, float musterBreite, float<br />

musterHoehe)<br />

{<br />

if (objekt == null)<br />

throw new IllegalArgumentException("objekt ist null");<br />

if (lambda


l)<br />

{<br />

}<br />

listeners.remove(l);<br />

private void fireFortschrittEvent(int aktuelleSpalte)<br />

{<br />

for (Iterator it=listeners.iterator(); it.hasNext();)<br />

{<br />

BerechnungsFortschrittListener l =<br />

(BerechnungsFortschrittListener)it.next();<br />

l.berechnungsFortschritt(aktuelleSpalte, muster.length);<br />

}<br />

}<br />

/** Gibt ein Array mit den summierten Elongationen <strong>der</strong> Wellen<br />

(Interferenzmuster)<br />

zurück. Die Werte können auch negativ sein */<br />

public double[][] getMuster()<br />

{<br />

return muster;<br />

}<br />

public ObjektPunkt[] getObjekt()<br />

{<br />

return objekt;<br />

}<br />

public double getLambda()<br />

{<br />

return lambda;<br />

}<br />

public double getMusterBreite()<br />

{<br />

return muster.length * breiteVomPixel;<br />

}<br />

public double getMusterHoehe()<br />

{<br />

return muster[0].length * hoeheVomPixel;<br />

}<br />

/** Die kleinste auftretende Amplitude, wird für die umrechnung in<br />

in Hell-Dunkel Werte benötigt */<br />

public double getMinAmplitude()<br />

{<br />

return minAmplitude;<br />

}<br />

/** Minimale Auslenkung, siehe getMinAmplitude() */<br />

public double getMaxAmplitude()<br />

{<br />

return maxAmplitude;<br />

}<br />

private void berechneMuster()<br />

{<br />

for (int x=0; x


Photofläche (in Pixeln).<br />

// Der Pixel, den wir hier an dieser Stelle gerade behandeln<br />

ist P(x|y)<br />

muster[x][y] = 0.0;<br />

// Jetzt außerdem noch jeden Punkt des Objektes abklappern:<br />

for (int obj=0; obj


MainShell.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.custom.*;<br />

import org.eclipse.swt.events.*;<br />

import org.eclipse.swt.graphics.*;<br />

import org.eclipse.swt.layout.*;<br />

import org.eclipse.swt.widgets.*;<br />

import java.io.*;<br />

import java.text.*;<br />

import java.util.*;<br />

/** Hauptfenster <strong>der</strong> Anwendung */<br />

public class MainShell<br />

{<br />

private Shell shell;<br />

private Display display;<br />

private ToolBar toolBar;<br />

private ToolItem tiNeu;<br />

private ToolItem tiOeffnen;<br />

private ToolItem tiSpeichern;<br />

private ToolItem tiPunktHinzufuegen;<br />

private ToolItem tiTextHinzufuegen;<br />

private ToolItem tiPunktLoeschen;<br />

private ToolItem tiBerechnen;<br />

private ToolItem tiInfo;<br />

private ToolItem tiBeenden;<br />

private Image imgNeu;<br />

private Image imgOeffnen;<br />

private Image imgSpeichern;<br />

private Image imgPunktHinzufuegen;<br />

private Image imgTextHinzufuegen;<br />

private Image imgPunktLoeschen;<br />

private Image imgBerechnen;<br />

private Image imgBerechnenDisabled;<br />

private Image imgInfo;<br />

private Image imgBeenden;<br />

private Image imgIcon;<br />

private HologrammEditor holoEditor;<br />

private EigenschaftenEditorControl eigenschaftenEditor;<br />

private HelpViewer helpViewer;<br />

private ScrolledComposite holoEditorScroller;<br />

public MainShell()<br />

{<br />

display = CGHMain.display;<br />

shell = new Shell(display);<br />

shell.setText("CGH");<br />

imgIcon = new Image(display,<br />

getClass().getResourceAsStream("cgh.ico"));<br />

shell.setImage(imgIcon);<br />

51


}<br />

macheGui();<br />

registriereListener();<br />

shell.pack();<br />

SWTUtils.centerShell(shell, null);<br />

shell.open();<br />

/** Öffnet eine Datei, ist die Endung .bmp o<strong>der</strong> .gif wird sie im<br />

ErgebnisDialog geöffnet,<br />

sonst im HologrammEditor */<br />

public void open(String filename)<br />

{<br />

if (filename == null || filename.equals(""))<br />

throw new IllegalArgumentException("filename ist ungültig");<br />

if (filename.toUpperCase().endsWith(".BMP") ||<br />

filename.toUpperCase().endsWith(".GIF"))<br />

{<br />

final ImageData data = new ImageData(filename);<br />

double durchschnittTemp = 0.0;<br />

for (int x=0; x


{<br />

SWTUtils.messageBox(shell, SWT.ICON_ERROR | SWT.OK, "Öffnen",<br />

"Fehler beim Öffnen: " + e);<br />

}<br />

if (sim != null)<br />

{<br />

holoEditor.setSimulation(sim);<br />

holoEditor.setAuswahl(sim);<br />

holoEditor.redraw();<br />

}<br />

}<br />

private void registriereListener()<br />

{<br />

tiNeu.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

holoEditor.setSimulation(new Simulation());<br />

holoEditor.setAuswahl(holoEditor.getSimulation());<br />

holoEditor.redraw();<br />

}<br />

} );<br />

tiOeffnen.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

FileDialog fd = new FileDialog(shell, SWT.OPEN);<br />

fd.setFilterExtensions(new String[]{ "*.cgh", "*.bmp",<br />

"*.gif", "*.*" });<br />

fd.setFilterNames(new String[]{ "Hologramm-Datei (*.cgh)",<br />

"Windows Bitmap (*.bmp)",<br />

"Compuserve GIF-Bild (*.gif)", "Alle Dateien" });<br />

String filename = null;<br />

Simulation sim = null;<br />

if ((filename = fd.open()) != null)<br />

{<br />

open(filename);<br />

}<br />

}<br />

} );<br />

tiSpeichern.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

FileDialog fd = new FileDialog(shell, SWT.SAVE);<br />

fd.setFilterExtensions(new String[]{ "*.cgh", "*.*" });<br />

fd.setFilterNames(new String[]{ "Hologramm-Datei (*.cgh)",<br />

"Alle Dateien" });<br />

String filename = null;<br />

if ((filename = fd.open()) != null)<br />

{<br />

eigenschaftenEditor.speichereEigenschaften();<br />

try<br />

{<br />

ObjectOutputStream oos = new ObjectOutputStream(new<br />

FileOutputStream(filename));<br />

oos.writeObject(holoEditor.getSimulation());<br />

oos.close();<br />

}<br />

catch (IOException e)<br />

{<br />

SWTUtils.messageBox(shell, SWT.ICON_ERROR | SWT.OK,<br />

53


"Speichern", "Fehler beim Speichern: " + e);<br />

}<br />

}<br />

}<br />

} );<br />

tiPunktHinzufuegen.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

holoEditor.startePunktEingabe();<br />

}<br />

} );<br />

tiTextHinzufuegen.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

TextInputDialog tid = new TextInputDialog(shell);<br />

TextPseudoObjekt text = null;<br />

if ((text = tid.open()) != null)<br />

{<br />

holoEditor.starteTextEingabe(text);<br />

}<br />

}<br />

} );<br />

tiPunktLoeschen.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

if (holoEditor.getAuswahl() instanceof ObjektPunkt)<br />

{<br />

holoEditor.getSimulation().punktLoeschen((ObjektPunkt)holoEditor.get<br />

Auswahl());<br />

holoEditor.setAuswahl(holoEditor.getSimulation());<br />

holoEditor.redraw();<br />

}<br />

else<br />

display.beep();<br />

}<br />

} );<br />

tiBerechnen.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

tiBerechnen.setEnabled(false);<br />

final Cursor waitCursor = new Cursor(display,<br />

SWT.CURSOR_WAIT);<br />

shell.setCursor(waitCursor);<br />

eigenschaftenEditor.speichereEigenschaften();<br />

Simulation sim = holoEditor.getSimulation();<br />

final InterferenzMuster muster = new<br />

InterferenzMuster(sim.getObjekt(), sim.zufallsPhasen, sim.lambda,<br />

sim.breiteInPixel, sim.hoeheInPixel, sim.musterBreite,<br />

sim.musterHoehe);<br />

muster.addFortschrittListener(new<br />

BerechnungsFortschrittListener()<br />

{<br />

public void berechnungsFortschritt(int aktuelleSpalte,<br />

int gesamtSpalten)<br />

{<br />

if (aktuelleSpalte ==<br />

BerechnungsFortschrittListener.BERECHNUNG_BEENDET)<br />

{<br />

54


display.asyncExec(new Runnable()<br />

{<br />

public void run()<br />

{<br />

Photo photo = new Photo(muster);<br />

ErgebnisDialog ed = new<br />

ErgebnisDialog(shell, photo);<br />

ed.open();<br />

tiBerechnen.setEnabled(true);<br />

shell.setCursor(null);<br />

waitCursor.dispose();<br />

shell.setText("CGH");<br />

}<br />

} );<br />

}<br />

else<br />

{<br />

final String titel = "CGH - " +<br />

NumberFormat.getPercentInstance().format((float)aktuelleSpalte /<br />

(float)gesamtSpalten);<br />

if (! display.isDisposed())<br />

{<br />

display.asyncExec(new Runnable()<br />

{<br />

public void run()<br />

{<br />

if (! shell.isDisposed())<br />

shell.setText(titel);<br />

}<br />

} );<br />

}<br />

}<br />

}<br />

} );<br />

muster.start();<br />

}<br />

} );<br />

tiInfo.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

SWTUtils.messageBox(shell, SWT.ICON_INFORMATION | SWT.OK,<br />

"Über das Programm...",<br />

"CGH - Copyright © 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de\n\n"+<br />

"CGH ist ein Programm, welches Hologramme von<br />

Punktmustern\n"+<br />

"am Computer berechnet und anzeigt. Diese können dann<br />

vom Bildschirm\n"+<br />

"abphotografiert werden o<strong>der</strong> mit Hilfe von Plottern in<br />

ein \"echtes\" Hologramm\n"+<br />

"umgewandelt werden.\n"+<br />

"Das Programm wurde im Rahmen einer Facharbeit im Fach<br />

Physik am Städtischen\n"+<br />

"Gymnasium Bad Laasphe entwickelt.");<br />

}<br />

} );<br />

tiBeenden.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

shell.close();<br />

}<br />

55


}<br />

} );<br />

private void macheGui()<br />

{<br />

helpViewer = new HelpViewer(shell);<br />

macheToolBar();<br />

holoEditorScroller = new ScrolledComposite(shell, SWT.H_SCROLL |<br />

SWT.V_SCROLL | SWT.BORDER);<br />

holoEditorScroller.setAlwaysShowScrollBars(true);<br />

holoEditor = new HologrammEditor(holoEditorScroller, new<br />

Simulation(), helpViewer);<br />

holoEditorScroller.setContent(holoEditor);<br />

eigenschaftenEditor = new EigenschaftenEditorControl(shell,<br />

holoEditor, helpViewer);<br />

holoEditor.setAuswahl(holoEditor.getSimulation());<br />

holoEditor.setLocation(0, 0);<br />

holoEditor.setSize(holoEditor.computeSize(SWT.DEFAULT,<br />

SWT.DEFAULT));<br />

}<br />

shell.setLayout(new FormLayout());<br />

FormData fd;<br />

fd = new FormData();<br />

fd.left = new FormAttachment(0);<br />

fd.right = new FormAttachment(100);<br />

fd.top = new FormAttachment(0);<br />

toolBar.setLayoutData(fd);<br />

fd = new FormData();<br />

fd.left = new FormAttachment(0);<br />

fd.top = new FormAttachment(toolBar);<br />

fd.bottom = new FormAttachment(100);<br />

fd.right = new FormAttachment(eigenschaftenEditor);<br />

holoEditorScroller.setLayoutData(fd);<br />

fd = new FormData();<br />

fd.top = new FormAttachment(toolBar);<br />

fd.right = new FormAttachment(100);<br />

//fd.bottom = new FormAttachment(100);<br />

eigenschaftenEditor.setLayoutData(fd);<br />

fd = new FormData();<br />

fd.top = new FormAttachment(eigenschaftenEditor, 5);<br />

fd.left = new FormAttachment(holoEditorScroller, 5);<br />

fd.right = new FormAttachment(100, -5);<br />

fd.bottom = new FormAttachment(100, -5);<br />

helpViewer.setLayoutData(fd);<br />

private void macheToolBar()<br />

{<br />

final String HELP_PROPERTY = "dynamicHelpText";<br />

imgNeu = new Image(display,<br />

getClass().getResourceAsStream("filenew.gif"));<br />

imgOeffnen = new Image(display,<br />

getClass().getResourceAsStream("open.gif"));<br />

imgSpeichern = new Image(display,<br />

getClass().getResourceAsStream("save_edit.gif"));<br />

56


imgPunktHinzufuegen = new Image(display,<br />

getClass().getResourceAsStream("add.gif"));<br />

imgTextHinzufuegen = new Image(display,<br />

getClass().getResourceAsStream("buchstaben.gif"));<br />

imgPunktLoeschen = new Image(display,<br />

getClass().getResourceAsStream("delete_edit.gif"));<br />

imgBerechnen = new Image(display,<br />

getClass().getResourceAsStream("berechnen.gif"));<br />

imgBerechnenDisabled = new Image(display,<br />

getClass().getResourceAsStream("berechnen_disabled.gif"));<br />

imgInfo = new Image(display,<br />

getClass().getResourceAsStream("info.gif"));<br />

imgBeenden = new Image(display,<br />

getClass().getResourceAsStream("exit.gif"));<br />

toolBar = new ToolBar(shell, SWT.HORIZONTAL | SWT.FLAT |<br />

SWT.WRAP);<br />

tiNeu = new ToolItem(toolBar, SWT.PUSH);<br />

tiNeu.setText("&Neu");<br />

tiNeu.setImage(imgNeu);<br />

tiNeu.setData(HELP_PROPERTY, "Setzt die Simulation auf<br />

Standardwerte zurück. "+<br />

"Achtung: Die aktuelle Simulation ist dann \"verloren\"!");<br />

tiOeffnen = new ToolItem(toolBar, SWT.PUSH);<br />

tiOeffnen.setText("Ö&ffnen");<br />

tiOeffnen.setImage(imgOeffnen);<br />

tiOeffnen.setData(HELP_PROPERTY, "Öffnet eine in Datei<br />

gespeicherte Simulation o<strong>der</strong> ein bereits berechnetes "+<br />

"Intereferenzmuster. Die Simulation kann dann bearbeitet und<br />

berechnet werden. Än<strong>der</strong>ungen haben auf die "+<br />

"gespeicherte Simulation keinen Einfluss.");<br />

tiSpeichern = new ToolItem(toolBar, SWT.PUSH);<br />

tiSpeichern.setText("&Speichern");<br />

tiSpeichern.setImage(imgSpeichern);<br />

tiSpeichern.setData(HELP_PROPERTY, "Speichert die aktuelle<br />

Simulation in eine Datei. "+<br />

"Diese kann dann später wie<strong>der</strong> geöffnet und verän<strong>der</strong>t<br />

werden.");<br />

new ToolItem(toolBar, SWT.SEPARATOR);<br />

tiPunktHinzufuegen = new ToolItem(toolBar, SWT.PUSH);<br />

tiPunktHinzufuegen.setText("Punkt &Hinzufügen");<br />

tiPunktHinzufuegen.setImage(imgPunktHinzufuegen);<br />

tiPunktHinzufuegen.setData(HELP_PROPERTY, "Um <strong>der</strong> Simulation einen<br />

Objektpunkt hinzuzufügen, "+<br />

"klicken Sie auf diesen Knopf und dann in den Hologramm-Editor.<br />

An <strong>der</strong> Stelle, wo Sie "+<br />

"die M<strong>aus</strong>e wie<strong>der</strong> loslassen, wird ein neuer Punkt erzeugt.");<br />

tiTextHinzufuegen = new ToolItem(toolBar, SWT.PUSH);<br />

tiTextHinzufuegen.setText("&Text Hinzufügen");<br />

tiTextHinzufuegen.setImage(imgTextHinzufuegen);<br />

tiTextHinzufuegen.setData(HELP_PROPERTY, "Öffnet einen Dialog, in<br />

dem Sie einen Text eingeben können. "+<br />

"Klicken Sie dann in den Hologramm-Editor. An <strong>der</strong> Stelle, wo<br />

Sie die M<strong>aus</strong> loslassen, wird <strong>der</strong> "+<br />

"Text als Punktmuster eingefügt.");<br />

tiPunktLoeschen = new ToolItem(toolBar, SWT.PUSH);<br />

57


tiPunktLoeschen.setText("Punkt &Löschen");<br />

tiPunktLoeschen.setImage(imgPunktLoeschen);<br />

tiPunktLoeschen.setData(HELP_PROPERTY, "Entfernt den im Hologramm-<br />

Editor <strong>aus</strong>gewählten Objektpunkt "+<br />

"<strong>aus</strong> <strong>der</strong> Simulation. Ist kein Punkt <strong>aus</strong>gewählt, passiert<br />

nichts.");<br />

new ToolItem(toolBar, SWT.SEPARATOR);<br />

tiBerechnen = new ToolItem(toolBar, SWT.PUSH);<br />

tiBerechnen.setText("&Berechnen");<br />

tiBerechnen.setImage(imgBerechnen);<br />

tiBerechnen.setDisabledImage(imgBerechnenDisabled);<br />

tiBerechnen.setData(HELP_PROPERTY, "Berechnet das Interferenz-<br />

Muster des Hologrammes. "+<br />

"Das Muster wird in einem neuen Fenster angezeigt. Die<br />

Berechnung kann einige Zeit dauern!");<br />

new ToolItem(toolBar, SWT.SEPARATOR);<br />

tiInfo = new ToolItem(toolBar, SWT.PUSH);<br />

tiInfo.setText("Inf&o");<br />

tiInfo.setImage(imgInfo);<br />

tiInfo.setData(HELP_PROPERTY, "Zeigt Informationen zum Programm<br />

(Autor, etc.) an.");<br />

new ToolItem(toolBar, SWT.SEPARATOR);<br />

tiBeenden = new ToolItem(toolBar, SWT.PUSH);<br />

tiBeenden.setText("B&eenden");<br />

tiBeenden.setImage(imgBeenden);<br />

tiBeenden.setData(HELP_PROPERTY, "Beendet das Programm. Die<br />

Simulation wird nicht gespeichert, "+<br />

"wollen Sie sie später weiter bearbeiten, müssen Sie sie vorm<br />

Beenden abspeichern.");<br />

toolBar.addMouseMoveListener(new MouseMoveListener()<br />

{<br />

public void mouseMove(MouseEvent evt)<br />

{<br />

ToolItem item = toolBar.getItem(new Point(evt.x, evt.y));<br />

String help = null;<br />

if ((item != null) && ((help =<br />

(String)item.getData(HELP_PROPERTY)) != null))<br />

helpViewer.setHilfe(help);<br />

else<br />

helpViewer.setHilfe(null);<br />

}<br />

} );<br />

toolBar.addMouseTrackListener(new MouseTrackAdapter()<br />

{<br />

public void mouseExit(MouseEvent evt)<br />

{<br />

helpViewer.setHilfe(null);<br />

}<br />

} );<br />

}<br />

private String exceptionToString(Exception e)<br />

{<br />

StringWriter sw = new StringWriter();<br />

PrintWriter pw = new PrintWriter(sw);<br />

58


}<br />

e.printStackTrace(pw);<br />

pw.close();<br />

return sw.toString();<br />

/** Die Event-Loop des Programmes */<br />

public void waitForClose()<br />

{<br />

while (! shell.isDisposed())<br />

{<br />

try<br />

{<br />

if (! display.readAndDispatch())<br />

display.sleep();<br />

}<br />

catch (Exception e)<br />

{<br />

e.printStackTrace();<br />

SWTUtils.messageBox(shell, SWT.ICON_ERROR | SWT.OK,<br />

"Unerwarteter Fehler", exceptionToString(e));<br />

}<br />

}<br />

}<br />

}<br />

NullEditor.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.layout.*;<br />

import org.eclipse.swt.widgets.*;<br />

/** Dieser Editor wird im EigenschaftenEditorControl angezeigt, wenn<br />

für die<br />

Klasser <strong>der</strong> Auswahl kein an<strong>der</strong>er Editor verfügbar ist. Dieser Editor<br />

zeigt einfach nur einen Hinweistext an */<br />

public class NullEditor extends ObjektEditor<br />

{<br />

public NullEditor(Composite parent)<br />

{<br />

super(parent, null);<br />

setLayout(new FillLayout());<br />

new Label(this, SWT.CENTER).setText("Keine Eigenschaften<br />

verfügbar");<br />

}<br />

public void editiereObjekt(Object obj)<br />

{<br />

}<br />

public void speichereEigenschaften()<br />

{<br />

}<br />

59


}<br />

public Class getEditorFuer()<br />

{<br />

return null;<br />

}<br />

ObjektEditor.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.widgets.*;<br />

/** Allgemeine Oberklasse für alle Objekte, die eine Auswahl editieren<br />

können,<br />

z.B. SimulationEditor o<strong>der</strong> ObjektPUnktEditor. Subklassen werden im<br />

EigenschaftenEditorControl angezeigt */<br />

public abstract class ObjektEditor extends Composite<br />

{<br />

protected HologrammEditor editorFuer;<br />

}<br />

public ObjektEditor(Composite parent, HologrammEditor editorFuer)<br />

{<br />

super(parent, SWT.NONE);<br />

this.editorFuer = editorFuer;<br />

}<br />

/** Startet die editierung des Objektes obj */<br />

public abstract void editiereObjekt(Object obj);<br />

/** Speichert die editierten Eigenschaften im Objekt */<br />

public abstract void speichereEigenschaften();<br />

/** Welche Objekte kann dieser ObjektEditor bearbeiten? */<br />

public abstract Class getEditorFuer();<br />

/** Kann dieser ObjektEditor das Objekt obj bearbeiten?<br />

(basiert auf getEditorFuer()) */<br />

public boolean isEditorFuer(Object obj)<br />

{<br />

if (obj == null)<br />

return false;<br />

return getEditorFuer().equals(obj.getClass());<br />

}<br />

ObjektPunkt.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

/** Diese Klasse modelliert einen Punkt des zu holographierenden<br />

Objektes */<br />

public class ObjektPunkt implements java.io.Serializable<br />

{<br />

private static final long serialVersionUID = 1;<br />

/** Die X-Koordinate des Objektpunktes in cm */<br />

60


public float x;<br />

/** Die Y-Koordinate des Objektpunktes in cm */<br />

public float y;<br />

/** Die Z-Koordinate (Tiefe) des Objektpunktes in cm */<br />

public float z;<br />

/** Die Amplitude (maximale Auslenkung) des von dem Objektpunktes<br />

<strong>aus</strong>gehenden Strahles */<br />

public float amplitude;<br />

/** zufallsPhase wird zu jedem <strong>aus</strong>gehenden Strahl hinzuaddiert, um<br />

eine Oberflächenrauhigkeit zu simulieren, die den Kontrast erhöht.<br />

Der Wert ist: 0


private NumberFormat floatFormatter;<br />

public ObjektPunktEditor(Composite parent, HologrammEditor<br />

editorFuer, HelpViewer helpViewer)<br />

{<br />

super(parent, editorFuer);<br />

floatFormatter = NumberFormat.getInstance();<br />

floatFormatter.setMinimumFractionDigits(1);<br />

floatFormatter.setMaximumFractionDigits(2);<br />

macheGui();<br />

SelectionListener sl = new SelectionAdapter()<br />

{<br />

public void widgetDefaultSelected(SelectionEvent evt)<br />

{<br />

speichereEigenschaften();<br />

}<br />

};<br />

txtX.addSelectionListener(sl);<br />

txtY.addSelectionListener(sl);<br />

txtZ.addSelectionListener(sl);<br />

txtAmplitude.addSelectionListener(sl);<br />

editorFuer.addObjektPunktPosListener(this);<br />

txtX.addMouseTrackListener(new DynamicHelpListener(helpViewer,<br />

"Die X-Koordinate des <strong>aus</strong>gewählten Punktes "+<br />

"in Zentimetern."));<br />

txtY.addMouseTrackListener(new DynamicHelpListener(helpViewer,<br />

"Die Y-Koordinate des <strong>aus</strong>gewählten Punktes "+<br />

"in Zentimetern."));<br />

txtZ.addMouseTrackListener(new DynamicHelpListener(helpViewer,<br />

"Die Z-Koordinate (Entfernung von <strong>der</strong> "+<br />

"Hologrammebene) in Zentimetern. Sollte zwischen 30 und 40 cm<br />

sein."));<br />

txtAmplitude.addMouseTrackListener(new<br />

DynamicHelpListener(helpViewer, "Die Amplitude (maximale Auslenkung)<br />

"+<br />

"des Lichtstrahles, <strong>der</strong> von dem <strong>aus</strong>gewählten Punkt <strong>aus</strong>geht.<br />

Wichtig ist nicht <strong>der</strong> absolute Wert, "+<br />

"son<strong>der</strong>n das Verhältnis zu den Amplituden <strong>der</strong> an<strong>der</strong>en<br />

Punkten."));<br />

}<br />

public void punktPosGeaen<strong>der</strong>t(Object sen<strong>der</strong>, ObjektPunkt punkt)<br />

{<br />

if (this.punkt == punkt)<br />

{<br />

txtX.setText(floatFormatter.format(punkt.x));<br />

txtY.setText(floatFormatter.format(punkt.y));<br />

}<br />

}<br />

private void macheGui()<br />

{<br />

GridLayout layout = new GridLayout(2, false);<br />

layout.marginWidth = 5;<br />

layout.marginHeight = 5;<br />

layout.verticalSpacing = 5;<br />

layout.horizontalSpacing = 5;<br />

setLayout(layout);<br />

62


}<br />

GridData gd;<br />

Label lblDesc;<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("X-Koordinate [cm]:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtX = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtX.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Y-Koordinate [cm]:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtY = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtY.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Z-Koordinate (Tiefe) [cm]:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtZ = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtZ.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Amplitude:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtAmplitude = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtAmplitude.setLayoutData(gd);<br />

public void editiereObjekt(Object obj)<br />

{<br />

if (! (obj instanceof ObjektPunkt))<br />

throw new IllegalArgumentException("obj ist nicht vom Typ<br />

ObjektPunkt");<br />

if (obj == null)<br />

throw new IllegalArgumentException("obj darf nicht null sein");<br />

punkt = (ObjektPunkt)obj;<br />

updateGui();<br />

63


}<br />

private void updateGui()<br />

{<br />

txtX.setText(floatFormatter.format(punkt.x));<br />

txtY.setText(floatFormatter.format(punkt.y));<br />

txtZ.setText(floatFormatter.format(punkt.z));<br />

txtAmplitude.setText(floatFormatter.format(punkt.amplitude));<br />

}<br />

public void speichereEigenschaften()<br />

{<br />

if (punkt != null)<br />

{<br />

try<br />

{<br />

punkt.x =<br />

floatFormatter.parse(txtX.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "X-Koordinate ist ungültig: " + e);<br />

}<br />

try<br />

{<br />

punkt.y =<br />

floatFormatter.parse(txtY.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Y-Koordinate ist ungültig: " + e);<br />

}<br />

try<br />

{<br />

punkt.z =<br />

floatFormatter.parse(txtZ.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Z-Koordinate ist ungültig: " + e);<br />

}<br />

try<br />

{<br />

punkt.amplitude =<br />

floatFormatter.parse(txtAmplitude.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Amplitude ist ungültig: " + e);<br />

}<br />

}<br />

}<br />

updateGui();<br />

editorFuer.redraw();<br />

public Class getEditorFuer()<br />

{<br />

64


}<br />

}<br />

return ObjektPunkt.class;<br />

ObjektPunktPosListener.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import java.util.*;<br />

/** Dieses interface wird implementiert, um Benachrichtigung darüber<br />

zu<br />

bekommen, wenn sich die Position eines ObjektPUnkts geän<strong>der</strong>t hat */<br />

public interface ObjektPunktPosListener extends EventListener<br />

{<br />

public void punktPosGeaen<strong>der</strong>t(Object sen<strong>der</strong>, ObjektPunkt punkt);<br />

}<br />

Photo.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.graphics.*;<br />

/* Beschreibt die Hell-Dunkel-Verteilung, die auf einer Photoplatte<br />

entstehen würde */<br />

public class Photo<br />

{<br />

private double[][] muster;<br />

private InterferenzMuster im;<br />

private ImageData id;<br />

private double durchschnittsPixel;<br />

/** Leerer Konstruktor */<br />

protected Photo()<br />

{<br />

}<br />

/** Erstellt eine neue Photoplatte <strong>aus</strong> dem gegebenen (berechneten)<br />

Interferenzmuster */<br />

public Photo(InterferenzMuster im)<br />

{<br />

this.im = im;<br />

muster = im.getMuster();<br />

}<br />

// Palette mit 256 Gr<strong>aus</strong>tufen erzeugen<br />

RGB[] rgbs = new RGB[256];<br />

for (int i=0; i


** Gibt den Inhalt <strong>der</strong> Photoplatte als Bild zurück, das dann<br />

dargestellt<br />

werden kann */<br />

public ImageData getImageData()<br />

{<br />

return id;<br />

}<br />

/** Gibt den Durchschnittswert aller Pixel zurück */<br />

public double getDurchschnittsPixel()<br />

{<br />

return durchschnittsPixel;<br />

}<br />

/** Berechnung erfolgt dardurch, dass die summierten Elongationen<br />

<strong>aus</strong> dem<br />

InterferenzMuster (die auch negativ sein können!)umgerechnet<br />

werden in<br />

Werte zwischen 0 und 255, die dann den Helligkeitswert ergeben. */<br />

private void berechnePhoto()<br />

{<br />

double streckFaktor = 255 / (im.getMaxAmplitude() -<br />

im.getMinAmplitude());<br />

durchschnittsPixel = 0;<br />

for (int x=0; x


public int anzeigeSkalierung;<br />

private List objekt;<br />

public Simulation(boolean zufallsPhasen, double lambda, int<br />

breiteInPixel, int hoeheInPixel,<br />

float musterBreite, float musterHoehe, int anzeigeSkalierung)<br />

{<br />

this.zufallsPhasen = zufallsPhasen;<br />

this.lambda = lambda;<br />

this.breiteInPixel = breiteInPixel;<br />

this.hoeheInPixel = hoeheInPixel;<br />

this.musterBreite = musterBreite;<br />

this.musterHoehe = musterHoehe;<br />

}<br />

}<br />

this.anzeigeSkalierung = anzeigeSkalierung;<br />

objekt = new ArrayList();<br />

/** this(true, 633e-7, 640, 480, 1.0f, 0.75f, 6) */<br />

public Simulation()<br />

{<br />

this(true, 633e-7, 640, 480, 1.0f, 0.75f, 6);<br />

}<br />

/** Einen punkt zur Simulation hinzufügen */<br />

public void punktHinzufuegen(ObjektPunkt punkt)<br />

{<br />

objekt.add(punkt);<br />

}<br />

/** Einen ObjektPunkt wie<strong>der</strong> <strong>aus</strong> <strong>der</strong> Simulation entfernen */<br />

public boolean punktLoeschen(ObjektPunkt punkt)<br />

{<br />

return objekt.remove(punkt);<br />

}<br />

/** Iterator über alle ObjektPunkte */<br />

public Iterator objektIterator()<br />

{<br />

return objekt.iterator();<br />

}<br />

/** Alle ObjektPUnkte im Array zurückgeben */<br />

public ObjektPunkt[] getObjekt()<br />

{<br />

return (ObjektPunkt[])objekt.toArray(new ObjektPunkt[0]);<br />

}<br />

SimulationEditor.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.events.*;<br />

import org.eclipse.swt.layout.*;<br />

import org.eclipse.swt.widgets.*;<br />

67


import java.text.*;<br />

/** Editor, wenn die Auswahl vom Typ Simulation ist */<br />

public class SimulationEditor extends ObjektEditor<br />

{<br />

private Simulation simulation = null;<br />

private Button cbZufallsPhasen;<br />

private Text txtLambda;<br />

private Text txtBreiteInPixel;<br />

private Text txtHoeheInPixel;<br />

private Text txtMusterBreite;<br />

private Text txtMusterHoehe;<br />

private Combo comboSkalierung;<br />

private NumberFormat floatFormatter;<br />

public SimulationEditor(Composite parent, HologrammEditor<br />

editorFuer, HelpViewer helpViewer)<br />

{<br />

super(parent, editorFuer);<br />

floatFormatter = NumberFormat.getInstance();<br />

floatFormatter.setMinimumFractionDigits(1);<br />

floatFormatter.setMaximumFractionDigits(2);<br />

macheGui();<br />

SelectionListener sl = new SelectionListener()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

speichereEigenschaften();<br />

}<br />

public void widgetDefaultSelected(SelectionEvent evt)<br />

{<br />

speichereEigenschaften();<br />

}<br />

};<br />

cbZufallsPhasen.addSelectionListener(sl);<br />

txtLambda.addSelectionListener(sl);<br />

txtBreiteInPixel.addSelectionListener(sl);<br />

txtHoeheInPixel.addSelectionListener(sl);<br />

txtMusterBreite.addSelectionListener(sl);<br />

txtMusterHoehe.addSelectionListener(sl);<br />

comboSkalierung.addSelectionListener(sl);<br />

cbZufallsPhasen.addMouseTrackListener(new<br />

DynamicHelpListener(helpViewer, "Bestimmt, ob zu den "+<br />

"Auslenkungen <strong>der</strong> Lichtstrahlen auf <strong>der</strong> Hologrammebene ein<br />

konstanter, aber für jeden Punkt "+<br />

"an<strong>der</strong>er Phasenwert dazuaddiert werden soll. Dies erhöht den<br />

Kontrast des "+<br />

"Interferenzmusters."));<br />

txtLambda.addMouseTrackListener(new<br />

DynamicHelpListener(helpViewer, "Die Wellenlänge des virtuellen<br />

Lasers, "+<br />

"<strong>der</strong> zum Berechnen verwendet wird in Metern. Die Wellenlänge<br />

muss auch <strong>der</strong> entsprechen, die bei <strong>der</strong> "+<br />

"Rekonstruktion verwendet werden soll. Als Komma muss ein Punkt<br />

verwendet werden."));<br />

txtBreiteInPixel.addMouseTrackListener(new<br />

68


DynamicHelpListener(helpViewer, "Die Breite des berechneten "+<br />

"Interferenzmusters in Pixeln. Sollte <strong>der</strong> Breite des<br />

Bildschirmes entsprechen, allerdings: "+<br />

"je größer dieser Wert, desto länger dauert die Berechnung!"));<br />

txtHoeheInPixel.addMouseTrackListener(new<br />

DynamicHelpListener(helpViewer, "Die Höhe des berechneten "+<br />

"Interferenzmusters in Pixeln. Sollte <strong>der</strong> Höhe des Bildschirmes<br />

entsprechen, allerdings: "+<br />

"je größer dieser Wert, desto länger dauert die Berechnung!"));<br />

txtMusterBreite.addMouseTrackListener(new<br />

DynamicHelpListener(helpViewer, "Die Breite, die das Hologramm "+<br />

"nach dem Abphotographieren und Verkleinern haben soll in<br />

Zentimetern."));<br />

txtMusterHoehe.addMouseTrackListener(new<br />

DynamicHelpListener(helpViewer, "Die Höhe, die das Hologramm "+<br />

"nach dem Abphotographieren und Verkleinern haben soll in<br />

Zentimetern."));<br />

comboSkalierung.addMouseTrackListener(new<br />

DynamicHelpListener(helpViewer, "Wieviel soll <strong>der</strong> Hologramm-Editor "+<br />

"das Hologramm gegenüber <strong>der</strong> Originalgröße (Musterbreite x<br />

Musterhöhe) vergrößern. Auf die Berechnung "+<br />

"hat dies keinen Einfluss."));<br />

}<br />

private void macheGui()<br />

{<br />

GridLayout layout = new GridLayout(2, false);<br />

layout.marginWidth = 5;<br />

layout.marginHeight = 5;<br />

layout.verticalSpacing = 5;<br />

layout.horizontalSpacing = 5;<br />

setLayout(layout);<br />

GridData gd;<br />

Label lblDesc;<br />

cbZufallsPhasen = new Button(this, SWT.CHECK);<br />

cbZufallsPhasen.setText("Zufallsphasen");<br />

gd = new GridData();<br />

gd.horizontalSpan = 2;<br />

cbZufallsPhasen.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Wellenlänge [m]:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtLambda = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtLambda.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Breite in Pixeln:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtBreiteInPixel = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

69


gd.grabExcessHorizontalSpace = true;<br />

txtBreiteInPixel.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Höhe in Pixeln:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtHoeheInPixel = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtHoeheInPixel.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Musterbreite [cm]:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtMusterBreite = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtMusterBreite.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Musterhöhe [cm]:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

txtMusterHoehe = new Text(this, SWT.BORDER | SWT.SINGLE);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtMusterHoehe.setLayoutData(gd);<br />

lblDesc = new Label(this, SWT.NONE);<br />

lblDesc.setText("Editor Vergrößerung:");<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblDesc.setLayoutData(gd);<br />

comboSkalierung = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);<br />

comboSkalierung.setItems(new String[]{ "2-fach", "4-fach", "6fach",<br />

"8-fach", "10-fach" });<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

comboSkalierung.setLayoutData(gd);<br />

}<br />

public void editiereObjekt(Object obj)<br />

{<br />

if (! (obj instanceof Simulation))<br />

throw new IllegalArgumentException("obj ist nicht vom Typ<br />

Simulation");<br />

if (obj == null)<br />

throw new IllegalArgumentException("obj darf nicht null sein");<br />

simulation = (Simulation)obj;<br />

70


}<br />

updateGui();<br />

private void updateGui()<br />

{<br />

cbZufallsPhasen.setSelection(simulation.zufallsPhasen);<br />

txtLambda.setText(""+(simulation.lambda/100));<br />

txtBreiteInPixel.setText(""+simulation.breiteInPixel);<br />

txtHoeheInPixel.setText(""+simulation.hoeheInPixel);<br />

txtMusterBreite.setText(floatFormatter.format(simulation.musterBreit<br />

e));<br />

txtMusterHoehe.setText(floatFormatter.format(simulation.musterHoehe)<br />

);<br />

comboSkalierung.select((simulation.anzeigeSkalierung / 2)-1);<br />

}<br />

public void speichereEigenschaften()<br />

{<br />

if (simulation != null)<br />

{<br />

simulation.zufallsPhasen = cbZufallsPhasen.getSelection();<br />

try<br />

{<br />

simulation.lambda =<br />

Double.parseDouble(txtLambda.getText().trim())*100;<br />

}<br />

catch (NumberFormatException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Wellenlänge ist ungültig: " + e);<br />

}<br />

try<br />

{<br />

simulation.breiteInPixel =<br />

Integer.parseInt(txtBreiteInPixel.getText().trim());<br />

}<br />

catch (NumberFormatException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Breite in Pixeln ist ungültig: " + e);<br />

}<br />

try<br />

{<br />

simulation.hoeheInPixel =<br />

Integer.parseInt(txtHoeheInPixel.getText().trim());<br />

}<br />

catch (NumberFormatException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Höhe in Pixeln ist ungültig: " + e);<br />

}<br />

try<br />

{<br />

simulation.musterBreite =<br />

floatFormatter.parse(txtMusterBreite.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Musterbreite ist ungültig: " + e);<br />

}<br />

71


try<br />

{<br />

simulation.musterHoehe =<br />

floatFormatter.parse(txtMusterHoehe.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(getShell(), SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Musterhöhe ist ungültig: " + e);<br />

}<br />

simulation.anzeigeSkalierung =<br />

(comboSkalierung.getSelectionIndex()+1)*2;<br />

}<br />

}<br />

}<br />

updateGui();<br />

editorFuer.redraw();<br />

public Class getEditorFuer()<br />

{<br />

return Simulation.class;<br />

}<br />

SWTUtils.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.graphics.*;<br />

import org.eclipse.swt.widgets.*;<br />

public class SWTUtils<br />

{<br />

/** Zeigt eine MessageBox an */<br />

public static int messageBox(Shell parent, int style, String title,<br />

String message)<br />

{<br />

MessageBox msgBox = new MessageBox(parent, style);<br />

msgBox.setMessage(message);<br />

msgBox.setText(title);<br />

return msgBox.open();<br />

}<br />

/** Zentriert shell auf centerOn. Wenn centerOn null ist, wird shell<br />

auf dem Bildschirm zentriert */<br />

public static void centerShell(Shell shell, Shell centerOn)<br />

{<br />

Rectangle rect = (centerOn == null ?<br />

shell.getDisplay().getBounds() : centerOn.getBounds());<br />

shell.setLocation((rect.width-shell.getBounds().width)/2+rect.x,<br />

(rect.height-shell.getBounds().height)/2+rect.y);<br />

}<br />

}<br />

TextInputDialog.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

72


michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.events.*;<br />

import org.eclipse.swt.layout.*;<br />

import org.eclipse.swt.widgets.*;<br />

import java.text.*;<br />

/** Dieser Dialog wird angezeigt, wenn <strong>der</strong> Button "Text hinzufügen"<br />

gewählt<br />

wurde */<br />

public class TextInputDialog extends Dialog<br />

{<br />

private TextPseudoObjekt result = null;<br />

private Display display;<br />

private Shell shell;<br />

private Label lblMessage;<br />

private Text txtEingabe;<br />

private Button btnOk;<br />

private Button btnAbbrechen;<br />

private Label lblStartZ;<br />

private Text txtStartZ;<br />

private Label lblOffsetZ;<br />

private Text txtOffsetZ;<br />

private NumberFormat floatFormatter;<br />

public TextInputDialog(Shell parent)<br />

{<br />

super(parent, SWT.NONE);<br />

}<br />

floatFormatter = NumberFormat.getInstance();<br />

floatFormatter.setMinimumFractionDigits(1);<br />

floatFormatter.setMaximumFractionDigits(2);<br />

public TextPseudoObjekt open()<br />

{<br />

display = CGHMain.display;<br />

shell = new Shell(getParent(), SWT.DIALOG_TRIM |<br />

SWT.APPLICATION_MODAL);<br />

shell.setText("Text Hinzufügen");<br />

result = null;<br />

macheGui();<br />

btnOk.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

result = new TextPseudoObjekt(txtEingabe.getText(), 30f,<br />

0.2f);<br />

try<br />

{<br />

result.startZ =<br />

floatFormatter.parse(txtStartZ.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(shell, SWT.ICON_WARNING | SWT.OK,<br />

73


"Fehler", "Starttiefe ist ungültig, verwende Standardwert 30.0: " +<br />

e);<br />

}<br />

try<br />

{<br />

result.offsetZ =<br />

floatFormatter.parse(txtOffsetZ.getText().trim()).floatValue();<br />

}<br />

catch (ParseException e)<br />

{<br />

SWTUtils.messageBox(shell, SWT.ICON_WARNING | SWT.OK,<br />

"Fehler", "Tiefenoffset ist ungültig, verwende Standardwert 0.2: " +<br />

e);<br />

}<br />

shell.close();<br />

}<br />

} );<br />

btnAbbrechen.addSelectionListener(new SelectionAdapter()<br />

{<br />

public void widgetSelected(SelectionEvent evt)<br />

{<br />

shell.close();<br />

}<br />

} );<br />

txtEingabe.addVerifyListener(new VerifyListener()<br />

{<br />

public void verifyText(VerifyEvent evt)<br />

{<br />

String text = evt.text;<br />

StringBuffer ok = new StringBuffer();<br />

}<br />

}<br />

} );<br />

for (int i=0; i= 'A' && c = 'a' && c


txtEingabe = new Text(shell, SWT.BORDER | SWT.SINGLE);<br />

txtEingabe.setText("");<br />

/* Code für Positions-Group */<br />

Group posGroup = new Group(shell, SWT.NONE);<br />

posGroup.setText("Z-Koordinate (Tiefe)");<br />

lblStartZ = new Label(posGroup, SWT.NONE);<br />

lblStartZ.setText("Position des ersten Buchstabens:");<br />

txtStartZ = new Text(posGroup, SWT.BORDER | SWT.SINGLE);<br />

txtStartZ.setText(floatFormatter.format(30.0f));<br />

lblOffsetZ = new Label(posGroup, SWT.NONE);<br />

lblOffsetZ.setText("Offset für nachfolgende Buchstaben:");<br />

txtOffsetZ = new Text(posGroup, SWT.BORDER | SWT.SINGLE);<br />

txtOffsetZ.setText(floatFormatter.format(0.2f));<br />

posGroup.setLayout(new GridLayout(2, false));<br />

GridData gd;<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblStartZ.setLayoutData(gd);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtStartZ.setLayoutData(gd);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

lblOffsetZ.setLayoutData(gd);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtOffsetZ.setLayoutData(gd);<br />

/* Code für Knopf-Leiste: */<br />

Composite buttonBar = new Composite(shell, SWT.NONE);<br />

btnOk = new Button(buttonBar, SWT.PUSH);<br />

btnOk.setText("&OK");<br />

btnAbbrechen = new Button(buttonBar, SWT.PUSH);<br />

btnAbbrechen.setText("&Abbrechen");<br />

shell.setDefaultButton(btnOk);<br />

RowLayout rl = new RowLayout();<br />

rl.marginHeight = 0;<br />

rl.marginWidth = 0;<br />

rl.spacing = 5;<br />

buttonBar.setLayout(rl);<br />

// Layout für Shell:<br />

shell.setLayout(new GridLayout(1, false));<br />

//GridData gd;<br />

gd = new GridData();<br />

75


}<br />

}<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.verticalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

lblMessage.setLayoutData(gd);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

txtEingabe.setLayoutData(gd);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.FILL;<br />

gd.grabExcessHorizontalSpace = true;<br />

posGroup.setLayoutData(gd);<br />

gd = new GridData();<br />

gd.horizontalAlignment = SWT.END;<br />

buttonBar.setLayoutData(gd);<br />

TextPseudoObjekt.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

/** Diese Klasse stellt einen Text dar, <strong>der</strong> eingefügt werden soll.<br />

Es ist deshalb nur ein PseudoObjekt, da es nicht in die Simulation<br />

eingefügt wird, son<strong>der</strong>n in mehrere ObjektPUnkte umgerechnet wird und<br />

diese<br />

dann eingefügt werden */<br />

public class TextPseudoObjekt<br />

{<br />

public String text;<br />

public float startZ;<br />

public float offsetZ;<br />

}<br />

public TextPseudoObjekt(String text, float startZ, float offsetZ)<br />

{<br />

this.text = text;<br />

this.startZ = startZ;<br />

this.offsetZ = offsetZ;<br />

}<br />

VollBildDialog.java<br />

// CGH - Copyright (C) 2004-2005 Michael <strong>Partheil</strong>,<br />

michael.partheil@gmx.de<br />

import org.eclipse.swt.*;<br />

import org.eclipse.swt.events.*;<br />

import org.eclipse.swt.graphics.*;<br />

import org.eclipse.swt.widgets.*;<br />

/** Zeigt ein Hologramm Vollbild an, zum abphotographieren */<br />

public class VollBildDialog extends Dialog<br />

{<br />

private Image img;<br />

76


private boolean zeigeHinweis = true;<br />

public VollBildDialog(Shell parent, Image imgHolo)<br />

{<br />

super(parent, SWT.NONE);<br />

img = imgHolo;<br />

}<br />

// Achtung: Der zurückgegebene Cursor muss "eigenverantwortlich"<br />

disposed werden!!!!<br />

// (kein reference-counting etc)<br />

private static Cursor macheLeerenCursor()<br />

{<br />

PaletteData paletteData = new PaletteData(new RGB[] { new<br />

RGB(0,0,0) , new RGB(255,255,255) });<br />

ImageData sourceData = new ImageData(32,32,1,paletteData);<br />

ImageData maskData = new ImageData(32,32,1,paletteData);<br />

}<br />

int[] cursorSource = new int[32*32];<br />

for (int i=0; i


}<br />

}<br />

shell.addKeyListener(new KeyAdapter()<br />

{<br />

public void keyPressed(KeyEvent evt)<br />

{<br />

shell.close();<br />

}<br />

} );<br />

display.timerExec(3000, new Runnable()<br />

{<br />

public void run()<br />

{<br />

if (! shell.isDisposed())<br />

{<br />

zeigeHinweis = false;<br />

shell.redraw();<br />

}<br />

}<br />

} );<br />

shell.setBounds(display.getBounds());<br />

shell.open();<br />

while (! shell.isDisposed())<br />

{<br />

if (! display.readAndDispatch())<br />

display.sleep();<br />

}<br />

leerCursor.dispose();<br />

78

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!