/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkGraphLayoutFilter.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkGraphLayoutFilter.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPolyData.h" vtkCxxRevisionMacro(vtkGraphLayoutFilter, "$Revision: 1.14 $"); vtkStandardNewMacro(vtkGraphLayoutFilter); vtkGraphLayoutFilter::vtkGraphLayoutFilter() { this->GraphBounds[0] = this->GraphBounds[2] = this->GraphBounds[4] = -0.5; this->GraphBounds[1] = this->GraphBounds[3] = this->GraphBounds[5] = 0.5; this->MaxNumberOfIterations = 50; this->CoolDownRate = 10.0; this->AutomaticBoundsComputation = 1; this->ThreeDimensionalLayout = 1; } // A vertex contains a position and a displacement. typedef struct _vtkLayoutVertex { double x[3]; double d[3]; } vtkLayoutVertex; // An edge consists of two vertices joined together. // This struct acts as a "pointer" to those two vertices. typedef struct _vtkLayoutEdge { int t; int u; } vtkLayoutEdge; // Cool-down function. static inline double CoolDown(double t, double r) { return t-(t/r); } static inline double forceAttract(double x, double k) { return (x * x) / k; } static inline double forceRepulse(double x, double k) { if (x != 0.0) { return k * k / x; } else { return VTK_DOUBLE_MAX; } } int vtkGraphLayoutFilter::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector) { // get the info objects vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the input and ouptut vtkPolyData *input = vtkPolyData::SafeDownCast( inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPoints *pts = input->GetPoints(); vtkCellArray *lines = input->GetLines(); int numLines = lines->GetNumberOfCells(); //Number of lines/edges. int numPts = input->GetNumberOfPoints(); //Number of points/vertices. double diff[3], len; //The difference vector. int i, j, l; //Iteration variables. vtkIdType npts = 0; vtkIdType *cellPts = 0; double fa, fr, minimum; vtkDebugMacro(<<"Drawing graph"); if ( numPts <= 0 || numLines <= 0) { vtkErrorMacro(<<"No input"); return 1; } // Generate bounds automatically if necessary. It's the same // as the input bounds. if ( this->AutomaticBoundsComputation ) { pts->GetBounds(this->GraphBounds); } for (i=0; i<3; i++) { if ( this->GraphBounds[2*i+1] <= this->GraphBounds[2*i] ) { this->GraphBounds[2*i+1] = this->GraphBounds[2*i] + 1; } } // Allocate memory for structures. Break polylines into line segments. numLines=0; for (i=0, lines->InitTraversal(); lines->GetNextCell(npts, cellPts); i++) { numLines += npts - 1; } vtkLayoutVertex *v = new vtkLayoutVertex [numPts]; vtkLayoutEdge *e = new vtkLayoutEdge [numLines]; // Get the points, either x,y,0 or x,y,z for (i=0; iGetPoint(i,v[i].x); if ( ! this->ThreeDimensionalLayout ) { v[i].x[2] = 0; } } // Get the edges numLines=0; for (i=0, lines->InitTraversal(); lines->GetNextCell(npts, cellPts); i++) { for (j=0; jGraphBounds[1] - this->GraphBounds[0]) * (this->GraphBounds[3] - this->GraphBounds[2]) * (this->GraphBounds[5] - this->GraphBounds[4]); double temp = sqrt( (this->GraphBounds[1]-this->GraphBounds[0])* (this->GraphBounds[1]-this->GraphBounds[0]) + (this->GraphBounds[3]-this->GraphBounds[2])* (this->GraphBounds[3]-this->GraphBounds[2]) + (this->GraphBounds[5]-this->GraphBounds[4])* (this->GraphBounds[5]-this->GraphBounds[4]) ); // The optimal distance between vertices. double k = pow((double)volume/numPts,0.33333); // Begin iterations. double norm; for(i=0; iMaxNumberOfIterations; i++) { // Calculate the repulsive forces. for(j=0; jCoolDownRate); } // Get the bounds of the graph and scale and translate to // bring them within the bounds specified. vtkPoints *newPts = vtkPoints::New(); newPts->SetNumberOfPoints(numPts); for (i=0; iSetPoint(i,v[i].x); } double bounds[6], sf[3], x[3], xNew[3]; double center[3], graphCenter[3]; newPts->GetBounds(bounds); for (i=0; i<3; i++) { if ( (len=(bounds[2*i+1] - bounds[2*i])) == 0.0 ) { len = 1.0; } sf[i] = (this->GraphBounds[2*i+1] - this->GraphBounds[2*i]) / len; center[i] = (bounds[2*i+1] + bounds[2*i])/2.0; graphCenter[i] = (this->GraphBounds[2*i+1] + this->GraphBounds[2*i])/2.0; } double scale = sf[0]; scale = (scale < sf[1] ? scale : sf[1]); scale = (scale < sf[2] ? scale : sf[2]); for (i=0; iGetPoint(i, x); for (j=0; j<3; j++) { xNew[j] = graphCenter[j] + scale*(x[j]-center[j]); } newPts->SetPoint(i,xNew); } // Send the data to output. output->SetPoints(newPts); output->SetLines(lines); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); // Clean up. newPts->Delete(); delete [] v; delete [] e; return 1; } void vtkGraphLayoutFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "AutomaticBoundsComputation: " << (this->AutomaticBoundsComputation ? "On\n" : "Off\n"); os << indent << "GraphBounds: \n"; os << indent << " Xmin,Xmax: (" << this->GraphBounds[0] << ", " << this->GraphBounds[1] << ")\n"; os << indent << " Ymin,Ymax: (" << this->GraphBounds[2] << ", " << this->GraphBounds[3] << ")\n"; os << indent << " Zmin,Zmax: (" << this->GraphBounds[4] << ", " << this->GraphBounds[5] << ")\n"; os << indent << "MaxNumberOfIterations: " << this->MaxNumberOfIterations << endl; os << indent << "CoolDownRate: " << this->CoolDownRate << endl; os << indent << "Three Dimensional Layout: " << (this->ThreeDimensionalLayout ? "On\n" : "Off\n"); }