Aufgaben Phase 2 - Lehrgebiet Datenbanksysteme für neue

Werbung
Fachpraktikum 1590
„Erweiterbare Datenbanksysteme“
Aufgaben Phase 2
Wintersemester 2006/2007
Ralf Hartmut Güting, Dirk Ansorge, Thomas Behr, Markus Spiekermann
Praktische Informatik IV, FernUniversität in Hagen
58084 Hagen
–
1
–
Vorwort
Liebe Studierende,
hiermit halten Sie nun die Aufgabenvorschläge zur zweiten Phase des Fachpraktikums in den
Händen. Arbeiten Sie die Aufgabenstellungen bitte durch und überlegen Sie sich Fragen dazu.
Eine Zuteilung von Aufgaben zu Gruppen erfolgt während der zweiten Präsenzphase. Innerhalb
der Gruppen findet dann eine ausführliche Diskussion der zugeteilten Aufgabe mit dem Ziel, eine
möglichst genaue Spezifikation der Programmierarbeiten zu erstellen, statt.
Die drei zur Auswahl stehenden Aufgaben beschäftigen sich mit i) der Einbettung von Web-spezifischen Datentypen und der Speicherung von Webseiten in SECONDO, ii) einem Datentyp für
Schachpartien und der Bereitstellung einiger Operatoren dafür und iii) der Implementierung einer
Algebra für Graphen in SECONDO.
Viel Spaß mit den Aufgaben
Ihre Praktikumsbetreuer
–
1
2
–
Erstellung einer Algebra zur Darstellung von Webseiten
1.1
Einleitung
Mehr oder weniger wichtige Informationen werden im World Wide Web im Regelfall durch
Dokumente im HTML1-Format beschrieben. Neben der reinen textuellen Darstellung können
zusätzlich Bilder, Videos oder Sounds in solchen Dokumenten eingebettet sein. Diese komplexen
Objekte sind nicht Bestandteil der eigentlichen HTML-Datei, sondern existieren als externe
Dateien, die durch Hyperlinks referenziert werden. Auch Darstellungsinformationen (StyleSheets) oder Reaktionen auf Benutzeraktionen (Javascript) können als externe Datei vorliegen.
Im Gegensatz zu den davorgenannten Objekten ist es hier auch möglich, diese direkt innerhalb
der html-Datei einzubinden.
Durch die Lösung dieser Aufgabe soll SECONDO befähigt werden, komplette Webseiten mit allen
dazugehörigen Objekten zu verwalten. Dazu sind geeignete Datenstrukturen zu entwerfen.
Zusätzlich sollen auch Webseiten direkt aus dem WWW geladen werden können. Über entsprechende Operationen soll es möglich sein, ähnliche Webseiten zu erkennen. Ähnlichkeit kann sich
hierbei auf den Inhalt oder die Struktur, d.h. den Aufbau des Dokuments, beziehen. Eine Erweiterung der Benutzerschnittstelle von SECONDO soll die Möglichkeit bieten, die in einer Datenbank
gespeicherten Dokumente anzuzeigen und innerhalb einer Relation, die verschiedene Webseiten
enthält, zu navigieren.
1.2
1.2.1
Beschreibung der Algebra
Informelle Beschreibung
Die Algebra, die Sie implementieren, soll mindestens die Typen url, html und page enthalten,
die im folgenden zusammen mit einigen Operationen zunächst informell beschrieben sind. Die
genauen Signaturen finden Sie in Abschnitt 1.2.2.
• url
Eine URL2 besteht aus dem Protokoll und dem Ort einer Ressource im WWW. Der Ort setzt
sich aus dem Hostnamen bzw. der IP-Adresse eines Computers sowie dem Dateinamen auf
dem betreffenden Computer zusammen. Ihre Algebra soll das Erzeugen von URL’s aus
Strings und Texten ermöglichen. Zusätzlich sollen die drei genannten Komponenten aus
einer gegebenen URL extrahiert werden können. Um eine Indexierung der Seiten über die
URL zu ermöglichen, leiten Sie Ihren Datentyp von IndexableStandardAttribute ab,
und implementieren Sie die dort geforderten Funktionen.
• html
Dieser Datentyp stellt eine einzelne HTML-Datei ohne eingebettete Objekte dar. Neben der
Extraktion von Informationen (Text, enthaltene URL’s von eingebetteten und externen
Objekten, Quell-URL, Datum der letzten Änderung, Meta-Informationen usw.) soll Ihre
1. HyperText Markup Language
2. Uniform Resource Locator
–
3
–
Algebra auch Funktionen bereitstellen, die eine Analyse der Struktur eines HTML-Dokuments ermöglichen. So sollen auch Informationen über die Anzahl der enthaltenen Tabellen
etc. abrufbar sein. Weiterhin soll ein Operator existieren, der die Ähnlichkeit von HTMLDokumenten bzgl. Ihrer Struktur berechnet. Bei der Strukturähnlichkeit soll angegeben
werden können, bis zu welcher Strukturtiefe, der Vergleich stattfinden soll. Ein negativer
Wert entspricht dabei der vollständigen Tiefe beider Kandidaten. Zusätzlich soll angegeben
werden können, ob die Reihenfolge der Strukturelemente mit einbezogen werden soll, oder
ob es egal ist, ob ein Textabschnitt von einem Bild gefolgt wird oder ob das Bild vor dem
Text steht.
• page
Der Datentyp page speichert eine vollständige Webseite. Neben der reinen html-Datei, die
natürlich über einen Operator abgefragt werden kann, enthält dieser Datentyp zusätzlich
alle eingebetteten Objekte. Überlegen Sie, wie Sie unterschiedliche Anzahlen solcher
Objekte durch eine feste Anzahl FLOB’s repräsentieren können. Die eingebetteten Objekte
sollen durch einen Operator abrufbar sein. Dieser liefert einen Tupelstrom, der neben weiteren Informationen auch das Objekt selbst als Binärdatei enthält.
Neben den verschiedenen Datentypen mit ihren Operationen sollen Operatoren (wget und
pageget) implementiert werden, die Web-Seiten direkt laden können. Diese beiden Operationen
haben die gleichen Argumente, liefern jedoch unterschiedliche Ergebnistypen. Während der
pageget-Operator einen Tupelstrom mit Attributen vom Typ url und page erzeugt, produziert
der wget-Operator Tupelströme mit den Attributtypen url, string, binfile, wobei der String
eine Typbeschreibung (MIME1 Typ ) (z.B. text/html oder application/pdf) darstellt.
Beide Operatoren sollen mehrere Parameter akzeptieren. Das erste Argument dieser Operationen
ist vom Typ url und kennzeichnet die initial zu ladende Webressource. Handelt es sich hierbei
nicht um eine HTML-Datei, so gibt der pageget -Operator einen leeren Strom zurück, der wgetOperator einen Strom mit einem einzelnen Tupel.
Der zweite Parameter vom Typ bool gibt an, ob Hyperlinks rekursiv verfolgt werden sollen. Hierbei werden alle HTML-Dokumente nach ihren externen Links untersucht und diese ebenfalls in
den Ausgabe-Strom übernommen. Beachten Sie, daß es oft zyklische Abhängigkeiten zwischen
den einzelnen HTML-Dokumenten gibt. Dateien sollen nur einmal in den Strom eingefügt werden. Verwenden Sie daher eine geeignete Datenstruktur, die die bereits verarbeiteten URL’s speichert. Der nächste Parameter gibt die maximale Rekursionstiefe (Typ int) an, falls das zweite
Argument true ist; anderenfalls wird dieser Parameter ignoriert. Ein negativer Wert kennzeichnet
eine unendliche Rekursionstiefe. Standardmäßig sollen beide Operationen nur Dateien verarbeiten, die von der gleichen Quelle (Host) stammen. Im dritten Parameter (Typ text) soll zusätzlich
eine komma-separierte Liste von weiteren Hosts angegeben werden können, auf die die Verarbeitung ausgedehnt werden soll. Der letzte Parameter ist eine Funktion url → bool, die Bedingungen für zu verarbeitende URL’s definiert. Überlegen Sie, ob ggf. weitere Argumente wichtig sein
könnten und ergänzen Sie die Parameterliste entsprechend mit optionalen Argumenten.
Beide Operatoren sollen „nur“ das HTTP2-Protokoll unterstützen. Wenn Sie möchten, dürfen Sie
beide Operatoren natürlich auf beliebige weitere Protokolle ausweiten.
1. Multipurpose Internet Mail Extension
2. Hyper Text Transfer Protocol
–
1.2.2
4
–
Signatur der Algebra
Die Signatur der Algebra finden Sie in der folgenden Tabelle.
algebra
web
sorts
url, html, page
ops
protocol:
url
→
text
host:
url
→
text
filename:
url
→
text
source:
{html, page}
→
url
createurl:
text
→
url
content:
html
→
text
urls:
{html, page}
→
stream(url)
containsurl
{html, page} × url
→
bool
last_modified:
html
→
instant
metainfo:
html × string
→
text
metainfos:
html
→
stream(tuple( [Key: string,
Content: text]))
number_of:
html × string
→
int
similar:
html × html × int × bool
→
real
extracthtml:
page
→
html
numOfFiles:
page
→
int
getFiles:
page
→
stream(tuple( [Source: url,
Type: string, File: binfile]))
wget:
url × bool × int × text ×
map: url → bool
→
stream(tuple( [Source: url,
Type: string, File: binfile]))
pageget:
url × bool × int × text ×
(url → bool)
→
stream(tuple( [Source: url,
Page: page]))
=:
∀t ∈{url, html, page}:
t×t
→
bool
1.3
Erweiterung der Javagui
Implementieren Sie einen neuen Viewer für die Datentypen Ihrer Algebra. Es soll zusätzlich möglich sein, daß ganze Relationen mit Attributen vom Typ page angezeigt werden können. Klickt
man innerhalb einer Seite auf einen Link, so soll geprüft werden, ob die dahinterliegende URL in
–
5
–
der Relation vorhanden ist und die entsprechende Seite soll dann ggf. angezeigt werden. Falls
mehrere Tupel die gleiche URL enthalten, soll der Benutzer die von ihm gewünschte Seite auswählen können. Verwenden Sie zur Implementierung Ihres „Browsers“ ausschließlich Klassen
der Java-Standard-Bibliothek (Version 1.4.2).
1.4
Hinweise
Eine gute Beschreibung des HTML-Formats finden Sie unter http://de.selfhtml.org. Die
vollständige HTML-Spezifikation ist unter: http://www.w3.org/TR/html401 abrufbar. Das
http-Protokoll ist in der Version 1.1 im Dokument RCF12616 beschrieben.
Leider gibt es größere Unterschiede in der Netzanbindung innerhalb verschiedener Betriebssysteme. Um Kompatibilität zu gewährleisten, sollen die Operationen wget und pageget nicht
direkt auf den C bzw. C++ Bibliotheken aufsetzen. Stattdessen soll die Kommunikation mittels
der in SECONDO vorhandenen Socket-Klasse erfolgen, der für verschiedene Betriebssysteme
unterschiedliche Implementierungen zugrundeliegen. Die Interfacebeschreibung finden Sie im
SECONDO-Verzeichnis unter include/SocketIO.h.
1. Request For Comments
–
2
6
–
Ein Datentyp für Schachpartien
Um diese Aufgabe bearbeiten zu können, müssen Sie die Grundregeln des Schachspiels kennen
(lernen). Tiefergehende Kenntnisse sind nicht erforderlich.
In diesem Projekt soll eine Algebra implementiert werden, die es ermöglicht, Schachpartien zu
verwalten. Zum Thema Schach gibt es viele Programme, die notierte Partien in verschiedenen
Formaten verwalten können. Ein offenes und weit verbreitetes Format ist PGN1 (Portable Game
Notation). Im Internet findet man dazu unter verschiedenen Quellen große Partiensammlungen2.
Eine Partie im PGN-Format sieht etwa folgendermaßen aus:
[Event "Tal Memorial"]
[Site "Moscow RUS"]
[Date "2006.11.14"]
[Round "7"]
[White "Ponomariov,R"]
[Black "Aronian,L"]
[Result "1/2-1/2"]
[WhiteElo "2703"]
[BlackElo "2741"]
[EventDate "2006.11.06"]
[ECO "C88"]
1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 O-O 8.
a4 b4 9. a5 d5 10. exd5 e4 11. dxc6 exf3 12. d3 fxg2 13. Qf3 Rb8 14. Bc4
Ne8 15. Bf4 Bf6 16. Nd2 Bxb2 17. Rab1 Bc3 18. Bg5 Bf6 19. Rxe8 Rxe8 20.
Ne4
Rxe4 21. Bxf6 Qxf6 22. Qxf6 gxf6 23. dxe4 Kf8 24. Kxg2 Ke7 25. Rd1 1/2-1/2
In der obigen Notation bezeichnen die Buchstaben von a-h die Spalten (im Schach Linien
genannt, engl.: files) und die Ziffern von 1-8 die Reihen des Spielbretts. Dabei wird der Figurentyp durch einen Buchstaben der englischen Bezeichnung abgekürzt (Pawn~Bauer, Knight~Springer, Bishop~Läufer, Rook~Turm, Queen~Königin, King~König). Nun zieht abwechselnd eine
weiße und eine schwarze Figur, die Bewegung einer Figur bezeichnet man als Halbzug. Die obige
Notation ist recht kompakt, d.h. es wird nur die Figur und das Zielfeld definiert (bei Bauernzügen
entfällt die Figurbezeichnung). Sollte dies nicht reichen, so wird durch die zusätzliche Angabe
von Linie und/oder Reihe Eindeutigkeit erreicht. Eine präzise Definition der Notation findet man
in den FIDE-Regeln3.
Die Algebra soll einen Datentyp chessgame besitzen, dessen interne Datenstruktur eine Partie
speichern kann, d.h. die Züge (ein Zug besteht aus einer Bewegung von Weiß und Schwarz, das
Setzen einer einzelnen Figur bezeichnet man als Halbzug) und im PGN-Format enthaltene MetaInformationen, z.B. Namen der Spieler, Datum des Spiels, Ergebnis, etc. Zusätzlich sollen aus der
Zugfolge auch weitere Informationen abgeleitet werden können, z.B. die Stellung oder die verbleibenden Figuren (Material) nach einem bestimmten Halbzug, etc.
Der Viewer soll das Anzeigen und Editieren von Spielen unterstützen. Zusätzlich soll es möglich
sein, Suchkritierien und Stellungen einzugeben, aus denen dann eine Query erzeugt wird. Dazu
muss natürlich ein vordefiniertes Datenbankschema festgelegt werden, über dem SQL-Anfragen
1. Zur Dokumentation des PGN-Formats siehe z.B. http://tim-mann.org/xboard.html
2. http://www.schachbund.de/links/_Internet/Archive
3. FIDE (Fédération Internationale des Échecs), siehe z.B. http://www.schachbund.de/fideregeln
–
7
–
formuliert werden können. Für Standardattribute sollten Indexe angelegt werden, um Suchen zu
beschleunigen. Suchergebnisse sollen als PGN-Dateien exportiert werden können.
Spezifikation der Algebra
Es sollen die Datentypen chessgame, position, move, material implementiert werden. Der
Typ chessgame stellt eine komplette Partie dar, position eine Stellung und move einen Halbzug
Der Typ material stellt eine Menge von weißen und schwarzen Figuren dar; damit kann z.B.
nach Stellungen gesucht werden, die dieses Figurenmaterial enthalten. Grundlegende Operationen über diesen Typen sind :
•
•
•
•
•
•
•
getkey
positions
moves
getposition
getmove
pieces
moveNo
:
:
:
:
:
:
:
chessgame x string -> string
chessgame -> stream(position)
chessgame -> stream(move)
chessgame x int -> position
chessgame x int -> move
position -> material
position -> int, move -> int
Damit lassen sich aus einer Partie detailliertere Informationen gewinnen. Die Operation getkey
akzeptiert die folgenden Schlüsselwörter: name_{w,b} (Name des Spielers der die weißen bzw.
schwarzen Steine spielt), rating_{b,w}, event, site, date, result, eco_code, moves, ggf. weitere
Metadaten eine Spieles. Die Operationen getposition und getmove ermitteln die Stellung bzw.
die Figurbewegung des angegebenen Halbzugs. Mittels pieces kann das Material einer Stellung
berechnet werden und moveNo bestimmt zu einer Stellung oder einem Zug die Nummer des Halbzugs der zugehörigen Partie. Charakteristika von Zügen lassen sich über die folgenden Operationen bestimmen:
•
•
•
•
•
•
•
•
agent
:
captured :
startrow :
endrow
:
startfile:
endfile :
check
:
captures :
move
move
move
move
move
move
move
move
->
->
->
->
->
->
->
->
string
string
int
int
string
string
bool
bool
Die Operationen agent und captured ermitteln den engl. Figurennamen einer bewegten oder
gefangenen (geschlagenen) Figur bzw. den Wert “none“. Dabei werden weiße Figuren durch
einen großen, Schwarze durch einen kleinen Anfangsbuchstaben gekennzeichnet, z.B.: weiße
Dame ~ “Queen“, schwarzer Springer ~ “knight“. Linien werden durch die Stringwerte “a“ bis
“h“ und Reihen durch die Integerwerte 1-8 identifiziert. Über die Prädikate check und captures
kann man testen, ob in einem Zug Schach geboten bzw. eine Figur gefangen wird. Tests auf Stellungen oder Teilstellungen können mittels der folgenden Operationen durchgeführt werden:
•
•
range
: position x string x int x string x int -> position
includes : position x position -> bool
Durch Angabe des linken, unteren Feldes und des rechten, oberen Feldes liefert der range Operator eine Stellung, die nur die Figuren aus dem angegebenen Bereich enthält, z.B. definiert der
Ausschnitt “a“,1,“a“,8 die gesamte Linie a. Der Operator includes liefert TRUE, wenn die
–
8
–
erste Stellung in der Zweiten enthalten ist, d.h. jede Figur des ersten Arguments ist in der zweiten
Stellung auf demselben Feld. Um die Suche nach ähnlichen Stellungen zu ermöglichen, gibt es
die Operationen
•
•
•
count : material x string -> int
count : material x int -> int
=, < : material x material -> bool
die die Anzahl der Figuren eines bestimmten Typs bzw. die Anzahl aller Figuren ermitteln oder
einen Vergleich des Materials erlauben.
Da die Bewegung einer Figur auch als moving point aufgefaßt werden kann, soll es möglich sein,
eine komplette Schachpartie in eine Menge von Tupeln des Schemas [Piece: string, White:
bool, Route: mpoint] zu konvertieren. Jede Figur wird so durch ein Tupel dargestellt, welches
die Information über all seine Bewegungen enthält. Dazu soll der Operator
•
movingpoints : chessgame -> stream(tuple([Piece: string,
White: bool, Route: mpoint]))
implementiert werden.
Beispielanfragen
Angenommen games sei eine Relation vom Typ rel(tuple([Match: chessgame])), in welchen
Partien wurde die weiße Dame gefangen?
query games feed extendstream[Move: .Match moves]
filter[.Move captured “Queen“] consume;
Finde alle Paare von Partien, in denen nach dem 20. Zug dasselbe Material bzw. dieselbe Stellung
auf dem Brett steht:
let games_20 = games feed extend[Pos20: getpos(40, .Match)]
extend[Mat20: .Pos20 pieces] consume;
query games_20 feed games_20 feed {x} hashjoin[Mat20, Mat20_x, 9997] consume;
query games_20 feed games_20 feed {x} hashjoin[Pos20, Pos20_x, 9997] consume;
Finde alle Paare von Partien, in denen nach dem 20. Zug eine Stellung in der Stellung der anderen
enthalten ist, jedoch nur bezogen auf das Zentrum des Spielbretts:
query games_20 feed games_20 feed {x}
symmjoin[range(.Pos20, “c“, 3, “f“, 8)
includes range(..Pos20,
“c“, 3, “f“, 8)] consume;
–
3
9
–
Graphen in SECONDO
In der Informatik werden Graphen häufig verwendet, um Beziehungen zwischen Objekten zu
beschreiben und zu visualisieren. Die Anwendungsfelder reichen dabei von E/R-Diagrammen
über Flußdiagramme bis hin zu Netzwerken. In SECONDO sollen nun Typen zur Darstellung von
gerichteten, kantenbewerteten Graphen bereit gestellt werden, nämlich die Typen graph, edge,
vertex und path. Neben der Möglichkeit, Graphen in SECONDO direkt als Konstanten zu definieren, soll es erlaubt sein, sie auch aus Relationen bzw. Tupelströmen zu erzeugen. Dabei wird das
Ergebnis eines join-Operators eingesammelt und als Kantenmenge eines Graphen interpretiert.
Zu beachten ist, daß der Anwender vor der Benutzung des dafür benötigten constGraph-Operators sicher stellen muß, daß alle verschiedenen Tupel aller verwendeten Relationen mit unterschiedlichen Nummern indiziert sind. Dies ist damit begründet, daß diese Indizierung bei der
Graphkonstruktion zur Identifizierung gleicher Knoten verwendet wird.
Zur Vereinfachung der späteren Visualisierung kann für jeden Knoten eine räumliche Information
in Form eines point-Objektes angegeben werden. Diese Information wird dazu genutzt, die Darstellung eines Graphen, der aus geometrischen Objekten abgeleitet wurde, in einem SECONDOViewer einigermaßen realitätsgetreu zu halten.
Neben den oben angegebenen Typen soll die zu implementierende GraphAlgebra noch mindestens die folgenden Operatoren enthalten:
• constGraph: stream(Tuple) x int_attr x int_attr x (Tuple -> real) -> graph
Erzeugt einen Graphen aus einem Tupelstrom. Die Attributnamen geben Attribute vom
Integer-Typ für die oben beschriebenen Tupelnummern an, während der vierte Parameter
für die Kantenmarkierung verwendet wird.
• constGraph: stream(Tuple) x int_attr x int_attr x (Tuple -> real)
x point_attr x point_attr
-> graph
Arbeitet wie der vorige Operator. Zusätzlich werden Attributnamen von point-Objekten
für die beiden Knoten übergeben.
• vertices: graph -> stream(tuple([Vertex: vertex]))
Erzeugt einen Strom von vertex-Tupeln, der alle Knoten des Graphen in ungeordneter Reihenfolge enthält.
• edges: graph -> stream(tuple([Edge: edge]))
Erzeugt einen Strom von edge-Tupeln, der alle Kanten des Graphen in ungeordneter Reihenfolge enthält.
• equal: graph x graph -> bool
Liefert TRUE, falls beide Graphen gleich bzgl. ihrer Knoten und Kanten sind. Sonst FALSE.
• partOf: graph x graph -> bool
Liefert TRUE, falls der zweite angegebene Graph ein Teilgraph des ersten Graphen ist. Sonst
FALSE.
• connectedComponents: graph -> stream(tuple([Graph: graph]))
Erzeugt einen Strom von Graphen, die den starken Zusammenhangskomponenten des angegebenen Graphen entsprechen.
–
10
–
• merge: graph x graph -> graph
Die zwei angegebenen Graphen werden zu einem einzelnen Graphen verschmolzen. Knoten
mit identischen Nummern werden einfach verschmolzen, während bei zwei gleichen Kanten, die aber eine unterschiedliche Bewertung haben, die „billigere“ Kante verwendet wird.
• maxDegree/minDegree: graph -> int
Gibt den maximalen/minimalen Grad des Graphen zurück.
• theVertex: graph x int -> vertex
Gibt den Knoten des gegebenen Graphen zurück, der den übergebenen Integer-Wert als
Index verwendet. Ist der Wert nicht vorhanden, ist das resultierende vertex-Objekt undefiniert.
• shortestPath: graph x vertex x vertex -> path
Erzeugt ein path-Objekt, das den kürzesten Pfad vom ersten zum zweiten Knoten
beschreibt.
• edges: path -> stream(tuple([Edge: edge]))
Erzeugt einen edge-Tupelstrom, in dem die Kanten in geordneter Reihenfolge geliefert werden.
• vertices: path -> stream(tuple([Vertex: vertex]))
Erzeugt einen vertex-Tupelstrom, in dem die Knoten in geordneter Reihenfolge geliefert
werden.
• circle: graph x vertex x real -> graph
Erzeugt einen Teilgraphen des angegeben Graphen G, der, ausgehend von dem gegebenen
Knoten k, alle weiteren Knoten (und die verbindenden Kanten) von G enthält, die maximal
so weit entfernt von k sind, wie es der dritte Parameter angibt. Die Entfernung ist dabei als
Netzwerkentfernung zu interpretieren, d. h. die Entfernung zweier durch eine Kante verbundenen Knoten ist genau gleich der Kantenbewertung dieser Kante.
• key: vertex -> int
pos: vertex -> point
source: edge -> int
target: edge -> int
cost: edge -> real
Mittels dieser Operatoren können die Daten von vertex- und edge-Objekten ausgelesen
werden.
Für die Berechnung der point-Objekte, die für den constGraph-Operator benötigt werden, ist es
nötig, einen (überladenen) Operator centerPoint: (point, points, line, region) ->
point zu implementieren, der einen Punkt berechnet, der das entsprechende Objekt möglichst gut
repräsentiert.
Zur Visualisierung von Graphen soll der Hoese-Viewer um entsprechende Funktionalitäten erweitert werden. Hierbei ist zu beachten, daß gerichtete Graphen dargestellt werden müssen, d.h. es
müssen Kanten mit Pfeilen ergänzt werden.
Der schwierigste Aspekt bei der Visualisierung von Graphen ist die Verteilung der Knoten in der
Ebene. Sofern point-Objekte für die Knoten des Graphen vorhanden sind, sollen diese für die
–
11
–
Verteilung der Knoten genutzt werden. Andernfalls soll bei kantenbewerteten Graphen die Kantenbewertung für die Plazierung verwendet werden, d.h. Knoten die durch Kanten mit niedriger
Bewertung verbunden sind, sollen räumlich näher zueinander plaziert werden als welche, die mit
höherwertigen Kanten verbunden sind. Hierbei macht es Sinn, sich zunächst drei verbundene
Knoten auszusuchen und diese in der Ebene gemäß ihrer Abstände zu plazieren. Alle anderen
Knoten können dann relativ zu diesen Knoten plaziert werden.
Für die Plazierung der Knoten, also die Berechnung von passenden point-Objekten, ist der folgende Operator zu implementieren:
• placeNodes: graph -> graph
Erzeugt bzw. verändert die point-Objekte des übergebenen graph-Objekts derart, daß entsprechend der obigen Beschreibung - eine möglichst gute Darstellung im Viewer erreicht
wird.
Der Hoese-Viewer soll vor der Anzeige eines graph-Objekts prüfen, ob für jeden Knoten pointDaten vorhanden sind. Ist dies nicht der Fall, wird eine Anzeige des Graphen mit einer entsprechenden Fehlermeldung verweigert. Infolgedessen sollte in den meisten Fällen ein placeNodesAufruf vor der Anzeige des Graphen erfolgen.
Herunterladen