/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkCompositeDataPipeline.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 "vtkCompositeDataPipeline.h" #include "vtkAlgorithm.h" #include "vtkAlgorithmOutput.h" #include "vtkHierarchicalDataInformation.h" #include "vtkHierarchicalDataSet.h" #include "vtkInformation.h" #include "vtkInformationDoubleKey.h" #include "vtkInformationIntegerKey.h" #include "vtkInformationIntegerVectorKey.h" #include "vtkInformationKey.h" #include "vtkInformationObjectBaseKey.h" #include "vtkInformationStringKey.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkSmartPointer.h" #include "vtkImageData.h" #include "vtkRectilinearGrid.h" #include "vtkStructuredGrid.h" #include "vtkUniformGrid.h" vtkCxxRevisionMacro(vtkCompositeDataPipeline, "$Revision: 1.23.2.4 $"); vtkStandardNewMacro(vtkCompositeDataPipeline); vtkInformationKeyMacro(vtkCompositeDataPipeline,BEGIN_LOOP,Integer); vtkInformationKeyMacro(vtkCompositeDataPipeline,END_LOOP,Integer); vtkInformationKeyMacro(vtkCompositeDataPipeline,COMPOSITE_DATA_TYPE_NAME,String); vtkInformationKeyMacro(vtkCompositeDataPipeline,COMPOSITE_DATA_INFORMATION,ObjectBase); vtkInformationKeyMacro(vtkCompositeDataPipeline,MARKED_FOR_UPDATE,Integer); vtkInformationKeyMacro(vtkCompositeDataPipeline,INPUT_REQUIRED_COMPOSITE_DATA_TYPE, String); vtkInformationKeyMacro(vtkCompositeDataPipeline,UPDATE_BLOCKS, ObjectBase); //---------------------------------------------------------------------------- vtkCompositeDataPipeline::vtkCompositeDataPipeline() { this->InLocalLoop = 0; this->InSubPass = 0; this->InformationCache = vtkInformation::New(); this->GenericRequest = vtkInformation::New(); this->DataObjectRequest = vtkInformation::New(); this->DataObjectRequest->Set(vtkDemandDrivenPipeline::REQUEST_DATA_OBJECT()); // The request is forwarded upstream through the pipeline. this->DataObjectRequest->Set( vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream); // Algorithms process this request after it is forwarded. this->DataObjectRequest->Set(vtkExecutive::ALGORITHM_AFTER_FORWARD(), 1); this->InformationRequest = vtkInformation::New(); this->InformationRequest->Set(vtkDemandDrivenPipeline::REQUEST_INFORMATION()); // The request is forwarded upstream through the pipeline. this->InformationRequest->Set( vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream); // Algorithms process this request after it is forwarded. this->InformationRequest->Set(vtkExecutive::ALGORITHM_AFTER_FORWARD(), 1); this->UpdateExtentRequest = vtkInformation::New(); this->UpdateExtentRequest->Set( vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT()); // The request is forwarded upstream through the pipeline. this->UpdateExtentRequest->Set( vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream); // Algorithms process this request before it is forwarded. this->UpdateExtentRequest->Set(vtkExecutive::ALGORITHM_BEFORE_FORWARD(), 1); this->DataRequest = vtkInformation::New(); this->DataRequest->Set(REQUEST_DATA()); // The request is forwarded upstream through the pipeline. this->DataRequest->Set( vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream); // Algorithms process this request after it is forwarded. this->DataRequest->Set(vtkExecutive::ALGORITHM_AFTER_FORWARD(), 1); } //---------------------------------------------------------------------------- vtkCompositeDataPipeline::~vtkCompositeDataPipeline() { this->InformationCache->Delete(); this->GenericRequest->Delete(); this->DataObjectRequest->Delete(); this->InformationRequest->Delete(); this->UpdateExtentRequest->Delete(); this->DataRequest->Delete(); } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::ComputePipelineMTime(vtkInformation* request, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec, int requestFromOutputPort, unsigned long* mtime) { // if not a subpass then just do normal stuff if (!this->InSubPass) { return this->Superclass::ComputePipelineMTime(request, inInfoVec, outInfoVec, requestFromOutputPort, mtime); } // if in subpass then Update the time only if it is the beginning of the // next pass in the loop. if (request->Has(vtkCompositeDataSet::INDEX())) { this->SubPassTime.Modified(); } *mtime = this->SubPassTime; return 1; } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::ProcessRequest(vtkInformation* request, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec) { if(this->Algorithm && request->Has(BEGIN_LOOP())) { this->InSubPass = 1; return 1; } if(this->Algorithm && request->Has(END_LOOP())) { this->InSubPass = 0; return 1; } if(this->Algorithm && request->Has(REQUEST_DATA_OBJECT())) { if (this->InSubPass) { int result = 1; if (this->SubPassTime > this->DataObjectTime.GetMTime()) { // Request information from the algorithm. result = this->ExecuteDataObjectForBlock(request); } return result; } } if(this->Algorithm && request->Has(REQUEST_INFORMATION())) { // Make sure our output information is up-to-date. int result = 1; if (this->InSubPass) { if(this->SubPassTime > this->InformationTime.GetMTime()) { result = this->ExecuteInformationForBlock(request); // Information is now up to date. this->InformationTime.Modified(); } } else { int appendKey = 1; vtkInformationKey** keys = request->Get(vtkExecutive::KEYS_TO_COPY()); if (keys) { int len = request->Length(vtkExecutive::KEYS_TO_COPY()); for (int i=0; iAppend(vtkExecutive::KEYS_TO_COPY(), vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION()); } result = this->Superclass::ProcessRequest(request, inInfoVec,outInfoVec); } return result; } if(request->Has(REQUEST_UPDATE_EXTENT())) { if (this->InSubPass) { return 1; } } if(this->Algorithm && request->Has(REQUEST_DATA())) { if (this->InSubPass) { return this->ExecuteDataForBlock(request); } // Get the output port from which the request was made. int outputPort = -1; if(request->Has(FROM_OUTPUT_PORT())) { outputPort = request->Get(FROM_OUTPUT_PORT()); } // UPDATE_BLOCKS() is the key that tells filters downstream which // blocks of a composite dataset is available. This consumers will then // ask for these blocks if they have to loop (simple filters in the // middle) int appendKey = 1; vtkInformationKey** keys = request->Get(vtkExecutive::KEYS_TO_COPY()); if (keys) { int len = request->Length(vtkExecutive::KEYS_TO_COPY()); for (int i=0; iAppend(vtkExecutive::KEYS_TO_COPY(), vtkCompositeDataPipeline::UPDATE_BLOCKS()); } if(this->NeedToExecuteData(outputPort,inInfoVec,outInfoVec)) { // We have to check whether an input is marked for update before // ExecuteData() is entered. When looping over blocks, the // composite data producer up the pipeline will trick the // intermediate simple filters to execute by sending an update // mtime. However, if none of those filters are modified, this // would cause unnecessary execution of the whole intermediate // pipeline. Here, NeedToExecuteData() is called and the result // cached so that the blocks that are up to date can be skipped // later. // Loop over all input ports. for(int i=0; i < this->Algorithm->GetNumberOfInputPorts(); ++i) { // Loop over all connections on this input port. int numInConnections = inInfoVec[i]->GetNumberOfInformationObjects(); for (int j=0; jGetInformationObject(j); vtkDemandDrivenPipeline* ddp = vtkDemandDrivenPipeline::SafeDownCast( inInfo->GetExecutive(vtkExecutive::PRODUCER())); inInfo->Remove(MARKED_FOR_UPDATE()); if (ddp) { if (ddp->NeedToExecuteData(-1,ddp->GetInputInformation(), ddp->GetOutputInformation())) { inInfo->Set(MARKED_FOR_UPDATE(), 1); } } } } } } // Let the superclass handle other requests. return this->Superclass::ProcessRequest(request, inInfoVec, outInfoVec); } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::VerifyOutputInformation( int outputPort, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec) { if (outputPort < 0) { return this->Superclass::VerifyOutputInformation( outputPort, inInfoVec, outInfoVec); } vtkInformation* portInfo = this->Algorithm->GetOutputPortInformation(outputPort); if (portInfo->Has(COMPOSITE_DATA_TYPE_NAME())) { vtkInformation* outInfo = outInfoVec->GetInformationObject(outputPort); // For an unstructured extent, make sure the update request // exists. We do not need to check if it is valid because // out-of-range requests produce empty data. if(!outInfo->Has(MAXIMUM_NUMBER_OF_PIECES())) { vtkErrorMacro("No maximum number of pieces has been set in the " "information for output port " << outputPort << " on algorithm " << this->Algorithm->GetClassName() << "(" << this->Algorithm << ")."); return 0; } if(!outInfo->Has(UPDATE_PIECE_NUMBER())) { vtkErrorMacro("No update piece number has been set in the " "information for output port " << outputPort << " on algorithm " << this->Algorithm->GetClassName() << "(" << this->Algorithm << ")."); return 0; } if(!outInfo->Has(UPDATE_NUMBER_OF_PIECES())) { vtkErrorMacro("No update number of pieces has been set in the " "information for output port " << outputPort << " on algorithm " << this->Algorithm->GetClassName() << "(" << this->Algorithm << ")."); return 0; } if(!outInfo->Has(UPDATE_NUMBER_OF_GHOST_LEVELS())) { // Use zero ghost levels by default. outInfo->Set(UPDATE_NUMBER_OF_GHOST_LEVELS(), 0); } return 1; } return this->Superclass::VerifyOutputInformation( outputPort, inInfoVec, outInfoVec); } //---------------------------------------------------------------------------- // Handle REQUEST_DATA_OBJECT int vtkCompositeDataPipeline::ExecuteDataObject( vtkInformation* request, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec) { // Invoke the request on the algorithm. int result = this->CallAlgorithm(request, vtkExecutive::RequestDownstream, inInfoVec, outInfoVec); if (!result) { return result; } result = this->ExecuteDataObjectForBlock(request); if (!result) { return result; } int i; // Make sure a valid data object exists for all output ports. for(i=0; result && i < this->Algorithm->GetNumberOfOutputPorts(); ++i) { result = this->CheckDataObject(i, outInfoVec); } // Make sure a valid composite data object exists for all output ports. for(i=0; result && i < this->Algorithm->GetNumberOfOutputPorts(); ++i) { result = this->CheckCompositeData(i, outInfoVec); } return result; } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::ExecuteDataObjectForBlock(vtkInformation* request) { int result = 1; vtkInformationVector* outputVector = this->GetOutputInformation(); int numOut = outputVector->GetNumberOfInformationObjects(); for (int i=0; iAlgorithm->GetOutputPortInformation(0); if (portInfo->Has(COMPOSITE_DATA_TYPE_NAME())) { vtkInformation* info = outputVector->GetInformationObject(i); vtkDataObject* doOutput = info->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); vtkCompositeDataSet* output = vtkCompositeDataSet::SafeDownCast(doOutput); vtkDataObject* simpleOutput = 0; if (output) { vtkDataObject* dobj; // If the index is specified, use it. Otherwise, use (0,0) if (request->Has(vtkCompositeDataSet::INDEX())) { dobj = output->GetDataSet(request); } else { vtkSmartPointer r = vtkSmartPointer::New(); r->Set(vtkHierarchicalDataSet::LEVEL(), 0); r->Set(vtkCompositeDataSet::INDEX(), 0); dobj = output->GetDataSet(r); } if (dobj) { this->DataObjectTime.Modified(); vtkDataObject* currDObj = info->Get(vtkDataObject::DATA_OBJECT()); if (currDObj && strcmp(currDObj->GetClassName(), dobj->GetClassName()) == 0) { continue; } simpleOutput = dobj->NewInstance(); if (!simpleOutput) { vtkErrorMacro("Could not create a copy of " << dobj->GetClassName() << "."); return 0; } } } if (!simpleOutput) { // If there was no current data object in the composite data object // and there is already any data object in the output, move to the // next port if(info->Get(vtkDataObject::DATA_OBJECT())) { continue; } // Otherwise, simply create a polydata so that filters that // must have a data object (such as datasettodataset filters) // have a dummy dataset simpleOutput = vtkPolyData::New(); } simpleOutput->SetPipelineInformation(info); simpleOutput->Delete(); } } return result; } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::ExecuteInformationForBlock(vtkInformation* request) { vtkInformationVector* outputVector = this->GetOutputInformation(); int numOut = outputVector->GetNumberOfInformationObjects(); for (int i=0; iGetInformationObject(i); vtkDataObject* doOutput = info->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); vtkCompositeDataSet* output = vtkCompositeDataSet::SafeDownCast(doOutput); if (output) { vtkDataObject* dobj = output->GetDataSet(request); vtkDataObject* dobjCopy = info->Get(vtkDataObject::DATA_OBJECT()); if (dobj && dobjCopy) { dobjCopy->ShallowCopy(dobj); dobjCopy->CopyInformation(dobj); } } } return 1; } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::ExecuteDataStart( vtkInformation* request, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec) { this->Superclass::ExecuteDataStart(request, inInfoVec, outInfoVec); // True when the pipeline is iterating over the current (simple) filter // to produce composite output. In this case, ExecuteDataStart() should // NOT Initialize() the composite output. if (!this->InLocalLoop) { // Prepare outputs that will be generated to receive new data. for(int i=0; i < outInfoVec->GetNumberOfInformationObjects(); ++i) { vtkInformation* outInfo = outInfoVec->GetInformationObject(i); vtkDataObject* data = outInfo->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); if(data && !outInfo->Get(DATA_NOT_GENERATED())) { data->PrepareForNewData(); data->CopyInformationFromPipeline(request); } } } } //---------------------------------------------------------------------------- // Handle REQUEST_DATA int vtkCompositeDataPipeline::ExecuteData(vtkInformation* request, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec) { int result = 1; int outputPort = request->Get(FROM_OUTPUT_PORT()); int i, j; for(i=0; i < this->Algorithm->GetNumberOfOutputPorts(); ++i) { vtkInformation* info = outInfoVec->GetInformationObject(i); info->Remove(UPDATE_BLOCKS()); } // Loop over all input ports. for(i=0; i < this->Algorithm->GetNumberOfInputPorts(); ++i) { // Loop over all connections on this input port. int numInConnections = inInfoVec[i]->GetNumberOfInformationObjects(); for (j=0; jGetInformationObject(j); vtkCompositeDataSet* input = vtkCompositeDataSet::SafeDownCast( inInfo->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET())); // There is a composite input, no need to loop if (input) { continue; } vtkHierarchicalDataSet* updateInfo = vtkHierarchicalDataSet::SafeDownCast( inInfo->Get(vtkCompositeDataPipeline::UPDATE_BLOCKS())); // Tell the producer upstream that looping is about to start int retVal = this->SendBeginLoop(i, j, inInfo, updateInfo); if (retVal == vtkCompositeDataPipeline::EXECUTE_BLOCK_CONTINUE) { continue; } if (retVal == vtkCompositeDataPipeline::EXECUTE_BLOCK_ERROR) { return 0; } input = this->CreateInputCompositeData(i, inInfo); this->UpdateBlocks(i, j, outputPort, updateInfo, input, inInfo); if (!this->SendEndLoop(i, j)) { return 0; } } } int inputPortIsComposite; int inputIsComposite; int compositePort; this->CheckInputPorts(inputPortIsComposite, inputIsComposite, compositePort); if (inputIsComposite && !inputPortIsComposite) { this->ExecuteSimpleAlgorithm( request, inInfoVec, outInfoVec, compositePort); } else { result = this->Superclass::ExecuteData(request,inInfoVec,outInfoVec); } for(int jj=0; jj < this->Algorithm->GetNumberOfOutputPorts(); ++jj) { vtkInformation* info = this->GetOutputInformation(jj); vtkObject* dobj= info->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); if (dobj) { info->Set(UPDATE_BLOCKS(), dobj); } } return result; } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::CheckInputPorts(int& inputPortIsComposite, int& inputIsComposite, int& compositePort) { inputPortIsComposite = 0; inputIsComposite = 0; compositePort = -1; // Loop over all input ports and check if any of them asks // for composite data and has composite data. // Find the first port that asks for composite data and that // has composite data and break. // TODO: This should be changed to handle multiple ports that are // a mix of composite and simple data. for(int i=0; i < this->Algorithm->GetNumberOfInputPorts(); ++i) { vtkInformation* inPortInfo = this->Algorithm->GetInputPortInformation(i); if (inPortInfo->Has(INPUT_REQUIRED_COMPOSITE_DATA_TYPE())) { inputPortIsComposite = 1; } int numInConnections = this->Algorithm->GetNumberOfInputConnections(i); if (numInConnections > 0) { vtkInformation* inInfo = this->GetInputInformation(i, 0); if (inInfo->Has(vtkCompositeDataSet::COMPOSITE_DATA_SET())) { inputIsComposite = 1; compositePort = i; } } } } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::UpdateBlocks( int i, int j, int outputPort, vtkHierarchicalDataSet* updateInfo, vtkCompositeDataSet* input, vtkInformation* inInfo) { // Get the producer and its output port for input connection i,j. vtkExecutive* producer = 0; int producerPort = -1; if(vtkInformation* info = this->GetInputInformation(i, j)) { // Get the executive producing this input. If there is none, then // it is a NULL input. info->Get(vtkExecutive::PRODUCER(), producer, producerPort); } if(!producer) { this->SendEndLoop(i,j); return EXECUTE_BLOCK_ERROR; } // Execute the streaming demand driven pipeline for each block unsigned int numLevels = updateInfo->GetNumberOfLevels(); for (unsigned int k=0; kGetNumberOfDataSets(k); for (unsigned l=0; lGetDataSet(k,l)) { vtkDebugMacro(<< k << "," << l << " not marked for update"); continue; } // First pipeline mtime // Setup the request for pipeline modification time. this->GenericRequest->Set(vtkHierarchicalDataSet::LEVEL(), k); this->GenericRequest->Set(vtkCompositeDataSet::INDEX(), l); unsigned long mtime; producer->ComputePipelineMTime(this->GenericRequest, producer->GetInputInformation(), producer->GetOutputInformation(), producerPort, &mtime); // Do the data-object creation pass before the information pass. // Send the request for data object creation. this->DataObjectRequest->Set(vtkHierarchicalDataSet::LEVEL(), k); this->DataObjectRequest->Set(vtkCompositeDataSet::INDEX(), l); if (!this->ForwardUpstream(i, j, this->DataObjectRequest)) { this->SendEndLoop(i,j); return EXECUTE_BLOCK_ERROR; } // Send the request for information. this->InformationRequest->Set(vtkHierarchicalDataSet::LEVEL(), k); this->InformationRequest->Set(vtkCompositeDataSet::INDEX(), l); if (!this->ForwardUpstream(i, j, this->InformationRequest)) { this->SendEndLoop(i,j); return EXECUTE_BLOCK_ERROR; } // Update the whole thing // TODO: This might change if (inInfo->Has(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT())) { int extent[6] = {0,-1,0,-1,0,-1}; inInfo->Get( vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),extent); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent, 6); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT_INITIALIZED(), 1); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), 1); inInfo->Set( vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), 0); } // Send the request for update extent propagation. this->UpdateExtentRequest->Set(vtkHierarchicalDataSet::LEVEL(), k); this->UpdateExtentRequest->Set(vtkCompositeDataSet::INDEX(), l); this->UpdateExtentRequest->Set( vtkExecutive::FROM_OUTPUT_PORT(), outputPort); if (!this->ForwardUpstream(i, j, this->UpdateExtentRequest)) { this->SendEndLoop(i,j); return EXECUTE_BLOCK_ERROR; } // Send the request for data. this->DataRequest->Set(vtkHierarchicalDataSet::LEVEL(), k); this->DataRequest->Set(vtkCompositeDataSet::INDEX(), l); this->DataRequest->Set(FROM_OUTPUT_PORT(), outputPort); // Send the request. if (!this->ForwardUpstream(i, j, this->DataRequest)) { this->SendEndLoop(i,j); return EXECUTE_BLOCK_ERROR; } vtkDataObject* block = inInfo->Get(vtkDataObject::DATA_OBJECT()); if (block && input) { vtkDataObject* blockCopy = block->NewInstance(); blockCopy->ShallowCopy(block); input->AddDataSet(this->DataRequest, blockCopy); blockCopy->Delete(); } } } return EXECUTE_BLOCK_OK; } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::SendBeginLoop( int i, int j, vtkInformation* inInfo, vtkHierarchicalDataSet* updateInfo) { // Tell the producer upstream that looping is about to start this->GenericRequest->Set(BEGIN_LOOP(), 1); // The request is forwarded upstream through the pipeline. this->GenericRequest->Set( vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream); this->GenericRequest->Set(vtkExecutive::ALGORITHM_AFTER_FORWARD(), 1); // Send the request. if (!this->ForwardUpstream(i, j, this->GenericRequest)) { this->GenericRequest->Remove(BEGIN_LOOP()); return vtkCompositeDataPipeline::EXECUTE_BLOCK_ERROR; } if (!updateInfo) { // This means no composite data producer was found upstream. vtkDebugMacro(<< "No UPDATE_BLOCKS() for input " << i << "," << j << " was provided. Skipping."); this->SendEndLoop(i,j); this->GenericRequest->Remove(BEGIN_LOOP()); return vtkCompositeDataPipeline::EXECUTE_BLOCK_CONTINUE; } // If the input is up-to-date (not MARKED_FOR_UPDATE() by ProcessRequest -> // REQUEST_DATA()), there is no need to loop the input. If the input is // looped, it will cause unnecessary execution(s) if (!inInfo->Has(MARKED_FOR_UPDATE())) { this->SendEndLoop(i,j); this->GenericRequest->Remove(BEGIN_LOOP()); return vtkCompositeDataPipeline::EXECUTE_BLOCK_CONTINUE; } this->GenericRequest->Remove(BEGIN_LOOP()); return vtkCompositeDataPipeline::EXECUTE_BLOCK_OK; } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::SendEndLoop(int i, int j) { // Tell the producer upstream that looping is over vtkSmartPointer re = vtkSmartPointer::New(); re->Set(END_LOOP(), 1); // The request is forwarded upstream through the pipeline. re->Set(vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream); // Send the request. if (!this->ForwardUpstream(i, j, re)) { return 0; } return 1; } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::ExecuteSimpleAlgorithm( vtkInformation* request, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec, int compositePort) { int outputInitialized = 0; this->ExecuteDataStart(request,inInfoVec,outInfoVec); vtkInformation* outInfo = 0; vtkSmartPointer prevOutput; if (this->GetNumberOfOutputPorts() > 0) { outInfo = outInfoVec->GetInformationObject(0); } // Make sure a valid composite data object exists for all output ports. for(int i=0; i < this->Algorithm->GetNumberOfOutputPorts(); ++i) { this->CheckCompositeData(i, outInfoVec); } // Loop using the first input on the first port. // This might not be valid for all cases but it is a decent // assumption to start with. // TODO: Loop over all inputs vtkInformation* inInfo = this->GetInputInformation(compositePort, 0); vtkCompositeDataSet* input = vtkCompositeDataSet::SafeDownCast( inInfo->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET())); vtkHierarchicalDataSet* updateInfo = vtkHierarchicalDataSet::SafeDownCast( inInfo->Get(vtkCompositeDataPipeline::UPDATE_BLOCKS())); vtkCompositeDataSet* output = vtkCompositeDataSet::SafeDownCast( outInfo->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET())); prevOutput = outInfo->Get(vtkDataObject::DATA_OBJECT()); if (input && updateInfo) { vtkSmartPointer r = vtkSmartPointer::New(); r->Set(FROM_OUTPUT_PORT(), inInfo->GetPort(PRODUCER())); // The request is forwarded upstream through the pipeline. r->Set(vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream); // Algorithms process this request after it is forwarded. r->Set(vtkExecutive::ALGORITHM_AFTER_FORWARD(), 1); unsigned int numLevels = updateInfo->GetNumberOfLevels(); vtkSmartPointer prevInput = inInfo->Get(vtkDataObject::DATA_OBJECT()); vtkDebugMacro("EXECUTING: " << this->Algorithm->GetClassName()); // True when the pipeline is iterating over the current (simple) // filter to produce composite output. In this case, // ExecuteDataStart() should NOT Initialize() the composite output. this->InLocalLoop = 1; // Store the information (whole_extent and maximum_number_of_pieces) // before looping. Otherwise, executeinformation will cause // changes (because we pretend that the max. number of pieces is // one to process the whole block) this->PushInformation(inInfo); for (unsigned int k=0; kGetNumberOfDataSets(k); for (unsigned l=0; lGetDataSet(k,l)) { r->Set(vtkHierarchicalDataSet::LEVEL(), k); r->Set(vtkCompositeDataSet::INDEX(), l); vtkDataObject* dobj = input->GetDataSet(r); // There must be a bug somehwere. If this Remove() // is not called, the following Set() has the effect // of removing (!) the key. inInfo->Remove(vtkDataObject::DATA_OBJECT()); inInfo->Set(vtkDataObject::DATA_OBJECT(), dobj); // Process the whole dataset this->CopyFromDataToInformation(dobj, inInfo); r->Set(REQUEST_DATA_OBJECT()); this->Superclass::ExecuteDataObject (r,this->GetInputInformation(),this->GetOutputInformation()); r->Remove(REQUEST_DATA_OBJECT()); r->Set(REQUEST_INFORMATION()); this->Superclass::ExecuteInformation(r,inInfoVec,outInfoVec); r->Remove(REQUEST_INFORMATION()); for(int m=0; m < this->Algorithm->GetNumberOfOutputPorts(); ++m) { vtkInformation* info = this->GetOutputInformation(m); // Update the whole thing // TODO: This might change if (info->Has( vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT())) { int extent[6] = {0,-1,0,-1,0,-1}; info->Get( vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent); info->Set( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent, 6); info->Set( vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT_INITIALIZED(), 1); info->Set( vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), 1); info->Set( vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), 0); } } r->Set(REQUEST_UPDATE_EXTENT()); this->CallAlgorithm(r, vtkExecutive::RequestUpstream, inInfoVec, outInfoVec); this->ForwardUpstream(r); r->Remove(REQUEST_UPDATE_EXTENT()); r->Set(REQUEST_DATA()); this->Superclass::ExecuteData(r,inInfoVec,outInfoVec); r->Remove(REQUEST_DATA()); if (output && outInfo) { if (!outputInitialized) { output->PrepareForNewData(); outputInitialized = 1; } vtkDataObject* tmpOutput = outInfo->Get(vtkDataObject::DATA_OBJECT()); vtkDataObject* outputCopy = tmpOutput->NewInstance(); outputCopy->ShallowCopy(tmpOutput); output->AddDataSet(r, outputCopy); outputCopy->Delete(); } } } } // True when the pipeline is iterating over the current (simple) // filter to produce composite output. In this case, // ExecuteDataStart() should NOT Initialize() the composite output. this->InLocalLoop = 0; // Restore the extent information and force it to be // copied to the output. Composite sources should set // MAXIMUM_NUMBER_OF_PIECES to -1 anyway (and handle // piece requests properly). this->PopInformation(inInfo); r->Set(REQUEST_INFORMATION()); this->CopyDefaultInformation(r, vtkExecutive::RequestDownstream, this->GetInputInformation(), this->GetOutputInformation()); vtkDataObject* curInput = inInfo->Get(vtkDataObject::DATA_OBJECT()); if (curInput != prevInput) { inInfo->Remove(vtkDataObject::DATA_OBJECT()); inInfo->Set(vtkDataObject::DATA_OBJECT(), prevInput); } vtkDataObject* curOutput = outInfo->Get(vtkDataObject::DATA_OBJECT()); if (curOutput != prevOutput) { prevOutput->SetPipelineInformation(outInfo); } } this->ExecuteDataEnd(request,inInfoVec,outInfoVec); } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::ExecuteDataForBlock(vtkInformation* request) { vtkInformationVector* outputVector = this->GetOutputInformation(); int numOut = outputVector->GetNumberOfInformationObjects(); for (int i=0; iGetInformationObject(i); vtkDataObject* doOutput = info->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); vtkCompositeDataSet* output = vtkCompositeDataSet::SafeDownCast(doOutput); if (output) { vtkDataObject* dobj = output->GetDataSet(request); if (dobj) { vtkDataObject* dobjCopy = info->Get(vtkDataObject::DATA_OBJECT()); if (dobj && dobjCopy) { dobjCopy->ShallowCopy(dobj); } } } } return 1; } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::ForwardUpstream(vtkInformation* request) { return this->Superclass::ForwardUpstream(request); } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::ForwardUpstream( int i, int j, vtkInformation* request) { // Do not forward upstream if input information is shared. if(this->SharedInputInformation) { return 1; } if (!this->Algorithm->ModifyRequest(request, BeforeForward)) { return 0; } int result = 1; if(vtkExecutive* e = this->GetInputExecutive(i, j)) { vtkAlgorithmOutput* input = this->Algorithm->GetInputConnection(i, j); int port = request->Get(FROM_OUTPUT_PORT()); request->Set(FROM_OUTPUT_PORT(), input->GetIndex()); if(!e->ProcessRequest(request, e->GetInputInformation(), e->GetOutputInformation())) { result = 0; } request->Set(FROM_OUTPUT_PORT(), port); } if (!this->Algorithm->ModifyRequest(request, AfterForward)) { return 0; } return result; } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::CopyDefaultInformation( vtkInformation* request, int direction, vtkInformationVector** inInfoVec, vtkInformationVector* outInfoVec) { int hasUpdateBlocks = 0; if(direction == vtkExecutive::RequestDownstream) { vtkInformationKey** keys = request->Get(vtkExecutive::KEYS_TO_COPY()); if (keys) { int len = request->Length(vtkExecutive::KEYS_TO_COPY()); for (int i=0; iRemove(vtkExecutive::KEYS_TO_COPY(), vtkCompositeDataPipeline::UPDATE_BLOCKS()); } } } this->Superclass::CopyDefaultInformation(request, direction, inInfoVec, outInfoVec); if (hasUpdateBlocks) { request->Append(vtkExecutive::KEYS_TO_COPY(), vtkCompositeDataPipeline::UPDATE_BLOCKS()); } } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::CopyFromDataToInformation( vtkDataObject* dobj, vtkInformation* inInfo) { if (dobj->IsA("vtkImageData")) { inInfo->Set( WHOLE_EXTENT(), static_cast(dobj)->GetExtent(), 6); } else if (dobj->IsA("vtkStructuredGrid")) { inInfo->Set( WHOLE_EXTENT(), static_cast(dobj)->GetExtent(), 6); } else if (dobj->IsA("vtkRectilinearGrid")) { inInfo->Set( WHOLE_EXTENT(), static_cast(dobj)->GetExtent(), 6); } else if (dobj->IsA("vtkUniformGrid")) { inInfo->Set( WHOLE_EXTENT(), static_cast(dobj)->GetExtent(), 6); } else { inInfo->Set(MAXIMUM_NUMBER_OF_PIECES(), 1); } } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::PushInformation(vtkInformation* inInfo) { this->InformationCache->CopyEntry(inInfo, WHOLE_EXTENT()); this->InformationCache->CopyEntry(inInfo, MAXIMUM_NUMBER_OF_PIECES()); } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::PopInformation(vtkInformation* inInfo) { inInfo->CopyEntry(this->InformationCache, WHOLE_EXTENT()); inInfo->CopyEntry(this->InformationCache, MAXIMUM_NUMBER_OF_PIECES()); } //---------------------------------------------------------------------------- vtkCompositeDataSet* vtkCompositeDataPipeline::CreateInputCompositeData( int i, vtkInformation* inInfo) { vtkCompositeDataSet* input = 0; // If the input requires a composite dataset and one is not available, // create it. This means that there are "simple" filters between the // composite data producer and this filter vtkInformation* inPortInfo = this->Algorithm->GetInputPortInformation(i); const char* dt = inPortInfo->Get(INPUT_REQUIRED_COMPOSITE_DATA_TYPE()); if (dt) { if (strcmp(dt, "vtkCompositeDataSet") == 0) { // If vtkCompositeDataSet is specified, the algorithm // will work with all sub-classes. Create a vtkHierarchicalDataSet dt = "vtkHierarchicalDataSet"; } // If the composite data input to the algorithm is not // set, create and assign it. This happens when the producer // of the input data actually produces a simple data object // (in a loop) vtkDataObject* dobj = this->NewDataObject(dt); if (dobj) { dobj->SetPipelineInformation(inInfo); input = vtkCompositeDataSet::SafeDownCast(dobj); dobj->Delete(); } else { vtkErrorMacro("Cannot instantiate " << dt << ". The INPUT_REQUIRED_COMPOSITE_DATA_TYPE() of " << this->Algorithm->GetClassName() << " is not set properly."); } } return input; } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::CheckDataObject( int port, vtkInformationVector *outInfoVec) { // Check that the given output port has a valid data object. vtkInformation* outInfo = outInfoVec->GetInformationObject(port); vtkDataObject* data = outInfo->Get(vtkDataObject::DATA_OBJECT()); vtkInformation* portInfo = this->Algorithm->GetOutputPortInformation(port); if(const char* dt = portInfo->Get(vtkDataObject::DATA_TYPE_NAME())) { // The output port specifies a data type. Make sure the data // object exists and is of the right type. if(!data || !data->IsA(dt)) { // Try to create an instance of the correct type. data = this->NewDataObject(dt); this->SetOutputData(port, data, outInfo); if(data) { data->Delete(); } } if(!data) { // The algorithm has a bug and did not create the data object. vtkErrorMacro("Algorithm " << this->Algorithm->GetClassName() << "(" << this->Algorithm << ") did not create output for port " << port << " when asked by REQUEST_DATA_OBJECT and does not" << " specify a concrete DATA_TYPE_NAME."); return 0; } return 1; } else if(data || outInfo->Has(vtkCompositeDataSet::COMPOSITE_DATA_SET())) { // The algorithm did not specify its output data type. Just assume // the data object is of the correct type. return 1; } else { // The algorithm did not specify its output data type and no // object exists. vtkErrorMacro("Algorithm " << this->Algorithm->GetClassName() << "(" << this->Algorithm << ") did not create output for port " << port << " when asked by REQUEST_DATA_OBJECT and does not" << " specify any DATA_TYPE_NAME."); return 0; } } //---------------------------------------------------------------------------- int vtkCompositeDataPipeline::CheckCompositeData( int port, vtkInformationVector* outInfoVec) { // Check that the given output port has a valid data object. vtkInformation* outInfo = outInfoVec->GetInformationObject(port); vtkDataObject* data = outInfo->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); vtkInformation* portInfo = this->Algorithm->GetOutputPortInformation(port); if (const char* dt = portInfo->Get(COMPOSITE_DATA_TYPE_NAME())) { if(!data || !data->IsA(dt)) { // Try to create an instance of the correct type. data = this->NewDataObject(dt); data->SetPipelineInformation(outInfo); if(data) { data->Delete(); } } } // If this is a simple filter but has composite input, create a composite // output. int inputPortIsComposite; int inputIsComposite; int compositePort; this->CheckInputPorts(inputPortIsComposite, inputIsComposite, compositePort); if (inputIsComposite && !inputPortIsComposite) { // This assumes that the filter has one output. vtkDataObject* doOutput = outInfo->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); vtkCompositeDataSet* output = vtkCompositeDataSet::SafeDownCast(doOutput); if (!output) { output = vtkHierarchicalDataSet::New(); output->SetPipelineInformation(outInfo); output->Delete(); } } return 1; } //---------------------------------------------------------------------------- vtkDataObject* vtkCompositeDataPipeline::GetCompositeOutputData(int port) { if(!this->OutputPortIndexInRange(port, "get data for")) { return 0; } // Check that the given output port has a valid data object. this->CheckCompositeData(port, this->GetOutputInformation()); // Return the data object. if(vtkInformation* info = this->GetOutputInformation(port)) { return info->Get(vtkCompositeDataSet::COMPOSITE_DATA_SET()); } return 0; } //---------------------------------------------------------------------------- void vtkCompositeDataPipeline::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }