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