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 @@ ...@@ -29,6 +29,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/array.hpp>
#include "../exceptions/WOutOfBounds.h" #include "../exceptions/WOutOfBounds.h"
#include "../WAssert.h" #include "../WAssert.h"
#include "../WLimits.h" #include "../WLimits.h"
...@@ -244,6 +246,30 @@ double maxSegmentLength( const WLine& line ) ...@@ -244,6 +246,30 @@ double maxSegmentLength( const WLine& line )
return result; 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 computeBoundingBox( const WLine& line )
{ {
WBoundingBox result; WBoundingBox result;
......
...@@ -81,6 +81,17 @@ public: ...@@ -81,6 +81,17 @@ public:
* Collapse samplepoints which are equal and neighboured. * Collapse samplepoints which are equal and neighboured.
*/ */
void removeAdjacentDuplicates(); 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 // Some convinience functions as non-member non-friend functions
......
...@@ -169,3 +169,73 @@ boost::shared_ptr< WDataSetFibers > WDataSetFiberVector::toWDataSetFibers() cons ...@@ -169,3 +169,73 @@ boost::shared_ptr< WDataSetFibers > WDataSetFiberVector::toWDataSetFibers() cons
return boost::shared_ptr< WDataSetFibers >( new WDataSetFibers( points, fiberStartIndices, fiberLengths, pointFiberMapping ) ); 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: ...@@ -138,4 +138,12 @@ protected:
static boost::shared_ptr< WPrototyped > m_prototype; 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 #endif // WDATASETFIBERVECTOR_H
...@@ -375,3 +375,13 @@ boost::shared_ptr< WFiber > WFiberCluster::getLongestLine() const ...@@ -375,3 +375,13 @@ boost::shared_ptr< WFiber > WFiberCluster::getLongestLine() const
} }
return m_longestLine; 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: ...@@ -222,6 +222,13 @@ public:
*/ */
void generateLongestLine() const; 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: protected:
// TODO(math): The only reason why we store here a Reference to the fiber // 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 // dataset is, we need it in the WMVoxelizer module as well as the clustering
......
...@@ -80,10 +80,48 @@ const char** WMVoxelizer::getXPMIcon() const ...@@ -80,10 +80,48 @@ const char** WMVoxelizer::getXPMIcon() const
return voxelizer_xpm; 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() void WMVoxelizer::moduleMain()
{ {
m_moduleState.setResetable(); 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_moduleState.add( m_fullUpdate );
m_rootNode = new WGEManagedGroupNode( m_active ); m_rootNode = new WGEManagedGroupNode( m_active );
...@@ -94,36 +132,32 @@ void WMVoxelizer::moduleMain() ...@@ -94,36 +132,32 @@ void WMVoxelizer::moduleMain()
while( !m_shutdownFlag() ) // loop until the module container requests the module to quit 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 bool selectionPresent = m_clusterIC->getData();
{
// since there is no data yet we will eat property changes if( !m_tractIC->getData() )
m_rasterAlgo->get( true );
m_antialiased->get( true );
continue;
}
if( m_clusterIC->getData()->size() == 0 )
{ {
infoLog() << "Got empty fiber dataset. Ignoring.";
m_moduleState.wait();
continue; continue;
} }
boost::shared_ptr< WProgress > progress = boost::shared_ptr< WProgress >( new WProgress( "Marching Cubes", 4 ) ); size_t numTracts = ( selectionPresent ? m_clusterIC->getData()->size() : m_tractIC->getData()->size() );
m_progress->addSubProgress( progress );
infoLog() << "Start voxelization with: " << numTracts << " tracts";
boost::array< boost::shared_ptr< WDataSetScalar >, 2 > result = generateDatasets( m_tractIC->getData(), m_clusterIC->getData() );
++*progress; if( !result.empty() )
// full update
if( m_antialiased->changed() || m_rasterAlgo->changed() || m_voxelsPerUnit->changed() ||
m_clusters != m_clusterIC->getData() || m_parameterAlgo->changed() )
{ {
m_rasterAlgo->get( true ); m_voxelizedOC->updateData( result[0] );
m_antialiased->get( true ); if( result.size() == 2 ) // parameterized dataset available
m_clusters = m_clusterIC->getData(); {
update(); m_paramOC->updateData( result[1] );
}
m_rootNode->clear();
m_rootNode->insert( genDataSetGeode( result[0] ) );
} }
++*progress; infoLog() << "Finished.";
progress->finish();
m_moduleState.wait(); // waits for firing of m_moduleState ( dataChanged, shutdown, etc. ) m_moduleState.wait(); // waits for firing of m_moduleState ( dataChanged, shutdown, etc. )
} }
...@@ -133,34 +167,23 @@ void WMVoxelizer::moduleMain() ...@@ -133,34 +167,23 @@ void WMVoxelizer::moduleMain()
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode ); 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() ); WBoundingBox bb;
m_paramAlgoSelections->addItem( "No Parameterization", "Disable parameterization." ); // NOTE: you can add XPM images here. if( cluster )
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." ); bb = cluster->getBoundingBox();
m_paramAlgoSelections->addItem( "By Integration", "Integrate along the voxelized line." ); }
else
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.", bb = tracts->getBoundingBox();
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();
}
boost::shared_ptr< WGridRegular3D > WMVoxelizer::constructGrid( const WBoundingBox& bb ) const
{
int32_t nbVoxelsPerUnit = m_voxelsPerUnit->get( true ); 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. // 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 // 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 nbPosX = std::ceil( bb.xMax() - bb.xMin() ) + 1;
size_t nbPosY = std::ceil( bb.yMax() - bb.yMin() ) + 1; size_t nbPosY = std::ceil( bb.yMax() - bb.yMin() ) + 1;
...@@ -179,132 +202,114 @@ boost::shared_ptr< WGridRegular3D > WMVoxelizer::constructGrid( const WBoundingB ...@@ -179,132 +202,114 @@ boost::shared_ptr< WGridRegular3D > WMVoxelizer::constructGrid( const WBoundingB
nbVoxelsPerUnit * nbPosY, nbVoxelsPerUnit * nbPosY,
nbVoxelsPerUnit * nbPosZ, nbVoxelsPerUnit * nbPosZ,
transform ) ); transform ) );
debugLog() << "Created grid of size: " << grid->size();
return grid; 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; 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() ) ); 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 else
{ {
errorLog() << "Invalid rasterization algorithm: " << m_rasterAlgo->get(); errorLog() << "Invalid rasterization algorithm selected: " << rasterName << " aborting.";
m_rasterAlgo->set( std::string( "WBresenham" ) ); return result;
rasterAlgo = boost::shared_ptr< WBresenham >( new WBresenham( grid, m_antialiased->get() ) );
} }
debugLog() << "Using: " << m_rasterAlgo->get() << " as rasterization Algo.";
// decide which param algo to use: // decide which param algo to use:
size_t algo = m_parameterAlgo->get( true ).getItemIndexOfSelected( 0 );
boost::shared_ptr< WRasterParameterization > paramAlgo; 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.";
}
else if( algo == 1 )
{ {
debugLog() << "Parameterization algorithm: by longest line."; paramAlgo = boost::shared_ptr< WRasterParameterization >( new WCenterlineParameterization( grid, longestLine( tracts, cluster ) ) );
paramAlgo = boost::shared_ptr< WRasterParameterization >(
new WCenterlineParameterization( grid, m_clusters->getLongestLine() )
);
} }
else if( algo == 2 ) else if( paramName == "By Centerline" )
{ {
debugLog() << "Parameterization algorithm: by centerline."; paramAlgo = boost::shared_ptr< WRasterParameterization >( new WCenterlineParameterization( grid, centerLine( tracts, cluster ) ) );
paramAlgo = boost::shared_ptr< WRasterParameterization >(
new WCenterlineParameterization( grid, m_clusters->getCenterLine() )
);
} }
else if( algo == 3 ) else if( paramName == "By Integration" )
{ {
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 ) if( paramAlgo )
{ {
rasterAlgo->addParameterizationAlgorithm( 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 ) if( paramAlgo )
{ {
boost::shared_ptr< WDataSetScalar > outputDataSetIntegration = paramAlgo->getDataSet(); result[1] = paramAlgo->getDataSet();
m_paramOC->updateData( outputDataSetIntegration );
} }
m_rootNode->clear(); return result;
m_rootNode->insert( genDataSetGeode( outputDataSet ) );
} }
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(); if( cluster )
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 )
{ {
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" ); if( cluster )
m_voxelizedOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "voxelOutput", "The voxelized data set" ); {
m_paramOC = WModuleOutputData< WDataSetScalar >::createAndAdd( shared_from_this(), "parameterizationOutput", return cluster->getCenterLine();
"The parameter field for the voxelized fibers." ); }
WModule::connectors(); // call WModules initialization 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(); // for each tract apply a call to algo->raster( tract );
const std::list< size_t >& fiberIDs = cluster.getIndices();
std::list< size_t >::const_iterator cit = fiberIDs.begin();
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; if( cluster )
for( cit = fiberIDs.begin(); cit != fiberIDs.end(); ++cit )
{ {
const WFiber& fiber = fibs[ *cit ]; boost::shared_ptr< const WDataSetFiberVector > clusterTracts = cluster->getDataSetReference();
for( size_t i = 0; i < fiber.size(); ++i ) 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 )
{ {
result.expandBy( fiber[i] ); algo->raster( clusterTracts->at( *cit ) );
}
}
else
{