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.
 
 
 
 
 
 

1617 lines
49 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkDataSetSurfaceFilter.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 "vtkDataSetSurfaceFilter.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkGenericCell.h"
#include "vtkHexahedron.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMergePoints.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPyramid.h"
#include "vtkRectilinearGrid.h"
#include "vtkStructuredGrid.h"
#include "vtkUniformGrid.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkStructuredGridGeometryFilter.h"
#include "vtkStructuredPoints.h"
#include "vtkTetra.h"
#include "vtkUnsignedCharArray.h"
#include "vtkUnstructuredGrid.h"
#include "vtkVoxel.h"
#include "vtkWedge.h"
// Helper structure for hashing faces.
struct vtkFastGeomQuadStruct
{
vtkIdType p0;
vtkIdType p1;
vtkIdType p2;
vtkIdType p3;
vtkIdType p4;
vtkIdType p5;
vtkIdType SourceId;
struct vtkFastGeomQuadStruct *Next;
};
vtkCxxRevisionMacro(vtkDataSetSurfaceFilter, "$Revision: 1.49 $");
vtkStandardNewMacro(vtkDataSetSurfaceFilter);
//----------------------------------------------------------------------------
vtkDataSetSurfaceFilter::vtkDataSetSurfaceFilter()
{
this->QuadHash = NULL;
this->PointMap = NULL;
this->QuadHashLength = 0;
this->UseStrips = 0;
this->NumberOfNewCells = 0;
// Quad allocation stuff.
this->FastGeomQuadArrayLength = 0;
this->NumberOfFastGeomQuadArrays = 0;
this->FastGeomQuadArrays = NULL;
this->NextArrayIndex = 0;
this->NextQuadIndex = 0;
this->PieceInvariant = 0;
}
//----------------------------------------------------------------------------
vtkDataSetSurfaceFilter::~vtkDataSetSurfaceFilter()
{
if (this->QuadHash)
{
this->DeleteQuadHash();
}
}
//----------------------------------------------------------------------------
int vtkDataSetSurfaceFilter::RequestData(
vtkInformation *vtkNotUsed(request),
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
// get the info objects
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
vtkInformation *outInfo = outputVector->GetInformationObject(0);
// get the input and ouptut
vtkDataSet *input = vtkDataSet::SafeDownCast(
inInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkPolyData *output = vtkPolyData::SafeDownCast(
outInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkIdType numCells = input->GetNumberOfCells();
int *ext;
if (input->CheckAttributes())
{
return 1;
}
if (numCells == 0)
{
return 1;
}
switch (input->GetDataObjectType())
{
case VTK_UNSTRUCTURED_GRID:
{
if (!this->UnstructuredGridExecute(input, output))
{
return 1;
}
output->CheckAttributes();
return 1;
}
case VTK_RECTILINEAR_GRID:
{
vtkRectilinearGrid *grid = vtkRectilinearGrid::SafeDownCast(input);
ext = grid->GetExtent();
return this->StructuredExecute(grid, output, ext, inInfo);
}
case VTK_STRUCTURED_GRID:
{
vtkStructuredGrid *grid = vtkStructuredGrid::SafeDownCast(input);
ext = grid->GetExtent();
return this->StructuredExecute(grid, output, ext, inInfo);
}
case VTK_UNIFORM_GRID:
{
vtkUniformGrid *grid = vtkUniformGrid::SafeDownCast(input);
ext = grid->GetExtent();
return this->StructuredExecute(grid, output, ext, inInfo);
}
case VTK_STRUCTURED_POINTS:
{
vtkStructuredPoints *image = vtkStructuredPoints::SafeDownCast(input);
ext = image->GetExtent();
return this->StructuredExecute(image, output, ext, inInfo);
}
case VTK_IMAGE_DATA:
{
vtkImageData *image = vtkImageData::SafeDownCast(input);
ext = image->GetExtent();
return this->StructuredExecute(image, output, ext, inInfo);
}
case VTK_POLY_DATA:
{
vtkPolyData *inPd = vtkPolyData::SafeDownCast(input);
output->ShallowCopy(inPd);
return 1;
}
default:
return this->DataSetExecute(input, output);
}
}
//----------------------------------------------------------------------------
// It is a pain that structured data sets do not share a common super class
// other than data set, and data set does not allow access to extent!
int vtkDataSetSurfaceFilter::StructuredExecute(vtkDataSet *input,
vtkPolyData *output,
int *ext,
vtkInformation *inInfo)
{
int *wholeExt;
vtkIdType numPoints, cellArraySize;
vtkCellArray *outStrips;
vtkCellArray *outPolys;
vtkPoints *outPoints;
// Cell Array Size is a pretty good estimate.
// Does not consider direction of strip.
wholeExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
// Lets figure out how many cells and points we are going to have.
// It may be overkill comptuing the exact amount, but we can do it, so ...
cellArraySize = numPoints = 0;
// xMin face
if (ext[0] == wholeExt[0] && ext[2] != ext[3] && ext[4] != ext[5] && ext[0] != ext[1])
{
cellArraySize += 2*(ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
numPoints += (ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
}
// xMax face
if (ext[1] == wholeExt[1] && ext[2] != ext[3] && ext[4] != ext[5])
{
cellArraySize += 2*(ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
numPoints += (ext[3]-ext[2]+1)*(ext[5]-ext[4]+1);
}
// yMin face
if (ext[2] == wholeExt[2] && ext[0] != ext[1] && ext[4] != ext[5] && ext[2] != ext[3])
{
cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
numPoints += (ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
}
// yMax face
if (ext[3] == wholeExt[3] && ext[0] != ext[1] && ext[4] != ext[5])
{
cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
numPoints += (ext[1]-ext[0]+1)*(ext[5]-ext[4]+1);
}
// zMin face
if (ext[4] == wholeExt[4] && ext[0] != ext[1] && ext[2] != ext[3] && ext[4] != ext[5])
{
cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
numPoints += (ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
}
// zMax face
if (ext[5] == wholeExt[5] && ext[0] != ext[1] && ext[2] != ext[3])
{
cellArraySize += 2*(ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
numPoints += (ext[1]-ext[0]+1)*(ext[3]-ext[2]+1);
}
if (this->UseStrips)
{
outStrips = vtkCellArray::New();
outStrips->Allocate(cellArraySize);
output->SetStrips(outStrips);
outStrips->Delete();
}
else
{
outPolys = vtkCellArray::New();
outPolys->Allocate(cellArraySize);
output->SetPolys(outPolys);
outPolys->Delete();
}
outPoints = vtkPoints::New();
outPoints->Allocate(numPoints);
output->SetPoints(outPoints);
outPoints->Delete();
// Allocate attributes for copying.
output->GetPointData()->CopyAllocate(input->GetPointData());
output->GetCellData()->CopyAllocate(input->GetCellData());
if (this->UseStrips)
{
// xMin face
this->ExecuteFaceStrips(input, output, 0, ext, 0,1,2, inInfo);
// xMax face
this->ExecuteFaceStrips(input, output, 1, ext, 0,2,1, inInfo);
// yMin face
this->ExecuteFaceStrips(input, output, 0, ext, 1,2,0, inInfo);
// yMax face
this->ExecuteFaceStrips(input, output, 1, ext, 1,0,2, inInfo);
// zMin face
this->ExecuteFaceStrips(input, output, 0, ext, 2,0,1, inInfo);
// zMax face
this->ExecuteFaceStrips(input, output, 1, ext, 2,1,0, inInfo);
}
else
{
// xMin face
this->ExecuteFaceQuads(input, output, 0, ext, 0,1,2, inInfo);
// xMax face
this->ExecuteFaceQuads(input, output, 1, ext, 0,2,1, inInfo);
// yMin face
this->ExecuteFaceQuads(input, output, 0, ext, 1,2,0, inInfo);
// yMax face
this->ExecuteFaceQuads(input, output, 1, ext, 1,0,2, inInfo);
// zMin face
this->ExecuteFaceQuads(input, output, 0, ext, 2,0,1, inInfo);
// zMax face
this->ExecuteFaceQuads(input, output, 1, ext, 2,1,0, inInfo);
}
output->Squeeze();
return 1;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::ExecuteFaceStrips(vtkDataSet *input,
vtkPolyData *output,
int maxFlag, int *ext,
int aAxis, int bAxis, int cAxis,
vtkInformation *inInfo)
{
vtkPoints *outPts;
vtkCellArray *outStrips;
vtkPointData *inPD, *outPD;
int *wholeExt;
int pInc[3];
int qInc[3];
int cOutInc;
double pt[3];
vtkIdType inStartPtId;
vtkIdType outStartPtId;
vtkIdType outPtId;
vtkIdType inId, outId;
int ib, ic;
int aA2, bA2, cA2;
int rotatedFlag;
vtkIdType *stripArray;
vtkIdType stripArrayIdx;
outPts = output->GetPoints();
outPD = output->GetPointData();
inPD = input->GetPointData();
wholeExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
pInc[0] = 1;
pInc[1] = (ext[1]-ext[0]+1);
pInc[2] = (ext[3]-ext[2]+1) * pInc[1];
// quad increments (cell incraments, but cInc could be confused with c axis).
qInc[0] = 1;
qInc[1] = ext[1]-ext[0];
qInc[2] = (ext[3]-ext[2]) * qInc[1];
// Tempoprary variables to avoid many multiplications.
aA2 = aAxis * 2;
bA2 = bAxis * 2;
cA2 = cAxis * 2;
// We might as well put the test for this face here.
if (ext[bA2] == ext[bA2+1] || ext[cA2] == ext[cA2+1])
{
return;
}
if (maxFlag)
{ // max faces have a slightly different condition to avoid coincident faces.
if (ext[aA2] == ext[aA2+1] || ext[aA2+1] < wholeExt[aA2+1])
{
return;
}
}
else
{
if (ext[aA2] > wholeExt[aA2])
{
return;
}
}
// Lets rotate the image to make b the longest axis.
// This will make the tri strips longer.
rotatedFlag = 0;
if (ext[bA2+1]-ext[bA2] < ext[cA2+1]-ext[cA2])
{
int tmp;
rotatedFlag = 1;
tmp = cAxis;
cAxis = bAxis;
bAxis = tmp;
bA2 = bAxis * 2;
cA2 = cAxis * 2;
}
// Assuming no ghost cells ...
inStartPtId = 0;
if (maxFlag)
{
inStartPtId = pInc[aAxis]*(ext[aA2+1]-ext[aA2]);
}
outStartPtId = outPts->GetNumberOfPoints();
// Make the points for this face.
for (ic = ext[cA2]; ic <= ext[cA2+1]; ++ic)
{
for (ib = ext[bA2]; ib <= ext[bA2+1]; ++ib)
{
inId = inStartPtId + (ib-ext[bA2])*pInc[bAxis]
+ (ic-ext[cA2])*pInc[cAxis];
input->GetPoint(inId, pt);
outId = outPts->InsertNextPoint(pt);
// Copy point data.
outPD->CopyData(inPD,inId,outId);
}
}
// Do the cells.
cOutInc = ext[bA2+1] - ext[bA2] + 1;
// Tri Strips (no cell data ...).
// Allocate the temporary array user to create the tri strips.
stripArray = new vtkIdType[2*(ext[bA2+1]-ext[bA2]+1)];
// Make the cells for this face.
outStrips = output->GetStrips();
for (ic = ext[cA2]; ic < ext[cA2+1]; ++ic)
{
// Fill in the array describing the strips.
stripArrayIdx = 0;
outPtId = outStartPtId + (ic-ext[cA2])*cOutInc;
if (rotatedFlag)
{
for (ib = ext[bA2]; ib <= ext[bA2+1]; ++ib)
{
stripArray[stripArrayIdx++] = outPtId+cOutInc;
stripArray[stripArrayIdx++] = outPtId;
++outPtId;
}
}
else
{ // Faster to justto dupicate the inner most loop.
for (ib = ext[bA2]; ib <= ext[bA2+1]; ++ib)
{
stripArray[stripArrayIdx++] = outPtId;
stripArray[stripArrayIdx++] = outPtId+cOutInc;
++outPtId;
}
}
outStrips->InsertNextCell(stripArrayIdx, stripArray);
}
delete [] stripArray;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::ExecuteFaceQuads(vtkDataSet *input,
vtkPolyData *output,
int maxFlag, int *ext,
int aAxis, int bAxis, int cAxis,
vtkInformation *inInfo)
{
vtkPoints *outPts;
vtkCellArray *outPolys;
vtkPointData *inPD, *outPD;
vtkCellData *inCD, *outCD;
int *wholeExt;
int pInc[3];
int qInc[3];
int cOutInc;
double pt[3];
vtkIdType inStartPtId;
vtkIdType inStartCellId;
vtkIdType outStartPtId;
vtkIdType outPtId;
vtkIdType inId, outId;
int ib, ic;
int aA2, bA2, cA2;
outPts = output->GetPoints();
outPD = output->GetPointData();
inPD = input->GetPointData();
outCD = output->GetCellData();
inCD = input->GetCellData();
wholeExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
pInc[0] = 1;
pInc[1] = (ext[1]-ext[0]+1);
pInc[2] = (ext[3]-ext[2]+1) * pInc[1];
// quad increments (cell incraments, but cInc could be confused with c axis).
qInc[0] = 1;
qInc[1] = ext[1]-ext[0];
// The conditions are for when we have one or more degenerate axes (2d or 1d cells).
if (qInc[1] == 0)
{
qInc[1] = 1;
}
qInc[2] = (ext[3]-ext[2]) * qInc[1];
if (qInc[2] == 0)
{
qInc[2] = qInc[1];
}
// Temporary variables to avoid many multiplications.
aA2 = aAxis * 2;
bA2 = bAxis * 2;
cA2 = cAxis * 2;
// We might as well put the test for this face here.
if (ext[bA2] == ext[bA2+1] || ext[cA2] == ext[cA2+1])
{
return;
}
if (maxFlag)
{
if (ext[aA2+1] < wholeExt[aA2+1])
{
return;
}
}
else
{ // min faces have a slightly different condition to avoid coincident faces.
if (ext[aA2] == ext[aA2+1] || ext[aA2] > wholeExt[aA2])
{
return;
}
}
// Assuming no ghost cells ...
inStartPtId = inStartCellId = 0;
// I put this confusing conditional to fix a regression test.
// If we are creating a maximum face, then we indeed have to offset the input cell Ids.
// However, vtkGeometryFilter created a 2d image as a max face, but the cells are copied
// as a min face (no offset). Hence maxFlag = 1 and there should be no offset.
if (maxFlag && ext[aA2] < ext[1+aA2])
{
inStartPtId = pInc[aAxis]*(ext[aA2+1]-ext[aA2]);
inStartCellId = qInc[aAxis]*(ext[aA2+1]-ext[aA2]-1);
}
outStartPtId = outPts->GetNumberOfPoints();
// Make the points for this face.
for (ic = ext[cA2]; ic <= ext[cA2+1]; ++ic)
{
for (ib = ext[bA2]; ib <= ext[bA2+1]; ++ib)
{
inId = inStartPtId + (ib-ext[bA2])*pInc[bAxis]
+ (ic-ext[cA2])*pInc[cAxis];
input->GetPoint(inId, pt);
outId = outPts->InsertNextPoint(pt);
// Copy point data.
outPD->CopyData(inPD,inId,outId);
}
}
// Do the cells.
cOutInc = ext[bA2+1] - ext[bA2] + 1;
outPolys = output->GetPolys();
// Old method for creating quads (needed for cell data.).
for (ic = ext[cA2]; ic < ext[cA2+1]; ++ic)
{
for (ib = ext[bA2]; ib < ext[bA2+1]; ++ib)
{
outPtId = outStartPtId + (ib-ext[bA2]) + (ic-ext[cA2])*cOutInc;
inId = inStartCellId + (ib-ext[bA2])*qInc[bAxis] + (ic-ext[cA2])*qInc[cAxis];
outId = outPolys->InsertNextCell(4);
outPolys->InsertCellPoint(outPtId);
outPolys->InsertCellPoint(outPtId+cOutInc);
outPolys->InsertCellPoint(outPtId+cOutInc+1);
outPolys->InsertCellPoint(outPtId+1);
// Copy cell data.
outCD->CopyData(inCD,inId,outId);
}
}
}
//----------------------------------------------------------------------------
int vtkDataSetSurfaceFilter::DataSetExecute(vtkDataSet *input,
vtkPolyData *output)
{
vtkIdType cellId, newCellId;
int i, j;
vtkIdType numPts=input->GetNumberOfPoints();
vtkIdType numCells=input->GetNumberOfCells();
vtkGenericCell *cell;
vtkCell *face;
double x[3];
vtkIdList *cellIds;
vtkIdList *pts;
vtkPoints *newPts;
vtkIdType ptId, pt;
int npts;
vtkPointData *pd = input->GetPointData();
vtkCellData *cd = input->GetCellData();
vtkPointData *outputPD = output->GetPointData();
vtkCellData *outputCD = output->GetCellData();
if (numCells == 0)
{
return 1;
}
cellIds = vtkIdList::New();
pts = vtkIdList::New();
vtkDebugMacro(<<"Executing geometry filter");
cell = vtkGenericCell::New();
// Allocate
//
newPts = vtkPoints::New();
newPts->Allocate(numPts,numPts/2);
output->Allocate(4*numCells,numCells/2);
outputPD->CopyAllocate(pd,numPts,numPts/2);
outputCD->CopyAllocate(cd,numCells,numCells/2);
// Traverse cells to extract geometry
//
int abort=0;
vtkIdType progressInterval = numCells/20 + 1;
for(cellId=0; cellId < numCells && !abort; cellId++)
{
//Progress and abort method support
if ( !(cellId % progressInterval) )
{
vtkDebugMacro(<<"Process cell #" << cellId);
this->UpdateProgress ((double)cellId/numCells);
abort = this->GetAbortExecute();
}
input->GetCell(cellId,cell);
switch (cell->GetCellDimension())
{
// create new points and then cell
case 0: case 1: case 2:
npts = cell->GetNumberOfPoints();
pts->Reset();
for ( i=0; i < npts; i++)
{
ptId = cell->GetPointId(i);
input->GetPoint(ptId, x);
pt = newPts->InsertNextPoint(x);
outputPD->CopyData(pd,ptId,pt);
pts->InsertId(i,pt);
}
newCellId = output->InsertNextCell(cell->GetCellType(), pts);
outputCD->CopyData(cd,cellId,newCellId);
break;
case 3:
for (j=0; j < cell->GetNumberOfFaces(); j++)
{
face = cell->GetFace(j);
input->GetCellNeighbors(cellId, face->PointIds, cellIds);
if ( cellIds->GetNumberOfIds() <= 0)
{
npts = face->GetNumberOfPoints();
pts->Reset();
for ( i=0; i < npts; i++)
{
ptId = face->GetPointId(i);
input->GetPoint(ptId, x);
pt = newPts->InsertNextPoint(x);
outputPD->CopyData(pd,ptId,pt);
pts->InsertId(i,pt);
}
newCellId = output->InsertNextCell(face->GetCellType(), pts);
outputCD->CopyData(cd,cellId,newCellId);
}
}
break;
} //switch
} //for all cells
vtkDebugMacro(<<"Extracted " << newPts->GetNumberOfPoints() << " points,"
<< output->GetNumberOfCells() << " cells.");
// Update ourselves and release memory
//
cell->Delete();
output->SetPoints(newPts);
newPts->Delete();
//free storage
output->Squeeze();
cellIds->Delete();
pts->Delete();
return 1;
}
//----------------------------------------------------------------------------
int vtkDataSetSurfaceFilter::RequestUpdateExtent(
vtkInformation *vtkNotUsed(request),
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
// get the info objects
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
vtkInformation *outInfo = outputVector->GetInformationObject(0);
int piece, numPieces, ghostLevels;
piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER());
numPieces =
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES());
ghostLevels =
outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS());
if (numPieces > 1 && this->PieceInvariant)
{
// The special execute for structured data handle boundaries internally.
// PolyData does not need any ghost levels.
vtkDataObject* dobj = inInfo->Get(vtkDataObject::DATA_OBJECT());
if (dobj && !strcmp(dobj->GetClassName(), "vtkUnstructuredGrid"))
{ // Processing does nothing fo ghost levels yet so ...
// Be careful to set output ghost level value one less than default
// when they are implemented. I had trouble with multiple executes.
++ghostLevels;
}
}
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), piece);
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(),
numPieces);
inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(),
ghostLevels);
inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1);
return 1;
}
//----------------------------------------------------------------------------
int vtkDataSetSurfaceFilter::FillInputPortInformation(int, vtkInformation *info)
{
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
return 1;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
if (this->UseStrips)
{
os << indent << "UseStripsOn\n";
}
else
{
os << indent << "UseStripsOff\n";
}
os << indent << "PieceInvariant: " << this->PieceInvariant << endl;
}
//========================================================================
// Tris are now degenerate quads so we only need one hash table.
// We might want to change the method names from QuadHash to just Hash.
//----------------------------------------------------------------------------
int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput,
vtkPolyData *output)
{
vtkCellArray *newVerts;
vtkCellArray *newLines;
vtkCellArray *newPolys;
vtkPoints *newPts;
vtkIdType *ids;
int progressCount;
vtkIdType cellId;
int i, j;
vtkIdType *cellPointer;
int cellType;
vtkUnstructuredGrid *input = vtkUnstructuredGrid::SafeDownCast(dataSetInput);
vtkIdType numPts=input->GetNumberOfPoints();
vtkIdType numCells=input->GetNumberOfCells();
vtkGenericCell *cell;
int numFacePts, numCellPts;
vtkIdType inPtId, outPtId;
vtkPointData *inputPD = input->GetPointData();
vtkCellData *inputCD = input->GetCellData();
vtkCellData *cd = input->GetCellData();
vtkPointData *outputPD = output->GetPointData();
vtkCellData *outputCD = output->GetCellData();
vtkIdType outPts[6];
vtkFastGeomQuad *q;
unsigned char* cellTypes = input->GetCellTypesArray()->GetPointer(0);
// These are for the default case/
vtkIdList *pts;
vtkPoints *coords;
vtkCell *face;
int flag2D = 0;
pts = vtkIdList::New();
coords = vtkPoints::New();
cell = vtkGenericCell::New();
this->NumberOfNewCells = 0;
this->InitializeQuadHash(numPts);
// Allocate
//
newPts = vtkPoints::New();
newPts->Allocate(numPts);
newPolys = vtkCellArray::New();
newPolys->Allocate(4*numCells,numCells/2);
newVerts = vtkCellArray::New();
newLines = vtkCellArray::New();
outputPD->CopyAllocate(inputPD, numPts, numPts/2);
outputCD->CopyAllocate(inputCD, numCells, numCells/2);
// First insert all points. Points have to come first in poly data.
cellPointer = input->GetCells()->GetPointer();
for(cellId=0; cellId < numCells; cellId++)
{
// Direct access to cells.
cellType = cellTypes[cellId];
numCellPts = cellPointer[0];
ids = cellPointer+1;
// Move to the next cell.
cellPointer += (1 + *cellPointer);
// A couple of common cases to see if things go faster.
if (cellType == VTK_VERTEX || cellType == VTK_POLY_VERTEX)
{
newVerts->InsertNextCell(numCellPts);
for (i = 0; i < numCellPts; ++i)
{
inPtId = ids[i];
outPtId = this->GetOutputPointId(inPtId, input, newPts, outputPD);
newVerts->InsertCellPoint(outPtId);
}
outputCD->CopyData(cd, cellId, this->NumberOfNewCells++);
}
}
// Traverse cells to extract geometry
//
progressCount = 0;
int abort=0;
vtkIdType progressInterval = numCells/20 + 1;
// First insert all points lines in output and 3D geometry in hash.
// Save 2D geometry for second pass.
// initialize the pointer to the cells for fast traversal.
cellPointer = input->GetCells()->GetPointer();
for(cellId=0; cellId < numCells && !abort; cellId++)
{
//Progress and abort method support
if ( progressCount >= progressInterval )
{
vtkDebugMacro(<<"Process cell #" << cellId);
this->UpdateProgress ((double)cellId/numCells);
abort = this->GetAbortExecute();
progressCount = 0;
}
progressCount++;
// Direct access to cells.
cellType = cellTypes[cellId];
numCellPts = cellPointer[0];
ids = cellPointer+1;
// Move to the next cell.
cellPointer += (1 + *cellPointer);
// A couple of common cases to see if things go faster.
if (cellType == VTK_VERTEX || cellType == VTK_POLY_VERTEX)
{
// Do nothing. This case was handled in the provious loop.
}
else if (cellType == VTK_LINE || cellType == VTK_POLY_LINE)
{
newLines->InsertNextCell(numCellPts);
for (i = 0; i < numCellPts; ++i)
{
inPtId = ids[i];
outPtId = this->GetOutputPointId(inPtId, input, newPts, outputPD);
newLines->InsertCellPoint(outPtId);
}
outputCD->CopyData(cd, cellId, this->NumberOfNewCells++);
}
else if (cellType == VTK_HEXAHEDRON)
{
this->InsertQuadInHash(ids[0], ids[1], ids[5], ids[4], cellId);
this->InsertQuadInHash(ids[0], ids[3], ids[2], ids[1], cellId);
this->InsertQuadInHash(ids[0], ids[4], ids[7], ids[3], cellId);
this->InsertQuadInHash(ids[1], ids[2], ids[6], ids[5], cellId);
this->InsertQuadInHash(ids[2], ids[3], ids[7], ids[6], cellId);
this->InsertQuadInHash(ids[4], ids[5], ids[6], ids[7], cellId);
}
else if (cellType == VTK_VOXEL)
{
this->InsertQuadInHash(ids[0], ids[1], ids[5], ids[4], cellId);
this->InsertQuadInHash(ids[0], ids[2], ids[3], ids[1], cellId);
this->InsertQuadInHash(ids[0], ids[4], ids[6], ids[2], cellId);
this->InsertQuadInHash(ids[1], ids[3], ids[7], ids[5], cellId);
this->InsertQuadInHash(ids[2], ids[6], ids[7], ids[3], cellId);
this->InsertQuadInHash(ids[4], ids[5], ids[7], ids[6], cellId);
}
else if (cellType == VTK_TETRA)
{
this->InsertTriInHash(ids[0], ids[1], ids[3], cellId);
this->InsertTriInHash(ids[0], ids[2], ids[1], cellId);
this->InsertTriInHash(ids[0], ids[3], ids[2], cellId);
this->InsertTriInHash(ids[1], ids[2], ids[3], cellId);
}
else if (cellType == VTK_PENTAGONAL_PRISM)
{
// The quads :
this->InsertQuadInHash (ids[0], ids[1], ids[6], ids[5], cellId);
this->InsertQuadInHash (ids[1], ids[2], ids[7], ids[6], cellId);
this->InsertQuadInHash (ids[2], ids[3], ids[8], ids[7], cellId);
this->InsertQuadInHash (ids[3], ids[4], ids[9], ids[8], cellId);
this->InsertQuadInHash (ids[4], ids[0], ids[5], ids[9], cellId);
this->InsertPentaInHash(ids[0], ids[1], ids[2], ids[3], ids[4], cellId);
this->InsertPentaInHash(ids[5], ids[6], ids[7], ids[8], ids[9], cellId);
}
else if (cellType == VTK_HEXAGONAL_PRISM)
{
// The quads :
this->InsertQuadInHash(ids[0], ids[1], ids[7], ids[6], cellId);
this->InsertQuadInHash(ids[1], ids[2], ids[8], ids[7], cellId);
this->InsertQuadInHash(ids[2], ids[3], ids[9], ids[8], cellId);
this->InsertQuadInHash(ids[3], ids[4], ids[10], ids[9], cellId);
this->InsertQuadInHash(ids[4], ids[5], ids[11], ids[10], cellId);
this->InsertQuadInHash(ids[5], ids[0], ids[6], ids[11], cellId);
this->InsertHexInHash (ids[0], ids[1], ids[2], ids[3], ids[4], ids[5], cellId);
this->InsertHexInHash (ids[6], ids[7], ids[8], ids[9], ids[10], ids[11], cellId);
}
else if (cellType == VTK_PIXEL || cellType == VTK_QUAD ||
cellType == VTK_TRIANGLE || cellType == VTK_POLYGON ||
cellType == VTK_TRIANGLE_STRIP ||
cellType == VTK_QUADRATIC_TRIANGLE ||
cellType == VTK_QUADRATIC_QUAD )
{ // save 2D cells for second pass
flag2D = 1;
}
else
// Default way of getting faces. Differentiates between linear
// and higher order cells.
{
input->GetCell(cellId,cell);
if ( cell->IsLinear() )
{
if (cell->GetCellDimension() == 3)
{
int numFaces = cell->GetNumberOfFaces();
for (j=0; j < numFaces; j++)
{
face = cell->GetFace(j);
numFacePts = face->GetNumberOfPoints();
if (numFacePts == 4)
{
this->InsertQuadInHash(face->PointIds->GetId(0),
face->PointIds->GetId(1),
face->PointIds->GetId(2),
face->PointIds->GetId(3), cellId);
}
else if (numFacePts == 3)
{
this->InsertTriInHash(face->PointIds->GetId(0),
face->PointIds->GetId(1),
face->PointIds->GetId(2), cellId);
}
else
{
vtkWarningMacro(<< "I cannot deal with faces with " << numFacePts
<< " points.");
}
} // for all cell faces
} // if 3D
else
{
vtkDebugMacro("Missing cell type.");
}
} // a linear cell type
else //process nonlinear cells via triangulation
{
if ( cell->GetCellDimension() == 1 )
{
cell->Triangulate(0,pts,coords);
for (i=0; i < pts->GetNumberOfIds(); i+=2)
{
newLines->InsertNextCell(2);
inPtId = pts->GetId(i);
outputCD->CopyData( cd, cellId, this->NumberOfNewCells++ );
outPtId = this->GetOutputPointId(inPtId, input, newPts, outputPD);
newLines->InsertCellPoint(outPtId);
inPtId = pts->GetId(i+1);
outPtId = this->GetOutputPointId(inPtId, input, newPts, outputPD);
newLines->InsertCellPoint(outPtId);
}
}
else if ( cell->GetCellDimension() == 2 )
{
vtkWarningMacro(<< "2-D nonlinear cells must be processed with all other 2-D cells.");
}
else //3D nonlinear cell
{
vtkIdList *cellIds = vtkIdList::New();
int numFaces = cell->GetNumberOfFaces();
for (j=0; j < numFaces; j++)
{
face = cell->GetFace(j);
input->GetCellNeighbors(cellId, face->PointIds, cellIds);
if ( cellIds->GetNumberOfIds() <= 0)
{
// FIXME: Face could not be consistent. vtkOrderedTriangulator is a better option
face->Triangulate(0,pts,coords);
for (i=0; i < pts->GetNumberOfIds(); i+=3)
{
this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1),
pts->GetId(i+2), cellId);
}
}
}
cellIds->Delete();
} //3d cell
} //nonlinear cell
} // Cell type else.
} // for all cells.
// It would be possible to add these (except for polygons with 5+ sides)
// to the hashes. Alternatively, the higher order 2d cells could be handled
// in the following loop.
// Now insert 2DCells. Because of poly datas (cell data) ordering,
// the 2D cells have to come after points and lines.
// initialize the pointer to the cells for fast traversal.
cellPointer = input->GetCells()->GetPointer();
for(cellId=0; cellId < numCells && !abort && flag2D; cellId++)
{
// Direct acces to cells.
cellType = input->GetCellType(cellId);
numCellPts = cellPointer[0];
ids = cellPointer+1;
// Move to the next cell.
cellPointer += (1 + *cellPointer);
// A couple of common cases to see if things go faster.
if (cellType == VTK_PIXEL)
{ // Do we really want to insert the 2D cells into a hash?
pts->Reset();
pts->InsertId(0, this->GetOutputPointId(ids[0], input, newPts, outputPD));
pts->InsertId(1, this->GetOutputPointId(ids[1], input, newPts, outputPD));
pts->InsertId(2, this->GetOutputPointId(ids[3], input, newPts, outputPD));
pts->InsertId(3, this->GetOutputPointId(ids[2], input, newPts, outputPD));
newPolys->InsertNextCell(pts);
outputCD->CopyData(cd, cellId, this->NumberOfNewCells++);
}
else if (cellType == VTK_POLYGON || cellType == VTK_TRIANGLE || cellType == VTK_QUAD)
{
pts->Reset();
for ( i=0; i < numCellPts; i++)
{
inPtId = ids[i];
outPtId = this->GetOutputPointId(inPtId, input, newPts, outputPD);
pts->InsertId(i, outPtId);
}
newPolys->InsertNextCell(pts);
outputCD->CopyData(cd, cellId, this->NumberOfNewCells++);
}
else if (cellType == VTK_TRIANGLE_STRIP)
{
// Change strips to triangles so we do not have to worry about order.
int toggle = 0;
vtkIdType ptIds[3];
// This check is not really necessary. It was put here because of another (now fixed) bug.
if (numCellPts > 1)
{
ptIds[0] = this->GetOutputPointId(ids[0], input, newPts, outputPD);
ptIds[1] = this->GetOutputPointId(ids[1], input, newPts, outputPD);
for (i = 2; i < numCellPts; ++i)
{
ptIds[2] = this->GetOutputPointId(ids[i], input, newPts, outputPD);
newPolys->InsertNextCell(3, ptIds);
outputCD->CopyData(cd, cellId, this->NumberOfNewCells++);
ptIds[toggle] = ptIds[2];
toggle = !toggle;
}
}
}
else if ( cellType == VTK_QUADRATIC_TRIANGLE || cellType == VTK_QUADRATIC_QUAD )
{
input->GetCell( cellId, cell );
cell->Triangulate( 0, pts, coords );
for ( i=0; i < pts->GetNumberOfIds(); i+=3 )
{
outPts[0] = this->GetOutputPointId( pts->GetId(i), input, newPts, outputPD );
outPts[1] = this->GetOutputPointId( pts->GetId(i+1), input, newPts, outputPD );
outPts[2] = this->GetOutputPointId( pts->GetId(i+2), input, newPts, outputPD );
newPolys->InsertNextCell( 3, outPts );
outputCD->CopyData(cd, cellId, this->NumberOfNewCells++);
}
}
} // for all cells.
// Now transfer geometry from hash to output (only triangles and quads).
this->InitQuadHashTraversal();
while ( (q = this->GetNextVisibleQuadFromHash()) )
{
// If Tri or Quad:
if( q->p4 == -1 && q->p5 == -1)
{
if ( q->p0 == q->p3)
{
outPts[0] = this->GetOutputPointId(q->p0, input, newPts, outputPD);
outPts[1] = this->GetOutputPointId(q->p1, input, newPts, outputPD);
outPts[2] = this->GetOutputPointId(q->p2, input, newPts, outputPD);
newPolys->InsertNextCell(3, outPts);
outputCD->CopyData(inputCD, q->SourceId, this->NumberOfNewCells++);
}
else
{
outPts[0] = this->GetOutputPointId(q->p0, input, newPts, outputPD);
outPts[1] = this->GetOutputPointId(q->p1, input, newPts, outputPD);
outPts[2] = this->GetOutputPointId(q->p2, input, newPts, outputPD);
outPts[3] = this->GetOutputPointId(q->p3, input, newPts, outputPD);
newPolys->InsertNextCell(4, outPts);
outputCD->CopyData(inputCD, q->SourceId, this->NumberOfNewCells++);
}
}
else // Penta or Hex
{
if( q->p4 != -1 && q->p5 == -1)
{
outPts[0] = this->GetOutputPointId(q->p0, input, newPts, outputPD);
outPts[1] = this->GetOutputPointId(q->p1, input, newPts, outputPD);
outPts[2] = this->GetOutputPointId(q->p2, input, newPts, outputPD);
outPts[3] = this->GetOutputPointId(q->p3, input, newPts, outputPD);
outPts[4] = this->GetOutputPointId(q->p4, input, newPts, outputPD);
newPolys->InsertNextCell(5, outPts);
outputCD->CopyData(inputCD, q->SourceId, this->NumberOfNewCells++);
}
else
{
outPts[0] = this->GetOutputPointId(q->p0, input, newPts, outputPD);
outPts[1] = this->GetOutputPointId(q->p1, input, newPts, outputPD);
outPts[2] = this->GetOutputPointId(q->p2, input, newPts, outputPD);
outPts[3] = this->GetOutputPointId(q->p3, input, newPts, outputPD);
outPts[4] = this->GetOutputPointId(q->p4, input, newPts, outputPD);
outPts[5] = this->GetOutputPointId(q->p5, input, newPts, outputPD);
newPolys->InsertNextCell(6, outPts);
outputCD->CopyData(inputCD, q->SourceId, this->NumberOfNewCells++);
}
}
}
// Update ourselves and release memory
//
cell->Delete();
coords->Delete();
pts->Delete();
output->SetPoints(newPts);
newPts->Delete();
output->SetPolys(newPolys);
newPolys->Delete();
if (newVerts->GetNumberOfCells() > 0)
{
output->SetVerts(newVerts);
}
newVerts->Delete();
newVerts = NULL;
if (newLines->GetNumberOfCells() > 0)
{
output->SetLines(newLines);
}
newLines->Delete();
//free storage
output->Squeeze();
int ghostLevels = output->GetUpdateGhostLevel();
if (this->PieceInvariant)
{
output->RemoveGhostCells(ghostLevels+1);
}
this->DeleteQuadHash();
return 1;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::InitializeQuadHash(vtkIdType numPoints)
{
vtkIdType i;
if (this->QuadHash)
{
this->DeleteQuadHash();
}
// Prepare our special quad allocator (for efficiency).
this->InitFastGeomQuadAllocation(numPoints);
this->QuadHash = new vtkFastGeomQuad*[numPoints];
this->QuadHashLength = numPoints;
this->PointMap = new vtkIdType[numPoints];
for (i = 0; i < numPoints; ++i)
{
this->QuadHash[i] = NULL;
this->PointMap[i] = -1;
}
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::DeleteQuadHash()
{
vtkIdType i;
this->DeleteAllFastGeomQuads();
for (i = 0; i < this->QuadHashLength; ++i)
{
this->QuadHash[i] = NULL;
}
delete [] this->QuadHash;
this->QuadHash = NULL;
this->QuadHashLength = 0;
delete [] this->PointMap;
this->PointMap = NULL;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::InsertQuadInHash(vtkIdType a, vtkIdType b,
vtkIdType c, vtkIdType d,
vtkIdType sourceId)
{
int tmp;
vtkFastGeomQuad *quad, **end;
// Reorder to get smallest id in a.
if (b < a && b < c && b < d)
{
tmp = a;
a = b;
b = c;
c = d;
d = tmp;
}
else if (c < a && c < b && c < d)
{
tmp = a;
a = c;
c = tmp;
tmp = b;
b = d;
d = tmp;
}
else if (d < a && d < b && d < c)
{
tmp = a;
a = d;
d = c;
c = b;
b = tmp;
}
// Look for existing quad in the hash;
end = this->QuadHash + a;
quad = *end;
while (quad)
{
end = &(quad->Next);
// a has to match in this bin.
// c should be independant of point order.
if (c == quad->p2)
{
// Check boh orders for b and d.
if ((b == quad->p1 && d == quad->p3) || (b == quad->p3 && d == quad->p1))
{
// We have a match.
quad->SourceId = -1;
// That is all we need to do. Hide any quad shared by two or more cells.
return;
}
}
quad = *end;
}
// Create a new quad and add it to the hash.
quad = this->NewFastGeomQuad();
quad->Next = NULL;
quad->SourceId = sourceId;
quad->p0 = a;
quad->p1 = b;
quad->p2 = c;
quad->p3 = d;
quad->p4 = -1;
quad->p5 = -1;
*end = quad;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::InsertTriInHash(vtkIdType a, vtkIdType b,
vtkIdType c, vtkIdType sourceId)
{
int tmp;
vtkFastGeomQuad *quad, **end;
// Reorder to get smallest id in a.
if (b < a && b < c)
{
tmp = a;
a = b;
b = c;
c = tmp;
}
else if (c < a && c < b)
{
tmp = a;
a = c;
c = b;
b = tmp;
}
// We can't put the second smnallest in b because it might change the order
// of the verticies in the final triangle.
// Look for existing tri in the hash;
end = this->QuadHash + a;
quad = *end;
while (quad)
{
end = &(quad->Next);
// a has to match in this bin.
if (quad->p0 == quad->p3)
{
if ((b == quad->p1 && c == quad->p2) || (b == quad->p2 && c == quad->p1))
{
// We have a match.
quad->SourceId = -1;
// That is all we need to do. Hide any tri shared by two or more cells.
return;
}
}
quad = *end;
}
// Create a new quad and add it to the hash.
quad = this->NewFastGeomQuad();
quad->Next = NULL;
quad->SourceId = sourceId;
quad->p0 = a;
quad->p1 = b;
quad->p2 = c;
quad->p3 = a;
quad->p4 = -1;
quad->p5 = -1;
*end = quad;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::InsertPentaInHash(vtkIdType a, vtkIdType b,
vtkIdType c, vtkIdType d,
vtkIdType e, vtkIdType sourceId)
{
int idxmin = 0;
vtkIdType min = a;
vtkFastGeomQuad *quad, **end;
// Copy in an array
vtkIdType tab[5] = {a, b, c, d, e};
// Reorder to get smallest id in a.
for(int i=0;i<5;i++)
{
if( tab[i] < min )
{
min = tab[i];
idxmin = i;
}
}
a = tab[idxmin];
b = tab[(idxmin+1)%5];
c = tab[(idxmin+2)%5];
d = tab[(idxmin+3)%5];
e = tab[(idxmin+4)%5];
// Look for existing hex in the hash;
end = this->QuadHash + a;
quad = *end;
while (quad)
{
end = &(quad->Next);
// a has to match in this bin.
if (quad->p5 == -1)
{
if ((b == quad->p1 && c == quad->p2 && d == quad->p3 && e == quad->p4)
|| (b == quad->p4 && c == quad->p3 && d == quad->p2 && e == quad->p1))
{
// We have a match.
quad->SourceId = -1;
// That is all we need to do. Hide any tri shared by two or more cells.
return;
}
}
quad = *end;
}
// Create a new quad and add it to the hash.
quad = this->NewFastGeomQuad();
quad->Next = NULL;
quad->SourceId = sourceId;
quad->p0 = a;
quad->p1 = b;
quad->p2 = c;
quad->p3 = d;
quad->p4 = e;
quad->p5 = -1;
*end = quad;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::InsertHexInHash(vtkIdType a, vtkIdType b,
vtkIdType c, vtkIdType d,
vtkIdType e, vtkIdType f,
vtkIdType sourceId)
{
int idxmin = 0;
vtkIdType min = a;
vtkFastGeomQuad *quad, **end;
// Copy in an array
vtkIdType tab[6] = {a, b, c, d, e, f};
// Reorder to get smallest id in a.
for(int i=0;i<6;i++)
{
if( tab[i] < min )
{
min = tab[i];
idxmin = i;
}
}
a = tab[idxmin];
b = tab[(idxmin+1)%6];
c = tab[(idxmin+2)%6];
d = tab[(idxmin+3)%6];
e = tab[(idxmin+4)%6];
f = tab[(idxmin+5)%6];
// Look for existing hex in the hash;
end = this->QuadHash + a;
quad = *end;
while (quad)
{
end = &(quad->Next);
// a has to match in this bin.
// d should be independant of point order.
if (d == quad->p3)
{
if ((b == quad->p1 && c == quad->p2 && e == quad->p4 && f == quad->p5)
|| (b == quad->p5 && c == quad->p4 && e == quad->p2 && f == quad->p1))
{
// We have a match.
quad->SourceId = -1;
// That is all we need to do. Hide any tri shared by two or more cells.
return;
}
}
quad = *end;
}
// Create a new quad and add it to the hash.
quad = this->NewFastGeomQuad();
quad->Next = NULL;
quad->SourceId = sourceId;
quad->p0 = a;
quad->p1 = b;
quad->p2 = c;
quad->p3 = d;
quad->p4 = e;
quad->p5 = f;
*end = quad;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::InitFastGeomQuadAllocation(int numberOfCells)
{
int idx;
this->DeleteAllFastGeomQuads();
// Allocate 100 pointers to arrays.
// This should be plenty (unless we have riangle strips) ...
this->NumberOfFastGeomQuadArrays = 100;
this->FastGeomQuadArrays = new vtkFastGeomQuad*[100];
// Initalize all to NULL;
for (idx = 0; idx < 100; ++idx)
{
this->FastGeomQuadArrays[idx] = NULL;
}
// Set pointer to the begining.
this->NextArrayIndex = 0;
this->NextQuadIndex = 0;
// Lets keep the chunk size relatively small.
if (numberOfCells < 100)
{
this->FastGeomQuadArrayLength = 50;
}
else
{
this->FastGeomQuadArrayLength = numberOfCells / 2;
}
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::DeleteAllFastGeomQuads()
{
int idx;
for (idx = 0; idx < this->NumberOfFastGeomQuadArrays; ++idx)
{
if (this->FastGeomQuadArrays[idx])
{
delete [] this->FastGeomQuadArrays[idx];
this->FastGeomQuadArrays[idx] = NULL;
}
}
if (this->FastGeomQuadArrays)
{
delete [] this->FastGeomQuadArrays;
this->FastGeomQuadArrays = NULL;
}
this->FastGeomQuadArrayLength = 0;
this->NumberOfFastGeomQuadArrays = 0;
this->NextArrayIndex = 0;
this->NextQuadIndex = 0;
}
//----------------------------------------------------------------------------
vtkFastGeomQuad* vtkDataSetSurfaceFilter::NewFastGeomQuad()
{
if (this->FastGeomQuadArrayLength == 0)
{
vtkErrorMacro("Face hash allocation has not been initialized.");
return NULL;
}
// Although this should not happen often, check first.
if (this->NextArrayIndex >= this->NumberOfFastGeomQuadArrays)
{
int idx, num;
vtkFastGeomQuad** newArrays;
num = this->FastGeomQuadArrayLength * 2;
newArrays = new vtkFastGeomQuad*[num];
for (idx = 0; idx < num; ++idx)
{
newArrays[idx] = NULL;
if (idx < this->NumberOfFastGeomQuadArrays)
{
newArrays[idx] = this->FastGeomQuadArrays[idx];
}
}
delete [] this->FastGeomQuadArrays;
this->FastGeomQuadArrays = newArrays;
this->FastGeomQuadArrayLength = num;
}
// Next: allocate a new array if necessary.
if (this->FastGeomQuadArrays[this->NextArrayIndex] == NULL)
{
// We are allocating a whole bunch at a time to avoid
// allocation of many small pieces of memory.
this->FastGeomQuadArrays[this->NextArrayIndex]
= new vtkFastGeomQuad[this->FastGeomQuadArrayLength];
}
vtkFastGeomQuad* q = (this->FastGeomQuadArrays[this->NextArrayIndex]) + this->NextQuadIndex;
// Move to the next quad.
++(this->NextQuadIndex);
if (this->NextQuadIndex >= this->FastGeomQuadArrayLength)
{
++(this->NextArrayIndex);
this->NextQuadIndex = 0;
}
return q;
}
//----------------------------------------------------------------------------
void vtkDataSetSurfaceFilter::InitQuadHashTraversal()
{
this->QuadHashTraversalIndex = 0;
this->QuadHashTraversal = this->QuadHash[0];
}
//----------------------------------------------------------------------------
vtkFastGeomQuad *vtkDataSetSurfaceFilter::GetNextVisibleQuadFromHash()
{
vtkFastGeomQuad *quad;
quad = this->QuadHashTraversal;
// Move till traversal until we have a quad to return.
// Note: the current traversal has not been returned yet.
while (quad == NULL || quad->SourceId == -1)
{
if (quad)
{ // The quad must be hidden. Move to the next.
quad = quad->Next;
}
else
{ // must be the end of the linked list. Move to the next bin.
this->QuadHashTraversalIndex += 1;
if ( this->QuadHashTraversalIndex >= this->QuadHashLength)
{ // There are no more bins.
this->QuadHashTraversal = NULL;
return NULL;
}
quad = this->QuadHash[this->QuadHashTraversalIndex];
}
}
// Now we have a quad to return. Set the traversal to the next entry.
this->QuadHashTraversal = quad->Next;
return quad;
}
//----------------------------------------------------------------------------
vtkIdType vtkDataSetSurfaceFilter::GetOutputPointId(vtkIdType inPtId,
vtkDataSet *input,
vtkPoints *outPts,
vtkPointData *outPD)
{
vtkIdType outPtId;
outPtId = this->PointMap[inPtId];
if (outPtId == -1)
{
outPtId = outPts->InsertNextPoint(input->GetPoint(inPtId));
outPD->CopyData(input->GetPointData(), inPtId, outPtId);
this->PointMap[inPtId] = outPtId;
}
return outPtId;
}