Computerholographie - der Fam. Partheil aus Biedenkopf-Wallau
Computerholographie - der Fam. Partheil aus Biedenkopf-Wallau
Computerholographie - der Fam. Partheil aus Biedenkopf-Wallau
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