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
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;
|
|
}
|
|
|