1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkGraphLayout.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 "vtkGraphLayout.h"
22
23 #include "vtkAbstractTransform.h"
24 #include "vtkCellArray.h"
25 #include "vtkCellData.h"
26 #include "vtkDataArray.h"
27 #include "vtkEventForwarderCommand.h"
28 #include "vtkFloatArray.h"
29 #include "vtkGraphLayoutStrategy.h"
30 #include "vtkMath.h"
31 #include "vtkInformation.h"
32 #include "vtkInformationVector.h"
33 #include "vtkObjectFactory.h"
34 #include "vtkPointData.h"
35 #include "vtkPoints.h"
36 #include "vtkTable.h"
37
38 vtkStandardNewMacro(vtkGraphLayout);
39 vtkCxxSetObjectMacro(vtkGraphLayout, Transform, vtkAbstractTransform);
40
41 // ----------------------------------------------------------------------
42
vtkGraphLayout()43 vtkGraphLayout::vtkGraphLayout()
44 {
45 this->LayoutStrategy = 0;
46 this->StrategyChanged = false;
47 this->LastInput = NULL;
48 this->LastInputMTime = 0;
49 this->InternalGraph = 0;
50 this->ZRange = 0.0;
51 this->Transform = 0;
52 this->UseTransform = false;
53
54 this->EventForwarder = vtkEventForwarderCommand::New();
55 this->EventForwarder->SetTarget(this);
56 }
57
58 // ----------------------------------------------------------------------
59
~vtkGraphLayout()60 vtkGraphLayout::~vtkGraphLayout()
61 {
62 if (this->LayoutStrategy)
63 {
64 this->LayoutStrategy->RemoveObserver(this->EventForwarder);
65 this->LayoutStrategy->Delete();
66 }
67 if (this->InternalGraph)
68 {
69 this->InternalGraph->Delete();
70 }
71 if (this->Transform)
72 {
73 this->Transform->Delete();
74 }
75 this->EventForwarder->Delete();
76 }
77
78 // ----------------------------------------------------------------------
79
80 void
SetLayoutStrategy(vtkGraphLayoutStrategy * strategy)81 vtkGraphLayout::SetLayoutStrategy(vtkGraphLayoutStrategy *strategy)
82 {
83 // This method is a cut and paste of vtkCxxSetObjectMacro
84 // except for the call to SetGraph in the middle :)
85 if (strategy != this->LayoutStrategy)
86 {
87 vtkGraphLayoutStrategy *tmp = this->LayoutStrategy;
88 if (tmp)
89 {
90 tmp->RemoveObserver(this->EventForwarder);
91 }
92 this->LayoutStrategy = strategy;
93 if (this->LayoutStrategy != NULL)
94 {
95 this->StrategyChanged = true;
96 this->LayoutStrategy->Register(this);
97 this->LayoutStrategy->AddObserver(vtkCommand::ProgressEvent,
98 this->EventForwarder);
99 if (this->InternalGraph)
100 {
101 // Set the graph in the layout strategy
102 this->LayoutStrategy->SetGraph(this->InternalGraph);
103 }
104 }
105 if (tmp != NULL)
106 {
107 tmp->UnRegister(this);
108 }
109 this->Modified();
110 }
111 }
112
113 // ----------------------------------------------------------------------
114
115 unsigned long
GetMTime()116 vtkGraphLayout::GetMTime()
117 {
118 unsigned long mTime = this->Superclass::GetMTime();
119 unsigned long time;
120
121 if (this->LayoutStrategy != NULL)
122 {
123 time = this->LayoutStrategy->GetMTime();
124 mTime = (time > mTime ? time : mTime);
125 }
126 return mTime;
127 }
128
129 // ----------------------------------------------------------------------
130
131 int
IsLayoutComplete()132 vtkGraphLayout::IsLayoutComplete()
133 {
134 if (this->LayoutStrategy)
135 {
136 return this->LayoutStrategy->IsLayoutComplete();
137 }
138
139 // This is an error condition
140 vtkErrorMacro("IsLayoutComplete called with layout strategy==NULL");
141 return 0;
142 }
143
144 // ----------------------------------------------------------------------
145
146 int
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)147 vtkGraphLayout::RequestData(vtkInformation *vtkNotUsed(request),
148 vtkInformationVector **inputVector,
149 vtkInformationVector *outputVector)
150 {
151 if (this->LayoutStrategy == NULL)
152 {
153 vtkErrorMacro(<< "Layout strategy must be non-null.");
154 return 0;
155 }
156
157 // get the info objects
158 vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
159 vtkInformation *outInfo = outputVector->GetInformationObject(0);
160
161 // get the input and output
162 vtkGraph *input = vtkGraph::SafeDownCast(
163 inInfo->Get(vtkDataObject::DATA_OBJECT()));
164 vtkGraph *output = vtkGraph::SafeDownCast(
165 outInfo->Get(vtkDataObject::DATA_OBJECT()));
166
167 // Is this a completely new input? Is it the same input as the last
168 // time the filter ran but with a new MTime? If either of those is
169 // true, make a copy and give it to the strategy object anew.
170 if (this->StrategyChanged ||
171 input != this->LastInput ||
172 input->GetMTime() > this->LastInputMTime)
173 {
174 if (this->StrategyChanged)
175 {
176 vtkDebugMacro(<<"Strategy changed so reading in input again.");
177 this->StrategyChanged = false;
178 }
179 else if (input != this->LastInput)
180 {
181 vtkDebugMacro(<<"Filter running with different input. Resetting in strategy.");
182 }
183 else
184 {
185 vtkDebugMacro(<<"Input modified since last run. Resetting in strategy.");
186 }
187
188 if (this->InternalGraph)
189 {
190 this->InternalGraph->Delete();
191 }
192
193 this->InternalGraph = input->NewInstance();
194 // The strategy object is going to modify the Points member so
195 // we'll replace that with a deep copy. For everything else a
196 // shallow copy is sufficient.
197 this->InternalGraph->ShallowCopy(input);
198
199 // The copy of the points will be to a float type
200 vtkPoints* newPoints = vtkPoints::New(VTK_FLOAT);
201 newPoints->DeepCopy(input->GetPoints());
202 this->InternalGraph->SetPoints(newPoints);
203 newPoints->Delete();
204
205
206 // Save information about the input so that we can detect when
207 // it's changed on future runs. According to the VTK pipeline
208 // design, this is a bad thing. In this case there's no
209 // particularly graceful way around it since the pipeline was not
210 // designed to support incremental execution.
211 this->LastInput = input;
212 this->LastInputMTime = input->GetMTime();
213
214 // Give the layout strategy a pointer to the input. We set it to
215 // NULL first to force the layout algorithm to re-initialize
216 // itself. This is necessary in case the input is the same data
217 // object with a newer mtime.
218 this->LayoutStrategy->SetGraph(NULL);
219 this->LayoutStrategy->SetGraph(this->InternalGraph);
220 } // Done handling a new or changed filter input.
221
222 // No matter whether the input is new or not, the layout strategy
223 // needs to do its thing. It modifies its input
224 // (this->InternalGraph) so we can just use that as the output.
225 this->LayoutStrategy->Layout();
226 output->ShallowCopy(this->InternalGraph);
227
228 // Perturb points so they do not all have the same z value.
229 if (this->ZRange != 0.0)
230 {
231 vtkIdType numVert = output->GetNumberOfVertices();
232 double x[3];
233 bool onPlane = true;
234 for (vtkIdType i = 0; i < numVert; ++i)
235 {
236 output->GetPoint(i, x);
237 if (x[2] != 0.0)
238 {
239 onPlane = false;
240 break;
241 }
242 }
243 if (onPlane)
244 {
245 vtkPoints* pts = vtkPoints::New();
246 pts->SetNumberOfPoints(numVert);
247 for (vtkIdType i = 0; i < numVert; ++i)
248 {
249 output->GetPoint(i, x);
250 x[2] = this->ZRange*static_cast<double>(i)/numVert;
251 pts->SetPoint(i, x);
252 }
253 output->SetPoints(pts);
254 pts->Delete();
255 }
256 }
257
258 if (this->UseTransform && this->Transform)
259 {
260 vtkIdType numVert = output->GetNumberOfVertices();
261 double x[3];
262 double y[3];
263 vtkPoints* pts = vtkPoints::New();
264 pts->SetNumberOfPoints(numVert);
265 for (vtkIdType i = 0; i < numVert; ++i)
266 {
267 output->GetPoint(i, x);
268 this->Transform->TransformPoint(x, y);
269 pts->SetPoint(i, y);
270 }
271 output->SetPoints(pts);
272 pts->Delete();
273 }
274
275 return 1;
276 }
277
278 // ----------------------------------------------------------------------
279
280
PrintSelf(ostream & os,vtkIndent indent)281 void vtkGraphLayout::PrintSelf(ostream& os, vtkIndent indent)
282 {
283 this->Superclass::PrintSelf(os, indent);
284 os << indent << "StrategyChanged: " << (this->StrategyChanged ? "True" : "False") << endl;
285 os << indent << "LayoutStrategy: " << (this->LayoutStrategy ? "" : "(none)") << endl;
286 if (this->LayoutStrategy)
287 {
288 this->LayoutStrategy->PrintSelf(os, indent.GetNextIndent());
289 }
290 os << indent << "InternalGraph: " << (this->InternalGraph ? "" : "(none)") << endl;
291 if (this->InternalGraph)
292 {
293 this->InternalGraph->PrintSelf(os, indent.GetNextIndent());
294 }
295 os << indent << "ZRange: " << this->ZRange << endl;
296 os << indent << "Transform: " << (this->Transform ? "" : "(none)") << endl;
297 if (this->Transform)
298 {
299 this->Transform->PrintSelf(os, indent.GetNextIndent());
300 }
301 os << indent << "UseTransform: " << (this->UseTransform ? "True" : "False") << endl;
302 }
303