/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkFacetReader.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. =========================================================================*/ #include "vtkFacetReader.h" #include "vtkPolyData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkErrorCode.h" #include "vtkCellType.h" #include "vtkCellArray.h" #include "vtkGarbageCollector.h" #include "vtkAppendPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkUnsignedIntArray.h" #include "vtkDoubleArray.h" #include "vtkSmartPointer.h" #include #include #include vtkCxxRevisionMacro(vtkFacetReader, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkFacetReader); //------------------------------------------------------------------------------ // Due to a buggy stream library on the HP and another on Mac OSX, we // need this very carefully written version of getline. Returns true // if any data were read before the end-of-file was reached. // static bool GetLineFromStream(istream& is, vtkstd::string& line, bool *has_newline = 0) { const int bufferSize = 1024; char buffer[bufferSize]; line = ""; bool haveData = false; if ( has_newline ) { *has_newline = false; } // If no characters are read from the stream, the end of file has // been reached. while((is.getline(buffer, bufferSize), is.gcount() > 0)) { haveData = true; line.append(buffer); // If newline character was read, the gcount includes the // character, but the buffer does not. The end of line has been // reached. if(strlen(buffer) < static_cast(is.gcount())) { if ( has_newline ) { *has_newline = true; } break; } // The fail bit may be set. Clear it. is.clear(is.rdstate() & ~ios::failbit); } return haveData; } //---------------------------------------------------------------------------- vtkFacetReader::vtkFacetReader() { this->FileName = NULL; this->SetNumberOfInputPorts(0); } //---------------------------------------------------------------------------- vtkFacetReader::~vtkFacetReader() { if (this->FileName) { delete [] this->FileName; } } //---------------------------------------------------------------------------- int vtkFacetReader::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { // get the info object vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the ouptut vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); if ( !this->FileName ) { vtkErrorMacro("No filename specified"); return 1; } struct stat fs; if ( stat(this->FileName, &fs) ) { this->SetErrorCode(vtkErrorCode::FileNotFoundError); vtkErrorMacro("Specified filename not found"); return 1; } ifstream ifs(this->FileName, ios::in); if (!ifs) { this->SetErrorCode(vtkErrorCode::FileNotFoundError); vtkErrorMacro("Specified filename not found"); return 1; } vtkDebugMacro( << "Reading Facet file"); vtkstd::string line; // Read first row if ( !GetLineFromStream(ifs, line) ) { vtkErrorMacro("Cannot read file comment"); return 1; } // Read number of parts int num_parts = 0; if ( !GetLineFromStream(ifs, line) || sscanf(line.c_str(), "%d", &num_parts) != 1 || num_parts < 0 ) { vtkErrorMacro("Bad number of parts line"); return 1; } vtkDebugMacro("Number of parts is: " << num_parts); // Buffers for various information from file vtkstd::vector pointList; vtkstd::vector stringBuffer; // We will need append individual parts together. Once multiblock is // supported, this should go out. vtkSmartPointer appendPtr = vtkSmartPointer::New(); // Block garbage collection so that appends will not take too long. vtkGarbageCollector::DeferredCollectionPush(); int part; int error = 0; // Loop thrugh individual parts for ( part = 0; part < num_parts || error; part ++ ) { vtkstd::string partName; vtkDebugMacro("Reading part: " << part); // Read part name if ( !GetLineFromStream(ifs, partName) ) { vtkErrorMacro("Cannot read part name"); error = 1; break; } vtkDebugMacro("Part name: " << partName.c_str()); // Read cell/point index and geometry information including the number of // points. cell/point index for points is always 0 int cell_point_index = -1; int numpts = -1, tmp; if ( !GetLineFromStream(ifs, line) || sscanf(line.c_str(), "%d", &cell_point_index) != 1 || cell_point_index != 0 || !GetLineFromStream(ifs, line) || sscanf(line.c_str(), "%d %d %d", &numpts, &tmp, &tmp) != 3 || numpts < 0 ) { vtkErrorMacro("Problem reading number of points"); error = 1; break; } vtkIdType num_points = numpts; vtkIdType point; vtkSmartPointer myPointsPtr = vtkSmartPointer::New(); // Read individual points for ( point = 0; point < num_points; point ++ ) { // Read point double x = 0, y = 0, z = 0; if ( !GetLineFromStream(ifs, line) || sscanf(line.c_str(), "%lf %lf %lf", &x, &y, &z) != 3 ) { vtkErrorMacro("Problem reading point: " << point); error = 1; break; } myPointsPtr->InsertNextPoint(x, y, z); } if ( error ) { break; } // Read cell point index if ( !GetLineFromStream(ifs, line) || sscanf(line.c_str(), "%d", &cell_point_index) != 1 || cell_point_index != 1 ) { vtkErrorMacro("Cannot read cell/point index or it is not 1"); error = 1; break; } // Read part name if ( !GetLineFromStream(ifs, line) || partName != line ) { vtkErrorMacro("Cannot read part name or the part name does not match"); error = 1; break; } // Read topology information int numcells = -1, numpointpercell = -1; if ( !GetLineFromStream(ifs, line) || sscanf(line.c_str(), "%d %d", &numcells, &numpointpercell) != 2 || numcells < 0 || numpointpercell < 0 ) { vtkErrorMacro("Problem reading number of cells and points per cell"); error = 1; break; } vtkIdType num_cells = numcells; vtkIdType num_points_per_cell = numpointpercell; if ( pointList.size() < static_cast(num_points_per_cell) ) { pointList.resize(num_points_per_cell); } // We need arrays to store material and part number vtkSmartPointer materialArrayPtr = vtkSmartPointer::New(); materialArrayPtr->SetName("Material"); materialArrayPtr->SetNumberOfComponents(1); materialArrayPtr->SetNumberOfTuples(num_cells); vtkSmartPointer relativePartArrayPtr = vtkSmartPointer::New(); relativePartArrayPtr->SetName("RelativePartNumber"); relativePartArrayPtr->SetNumberOfComponents(1); relativePartArrayPtr->SetNumberOfTuples(num_cells); vtkSmartPointer myCellsPtr = vtkSmartPointer::New(); // Read cells vtkIdType cell; for ( cell = 0; cell < num_cells; cell ++ ) { // Read cell if ( !GetLineFromStream(ifs, line) ) { vtkErrorMacro("Cannot read cell: " << cell); error = 1; break; } // Read specified number of points from cell information if ( stringBuffer.size() < line.size()+1 ) { stringBuffer.resize(line.size()+1); } char* strPtr = &(*stringBuffer.begin()); strcpy(strPtr, line.c_str()); istrstream lineStream(strPtr); vtkIdType kk; int material = -1, relativePartNumber = -1; for ( kk = 0; kk < num_points_per_cell; kk ++ ) { int val; if ( !(lineStream >> val) ) { vtkErrorMacro("Cannot extract cell points for cell: " << cell); error = 1; break; } // point indices start with 0, while cell descriptions have point // indices starting with 1 pointList[kk] = val -1; } // Extract material and part number if ( !(lineStream >> material >> relativePartNumber) ) { vtkErrorMacro("Cannot extract cell material and part for cell: " << cell); error = 1; break; } materialArrayPtr->SetTuple1(cell, material); relativePartArrayPtr->SetTuple1(cell, relativePartNumber); myCellsPtr->InsertNextCell(num_points_per_cell, &(*pointList.begin())); } if ( error ) { break; } vtkIdType cc; // Create another array with absolute part number vtkUnsignedIntArray* partNumberArray = vtkUnsignedIntArray::New(); partNumberArray->SetName("PartNumber"); partNumberArray->SetNumberOfComponents(1); partNumberArray->SetNumberOfTuples(num_cells); for ( cc = 0; cc < partNumberArray->GetNumberOfTuples(); cc ++ ) { partNumberArray->SetTuple1(cc, part); } // Create part and store it vtkPolyData* partGrid = vtkPolyData::New(); switch ( num_points_per_cell ) { case 1: partGrid->SetVerts(myCellsPtr); break; case 2: partGrid->SetLines(myCellsPtr); break; case 3: partGrid->SetPolys(myCellsPtr); break; default: partGrid->SetPolys(myCellsPtr); break; } partGrid->SetPoints(myPointsPtr); partGrid->GetCellData()->AddArray(partNumberArray); partGrid->GetCellData()->AddArray(materialArrayPtr); partGrid->GetCellData()->AddArray(relativePartArrayPtr); partGrid->GetCellData()->SetScalars(materialArrayPtr); appendPtr->AddInput(partGrid); partNumberArray->Delete(); partGrid->Delete(); } if ( !error ) { // If everything ok, use append. appendPtr->Update(); output->ShallowCopy(appendPtr->GetOutput()); } // Release garbage collection vtkGarbageCollector::DeferredCollectionPop(); vtkDebugMacro("Done reading file: " << this->FileName); return 1; } //---------------------------------------------------------------------------- void vtkFacetReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "File Name: " << (this->FileName ? this->FileName : "(none)") << "\n"; }