1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestGraphHierarchicalBundle.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16 Copyright 2008 Sandia Corporation.
17 Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18 the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20
21 #include "vtkActor.h"
22 #include "vtkActor2D.h"
23 #include "vtkCommand.h"
24 #include "vtkGraph.h"
25 #include "vtkGraphHierarchicalBundle.h"
26 #include "vtkGraphLayout.h"
27 #include "vtkGraphToPolyData.h"
28 #include "vtkInteractorStyleImage.h"
29 #include "vtkLookupTable.h"
30 #include "vtkMath.h"
31 #include "vtkMutableDirectedGraph.h"
32 #include "vtkPointData.h"
33 #include "vtkPoints.h"
34 #include "vtkPolyDataMapper.h"
35 #include "vtkProperty.h"
36 #include "vtkRandomGraphSource.h"
37 #include "vtkRegressionTestImage.h"
38 #include "vtkRenderer.h"
39 #include "vtkRenderWindow.h"
40 #include "vtkRenderWindowInteractor.h"
41 #include "vtkSmartPointer.h"
42 #include "vtkSplineFilter.h"
43 #include "vtkStringArray.h"
44 #include "vtkTextProperty.h"
45 #include "vtkTree.h"
46 #include "vtkTreeLayoutStrategy.h"
47 #include "vtkVariant.h"
48 //#include "vtkXMLTreeReader.h"
49
50 #define VTK_CREATE(type, name) \
51 vtkSmartPointer<type> name = vtkSmartPointer<type>::New()
52
53
54 #define RANDOM_TREE 0
55 #define STRUCTURED_TREE 1
56 #define VTK_SOURCES_TREE 2
57
TestGraphHierarchicalBundle(int argc,char * argv[])58 int TestGraphHierarchicalBundle(int argc, char* argv[])
59 {
60 int treeType = STRUCTURED_TREE;
61 const char* file = 0;
62 bool showTree = false;
63 vtkIdType numVertices = 200;
64 vtkIdType numEdges = 100;
65 double bundlingStrength = 0.9;
66 bool radial = true;
67 double angle = 360;
68 double logSpacing = 0.8;
69 double leafSpacing = 0.9;
70
71 for (int i = 1; i < argc; i++)
72 {
73 if (!strcmp(argv[i], "-I"))
74 {
75 continue;
76 }
77 if (!strcmp(argv[i], "-D"))
78 {
79 i++;
80 continue;
81 }
82 if (!strcmp(argv[i], "-T"))
83 {
84 i++;
85 continue;
86 }
87 if (!strcmp(argv[i], "-V"))
88 {
89 i++;
90 continue;
91 }
92 if (!strcmp(argv[i], "-t"))
93 {
94 showTree = true;
95 continue;
96 }
97 if (!strcmp(argv[i], "-S"))
98 {
99 radial = false;
100 continue;
101 }
102 if (!strcmp(argv[i], "-A"))
103 {
104 i++;
105 angle = atof(argv[i]);
106 continue;
107 }
108 if (!strcmp(argv[i], "-L"))
109 {
110 i++;
111 logSpacing = atof(argv[i]);
112 continue;
113 }
114 if (!strcmp(argv[i], "-f"))
115 {
116 i++;
117 leafSpacing = atof(argv[i]);
118 continue;
119 }
120 if (!strcmp(argv[i], "-r"))
121 {
122 treeType = RANDOM_TREE;
123 i++;
124 numVertices = atoi(argv[i]);
125 i++;
126 numEdges = atoi(argv[i]);
127 continue;
128 }
129 if (!strcmp(argv[i], "-s"))
130 {
131 treeType = STRUCTURED_TREE;
132 i++;
133 numVertices = atoi(argv[i]);
134 i++;
135 numEdges = atoi(argv[i]);
136 continue;
137 }
138 if (!strcmp(argv[i], "-v"))
139 {
140 treeType = VTK_SOURCES_TREE;
141 i++;
142 file = argv[i];
143 continue;
144 }
145 if (!strcmp(argv[i], "-b"))
146 {
147 i++;
148 bundlingStrength = atof(argv[i]);
149 continue;
150 }
151
152 cerr << argv[0] << " Options:\n"
153 << " -I : interactive\n"
154 << " -r #vertices #edges: show random tree with random edges\n"
155 << " -s #vertices #edges: show structured tree with structured edges\n"
156 //<< " -v filename : show VTK data in XML file\n"
157 << " -b strength : bundling strength (0.0 to 1.0; default 0.8)\n"
158 << " -S : standard tree layout (default radial)\n"
159 << " -A angle : tree sweep angle (default 360)\n"
160 << " -L logspacing : tree logspacing (0.0 to 1.0; default 0.8)\n"
161 << " -f leafspacing : tree leaf spacing\n"
162 << " -t : show tree instead of edge bundles\n";
163 return 0;
164 }
165 vtkIdType levelOneVertices = static_cast<vtkIdType>(sqrt(static_cast<float>(numVertices)));
166
167 // Create the graph.
168
169 vtkGraph *graph = 0;
170 if (treeType == RANDOM_TREE)
171 {
172 VTK_CREATE(vtkRandomGraphSource, source);
173 source->SetNumberOfVertices(numVertices);
174 source->SetNumberOfEdges(numEdges);
175 source->SetStartWithTree(false);
176 source->Update();
177 graph = source->GetOutput();
178
179 VTK_CREATE(vtkStringArray, nameArray);
180 nameArray->SetName("name");
181 for (vtkIdType i = 0; i < graph->GetNumberOfVertices(); i++)
182 {
183 nameArray->InsertNextValue(vtkVariant(i).ToString());
184 }
185 graph->GetVertexData()->AddArray(nameArray);
186 graph->Register(0);
187 }
188 else if (treeType == STRUCTURED_TREE)
189 {
190 vtkMutableDirectedGraph* g = vtkMutableDirectedGraph::New();
191 for (vtkIdType v = 0; v < numVertices; v++)
192 {
193 g->AddVertex();
194 }
195 for (vtkIdType e = 0; e < numEdges; e++)
196 {
197 g->AddEdge(e%numVertices, (e*e)%numVertices);
198 }
199 graph = g;
200 }
201 #if 0
202 else
203 {
204 VTK_CREATE(vtkXMLTreeReader, reader);
205 reader->SetFileName(file);
206 reader->Update();
207 graph = reader->GetOutput();
208 graph->Register(0);
209 }
210 #endif
211
212 //for (vtkIdType a = 0; a < graph->GetNumberOfEdges(); a++)
213 // {
214 // cerr << "edge " << a << ": " << graph->GetSourceVertex(a) << "," << graph->GetTargetVertex(a) << endl;
215 // }
216
217 // Create the tree.
218 VTK_CREATE(vtkMutableDirectedGraph, tree);
219 if (treeType == RANDOM_TREE)
220 {
221 tree->AddVertex();
222 for (vtkIdType i = 1; i < numVertices; i++)
223 {
224 vtkIdType parent = static_cast<vtkIdType>(vtkMath::Random(0, tree->GetNumberOfVertices()));
225 tree->AddChild(parent);
226 }
227 tree->GetVertexData()->AddArray(graph->GetVertexData()->GetAbstractArray("name"));
228 }
229 else if (treeType == STRUCTURED_TREE)
230 {
231 vtkIdType i;
232 tree->AddVertex();
233 for (i = 0; i < levelOneVertices; i++)
234 {
235 tree->AddChild(0);
236 }
237 vtkIdType levelTwoVertices = numVertices - levelOneVertices - 1;
238 for (i = 0; i < levelTwoVertices; i++)
239 {
240 tree->AddChild(static_cast<vtkIdType>(i / (levelTwoVertices / static_cast<double>(levelOneVertices)) + 1.5));
241 }
242 tree->GetVertexData()->AddArray(graph->GetVertexData()->GetAbstractArray("name"));
243 }
244 else
245 {
246 VTK_CREATE(vtkStringArray, kitNames);
247 kitNames->InsertNextValue("Common");
248 kitNames->InsertNextValue("Filtering");
249 kitNames->InsertNextValue("GenericFiltering");
250 kitNames->InsertNextValue("Graphics");
251 kitNames->InsertNextValue("Hybrid");
252 kitNames->InsertNextValue("Imaging");
253 kitNames->InsertNextValue("Infovis");
254 kitNames->InsertNextValue("IO");
255 kitNames->InsertNextValue("Parallel");
256 kitNames->InsertNextValue("Rendering");
257 kitNames->InsertNextValue("VolumeRendering");
258 kitNames->InsertNextValue("Widgets");
259
260 // Add vertices representing classes.
261 for (vtkIdType i = 0; i < graph->GetNumberOfVertices(); i++)
262 {
263 tree->AddVertex();
264 }
265
266 VTK_CREATE(vtkStringArray, extendedNameArray);
267 extendedNameArray->DeepCopy(graph->GetVertexData()->GetAbstractArray("name"));
268 extendedNameArray->SetName("name");
269
270 // Add root.
271 extendedNameArray->InsertNextValue("VTK");
272 vtkIdType root = tree->AddVertex();
273
274 // Add kit vertices.
275 for (vtkIdType k = 0; k < kitNames->GetNumberOfValues(); k++)
276 {
277 tree->AddChild(root);
278 extendedNameArray->InsertNextValue(kitNames->GetValue(k));
279 }
280
281 vtkStringArray* fileArray = vtkStringArray::SafeDownCast(
282 graph->GetVertexData()->GetAbstractArray("filename"));
283 for (vtkIdType i = 0; i < graph->GetNumberOfVertices(); i++)
284 {
285 vtkStdString curFile = fileArray->GetValue(i);
286 bool found = false;
287 vtkIdType k;
288 for (k = 0; k < kitNames->GetNumberOfValues(); k++)
289 {
290 vtkStdString kit = kitNames->GetValue(k);
291 if (curFile.substr(0, kit.length()) == kit)
292 {
293 tree->AddEdge(root + 1 + k, i);
294 found = true;
295 break;
296 }
297 }
298 if (!found)
299 {
300 cerr << "cannot find match for filename " << file << endl;
301 }
302 }
303
304 tree->GetVertexData()->AddArray(extendedNameArray);
305 }
306
307 VTK_CREATE(vtkTree, realTree);
308 if (!realTree->CheckedShallowCopy(tree))
309 {
310 cerr << "Invalid tree structure." << endl;
311 }
312
313 VTK_CREATE(vtkTreeLayoutStrategy, treeStrategy);
314 treeStrategy->SetAngle(angle);
315 treeStrategy->SetRadial(radial);
316 treeStrategy->SetLogSpacingValue(logSpacing);
317 treeStrategy->SetLeafSpacing(leafSpacing);
318
319 VTK_CREATE(vtkGraphLayout, treeLayout);
320 treeLayout->SetInputData(realTree);
321 treeLayout->SetLayoutStrategy(treeStrategy);
322
323 VTK_CREATE(vtkGraphHierarchicalBundle, bundle);
324 bundle->SetInputData(0, graph);
325 bundle->SetInputConnection(1, treeLayout->GetOutputPort(0));
326 bundle->SetBundlingStrength(bundlingStrength);
327 bundle->SetDirectMapping(true);
328
329 VTK_CREATE(vtkSplineFilter, spline);
330 spline->SetInputConnection(0, bundle->GetOutputPort(0));
331
332 VTK_CREATE(vtkLookupTable, lut);
333 int numValues = 100;
334 lut->SetNumberOfTableValues(numValues);
335 lut->Build();
336 for (int i = 0; i < numValues; i++)
337 {
338 double frac = static_cast<double>(i)/numValues;
339 lut->SetTableValue(i, 1.0 - frac, frac, 0.0);
340 }
341
342 VTK_CREATE(vtkPolyDataMapper, polyMapper);
343 polyMapper->SetInputConnection(0, spline->GetOutputPort(0));
344 polyMapper->SetScalarModeToUsePointFieldData();
345 polyMapper->SetLookupTable(lut);
346 polyMapper->SelectColorArray("fraction");
347
348 VTK_CREATE(vtkActor, polyActor);
349 polyActor->SetMapper(polyMapper);
350 polyActor->GetProperty()->SetOpacity(0.5);
351
352 VTK_CREATE(vtkGraphToPolyData, treePoly);
353 //treePoly->SetInput(tree);
354 treePoly->SetInputConnection(0, treeLayout->GetOutputPort(0));
355
356 VTK_CREATE(vtkPolyDataMapper, treeMapper);
357 treeMapper->SetInputConnection(0, treePoly->GetOutputPort(0));
358
359 VTK_CREATE(vtkActor, treeActor);
360 treeActor->SetMapper(treeMapper);
361 treeActor->GetProperty()->SetColor(0.4, 0.6, 1.0);
362
363 #if 0
364 VTK_CREATE(vtkDynamic2DLabelMapper, labelMapper);
365 labelMapper->SetInputConnection(0, treePoly->GetOutputPort(0));
366 labelMapper->SetLabelModeToLabelFieldData();
367 labelMapper->SetFieldDataName("name");
368 labelMapper->SetLabelFormat("%s");
369 labelMapper->GetLabelTextProperty()->SetColor(0.0, 0.0, 0.0);
370
371 VTK_CREATE(vtkActor2D, labelActor);
372 labelActor->SetMapper(labelMapper);
373 #endif
374
375 VTK_CREATE(vtkRenderer, ren);
376 ren->SetBackground(1.0, 1.0, 1.0);
377
378 if (showTree)
379 {
380 ren->AddActor(treeActor);
381 }
382 else
383 {
384 ren->AddActor(polyActor);
385 }
386 //ren->AddActor2D(labelActor);
387
388 VTK_CREATE(vtkRenderWindowInteractor, iren);
389 VTK_CREATE(vtkInteractorStyleImage, style);
390 VTK_CREATE(vtkRenderWindow, win);
391 iren->SetInteractorStyle(style);
392 win->AddRenderer(ren);
393 win->SetInteractor(iren);
394 //win->LineSmoothingOn();
395
396 int retVal = vtkRegressionTestImage(win);
397 if (retVal == vtkRegressionTester::DO_INTERACTOR)
398 {
399 win->Render();
400 iren->Start();
401 retVal = vtkRegressionTester::PASSED;
402 }
403
404 // Clean up
405 graph->Delete();
406
407 return !retVal;
408 }
409