/*========================================================================= Program: Visualization Toolkit Module: vtkChacoGraphReader.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 2008 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ // .NAME vtkChacoGraphReader - Reads chaco graph files. // // .SECTION Description // vtkChacoGraphReader reads in files in the CHACO format. // An example is the following: // // 10 13 // 2 6 10 // 1 3 // 2 4 8 // 3 5 // 4 6 10 // 1 5 7 // 6 8 // 3 7 9 // 8 10 // 1 5 9 // // The first line gives the number of vertices and edges in the graph. // Each additional line is the connectivity list for each vertex in the graph. // Vertex 1 is connected to 2, 6, and 10, vertex 2 is connected to 1 and 3, etc. // NOTE: Chaco ids start with 1, while VTK ids start at 0, so VTK ids will be // one less than the chaco ids. #include "vtkChacoGraphReader.h" #include "vtkCellData.h" #include "vtkIntArray.h" #include "vtkMutableUndirectedGraph.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkSmartPointer.h" #include "vtkStdString.h" #include "vtksys/FStream.hxx" #include #include #define VTK_CREATE(type, name) vtkSmartPointer name = vtkSmartPointer::New() // I need a safe way to read a line of arbitrary length. It exists on // some platforms but not others so I'm afraid I have to write it // myself. // This function is also defined in Infovis/vtkDelimitedTextReader.cxx, // so it would be nice to put this in a common file. static int my_getline(std::istream& stream, vtkStdString& output, char delim = '\n'); vtkStandardNewMacro(vtkChacoGraphReader); vtkChacoGraphReader::vtkChacoGraphReader() { // Default values for the origin vertex this->FileName = nullptr; this->SetNumberOfInputPorts(0); } vtkChacoGraphReader::~vtkChacoGraphReader() { this->SetFileName(nullptr); } void vtkChacoGraphReader::PrintSelf(std::ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << endl; } int vtkChacoGraphReader::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { if (this->FileName == nullptr) { vtkErrorMacro("File name undefined"); return 0; } vtksys::ifstream fin(this->FileName); if (!fin.is_open()) { vtkErrorMacro("Could not open file " << this->FileName << "."); return 0; } // Create a mutable graph builder VTK_CREATE(vtkMutableUndirectedGraph, builder); // Get the header line vtkStdString line; my_getline(fin, line); std::stringstream firstLine; firstLine << line; vtkIdType numVerts; vtkIdType numEdges; firstLine >> numVerts >> numEdges; vtkIdType type = 0; if (firstLine.good()) { firstLine >> type; } // Create the weight arrays int vertWeights = type % 10; int edgeWeights = (type / 10) % 10; // cerr << "type=" << type << ",vertWeights=" << vertWeights << ",edgeWeights=" << edgeWeights << // endl; vtkIntArray** vertArr = new vtkIntArray*[vertWeights]; for (int vw = 0; vw < vertWeights; vw++) { std::ostringstream oss; oss << "weight " << (vw + 1); vertArr[vw] = vtkIntArray::New(); vertArr[vw]->SetName(oss.str().c_str()); builder->GetVertexData()->AddArray(vertArr[vw]); vertArr[vw]->Delete(); } vtkIntArray** edgeArr = new vtkIntArray*[edgeWeights]; for (int ew = 0; ew < edgeWeights; ew++) { std::ostringstream oss; oss << "weight " << (ew + 1); edgeArr[ew] = vtkIntArray::New(); edgeArr[ew]->SetName(oss.str().c_str()); builder->GetEdgeData()->AddArray(edgeArr[ew]); edgeArr[ew]->Delete(); } // Add the vertices for (vtkIdType v = 0; v < numVerts; v++) { builder->AddVertex(); } // Add the edges for (vtkIdType u = 0; u < numVerts; u++) { my_getline(fin, line); std::stringstream stream; stream << line; // cerr << "read line " << stream.str() << endl; int weight; for (int vw = 0; vw < vertWeights; vw++) { stream >> weight; vertArr[vw]->InsertNextValue(weight); } vtkIdType v; while (stream.good()) { stream >> v; // cerr << "read adjacent vertex " << v << endl; // vtkGraph ids are 1 less than Chaco graph ids v--; // Only add the edge if v less than u. // This avoids adding the same edge twice. if (v < u) { builder->AddEdge(u, v); for (int ew = 0; ew < edgeWeights; ew++) { stream >> weight; edgeArr[ew]->InsertNextValue(weight); } } } } delete[] edgeArr; delete[] vertArr; // Clean up fin.close(); // Get the output graph vtkGraph* output = vtkGraph::GetData(outputVector); if (!output->CheckedShallowCopy(builder)) { vtkErrorMacro(<< "Invalid graph structure"); return 0; } return 1; } static int my_getline(std::istream& in, vtkStdString& out, char delimiter) { out = vtkStdString(); unsigned int numCharactersRead = 0; int nextValue = 0; while ((nextValue = in.get()) != EOF && numCharactersRead < out.max_size()) { ++numCharactersRead; char downcast = static_cast(nextValue); if (downcast != delimiter) { out += downcast; } else { return numCharactersRead; } } return numCharactersRead; }