/*========================================================================= Program: Visualization Toolkit Module: vtkXMLUnstructuredDataWriter.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. =========================================================================*/ #include "vtkXMLUnstructuredDataWriter.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkCellIterator.h" #include "vtkDataArray.h" #include "vtkDataCompressor.h" #include "vtkDataSetAttributes.h" #include "vtkErrorCode.h" #include "vtkGenericCell.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPointSet.h" #include "vtkPoints.h" #include "vtkPolyhedron.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkUnsignedCharArray.h" #define vtkXMLOffsetsManager_DoNotInclude #include "vtkXMLOffsetsManager.h" #undef vtkXMLOffsetsManager_DoNotInclude #include //---------------------------------------------------------------------------- vtkXMLUnstructuredDataWriter::vtkXMLUnstructuredDataWriter() { this->NumberOfPieces = 1; this->WritePiece = -1; this->GhostLevel = 0; this->CellPoints = vtkIdTypeArray::New(); this->CellOffsets = vtkIdTypeArray::New(); this->CellPoints->SetName("connectivity"); this->CellOffsets->SetName("offsets"); this->CurrentPiece = 0; this->FieldDataOM->Allocate(0); this->PointsOM = new OffsetsManagerGroup; this->PointDataOM = new OffsetsManagerArray; this->CellDataOM = new OffsetsManagerArray; this->Faces = vtkIdTypeArray::New(); this->FaceOffsets = vtkIdTypeArray::New(); this->Faces->SetName("faces"); this->FaceOffsets->SetName("faceoffsets"); } //---------------------------------------------------------------------------- vtkXMLUnstructuredDataWriter::~vtkXMLUnstructuredDataWriter() { this->CellPoints->Delete(); this->CellOffsets->Delete(); this->Faces->Delete(); this->FaceOffsets->Delete(); delete this->PointsOM; delete this->PointDataOM; delete this->CellDataOM; } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "NumberOfPieces: " << this->NumberOfPieces << "\n"; os << indent << "WritePiece: " << this->WritePiece << "\n"; os << indent << "GhostLevel: " << this->GhostLevel << "\n"; } //---------------------------------------------------------------------------- vtkPointSet* vtkXMLUnstructuredDataWriter::GetInputAsPointSet() { return static_cast(this->Superclass::GetInput()); } //---------------------------------------------------------------------------- int vtkXMLUnstructuredDataWriter::ProcessRequest(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { if(request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT())) { if((this->WritePiece < 0) || (this->WritePiece >= this->NumberOfPieces)) { this->SetInputUpdateExtent( this->CurrentPiece, this->NumberOfPieces, this->GhostLevel); } else { this->SetInputUpdateExtent( this->WritePiece, this->NumberOfPieces, this->GhostLevel); } return 1; } // generate the data else if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) { this->SetErrorCode(vtkErrorCode::NoError); if(!this->Stream && !this->FileName && !this->WriteToOutputString) { this->SetErrorCode(vtkErrorCode::NoFileNameError); vtkErrorMacro("The FileName or Stream must be set first or " "the output must be written to a string."); return 0; } int numPieces = this->NumberOfPieces; if (this->WritePiece >= 0) { this->CurrentPiece = this->WritePiece; } else { float wholeProgressRange[2] = {0,1}; this->SetProgressRange(wholeProgressRange, this->CurrentPiece, this->NumberOfPieces); } int result = 1; if ((this->CurrentPiece == 0 && this->CurrentTimeIndex == 0) || this->WritePiece >= 0) { // We are just starting to write. Do not call // UpdateProgressDiscrete because we want a 0 progress callback the // first time. this->UpdateProgress(0); // Initialize progress range to entire 0..1 range. if (this->WritePiece >= 0) { float wholeProgressRange[2] = {0,1}; this->SetProgressRange(wholeProgressRange, 0, 1); } if (!this->OpenStream()) { this->NumberOfPieces = numPieces; return 0; } if (this->GetInputAsDataSet() != nullptr && (this->GetInputAsDataSet()->GetPointGhostArray() != nullptr && this->GetInputAsDataSet()->GetCellGhostArray() != nullptr)) { // use the current version for the file. this->UsePreviousVersion = false; } // Write the file. if (!this->StartFile()) { this->NumberOfPieces = numPieces; return 0; } if (!this->WriteHeader()) { this->NumberOfPieces = numPieces; return 0; } this->CurrentTimeIndex = 0; if( this->DataMode == vtkXMLWriter::Appended && this->FieldDataOM->GetNumberOfElements()) { // Write the field data arrays. this->WriteFieldDataAppendedData(this->GetInput()->GetFieldData(), this->CurrentTimeIndex, this->FieldDataOM); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } } } if( !(this->UserContinueExecuting == 0)) //if user ask to stop do not try to write a piece { result = this->WriteAPiece(); } if((this->WritePiece < 0) || (this->WritePiece >= this->NumberOfPieces)) { // Tell the pipeline to start looping. if (this->CurrentPiece == 0) { request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); } this->CurrentPiece++; } if (this->CurrentPiece == this->NumberOfPieces || this->WritePiece >= 0) { request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); this->CurrentPiece = 0; // We are done writing all the pieces, lets loop over time now: this->CurrentTimeIndex++; if( this->UserContinueExecuting != 1 ) { if (!this->WriteFooter()) { this->NumberOfPieces = numPieces; return 0; } if (!this->EndFile()) { this->NumberOfPieces = numPieces; return 0; } this->CloseStream(); this->CurrentTimeIndex = 0; // Reset } } this->NumberOfPieces = numPieces; // We have finished writing (at least this piece) this->SetProgressPartial(1); return result; } return this->Superclass::ProcessRequest(request, inputVector, outputVector); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::AllocatePositionArrays() { this->NumberOfPointsPositions = new vtkTypeInt64[this->NumberOfPieces]; this->PointsOM->Allocate(this->NumberOfPieces, this->NumberOfTimeSteps); this->PointDataOM->Allocate(this->NumberOfPieces); this->CellDataOM->Allocate(this->NumberOfPieces); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::DeletePositionArrays() { delete [] this->NumberOfPointsPositions; this->NumberOfPointsPositions = nullptr; } //---------------------------------------------------------------------------- int vtkXMLUnstructuredDataWriter::WriteHeader() { vtkIndent indent = vtkIndent().GetNextIndent(); ostream& os = *(this->Stream); if(!this->WritePrimaryElement(os, indent)) { return 0; } this->WriteFieldData(indent.GetNextIndent()); if(this->DataMode == vtkXMLWriter::Appended) { vtkIndent nextIndent = indent.GetNextIndent(); this->AllocatePositionArrays(); if((this->WritePiece < 0) || (this->WritePiece >= this->NumberOfPieces)) { // Loop over each piece and write its structure. int i; for(i=0; i < this->NumberOfPieces; ++i) { // Open the piece's element. os << nextIndent << "WriteAppendedPieceAttributes(i); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } os << ">\n"; this->WriteAppendedPiece(i, nextIndent.GetNextIndent()); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } // Close the piece's element. os << nextIndent << "\n"; } } else { // Write just the requested piece. // Open the piece's element. os << nextIndent << "WriteAppendedPieceAttributes(this->WritePiece); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } os << ">\n"; this->WriteAppendedPiece(this->WritePiece, nextIndent.GetNextIndent()); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } // Close the piece's element. os << nextIndent << "\n"; } // Close the primary element. os << indent << "GetDataSetName() << ">\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); this->DeletePositionArrays(); return 0; } this->StartAppendedData(); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } } return 1; } void CreateFaceStream(vtkCellIterator* cellIter, vtkIdTypeArray* faceStream, vtkIdTypeArray* faceOffsets) { vtkNew cell; faceStream->Reset(); faceOffsets->Reset(); vtkIdType offset(0); for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) { vtkIdType ct = cellIter->GetCellType(); if (ct != VTK_POLYHEDRON) { faceOffsets->InsertNextValue(-1); continue; } cellIter->GetCell(cell.GetPointer()); vtkCell* theCell = cell->GetRepresentativeCell(); vtkPolyhedron* poly = vtkPolyhedron::SafeDownCast(theCell); if (!poly || !poly->GetNumberOfFaces()) { continue; } vtkIdType n(0); vtkIdType* faces = poly->GetFaces(); vtkIdType nFaces = faces[n++]; // create offset in vtkUnstructuredGrid fashion, this will later be converted using ConvertFaces faceOffsets->InsertNextValue(offset); faceStream->InsertNextValue(nFaces); for(vtkIdType i = 0; i < nFaces; ++i) { vtkIdType nFaceVerts = faces[n++]; faceStream->InsertNextValue(nFaceVerts); for (vtkIdType j = 0; j < nFaceVerts; ++j) { vtkIdType vi = faces[n++]; faceStream->InsertNextValue(vi); } } offset += n; } } //---------------------------------------------------------------------------- int vtkXMLUnstructuredDataWriter::WriteAPiece() { vtkIndent indent = vtkIndent().GetNextIndent(); int result=1; if(this->DataMode == vtkXMLWriter::Appended) { this->WriteAppendedPieceData(this->CurrentPiece); } else { result = this->WriteInlineMode(indent); } if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); result = 0; } return result; } //---------------------------------------------------------------------------- int vtkXMLUnstructuredDataWriter::WriteFooter() { vtkIndent indent = vtkIndent().GetNextIndent(); ostream& os = *(this->Stream); if(this->DataMode == vtkXMLWriter::Appended) { this->DeletePositionArrays(); this->EndAppendedData(); } else { // Close the primary element. os << indent << "GetDataSetName() << ">\n"; os.flush(); if (os.fail()) { return 0; } } return 1; } //---------------------------------------------------------------------------- int vtkXMLUnstructuredDataWriter::WriteInlineMode(vtkIndent indent) { ostream& os = *(this->Stream); vtkIndent nextIndent = indent.GetNextIndent(); // Open the piece's element. os << nextIndent << "WriteInlinePieceAttributes(); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return 0; } os << ">\n"; this->WriteInlinePiece(nextIndent.GetNextIndent()); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return 0; } // Close the piece's element. os << nextIndent << "\n"; return 1; } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteInlinePieceAttributes() { vtkPointSet* input = this->GetInputAsPointSet(); this->WriteScalarAttribute("NumberOfPoints", input->GetNumberOfPoints()); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteInlinePiece(vtkIndent indent) { vtkPointSet* input = this->GetInputAsPointSet(); // Split progress among point data, cell data, and point arrays. float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); float fractions[4]; this->CalculateDataFractions(fractions); // Set the range of progress for the point data arrays. this->SetProgressRange(progressRange, 0, fractions); // Write the point data arrays. this->WritePointDataInline(input->GetPointData(), indent); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } // Set the range of progress for the cell data arrays. this->SetProgressRange(progressRange, 1, fractions); // Write the cell data arrays. this->WriteCellDataInline(input->GetCellData(), indent); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } // Set the range of progress for the point specification array. this->SetProgressRange(progressRange, 2, fractions); // Write the point specification array. this->WritePointsInline(input->GetPoints(), indent); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteAppendedPieceAttributes(int index) { this->NumberOfPointsPositions[index] = this->ReserveAttributeSpace("NumberOfPoints"); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteAppendedPiece(int index, vtkIndent indent) { vtkPointSet* input = this->GetInputAsPointSet(); this->WritePointDataAppended(input->GetPointData(), indent, &this->PointDataOM->GetPiece(index)); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } this->WriteCellDataAppended(input->GetCellData(), indent, &this->CellDataOM->GetPiece(index)); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } this->WritePointsAppended(input->GetPoints(), indent, &this->PointsOM->GetPiece(index)); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteAppendedPieceData(int index) { ostream& os = *(this->Stream); vtkPointSet* input = this->GetInputAsPointSet(); std::streampos returnPosition = os.tellp(); os.seekp(std::streampos(this->NumberOfPointsPositions[index])); vtkPoints* points = input->GetPoints(); this->WriteScalarAttribute("NumberOfPoints", (points?points->GetNumberOfPoints():0)); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } os.seekp(returnPosition); // Split progress among point data, cell data, and point arrays. float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); float fractions[4]; this->CalculateDataFractions(fractions); // Set the range of progress for the point data arrays. this->SetProgressRange(progressRange, 0, fractions); // Write the point data arrays. this->WritePointDataAppendedData(input->GetPointData(), this->CurrentTimeIndex, &this->PointDataOM->GetPiece(index)); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } // Set the range of progress for the cell data arrays. this->SetProgressRange(progressRange, 1, fractions); // Write the cell data arrays. this->WriteCellDataAppendedData(input->GetCellData(), this->CurrentTimeIndex, &this->CellDataOM->GetPiece(index)); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } // Set the range of progress for the point specification array. this->SetProgressRange(progressRange, 2, fractions); // Write the point specification array. // Since we are writing the point let save the Modified Time of vtkPoints: this->WritePointsAppendedData(input->GetPoints(), this->CurrentTimeIndex, &this->PointsOM->GetPiece(index)); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsInline( const char *name, vtkCellIterator *cellIter, vtkIdType numCells, vtkIdType cellSizeEstimate, vtkIndent indent) { this->ConvertCells(cellIter, numCells, cellSizeEstimate); vtkNew types; types->Allocate(numCells); vtkIdType nPolyhedra(0); for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) { vtkIdType ct = cellIter->GetCellType(); if (ct == VTK_POLYHEDRON) { ++nPolyhedra; } types->InsertNextValue(static_cast(ct)); } if (nPolyhedra > 0) { vtkNew faces, offsets; CreateFaceStream(cellIter, faces.GetPointer(), offsets.GetPointer()); this->ConvertFaces(faces.GetPointer(), offsets.GetPointer()); } else { this->Faces->SetNumberOfTuples(0); this->FaceOffsets->SetNumberOfTuples(0); } this->WriteCellsInlineWorker(name, types.GetPointer(), indent); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsInline(const char* name, vtkCellArray* cells, vtkDataArray* types, vtkIndent indent) { this->WriteCellsInline(name, cells, types, nullptr, nullptr, indent); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsInline(const char* name, vtkCellArray* cells, vtkDataArray* types, vtkIdTypeArray* faces, vtkIdTypeArray* faceOffsets, vtkIndent indent) { if(cells) { this->ConvertCells(cells); } this->ConvertFaces(faces, faceOffsets); this->WriteCellsInlineWorker(name, types, indent); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsInlineWorker( const char *name, vtkDataArray *types, vtkIndent indent) { ostream& os = *(this->Stream); os << indent << "<" << name << ">\n"; // Split progress by cell connectivity, offset, and type arrays. float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); float fractions[6]; this->CalculateCellFractions(fractions, types?types->GetNumberOfTuples():0); // Set the range of progress for the connectivity array. this->SetProgressRange(progressRange, 0, fractions); // Write the connectivity array. this->WriteArrayInline(this->CellPoints, indent.GetNextIndent()); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } // Set the range of progress for the offsets array. this->SetProgressRange(progressRange, 1, fractions); // Write the offsets array. this->WriteArrayInline(this->CellOffsets, indent.GetNextIndent()); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } if(types) { // Set the range of progress for the types array. this->SetProgressRange(progressRange, 2, fractions); // Write the types array. this->WriteArrayInline(types, indent.GetNextIndent(), "types"); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } } if (this->Faces->GetNumberOfTuples()) { // Set the range of progress for the faces array. this->SetProgressRange(progressRange, 3, fractions); // Write the connectivity array. this->WriteArrayInline(this->Faces, indent.GetNextIndent(), "faces"); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } } if (this->FaceOffsets->GetNumberOfTuples()) { // Set the range of progress for the face offset array. this->SetProgressRange(progressRange, 4, fractions); // Write the face offsets array. this->WriteArrayInline(this->FaceOffsets, indent.GetNextIndent(), "faceoffsets"); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); } } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsAppended(const char* name, vtkDataArray* types, vtkIndent indent, OffsetsManagerGroup *cellsManager) { this->WriteCellsAppended(name, types, nullptr, nullptr, indent, cellsManager); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsAppended(const char* name, vtkDataArray* types, vtkIdTypeArray* faces, vtkIdTypeArray* faceOffsets, vtkIndent indent, OffsetsManagerGroup *cellsManager) { this->ConvertFaces(faces,faceOffsets); ostream& os = *(this->Stream); os << indent << "<" << name << ">\n"; // Helper for the 'for' loop vtkDataArray *allcells[5]; allcells[0] = this->CellPoints; allcells[1] = this->CellOffsets; allcells[2] = types; allcells[3] = this->Faces->GetNumberOfTuples() ? this->Faces : nullptr; allcells[4] = this->FaceOffsets->GetNumberOfTuples() ? this->FaceOffsets : nullptr; const char *names[] = {nullptr, nullptr, "types", nullptr, nullptr}; for(int t=0; tNumberOfTimeSteps; t++) { for(int i=0; i<5; i++) { if(allcells[i]) { this->WriteArrayAppended(allcells[i], indent.GetNextIndent(), cellsManager->GetElement(i), names[i], 0, t); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } } } } os << indent << "\n"; os.flush(); if (os.fail()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return; } } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsAppended( const char *name, vtkCellIterator *cellIter, vtkIdType numCells, vtkIndent indent, OffsetsManagerGroup *cellsManager) { vtkNew types; types->Allocate(numCells); vtkIdType nPolyhedra(0); for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) { vtkIdType ct = cellIter->GetCellType(); if (ct == VTK_POLYHEDRON) { ++nPolyhedra; } types->InsertNextValue(static_cast(ct)); } if (nPolyhedra > 0) { vtkNew faces, offsets; CreateFaceStream(cellIter, faces.GetPointer(), offsets.GetPointer()); this->WriteCellsAppended(name, types.GetPointer(), faces.GetPointer(), offsets.GetPointer(), indent, cellsManager); } else { this->WriteCellsAppended(name, types.GetPointer(), nullptr, nullptr, indent, cellsManager); } } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsAppendedData(vtkCellArray* cells, vtkDataArray* types, int timestep, OffsetsManagerGroup *cellsManager) { this->WriteCellsAppendedData(cells, types, nullptr, nullptr, timestep, cellsManager); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsAppendedData( vtkCellIterator *cellIter, vtkIdType numCells, vtkIdType cellSizeEstimate, int timestep, OffsetsManagerGroup *cellsManager) { this->ConvertCells(cellIter, numCells, cellSizeEstimate); vtkNew types; types->Allocate(this->CellOffsets->GetNumberOfTuples() + 1); int nPolyhedra(0); for(cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) { vtkIdType ct = cellIter->GetCellType(); if (ct == VTK_POLYHEDRON) { ++nPolyhedra; } types->InsertNextValue(static_cast(ct)); } if (nPolyhedra > 0) { // even though it looks like we do this for the second time // the test points out that it is needed here. vtkNew faces, offsets; CreateFaceStream(cellIter, faces.GetPointer(), offsets.GetPointer()); this->ConvertFaces(faces.GetPointer(), offsets.GetPointer()); } else { this->Faces->SetNumberOfTuples(0); this->FaceOffsets->SetNumberOfTuples(0); } this->WriteCellsAppendedDataWorker(types.GetPointer(), timestep, cellsManager); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsAppendedData(vtkCellArray* cells, vtkDataArray* types, vtkIdTypeArray* faces, vtkIdTypeArray* faceOffsets, int timestep, OffsetsManagerGroup *cellsManager) { if (cells) { this->ConvertCells(cells); } this->ConvertFaces(faces, faceOffsets); this->WriteCellsAppendedDataWorker(types, timestep, cellsManager); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::WriteCellsAppendedDataWorker( vtkDataArray *types, int timestep, OffsetsManagerGroup *cellsManager) { // Split progress by cell connectivity, offset, and type arrays. float progressRange[5] = {0,0,0,0,0}; this->GetProgressRange(progressRange); float fractions[6]; this->CalculateCellFractions(fractions, types?types->GetNumberOfTuples():0); // Helper for the 'for' loop vtkDataArray *allcells[5]; allcells[0] = this->CellPoints; allcells[1] = this->CellOffsets; allcells[2] = types; allcells[3] = this->Faces->GetNumberOfTuples() ? this->Faces : nullptr; allcells[4] = this->FaceOffsets->GetNumberOfTuples() ? this->FaceOffsets : nullptr; for(int i=0; i<5; i++) { if(allcells[i]) { // Set the range of progress for the connectivity array. this->SetProgressRange(progressRange, i, fractions); vtkMTimeType mtime = allcells[i]->GetMTime(); vtkMTimeType &cellsMTime = cellsManager->GetElement(i).GetLastMTime(); // Only write cells if MTime has changed if( cellsMTime != mtime ) { cellsMTime = mtime; // Write the connectivity array. this->WriteArrayAppendedData(allcells[i], cellsManager->GetElement(i).GetPosition(timestep), cellsManager->GetElement(i).GetOffsetValue(timestep)); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return; } } else { // One timestep must have already been written or the // mtime would have changed and we would not be here. assert( timestep > 0 ); cellsManager->GetElement(i).GetOffsetValue(timestep) = cellsManager->GetElement(i).GetOffsetValue(timestep-1); this->ForwardAppendedDataOffset(cellsManager->GetElement(i).GetPosition(timestep), cellsManager->GetElement(i).GetOffsetValue(timestep), "offset" ); } } } } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::ConvertCells( vtkCellIterator *cellIter, vtkIdType numCells, vtkIdType cellSizeEstimate) { this->CellPoints->Allocate(numCells * cellSizeEstimate); this->CellOffsets->Allocate(numCells); for (cellIter->InitTraversal(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) { vtkIdType *begin = cellIter->GetPointIds()->GetPointer(0); vtkIdType *end = begin + cellIter->GetNumberOfPoints(); while (begin != end) { this->CellPoints->InsertNextValue(*begin++); } this->CellOffsets->InsertNextValue(this->CellPoints->GetNumberOfTuples()); } this->CellPoints->Squeeze(); this->CellOffsets->Squeeze(); } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::ConvertCells(vtkCellArray* cells) { vtkIdTypeArray* connectivity = cells->GetData(); vtkIdType numberOfCells = cells->GetNumberOfCells(); vtkIdType numberOfTuples = connectivity->GetNumberOfTuples(); this->CellPoints->SetNumberOfTuples(numberOfTuples - numberOfCells); this->CellOffsets->SetNumberOfTuples(numberOfCells); vtkIdType* inCell = connectivity->GetPointer(0); vtkIdType* outCellPointsBase = this->CellPoints->GetPointer(0); vtkIdType* outCellPoints = outCellPointsBase; vtkIdType* outCellOffset = this->CellOffsets->GetPointer(0); vtkIdType i; for(i=0;i < numberOfCells; ++i) { vtkIdType numberOfPoints = *inCell++; memcpy(outCellPoints, inCell, sizeof(vtkIdType)*numberOfPoints); outCellPoints += numberOfPoints; inCell += numberOfPoints; *outCellOffset++ = outCellPoints - outCellPointsBase; } } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::ConvertFaces(vtkIdTypeArray* faces, vtkIdTypeArray* faceOffsets) { if (!faces || !faces->GetNumberOfTuples() || !faceOffsets || !faceOffsets->GetNumberOfTuples()) { this->Faces->SetNumberOfTuples(0); this->FaceOffsets->SetNumberOfTuples(0); return; } // copy faces stream. this->Faces->SetNumberOfTuples(faces->GetNumberOfTuples()); vtkIdType * fromPtr = faces->GetPointer(0); vtkIdType * toPtr = this->Faces->GetPointer(0); for (vtkIdType i = 0; i < faces->GetNumberOfTuples(); i++) { *toPtr++ = *fromPtr++; } // this->FaceOffsets point to the face arrays of cells. Specifically // FaceOffsets[i] points to the end of the i-th cell's faces + 1. While // input faceOffsets[i] points to the beginning of the i-th cell. Note // that for both arrays, a non-polyhedron cell has an offset of -1. vtkIdType numberOfCells = faceOffsets->GetNumberOfTuples(); this->FaceOffsets->SetNumberOfTuples(numberOfCells); vtkIdType* newOffsetPtr = this->FaceOffsets->GetPointer(0); vtkIdType* oldOffsetPtr = faceOffsets->GetPointer(0); vtkIdType* facesPtr = this->Faces->GetPointer(0); bool foundPolyhedronCell = false; for (vtkIdType i = 0; i < numberOfCells; i++) { if (oldOffsetPtr[i] < 0) //non-polyhedron cell { newOffsetPtr[i] = -1; } else // polyhedron cell { foundPolyhedronCell = true; // read numberOfFaces in a cell vtkIdType currLoc = oldOffsetPtr[i]; vtkIdType numberOfCellFaces = facesPtr[currLoc]; currLoc += 1; for (vtkIdType j = 0; j < numberOfCellFaces; j++) { // read numberOfPoints in a face vtkIdType numberOfFacePoints = facesPtr[currLoc]; currLoc += numberOfFacePoints + 1; } newOffsetPtr[i] = currLoc; } } if (!foundPolyhedronCell) { this->Faces->SetNumberOfTuples(0); this->FaceOffsets->SetNumberOfTuples(0); } } //---------------------------------------------------------------------------- vtkIdType vtkXMLUnstructuredDataWriter::GetNumberOfInputPoints() { vtkPointSet* input = this->GetInputAsPointSet(); vtkPoints* points = input->GetPoints(); return points?points->GetNumberOfPoints():0; } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::CalculateDataFractions(float* fractions) { // Calculate the fraction of point/cell data and point // specifications contributed by each component. vtkPointSet* input = this->GetInputAsPointSet(); int pdArrays = input->GetPointData()->GetNumberOfArrays(); int cdArrays = input->GetCellData()->GetNumberOfArrays(); vtkIdType pdSize = pdArrays*this->GetNumberOfInputPoints(); vtkIdType cdSize = cdArrays*this->GetNumberOfInputCells(); int total = (pdSize+cdSize+this->GetNumberOfInputPoints()); if(total == 0) { total = 1; } fractions[0] = 0; fractions[1] = float(pdSize)/total; fractions[2] = float(pdSize+cdSize)/total; fractions[3] = 1; } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::CalculateCellFractions(float* fractions, vtkIdType typesSize) { // Calculate the fraction of cell specification data contributed by // each of the connectivity, offset, and type arrays. vtkIdType connectSize = this->CellPoints->GetNumberOfTuples(); vtkIdType offsetSize = this->CellOffsets->GetNumberOfTuples(); vtkIdType faceSize = this->Faces ? this->Faces->GetNumberOfTuples() : 0; vtkIdType faceoffsetSize = this->FaceOffsets ? this->FaceOffsets->GetNumberOfTuples() : 0; vtkIdType total = connectSize+offsetSize+faceSize+faceoffsetSize+typesSize; if(total == 0) { total = 1; } fractions[0] = 0; fractions[1] = float(connectSize)/total; fractions[2] = float(connectSize+offsetSize)/total; fractions[3] = float(connectSize+offsetSize+faceSize)/total; fractions[4] = float(connectSize+offsetSize+faceSize+faceoffsetSize)/total; fractions[5] = 1; } //---------------------------------------------------------------------------- void vtkXMLUnstructuredDataWriter::SetInputUpdateExtent( int piece, int numPieces, int ghostLevel) { vtkInformation* inInfo = this->GetExecutive()->GetInputInformation(0, 0); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), numPieces); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), piece); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), ghostLevel); }