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.
 
 
 
 
 
 

656 lines
22 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkContourFilter.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 "vtkContourFilter.h"
#include "vtkCell.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkContourGrid.h"
#include "vtkContourValues.h"
#include "vtkCutter.h"
#include "vtkGarbageCollector.h"
#include "vtkGenericCell.h"
#include "vtkGridSynchronizedTemplates3D.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMergePoints.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkRectilinearGrid.h"
#include "vtkRectilinearSynchronizedTemplates.h"
#include "vtkSimpleScalarTree.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkStructuredGrid.h"
#include "vtkSynchronizedTemplates2D.h"
#include "vtkSynchronizedTemplates3D.h"
#include "vtkTimerLog.h"
#include "vtkUniformGrid.h"
#include "vtkUnstructuredGrid.h"
#include <math.h>
vtkCxxRevisionMacro(vtkContourFilter, "$Revision: 1.125 $");
vtkStandardNewMacro(vtkContourFilter);
vtkCxxSetObjectMacro(vtkContourFilter,ScalarTree,vtkScalarTree);
// Construct object with initial range (0,1) and single contour value
// of 0.0.
vtkContourFilter::vtkContourFilter()
{
this->ContourValues = vtkContourValues::New();
this->ComputeNormals = 1;
this->ComputeGradients = 0;
this->ComputeScalars = 1;
this->Locator = NULL;
this->UseScalarTree = 0;
this->ScalarTree = NULL;
this->SynchronizedTemplates2D = vtkSynchronizedTemplates2D::New();
this->SynchronizedTemplates3D = vtkSynchronizedTemplates3D::New();
this->GridSynchronizedTemplates = vtkGridSynchronizedTemplates3D::New();
this->RectilinearSynchronizedTemplates = vtkRectilinearSynchronizedTemplates::New();
// by default process active point scalars
this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS,
vtkDataSetAttributes::SCALARS);
}
vtkContourFilter::~vtkContourFilter()
{
this->ContourValues->Delete();
if ( this->Locator )
{
this->Locator->UnRegister(this);
this->Locator = NULL;
}
if ( this->ScalarTree )
{
this->ScalarTree->Delete();
this->ScalarTree = 0;
}
this->SynchronizedTemplates2D->Delete();
this->SynchronizedTemplates3D->Delete();
this->GridSynchronizedTemplates->Delete();
this->RectilinearSynchronizedTemplates->Delete();
}
// Overload standard modified time function. If contour values are modified,
// then this object is modified as well.
unsigned long vtkContourFilter::GetMTime()
{
unsigned long mTime=this->Superclass::GetMTime();
unsigned long time;
if (this->ContourValues)
{
time = this->ContourValues->GetMTime();
mTime = ( time > mTime ? time : mTime );
}
if (this->Locator)
{
time = this->Locator->GetMTime();
mTime = ( time > mTime ? time : mTime );
}
return mTime;
}
int vtkContourFilter::RequestUpdateExtent(vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
vtkDataSet *input =
vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
int numContours=this->ContourValues->GetNumberOfContours();
double *values=this->ContourValues->GetValues();
vtkInformation *fInfo =
vtkDataObject::GetActiveFieldInformation(inInfo,
vtkDataObject::FIELD_ASSOCIATION_POINTS,
vtkDataSetAttributes::SCALARS);
int sType = VTK_DOUBLE;
if (fInfo)
{
sType = fInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE());
}
// handle 2D images
int i;
if (vtkImageData::SafeDownCast(input) && sType != VTK_BIT &&
!vtkUniformGrid::SafeDownCast(input))
{
int dim = 3;
int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
if (uExt[0] == uExt[1])
{
--dim;
}
if (uExt[2] == uExt[3])
{
--dim;
}
if (uExt[4] == uExt[5])
{
--dim;
}
if ( dim == 2 )
{
this->SynchronizedTemplates2D->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->SynchronizedTemplates2D->SetValue(i,values[i]);
}
this->SynchronizedTemplates2D->SetComputeScalars(this->ComputeScalars);
return this->SynchronizedTemplates2D->
ProcessRequest(request,inputVector,outputVector);
}
else if (dim == 3)
{
this->SynchronizedTemplates3D->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->SynchronizedTemplates3D->SetValue(i,values[i]);
}
this->SynchronizedTemplates3D->SetComputeNormals(this->ComputeNormals);
this->SynchronizedTemplates3D->SetComputeGradients(this->ComputeGradients);
this->SynchronizedTemplates3D->SetComputeScalars(this->ComputeScalars);
return this->SynchronizedTemplates3D->
ProcessRequest(request,inputVector,outputVector);
}
} //if image data
// handle 3D RGrids
if (vtkRectilinearGrid::SafeDownCast(input) && sType != VTK_BIT)
{
int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
// if 3D
if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5])
{
this->RectilinearSynchronizedTemplates->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->RectilinearSynchronizedTemplates->SetValue(i,values[i]);
}
this->RectilinearSynchronizedTemplates->SetComputeNormals(this->ComputeNormals);
this->RectilinearSynchronizedTemplates->SetComputeGradients(this->ComputeGradients);
this->RectilinearSynchronizedTemplates->SetComputeScalars(this->ComputeScalars);
return this->RectilinearSynchronizedTemplates->
ProcessRequest(request,inputVector,outputVector);
}
} //if 3D RGrid
// handle 3D SGrids
if (vtkStructuredGrid::SafeDownCast(input) && sType != VTK_BIT)
{
int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
// if 3D
if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5])
{
this->GridSynchronizedTemplates->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->GridSynchronizedTemplates->SetValue(i,values[i]);
}
this->GridSynchronizedTemplates->SetComputeNormals(this->ComputeNormals);
this->GridSynchronizedTemplates->SetComputeGradients(this->ComputeGradients);
this->GridSynchronizedTemplates->SetComputeScalars(this->ComputeScalars);
return this->GridSynchronizedTemplates->
ProcessRequest(request,inputVector,outputVector);
}
} //if 3D SGrid
inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
return 1;
}
// General contouring filter. Handles arbitrary input.
//
int vtkContourFilter::RequestData(
vtkInformation* request,
vtkInformationVector** inputVector,
vtkInformationVector* outputVector)
{
// get the input
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
vtkDataSet *input = vtkDataSet::SafeDownCast(
inInfo->Get(vtkDataObject::DATA_OBJECT()));
if (!input)
{
return 0;
}
// get the contours
int numContours=this->ContourValues->GetNumberOfContours();
double *values=this->ContourValues->GetValues();
int i;
// is there data to process?
if (!this->GetInputArrayToProcess(0, inputVector))
{
return 1;
}
int sType = this->GetInputArrayToProcess(0, inputVector)->GetDataType();
// handle 2D images
if (vtkImageData::SafeDownCast(input) && sType != VTK_BIT &&
!vtkUniformGrid::SafeDownCast(input))
{
int dim = 3;
int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
if (uExt[0] == uExt[1])
{
--dim;
}
if (uExt[2] == uExt[3])
{
--dim;
}
if (uExt[4] == uExt[5])
{
--dim;
}
if ( dim == 2 )
{
this->SynchronizedTemplates2D->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->SynchronizedTemplates2D->SetValue(i,values[i]);
}
this->SynchronizedTemplates2D->
SetInputArrayToProcess(0,this->GetInputArrayInformation(0));
return
this->SynchronizedTemplates2D->ProcessRequest(request,inputVector,outputVector);
}
else if ( dim == 3 )
{
this->SynchronizedTemplates3D->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->SynchronizedTemplates3D->SetValue(i,values[i]);
}
this->SynchronizedTemplates3D->SetComputeNormals(this->ComputeNormals);
this->SynchronizedTemplates3D->SetComputeGradients(this->ComputeGradients);
this->SynchronizedTemplates3D->SetComputeScalars(this->ComputeScalars);
this->SynchronizedTemplates3D->
SetInputArrayToProcess(0,this->GetInputArrayInformation(0));
return
this->SynchronizedTemplates3D->ProcessRequest(request,inputVector,outputVector);
}
} //if image data
// handle 3D RGrids
if (vtkRectilinearGrid::SafeDownCast(input) && sType != VTK_BIT)
{
int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
// if 3D
if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5])
{
this->RectilinearSynchronizedTemplates->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->RectilinearSynchronizedTemplates->SetValue(i,values[i]);
}
this->RectilinearSynchronizedTemplates->SetComputeNormals(this->ComputeNormals);
this->RectilinearSynchronizedTemplates->SetComputeGradients(this->ComputeGradients);
this->RectilinearSynchronizedTemplates->SetComputeScalars(this->ComputeScalars);
this->RectilinearSynchronizedTemplates->
SetInputArrayToProcess(0,this->GetInputArrayInformation(0));
return this->RectilinearSynchronizedTemplates->
ProcessRequest(request,inputVector,outputVector);
}
} // if 3D Rgrid
// handle 3D SGrids
if (vtkStructuredGrid::SafeDownCast(input) && sType != VTK_BIT)
{
int *uExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
// if 3D
if (uExt[0] < uExt[1] && uExt[2] < uExt[3] && uExt[4] < uExt[5])
{
this->GridSynchronizedTemplates->SetNumberOfContours(numContours);
for (i=0; i < numContours; i++)
{
this->GridSynchronizedTemplates->SetValue(i,values[i]);
}
this->GridSynchronizedTemplates->SetComputeNormals(this->ComputeNormals);
this->GridSynchronizedTemplates->SetComputeGradients(this->ComputeGradients);
this->GridSynchronizedTemplates->SetComputeScalars(this->ComputeScalars);
this->GridSynchronizedTemplates->
SetInputArrayToProcess(0,this->GetInputArrayInformation(0));
return this->GridSynchronizedTemplates->
ProcessRequest(request,inputVector,outputVector);
}
} //if 3D SGrid
vtkIdType cellId;
int abortExecute=0;
vtkIdList *cellPts;
vtkDataArray *inScalars;
vtkCellArray *newVerts, *newLines, *newPolys;
vtkPoints *newPts;
vtkIdType numCells, estimatedSize;
vtkDataArray *cellScalars;
vtkInformation* info = outputVector->GetInformationObject(0);
vtkPolyData *output = vtkPolyData::SafeDownCast(
info->Get(vtkDataObject::DATA_OBJECT()));
if (!output) {return 0;}
vtkPointData *inPd=input->GetPointData(), *outPd=output->GetPointData();
vtkCellData *inCd=input->GetCellData(), *outCd=output->GetCellData();
vtkDebugMacro(<< "Executing contour filter");
if (input->GetDataObjectType() == VTK_UNSTRUCTURED_GRID)
{
vtkDebugMacro(<< "Processing unstructured grid");
vtkContourGrid *cgrid;
cgrid = vtkContourGrid::New();
cgrid->SetInput((vtkUnstructuredGrid *)input);
for (i = 0; i < numContours; i++)
{
cgrid->SetValue(i, values[i]);
}
cgrid->GetOutput()->SetUpdateExtent(output->GetUpdatePiece(),
output->GetUpdateNumberOfPieces(),
output->GetUpdateGhostLevel());
cgrid->SetInputArrayToProcess(0,this->GetInputArrayInformation(0));
cgrid->Update();
output->ShallowCopy(cgrid->GetOutput());
cgrid->SetInput(0);
cgrid->Delete();
} //if type VTK_UNSTRUCTURED_GRID
else
{
numCells = input->GetNumberOfCells();
inScalars = this->GetInputArrayToProcess(0,inputVector);
if ( ! inScalars || numCells < 1 )
{
vtkDebugMacro(<<"No data to contour");
return 1;
}
// Create objects to hold output of contour operation. First estimate
// allocation size.
//
estimatedSize = (vtkIdType) pow ((double) numCells, .75);
estimatedSize *= numContours;
estimatedSize = estimatedSize / 1024 * 1024; //multiple of 1024
if (estimatedSize < 1024)
{
estimatedSize = 1024;
}
newPts = vtkPoints::New();
newPts->Allocate(estimatedSize,estimatedSize);
newVerts = vtkCellArray::New();
newVerts->Allocate(estimatedSize,estimatedSize);
newLines = vtkCellArray::New();
newLines->Allocate(estimatedSize,estimatedSize);
newPolys = vtkCellArray::New();
newPolys->Allocate(estimatedSize,estimatedSize);
cellScalars = inScalars->NewInstance();
cellScalars->SetNumberOfComponents(inScalars->GetNumberOfComponents());
cellScalars->Allocate(cellScalars->GetNumberOfComponents()*VTK_CELL_SIZE);
// locator used to merge potentially duplicate points
if ( this->Locator == NULL )
{
this->CreateDefaultLocator();
}
this->Locator->InitPointInsertion (newPts,
input->GetBounds(),estimatedSize);
// interpolate data along edge
// if we did not ask for scalars to be computed, don't copy them
if (!this->ComputeScalars)
{
outPd->CopyScalarsOff();
}
outPd->InterpolateAllocate(inPd,estimatedSize,estimatedSize);
outCd->CopyAllocate(inCd,estimatedSize,estimatedSize);
// If enabled, build a scalar tree to accelerate search
//
if ( !this->UseScalarTree )
{
vtkGenericCell *cell = vtkGenericCell::New();
// Three passes over the cells to process lower dimensional cells first.
// For poly data output cells need to be added in the order:
// verts, lines and then polys, or cell data gets mixed up.
// A better solution is to have an unstructured grid output.
// I create a table that maps cell type to cell dimensionality,
// because I need a fast way to get cell dimensionality.
// This assumes GetCell is slow and GetCellType is fast.
// I do not like hard coding a list of cell types here,
// but I do not want to add GetCellDimension(vtkIdType cellId)
// to the vtkDataSet API. Since I anticipate that the output
// will change to vtkUnstructuredGrid. This temporary solution
// is acceptable.
//
int cellType;
unsigned char cellTypeDimensions[VTK_NUMBER_OF_CELL_TYPES];
vtkCutter::GetCellTypeDimensions(cellTypeDimensions);
int dimensionality;
// We skip 0d cells (points), because they cannot be cut (generate no data).
for (dimensionality = 1; dimensionality <= 3; ++dimensionality)
{
// Loop over all cells; get scalar values for all cell points
// and process each cell.
//
for (cellId=0; cellId < numCells && !abortExecute; cellId++)
{
// I assume that "GetCellType" is fast.
cellType = input->GetCellType(cellId);
if (cellType >= VTK_NUMBER_OF_CELL_TYPES)
{ // Protect against new cell types added.
vtkErrorMacro("Unknown cell type " << cellType);
continue;
}
if (cellTypeDimensions[cellType] != dimensionality)
{
continue;
}
input->GetCell(cellId,cell);
cellPts = cell->GetPointIds();
inScalars->GetTuples(cellPts,cellScalars);
if (dimensionality == 3 && ! (cellId % 5000) )
{
vtkDebugMacro(<<"Contouring #" << cellId);
this->UpdateProgress ((double)cellId/numCells);
abortExecute = this->GetAbortExecute();
}
for (i=0; i < numContours; i++)
{
cell->Contour(values[i], cellScalars, this->Locator,
newVerts, newLines, newPolys, inPd, outPd,
inCd, cellId, outCd);
} // for all contour values
} // for all cells
} // for all dimensions
cell->Delete();
} //if using scalar tree
else
{
vtkCell *cell;
if ( this->ScalarTree == NULL )
{
this->ScalarTree = vtkSimpleScalarTree::New();
}
this->ScalarTree->SetDataSet(input);
// Note: This will have problems when input contains 2D and 3D cells.
// CellData will get scrabled because of the implicit ordering of
// verts, lines and polys in vtkPolyData. The solution
// is to convert this filter to create unstructured grid.
//
// Loop over all contour values. Then for each contour value,
// loop over all cells.
//
for (i=0; i < numContours; i++)
{
for ( this->ScalarTree->InitTraversal(values[i]);
(cell=this->ScalarTree->GetNextCell(cellId,cellPts,cellScalars)) != NULL; )
{
cell->Contour(values[i], cellScalars, this->Locator,
newVerts, newLines, newPolys, inPd, outPd,
inCd, cellId, outCd);
} //for all cells
} //for all contour values
} //using scalar tree
vtkDebugMacro(<<"Created: "
<< newPts->GetNumberOfPoints() << " points, "
<< newVerts->GetNumberOfCells() << " verts, "
<< newLines->GetNumberOfCells() << " lines, "
<< newPolys->GetNumberOfCells() << " triangles");
// Update ourselves. Because we don't know up front how many verts, lines,
// polys we've created, take care to reclaim memory.
//
output->SetPoints(newPts);
newPts->Delete();
cellScalars->Delete();
if (newVerts->GetNumberOfCells())
{
output->SetVerts(newVerts);
}
newVerts->Delete();
if (newLines->GetNumberOfCells())
{
output->SetLines(newLines);
}
newLines->Delete();
if (newPolys->GetNumberOfCells())
{
output->SetPolys(newPolys);
}
newPolys->Delete();
this->Locator->Initialize();//releases leftover memory
output->Squeeze();
} //else if not vtkUnstructuredGrid
return 1;
}
// Specify a spatial locator for merging points. By default,
// an instance of vtkMergePoints is used.
void vtkContourFilter::SetLocator(vtkPointLocator *locator)
{
if ( this->Locator == locator )
{
return;
}
if ( this->Locator )
{
this->Locator->UnRegister(this);
this->Locator = NULL;
}
if ( locator )
{
locator->Register(this);
}
this->Locator = locator;
this->Modified();
}
void vtkContourFilter::CreateDefaultLocator()
{
if ( this->Locator == NULL )
{
this->Locator = vtkMergePoints::New();
this->Locator->Register(this);
this->Locator->Delete();
}
}
void vtkContourFilter::SetArrayComponent( int comp )
{
this->SynchronizedTemplates2D->SetArrayComponent( comp );
this->SynchronizedTemplates3D->SetArrayComponent( comp );
this->RectilinearSynchronizedTemplates->SetArrayComponent( comp );
}
int vtkContourFilter::GetArrayComponent()
{
return( this->SynchronizedTemplates2D->GetArrayComponent() );
}
int vtkContourFilter::FillInputPortInformation(int, vtkInformation *info)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
return 1;
}
void vtkContourFilter::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Compute Gradients: "
<< (this->ComputeGradients ? "On\n" : "Off\n");
os << indent << "Compute Normals: "
<< (this->ComputeNormals ? "On\n" : "Off\n");
os << indent << "Compute Scalars: "
<< (this->ComputeScalars ? "On\n" : "Off\n");
this->ContourValues->PrintSelf(os,indent.GetNextIndent());
os << indent << "Use Scalar Tree: "
<< (this->UseScalarTree ? "On\n" : "Off\n");
if ( this->ScalarTree )
{
os << indent << "Scalar Tree: " << this->ScalarTree << "\n";
}
else
{
os << indent << "Scalar Tree: (none)\n";
}
if ( this->Locator )
{
os << indent << "Locator: " << this->Locator << "\n";
}
else
{
os << indent << "Locator: (none)\n";
}
}
//----------------------------------------------------------------------------
void vtkContourFilter::ReportReferences(vtkGarbageCollector* collector)
{
this->Superclass::ReportReferences(collector);
// These filters share our input and are therefore involved in a
// reference loop.
vtkGarbageCollectorReport(collector, this->ScalarTree, "ScalarTree");
}