1 #include "COGDFLayout.h"
2 
3 #include <qvge/CNodeEditorScene.h>
4 #include <qvge/CNode.h>
5 #include <qvge/CDirectEdge.h>
6 
7 #include <ogdf/fileformats/GraphIO.h>
8 
9 #include <ogdf/basic/Graph.h>
10 #include <ogdf/basic/GraphAttributes.h>
11 #include <ogdf/basic/LayoutModule.h>
12 
13 #include <ogdf/misclayout/BalloonLayout.h>
14 
15 #include <iostream>     // std::ios, std::istream, std::cout
16 #include <fstream>      // std::filebuf
17 
18 #include <QMap>
19 #include <QApplication>
20 #include <QFileInfo>
21 
22 
COGDFLayout()23 COGDFLayout::COGDFLayout()
24 {
25 }
26 
27 
toVariant(ogdf::Shape shape)28 static QVariant toVariant(ogdf::Shape shape)
29 {
30     using namespace ogdf;
31 
32     switch (shape)
33     {
34     case Shape::Rect:           return "square";
35     case Shape::RoundedRect:    return "rsquare";
36     case Shape::Ellipse:        return "disc";
37     case Shape::Triangle:       return "triangle";
38     case Shape::Pentagon:       return "star";
39     case Shape::Hexagon:        return "hexagon";
40     case Shape::Octagon:        return "octagon";
41     case Shape::Rhomb:          return "diamond";
42     case Shape::Trapeze:        return "trapeze";
43     case Shape::Parallelogram:  return "parallelogram";
44     case Shape::InvTriangle:    return "triangle2";
45     case Shape::InvTrapeze:     return "trapeze2";
46     case Shape::InvParallelogram:  return "parallelogram2";
47     case Shape::Image:          return "image";
48     }
49 
50     return QVariant();
51 }
52 
53 
toVariant(ogdf::StrokeType stroke)54 static QVariant toVariant(ogdf::StrokeType stroke)
55 {
56     using namespace ogdf;
57 
58     switch (stroke)
59     {
60     case StrokeType::Solid:         return "solid";
61     case StrokeType::Dash:          return "dashed";
62     case StrokeType::Dot:           return "dotted";
63     case StrokeType::Dashdot:       return "dashdot";
64     case StrokeType::Dashdotdot:    return "dashdotdot";
65     default:;
66     }
67 
68     return QVariant();
69 }
70 
71 
doLayout(ogdf::LayoutModule & layout,CNodeEditorScene & scene)72 void COGDFLayout::doLayout(ogdf::LayoutModule &layout, CNodeEditorScene &scene)
73 {
74 	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
75 
76     ogdf::Graph G;
77     ogdf::GraphAttributes GA(G, ogdf::GraphAttributes::nodeGraphics | ogdf::GraphAttributes::edgeGraphics);
78 
79     // qvge -> ogdf
80     auto nodes = scene.getItems<CNode>();
81     auto edges = scene.getItems<CEdge>();
82 
83     QMap<CNode*, ogdf::node> nodeMap;
84 
85     for (CNode* node : nodes)
86     {
87         ogdf::node n = G.newNode();
88 //        GA.x(n) = node->pos().x();
89 //        GA.y(n) = node->pos().y();
90         GA.x(n) = 0;
91         GA.y(n) = 0;
92 
93         nodeMap[node] = n;
94     }
95 
96     for (CEdge* edge: edges)
97     {
98         ogdf::node n1 = nodeMap[edge->firstNode()];
99         ogdf::node n2 = nodeMap[edge->lastNode()];
100         ogdf::edge e = G.newEdge(n1, n2);
101     }
102 
103 
104     // ogdf layout
105     layout.call(GA);
106 
107 
108     // ogdf -> qvge
109     for (auto it = nodeMap.begin(); it != nodeMap.end(); ++it)
110     {
111         CNode* node = it.key();
112         ogdf::node n = it.value();
113 
114         node->setPos(GA.x(n), GA.y(n));
115     }
116 
117     // finalize
118     scene.setSceneRect(scene.itemsBoundingRect());
119 
120     scene.addUndoState();
121 
122 
123 	QApplication::restoreOverrideCursor();
124 }
125 
126 
graphTopologyToScene(const ogdf::Graph & G,const ogdf::GraphAttributes & GA,CNodeEditorScene & scene)127 void COGDFLayout::graphTopologyToScene(const ogdf::Graph &G, const ogdf::GraphAttributes &GA, CNodeEditorScene &scene)
128 {
129     //scene.reset();
130 	scene.initialize();
131 
132     // create nodes
133     QMap<ogdf::node, CNode*> nodeMap;
134 
135     for (auto n: G.nodes)
136     {
137         CNode* node = new CNode;
138         scene.addItem(node);
139 
140         nodeMap[n] = node;
141 
142         if (GA.has(GA.nodeGraphics))
143         {
144             node->setPos(GA.x(n), GA.y(n));
145         }
146     }
147 
148     for (auto e: G.edges)
149     {
150 		CEdge* edge = new CDirectEdge;
151         scene.addItem(edge);
152 
153         edge->setFirstNode(nodeMap[e->source()]);
154         edge->setLastNode(nodeMap[e->target()]);
155     }
156 
157     // finalize
158     scene.setSceneRect(scene.itemsBoundingRect());
159 }
160 
161 
graphToScene(const ogdf::Graph & G,const ogdf::GraphAttributes & GA,CNodeEditorScene & scene)162 void COGDFLayout::graphToScene(const ogdf::Graph &G, const ogdf::GraphAttributes &GA, CNodeEditorScene &scene)
163 {
164     scene.reset();
165 
166     // create nodes
167     QMap<ogdf::node, CNode*> nodeMap;
168 
169     for (auto n: G.nodes)
170     {
171         CNode* node = scene.createNewNode();
172         scene.addItem(node);
173 
174         nodeMap[n] = node;
175 
176         if (GA.has(GA.nodeGraphics))
177         {
178 			node->setPos(GA.x(n), GA.y(n));
179             node->setAttribute("size", QSizeF(GA.width(n), GA.height(n)));
180             node->setAttribute("shape", toVariant(GA.shape(n)));
181         }
182 
183         if (GA.has(GA.nodeStyle))
184         {
185             auto c = GA.fillColor(n);
186             node->setAttribute("color", QColor(c.red(), c.green(), c.blue()));
187 
188 			auto sc = GA.strokeColor(n);
189 			node->setAttribute("stroke.color", QColor(c.red(), c.green(), c.blue()));
190 
191 			node->setAttribute("stroke.style", toVariant(GA.strokeType(n)));
192 			node->setAttribute("stroke.size", GA.strokeWidth(n));
193         }
194 
195 		int id = -1;
196 		if (GA.has(GA.nodeId)) {
197 			id = GA.idNode(n);
198 			if (id >= 0) node->setId(QString::number(id));
199 		}
200 
201         if (GA.has(GA.nodeLabel)) {
202 			auto label = QString::fromStdString(GA.label(n));	// label -> ID
203 			if (id < 0 && label.size()) node->setId(label);
204 		}
205 
206 		if (GA.has(GA.nodeTemplate)) {
207 			auto label = QString::fromStdString(GA.templateNode(n));	// comment -> label
208 			if (label.size())
209 				node->setAttribute("label", label);
210 		}
211 
212         if (GA.has(GA.nodeWeight))
213             node->setAttribute("weight", GA.weight(n));
214     }
215 
216 
217     for (auto e: G.edges)
218     {
219 		CEdge* edge = scene.createNewConnection();
220         scene.addItem(edge);
221 
222         edge->setFirstNode(nodeMap[e->source()]);
223         edge->setLastNode(nodeMap[e->target()]);
224 
225         if (GA.has(GA.edgeDoubleWeight))
226             edge->setAttribute("weight", GA.doubleWeight(e));
227         else if (GA.has(GA.edgeIntWeight))
228             edge->setAttribute("weight", GA.intWeight(e));
229 
230         if (GA.has(GA.edgeLabel))
231             edge->setAttribute("label", QString::fromStdString(GA.label(e)));
232 
233         if (GA.has(GA.edgeStyle))
234         {
235             auto c = GA.strokeColor(e);
236             edge->setAttribute("color", QColor(c.red(), c.green(), c.blue()));
237 
238             edge->setAttribute("style", toVariant(GA.strokeType(e)));
239         }
240     }
241 
242 
243     // finalize
244     scene.setSceneRect(scene.itemsBoundingRect());
245 }
246 
247 
248 // file IO
249 
loadGraph(const QString & filename,CNodeEditorScene & scene,QString * lastError)250 bool COGDFLayout::loadGraph(const QString &filename, CNodeEditorScene &scene, QString* lastError)
251 {
252     ogdf::Graph G;
253     ogdf::GraphAttributes GA(G, -1);   // all attrs
254 
255     QString format = QFileInfo(filename).suffix().toLower();
256 
257     std::filebuf fb;
258     if (!fb.open (filename.toStdString(), std::ios::in))
259         return false;
260 
261     std::istream is(&fb);
262 
263     bool ok = false;
264 
265 	if (format == "gml")
266 	{
267         ok = ogdf::GraphIO::readGML(GA, G, is);
268 	}
269 	else
270 	if (format == "dot" || format == "gv")
271 	{
272         ok = ogdf::GraphIO::readDOT(GA, G, is);
273 
274 		// normalize node positions
275 		if (ok && GA.has(GA.nodeGraphics))
276 		{
277 			for (auto n : G.nodes)
278 			{
279                 if (GA.x(n) != 0.0 || GA.y(n) != 0.0)
280 				{
281 					GA.x(n) *= 72.0;
282 					GA.y(n) *= -72.0;
283 					GA.width(n) *= 72.0;
284 					GA.height(n) *= 72.0;
285 				}
286 			}
287 		}
288 	}
289 
290     if (ok)
291     {
292 		autoLayoutIfNone(G, GA);
293         graphToScene(G, GA, scene);
294 		scene.addUndoState();
295 	}
296 
297     fb.close();
298 
299     return ok;
300 }
301 
302 
303 // privates
304 
autoLayoutIfNone(const ogdf::Graph & G,ogdf::GraphAttributes & GA)305 bool COGDFLayout::autoLayoutIfNone(const ogdf::Graph &G, ogdf::GraphAttributes &GA)
306 {
307 	if (GA.has(GA.nodeGraphics))
308 	{
309 		for (auto n : G.nodes)
310 		{
311             if (GA.x(n) != 0.0 || GA.y(n) != 0.0)
312 				return false;
313 		}
314 	}
315 	else
316 		return false;
317 
318 	ogdf::BalloonLayout layout;
319 	layout.call(GA);
320 
321 	// factor x2
322 	for (auto n : G.nodes)
323 	{
324 		GA.x(n) *= 2.0;
325 		GA.y(n) *= 2.0;
326 	}
327 
328 	return true;
329 }
330