Praktikum 3: Klassen im Zusammenspiel 1. Lernziele
Die folgenden, in der Vorlesung behandelten Themen sollen vertieft und angewendet wer- den:
• Objektorientierte Programmierung
• Klassen- und Objektmodell
• Einbinden von externen Bibliotheken
2. Aufgabe
In diesem Praktikum soll ein Modell f¨ur die Implementierung eines gewichteten, gerichte- ten Graphen entwickelt werden.
Teil 1 (Datenstruktur): Graphen (siehe Abbildung 1a) bestehen aus Knoten und Kan- ten. Knoten sind darin als Kreise und Kanten als Pfeile dargestellt. Erstellen Sie hierzu die Klasse DiGraphals Hauptklasse f¨ur den Graphen, sowie die Klassen Node und Edge, f¨ur die Knoten und Kanten.
Da ein Graph aus einer beliebigen Anzahl von Knoten und Kanten bestehen kann, muss eine geeignete Datenstruktur zur Speicherung der Objekte gew¨ahlt werden.
Die g¨angigste Form einen Graphen in einem Programm darzustellen ist die soge- nannte Adjazenzliste (siehe Abbildung 1b). In einer Adjazenzliste werden zu jedem Knoten alle von ihm ausgehenden Kanten abgespeichert. Realisieren Sie dies in Ihrer Implementierung, indem Sie der KlasseNode, die in der Vorlesung entwickelte Liste hinzuf¨ugen.
In den Klassen m¨ussen zus¨atzlich folgende Methoden vorhanden sein:
DiGraph:
Methoden
• void addNode(Node * node)
F¨ugt die Adresse eines Klassenobjekts vom Typ Node dem Graphen hinzu.
• void addEdge(std::string key1, std::string key2, float weight) Erstellt ein neues Klassenobjekt vom Typ Edge mit Startknoten key1, End- knoten key2 sowie einem Kantengewicht von weight. Anschließend wird die Kante der Adjazenzliste des Knotenskey1 hinzugef¨ugt.
• Liste<Node*> getNeighbours(std::string key)
Gibt eine Liste aller benachbarter Knoten des Knotens mit dem Schl¨ussel key zur¨uck.
• Liste<Edge*> getEdges(std::string key)
Gibt eine Liste aller abgehenden Kanten des Knotens mit dem Schl¨ussel key zur¨uck.
• Liste<Node*> getNodes()
Gibt eine Liste aller Knoten des Graphen zur¨uck.
Attribute
• Node** nodes
Array von Knoten mit dem Bezeichnernodes, in dem alle Knoten des Graphen gespeichert sind.
Node:
Methoden
• Getter- und Setter-Methoden, um die Attribute in der Klasse Node zu setzen und auszulesen:
– std::string getKey(void) – int getPositionX(void) – int getPositionY(void) – Liste<Edge*> getEdges(void)
– void setKey(std::string new key) – void setPositionX(int x)
– void setPositionY(int y) – void setNewEdge(Edge * edge) Attribute
• std::string node key
Attribut zur eindeutigen Identifikation des Knotens.
• int position xund int position y
Attribute f¨ur die Position des Knotens zur sp¨ateren Darstellung in der show Methode im Graphen.
• Liste<Edge*> edges
Attribut f¨ur die Adjazenzliste im Knoten, in der die Adressen aller ausgehenden Kanten gespeichert sind.
Edge:
Methoden
• Getter- und Setter-Methoden, um die Attribute in der Klasse Edge zu setzen und auszulesen:
– float getWeight(void) – Node * getStartNode(void) – Node * getEndNode(void)
– void setWeight(float w) – void setStartNode(Node * n) – void setEndNode(Node * n)
• Getter-Methoden:getWeight(), getStartNode(),getEndNode() Attribute
• Node *startnode und Node *endnode
Zum Speichern der Adressen der verbundenen Knoten.
• float weight
Zum Speichern des Kantengewichts.
Erstellen Sie f¨ur jede Klasse geeignete Konstruktoren und Destruktoren.
Liste:
Methoden
• unsigned int size(void)
Gibt die Anzahl der in der Liste vorhandenen Elemente zur¨uck.
• Liste(const Liste &old) Kopierkonstruktor f¨ur die Liste.
Teil 2 (Darstellung): Damit der Graph in einer anschaulichen Form auf dem Bildschirm ausgegeben werden kann, wird in diesem Praktikum die externe Bibliothek SFML verwendet. Die Einrichtung von SFML auf ihrem Privatsystem, zur Vorarbeit f¨ur das Praktikum, k¨onnen Sie den allgemeinen Praktikumsinformationen entnehmen.
Um die Darstellung des Graphen lose gekoppelt von der Graph-Implementierung zu halten, erstellen Sie die Klasse SFMLGraphVisualizer:
Attribute
• sf::RenderWindow window;
Attribut vom SFML Fensterdatentyp zur Visualisierung des gezeichneten Gra-
Methoden
• void visualize(DiGraph &graph)
Zeichnet den Graphen in ein neues Fensterimg
Wenn Sie die Funktionen gerne selbst implementieren m¨ochten, k¨onnen Sie hierzu die SFML Dokumentation unter http://www.sfml-dev.org nutzen. Eine Beispiel Implementierung, die allerdings noch vervollst¨andigt werden muss, finden Sie im Anhang A.
Teil 3 (Hauptprogramm): Erstellen Sie ein Hauptprogramm, welches einen beliebigen Graphen (z.B. den Graphen aus Abb. 1a) erzeugt und auf dem Bildschirm ausgibt.
3. Testat
Voraussetzung ist jeweils ein fehlerfreies, korrekt formatiertes Programm. Der korrekte Programmlauf muss nachgewiesen werden. Sie m¨ussen in der Lage sein, Ihr Programm im Detail zu erkl¨aren und ggf. auf Anweisung hin zu modifizieren.
Das Praktikum muss sp¨atestens zu Beginn des n¨achsten Praktikumtermins vollst¨andig bearbeitet und abtestiert sein.
A. Visualisierung des Graphen mit SFML
1 # i n c l u d e < S F M L / G r a p h i c s . hpp >
2 # i n c l u d e < S F M L / W i n d o w . hpp >
3 # i n c l u d e < m a t h . h >
4 # i n c l u d e < sstream >
5
6 # d e f i n e N O D E R A D I U S 30
7 u s i n g n a m e s p a c e std ;
8 9
10 c l a s s S F M L G r a p h V i s u a l i z e r {
11 p r i v a t e:
12 sf :: R e n d e r W i n d o w w i n d o w ;
13 sf :: F o n t f o n t ;
14
15 p u b l i c:
16
17 S F M L G r a p h V i s u a l i z e r () {
18 // l o a d my f o n t
19 this- > f o n t . l o a d F r o m F i l e (" a r i a l . ttf ");
20 }
21
22 v o i d v i s u a l i z e ( D i G r a p h & g ) {
23
24 w i n d o w . c r e a t e ( sf :: V i d e o M o d e (1024 , 768) , " m y G r a p h ");
25
26 Liste < N o d e * > n o d e s = g . g e t N o d e s ();
27
28 w h i l e ( w i n d o w . i s O p e n ()) {
29 // P r o c e s s e v e n t s
30 sf :: E v e n t e v e n t ;
31
32 w h i l e ( w i n d o w . p o l l E v e n t ( e v e n t )) {
33 // C l o s e w i n d o w : e x i t
34 if ( e v e n t . t y p e == sf :: E v e n t :: C l o s e d )
35 w i n d o w . c l o s e ();
36 }
37
38 // C l e a r s c r e e n
39 w i n d o w . c l e a r ( sf :: C o l o r :: W h i t e );
40 for (u n s i g n e d int i = 0; i < n o d e s . s i z e (); i ++) {
41 N o d e * n o d e = n o d e s . g e t V a l u e A t ( i );
42
43 sf :: C o l o r c o l o r (255 , 0 , 0);
44 d r a w N o d e (* node , c o l o r );
45
46 // A u s g e h e n d e K a n t e n e i n z e i c h n e n
47 Liste < E d g e * > e d g e s = g . g e t E d g e s ( node - > g e t K e y ( ) ) ;
48
49 for (u n s i g n e d int j = 0; j < e d g e s . s i z e (); j ++) {
50 d r a w E d g e (*( e d g e s . g e t V a l u e A t ( j )) , sf :: C o l o r :: Black ,
52 }
53 }
54 // U p d a t e the w i n d o w
55 w i n d o w . d i s p l a y ();
56 }
57 }
58 59
60 v o i d d r a w N o d e ( N o d e & node , sf :: C o l o r n o d e C o l o r ) {
61
62 sf :: C i r c l e S h a p e C i r c l e ( N O D E R A D I U S );
63 C i r c l e . s e t P o s i t i o n ( n o d e . g e t P o s i t i o n X () - N O D E R A D I U S ,
64 n o d e . g e t P o s i t i o n Y () - N O D E R A D I U S );
65 C i r c l e . s e t F i l l C o l o r ( sf :: C o l o r :: W h i t e );
66 C i r c l e . s e t O u t l i n e C o l o r ( n o d e C o l o r );
67 C i r c l e . s e t O u t l i n e T h i c k n e s s ( 5 ) ;
68
69 w i n d o w . d r a w ( C i r c l e );
70
71 sf :: T e x t L a b e l ( n o d e . g e t K e y () , font , 3 2 ) ;
72 L a b e l . s e t P o s i t i o n ( n o d e . g e t P o s i t i o n X () - N O D E R A D I U S / 2 + 5 ,
73 n o d e . g e t P o s i t i o n Y () - N O D E R A D I U S / 2 - 5);
74 L a b e l . s e t F i l l C o l o r ( sf :: C o l o r :: B l u e );
75
76 w i n d o w . d r a w ( L a b e l );
77 }
78 79
80 v o i d d r a w E d g e ( E d g e & edge , sf :: C o l o r color , d o u b l e weight ,
81 int t h i c k n e s s = 1 , int a r r o w M a g n i t u d e = 20) {
82
83 sf :: V e c t o r 2 f p ( e d g e . g e t S t a r t N o d e () - > g e t P o s i t i o n X () ,
84 e d g e . g e t S t a r t N o d e () - > g e t P o s i t i o n Y ( ) ) ;
85 sf :: V e c t o r 2 f q ( e d g e . g e t E n d N o d e () - > g e t P o s i t i o n X () ,
86 e d g e . g e t E n d N o d e () - > g e t P o s i t i o n Y ( ) ) ;
87 88
89 // B e r e c h n e den W i n k e l
90 c o n s t d o u b l e PI = 3 . 1 4 1 5 9 2 6 5 3 ;
91 d o u b l e a n g l e = a t a n 2 ((d o u b l e) p . y - q . y , (d o u b l e) p . x - q . x );
92
93 // B e r e c h n e v e r k u e r z t e n P f e i l
94 q . x = (int) ( q . x + N O D E R A D I U S * cos ( a n g l e ));
95 q . y = (int) ( q . y + N O D E R A D I U S * sin ( a n g l e ));
96 p . x = (int) ( p . x - N O D E R A D I U S * cos ( a n g l e ));
97 p . y = (int) ( p . y - N O D E R A D I U S * sin ( a n g l e ));
98
99 sf :: V e r t e x l i n e [2] =
100 {
101 sf :: V e r t e x ( sf :: V e c t o r 2 f ( p . x , p . y ) , c o l o r ) ,
102 sf :: V e r t e x ( sf :: V e c t o r 2 f ( q . x , q . y ) , c o l o r )
103 };
104
105 // t h i c k n e s s
106 w i n d o w . d r a w ( line , 2 , sf :: L i n e s );
107
108 std :: s t r i n g s t r e a m w e i g h t s t r i n g ;
109 w e i g h t s t r i n g < < w e i g h t ;
110 sf :: T e x t L a b e l w e i g h t ( w e i g h t s t r i n g . str () , font , 3 2 ) ;
111 int s i z e = s q r t ( pow ( p . x - q . x , 2) + pow ( p . y - q . y , 2 ) ) ;
112 L a b e l w e i g h t . s e t P o s i t i o n ( p . x - ( s i z e / 2)* cos ( a n g l e ) + 1 0 * sin ( a n g l e ) ,
113 p . y - ( s i z e / 2)* sin ( a n g l e ) + 1 0 * cos ( a n g l e ));
114 L a b e l w e i g h t . s e t F i l l C o l o r ( sf :: C o l o r :: B l u e );
115 w i n d o w . d r a w ( L a b e l w e i g h t );
116
117 // E r s t e s S e g m e n t
118 p . x = (int) ( q . x + a r r o w M a g n i t u d e * cos ( a n g l e + PI / 8 ) ) ;
119 p . y = (int) ( q . y + a r r o w M a g n i t u d e * sin ( a n g l e + PI / 8 ) ) ;
120 sf :: V e r t e x f i r s t [2] =
121 {
122 sf :: V e r t e x ( sf :: V e c t o r 2 f ( p . x , p . y ) , c o l o r ) ,
123 sf :: V e r t e x ( sf :: V e c t o r 2 f ( q . x , q . y ) , c o l o r )
124 };
125 w i n d o w . d r a w ( first , 2 , sf :: L i n e s );
126 127
128 // Z w e i t e s S e g m e n t
129 p . x = (int) ( q . x + a r r o w M a g n i t u d e * cos ( a n g l e - PI / 8 ) ) ;
130 p . y = (int) ( q . y + a r r o w M a g n i t u d e * sin ( a n g l e - PI / 8 ) ) ;
131 sf :: V e r t e x s e c o n d [2] =
132 {
133 sf :: V e r t e x ( sf :: V e c t o r 2 f ( p . x , p . y ) , c o l o r ) ,
134 sf :: V e r t e x ( sf :: V e c t o r 2 f ( q . x , q . y ) , c o l o r )
135 };
136 w i n d o w . d r a w ( second , 2 , sf :: L i n e s );
137 }
138 };
(a) Gerichteter, gewichteter Graph
(b) dazugeh¨orige Adjazenzliste
Abbildung 1: Datenstruktur “DiGraph”