Commit b3606ce7 authored by Will Schroeder's avatar Will Schroeder

Refactored code and thread over slices

All templated code has been consolidated into a single templated
class. The vtkSMPTools::For() has been rewritten to loop over slices
rather than edges (a tad faster and the code is cleaner).
parent 5a64ead3
......@@ -194,6 +194,61 @@ public:
eIds[2] += this->EdgeUses[eCase][2]; //y-edges
eIds[3] = eIds[2] + this->EdgeUses[eCase][3];
}
// Threading integration via SMPTools
template <class TT> class Pass1
{
public:
Pass1(vtkFlyingEdges2DAlgorithm<TT> *algo, double value)
{ this->Algo = algo; this->Value = value;}
vtkFlyingEdges2DAlgorithm<TT> *Algo;
double Value;
void operator()(vtkIdType row, vtkIdType end)
{
TT *rowPtr = this->Algo->Scalars + row*this->Algo->Inc1;
for ( ; row < end; ++row)
{
this->Algo->ProcessXEdge(this->Value, rowPtr, row);
rowPtr += this->Algo->Inc1;
}//for all rows in this batch
}
};
template <class TT> class Pass2
{
public:
Pass2(vtkFlyingEdges2DAlgorithm<TT> *algo)
{ this->Algo = algo;}
vtkFlyingEdges2DAlgorithm<TT> *Algo;
void operator()(vtkIdType row, vtkIdType end)
{
for ( ; row < end; ++row)
{
this->Algo->ProcessYEdges(row);
}//for all rows in this batch
}
};
template <class TT> class Pass3
{
public:
Pass3(vtkFlyingEdges2DAlgorithm<TT> *algo, double value)
{ this->Algo = algo; this->Value = value;}
vtkFlyingEdges2DAlgorithm<TT> *Algo;
double Value;
void operator()(vtkIdType row, vtkIdType end)
{
T *rowPtr = this->Algo->Scalars + row*this->Algo->Inc1;
for ( ; row < end; ++row)
{
this->Algo->GenerateOutput(this->Value, rowPtr, row);
rowPtr += this->Algo->Inc1;
}//for all rows in this batch
}
};
// Interface between VTK and templated functions
static void ContourImage(vtkFlyingEdges2D *self, T *scalars, vtkPoints *newPts,
vtkDataArray *newScalars, vtkCellArray *newLines,
vtkImageData *input, int *updateExt);
};
//----------------------------------------------------------------------------
......@@ -546,95 +601,15 @@ GenerateOutput(double value, T* rowPtr, vtkIdType row)
} //for all non-trimmed cells along this x-edge
}
//----------------------------------------------------------------------------
// Here is the VTK class proper.
// Construct object with initial contour value of 0.0.
vtkFlyingEdges2D::vtkFlyingEdges2D()
{
this->ContourValues = vtkContourValues::New();
this->ComputeScalars = 1;
this->ArrayComponent = 0;
// by default process active point scalars
this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS,
vtkDataSetAttributes::SCALARS);
}
//----------------------------------------------------------------------------
vtkFlyingEdges2D::~vtkFlyingEdges2D()
{
this->ContourValues->Delete();
}
//----------------------------------------------------------------------------
// Description:
// Overload standard modified time function. If contour values are modified,
// then this object is modified as well.
unsigned long vtkFlyingEdges2D::GetMTime()
{
unsigned long mTime=this->Superclass::GetMTime();
unsigned long mTime2=this->ContourValues->GetMTime();
return ( mTime2 > mTime ? mTime2 : mTime );
}
//----------------------------------------------------------------------------
// Build threading integration with the SMPTools
template <class T>
class vtkFlyingEdgesPass1
{
public:
vtkFlyingEdges2DAlgorithm<T> *Algo;
double Value;
void operator()(vtkIdType row, vtkIdType end)
{
T *rowPtr = this->Algo->Scalars + row*this->Algo->Inc1;
for ( ; row < end; ++row)
{
this->Algo->ProcessXEdge(this->Value, rowPtr, row);
rowPtr += this->Algo->Inc1;
}//for all rows in this batch
}
};
template <class T>
class vtkFlyingEdgesPass2
{
public:
vtkFlyingEdges2DAlgorithm<T> *Algo;
void operator()(vtkIdType row, vtkIdType end)
{
for ( ; row < end; ++row)
{
this->Algo->ProcessYEdges(row);
}//for all rows in this batch
}
};
template <class T>
class vtkFlyingEdgesPass3
{
public:
vtkFlyingEdges2DAlgorithm<T> *Algo;
double Value;
void operator()(vtkIdType row, vtkIdType end)
{
T *rowPtr = this->Algo->Scalars + row*this->Algo->Inc1;
for ( ; row < end; ++row)
{
this->Algo->GenerateOutput(this->Value, rowPtr, row);
rowPtr += this->Algo->Inc1;
}//for all rows in this batch
}
};
//----------------------------------------------------------------------------
// Contouring filter specialized for images. This templated function interfaces the
// vtkFlyingEdges2D class with the templated algorithm class. It also invokes
// the three passes of the Flying Edges algorithm.
//
template <class T>
void vtkContourImage(vtkFlyingEdges2D *self, T *scalars, vtkPoints *newPts,
vtkDataArray *newScalars, vtkCellArray *newLines,
vtkImageData *input, int *updateExt)
template <class T> void vtkFlyingEdges2DAlgorithm<T>::
ContourImage(vtkFlyingEdges2D *self, T *scalars, vtkPoints *newPts,
vtkDataArray *newScalars, vtkCellArray *newLines,
vtkImageData *input, int *updateExt)
{
double value, *values = self->GetValues();
int numContours = self->GetNumberOfContours();
......@@ -719,7 +694,7 @@ void vtkContourImage(vtkFlyingEdges2D *self, T *scalars, vtkPoints *newPts,
// The algorithm is separated into multiple passes. The first pass
// computes intersections on row edges, counting the number of intersected edges
// as it progresses. It also keeps track of the generated cases and
// as it progresses. It also keeps track of the generated edge cases and
// other incidental information about intersections along rows. The second
// pass generates polylines from the cases and intersection information.
// In the final and third pass output points and lines are generated.
......@@ -732,16 +707,13 @@ void vtkContourImage(vtkFlyingEdges2D *self, T *scalars, vtkPoints *newPts,
// PASS 1: Traverse all rows generating intersection points and building
// the case table. Also accumulate information necessary for later allocation.
// For example the number of output points is computed.
vtkFlyingEdgesPass1<T> pass1;
pass1.Algo = &algo;
pass1.Value = value;
vtkFlyingEdges2DAlgorithm<T>::Pass1<T> pass1(&algo,value);
vtkSMPTools::For(0,algo.Dims[1], pass1);
// PASS 2: Traverse all rows and process cell y edges. Continue building
// case table from y contributions (using computational trimming to reduce
// work) and keep track of cell y intersections.
vtkFlyingEdgesPass2<T> pass2;
pass2.Algo = &algo;
vtkFlyingEdges2DAlgorithm<T>::Pass2<T> pass2(&algo);
vtkSMPTools::For(0,algo.Dims[1]-1, pass2);
// PASS 3: Now allocate and generate output. First we have to update the
......@@ -779,9 +751,7 @@ void vtkContourImage(vtkFlyingEdges2D *self, T *scalars, vtkPoints *newPts,
}
// Now process each x-row and produce the output primitives.
vtkFlyingEdgesPass3<T> pass3;
pass3.Algo = &algo;
pass3.Value = value;
vtkFlyingEdges2DAlgorithm<T>::Pass3<T> pass3(&algo,value);
vtkSMPTools::For(0,algo.Dims[1]-1, pass3);
// Handle multiple contours
......@@ -795,6 +765,38 @@ void vtkContourImage(vtkFlyingEdges2D *self, T *scalars, vtkPoints *newPts,
delete [] algo.EdgeMetaData;
}
//----------------------------------------------------------------------------
// Here is the VTK class proper.
// Construct object with initial contour value of 0.0.
vtkFlyingEdges2D::vtkFlyingEdges2D()
{
this->ContourValues = vtkContourValues::New();
this->ComputeScalars = 1;
this->ArrayComponent = 0;
// by default process active point scalars
this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS,
vtkDataSetAttributes::SCALARS);
}
//----------------------------------------------------------------------------
vtkFlyingEdges2D::~vtkFlyingEdges2D()
{
this->ContourValues->Delete();
}
//----------------------------------------------------------------------------
// Description:
// Overload standard modified time function. If contour values are modified,
// then this object is modified as well.
unsigned long vtkFlyingEdges2D::GetMTime()
{
unsigned long mTime=this->Superclass::GetMTime();
unsigned long mTime2=this->ContourValues->GetMTime();
return ( mTime2 > mTime ? mTime2 : mTime );
}
//----------------------------------------------------------------------------
// Contouring filter specialized for images (or slices from images)
//
......@@ -850,8 +852,8 @@ int vtkFlyingEdges2D::RequestData( vtkInformation *vtkNotUsed(request),
void *scalars = inScalars->GetVoidPointer(0);
switch (inScalars->GetDataType())
{
vtkTemplateMacro(
vtkContourImage(this,(VTK_TT *)scalars, newPts,
vtkTemplateMacro(vtkFlyingEdges2DAlgorithm<VTK_TT>::
ContourImage(this,(VTK_TT *)scalars, newPts,
newScalars, newLines, input, ext));
}//switch
......
......@@ -36,7 +36,7 @@ vtkStandardNewMacro(vtkFlyingEdges3D);
// This templated class implements the heart of the algorithm.
// vtkFlyingEdges3D populates the information in this class and
// then invokes ContourImage() to actually initiate execution.
// then invokes Contour() to actually initiate execution.
template <class T>
class vtkFlyingEdges3DAlgorithm
{
......@@ -292,6 +292,82 @@ public:
eIds[10] += this->EdgeUses[eCase][10];
eIds[11] = eIds[10] + this->EdgeUses[eCase][11];
}
// Threading integration via SMPTools
template <class TT> class Pass1
{
public:
vtkFlyingEdges3DAlgorithm<TT> *Algo;
double Value;
Pass1(vtkFlyingEdges3DAlgorithm<TT> *algo, double value)
{this->Algo = algo; this->Value = value;}
void operator()(vtkIdType slice, vtkIdType end)
{
vtkIdType row;
TT *rowPtr, *slicePtr = this->Algo->Scalars + slice*this->Algo->Inc2;
for ( ; slice < end; ++slice )
{
for (row=0, rowPtr=slicePtr; row < this->Algo->Dims[1]; ++row)
{
this->Algo->ProcessXEdge(this->Value, rowPtr, row, slice);
rowPtr += this->Algo->Inc1;
}//for all rows in this slice
slicePtr += this->Algo->Inc2;
}//for all slices in this batch
}
};
template <class TT> class Pass2
{
public:
Pass2(vtkFlyingEdges3DAlgorithm<TT> *algo)
{this->Algo = algo;}
vtkFlyingEdges3DAlgorithm<TT> *Algo;
void operator()(vtkIdType slice, vtkIdType end)
{
for ( ; slice < end; ++slice)
{
for ( vtkIdType row=0; row < (this->Algo->Dims[1]-1); ++row)
{
this->Algo->ProcessYZEdges(row, slice);
}//for all rows in this slice
}//for all slices in this batch
}
};
template <class TT> class Pass3
{
public:
Pass3(vtkFlyingEdges3DAlgorithm<TT> *algo, double value)
{this->Algo = algo; this->Value = value;}
vtkFlyingEdges3DAlgorithm<TT> *Algo;
double Value;
void operator()(vtkIdType slice, vtkIdType end)
{
vtkIdType row;
vtkIdType *eMD0 = this->Algo->EdgeMetaData + slice*6*this->Algo->Dims[1];
vtkIdType *eMD1 = eMD0 + 6*this->Algo->Dims[1];
TT *rowPtr, *slicePtr = this->Algo->Scalars + slice*this->Algo->Inc2;
for ( ; slice < end; ++slice )
{
// It's possible to skip entire slices if there is nothing to generate
if ( eMD1[3] > eMD0[3] ) //there are triangle primitives!
{
for (row=0, rowPtr=slicePtr; row < this->Algo->Dims[1]-1; ++row)
{
this->Algo->GenerateOutput(this->Value, rowPtr, row, slice);
rowPtr += this->Algo->Inc1;
}//for all rows in this slice
}//if there are triangles
slicePtr += this->Algo->Inc2;
}//for all slices in this batch
}
};
// Interface between VTK and templated functions
static void Contour(vtkFlyingEdges3D *self, vtkImageData *input,
int extent[6], vtkIdType *incs, T *scalars,
vtkPoints *newPts, vtkCellArray *newTris,
vtkDataArray *newScalars,vtkFloatArray *newNormals,
vtkFloatArray *newGradients);
};
//----------------------------------------------------------------------------
......@@ -966,70 +1042,18 @@ GenerateOutput(double value, T* rowPtr, vtkIdType row, vtkIdType slice)
} //for all non-trimmed cells along this x-edge
}
//----------------------------------------------------------------------------
// Build threading integration with the SMPTools
template <class T> class vtkFlyingEdges3DPass1
{
public:
vtkFlyingEdges3DAlgorithm<T> *Algo;
double Value;
void operator()(vtkIdType eId, vtkIdType end)
{
for ( ; eId < end; ++eId)
{
vtkIdType slice = eId / this->Algo->Dims[1];
vtkIdType row = eId % this->Algo->Dims[1];
T *rowPtr = this->Algo->Scalars + slice*this->Algo->Inc2 +
row*this->Algo->Inc1;
this->Algo->ProcessXEdge(this->Value, rowPtr, row, slice);
}//for all rows in this batch
}
};
template <class T> class vtkFlyingEdges3DPass2
{
public:
vtkFlyingEdges3DAlgorithm<T> *Algo;
void operator()(vtkIdType eId, vtkIdType end)
{
for ( ; eId < end; ++eId)
{
vtkIdType slice = eId / (this->Algo->Dims[1]-1);
vtkIdType row = eId % (this->Algo->Dims[1]-1);
this->Algo->ProcessYZEdges(row, slice);
}//for all rows in this batch
}
};
template <class T> class vtkFlyingEdges3DPass3
{
public:
vtkFlyingEdges3DAlgorithm<T> *Algo;
double Value;
vtkIdType Slice;
T *SlicePtr;
void operator()(vtkIdType row, vtkIdType end)
{
T *rowPtr = this->SlicePtr + row*this->Algo->Inc1;
for ( ; row < end; ++row)
{
this->Algo->GenerateOutput(this->Value, rowPtr, row, this->Slice);
rowPtr += this->Algo->Inc1;
}//for all rows in this batch
}
};
//----------------------------------------------------------------------------
// Contouring filter specialized for 3D volumes. This templated function
// interfaces the vtkFlyingEdges3D class with the templated algorithm
// class. It also invokes the three passes of the Flying Edges algorithm.
template <class T>
void ContourImage(vtkFlyingEdges3D *self, vtkImageData *input, int extent[6],
vtkIdType *incs, T *scalars, vtkPoints *newPts,
vtkCellArray *newTris, vtkDataArray *newScalars,
vtkFloatArray *newNormals, vtkFloatArray *newGradients)
template <class T> void vtkFlyingEdges3DAlgorithm<T>::
Contour(vtkFlyingEdges3D *self, vtkImageData *input, int extent[6],
vtkIdType *incs, T *scalars, vtkPoints *newPts, vtkCellArray *newTris,
vtkDataArray *newScalars, vtkFloatArray *newNormals,
vtkFloatArray *newGradients)
{
double value, *values = self->GetValues();
int numContours = self->GetNumberOfContours();
T *slicePtr;
vtkIdType vidx, row, slice, *eMD, zInc;
vtkIdType numOutXPts, numOutYPts, numOutZPts, numOutTris;
vtkIdType numXPts=0, numYPts=0, numZPts=0, numTris=0;
......@@ -1077,17 +1101,14 @@ void ContourImage(vtkFlyingEdges3D *self, vtkImageData *input, int extent[6],
// intersections (i.e., accumulate information necessary for later output
// memory allocation, e.g., the number of output points along the x-rows
// are counted).
vtkFlyingEdges3DPass1<T> pass1;
pass1.Algo = &algo;
pass1.Value = value;
vtkSMPTools::For(0,algo.NumberOfEdges, pass1);
vtkFlyingEdges3DAlgorithm<T>::Pass1<T> pass1(&algo,value);
vtkSMPTools::For(0,algo.Dims[2], pass1);
// PASS 2: Traverse all voxel x-rows and process voxel y&z edges. The
// result is a count of the number of y- and z-intersections, as well as
// the number of triangles generated along these voxel rows.
vtkFlyingEdges3DPass2<T> pass2;
pass2.Algo = &algo;
vtkSMPTools::For(0,(algo.Dims[1]-1)*(algo.Dims[2]-1), pass2);
vtkFlyingEdges3DAlgorithm<T>::Pass2<T> pass2(&algo);
vtkSMPTools::For(0,algo.Dims[2]-1, pass2);
// PASS 3: Now allocate and generate output. First we have to update the
// edge meta data to partition the output into separate pieces so
......@@ -1145,23 +1166,8 @@ void ContourImage(vtkFlyingEdges3D *self, vtkImageData *input, int extent[6],
algo.NeedGradients = (algo.NewGradients || algo.NewNormals ? 1 : 0);
// Process voxel rows and generate output
vtkFlyingEdges3DPass3<T> pass3;
pass3.Algo = &algo;
pass3.Value = value;
vtkIdType *eMD0, *eMD1 = algo.EdgeMetaData;
for (slicePtr=scalars, slice=0; slice < (algo.Dims[2]-1); ++slice)
{
// It's possible to skip entire slices if there is nothing to generate
eMD0 = eMD1;
eMD1 = algo.EdgeMetaData + (slice+1)*6*algo.Dims[1];
if ( eMD1[3] > eMD0[3] ) //there are triangle primitives!
{
pass3.SlicePtr = slicePtr;
pass3.Slice = slice;
vtkSMPTools::For(0,algo.Dims[1]-1, pass3);
}//if data to generate
slicePtr += algo.Inc2;
}//for all slices
vtkFlyingEdges3DAlgorithm<T>::Pass3<T> pass3(&algo,value);
vtkSMPTools::For(0,algo.Dims[2]-1, pass3);
// Handle multiple contours
startXPts = numOutXPts;
......@@ -1176,9 +1182,8 @@ void ContourImage(vtkFlyingEdges3D *self, vtkImageData *input, int extent[6],
}
//----------------------------------------------------------------------------
// Description:
// Construct object with initial scalar range (0,1) and single contour value
// of 0.0.
// Here is the VTK class proper.
// Construct object with a single contour value of 0.0.
vtkFlyingEdges3D::vtkFlyingEdges3D()
{
this->ContourValues = vtkContourValues::New();
......@@ -1322,9 +1327,10 @@ int vtkFlyingEdges3D::RequestData(
vtkIdType *incs = input->GetIncrements();
switch (inScalars->GetDataType())
{
vtkTemplateMacro(
ContourImage(this, input, exExt, incs, (VTK_TT *)ptr, newPts, newTris,
newScalars, newNormals, newGradients));
vtkTemplateMacro(vtkFlyingEdges3DAlgorithm<VTK_TT>::
Contour(this, input, exExt, incs, (VTK_TT *)ptr,
newPts, newTris, newScalars, newNormals,
newGradients));
}
vtkDebugMacro(<<"Created: "
......
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