/*========================================================================= Program: Visualization Toolkit Module: vtkKCoreLayout.cxx 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. =========================================================================*/ /*---------------------------------------------------------------------------- Copyright (c) Sandia Corporation See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. ----------------------------------------------------------------------------*/ #include "vtkKCoreLayout.h" #include "vtkAdjacentVertexIterator.h" #include "vtkDataSetAttributes.h" #include "vtkDoubleArray.h" #include "vtkGraph.h" #include "vtkIdTypeArray.h" #include "vtkInEdgeIterator.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkSelection.h" #include "vtkSmartPointer.h" #include #define _USE_MATH_DEFINES #include using std::cout; using std::endl; #define VTK_CREATE(type, name) \ vtkSmartPointer name = vtkSmartPointer::New() /////////////////////////////////////////////////////////////////////////////////// // vtkKCoreLayout vtkStandardNewMacro(vtkKCoreLayout); // Default Constructor vtkKCoreLayout::vtkKCoreLayout() { this->SetNumberOfInputPorts(1); this->KCoreLabelArrayName = nullptr; this->PolarCoordsRadiusArrayName = nullptr; this->PolarCoordsAngleArrayName = nullptr; this->CartesianCoordsXArrayName = nullptr; this->CartesianCoordsYArrayName = nullptr; this->Cartesian = true; this->Polar = false; this->Epsilon = 0.2f; this->UnitRadius = 1.0f; } // Default Destructor vtkKCoreLayout::~vtkKCoreLayout() { this->KCoreLabelArrayName = nullptr; } // ------------------------------------------------------------------------------------------------- void vtkKCoreLayout::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); if(this->KCoreLabelArrayName) { os << indent << "KCoreLabelArrayName : " << this->KCoreLabelArrayName << endl; } else { os << indent << "KCoreLabelArrayName : nullptr" << endl; } os << indent << "Polar : " << this->Polar << endl; os << indent << "Cartesian : " << this->Cartesian << endl; if(this->PolarCoordsRadiusArrayName) { os << indent << "PolarCoordsRadiusArrayName: " << this->PolarCoordsRadiusArrayName << endl; } else { os << indent << "PolarCoordsRadiusArrayName: (none)" << endl; } if(this->PolarCoordsAngleArrayName) { os << indent << "PolarCoordsAngleArrayName : " << this->PolarCoordsAngleArrayName << endl; } else { os << indent << "PolarCoordsAngleArrayName : (none)" << endl; } if(this->CartesianCoordsXArrayName) { os << indent << "CartesianCoordsXArrayName : " << this->CartesianCoordsXArrayName << endl; } else { os << indent << "CartesianCoordsXArrayName : (none)" << endl; } if(this->CartesianCoordsYArrayName) { os << indent << "CartesianCoordsYArrayName : " << this->CartesianCoordsYArrayName << endl; } else { os << indent << "CartesianCoordsYArrayName : (none)" << endl; } os << indent << "Epsilon : " << this->Epsilon << endl; os << indent << "UnitRadius : " << this->UnitRadius << endl; } // ------------------------------------------------------------------------------------------------- void vtkKCoreLayout::SetGraphConnection(vtkAlgorithmOutput* input) { this->SetInputConnection(0, input); } // ------------------------------------------------------------------------------------------------- int vtkKCoreLayout::FillInputPortInformation(int port, vtkInformation* info) { if(port == 0) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph"); return 1; } return 0; } // ------------------------------------------------------------------------------------------------- int vtkKCoreLayout::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { float radius = 0.0f; float angle = 0.0f; int max_core_level = -1; float epsilon = this->Epsilon; float unit_radius = this->UnitRadius; //cout << ">\tvtkKCoreLayout.RequestData()" << endl; // get the info objects vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the input and output vtkGraph * input = vtkGraph::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkGraph * output = vtkGraph::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); // Send the data to output output->ShallowCopy(input); // graph size vtkIdType num_verts = output->GetNumberOfVertices(); if(!this->KCoreLabelArrayName) { const char * kcore = "kcore"; this->KCoreLabelArrayName = strcpy(new char [strlen(kcore)+1], kcore); } // Get the kcore attribute array vtkIntArray * kcore_array = vtkArrayDownCast( output->GetVertexData()->GetArray(this->KCoreLabelArrayName)); if(!kcore_array) { vtkErrorMacro(<<"Vertex attribute array " << this->KCoreLabelArrayName << " is not a vtkIntArray."); return 0; } VTK_CREATE(vtkDoubleArray, arrayX); VTK_CREATE(vtkDoubleArray, arrayY); VTK_CREATE(vtkDoubleArray, arrayRadius); VTK_CREATE(vtkDoubleArray, arrayAngle); // Create output arrays (radius, angle) for polar coordinates if(this->Cartesian) { arrayX->SetNumberOfTuples( output->GetNumberOfVertices() ); if(this->CartesianCoordsXArrayName) { arrayX->SetName(this->CartesianCoordsXArrayName); } else { arrayX->SetName("coord_x"); } arrayY->SetNumberOfTuples( output->GetNumberOfVertices() ); if(this->CartesianCoordsXArrayName) { arrayY->SetName(this->CartesianCoordsXArrayName); } else { arrayY->SetName("coord_y"); } output->GetVertexData()->AddArray( arrayX ); output->GetVertexData()->AddArray( arrayY ); } if(this->Polar) { arrayRadius->SetNumberOfTuples( output->GetNumberOfVertices() ); if(this->PolarCoordsRadiusArrayName) { arrayRadius->SetName(this->PolarCoordsRadiusArrayName); } else { arrayRadius->SetName("coord_radius"); } arrayAngle->SetNumberOfTuples( output->GetNumberOfVertices() ); if(this->PolarCoordsAngleArrayName) { arrayAngle->SetName(this->PolarCoordsAngleArrayName); } else { arrayAngle->SetName("coord_angle"); } output->GetVertexData()->AddArray( arrayRadius ); output->GetVertexData()->AddArray( arrayAngle ); } if( !this->Polar && !this->Cartesian ) { vtkWarningMacro(<< "Neither Polar nor Cartesian output coordinate type specified. Operating as a Pass-Through filter"); return 1; } // find the maximum core level for(vtkIdType i=0; iGetNumberOfTuples(); i++) { max_core_level = max_core_level < kcore_array->GetValue(i) ? kcore_array->GetValue(i) : max_core_level; } //cout << "max core level: " << max_core_level << endl; // Loop over each vertex and calculate its position for(vtkIdType vidx=0; vidxGetValue(vidx); if(current_level == max_core_level) { radius = unit_radius; angle = float(rand()%100000)/100000 * 2.0 * vtkMath::Pi(); //cout << vidx << "\t(" << radius << "," << angle << ")" << endl; if(this->Cartesian) { arrayX->SetValue(vidx, radius * cos(angle) ); arrayY->SetValue(vidx, radius * sin(angle) ); } if(this->Polar) { arrayRadius->SetValue(vidx, radius); arrayAngle->SetValue(vidx, angle); } } else { // vertices in shells other than the innermost are positioned in rings around the shells // farther in. By default, each ring is 1 unit out from the next one. The innermost has // a radius of 1. int vertex_native_ring = (max_core_level - current_level) + 1; // the radius is adjusted by how many of this vertex's neighbors are in the same or // higher numbered shells. //int neighbors_same_or_higher = 0; vtkIdTypeArray * neighbors_same_or_higher = vtkIdTypeArray::New(); vtkAdjacentVertexIterator * it = vtkAdjacentVertexIterator::New(); output->GetAdjacentVertices( vidx, it ); while(it->HasNext()) { vtkIdType nid = it->Next(); if( kcore_array->GetValue(nid) >= current_level ) { neighbors_same_or_higher->InsertNextValue( nid ); } } it->Delete(); //cout << vidx << "\tneighbors_same_or_higher = " << neighbors_same_or_higher->GetNumberOfTuples() << endl; int neighbor_average_ring = 0; if( neighbors_same_or_higher->GetNumberOfTuples() > 0 ) { for( vtkIdType i=0; iGetNumberOfTuples(); i++ ) { vtkIdType neighbor_idx = neighbors_same_or_higher->GetValue(i); neighbor_average_ring += (1 + max_core_level - kcore_array->GetValue( neighbor_idx )); } } else { // No neighbors - do something semi-reasonable and pretend they're all in the regular // ring anyway. neighbor_average_ring = vertex_native_ring; } //cout << vidx << "\tneighbor_average_ring = " << neighbor_average_ring << endl; // Use epsilon as an interpolation factor between the two ring levels radius = (1-epsilon) * vertex_native_ring + epsilon * neighbor_average_ring; radius *= unit_radius; #ifdef DEBUG_KCORELAYOUT cout << "DEBUG: Vertex in shell level "<< current_level << " (native ring " << vertex_native_ring << ", max core level " << max_core_level << ") and average neighbor ring " << neighbor_average_ring << " (" << neighbors_same_or_higher->GetNumberOfTuples() << " neighbor(s)) is at radius " << radius << " with epsilon " << epsilon << endl; #endif // Need the angle. angle = float(rand()%100000)/100000 * (2.0 * vtkMath::Pi()); // set the values if(this->Cartesian) { arrayX->SetValue(vidx, radius * cos(angle) ); arrayY->SetValue(vidx, radius * sin(angle) ); } if(this->Polar) { arrayRadius->SetValue(vidx, radius); arrayAngle->SetValue(vidx, angle); } neighbors_same_or_higher->Delete(); } } return 1; }