/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkChacoReader.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. =========================================================================*/ /*---------------------------------------------------------------------------- Copyright (c) Sandia Corporation See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. ----------------------------------------------------------------------------*/ #include #include #include "vtkChacoReader.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkInformation.h" #include "vtkInformationDoubleVectorKey.h" #include "vtkInformationVector.h" #include "vtkIntArray.h" #include "vtkObjectFactory.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkUnstructuredGrid.h" vtkCxxRevisionMacro(vtkChacoReader, "$Revision: 1.9 $"); vtkStandardNewMacro(vtkChacoReader); //---------------------------------------------------------------------------- // Description: // Instantiate object with NULL filename. vtkChacoReader::vtkChacoReader() { this->BaseName = NULL; this->GenerateGlobalElementIdArray = 1; this->GenerateGlobalNodeIdArray = 1; this->GenerateVertexWeightArrays = 0; this->GenerateEdgeWeightArrays = 0; this->EarrayName = NULL; this->VarrayName = NULL; 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 = NULL; this->CurrentGraphFP = NULL; this->CurrentBaseName = NULL; this->DataCache = vtkUnstructuredGrid::New(); this->RemakeDataCacheFlag = 1; this->Line_length = 200; this->Line = new char [200]; this->Offset = 0; this->Break_pnt = 200; this->Save_pnt = 0; this->SetNumberOfInputPorts(0); } //---------------------------------------------------------------------------- vtkChacoReader::~vtkChacoReader() { this->SetBaseName(NULL); this->SetCurrentBaseName(NULL); this->ClearWeightArrayNames(); this->DataCache->Delete(); this->DataCache = NULL; delete [] this->Line; } //---------------------------------------------------------------------------- void vtkChacoReader::ClearWeightArrayNames() { int i=0; if (this->VarrayName) { for (i=0; iNumberOfVertexWeights; i++) { delete [] this->VarrayName[i]; } delete [] this->VarrayName; this->VarrayName = NULL; } if (this->EarrayName) { for (i=0; iNumberOfEdgeWeights; i++) { delete [] this->EarrayName[i]; } delete [] this->EarrayName; this->EarrayName = NULL; } } void vtkChacoReader::MakeWeightArrayNames(int nv, int ne) { int i=0; if (nv > 0) { this->VarrayName = new char *[nv]; for (i=0; iVarrayName[i] = new char [64]; sprintf(this->VarrayName[i], "VertexWeight%d", i+1); } } if (ne > 0) { this->EarrayName = new char *[ne]; for (i=0; iEarrayName[i] = new char [64]; sprintf(this->EarrayName[i], "EdgeWeight%d", i+1); } } } char *vtkChacoReader::GetVertexWeightArrayName(int weight) { if (this->GetGenerateVertexWeightArrays() && (weight > 0) && (weight <= this->NumberOfVertexWeights)) { return this->VarrayName[weight-1]; } return NULL; } char *vtkChacoReader::GetEdgeWeightArrayName(int weight) { if (this->GetGenerateEdgeWeightArrays() && (weight > 0) && (weight <= this->NumberOfEdgeWeights)) { return this->EarrayName[weight-1]; } return NULL; } //---------------------------------------------------------------------------- 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 == NULL) || strcmp(this->CurrentBaseName, this->BaseName)); 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 = vtkDoubleArray::SafeDownCast( this->DataCache->GetPointData()->GetArray(this->VarrayName[0])); haveVertexWeightArrays = (da != NULL); } if (ncells && (this->NumberOfEdgeWeights > 0)) { vtkDoubleArray *da = vtkDoubleArray::SafeDownCast( this->DataCache->GetCellData()->GetArray(this->EarrayName[0])); haveEdgeWeightArrays = (da != NULL); } 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; iNumberOfVertexWeights; i++) { this->DataCache->GetPointData()->RemoveArray(this->VarrayName[i]); } this->NumberOfPointWeightArrays = 0; } if (haveEdgeWeightArrays && !this->GenerateEdgeWeightArrays) { for (i=0; iNumberOfEdgeWeights; i++) { this->DataCache->GetCellData()->RemoveArray(this->EarrayName[i]); } this->NumberOfCellWeightArrays = 0; } vtkIntArray *ia = vtkIntArray::SafeDownCast( this->DataCache->GetCellData()->GetArray(this->GetGlobalElementIdArrayName())); if (!ia && this->GenerateGlobalElementIdArray) { this->AddElementIds(this->DataCache); } else if (ia && !this->GenerateGlobalElementIdArray) { this->DataCache->GetCellData()->RemoveArray(this->GetGlobalElementIdArrayName()); } ia = vtkIntArray::SafeDownCast( this->DataCache->GetPointData()->GetArray(this->GetGlobalNodeIdArrayName())); if (!ia && this->GenerateGlobalNodeIdArray) { this->AddNodeIds(this->DataCache); } else if (ia && !this->GenerateGlobalNodeIdArray) { this->DataCache->GetPointData()->RemoveArray(this->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 = NULL; double *z = NULL; 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"); if (x) delete [] x; if (y) delete [] y; return 0; } int rc = this->InputGeom(this->NumberOfVertices, this->Dimensionality, x, y, z); this->ResetInputBuffers(); if (rc == 0) { if (x) delete [] x; if (y) delete [] y; if (z) delete [] z; return 0; } if (this->Dimensionality == 3) { for (id=0; idNumberOfVertices; id++) { ptarray->InsertNextPoint(x[id], y[id], z[id]); } } else if (this->Dimensionality == 2) { for (id=0; idNumberOfVertices; id++) { ptarray->InsertNextPoint(x[id], y[id], 0.0); } } else if (this->Dimensionality == 1) { for (id=0; idNumberOfVertices; id++) { ptarray->InsertNextPoint(x[id], 0.0, 0.0); } } output->SetPoints(ptarray); if (x) delete [] x; if (y) delete [] y; if (z) 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 = NULL; vtkIdType *nbors = NULL; double *vweights = NULL; double *eweights = NULL; double **vw = NULL; double **ew = NULL; 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 = NULL; vtkDoubleArray **earrays = NULL; double *vwgt = NULL; double *ewgt = NULL; if (vw) { varrays = new vtkDoubleArray * [this->NumberOfVertexWeights]; for (i=0; iNumberOfVertexWeights; 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; iNumberOfEdgeWeights; i++) { earrays[i] = vtkDoubleArray::New(); earrays[i]->SetNumberOfValues(this->NumberOfEdges); earrays[i]->SetName(this->EarrayName[i]); } ewgt = eweights; } vtkIdTypeArray *ca = vtkIdTypeArray::New(); if (idx == NULL) { // 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; idNumberOfVertices; id++) { *captr++ = 1; // number of vertices in cell *captr++ = id; // internal ID of vertex if (vw) { for (int w=0; wNumberOfVertexWeights; w++) { varrays[w]->SetValue(id, *vwgt++); } } } vtkCellArray *cells = vtkCellArray::New(); cells->SetCells(this->NumberOfVertices, 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; iNumberOfEdgeWeights; 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; iNumberOfVertexWeights; 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->SetCells(this->NumberOfEdges, 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; iNumberOfVertexWeights; i++) { if (retVal) { output->GetPointData()->AddArray(varrays[i]); } varrays[i]->Delete(); } delete [] varrays; } if (ew) { delete [] eweights; for (i=0; iNumberOfEdgeWeights; 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(this->GetGlobalElementIdArrayName()); ia->SetNumberOfValues(len); for (vtkIdType i=0; iSetValue(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(this->GetGlobalNodeIdArrayName()); ia->SetNumberOfValues(len); for (vtkIdType i=0; iSetValue(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 = NULL; this->CurrentGraphFP = NULL; } } int vtkChacoReader::OpenCurrentFile() { int result = 0; if ( this->CurrentGeometryFP == NULL) { int len = strlen(this->BaseName); char *buf = new char [len+64]; sprintf(buf, "%s.coords", this->BaseName); this->CurrentGeometryFP = fopen(buf, "r"); if (this->CurrentGeometryFP == NULL) { vtkErrorMacro(<< "Problem opening " << buf); this->SetCurrentBaseName( NULL ); } else { sprintf(buf, "%s.graph", this->BaseName); this->CurrentGraphFP = fopen(buf, "r"); if (this->CurrentGraphFP == NULL) { vtkErrorMacro(<< "Problem opening " << buf); this->SetCurrentBaseName( NULL ); fclose(this->CurrentGeometryFP); this->CurrentGeometryFP = NULL; } 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->Line_length = 200; 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 NULL if no weights wanted) double **eweights ) // edge weights in order in file (or NULL) { 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 == NULL) { vtkErrorMacro(<< "vtkChacoReader::InputGraph2, parameter list"); return 0; } *start = NULL; if (adjacency) { *adjacency = NULL; } if (vweights) { *vweights = NULL; } if (eweights) { *eweights = NULL; } 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) { j = this->ReadInt(fin, &end_flag); ++line_num; } while (!end_flag) { j = 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 ? } else { *adjacency = NULL; } 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 : NULL); ewptr = (eweights ? *eweights : NULL); 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; jBaseName << ".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 = NULL; if (adjacency && (*adjacency != NULL)) { delete [] *adjacency; *adjacency = NULL; } if (vweights && (*vweights != NULL)) { delete [] *vweights; *vweights = NULL; } if (eweights && (*eweights != NULL)) { delete [] *eweights; *eweights = NULL; } } 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 *) NULL) { *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 *) NULL) { *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); } }