Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1350 lines
45 KiB

/*=========================================================================
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; i<len; i++)
{
if (keys[i] == vtkCompositeDataPipeline::COMPOSITE_DATA_INFORMATION())
{
appendKey = 0;
break;
}
}
}
if (appendKey)
{
request->Append(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; i<len; i++)
{
if (keys[i] == vtkCompositeDataPipeline::UPDATE_BLOCKS())
{
appendKey = 0;
break;
}
}
}
if (appendKey)
{
request->Append(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; j<numInConnections; j++)
{
vtkInformation* inInfo = inInfoVec[i]->GetInformationObject(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; i<numOut; i++)
{
vtkInformation* portInfo =
this->Algorithm->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<vtkInformation> r =
vtkSmartPointer<vtkInformation>::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; i<numOut; i++)
{
vtkInformation* info = outputVector->GetInformationObject(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; j<numInConnections; j++)
{
// If the algorithm connected to the input port did not provide
// a composite dataset, it is a "simple" algorithm. Every block
// that consists of a group of simple algorithms has to be executed
// in a loop to process composite datasets. This is done by a
// collaboration of the composite source and algorithm that surround
// this simple algorithm block.
vtkInformation* inInfo = inInfoVec[i]->GetInformationObject(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; k<numLevels; k++)
{
unsigned int numDataSets = updateInfo->GetNumberOfDataSets(k);
for (unsigned l=0; l<numDataSets; l++)
{
if (!updateInfo->GetDataSet(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<vtkInformation> re =
vtkSmartPointer<vtkInformation>::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<vtkDataObject> 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<vtkInformation> r =
vtkSmartPointer<vtkInformation>::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<vtkDataObject> 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; k<numLevels; k++)
{
unsigned int numDataSets = updateInfo->GetNumberOfDataSets(k);
for (unsigned l=0; l<numDataSets; l++)
{
if (updateInfo->GetDataSet(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; i<numOut; i++)
{
vtkInformation* info = outputVector->GetInformationObject(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; i<len; i++)
{
if (keys[i] == vtkCompositeDataPipeline::UPDATE_BLOCKS())
{
hasUpdateBlocks = 1;
break;
}
}
if (hasUpdateBlocks)
{
request->Remove(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<vtkImageData*>(dobj)->GetExtent(), 6);
}
else if (dobj->IsA("vtkStructuredGrid"))
{
inInfo->Set(
WHOLE_EXTENT(), static_cast<vtkStructuredGrid*>(dobj)->GetExtent(), 6);
}
else if (dobj->IsA("vtkRectilinearGrid"))
{
inInfo->Set(
WHOLE_EXTENT(), static_cast<vtkRectilinearGrid*>(dobj)->GetExtent(), 6);
}
else if (dobj->IsA("vtkUniformGrid"))
{
inInfo->Set(
WHOLE_EXTENT(), static_cast<vtkUniformGrid*>(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);
}