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.
1134 lines
35 KiB
1134 lines
35 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkDemandDrivenPipeline.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 "vtkDemandDrivenPipeline.h"
|
|
|
|
#include "vtkAlgorithm.h"
|
|
#include "vtkAlgorithmOutput.h"
|
|
#include "vtkCellData.h"
|
|
#include "vtkCommand.h"
|
|
#include "vtkDataObject.h"
|
|
#include "vtkDataSet.h"
|
|
#include "vtkGarbageCollector.h"
|
|
#include "vtkHierarchicalBoxDataSet.h"
|
|
#include "vtkHierarchicalDataSet.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationIntegerKey.h"
|
|
#include "vtkInformationKeyVectorKey.h"
|
|
#include "vtkInformationRequestKey.h"
|
|
#include "vtkInformationUnsignedLongKey.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkInstantiator.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPointData.h"
|
|
|
|
#include "vtkImageData.h"
|
|
#include "vtkPolyData.h"
|
|
#include "vtkRectilinearGrid.h"
|
|
#include "vtkStructuredGrid.h"
|
|
#include "vtkStructuredPoints.h"
|
|
#include "vtkUnstructuredGrid.h"
|
|
|
|
#include <vtkstd/vector>
|
|
|
|
vtkCxxRevisionMacro(vtkDemandDrivenPipeline, "$Revision: 1.37.4.5 $");
|
|
vtkStandardNewMacro(vtkDemandDrivenPipeline);
|
|
|
|
vtkInformationKeyMacro(vtkDemandDrivenPipeline, DATA_NOT_GENERATED, Integer);
|
|
vtkInformationKeyMacro(vtkDemandDrivenPipeline, RELEASE_DATA, Integer);
|
|
vtkInformationKeyMacro(vtkDemandDrivenPipeline, REQUEST_DATA, Request);
|
|
vtkInformationKeyMacro(vtkDemandDrivenPipeline, REQUEST_DATA_NOT_GENERATED, Request);
|
|
vtkInformationKeyMacro(vtkDemandDrivenPipeline, REQUEST_DATA_OBJECT, Request);
|
|
vtkInformationKeyMacro(vtkDemandDrivenPipeline, REQUEST_INFORMATION, Request);
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDemandDrivenPipeline::vtkDemandDrivenPipeline()
|
|
{
|
|
this->InfoRequest = 0;
|
|
this->DataObjectRequest = 0;
|
|
this->DataRequest = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDemandDrivenPipeline::~vtkDemandDrivenPipeline()
|
|
{
|
|
if (this->InfoRequest)
|
|
{
|
|
this->InfoRequest->Delete();
|
|
}
|
|
if (this->DataObjectRequest)
|
|
{
|
|
this->DataObjectRequest->Delete();
|
|
}
|
|
if (this->DataRequest)
|
|
{
|
|
this->DataRequest->Delete();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDemandDrivenPipeline::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
os << indent << "PipelineMTime: " << this->PipelineMTime << "\n";
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
vtkDemandDrivenPipeline::ComputePipelineMTime(vtkInformation* request,
|
|
vtkInformationVector** inInfoVec,
|
|
vtkInformationVector* outInfoVec,
|
|
int requestFromOutputPort,
|
|
unsigned long* mtime)
|
|
{
|
|
// The pipeline's MTime starts with this algorithm's MTime.
|
|
// Invoke the request on the algorithm.
|
|
this->InAlgorithm = 1;
|
|
int result =
|
|
this->Algorithm->ComputePipelineMTime(request,
|
|
inInfoVec, outInfoVec,
|
|
requestFromOutputPort,
|
|
&this->PipelineMTime);
|
|
this->InAlgorithm = 0;
|
|
|
|
// If the algorithm failed report it now.
|
|
if(!result)
|
|
{
|
|
if(request)
|
|
{
|
|
vtkErrorMacro("Algorithm " << this->Algorithm->GetClassName()
|
|
<< "(" << this->Algorithm
|
|
<< ") returned failure for pipeline"
|
|
<< " modified time request from output port "
|
|
<< requestFromOutputPort<< ": " << *request);
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro("Algorithm " << this->Algorithm->GetClassName()
|
|
<< "(" << this->Algorithm
|
|
<< ") returned failure for pipeline"
|
|
<< " modified time request from output port "
|
|
<< requestFromOutputPort<< ".");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Forward the request upstream if not sharing input information.
|
|
if(!this->SharedInputInformation)
|
|
{
|
|
// We want the maximum PipelineMTime of all inputs.
|
|
for(int i=0; i < this->Algorithm->GetNumberOfInputPorts(); ++i)
|
|
{
|
|
for(int j=0; j < inInfoVec[i]->GetNumberOfInformationObjects(); ++j)
|
|
{
|
|
vtkInformation* info = inInfoVec[i]->GetInformationObject(j);
|
|
// call ComputePipelineMTime on the input
|
|
vtkExecutive* e;
|
|
int producerPort;
|
|
info->Get(vtkExecutive::PRODUCER(),e,producerPort);
|
|
if(e)
|
|
{
|
|
unsigned long pmtime;
|
|
if(!e->ComputePipelineMTime(request,
|
|
e->GetInputInformation(),
|
|
e->GetOutputInformation(),
|
|
producerPort, &pmtime))
|
|
{
|
|
return 0;
|
|
}
|
|
if(pmtime > this->PipelineMTime)
|
|
{
|
|
this->PipelineMTime = pmtime;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*mtime = this->PipelineMTime;
|
|
return 1;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::ProcessRequest(vtkInformation* request,
|
|
vtkInformationVector** inInfoVec,
|
|
vtkInformationVector* outInfoVec)
|
|
{
|
|
// The algorithm should not invoke anything on the executive.
|
|
if(!this->CheckAlgorithm("ProcessRequest", request))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if(this->Algorithm && request->Has(REQUEST_DATA_OBJECT()))
|
|
{
|
|
// if we are up to date then short circuit
|
|
if (this->PipelineMTime < this->DataObjectTime.GetMTime())
|
|
{
|
|
return 1;
|
|
}
|
|
// Update inputs first if they are out of date
|
|
if(!this->ForwardUpstream(request))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Make sure our output data type is up-to-date.
|
|
int result = 1;
|
|
if(this->PipelineMTime > this->DataObjectTime.GetMTime())
|
|
{
|
|
// Request data type from the algorithm.
|
|
result = this->ExecuteDataObject(request,inInfoVec,outInfoVec);
|
|
|
|
// Make sure the data object exists for all output ports.
|
|
for(int i=0;
|
|
result && i < outInfoVec->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
vtkInformation* info = outInfoVec->GetInformationObject(i);
|
|
if(!info->Get(vtkDataObject::DATA_OBJECT()))
|
|
{
|
|
result = 0;
|
|
}
|
|
}
|
|
|
|
if(result)
|
|
{
|
|
// Data object is now up to date.
|
|
this->DataObjectTime.Modified();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
if(this->Algorithm && request->Has(REQUEST_INFORMATION()))
|
|
{
|
|
// if we are up to date then short circuit
|
|
if (this->PipelineMTime < this->InformationTime.GetMTime())
|
|
{
|
|
return 1;
|
|
}
|
|
// Update inputs first.
|
|
if(!this->ForwardUpstream(request))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Make sure our output information is up-to-date.
|
|
int result = 1;
|
|
if(this->PipelineMTime > this->InformationTime.GetMTime())
|
|
{
|
|
// Make sure input types are valid before algorithm does anything.
|
|
if(!this->InputCountIsValid(inInfoVec) ||
|
|
!this->InputTypeIsValid(inInfoVec))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Request information from the algorithm.
|
|
result = this->ExecuteInformation(request,inInfoVec,outInfoVec);
|
|
|
|
// Information is now up to date.
|
|
this->InformationTime.Modified();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
if(this->Algorithm && request->Has(REQUEST_DATA()))
|
|
{
|
|
// 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());
|
|
}
|
|
|
|
// Make sure our outputs are up-to-date.
|
|
int result = 1;
|
|
if(this->NeedToExecuteData(outputPort,inInfoVec,outInfoVec))
|
|
{
|
|
// Update inputs first.
|
|
if(!this->ForwardUpstream(request))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Make sure inputs are valid before algorithm does anything.
|
|
if(!this->InputCountIsValid(inInfoVec) ||
|
|
!this->InputTypeIsValid(inInfoVec) ||
|
|
!this->InputFieldsAreValid(inInfoVec))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Request data from the algorithm.
|
|
result = this->ExecuteData(request,inInfoVec,outInfoVec);
|
|
|
|
// Data are now up to date.
|
|
this->DataTime.Modified();
|
|
|
|
// Some filters may modify themselves while processing
|
|
// REQUEST_DATA. Since we mark the filter execution end time
|
|
// here this behavior does not cause re-execution, so it should
|
|
// be allowed. The filter is now considered up-to-date.
|
|
// However, we must prevent the REQUEST_DATA_OBJECT and
|
|
// REQUEST_INFORMATION passes from re-running, so mark them
|
|
// up-do-date also. It is up to the filter to not modify itself
|
|
// in a way that would change the result of any pass.
|
|
this->InformationTime.Modified();
|
|
this->DataObjectTime.Modified();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Let the superclass handle other requests.
|
|
return this->Superclass::ProcessRequest(request, inInfoVec, outInfoVec);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDemandDrivenPipeline::ResetPipelineInformation(int,
|
|
vtkInformation* info)
|
|
{
|
|
info->Remove(RELEASE_DATA());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::Update()
|
|
{
|
|
return this->Superclass::Update();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::Update(int port)
|
|
{
|
|
if(!this->UpdateInformation())
|
|
{
|
|
return 0;
|
|
}
|
|
if(port >= -1 && port < this->Algorithm->GetNumberOfOutputPorts())
|
|
{
|
|
return this->UpdateData(port);
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::UpdatePipelineMTime()
|
|
{
|
|
// The algorithm should not invoke anything on the executive.
|
|
if(!this->CheckAlgorithm("UpdatePipelineMTime", 0))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Send the request for pipeline modified time.
|
|
unsigned long mtime;
|
|
this->ComputePipelineMTime(0,
|
|
this->GetInputInformation(),
|
|
this->GetOutputInformation(),
|
|
-1, &mtime);
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::UpdateDataObject()
|
|
{
|
|
// The algorithm should not invoke anything on the executive.
|
|
if(!this->CheckAlgorithm("UpdateDataObject", 0))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Update the pipeline mtime first.
|
|
if(!this->UpdatePipelineMTime())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Setup the request for data object creation.
|
|
if (!this->DataObjectRequest)
|
|
{
|
|
this->DataObjectRequest = vtkInformation::New();
|
|
this->DataObjectRequest->Set(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);
|
|
}
|
|
|
|
// Send the request.
|
|
return this->ProcessRequest(this->DataObjectRequest,
|
|
this->GetInputInformation(),
|
|
this->GetOutputInformation());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::UpdateInformation()
|
|
{
|
|
// The algorithm should not invoke anything on the executive.
|
|
if(!this->CheckAlgorithm("UpdateInformation", 0))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Do the data-object creation pass before the information pass.
|
|
if(!this->UpdateDataObject())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Setup the request for information.
|
|
if (!this->InfoRequest)
|
|
{
|
|
this->InfoRequest = vtkInformation::New();
|
|
this->InfoRequest->Set(REQUEST_INFORMATION());
|
|
// The request is forwarded upstream through the pipeline.
|
|
this->InfoRequest->Set(vtkExecutive::FORWARD_DIRECTION(), vtkExecutive::RequestUpstream);
|
|
// Algorithms process this request after it is forwarded.
|
|
this->InfoRequest->Set(vtkExecutive::ALGORITHM_AFTER_FORWARD(), 1);
|
|
}
|
|
|
|
// Send the request.
|
|
return this->ProcessRequest(this->InfoRequest,
|
|
this->GetInputInformation(),
|
|
this->GetOutputInformation());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::UpdateData(int outputPort)
|
|
{
|
|
// The algorithm should not invoke anything on the executive.
|
|
if(!this->CheckAlgorithm("UpdateData", 0))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Range check.
|
|
if(outputPort < -1 ||
|
|
outputPort >= this->Algorithm->GetNumberOfOutputPorts())
|
|
{
|
|
vtkErrorMacro("UpdateData given output port index "
|
|
<< outputPort << " on an algorithm with "
|
|
<< this->Algorithm->GetNumberOfOutputPorts()
|
|
<< " output ports.");
|
|
return 0;
|
|
}
|
|
|
|
// Setup the request for data.
|
|
if (!this->DataRequest)
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Send the request.
|
|
this->DataRequest->Set(FROM_OUTPUT_PORT(), outputPort);
|
|
return this->ProcessRequest(this->DataRequest,
|
|
this->GetInputInformation(),
|
|
this->GetOutputInformation());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::ExecuteDataObject(vtkInformation* request,
|
|
vtkInformationVector** inInfo,
|
|
vtkInformationVector* outInfo)
|
|
{
|
|
// Invoke the request on the algorithm.
|
|
int result = this->CallAlgorithm(request, vtkExecutive::RequestDownstream,
|
|
inInfo, outInfo);
|
|
|
|
// Make sure a valid data object exists for all output ports.
|
|
for(int i=0; result && i < this->Algorithm->GetNumberOfOutputPorts(); ++i)
|
|
{
|
|
result = this->CheckDataObject(i, outInfo);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::ExecuteInformation
|
|
(vtkInformation* request,
|
|
vtkInformationVector** inInfoVec,
|
|
vtkInformationVector* outInfoVec)
|
|
{
|
|
// Give each output data object a chance to set default values in
|
|
// its pipeline information. Provide the first input's information
|
|
// to each output.
|
|
vtkInformation* inInfo = 0;
|
|
if(this->GetNumberOfInputPorts() > 0)
|
|
{
|
|
inInfo = inInfoVec[0]->GetInformationObject(0);
|
|
}
|
|
for(int i=0; i < this->Algorithm->GetNumberOfOutputPorts(); ++i)
|
|
{
|
|
vtkInformation* outInfo = outInfoVec->GetInformationObject(i);
|
|
if(vtkDataObject* outData = outInfo->Get(vtkDataObject::DATA_OBJECT()))
|
|
{
|
|
outData->CopyInformationToPipeline(request, inInfo);
|
|
}
|
|
}
|
|
|
|
// Invoke the request on the algorithm.
|
|
return this->CallAlgorithm(request, vtkExecutive::RequestDownstream,
|
|
inInfoVec, outInfoVec);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::ExecuteData(vtkInformation* request,
|
|
vtkInformationVector** inInfo,
|
|
vtkInformationVector* outInfo)
|
|
{
|
|
this->ExecuteDataStart(request, inInfo, outInfo);
|
|
// Invoke the request on the algorithm.
|
|
int result = this->CallAlgorithm(request, vtkExecutive::RequestDownstream,
|
|
inInfo, outInfo);
|
|
this->ExecuteDataEnd(request, inInfo, outInfo);
|
|
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDemandDrivenPipeline::ExecuteDataStart(vtkInformation* request,
|
|
vtkInformationVector** inInfo,
|
|
vtkInformationVector* outputs)
|
|
{
|
|
int i;
|
|
|
|
// Ask the algorithm to mark outputs that it will not generate.
|
|
request->Remove(REQUEST_DATA());
|
|
request->Set(REQUEST_DATA_NOT_GENERATED());
|
|
this->CallAlgorithm(request, vtkExecutive::RequestDownstream,
|
|
inInfo, outputs);
|
|
request->Remove(REQUEST_DATA_NOT_GENERATED());
|
|
request->Set(REQUEST_DATA());
|
|
|
|
// Prepare outputs that will be generated to receive new data.
|
|
for(i=0; i < outputs->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
vtkInformation* outInfo = outputs->GetInformationObject(i);
|
|
vtkDataObject* data = outInfo->Get(vtkDataObject::DATA_OBJECT());
|
|
if(data && !outInfo->Get(DATA_NOT_GENERATED()))
|
|
{
|
|
data->PrepareForNewData();
|
|
data->CopyInformationFromPipeline(request);
|
|
}
|
|
}
|
|
|
|
// Pass the vtkDataObject's field data from the first input to all
|
|
// outputs.
|
|
if (this->GetNumberOfInputPorts() > 0)
|
|
{
|
|
vtkDataObject* input = this->GetInputData(0, 0);
|
|
if (input && input->GetFieldData())
|
|
{
|
|
for(i=0; i < outputs->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
vtkInformation* outInfo = outputs->GetInformationObject(i);
|
|
vtkDataObject* output = outInfo->Get(vtkDataObject::DATA_OBJECT());
|
|
if(output)
|
|
{
|
|
output->GetFieldData()->PassData(input->GetFieldData());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Tell observers the algorithm is about to execute.
|
|
this->Algorithm->InvokeEvent(vtkCommand::StartEvent,NULL);
|
|
|
|
// The algorithm has not yet made any progress.
|
|
this->Algorithm->SetAbortExecute(0);
|
|
this->Algorithm->UpdateProgress(0.0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDemandDrivenPipeline::ExecuteDataEnd(vtkInformation* request,
|
|
vtkInformationVector** inInfoVec,
|
|
vtkInformationVector* outputs)
|
|
{
|
|
// The algorithm has either finished or aborted.
|
|
if(!this->Algorithm->GetAbortExecute())
|
|
{
|
|
this->Algorithm->UpdateProgress(1.0);
|
|
}
|
|
|
|
// Tell observers the algorithm is done executing.
|
|
this->Algorithm->InvokeEvent(vtkCommand::EndEvent,NULL);
|
|
|
|
// Tell outputs they have been generated.
|
|
this->MarkOutputsGenerated(request,inInfoVec,outputs);
|
|
|
|
// Remove any not-generated mark.
|
|
int i, j;
|
|
for(i=0; i < outputs->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
vtkInformation* outInfo = outputs->GetInformationObject(i);
|
|
outInfo->Remove(DATA_NOT_GENERATED());
|
|
}
|
|
|
|
// Release input data if requested.
|
|
for(i=0; i < this->Algorithm->GetNumberOfInputPorts(); ++i)
|
|
{
|
|
for(j=0; j < inInfoVec[i]->GetNumberOfInformationObjects(); ++j)
|
|
{
|
|
vtkInformation* inInfo = inInfoVec[i]->GetInformationObject(j);
|
|
vtkDataObject* dataObject = inInfo->Get(vtkDataObject::DATA_OBJECT());
|
|
if(dataObject && (dataObject->GetGlobalReleaseDataFlag() ||
|
|
inInfo->Get(RELEASE_DATA())))
|
|
{
|
|
dataObject->ReleaseData();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDemandDrivenPipeline::MarkOutputsGenerated
|
|
(vtkInformation*,
|
|
vtkInformationVector** /* inInfoVec */,
|
|
vtkInformationVector* outputs)
|
|
{
|
|
// Tell all generated outputs that they have been generated.
|
|
for(int i=0; i < outputs->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
vtkInformation* outInfo = outputs->GetInformationObject(i);
|
|
vtkDataObject* data = outInfo->Get(vtkDataObject::DATA_OBJECT());
|
|
if(data && !outInfo->Get(DATA_NOT_GENERATED()))
|
|
{
|
|
data->DataHasBeenGenerated();
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::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->FastDelete();
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
// 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 vtkDemandDrivenPipeline::InputCountIsValid
|
|
(vtkInformationVector **inInfoVec)
|
|
{
|
|
// Check the number of connections for each port.
|
|
int result = 1;
|
|
for(int p=0; p < this->Algorithm->GetNumberOfInputPorts(); ++p)
|
|
{
|
|
if(!this->InputCountIsValid(p,inInfoVec))
|
|
{
|
|
result = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputCountIsValid
|
|
(int port, vtkInformationVector **inInfoVec)
|
|
{
|
|
// Get the number of connections for this port.
|
|
if (!inInfoVec[port])
|
|
{
|
|
return 0;
|
|
}
|
|
int connections = inInfoVec[port]->GetNumberOfInformationObjects();
|
|
|
|
// If the input port is optional, there may be less than one connection.
|
|
if(!this->InputIsOptional(port) && (connections < 1))
|
|
{
|
|
vtkErrorMacro("Input port " << port << " of algorithm "
|
|
<< this->Algorithm->GetClassName()
|
|
<< "(" << this->Algorithm << ") has " << connections
|
|
<< " connections but is not optional.");
|
|
return 0;
|
|
}
|
|
|
|
// If the input port is repeatable, there may be more than one connection.
|
|
if(!this->InputIsRepeatable(port) && (connections > 1))
|
|
{
|
|
vtkErrorMacro("Input port " << port << " of algorithm "
|
|
<< this->Algorithm->GetClassName()
|
|
<< "(" << this->Algorithm << ") has " << connections
|
|
<< " connections but is not repeatable.");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputTypeIsValid
|
|
(vtkInformationVector **inInfoVec)
|
|
{
|
|
// Check the connection types for each port.
|
|
int result = 1;
|
|
for(int p=0; p < this->Algorithm->GetNumberOfInputPorts(); ++p)
|
|
{
|
|
if(!this->InputTypeIsValid(p, inInfoVec))
|
|
{
|
|
result = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputTypeIsValid
|
|
(int port, vtkInformationVector **inInfoVec)
|
|
{
|
|
// Check the type of each connection on this port.
|
|
int result = 1;
|
|
if (!inInfoVec[port])
|
|
{
|
|
return 0;
|
|
}
|
|
for(int i=0; i < inInfoVec[port]->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
if(!this->InputTypeIsValid(port, i, inInfoVec))
|
|
{
|
|
result = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputTypeIsValid
|
|
(int port, int index, vtkInformationVector **inInfoVec)
|
|
{
|
|
if (!inInfoVec[port])
|
|
{
|
|
return 0;
|
|
}
|
|
vtkInformation* info = this->Algorithm->GetInputPortInformation(port);
|
|
vtkDataObject* input = this->GetInputData(port, index, inInfoVec);
|
|
|
|
// Enforce required type, if any.
|
|
if(const char* dt = info->Get(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE()))
|
|
{
|
|
// The input cannot be NULL unless the port is optional.
|
|
if(!input && !info->Get(vtkAlgorithm::INPUT_IS_OPTIONAL()))
|
|
{
|
|
vtkErrorMacro("Input for connection index " << index
|
|
<< " on input port index " << port
|
|
<< " for algorithm " << this->Algorithm->GetClassName()
|
|
<< "(" << this->Algorithm << ") is NULL, but a " << dt
|
|
<< " is required.");
|
|
return 0;
|
|
}
|
|
|
|
// The input must be of required type or NULL.
|
|
if(input && !input->IsA(dt))
|
|
{
|
|
vtkErrorMacro("Input for connection index " << index
|
|
<< " on input port index " << port
|
|
<< " for algorithm " << this->Algorithm->GetClassName()
|
|
<< "(" << this->Algorithm << ") is of type "
|
|
<< input->GetClassName() << ", but a " << dt
|
|
<< " is required.");
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputFieldsAreValid
|
|
(vtkInformationVector **inInfoVec)
|
|
{
|
|
// Check the fields for each port.
|
|
int result = 1;
|
|
for(int p=0; p < this->Algorithm->GetNumberOfInputPorts(); ++p)
|
|
{
|
|
if(!this->InputFieldsAreValid(p,inInfoVec))
|
|
{
|
|
result = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputFieldsAreValid
|
|
(int port, vtkInformationVector **inInfoVec)
|
|
{
|
|
// Check the fields for each connection on this port.
|
|
if (!inInfoVec[port])
|
|
{
|
|
return 0;
|
|
}
|
|
int result = 1;
|
|
for(int i=0; i < inInfoVec[port]->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
if(!this->InputFieldsAreValid(port, i, inInfoVec))
|
|
{
|
|
result = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputFieldsAreValid
|
|
(int port, int index, vtkInformationVector **inInfoVec)
|
|
{
|
|
vtkInformation* info = this->Algorithm->GetInputPortInformation(port);
|
|
vtkInformationVector* fields =
|
|
info->Get(vtkAlgorithm::INPUT_REQUIRED_FIELDS());
|
|
|
|
// If there are no required fields, there is nothing to check.
|
|
if(!fields)
|
|
{
|
|
return 1;
|
|
}
|
|
vtkDataObject* input = this->GetInputData(port, index, inInfoVec);
|
|
|
|
// NULL inputs do not have to have the proper fields.
|
|
if(!input)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
// Check availability of each required field.
|
|
int result = 1;
|
|
for(int i=0; i < fields->GetNumberOfInformationObjects(); ++i)
|
|
{
|
|
vtkInformation* field = fields->GetInformationObject(i);
|
|
|
|
// Decide which kinds of fields to check.
|
|
int checkPoints = 1;
|
|
int checkCells = 1;
|
|
int checkFields = 1;
|
|
if(field->Has(vtkDataObject::FIELD_ASSOCIATION()))
|
|
{
|
|
switch(field->Get(vtkDataObject::FIELD_ASSOCIATION()))
|
|
{
|
|
case vtkDataObject::FIELD_ASSOCIATION_POINTS:
|
|
checkCells = 0; checkFields = 0; break;
|
|
case vtkDataObject::FIELD_ASSOCIATION_CELLS:
|
|
checkPoints = 0; checkFields = 0; break;
|
|
case vtkDataObject::FIELD_ASSOCIATION_NONE:
|
|
checkPoints = 0; checkCells = 0; break;
|
|
}
|
|
}
|
|
|
|
// Point and cell data arrays only exist in vtkDataSet instances.
|
|
vtkDataSet* dataSet = vtkDataSet::SafeDownCast(input);
|
|
|
|
// Look for a point data, cell data, or field data array matching
|
|
// the requirements.
|
|
if(!(checkPoints && dataSet && dataSet->GetPointData() &&
|
|
this->DataSetAttributeExists(dataSet->GetPointData(), field)) &&
|
|
!(checkCells && dataSet && dataSet->GetCellData() &&
|
|
this->DataSetAttributeExists(dataSet->GetCellData(), field)) &&
|
|
!(checkFields && input && input->GetFieldData() &&
|
|
this->FieldArrayExists(input->GetFieldData(), field)))
|
|
{
|
|
/* TODO: Construct more descriptive error message from field
|
|
requirements. */
|
|
vtkErrorMacro("Required field not found in input.");
|
|
result = 0;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::DataSetAttributeExists(vtkDataSetAttributes* dsa,
|
|
vtkInformation* field)
|
|
{
|
|
if(field->Has(vtkDataObject::FIELD_ATTRIBUTE_TYPE()))
|
|
{
|
|
// A specific attribute must match the requirements.
|
|
int attrType = field->Get(vtkDataObject::FIELD_ATTRIBUTE_TYPE());
|
|
return this->ArrayIsValid(dsa->GetAttribute(attrType), field);
|
|
}
|
|
else
|
|
{
|
|
// Search for an array matching the requirements.
|
|
return this->FieldArrayExists(dsa, field);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::FieldArrayExists(vtkFieldData* data,
|
|
vtkInformation* field)
|
|
{
|
|
// Search the field data instance for an array matching the requirements.
|
|
for(int a=0; a < data->GetNumberOfArrays(); ++a)
|
|
{
|
|
if(this->ArrayIsValid(data->GetArray(a), field))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::ArrayIsValid(vtkDataArray* array,
|
|
vtkInformation* field)
|
|
{
|
|
// Enforce existence of the array.
|
|
if(!array)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Enforce name of the array. This should really only be used for
|
|
// field data (not point or cell data).
|
|
if(const char* name = field->Get(vtkDataObject::FIELD_NAME()))
|
|
{
|
|
if(!array->GetName() || (strcmp(name, array->GetName()) != 0))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Enforce component type for the array.
|
|
if(field->Has(vtkDataObject::FIELD_ARRAY_TYPE()))
|
|
{
|
|
int arrayType = field->Get(vtkDataObject::FIELD_ARRAY_TYPE());
|
|
if(array->GetDataType() != arrayType)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Enforce number of components for the array.
|
|
if(field->Has(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS()))
|
|
{
|
|
int arrayNumComponents =
|
|
field->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS());
|
|
if(array->GetNumberOfComponents() != arrayNumComponents)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Enforce number of tuples. This should really only be used for
|
|
// field data (not point or cell data).
|
|
if(field->Has(vtkDataObject::FIELD_NUMBER_OF_TUPLES()))
|
|
{
|
|
int arrayNumTuples = field->Get(vtkDataObject::FIELD_NUMBER_OF_TUPLES());
|
|
if(array->GetNumberOfTuples() != arrayNumTuples)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputIsOptional(int port)
|
|
{
|
|
if(vtkInformation* info = this->Algorithm->GetInputPortInformation(port))
|
|
{
|
|
return info->Get(vtkAlgorithm::INPUT_IS_OPTIONAL());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::InputIsRepeatable(int port)
|
|
{
|
|
if(vtkInformation* info = this->Algorithm->GetInputPortInformation(port))
|
|
{
|
|
return info->Get(vtkAlgorithm::INPUT_IS_REPEATABLE());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDataObject* vtkDemandDrivenPipeline::NewDataObject(const char* type)
|
|
{
|
|
// Check for some standard types and then try the instantiator.
|
|
if(strcmp(type, "vtkImageData") == 0)
|
|
{
|
|
return vtkImageData::New();
|
|
}
|
|
else if(strcmp(type, "vtkPolyData") == 0)
|
|
{
|
|
return vtkPolyData::New();
|
|
}
|
|
else if(strcmp(type, "vtkRectilinearGrid") == 0)
|
|
{
|
|
return vtkRectilinearGrid::New();
|
|
}
|
|
else if(strcmp(type, "vtkStructuredGrid") == 0)
|
|
{
|
|
return vtkStructuredGrid::New();
|
|
}
|
|
else if(strcmp(type, "vtkStructuredPoints") == 0)
|
|
{
|
|
return vtkStructuredPoints::New();
|
|
}
|
|
else if(strcmp(type, "vtkUnstructuredGrid") == 0)
|
|
{
|
|
return vtkUnstructuredGrid::New();
|
|
}
|
|
else if(strcmp(type, "vtkHierarchicalDataSet") == 0)
|
|
{
|
|
return vtkHierarchicalDataSet::New();
|
|
}
|
|
else if(strcmp(type, "vtkHierarchicalBoxDataSet") == 0)
|
|
{
|
|
return vtkHierarchicalBoxDataSet::New();
|
|
}
|
|
else if(vtkObject* obj = vtkInstantiator::CreateInstance(type))
|
|
{
|
|
vtkDataObject* data = vtkDataObject::SafeDownCast(obj);
|
|
if(!data)
|
|
{
|
|
obj->Delete();
|
|
}
|
|
return data;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline
|
|
::NeedToExecuteData(int outputPort,
|
|
vtkInformationVector** inInfoVec,
|
|
vtkInformationVector* outInfoVec)
|
|
{
|
|
// If the filter parameters or input have been modified since the
|
|
// last execution then we must execute. This is a shortcut for most
|
|
// filters since all outputs will have the same UpdateTime. This
|
|
// also handles the case in which there are no outputs.
|
|
if(this->PipelineMTime > this->DataTime.GetMTime())
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if(outputPort >= 0)
|
|
{
|
|
// If the output on the port making the request is out-of-date
|
|
// then we must execute.
|
|
vtkInformation* info = outInfoVec->GetInformationObject(outputPort);
|
|
vtkDataObject* data = info->Get(vtkDataObject::DATA_OBJECT());
|
|
if(!data || this->PipelineMTime > data->GetUpdateTime())
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No port is specified. Check all ports.
|
|
for(int i=0; i < this->Algorithm->GetNumberOfOutputPorts(); ++i)
|
|
{
|
|
if(this->NeedToExecuteData(i,inInfoVec,outInfoVec))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We do not need to execute.
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::SetReleaseDataFlag(int port, int n)
|
|
{
|
|
if(!this->OutputPortIndexInRange(port, "set release data flag on"))
|
|
{
|
|
return 0;
|
|
}
|
|
vtkInformation* info = this->GetOutputInformation(port);
|
|
if(this->GetReleaseDataFlag(port) != n)
|
|
{
|
|
info->Set(RELEASE_DATA(), n);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkDemandDrivenPipeline::GetReleaseDataFlag(int port)
|
|
{
|
|
if(!this->OutputPortIndexInRange(port, "get release data flag from"))
|
|
{
|
|
return 0;
|
|
}
|
|
vtkInformation* info = this->GetOutputInformation(port);
|
|
if(!info->Has(RELEASE_DATA()))
|
|
{
|
|
info->Set(RELEASE_DATA(), 0);
|
|
}
|
|
return info->Get(RELEASE_DATA());
|
|
}
|
|
|