Commit 8a13143a authored by Mathias Goldau's avatar Mathias Goldau

[CHANGE #220] Now the voxelizer accepts also WDataSetFibers (not only the...

[CHANGE #220] Now the voxelizer accepts also WDataSetFibers (not only the cluster) and the cluster plays more the role of a subset selection mechanism. Unfortuneately there is code duplication introduced in WFiberCluster and WDataSetFiberVector. I will fix this in the next step when the WFiberCluster is made independently from the dataset.
parent 428157fa
......@@ -29,6 +29,8 @@
#include <utility>
#include <vector>
#include <boost/array.hpp>
#include "../exceptions/WOutOfBounds.h"
#include "../WAssert.h"
#include "../WLimits.h"
......@@ -244,6 +246,30 @@ double maxSegmentLength( const WLine& line )
return result;
}
void WLine::unifyDirectionBy( const WLine& other )
{
const size_t numBasePoints = 4;
boost::array< WPosition, numBasePoints > m;
boost::array< WPosition, numBasePoints > n;
double distance = 0.0;
double inverseDistance = 0.0;
for( size_t i = 0; i < numBasePoints; ++i )
{
m[i] = other.at( ( other.size() - 1 ) * static_cast< double >( i ) / ( numBasePoints - 1 ) );
n[i] = at( ( size() - 1 ) * static_cast< double >( i ) / ( numBasePoints - 1 ) );
distance += length2( m[i] - n[i] );
inverseDistance += length2( m[i] - at( ( size() - 1 ) * static_cast< double >( numBasePoints - 1 - i ) / ( numBasePoints - 1 ) ) );
}
distance /= static_cast< double >( numBasePoints );
inverseDistance /= static_cast< double >( numBasePoints );
if( inverseDistance < distance )
{
this->reverseOrder();
}
}
WBoundingBox computeBoundingBox( const WLine& line )
{
WBoundingBox result;
......
......@@ -81,6 +81,17 @@ public:
* Collapse samplepoints which are equal and neighboured.
*/
void removeAdjacentDuplicates();
/**
* Put the line into reverse ordering if the reverse ordering would have a
* similar direction to the given line. That means if the start point (or
* multiple selected sample points) of the given line will better match to
* end point (or multiple selected sample points) of this line (in term of
* direction) the line is reordered.
*
* \param other The line giving the direction to align this line to.
*/
void unifyDirectionBy( const WLine& other );
};
// Some convinience functions as non-member non-friend functions
......
......@@ -169,3 +169,73 @@ boost::shared_ptr< WDataSetFibers > WDataSetFiberVector::toWDataSetFibers() cons
return boost::shared_ptr< WDataSetFibers >( new WDataSetFibers( points, fiberStartIndices, fiberLengths, pointFiberMapping ) );
}
boost::shared_ptr< WFiber > centerLine( boost::shared_ptr< const WDataSetFiberVector > tracts )
{
if( !tracts || tracts->empty() ) // invalid data produces invalid center lines
{
return boost::shared_ptr< WFiber >( new WFiber() );
}
size_t avgTractSize = 0;
for( WDataSetFiberVector::const_iterator cit = tracts->begin(); cit != tracts->end(); ++cit )
{
avgTractSize += cit->size();
}
avgTractSize /= tracts->size();
WFiber firstTract( tracts->front() );
firstTract.resampleByNumberOfPoints( avgTractSize );
boost::shared_ptr< WFiber > result( new WFiber( firstTract ) ); // copy the first tract into result centerline
for( size_t tractIndex = 1; tractIndex < tracts->size(); ++tractIndex )
{
WFiber other( tracts->at( tractIndex ) );
other.resampleByNumberOfPoints( avgTractSize );
other.unifyDirectionBy( firstTract );
for( size_t pointIndex = 0; pointIndex < avgTractSize; ++pointIndex )
{
result->at( pointIndex ) += other[ pointIndex ];
}
}
for( size_t pointIndex = 0; pointIndex < avgTractSize; ++pointIndex )
{
result->at( pointIndex ) /= static_cast< double >( tracts->size() );
}
return result;
}
boost::shared_ptr< WFiber > longestLine( boost::shared_ptr< const WDataSetFiberVector > tracts )
{
if( !tracts || tracts->empty() ) // invalid data produces invalid longest lines
{
return boost::shared_ptr< WFiber >( new WFiber() );
}
size_t maxSize = 0;
size_t maxIndex = 0;
for( size_t tractIndex = 0; tractIndex < tracts->size(); ++tractIndex )
{
if( maxSize < tracts->at( tractIndex ).size() )
{
maxSize = tracts->at( tractIndex ).size();
maxIndex = tractIndex;
}
}
return boost::shared_ptr< WFiber >( new WFiber( tracts->at( maxIndex ) ) );
}
boost::shared_ptr< WFiber > centerLine( boost::shared_ptr< const WDataSetFibers > tracts )
{
return centerLine( boost::shared_ptr< WDataSetFiberVector >( new WDataSetFiberVector( tracts ) ) );
}
boost::shared_ptr< WFiber > longestLine( boost::shared_ptr< const WDataSetFibers > tracts )
{
return longestLine( boost::shared_ptr< WDataSetFiberVector >( new WDataSetFiberVector( tracts ) ) );
}
......@@ -138,4 +138,12 @@ protected:
static boost::shared_ptr< WPrototyped > m_prototype;
};
boost::shared_ptr< WFiber > centerLine( boost::shared_ptr< const WDataSetFibers > tracts );
boost::shared_ptr< WFiber > longestLine( boost::shared_ptr< const WDataSetFibers > tracts );
boost::shared_ptr< WFiber > centerLine( boost::shared_ptr< const WDataSetFiberVector > tracts );
boost::shared_ptr< WFiber > longestLine( boost::shared_ptr< const WDataSetFiberVector > tracts );
#endif // WDATASETFIBERVECTOR_H
......@@ -375,3 +375,13 @@ boost::shared_ptr< WFiber > WFiberCluster::getLongestLine() const
}
return m_longestLine;
}
WBoundingBox WFiberCluster::getBoundingBox() const
{
WBoundingBox result;
for( std::list< size_t >::const_iterator cit = m_memberIndices.begin(); cit != m_memberIndices.end(); ++cit )
{
result.expandBy( computeBoundingBox( m_fibs->at( *cit ) ) );
}
return result;
}
......@@ -222,6 +222,13 @@ public:
*/
void generateLongestLine() const;
/**
* Recomputes on every call the axis aligned bounding box incorporating all tracts in this cluster.
*
* \return AABB as WBoundingBox.
*/
WBoundingBox getBoundingBox() const;
protected:
// TODO(math): The only reason why we store here a Reference to the fiber
// dataset is, we need it in the WMVoxelizer module as well as the clustering
......
......@@ -80,10 +80,48 @@ const char** WMVoxelizer::getXPMIcon() const
return voxelizer_xpm;
}
void WMVoxelizer::properties()
{
m_antialiased = m_properties->addProperty( "Antialiasing", "Enable/Disable antialiased drawing of voxels.", true, m_fullUpdate );
m_voxelsPerUnit = m_properties->addProperty( "Voxels per Unit", "Specified the number of voxels per unit in the coordinate system. This "
"is useful to increase the resolution of the grid", 1, m_fullUpdate );
// for selecting the parameterization method
m_paramAlgoSelections = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_paramAlgoSelections->addItem( "No Parameterization", "Disable parameterization." ); // NOTE: you can add XPM images here.
m_paramAlgoSelections->addItem( "By Longest Line", "Use the longest line and parameterize the bundle along it." );
m_paramAlgoSelections->addItem( "By Centerline", "Use the centerline and parameterize the bundle along it." );
m_paramAlgoSelections->addItem( "By Integration", "Integrate along the voxelized line." );
m_parameterAlgo = m_properties->addProperty( "Parameterization", "Select the parameterization algorithm.",
m_paramAlgoSelections->getSelectorFirst(), m_fullUpdate );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_parameterAlgo );
WPropertyHelper::PC_NOTEMPTY::addTo( m_parameterAlgo );
// for selecting the rasterization method
boost::shared_ptr< WItemSelection > rasterAlgos( new WItemSelection() );
rasterAlgos->addItem( "Bresenham", "Voxelization with 3D Bresenham" );
m_rasterAlgo = m_properties->addProperty( "Rasterization", "Which method for rasterizing the tracts", rasterAlgos->getSelectorFirst(),
m_fullUpdate );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_rasterAlgo );
WPropertyHelper::PC_NOTEMPTY::addTo( m_rasterAlgo );
WModule::properties();
}
void WMVoxelizer::connectors()
{
m_tractIC = WModuleInputData< const WDataSetFibers >::createAndAdd( shared_from_this(), "tractInput", "Deterministic tracts" );
m_clusterIC = WModuleInputData< const WFiberCluster >::createAndAdd( shared_from_this(), "clusterInput", "A subset (e.g. a cluster) of tracts" );
m_voxelizedOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "voxelOutput", "The voxelized data set" );
m_paramOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "parameterizationOutput",
"The parameter field for the voxelized fibers." );
WModule::connectors(); // call WModules initialization
}
void WMVoxelizer::moduleMain()
{
m_moduleState.setResetable();
m_moduleState.add( m_clusterIC->getDataChangedCondition() ); // additional fire-condition: "data changed" flag
m_moduleState.add( m_tractIC->getDataChangedCondition() );
m_moduleState.add( m_clusterIC->getDataChangedCondition() );
m_moduleState.add( m_fullUpdate );
m_rootNode = new WGEManagedGroupNode( m_active );
......@@ -94,36 +132,32 @@ void WMVoxelizer::moduleMain()
while( !m_shutdownFlag() ) // loop until the module container requests the module to quit
{
if( !m_clusterIC->getData() ) // ok, the output has not yet sent data
{
// since there is no data yet we will eat property changes
m_rasterAlgo->get( true );
m_antialiased->get( true );
continue;
}
if( m_clusterIC->getData()->size() == 0 )
bool selectionPresent = m_clusterIC->getData();
if( !m_tractIC->getData() )
{
infoLog() << "Got empty fiber dataset. Ignoring.";
m_moduleState.wait();
continue;
}
boost::shared_ptr< WProgress > progress = boost::shared_ptr< WProgress >( new WProgress( "Marching Cubes", 4 ) );
m_progress->addSubProgress( progress );
size_t numTracts = ( selectionPresent ? m_clusterIC->getData()->size() : m_tractIC->getData()->size() );
++*progress;
// full update
if( m_antialiased->changed() || m_rasterAlgo->changed() || m_voxelsPerUnit->changed() ||
m_clusters != m_clusterIC->getData() || m_parameterAlgo->changed() )
infoLog() << "Start voxelization with: " << numTracts << " tracts";
boost::array< boost::shared_ptr< WDataSetScalar >, 2 > result = generateDatasets( m_tractIC->getData(), m_clusterIC->getData() );
if( !result.empty() )
{
m_voxelizedOC->updateData( result[0] );
if( result.size() == 2 ) // parameterized dataset available
{
m_rasterAlgo->get( true );
m_antialiased->get( true );
m_clusters = m_clusterIC->getData();
update();
m_paramOC->updateData( result[1] );
}
m_rootNode->clear();
m_rootNode->insert( genDataSetGeode( result[0] ) );
}
++*progress;
progress->finish();
infoLog() << "Finished.";
m_moduleState.wait(); // waits for firing of m_moduleState ( dataChanged, shutdown, etc. )
}
......@@ -133,34 +167,23 @@ void WMVoxelizer::moduleMain()
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
}
void WMVoxelizer::properties()
boost::shared_ptr< WGridRegular3D > WMVoxelizer::constructGrid( boost::shared_ptr< const WDataSetFibers > tracts,
boost::shared_ptr< const WFiberCluster > cluster ) const
{
m_paramAlgoSelections = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_paramAlgoSelections->addItem( "No Parameterization", "Disable parameterization." ); // NOTE: you can add XPM images here.
m_paramAlgoSelections->addItem( "By Longest Line", "Use the longest line and parameterize the bundle along it." );
m_paramAlgoSelections->addItem( "By Centerline", "Use the centerline and parameterize the bundle along it." );
m_paramAlgoSelections->addItem( "By Integration", "Integrate along the voxelized line." );
m_antialiased = m_properties->addProperty( "Antialiasing", "Enable/Disable antialiased drawing of voxels.", true, m_fullUpdate );
m_rasterAlgo = m_properties->addProperty( "Raster Algo", "Specifies the algorithm you may want to use for voxelization.",
std::string( "WBresenham" ), m_fullUpdate );
m_voxelsPerUnit = m_properties->addProperty( "Voxels per Unit", "Specified the number of voxels per unit in the coordinate system. This "
"is useful to increase the resolution of the grid", 1, m_fullUpdate );
m_parameterAlgo = m_properties->addProperty( "Parameterization", "Select the parameterization algorithm.",
m_paramAlgoSelections->getSelectorFirst(), m_fullUpdate );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_parameterAlgo );
WPropertyHelper::PC_NOTEMPTY::addTo( m_parameterAlgo );
WModule::properties();
}
WBoundingBox bb;
if( cluster )
{
bb = cluster->getBoundingBox();
}
else
{
bb = tracts->getBoundingBox();
}
boost::shared_ptr< WGridRegular3D > WMVoxelizer::constructGrid( const WBoundingBox& bb ) const
{
int32_t nbVoxelsPerUnit = m_voxelsPerUnit->get( true );
// TODO(math): implement the snap-to-grid (of the T1 image) feature for fll and bur.
// TODO(math): remove hardcoded meta grid here.
// the "+1" in the following three statements is because there are may be some more voxels
// the "+1" in the following three statements is because there may be some more voxels
// The first and last voxel are only half sized! hence one more position is needed
size_t nbPosX = std::ceil( bb.xMax() - bb.xMin() ) + 1;
size_t nbPosY = std::ceil( bb.yMax() - bb.yMin() ) + 1;
......@@ -179,132 +202,114 @@ boost::shared_ptr< WGridRegular3D > WMVoxelizer::constructGrid( const WBoundingB
nbVoxelsPerUnit * nbPosY,
nbVoxelsPerUnit * nbPosZ,
transform ) );
debugLog() << "Created grid of size: " << grid->size();
return grid;
}
void WMVoxelizer::update()
boost::array< boost::shared_ptr< WDataSetScalar >, 2 > WMVoxelizer::generateDatasets(
boost::shared_ptr< const WDataSetFibers > tracts,
boost::shared_ptr< const WFiberCluster > cluster ) const
{
boost::shared_ptr< WGridRegular3D > grid = constructGrid( createBoundingBox( *m_clusters ) );
boost::array< boost::shared_ptr< WDataSetScalar >, 2 > result; // unusable instances
debugLog() << "Created grid of size: " << grid->size();
if( !tracts ) // mean while input connector has changed => abort
{
return result;
}
boost::shared_ptr< WGridRegular3D > grid = constructGrid( tracts, cluster );
boost::shared_ptr< WRasterAlgorithm > rasterAlgo;
if( m_rasterAlgo->get() == std::string( "WBresenham" ) )
std::string rasterName = m_rasterAlgo->get().at( 0 )->getName();
if( rasterName == "Bresenham" )
{
rasterAlgo = boost::shared_ptr< WBresenham >( new WBresenham( grid, m_antialiased->get() ) );
}
else if( m_rasterAlgo->get() == std::string( "WBresenhamDBL" ) )
{
rasterAlgo = boost::shared_ptr< WBresenhamDBL >( new WBresenhamDBL( grid, m_antialiased->get() ) );
}
else
{
errorLog() << "Invalid rasterization algorithm: " << m_rasterAlgo->get();
m_rasterAlgo->set( std::string( "WBresenham" ) );
rasterAlgo = boost::shared_ptr< WBresenham >( new WBresenham( grid, m_antialiased->get() ) );
errorLog() << "Invalid rasterization algorithm selected: " << rasterName << " aborting.";
return result;
}
debugLog() << "Using: " << m_rasterAlgo->get() << " as rasterization Algo.";
// decide which param algo to use:
size_t algo = m_parameterAlgo->get( true ).getItemIndexOfSelected( 0 );
boost::shared_ptr< WRasterParameterization > paramAlgo;
if( algo == 0 )
std::string paramName = m_parameterAlgo->get( true ).at( 0 )->getName();
if( paramName == "By Longest Line" )
{
debugLog() << "No parameterization algorithm selected.";
paramAlgo = boost::shared_ptr< WRasterParameterization >( new WCenterlineParameterization( grid, longestLine( tracts, cluster ) ) );
}
else if( algo == 1 )
else if( paramName == "By Centerline" )
{
debugLog() << "Parameterization algorithm: by longest line.";
paramAlgo = boost::shared_ptr< WRasterParameterization >(
new WCenterlineParameterization( grid, m_clusters->getLongestLine() )
);
paramAlgo = boost::shared_ptr< WRasterParameterization >( new WCenterlineParameterization( grid, centerLine( tracts, cluster ) ) );
}
else if( algo == 2 )
else if( paramName == "By Integration" )
{
debugLog() << "Parameterization algorithm: by centerline.";
paramAlgo = boost::shared_ptr< WRasterParameterization >(
new WCenterlineParameterization( grid, m_clusters->getCenterLine() )
);
}
else if( algo == 3 )
{
debugLog() << "Parameterization algorithm: by integration.";
paramAlgo = boost::shared_ptr< WRasterParameterization >(
new WIntegrationParameterization( grid )
);
paramAlgo = boost::shared_ptr< WRasterParameterization >( new WIntegrationParameterization( grid ) );
}
debugLog() << paramName << " as parameterization method selected.";
if( paramAlgo )
{
rasterAlgo->addParameterizationAlgorithm( paramAlgo );
}
raster( rasterAlgo );
raster( rasterAlgo, tracts, cluster );
result[0] = rasterAlgo->generateDataSet();
// update both outputs
boost::shared_ptr< WDataSetScalar > outputDataSet = rasterAlgo->generateDataSet();
m_voxelizedOC->updateData( outputDataSet );
if( paramAlgo )
{
boost::shared_ptr< WDataSetScalar > outputDataSetIntegration = paramAlgo->getDataSet();
m_paramOC->updateData( outputDataSetIntegration );
result[1] = paramAlgo->getDataSet();
}
m_rootNode->clear();
m_rootNode->insert( genDataSetGeode( outputDataSet ) );
return result;
}
void WMVoxelizer::raster( boost::shared_ptr< WRasterAlgorithm > algo ) const
boost::shared_ptr< WFiber > WMVoxelizer::longestLine( boost::shared_ptr< const WDataSetFibers > tracts,
boost::shared_ptr< const WFiberCluster > cluster ) const
{
const WDataSetFiberVector& fibs = *m_clusters->getDataSetReference();
const std::list< size_t >& fiberIDs = m_clusters->getIndices();
std::list< size_t >::const_iterator cit = fiberIDs.begin();
debugLog() << "Cluster indices to voxelize: " << fiberIDs;
debugLog() << "Using: " << m_clusters->getDataSetReference() << " as fiber dataset";
assert( fibs.size() > 0 && "no empty fiber dataset for clusters allowed in WMVoxelizer::createBoundingBox" );
assert( fibs[0].size() > 0 && "no empty fibers in a cluster allowed in WMVoxelizer::createBoundingBox" );
assert( fiberIDs.size() > 0 && "no empty clusters allowed in WMVoxelizer::createBoundingBox" );
for( cit = fiberIDs.begin(); cit != fiberIDs.end(); ++cit )
if( cluster )
{
algo->raster( fibs.at( *cit ) );
return cluster->getLongestLine();
}
algo->finished();
return longestLine( tracts );
}
void WMVoxelizer::connectors()
boost::shared_ptr< WFiber > WMVoxelizer::centerLine( boost::shared_ptr< const WDataSetFibers > tracts,
boost::shared_ptr< const WFiberCluster > cluster ) const
{
m_clusterIC = WModuleInputData< const WFiberCluster >::createAndAdd( shared_from_this(), "tractInput", "A cluster of tracts" );
m_voxelizedOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "voxelOutput", "The voxelized data set" );
m_paramOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "parameterizationOutput",
"The parameter field for the voxelized fibers." );
WModule::connectors(); // call WModules initialization
if( cluster )
{
return cluster->getCenterLine();
}
return centerLine( tracts );
}
WBoundingBox WMVoxelizer::createBoundingBox( const WFiberCluster& cluster ) const
void WMVoxelizer::raster( boost::shared_ptr< WRasterAlgorithm > algo, boost::shared_ptr< const WDataSetFibers > tracts,
boost::shared_ptr< const WFiberCluster > cluster ) const
{
const WDataSetFiberVector& fibs = *cluster.getDataSetReference();
const std::list< size_t >& fiberIDs = cluster.getIndices();
std::list< size_t >::const_iterator cit = fiberIDs.begin();
// for each tract apply a call to algo->raster( tract );
WAssert( fibs.size() > 0, "no empty fiber dataset for clusters allowed in WMVoxelizer::createBoundingBox" );
WAssert( fibs[0].size() > 0, "no empty fibers in a cluster allowed in WMVoxelizer::createBoundingBox" );
WAssert( fiberIDs.size() > 0, "no empty clusters allowed in WMVoxelizer::createBoundingBox" );
WBoundingBox result;
for( cit = fiberIDs.begin(); cit != fiberIDs.end(); ++cit )
if( cluster )
{
boost::shared_ptr< const WDataSetFiberVector > clusterTracts = cluster->getDataSetReference();
const std::list< size_t >& tractIDs = cluster->getIndices();
std::list< size_t >::const_iterator cit = tractIDs.begin();
for( cit = tractIDs.begin(); cit != tractIDs.end(); ++cit )
{
const WFiber& fiber = fibs[ *cit ];
for( size_t i = 0; i < fiber.size(); ++i )
algo->raster( clusterTracts->at( *cit ) );
}
}
else
{
result.expandBy( fiber[i] );
boost::shared_ptr< WDataSetFiberVector > allTracts( new WDataSetFiberVector( tracts ) );
for( WDataSetFiberVector::const_iterator cit = allTracts->begin(); cit != allTracts->end(); ++cit )
{
algo->raster( *cit );
}
}
return result;
algo->finished();
}
osg::ref_ptr< osg::Geode > WMVoxelizer::genDataSetGeode( boost::shared_ptr< WDataSetScalar > dataset ) const
......
......@@ -40,8 +40,9 @@ class WGEManagedGroupNode;
template< class T > class WModuleInputData;
/**
* Traces a given set of deterministic tracts as given by a WFiberCluster in a voxel-wise manner.
* Every voxel which is hit by one or more tracts or tract-segments is marked with a scalar.
* Traces a given set of deterministic tracts as given by a dataset of deterministic tracts (optionally only a subset may be
* processed) in a voxel-wise manner.
* Every voxel which is hit by one or more tracts or tract-segments is marked with a scalar and stored in a dataset scalar.
* \ingroup modules
*/
class WMVoxelizer : public WModule
......@@ -103,13 +104,20 @@ protected:
virtual void properties();
/**
* Every parameter change this function is doing:
* - bounding box and grid generation
* - executing a rasterization algo for the fibers
* - generate dataset out of the grid and a value set
* - display the rastered voxels
* Generates a intensity dataset where each tract is rasterized into. If additionally the (optional) cluster is given as
* subselection only tracts with IDs inside this dataset are considered. If additionally a parameterization was selected
* also a corresponding dataset will be generated and returned.
*
* \param tracts Dataset of deterministic tracts.
* \param cluster Optional selection of a subset of tracts.
*
* \return Two references to datasets where the intensity field is always the first and should be always present, but not when
* an error has occured. Since parameterization is optional, the second dataset will only be generated when a parameterization
* algo has been selected first.
*/
void update();
boost::array< boost::shared_ptr< WDataSetScalar >, 2 > generateDatasets(
boost::shared_ptr< const WDataSetFibers > tracts,
boost::shared_ptr< const WFiberCluster > cluster ) const;
/**
* Removes or inserts geode for the center line of the current cluster into this modules group node.
......@@ -127,11 +135,14 @@ protected:
osg::ref_ptr< osg::Geode > genDataSetGeode( boost::shared_ptr< WDataSetScalar > dataset ) const;
/**
* Performs rasterization with the given algorithm.
* Performs rasterization with the given algorithm on either all tracts or only a subset if given.
*
* \param algo The algorithm which actually rasters every fiber.
* \param tracts Dataset of tracts.
* \param cluster A subset of tracts.
*/
void raster( boost::shared_ptr< WRasterAlgorithm > algo ) const;
void raster( boost::shared_ptr< WRasterAlgorithm > algo, boost::shared_ptr< const WDataSetFibers > tracts,
boost::shared_ptr< const WFiberCluster > cluster ) const;
/**
* Creates two vertices describing the bounding box of a cluster.
......@@ -143,22 +154,59 @@ protected:
WBoundingBox createBoundingBox( const WFiberCluster& cluster ) const;
/**
* Constructs a grid out of the given bounding box.
* Constructs a grid out of the current tract dataset or out of a subset (selection) of this dataset.
*
* \param bb The bounding box
* \param tracts Dataset of deterministic tracts.
* \param cluster Optional subselection of tracts.
*
* \return A WGridRegular3D reference wherein the voxels may be marked.
*/