1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-FileCopyrightText: Copyright 2008 Sandia Corporation
// SPDX-License-Identifier: LicenseRef-BSD-3-Clause-Sandia-USGov
// .NAME vtkChacoGraphReader - Reads chaco graph files.
//
// .SECTION Description
// vtkChacoGraphReader reads in files in the CHACO format.
// An example is the following:
// <code>
// 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
// </code>
// 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 "vtksys/FStream.hxx"
#include <fstream>
#include <sstream>
#define VTK_CREATE(type, name) vtkSmartPointer<type> name = vtkSmartPointer<type>::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.
VTK_ABI_NAMESPACE_BEGIN
static int my_getline(std::istream& stream, std::string& 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
std::string 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, std::string& out, char delimiter)
{
out = std::string();
unsigned int numCharactersRead = 0;
int nextValue = 0;
while ((nextValue = in.get()) != EOF && numCharactersRead < out.max_size())
{
++numCharactersRead;
char downcast = static_cast<char>(nextValue);
if (downcast != delimiter)
{
out += downcast;
}
else
{
return numCharactersRead;
}
}
return numCharactersRead;
}
VTK_ABI_NAMESPACE_END
|