/*========================================================================= Program: Visualization Toolkit Module: vtkChacoReader.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 "vtkChacoReader.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkInformation.h" #include "vtkInformationDoubleVectorKey.h" #include "vtkInformationVector.h" #include "vtkIntArray.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkUnstructuredGrid.h" #include #include #include vtkStandardNewMacro(vtkChacoReader); //------------------------------------------------------------------------------ // Description: // Instantiate object with nullptr filename. vtkChacoReader::vtkChacoReader() { this->BaseName = nullptr; this->GenerateGlobalElementIdArray = 1; this->GenerateGlobalNodeIdArray = 1; this->GenerateVertexWeightArrays = 0; this->GenerateEdgeWeightArrays = 0; this->EarrayName = nullptr; this->VarrayName = nullptr; this->Dimensionality = -1; this->NumberOfVertices = 0; this->NumberOfEdges = 0; this->NumberOfVertexWeights = 0; this->NumberOfEdgeWeights = 0; this->GraphFileHasVertexNumbers = 0; this->NumberOfPointWeightArrays = 0; this->NumberOfCellWeightArrays = 0; this->CurrentGeometryFP = nullptr; this->CurrentGraphFP = nullptr; this->CurrentBaseName = nullptr; this->DataCache = vtkUnstructuredGrid::New(); this->RemakeDataCacheFlag = 1; this->Offset = 0; this->Break_pnt = 200; this->Save_pnt = 0; this->SetNumberOfInputPorts(0); } //------------------------------------------------------------------------------ vtkChacoReader::~vtkChacoReader() { this->SetBaseName(nullptr); this->SetCurrentBaseName(nullptr); this->ClearWeightArrayNames(); this->DataCache->Delete(); this->DataCache = nullptr; } //------------------------------------------------------------------------------ void vtkChacoReader::ClearWeightArrayNames() { int i = 0; if (this->VarrayName) { for (i = 0; i < this->NumberOfVertexWeights; i++) { delete[] this->VarrayName[i]; } delete[] this->VarrayName; this->VarrayName = nullptr; } if (this->EarrayName) { for (i = 0; i < this->NumberOfEdgeWeights; i++) { delete[] this->EarrayName[i]; } delete[] this->EarrayName; this->EarrayName = nullptr; } } //------------------------------------------------------------------------------ void vtkChacoReader::MakeWeightArrayNames(int nv, int ne) { int i = 0; if (nv > 0) { this->VarrayName = new char*[nv]; for (i = 0; i < nv; i++) { this->VarrayName[i] = new char[64]; snprintf(this->VarrayName[i], 64, "VertexWeight%d", i + 1); } } if (ne > 0) { this->EarrayName = new char*[ne]; for (i = 0; i < ne; i++) { this->EarrayName[i] = new char[64]; snprintf(this->EarrayName[i], 64, "EdgeWeight%d", i + 1); } } } //------------------------------------------------------------------------------ const char* vtkChacoReader::GetVertexWeightArrayName(int weight) { if (this->GetGenerateVertexWeightArrays() && (weight > 0) && (weight <= this->NumberOfVertexWeights)) { return this->VarrayName[weight - 1]; } return nullptr; } //------------------------------------------------------------------------------ const char* vtkChacoReader::GetEdgeWeightArrayName(int weight) { if (this->GetGenerateEdgeWeightArrays() && (weight > 0) && (weight <= this->NumberOfEdgeWeights)) { return this->EarrayName[weight - 1]; } return nullptr; } //------------------------------------------------------------------------------ int vtkChacoReader::RequestInformation(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* vtkNotUsed(outputVector)) { double x, y, z; if (!this->BaseName) { vtkErrorMacro(<< "No BaseName specified"); return 0; } int newFile = ((this->CurrentBaseName == nullptr) || strcmp(this->CurrentBaseName, this->BaseName) != 0); if (!newFile) { return 1; } if (this->OpenCurrentFile() != 1) { return 0; } // Get the dimension of the coordinates from the vertex file int rc = this->InputGeom(1, 0, &x, &y, &z); this->ResetInputBuffers(); if (rc) { // Get the number of vertices and edges, and number of // vertex weights and edge weights from the graph file. rc = this->InputGraph1(); this->ResetInputBuffers(); if (rc) { this->MakeWeightArrayNames(this->NumberOfVertexWeights, this->NumberOfEdgeWeights); } } // Close the file this->CloseCurrentFile(); this->RemakeDataCacheFlag = 1; return rc; } //------------------------------------------------------------------------------ int vtkChacoReader::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { if (!this->BaseName) { vtkErrorMacro(<< "No BaseName specified"); return 0; } vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkUnstructuredGrid* output = vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); int retVal = this->BuildOutputGrid(output); return retVal; } //------------------------------------------------------------------------------ int vtkChacoReader::BuildOutputGrid(vtkUnstructuredGrid* output) { int i = 0; if (this->OpenCurrentFile() != 1) { vtkWarningMacro(<< "Can't open file"); return 0; } int ncells = this->DataCache->GetNumberOfCells(); int haveVertexWeightArrays = 0; int haveEdgeWeightArrays = 0; if (ncells && (this->NumberOfVertexWeights > 0)) { vtkDoubleArray* da = vtkArrayDownCast( this->DataCache->GetPointData()->GetArray(this->VarrayName[0])); haveVertexWeightArrays = (da != nullptr); } if (ncells && (this->NumberOfEdgeWeights > 0)) { vtkDoubleArray* da = vtkArrayDownCast( this->DataCache->GetCellData()->GetArray(this->EarrayName[0])); haveEdgeWeightArrays = (da != nullptr); } if (!this->RemakeDataCacheFlag && ((!haveVertexWeightArrays && this->GenerateVertexWeightArrays) || (!haveEdgeWeightArrays && this->GenerateEdgeWeightArrays))) { this->RemakeDataCacheFlag = 1; } if (this->RemakeDataCacheFlag) { output->Initialize(); int rc = this->ReadFile(output); if (rc == 0) { this->CloseCurrentFile(); return 0; } if (this->GenerateGlobalElementIdArray) { this->AddElementIds(output); } if (this->GenerateGlobalNodeIdArray) { this->AddNodeIds(output); } // Save the output. Next time we execute, it may be simply // because they turned off vertex or edge weights, or decided they // do or do not want element or point IDs. For these we can just // modify the DataCache, rather than reading in the whole file // and creating a vtkUnstructuredGrid from it. this->DataCache->Initialize(); this->DataCache->ShallowCopy(output); this->RemakeDataCacheFlag = 0; } else { // Just copy the output we calculated last time, after checking // to see if any parameters have changed if (haveVertexWeightArrays && !this->GenerateVertexWeightArrays) { for (i = 0; i < this->NumberOfVertexWeights; i++) { this->DataCache->GetPointData()->RemoveArray(this->VarrayName[i]); } this->NumberOfPointWeightArrays = 0; } if (haveEdgeWeightArrays && !this->GenerateEdgeWeightArrays) { for (i = 0; i < this->NumberOfEdgeWeights; i++) { this->DataCache->GetCellData()->RemoveArray(this->EarrayName[i]); } this->NumberOfCellWeightArrays = 0; } vtkIntArray* ia = vtkArrayDownCast( this->DataCache->GetCellData()->GetArray(vtkChacoReader::GetGlobalElementIdArrayName())); if (!ia && this->GenerateGlobalElementIdArray) { this->AddElementIds(this->DataCache); } else if (ia && !this->GenerateGlobalElementIdArray) { this->DataCache->GetCellData()->RemoveArray(vtkChacoReader::GetGlobalElementIdArrayName()); } ia = vtkArrayDownCast( this->DataCache->GetPointData()->GetArray(vtkChacoReader::GetGlobalNodeIdArrayName())); if (!ia && this->GenerateGlobalNodeIdArray) { this->AddNodeIds(this->DataCache); } else if (ia && !this->GenerateGlobalNodeIdArray) { this->DataCache->GetPointData()->RemoveArray(vtkChacoReader::GetGlobalNodeIdArrayName()); } output->ShallowCopy(this->DataCache); } // This just makes sure the arrays are the same size as the number // of nodes or cell output->CheckAttributes(); // We may have some mem that can be condensed output->Squeeze(); this->CloseCurrentFile(); return 1; } //------------------------------------------------------------------------------ int vtkChacoReader::ReadFile(vtkUnstructuredGrid* output) { int i = 0; vtkIdType id = 0; // Reset the entire unstructured grid output->Reset(); this->NumberOfPointWeightArrays = 0; this->NumberOfCellWeightArrays = 0; // Read in the points. Maintain the order in the original file. // The order indicates the global node ID. vtkPoints* ptarray = vtkPoints::New(); ptarray->SetNumberOfPoints(this->NumberOfVertices); ptarray->SetDataTypeToDouble(); int memoryOK = 1; double* x = new double[this->NumberOfVertices]; double* y = nullptr; double* z = nullptr; if (!x) { memoryOK = 0; } else if (this->Dimensionality > 1) { y = new double[this->NumberOfVertices]; if (!y) { memoryOK = 0; } else if (this->Dimensionality > 2) { z = new double[this->NumberOfVertices]; if (!z) { memoryOK = 0; } } } if (!memoryOK) { vtkErrorMacro(<< "ReadFile memory allocation failure"); delete[] x; delete[] y; return 0; } int rc = this->InputGeom(this->NumberOfVertices, this->Dimensionality, x, y, z); this->ResetInputBuffers(); if (rc == 0) { delete[] x; delete[] y; delete[] z; return 0; } if (this->Dimensionality == 3) { for (id = 0; id < this->NumberOfVertices; id++) { ptarray->InsertNextPoint(x[id], y[id], z[id]); } } else if (this->Dimensionality == 2) { for (id = 0; id < this->NumberOfVertices; id++) { ptarray->InsertNextPoint(x[id], y[id], 0.0); } } else if (this->Dimensionality == 1) { for (id = 0; id < this->NumberOfVertices; id++) { ptarray->InsertNextPoint(x[id], 0.0, 0.0); } } output->SetPoints(ptarray); delete[] x; delete[] y; delete[] z; ptarray->Delete(); // Read in cell topology and possibly cell and point weights. // (The unstructured grid "cells" are the Chaco "edges".) // // Note: The order in which point and cell arrays appear in the // output must be fixed. This is because this reader is called // by vtkPChacoReader, and all processes must create output // ugrids with the cell arrays and point arrays in the same // order. The order we choose for point arrays is: // vertex weight arrays, if any, in order they appear in file // global point IDs, if any // // The order for cell arrays is: // edge weight arrays, if any, in order they appear in file // global element IDs, if any int retVal = 1; vtkIdType* idx = nullptr; vtkIdType* nbors = nullptr; double* vweights = nullptr; double* eweights = nullptr; double** vw = nullptr; double** ew = nullptr; if (this->GetGenerateVertexWeightArrays() && (this->NumberOfVertexWeights > 0)) { vw = &vweights; } if (this->GetGenerateEdgeWeightArrays() && (this->NumberOfEdgeWeights > 0)) { ew = &eweights; } rc = this->InputGraph2(&idx, &nbors, vw, ew); this->ResetInputBuffers(); if (rc == 0) { return 0; } vtkDoubleArray** varrays = nullptr; vtkDoubleArray** earrays = nullptr; double* vwgt = nullptr; double* ewgt = nullptr; if (vw) { varrays = new vtkDoubleArray*[this->NumberOfVertexWeights]; for (i = 0; i < this->NumberOfVertexWeights; i++) { varrays[i] = vtkDoubleArray::New(); varrays[i]->SetNumberOfValues(this->NumberOfVertices); varrays[i]->SetName(this->VarrayName[i]); } vwgt = vweights; } if (ew) { earrays = new vtkDoubleArray*[this->NumberOfEdgeWeights]; for (i = 0; i < this->NumberOfEdgeWeights; i++) { earrays[i] = vtkDoubleArray::New(); earrays[i]->SetNumberOfValues(this->NumberOfEdges); earrays[i]->SetName(this->EarrayName[i]); } ewgt = eweights; } vtkIdTypeArray* ca = vtkIdTypeArray::New(); if (idx == nullptr) { // Special case: there are no edges in this graph. Every // vertex will be a cell. ca->SetNumberOfValues(2 * this->NumberOfVertices); vtkIdType* captr = ca->GetPointer(0); for (id = 0; id < this->NumberOfVertices; id++) { *captr++ = 1; // number of vertices in cell *captr++ = id; // internal ID of vertex if (vw) { for (int w = 0; w < this->NumberOfVertexWeights; w++) { varrays[w]->SetValue(id, *vwgt++); } } } vtkCellArray* cells = vtkCellArray::New(); cells->AllocateExact(this->NumberOfVertices, ca->GetNumberOfValues() - this->NumberOfVertices); cells->ImportLegacyFormat(ca); output->SetCells(VTK_VERTEX, cells); cells->Delete(); } else { // The usual case: most or all vertices are connected to // other vertices. ca->SetNumberOfValues(3 * this->NumberOfEdges); vtkIdType* captr = ca->GetPointer(0); vtkIdType edgeNum = -1; for (id = 0; id < this->NumberOfVertices; id++) { // Each edge in the Chaco file is listed twice, for each // vertex. We only save the edge once. for (int n = idx[id]; n < idx[id + 1]; n++) { vtkIdType nbor = nbors[n] - 1; // internal id // Save each edge connected to this vertex, if it hasn't // been saved already. if (nbor > id) { edgeNum++; if (edgeNum == this->NumberOfEdges) { vtkErrorMacro(<< "Too many edges in Chaco file"); retVal = 0; break; } *captr++ = 2; // size of cell *captr++ = id; // first vertex *captr++ = nbor; // second vertex if (ew) { // Save the edge weights associated with this edge for (i = 0; i < this->NumberOfEdgeWeights; i++) { earrays[i]->SetValue(edgeNum, *ewgt++); } } } else if (ew) { ewgt += this->NumberOfEdgeWeights; // Skip duplicate edge weights } } if (!retVal) break; // Save the weights associated with this vertex if (vw) { for (i = 0; i < this->NumberOfVertexWeights; i++) { varrays[i]->SetValue(id, *vwgt++); } } } if (edgeNum != this->NumberOfEdges - 1) { vtkErrorMacro(<< "Too few edges in Chaco file"); retVal = 0; } delete[] idx; delete[] nbors; if (retVal) { vtkCellArray* cells = vtkCellArray::New(); cells->AllocateExact(this->NumberOfEdges, ca->GetNumberOfValues() - this->NumberOfEdges); cells->ImportLegacyFormat(ca); output->SetCells(VTK_LINE, cells); cells->Delete(); } else { output->Initialize(); } } ca->Delete(); if (retVal == 1) { this->NumberOfPointWeightArrays = this->NumberOfVertexWeights; this->NumberOfCellWeightArrays = this->NumberOfEdgeWeights; } if (vw) { delete[] vweights; for (i = 0; i < this->NumberOfVertexWeights; i++) { if (retVal) { output->GetPointData()->AddArray(varrays[i]); } varrays[i]->Delete(); } delete[] varrays; } if (ew) { delete[] eweights; for (i = 0; i < this->NumberOfEdgeWeights; i++) { if (retVal) { output->GetCellData()->AddArray(earrays[i]); } earrays[i]->Delete(); } delete[] earrays; } if (retVal) { output->Squeeze(); } return retVal; } //------------------------------------------------------------------------------ void vtkChacoReader::AddElementIds(vtkUnstructuredGrid* output) { // We arbitrarily assign the element ids, since Chaco files do // not have the notion of Element IDs. vtkIdType len = output->GetNumberOfCells(); vtkIntArray* ia = vtkIntArray::New(); ia->SetName(vtkChacoReader::GetGlobalElementIdArrayName()); ia->SetNumberOfValues(len); for (vtkIdType i = 0; i < len; i++) { ia->SetValue(i, i + 1); } output->GetCellData()->AddArray(ia); ia->Delete(); } //------------------------------------------------------------------------------ void vtkChacoReader::AddNodeIds(vtkUnstructuredGrid* output) { // The vertex IDs in a Chaco file begin at 1 for the first // vertex in the .coords file, and increase by 1 thereafter. vtkIdType len = output->GetNumberOfPoints(); vtkIntArray* ia = vtkIntArray::New(); ia->SetName(vtkChacoReader::GetGlobalNodeIdArrayName()); ia->SetNumberOfValues(len); for (vtkIdType i = 0; i < len; i++) { ia->SetValue(i, i + 1); } output->GetPointData()->AddArray(ia); ia->Delete(); } //------------------------------------------------------------------------------ void vtkChacoReader::PrintSelf(ostream& os, vtkIndent indent) { int i = 0; this->Superclass::PrintSelf(os, indent); if (this->GenerateGlobalElementIdArray) { os << indent << "GenerateGlobalElementIdArray: On\n"; } else { os << indent << "GenerateGlobalElementIdArray: Off\n"; } if (this->GenerateGlobalNodeIdArray) { os << indent << "GenerateGlobalNodeIdArray: On\n"; } else { os << indent << "GenerateGlobalNodeIdArray: Off\n"; } if (this->GenerateVertexWeightArrays) { os << indent << "GenerateVertexWeightArrays: On\n"; } else { os << indent << "GenerateVertexWeightArrays: Off\n"; } if (this->GenerateEdgeWeightArrays) { os << indent << "GenerateEdgeWeightArrays: On\n"; } else { os << indent << "GenerateEdgeWeightArrays: Off\n"; } os << indent << "Base Name: " << (this->BaseName ? this->BaseName : "(none)") << "\n"; os << indent << "Dimensionality: " << this->Dimensionality << "\n"; os << indent << "NumberOfVertices: " << this->NumberOfVertices << "\n"; os << indent << "NumberOfEdges: " << this->NumberOfEdges << "\n"; os << indent << "NumberOfVertexWeights: " << this->NumberOfVertexWeights << "\n"; os << indent << "NumberOfEdgeWeights: " << this->NumberOfEdgeWeights << "\n"; os << indent << "NumberOfPointWeightArrays: " << this->NumberOfPointWeightArrays << "\n"; os << indent << "NumberOfCellWeightArrays: " << this->NumberOfCellWeightArrays << "\n"; for (i = 1; i <= this->NumberOfPointWeightArrays; i++) { cout << "vertex weight array name: " << this->GetVertexWeightArrayName(i) << endl; } for (i = 1; i <= this->NumberOfCellWeightArrays; i++) { cout << "edge weight array name: " << this->GetEdgeWeightArrayName(i) << endl; } } //------------------------------------------------------------------------------ void vtkChacoReader::CloseCurrentFile() { if (this->CurrentGeometryFP) { fclose(this->CurrentGeometryFP); fclose(this->CurrentGraphFP); this->CurrentGeometryFP = nullptr; this->CurrentGraphFP = nullptr; } } //------------------------------------------------------------------------------ int vtkChacoReader::OpenCurrentFile() { int result = 0; if (this->CurrentGeometryFP == nullptr) { int len = static_cast(strlen(this->BaseName)); char* buf = new char[len + 64]; snprintf(buf, len + 64, "%s.coords", this->BaseName); this->CurrentGeometryFP = vtksys::SystemTools::Fopen(buf, "r"); if (this->CurrentGeometryFP == nullptr) { vtkErrorMacro(<< "Problem opening " << buf); this->SetCurrentBaseName(nullptr); } else { snprintf(buf, len + 64, "%s.graph", this->BaseName); this->CurrentGraphFP = vtksys::SystemTools::Fopen(buf, "r"); if (this->CurrentGraphFP == nullptr) { vtkErrorMacro(<< "Problem opening " << buf); this->SetCurrentBaseName(nullptr); fclose(this->CurrentGeometryFP); this->CurrentGeometryFP = nullptr; } else { this->SetCurrentBaseName(this->GetBaseName()); result = 1; } } delete[] buf; } return result; } //------------------------------------------------------------------------------ // Code to read Chaco files. // This software was developed by Bruce Hendrickson and Robert Leland // at Sandia National Laboratories under US Department of Energy // contract DE-AC04-76DP00789 and is copyrighted by Sandia Corporation. void vtkChacoReader::ResetInputBuffers() { this->Offset = 0; this->Break_pnt = 200; this->Save_pnt = 0; } //------------------------------------------------------------------------------ int vtkChacoReader::InputGeom(vtkIdType nvtxs, // Number of vertices to read in int igeom, // Dimension (1, 2 or 3), or 0 if you don't know double* x, double* y, double* z) { double xc = 0.0, yc = 0.0, zc = 0.0; int line_num, end_flag, ndims, i = 0; rewind(this->CurrentGeometryFP); line_num = 0; end_flag = 1; while (end_flag == 1) { xc = this->ReadVal(this->CurrentGeometryFP, &end_flag); ++line_num; } if (end_flag == -1) { vtkErrorMacro(<< "No values found in geometry file " << this->BaseName << ".coords"); return 0; } if (igeom == 0) { ndims = 1; yc = this->ReadVal(this->CurrentGeometryFP, &end_flag); if (end_flag == 0) { ndims = 2; zc = this->ReadVal(this->CurrentGeometryFP, &end_flag); if (end_flag == 0) { ndims = 3; this->ReadVal(this->CurrentGeometryFP, &end_flag); if (!end_flag) { vtkErrorMacro(<< "Invalid geometry file " << this->BaseName << ".coords"); return 0; } } } this->Dimensionality = ndims; } else { ndims = this->Dimensionality; if (ndims > 1) { yc = this->ReadVal(this->CurrentGeometryFP, &end_flag); if (ndims > 2) { zc = this->ReadVal(this->CurrentGeometryFP, &end_flag); } } this->ReadVal(this->CurrentGeometryFP, &end_flag); } x[0] = xc; if (ndims > 1) { y[0] = yc; if (ndims > 2) { z[0] = zc; } } if (nvtxs == 1) { return 1; } for (int nread = 1; nread < nvtxs; nread++) { ++line_num; if (ndims == 1) { i = fscanf(this->CurrentGeometryFP, "%lf", x + nread); } else if (ndims == 2) { i = fscanf(this->CurrentGeometryFP, "%lf%lf", x + nread, y + nread); } else if (ndims == 3) { i = fscanf(this->CurrentGeometryFP, "%lf%lf%lf", x + nread, y + nread, z + nread); } if (i == EOF) { vtkErrorMacro(<< "Too few lines in " << this->BaseName << ".coords"); return 0; } else if (i != ndims) { vtkErrorMacro(<< "Wrong dimension in " << this->BaseName << ".coords"); return 0; } } return 1; } //------------------------------------------------------------------------------ int vtkChacoReader::InputGraph1() { /* Read first line of input (= nvtxs, narcs, option). */ /* The (decimal) digits of the option variable mean: 1's digit not zero => input edge weights 10's digit not zero => input vertex weights 100's digit not zero => include vertex numbers */ FILE* fin = this->CurrentGraphFP; rewind(fin); /* Read any leading comment lines */ int end_flag = 1; vtkIdType numVertices = 0; while (end_flag == 1) { numVertices = this->ReadInt(fin, &end_flag); } if (numVertices <= 0) { vtkErrorMacro(<< "Invalid file " << this->BaseName << ".graph"); return 0; } this->NumberOfVertices = numVertices; this->NumberOfEdges = this->ReadInt(fin, &end_flag); if (this->NumberOfEdges < 0) { vtkErrorMacro(<< "Invalid file " << this->BaseName << ".graph"); return 0; } this->NumberOfVertexWeights = 0; this->NumberOfEdgeWeights = 0; this->GraphFileHasVertexNumbers = 0; /* Check if vertex or edge weights are used */ if (!end_flag) { vtkIdType option = this->ReadInt(fin, &end_flag); this->NumberOfEdgeWeights = (int)(option - 10 * (option / 10)); option /= 10; this->NumberOfVertexWeights = (int)(option - 10 * (option / 10)); option /= 10; this->GraphFileHasVertexNumbers = (int)(option - 10 * (option / 10)); } /* Read weight dimensions if they are specified separately */ if (!end_flag && this->NumberOfVertexWeights == 1) { vtkIdType j = this->ReadInt(fin, &end_flag); if (!end_flag) this->NumberOfVertexWeights = (int)j; } if (!end_flag && this->NumberOfEdgeWeights == 1) { vtkIdType j = this->ReadInt(fin, &end_flag); if (!end_flag) this->NumberOfEdgeWeights = (int)j; } return 1; } //------------------------------------------------------------------------------ int vtkChacoReader::InputGraph2( vtkIdType** start, // start[i]: location of vertex i in adjacency array vtkIdType** adjacency, // by vertex by vertex neighbor double** vweights, // by vertex by weight (or nullptr if no weights wanted) double** eweights) // edge weights in order in file (or nullptr) { vtkIdType* adjptr; double* ewptr; vtkIdType vtx, sum_edges, vertex, new_vertex; double weight, eweight; vtkIdType neighbor, j; int retVal = 1; vtkIdType nvtxs = this->NumberOfVertices; vtkIdType narcs = this->NumberOfEdges; int vwgt_dim = this->NumberOfVertexWeights; int ewgt_dim = this->NumberOfEdgeWeights; int vtxnums = this->GraphFileHasVertexNumbers; if (nvtxs < 1) { vtkErrorMacro(<< "vtkChacoReader::InputGraph2, NumberOfVertices not set"); return 0; } if (start == nullptr) { vtkErrorMacro(<< "vtkChacoReader::InputGraph2, parameter list"); return 0; } *start = nullptr; if (adjacency) { *adjacency = nullptr; } if (vweights) { *vweights = nullptr; } if (eweights) { *eweights = nullptr; } int line_num = 0; FILE* fin = this->CurrentGraphFP; rewind(fin); /* Read past the first line containing the metadata */ int end_flag = 1; while (end_flag == 1) { this->ReadInt(fin, &end_flag); ++line_num; } while (!end_flag) { this->ReadInt(fin, &end_flag); } ++line_num; /* Allocate space for rows and columns. */ *start = new vtkIdType[nvtxs + 1]; if (adjacency && (narcs > 0)) { *adjacency = new vtkIdType[2 * narcs + 1]; // why +1 ? } if (vweights && (vwgt_dim > 0)) { *vweights = new double[nvtxs * vwgt_dim]; } if (eweights && (ewgt_dim > 0) && (narcs > 0)) { *eweights = new double[(2 * narcs + 1) * ewgt_dim]; // why +1 ? } adjptr = (adjacency ? *adjacency : nullptr); ewptr = (eweights ? *eweights : nullptr); sum_edges = 0; (*start)[0] = 0; vertex = 0; vtx = 0; new_vertex = 1; while (((vwgt_dim > 0) || vtxnums || narcs) && end_flag != -1) { ++line_num; /* If multiple input lines per vertex, read vertex number. */ if (vtxnums) { j = this->ReadInt(fin, &end_flag); if (end_flag) { if (vertex == nvtxs) { break; } vtkErrorMacro(<< "Missing vertex number " << this->BaseName << ".graph, line " << line_num); retVal = 0; goto done; } if (j != vertex && j != vertex + 1) { vtkErrorMacro(<< "Out of order vertex " << this->BaseName << ".graph, line " << line_num); retVal = 0; goto done; } if (j != vertex) { new_vertex = 1; vertex = j; } else { new_vertex = 0; } } else { vertex = ++vtx; } if (vertex > nvtxs) break; /* If vertices are weighted, read vertex weight. */ if ((vwgt_dim > 0) && new_vertex) { for (j = 0; j < (vwgt_dim); j++) { weight = ReadVal(fin, &end_flag); if (end_flag) { vtkErrorMacro(<< "Vertex weights " << this->BaseName << ".graph, line " << line_num); retVal = 0; goto done; } if (vweights) { (*vweights)[(vertex - 1) * (vwgt_dim) + j] = weight; } } } /* Read number of adjacent vertex. */ neighbor = this->ReadInt(fin, &end_flag); while (!end_flag) { if (ewgt_dim > 0) { for (j = 0; j < ewgt_dim; j++) { eweight = ReadVal(fin, &end_flag); if (end_flag) { vtkErrorMacro(<< "Edge weights " << this->BaseName << ".graph, line " << line_num); retVal = 0; goto done; } if (ewptr) { *ewptr++ = eweight; } } } /* Add edge to data structure. */ if (++sum_edges > 2 * narcs) { vtkErrorMacro(<< "Too many adjacencies " << this->BaseName << ".graph, line " << line_num); retVal = 0; goto done; } if (adjptr) { *adjptr++ = neighbor; } /* Read number of next adjacent vertex. */ neighbor = this->ReadInt(fin, &end_flag); } (*start)[vertex] = sum_edges; } done: if ((vertex == 0) || (retVal == 0)) { /* Graph was empty */ delete[] * start; *start = nullptr; delete[] * adjacency; *adjacency = nullptr; delete[] * vweights; *vweights = nullptr; delete[] * eweights; *eweights = nullptr; } return retVal; } //------------------------------------------------------------------------------ double vtkChacoReader::ReadVal(FILE* infile, int* end_flag) { double val; char* ptr; char* ptr2; int length; int length_left; int white_seen; int done; int i; *end_flag = 0; if (Offset == 0 || this->Offset >= this->Break_pnt) { if (Offset >= this->Break_pnt) { length_left = this->Line_length - this->Save_pnt - 1; ptr2 = this->Line; ptr = &Line[Save_pnt]; for (i = length_left; i; i--) *ptr2++ = *ptr++; length = this->Save_pnt + 1; } else { length = this->Line_length; length_left = 0; } this->Line[this->Line_length - 1] = ' '; this->Line[this->Line_length - 2] = ' '; /* Now read next line, or next segment of current one. */ ptr2 = fgets(&Line[length_left], length, infile); if (ptr2 == (char*)nullptr) { *end_flag = -1; return ((double)0.0); } if (Line[this->Line_length - 1] == '\0' && this->Line[this->Line_length - 2] != '\0' && this->Line[this->Line_length - 2] != '\n' && this->Line[this->Line_length - 2] != '\f') { /* Line too long. Find last safe place in line. */ this->Break_pnt = this->Line_length - 1; this->Save_pnt = this->Break_pnt; white_seen = 0; done = 0; while (!done) { --Break_pnt; if (Line[Break_pnt] != '\0') { if (isspace((int)(Line[Break_pnt]))) { if (!white_seen) { this->Save_pnt = this->Break_pnt + 1; white_seen = 1; } } else if (white_seen) { done = 1; } } } } else { this->Break_pnt = this->Line_length; } this->Offset = 0; } while (isspace((int)(Line[Offset])) && this->Offset < this->Line_length) this->Offset++; if (Line[Offset] == '%' || this->Line[Offset] == '#') { *end_flag = 1; if (Break_pnt < this->Line_length) { FlushLine(infile); } return ((double)0.0); } ptr = &(Line[Offset]); val = strtod(ptr, &ptr2); if (ptr2 == ptr) { this->Offset = 0; *end_flag = 1; return ((double)0.0); } else { this->Offset = (int)(ptr2 - this->Line) / sizeof(char); } return (val); } //------------------------------------------------------------------------------ vtkIdType vtkChacoReader::ReadInt(FILE* infile, int* end_flag) { vtkIdType val; char* ptr; char* ptr2; int length; int length_left; int white_seen; int done; int i; *end_flag = 0; if (Offset == 0 || this->Offset >= this->Break_pnt) { if (Offset >= this->Break_pnt) { length_left = this->Line_length - this->Save_pnt - 1; ptr2 = this->Line; ptr = &Line[Save_pnt]; for (i = length_left; i; i--) *ptr2++ = *ptr++; length = this->Save_pnt + 1; } else { length = this->Line_length; length_left = 0; } this->Line[this->Line_length - 1] = ' '; this->Line[this->Line_length - 2] = ' '; /* Now read next line, or next segment of current one. */ ptr2 = fgets(&Line[length_left], length, infile); if (ptr2 == (char*)nullptr) { *end_flag = -1; return (0); } if (this->Line[this->Line_length - 1] == '\0' && this->Line[this->Line_length - 2] != '\0' && this->Line[this->Line_length - 2] != '\n' && this->Line[this->Line_length - 2] != '\f') { /*Line too long. Find last safe place in line. */ this->Break_pnt = this->Line_length - 1; this->Save_pnt = this->Break_pnt; white_seen = 0; done = 0; while (!done) { --Break_pnt; if (Line[Break_pnt] != '\0') { if (isspace((int)(Line[Break_pnt]))) { if (!white_seen) { this->Save_pnt = this->Break_pnt + 1; white_seen = 1; } } else if (white_seen) { done = 1; } } } } else { this->Break_pnt = this->Line_length; } this->Offset = 0; } while (isspace((int)(Line[Offset])) && this->Offset < this->Line_length) this->Offset++; if (Line[Offset] == '%' || this->Line[Offset] == '#') { *end_flag = 1; if (Break_pnt < this->Line_length) { FlushLine(infile); } return (0); } ptr = &(Line[Offset]); val = (int)strtol(ptr, &ptr2, 10); if (ptr2 == ptr) { this->Offset = 0; *end_flag = 1; return (0); } else { this->Offset = (int)(ptr2 - this->Line) / sizeof(char); } return (val); } //------------------------------------------------------------------------------ void vtkChacoReader::FlushLine(FILE* infile) { char c; c = getc(infile); while (c != '\n' && c != '\f') { c = getc(infile); } }