/*========================================================================= Program: Visualization Toolkit Module: vtkImageAlgorithm.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 "vtkImageAlgorithm.h" #include "vtkCellData.h" #include "vtkDataArray.h" #include "vtkErrorCode.h" #include "vtkImageData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkStreamingDemandDrivenPipeline.h" //------------------------------------------------------------------------------ vtkImageAlgorithm::vtkImageAlgorithm() { this->SetNumberOfInputPorts(1); this->SetNumberOfOutputPorts(1); // by default process active point scalars this->SetInputArrayToProcess( 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); } //------------------------------------------------------------------------------ vtkImageAlgorithm::~vtkImageAlgorithm() = default; //------------------------------------------------------------------------------ void vtkImageAlgorithm::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ // This is the superclasses style of Execute method. Convert it into // an imaging style Execute method. int vtkImageAlgorithm::RequestData(vtkInformation* request, vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { // the default implementation is to do what the old pipeline did find what // output is requesting the data, and pass that into ExecuteData // which output port did the request come from int outputPort = request->Get(vtkDemandDrivenPipeline::FROM_OUTPUT_PORT()); // if output port is negative then that means this filter is calling the // update directly, in that case just assume port 0 if (outputPort == -1) { outputPort = 0; } // get the data object vtkInformation* outInfo = outputVector->GetInformationObject(outputPort); // call ExecuteData this->SetErrorCode(vtkErrorCode::NoError); if (outInfo) { this->ExecuteDataWithInformation(outInfo->Get(vtkDataObject::DATA_OBJECT()), outInfo); } else { this->ExecuteData(nullptr); } // Check for any error set by downstream filter (IO in most case) if (this->GetErrorCode()) { return 0; } return 1; } //------------------------------------------------------------------------------ vtkTypeBool vtkImageAlgorithm::ProcessRequest( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // generate the data if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) { return this->RequestData(request, inputVector, outputVector); } // execute information if (request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION())) { return this->RequestInformation(request, inputVector, outputVector); } // propagate update extent if (request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT())) { return this->RequestUpdateExtent(request, inputVector, outputVector); } return this->Superclass::ProcessRequest(request, inputVector, outputVector); } void vtkImageAlgorithm::ExecuteDataWithInformation(vtkDataObject* dobj, vtkInformation*) { this->ExecuteData(dobj); } //------------------------------------------------------------------------------ // Assume that any source that implements ExecuteData // can handle an empty extent. void vtkImageAlgorithm::ExecuteData(vtkDataObject*) { this->Execute(); } //------------------------------------------------------------------------------ void vtkImageAlgorithm::Execute() { vtkErrorMacro(<< "Definition of Execute() method should be in subclass and you should really use " "the ExecuteData(vtkInformation *request,...) signature instead"); } //------------------------------------------------------------------------------ void vtkImageAlgorithm::CopyInputArrayAttributesToOutput(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // for image data to image data if (this->GetNumberOfInputPorts() && this->GetNumberOfOutputPorts()) { vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); // if the input is image data if (vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()))) { vtkInformation* info = this->GetInputArrayFieldInformation(0, inputVector); if (info) { int scalarType = info->Get(vtkDataObject::FIELD_ARRAY_TYPE()); int numComp = info->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()); for (int i = 0; i < this->GetNumberOfOutputPorts(); ++i) { vtkInformation* outInfo = outputVector->GetInformationObject(i); // if the output is image data if (vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()))) { // copy scalar type and scalar number of components vtkDataObject::SetPointDataActiveScalarInfo(outInfo, scalarType, numComp); } } } } } } //------------------------------------------------------------------------------ int vtkImageAlgorithm::RequestInformation( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // do nothing except copy scalar type info this->CopyInputArrayAttributesToOutput(request, inputVector, outputVector); return 1; } //------------------------------------------------------------------------------ int vtkImageAlgorithm::RequestUpdateExtent(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* vtkNotUsed(outputVector)) { // do nothing let subclasses handle it return 1; } //------------------------------------------------------------------------------ void vtkImageAlgorithm::AllocateOutputData( vtkImageData* output, vtkInformation* outInfo, int* uExtent) { // set the extent to be the update extent output->SetExtent(uExtent); int scalarType = vtkImageData::GetScalarType(outInfo); int numComponents = vtkImageData::GetNumberOfScalarComponents(outInfo); output->AllocateScalars(scalarType, numComponents); } //------------------------------------------------------------------------------ vtkImageData* vtkImageAlgorithm::AllocateOutputData(vtkDataObject* output, vtkInformation* outInfo) { // set the extent to be the update extent vtkImageData* out = vtkImageData::SafeDownCast(output); if (out) { int* uExtent = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT()); this->AllocateOutputData(out, outInfo, uExtent); } return out; } //------------------------------------------------------------------------------ // by default copy the attr from the first input to the first output void vtkImageAlgorithm::CopyAttributeData( vtkImageData* input, vtkImageData* output, vtkInformationVector** inputVector) { if (!input || !output) { return; } int inExt[6]; int outExt[6]; vtkDataArray* inArray; vtkDataArray* outArray; input->GetExtent(inExt); output->GetExtent(outExt); // Do not copy the array we will be generating. inArray = this->GetInputArrayToProcess(0, inputVector); // Conditionally copy point and cell data. Only copy if corresponding // indexes refer to identical points. double* oIn = input->GetOrigin(); double* sIn = input->GetSpacing(); double* oOut = output->GetOrigin(); double* sOut = output->GetSpacing(); if (oIn[0] == oOut[0] && oIn[1] == oOut[1] && oIn[2] == oOut[2] && sIn[0] == sOut[0] && sIn[1] == sOut[1] && sIn[2] == sOut[2]) { output->GetPointData()->CopyAllOn(); output->GetCellData()->CopyAllOn(); if (inArray && inArray->GetName()) { output->GetPointData()->CopyFieldOff(inArray->GetName()); } else if (inArray == input->GetPointData()->GetScalars()) { output->GetPointData()->CopyScalarsOff(); } // If the extents are the same, then pass the attribute data for // efficiency. if (inExt[0] == outExt[0] && inExt[1] == outExt[1] && inExt[2] == outExt[2] && inExt[3] == outExt[3] && inExt[4] == outExt[4] && inExt[5] == outExt[5]) { // Pass // set the name of the output to match the input name outArray = output->GetPointData()->GetScalars(); if (inArray) { outArray->SetName(inArray->GetName()); } // Cache the scalars otherwise it may get overwritten // during CopyAttributes() outArray->Register(this); output->GetPointData()->SetScalars(nullptr); output->CopyAttributes(input); // Restore the scalars int idx = output->GetPointData()->AddArray(outArray); output->GetPointData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS); outArray->UnRegister(this); } else { // Copy // Since this can be expensive to copy all of these values, // lets make sure there are arrays to copy (other than the scalars) if (input->GetPointData()->GetNumberOfArrays() > 1) { // Copy the point data. // CopyAllocate frees all arrays. // Cache the scalars otherwise it may get overwritten // during CopyAllocate() vtkDataArray* tmp = output->GetPointData()->GetScalars(); // set the name of the output to match the input name if (inArray) { tmp->SetName(inArray->GetName()); } tmp->Register(this); output->GetPointData()->SetScalars(nullptr); output->GetPointData()->CopyAllocate(input->GetPointData(), output->GetNumberOfPoints()); // Restore the scalars int idx = output->GetPointData()->AddArray(tmp); output->GetPointData()->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS); tmp->UnRegister(this); // Now Copy The point data, but only if output is a subextent of the // input. if (outExt[0] >= inExt[0] && outExt[1] <= inExt[1] && outExt[2] >= inExt[2] && outExt[3] <= inExt[3] && outExt[4] >= inExt[4] && outExt[5] <= inExt[5]) { output->GetPointData()->CopyStructuredData(input->GetPointData(), inExt, outExt); } } else { if (inArray) { vtkDataArray* tmp = output->GetPointData()->GetScalars(); tmp->SetName(inArray->GetName()); } } if (input->GetCellData()->GetNumberOfArrays() > 0) { output->GetCellData()->CopyAllocate(input->GetCellData(), output->GetNumberOfCells()); // Cell extent is one less than point extent. // Conditional to handle a colapsed axis (lower dimensional cells). if (inExt[0] < inExt[1]) { --inExt[1]; } if (inExt[2] < inExt[3]) { --inExt[3]; } if (inExt[4] < inExt[5]) { --inExt[5]; } // Cell extent is one less than point extent. if (outExt[0] < outExt[1]) { --outExt[1]; } if (outExt[2] < outExt[3]) { --outExt[3]; } if (outExt[4] < outExt[5]) { --outExt[5]; } // Now Copy The cell data, but only if output is a subextent of the input. if (outExt[0] >= inExt[0] && outExt[1] <= inExt[1] && outExt[2] >= inExt[2] && outExt[3] <= inExt[3] && outExt[4] >= inExt[4] && outExt[5] <= inExt[5]) { output->GetCellData()->CopyStructuredData(input->GetCellData(), inExt, outExt); } } } } } //------------------------------------------------------------------------------ vtkImageData* vtkImageAlgorithm::GetOutput() { return this->GetOutput(0); } //------------------------------------------------------------------------------ vtkImageData* vtkImageAlgorithm::GetOutput(int port) { return vtkImageData::SafeDownCast(this->GetOutputDataObject(port)); } //------------------------------------------------------------------------------ void vtkImageAlgorithm::SetOutput(vtkDataObject* d) { this->GetExecutive()->SetOutputData(0, d); } //------------------------------------------------------------------------------ int vtkImageAlgorithm::FillOutputPortInformation(int vtkNotUsed(port), vtkInformation* info) { // now add our info info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkImageData"); return 1; } //------------------------------------------------------------------------------ int vtkImageAlgorithm::FillInputPortInformation(int vtkNotUsed(port), vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData"); return 1; } //------------------------------------------------------------------------------ void vtkImageAlgorithm::SetInputData(vtkDataObject* input) { this->SetInputData(0, input); } //------------------------------------------------------------------------------ void vtkImageAlgorithm::SetInputData(int index, vtkDataObject* input) { this->SetInputDataInternal(index, input); } //------------------------------------------------------------------------------ vtkDataObject* vtkImageAlgorithm::GetInput(int port) { return this->GetExecutive()->GetInputData(port, 0); } //------------------------------------------------------------------------------ vtkImageData* vtkImageAlgorithm::GetImageDataInput(int port) { return vtkImageData::SafeDownCast(this->GetInput(port)); } //------------------------------------------------------------------------------ void vtkImageAlgorithm::AddInputData(vtkDataObject* input) { this->AddInputData(0, input); } //------------------------------------------------------------------------------ void vtkImageAlgorithm::AddInputData(int index, vtkDataObject* input) { this->AddInputDataInternal(index, input); }