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