/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkXMLStructuredDataWriter.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 "vtkXMLStructuredDataWriter.h" #include "vtkCellData.h" #include "vtkDataArray.h" #include "vtkDataCompressor.h" #include "vtkDataSet.h" #include "vtkErrorCode.h" #include "vtkExtentTranslator.h" #include "vtkInformation.h" #include "vtkInformationIntegerVectorKey.h" #include "vtkInformationVector.h" #include "vtkPointData.h" #include "vtkStreamingDemandDrivenPipeline.h" #define vtkOffsetsManager_DoNotInclude #include "vtkOffsetsManagerArray.h" #undef vtkOffsetsManager_DoNotInclude vtkCxxRevisionMacro(vtkXMLStructuredDataWriter, "$Revision: 1.20 $"); vtkCxxSetObjectMacro(vtkXMLStructuredDataWriter, ExtentTranslator, vtkExtentTranslator); //---------------------------------------------------------------------------- vtkXMLStructuredDataWriter::vtkXMLStructuredDataWriter() { this->ExtentTranslator = vtkExtentTranslator::New(); this->NumberOfPieces = 1; this->WriteExtent[0] = 0; this->WriteExtent[1] = -1; this->WriteExtent[2] = 0; this->WriteExtent[3] = -1; this->WriteExtent[4] = 0; this->WriteExtent[5] = -1; this->InternalWriteExtent[0] = 0; this->InternalWriteExtent[1] = -1; this->InternalWriteExtent[2] = 0; this->InternalWriteExtent[3] = -1; this->InternalWriteExtent[4] = 0; this->InternalWriteExtent[5] = -1; this->CurrentPiece = 0; this->ProgressFractions = 0; this->FieldDataOM->Allocate(0); this->PointDataOM = new OffsetsManagerArray; this->CellDataOM = new OffsetsManagerArray; } //---------------------------------------------------------------------------- vtkXMLStructuredDataWriter::~vtkXMLStructuredDataWriter() { this->SetExtentTranslator(0); delete[] this->ProgressFractions; delete this->PointDataOM; delete this->CellDataOM; } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "WriteExtent: " << this->WriteExtent[0] << " " << this->WriteExtent[1] << " " << this->WriteExtent[2] << " " << this->WriteExtent[3] << " " << this->WriteExtent[4] << " " << this->WriteExtent[5] << "\n"; os << indent << "InternalWriteExtent: " << this->InternalWriteExtent[0] << " " << this->InternalWriteExtent[1] << " " << this->InternalWriteExtent[2] << " " << this->InternalWriteExtent[3] << " " << this->InternalWriteExtent[4] << " " << this->InternalWriteExtent[5] << "\n"; if(this->ExtentTranslator) { os << indent << "ExtentTranslator: " << this->ExtentTranslator << "\n"; } else { os << indent << "ExtentTranslator: (none)\n"; } os << indent << "NumberOfPieces" << this->NumberOfPieces << "\n"; } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::SetInputUpdateExtent(int piece) { this->ExtentTranslator->SetPiece(piece); this->ExtentTranslator->PieceToExtent(); vtkInformation* inInfo = this->GetExecutive()->GetInputInformation(0, 0); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), this->ExtentTranslator->GetExtent(), 6); } //---------------------------------------------------------------------------- int vtkXMLStructuredDataWriter::ProcessRequest( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { if(request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT())) { // Prepare the extent translator to create the set of pieces. this->SetupExtentTranslator(); this->SetInputUpdateExtent(this->CurrentPiece); return 1; } // generate the data else if(request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) { this->SetErrorCode(vtkErrorCode::NoError); if(!this->Stream && !this->FileName) { this->SetErrorCode(vtkErrorCode::NoFileNameError); vtkErrorMacro("The FileName or Stream must be set first."); return 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. float wholeProgressRange[2] = {0,1}; this->SetProgressRange(wholeProgressRange, 0, 1); int result = 1; if (this->CurrentPiece == 0 && this->CurrentTimeIndex == 0 ) { if (!this->OpenFile()) { return 0; } // Write the file. if (!this->StartFile()) { return 0; } if (!this->WriteHeader()) { 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(); } // Tell the pipeline to start looping. if (this->CurrentPiece == 0) { request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); } this->CurrentPiece++; if (this->CurrentPiece == this->NumberOfPieces) { request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); this->CurrentPiece = 0; // We are done writting all the pieces, lets loop over time now: this->CurrentTimeIndex++; if( this->UserContinueExecuting != 1) { if (!this->WriteFooter()) { return 0; } if (!this->EndFile()) { return 0; } this->CloseFile(); this->CurrentTimeIndex = 0; // Reset } } // We have finished writing. this->UpdateProgressDiscrete(1); return result; } return this->Superclass::ProcessRequest(request, inputVector, outputVector); } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::AllocatePositionArrays() { // Prepare storage for the point and cell data array appended data // offsets for each piece. this->PointDataOM->Allocate(this->NumberOfPieces); this->CellDataOM->Allocate(this->NumberOfPieces); } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::DeletePositionArrays() { } //---------------------------------------------------------------------------- int vtkXMLStructuredDataWriter::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(); int extent[6]; // Loop over each piece and write its structure. int i; for(i=0; i < this->NumberOfPieces; ++i) { // Update the piece's extent. this->ExtentTranslator->SetPiece(i); this->ExtentTranslator->PieceToExtent(); this->ExtentTranslator->GetExtent(extent); os << nextIndent << "WriteVectorAttribute("Extent", 6, extent); os << ">\n"; if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } this->WriteAppendedPiece(i, 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->DeletePositionArrays(); this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); return 0; } this->StartAppendedData(); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } } // Split progress of the data write by the fraction contributed by // each piece. float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); this->ProgressFractions = new float[this->NumberOfPieces+1]; this->CalculatePieceFractions(this->ProgressFractions); return 1; } //---------------------------------------------------------------------------- int vtkXMLStructuredDataWriter::WriteAPiece() { vtkIndent indent = vtkIndent().GetNextIndent(); int result = 1; if(this->DataMode == vtkXMLWriter::Appended) { vtkDataSet* input = this->GetInputAsDataSet(); // Make sure input is valid. if(input->CheckAttributes() == 0) { this->WriteAppendedPieceData(this->CurrentPiece); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { this->DeletePositionArrays(); return 0; } } else { vtkErrorMacro("Input is invalid for piece " << this->CurrentPiece << ". Aborting."); result = 0; } } else { this->WriteInlineMode(indent); } return result; } //---------------------------------------------------------------------------- int vtkXMLStructuredDataWriter::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()) { this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError); } } delete[] this->ProgressFractions; this->ProgressFractions = 0; return 1; } //---------------------------------------------------------------------------- int vtkXMLStructuredDataWriter::WriteInlineMode(vtkIndent indent) { vtkDataSet* input = this->GetInputAsDataSet(); ostream& os = *(this->Stream); int extent[6]; vtkInformation* inInfo = this->GetExecutive()->GetInputInformation(0, 0); inInfo->Get( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent); // Split progress of the data write by the fraction contributed by // each piece. float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); // Write each piece's XML and data. int result = 1; // Set the progress range for this piece. this->SetProgressRange(progressRange, this->CurrentPiece, this->ProgressFractions); // Make sure input is valid. if(input->CheckAttributes() == 0) { os << indent << "WriteVectorAttribute("Extent", 6, extent); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return 0; } os << ">\n"; this->WriteInlinePiece(indent.GetNextIndent()); if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) { return 0; } os << indent << "\n"; } else { vtkErrorMacro("Input is invalid for piece " << this->CurrentPiece << ". Aborting."); result = 0; } return result; } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::SetupExtentTranslator() { vtkDataSet* input = this->GetInputAsDataSet(); // If no write extent has been set, use the whole extent. if((this->WriteExtent[0] == 0) && (this->WriteExtent[1] == -1) && (this->WriteExtent[2] == 0) && (this->WriteExtent[3] == -1) && (this->WriteExtent[4] == 0) && (this->WriteExtent[5] == -1)) { this->SetInternalWriteExtent(input->GetWholeExtent()); } else { this->SetInternalWriteExtent(this->WriteExtent); } // Our WriteExtent becomes the WholeExtent of the file. this->ExtentTranslator->SetWholeExtent(this->InternalWriteExtent); this->ExtentTranslator->SetNumberOfPieces(this->NumberOfPieces); vtkDebugMacro("Writing Extent: " << this->InternalWriteExtent[0] << " " << this->InternalWriteExtent[1] << " " << this->InternalWriteExtent[2] << " " << this->InternalWriteExtent[3] << " " << this->InternalWriteExtent[4] << " " << this->InternalWriteExtent[5] << " in " << this->NumberOfPieces << " pieces."); } //---------------------------------------------------------------------------- vtkDataArray* vtkXMLStructuredDataWriter ::CreateExactExtent(vtkDataArray* array, int* inExtent, int* outExtent, int isPoint) { int outDimensions[3]; outDimensions[0] = outExtent[1]-outExtent[0]+isPoint; outDimensions[1] = outExtent[3]-outExtent[2]+isPoint; outDimensions[2] = outExtent[5]-outExtent[4]+isPoint; int inDimensions[3]; inDimensions[0] = inExtent[1]-inExtent[0]+isPoint; inDimensions[1] = inExtent[3]-inExtent[2]+isPoint; inDimensions[2] = inExtent[5]-inExtent[4]+isPoint; if((inDimensions[0] == outDimensions[0]) && (inDimensions[1] == outDimensions[1]) && (inDimensions[2] == outDimensions[2])) { array->Register(0); return array; } int tupleSize = (array->GetDataTypeSize() * array->GetNumberOfComponents()); vtkIdType rowTuples = outDimensions[0]; vtkIdType sliceTuples = rowTuples*outDimensions[1]; vtkIdType volumeTuples = sliceTuples*outDimensions[2]; vtkIdType inIncrements[3]; inIncrements[0] = 1; inIncrements[1] = inDimensions[0]*inIncrements[0]; inIncrements[2] = inDimensions[1]*inIncrements[1]; vtkIdType outIncrements[3]; outIncrements[0] = 1; outIncrements[1] = outDimensions[0]*outIncrements[0]; outIncrements[2] = outDimensions[1]*outIncrements[1]; vtkDataArray* newArray = array->NewInstance(); newArray->SetName(array->GetName()); newArray->SetNumberOfComponents(array->GetNumberOfComponents()); newArray->SetNumberOfTuples(volumeTuples); int components = newArray->GetNumberOfComponents(); if((inDimensions[0] == outDimensions[0]) && (inDimensions[1] == outDimensions[1])) { // Copy an entire slice at a time. int k; for(k=0;k < outDimensions[2];++k) { vtkIdType sourceTuple = this->GetStartTuple(inExtent, inIncrements, outExtent[0], outExtent[2], outExtent[4]+k); vtkIdType destTuple = this->GetStartTuple(outExtent, outIncrements, outExtent[0], outExtent[2], outExtent[4]+k); memcpy(newArray->GetVoidPointer(destTuple*components), array->GetVoidPointer(sourceTuple*components), sliceTuples*tupleSize); } } else { // Copy a row at a time. int j, k; for(k=0;k < outDimensions[2];++k) { for(j=0;j < outDimensions[1];++j) { vtkIdType sourceTuple = this->GetStartTuple(inExtent, inIncrements, outExtent[0], outExtent[2]+j, outExtent[4]+k); vtkIdType destTuple = this->GetStartTuple(outExtent, outIncrements, outExtent[0], outExtent[2]+j, outExtent[4]+k); memcpy(newArray->GetVoidPointer(destTuple*components), array->GetVoidPointer(sourceTuple*components), rowTuples*tupleSize); } } } return newArray; } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::WritePrimaryElementAttributes(ostream &os, vtkIndent indent) { this->Superclass::WritePrimaryElementAttributes(os, indent); this->WriteVectorAttribute("WholeExtent", 6, this->InternalWriteExtent); } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::WriteAppendedPiece(int index, vtkIndent indent) { // Write the point data and cell data arrays. vtkDataSet* input = this->GetInputAsDataSet(); 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; } } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::WriteAppendedPieceData(int index) { // Write the point data and cell data arrays. vtkDataSet* input = this->GetInputAsDataSet(); // Split progress between point data and cell data arrays. float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); int pdArrays = input->GetPointData()->GetNumberOfArrays(); int cdArrays = input->GetCellData()->GetNumberOfArrays(); int total = (pdArrays+cdArrays)? (pdArrays+cdArrays):1; float fractions[3] = { 0, float(pdArrays)/total, 1 }; // Set the range of progress for the point data arrays. this->SetProgressRange(progressRange, 0, fractions); 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); this->WriteCellDataAppendedData(input->GetCellData(), this->CurrentTimeIndex, &this->CellDataOM->GetPiece(index)); } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::WriteInlinePiece(vtkIndent indent) { // Write the point data and cell data arrays. vtkDataSet* input = this->GetInputAsDataSet(); // Split progress between point data and cell data arrays. float progressRange[2] = {0,0}; this->GetProgressRange(progressRange); int pdArrays = input->GetPointData()->GetNumberOfArrays(); int cdArrays = input->GetCellData()->GetNumberOfArrays(); int total = (pdArrays+cdArrays)? (pdArrays+cdArrays):1; float fractions[3] = { 0, float(pdArrays)/total, 1 }; // Set the range of progress for the point data arrays. this->SetProgressRange(progressRange, 0, fractions); 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); this->WriteCellDataInline(input->GetCellData(), indent); } //---------------------------------------------------------------------------- vtkIdType vtkXMLStructuredDataWriter::GetStartTuple(int* extent, vtkIdType* increments, int i, int j, int k) { return (((i - extent[0]) * increments[0]) + ((j - extent[2]) * increments[1]) + ((k - extent[4]) * increments[2])); } //---------------------------------------------------------------------------- vtkDataArray* vtkXMLStructuredDataWriter::CreateArrayForPoints(vtkDataArray* inArray) { int inExtent[6]; int outExtent[6]; this->GetInputExtent(inExtent); vtkInformation* inInfo = this->GetExecutive()->GetInputInformation(0, 0); inInfo->Get( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), outExtent); return this->CreateExactExtent(inArray, inExtent, outExtent, 1); } //---------------------------------------------------------------------------- vtkDataArray* vtkXMLStructuredDataWriter::CreateArrayForCells(vtkDataArray* inArray) { int inExtent[6]; int outExtent[6]; this->GetInputExtent(inExtent); vtkInformation* inInfo = this->GetExecutive()->GetInputInformation(0, 0); inInfo->Get( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), outExtent); return this->CreateExactExtent(inArray, inExtent, outExtent, 0); } //---------------------------------------------------------------------------- void vtkXMLStructuredDataWriter::CalculatePieceFractions(float* fractions) { int i; int extent[6]; // Calculate the fraction of total data contributed by each piece. fractions[0] = 0; for(i=0;i < this->NumberOfPieces;++i) { // Update the piece's extent. this->ExtentTranslator->SetPiece(i); this->ExtentTranslator->PieceToExtent(); this->ExtentTranslator->GetExtent(extent); // Add this piece's size to the cumulative fractions array. fractions[i+1] = fractions[i] + ((extent[1]-extent[0]+1)* (extent[3]-extent[2]+1)* (extent[5]-extent[4]+1)); } if(fractions[this->NumberOfPieces] == 0) { fractions[this->NumberOfPieces] = 1; } for(i=0;i < this->NumberOfPieces;++i) { fractions[i+1] = fractions[i+1] / fractions[this->NumberOfPieces]; } }