Commit 6198ab4a authored by Will Schroeder's avatar Will Schroeder
Browse files

Fully fleshed out and working; 2.5x faster

parent 82a6c1dc
......@@ -12,13 +12,86 @@
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkSmartPointer.h"
#include "vtkCellArray.h"
#include "vtkStaticCellLinks.h"
#include "vtkSmartPointer.h"
#include "vtkImageData.h"
#include "vtkUnstructuredGrid.h"
#include "vtkPolyData.h"
#include "vtkExtractGeometry.h"
#include "vtkSphere.h"
#include "vtkTimerLog.h"
int TestStaticCellLinks( int argc, char *argv[] )
int TestStaticCellLinks( int, char *[] )
{
int dataDim = 3;
vtkSmartPointer<vtkImageData> volume =
vtkSmartPointer<vtkImageData>::New();
volume->SetDimensions(dataDim,dataDim,dataDim);
volume->AllocateScalars(VTK_INT,1);
vtkSmartPointer<vtkSphere> sphere =
vtkSmartPointer<vtkSphere>::New();
sphere->SetCenter(0,0,0);
sphere->SetRadius(100000);
// Side effect of this filter is conversion of volume to unstructured grid
vtkSmartPointer<vtkExtractGeometry> extract =
vtkSmartPointer<vtkExtractGeometry>::New();
extract->SetInputData(volume);
extract->SetImplicitFunction(sphere);
extract->Update();
// Grab the output
vtkSmartPointer<vtkUnstructuredGrid> ugrid =
vtkSmartPointer<vtkUnstructuredGrid>::New();
ugrid = extract->GetOutput();
vtkStaticCellLinks<int> slinks;
slinks.BuildLinks(ugrid);
int numCells = slinks.GetNumberOfCells(0);
const int *cells = slinks.GetCells(0);
cout << "Lower Left corner (numCells, cells): " << numCells << " (";
for (int i=0; i<numCells; ++i)
{
cout << cells[i];
if ( i < (numCells-1) ) cout << "," ;
}
cout << ")\n";
if ( numCells != 1 || cells[0] != 0 )
{
return EXIT_FAILURE;
}
numCells = slinks.GetNumberOfCells(13);
cells = slinks.GetCells(13);
cout << "Center (numCells, cells): " << numCells << " (";
for (int i=0; i<numCells; ++i)
{
cout << cells[i];
if ( i < (numCells-1) ) cout << "," ;
}
cout << ")\n";
if ( numCells != 8 )
{
return EXIT_FAILURE;
}
numCells = slinks.GetNumberOfCells(26);
cells = slinks.GetCells(26);
cout << "Upper Right corner (numCells, cells): " << numCells << " (";
for (int i=0; i<numCells; ++i)
{
cout << cells[i];
if ( i < (numCells-1) ) cout << "," ;
}
cout << ")\n";
if ( numCells != 1 || cells[0] != 7 )
{
return EXIT_FAILURE;
}
int retVal = 1;
return !retVal;
return EXIT_SUCCESS;
}
......@@ -21,16 +21,11 @@
// points. vtkStaticCellLinks is an array of links, each link represents a
// list of cell id's using a particular point. The information provided by
// this object can be used to determine neighbors and construct other local
// topological information. This class is a fast, threaded implementation of
// topological information. This class is a faster implementation of
// vtkCellLinks. However, it cannot be incrementally constructed; it is meant
// to be constructed once (statically) and must be rebuilt if the cells
// change.
// .SECTION Caveats
// This class uses vtkSMPTools to create the links quickly. Use
// VTK_SMP_IMPLEMENTATION_TYPE=TBB or other non-sequential type
// to get better performance.
// .SECTION See Also
// vtkCellLinks
......@@ -44,31 +39,14 @@
class vtkPolyData;
class vtkUnstructuredGrid;
//-----------------------------------------------------------------------------
// The following tuple consists of a point id and cell id. Taken together they
// represent a link from a point to a using cell. The tuple is templated on an
// id type as it can result in significant performance and memory increases.
template <typename IdType>
class PointCellTuple
{
public:
IdType PtId;
IdType CellId;
//Operator< used to support the subsequent sort operation.
bool operator< (const PointCellTuple& tuple) const
{return PtId < tuple.PtId;}
};
template <typename TIds>
class vtkStaticCellLinks :
public vtkTypeTemplate<vtkStaticCellLinks<TIds>, vtkObject>
class vtkStaticCellLinks
{
public:
// Description:
// Default constructor. BuildLinks() does most of the work.
vtkStaticCellLinks() :
NumTuples(0), NumPts(0), NumCells(0), Links(NULL), Offsets(NULL)
LinksSize(0), NumPts(0), NumCells(0), Links(NULL), Offsets(NULL)
{
}
......@@ -103,22 +81,23 @@ public:
// Description:
// Return a list of cell ids using the point.
const PointCellTuple<TIds> *GetCells(vtkIdType ptId)
const TIds *GetCells(vtkIdType ptId)
{
return this->Links + this->Offsets[ptId];
}
private:
vtkStaticCellLinks(const vtkStaticCellLinks&); // Not implemented.
void operator=(const vtkStaticCellLinks&); // Not implemented.
protected:
// Okay the various ivars
TIds NumTuples;
TIds LinksSize;
TIds NumPts;
TIds NumCells;
PointCellTuple<TIds> *Links; //the map to be sorted
TIds *Offsets; //offsets for each point into the map
TIds *Links; //contiguous runs of cells
TIds *Offsets; //offsets for each point into the link array
private:
vtkStaticCellLinks(const vtkStaticCellLinks&); // Not implemented.
void operator=(const vtkStaticCellLinks&); // Not implemented.
};
......
......@@ -14,25 +14,164 @@
=========================================================================*/
#include "vtkStaticCellLinks.h"
#ifndef vtkStaticCellLinls_txx
#ifndef vtkStaticCellLinks_txx
#define vtkStaticCellLinks_txx
#include "vtkCellArray.h"
#include "vtkIdTypeArray.h"
#include "vtkPolyData.h"
#include "vtkUnstructuredGrid.h"
//----------------------------------------------------------------------------
// Build the link list array.
// Build the link list array for unstructured grids
template <typename TIds> void vtkStaticCellLinks<TIds>::
BuildLinks(vtkPolyData *pd)
BuildLinks(vtkUnstructuredGrid *ugrid)
{
// Basic information about the grid
this->NumCells = ugrid->GetNumberOfCells();
this->NumPts = ugrid->GetNumberOfPoints();
// We're going to get into the guts of the class
vtkCellArray *cellArray = ugrid->GetCells();
const vtkIdType *cells = cellArray->GetPointer();
// I love this trick: the size of the Links array is equal to
// the size of the cell array, minus the number of cells.
this->LinksSize =
cellArray->GetNumberOfConnectivityEntries() - this->NumCells;
// Extra one allocated to simplify later pointer manipulation
this->Links = new TIds[this->LinksSize+1];
this->Links[this->LinksSize] = this->NumPts;
this->Offsets = new TIds[this->NumPts+1];
std::fill_n(this->Offsets, this->NumPts, 0);
// Now create the links.
vtkIdType npts, cellId, ptId;
const vtkIdType *cell=cells;
int i;
// Count number of point uses
for ( cellId=0; cellId < this->NumCells; ++cellId )
{
npts = *cell++;
for (i=0; i<npts; ++i)
{
this->Offsets[*cell++]++;
}
}
// Perform prefix sum
for ( ptId=0; ptId < this->NumPts; ++ptId )
{
npts = this->Offsets[ptId+1];
this->Offsets[ptId+1] = this->Offsets[ptId] + npts;
}
// Now build the links. The summation from the prefix sum indicates where
// the cells are to be inserted. Each time a cell is inserted, the offset
// is decremented. In the end, the offset array is also constructed as it
// points to the beginning of each cell run.
for ( cell=cells, cellId=0; cellId < this->NumCells; ++cellId )
{
npts = *cell++;
for (i=0; i<npts; ++i)
{
this->Offsets[*cell]--;
this->Links[this->Offsets[*cell++]] = cellId;
}
}
this->Offsets[this->NumPts] = this->LinksSize;
}
//----------------------------------------------------------------------------
// Build the link list array.
// Build the link list array for poly data. This is more complex because there
// are potentially fout different cell arrays to contend with.
template <typename TIds> void vtkStaticCellLinks<TIds>::
BuildLinks(vtkUnstructuredGrid *ugrid)
BuildLinks(vtkPolyData *pd)
{
// Basic information about the grid
this->NumCells = pd->GetNumberOfCells();
this->NumPts = pd->GetNumberOfPoints();
const vtkCellArray *cellArrays[4];
vtkIdType numCells[4];
vtkIdType sizes[4];
cellArrays[0] = pd->GetVerts();
cellArrays[1] = pd->GetLines();
cellArrays[2] = pd->GetPolys();
cellArrays[3] = pd->GetStrips();
for (i=0; i<4; ++i)
{
if ( cellArrays[i] != NULL )
{
numCells[i] = cellArrays[i]->GetNumberOfCells();
sizes[i] = cellArrays[i]->GetNumberOfConnectivityEntries() - numCells[i];
}
else
{
numCells[i] = 0;
sizes[i] = 0;
}
}//for the four polydata arrays
// Allocate
this->LinksSize = sizes[0] + sizes[1] + sizes[2] + sizes[3];
this->Links = new TIds[this->LinksSize];
this->Links[this->LinksSize] = this->NumPts;
this->Offsets = new TIds[this->NumPts+1];
this->Offsets[this->NumPts] = this->LinksSize;
std::fill_n(this->Offsets, this->NumPts, 0);
// Now create the links.
vtkIdType npts, cellId, CellId, ptId;
const vtkIdType *cell;
int i, j;
// Visit the four arrays
for ( CellId=0, j=0; j < 4; ++j )
{
// Count number of point uses
cell = cellArrays[j];
for ( cellId=0; cellId < numCells[i]; ++cellId )
{
npts = *cell++;
for (i=0; i<npts; ++i)
{
this->Offsets[CellId+(*cell)++]++;
}
}
CellId += numCells[j];
} //for each of the four polydata cell arrays
// Perform prefix sum
for ( ptId=0; ptId < this->NumPts; ++ptId )
{
npts = this->Offsets[ptId+1];
this->Offsets[ptId+1] = this->Offsets[ptId] + npts;
}
// Now build the links. The summation from the prefix sum indicates where
// the cells are to be inserted. Each time a cell is inserted, the offset
// is decremented. In the end, the offset array is also constructed as it
// points to the beginning of each cell run.
for ( CellId=0, j=0; j < 4; ++j )
{
cell = cellArrays[j];
for ( cellId=0; cellId < numCells[i]; ++cellId )
{
npts = *cell++;
for (i=0; i<npts; ++i)
{
this->Offsets[*cell]--;
this->Links[this->Offsets[*cell++]] = CellId+cellId;
}
}
CellId += numCells[j];
}//for each of the four polydata arrays
}
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment