1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
10
// OpenWalnut is free software: you can redistribute it and/or modify
11
// it under the terms of the GNU Lesser General Public License as published by
12
// the Free Software Foundation, either version 3 of the License, or
13
// (at your option) any later version.
15
// OpenWalnut is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU Lesser General Public License for more details.
20
// You should have received a copy of the GNU Lesser General Public License
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
23
//---------------------------------------------------------------------------
30
#include <boost/regex.hpp>
33
#include <osg/Geometry>
34
#include <osg/LightModel>
35
#include <osg/Material>
36
#include <osg/PolygonMode>
37
#include <osg/StateAttribute>
38
#include <osg/StateSet>
40
#include "core/common/WAssert.h"
41
#include "core/common/WPathHelper.h"
42
#include "core/common/WThreadedFunction.h"
43
#include "core/common/WStringUtils.h"
44
#include "core/dataHandler/WDataSetScalar.h"
45
#include "core/graphicsEngine/algorithms/WMarchingCubesAlgorithm.h"
46
#include "core/graphicsEngine/algorithms/WMarchingLegoAlgorithm.h"
47
#include "core/graphicsEngine/WGEGroupNode.h"
48
#include "core/graphicsEngine/WGEUtils.h"
49
#include "core/graphicsEngine/WROI.h"
50
#include "core/graphicsEngine/WROIArbitrary.h"
51
#include "core/graphicsEngine/WTriangleMesh.h"
52
#include "core/kernel/WKernel.h"
53
#include "core/kernel/WROIManager.h"
54
#include "WCreateSurfaceJob.h"
55
#include "WMAtlasSurfaces.h"
56
#include "WMAtlasSurfaces.xpm"
58
// This line is needed by the module loader to actually find your module.
59
W_LOADABLE_MODULE( WMAtlasSurfaces )
61
WMAtlasSurfaces::WMAtlasSurfaces():
64
m_moduleNode( new WGEGroupNode() ),
66
m_labelsLoaded( false )
70
WMAtlasSurfaces::~WMAtlasSurfaces()
75
boost::shared_ptr< WModule > WMAtlasSurfaces::factory() const
77
// See "src/modules/template/" for an extensively documented example.
78
return boost::shared_ptr< WModule >( new WMAtlasSurfaces() );
81
const char** WMAtlasSurfaces::getXPMIcon() const
86
const std::string WMAtlasSurfaces::getName() const
88
// Specify your module name here. This name must be UNIQUE!
89
return "Atlas Surfaces";
92
const std::string WMAtlasSurfaces::getDescription() const
94
return "Use a scalar data set that stores numbers for atlas regions and a "
95
"corresponding text file with labels for the numbers to create "
96
"surfaces bounding the atlas regions. The surfaces can be picked to reveal "
97
"their name in the HUD (module). Regions can be used as ROIs for fiber selection.";
100
void WMAtlasSurfaces::connectors()
102
// initialize connectors
103
m_input = boost::shared_ptr< WModuleInputData < WDataSetScalar > >(
104
new WModuleInputData< WDataSetScalar >( shared_from_this(), "in", "Dataset to create atlas surfaces from." ) );
105
// add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
106
addConnector( m_input );
108
// call WModules initialization
109
WModule::connectors();
112
void WMAtlasSurfaces::properties()
114
WPropertyBase::PropertyChangeNotifierType propertyCallback = boost::bind( &WMAtlasSurfaces::propertyChanged, this );
115
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
117
m_labelFile = m_properties->addProperty( "Label file", "", boost::filesystem::path( "" ), m_propCondition );
118
WPropertyHelper::PC_PATHEXISTS::addTo( m_labelFile );
120
m_propCreateRoiTrigger = m_properties->addProperty( "Create Roi", "Press!", WPVBaseTypes::PV_TRIGGER_READY, m_propCondition );
122
WModule::properties();
125
void WMAtlasSurfaces::moduleMain()
127
// use the m_input "data changed" flag
128
m_moduleState.setResetable( true, true );
129
m_moduleState.add( m_propCondition );
130
m_moduleState.add( m_active->getUpdateCondition() );
131
m_moduleState.add( m_input->getDataChangedCondition() );
133
// signal ready state
136
// loop until the module container requests the module to quit
137
while( !m_shutdownFlag() )
139
m_moduleState.wait();
141
if( m_shutdownFlag() )
146
if( m_dataSet != m_input->getData() || m_labelFile->changed() )
148
// acquire data from the input connector
149
m_dataSet = m_input->getData();
151
if( m_labelFile->get( true ) == boost::filesystem::path( "" ) )
153
std::string fn = m_dataSet->getFilename();
155
std::string ext( "" );
156
if( fn.find( ".nii.gz" ) != std::string::npos )
160
else if( fn.find( ".nii" ) != std::string::npos )
165
std::string csvExt( ".csv" );
168
// fn.replace( fn.find( ext ), ext.size(), csvExt );
174
m_labelFile->set( fn );
177
if( !boost::filesystem::exists( m_labelFile->get() ) )
179
wlog::warn( "Atlas Surfaces" ) << "Expected label file does not exist! (" << m_labelFile->get().string() << ")";
183
loadLabels( m_labelFile->get( true ).string() );
185
switch( ( *m_dataSet ).getValueSet()->getDataType() )
187
case W_DT_UNSIGNED_CHAR:
189
case W_DT_SIGNED_INT:
190
debugLog() << "Starting creating region meshes";
192
debugLog() << "Finished creating region meshes";
193
debugLog() << "Starting creating OSG nodes";
195
debugLog() << "Finished creating OSG nodes";
201
WAssert( false, "Wrong data type in AtlasSurfaces module" );
205
if( m_active->changed() )
207
if( m_active->get( true ) )
209
m_moduleNode->setNodeMask( 0xFFFFFFFF );
213
m_moduleNode->setNodeMask( 0x0 );
217
if( m_propCreateRoiTrigger->get( true ) == WPVBaseTypes::PV_TRIGGER_TRIGGERED )
219
m_propCreateRoiTrigger->set( WPVBaseTypes::PV_TRIGGER_READY, false );
223
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_moduleNode );
226
void WMAtlasSurfaces::createSurfaces()
228
boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( m_dataSet->getGrid() );
230
boost::shared_ptr<WProgressCombiner> newProgress = boost::shared_ptr<WProgressCombiner>( new WProgressCombiner() );
231
boost::shared_ptr<WProgress>pro = boost::shared_ptr<WProgress>( new WProgress( "dummy", m_dataSet->getMax() ) );
232
m_progress->addSubProgress( pro );
234
boost::shared_ptr<WThreadedJobs<WDataSetScalar, size_t> >job;
236
m_regionMeshes2 = boost::shared_ptr< std::vector< boost::shared_ptr< WTriangleMesh > > >(
237
new std::vector< boost::shared_ptr< WTriangleMesh > >( m_dataSet->getMax() + 1 ) );
239
switch( ( *m_dataSet ).getValueSet()->getDataType() )
241
case W_DT_UNSIGNED_CHAR:
242
job = boost::shared_ptr<WCreateSurfaceJob<unsigned char> >(
243
new WCreateSurfaceJob<unsigned char>( m_dataSet, m_regionMeshes2, newProgress, pro ) );
246
job = boost::shared_ptr<WCreateSurfaceJob<int16_t> >(
247
new WCreateSurfaceJob<int16_t>( m_dataSet, m_regionMeshes2, newProgress, pro ) );
249
case W_DT_SIGNED_INT:
250
job = boost::shared_ptr<WCreateSurfaceJob<int> >(
251
new WCreateSurfaceJob<int>( m_dataSet, m_regionMeshes2, newProgress, pro ) );
256
WAssert( false, "Unknown data type in AtlasSurfaces module" );
259
WThreadedFunction< WThreadedJobs<WDataSetScalar, size_t> >threadPool( 4, job );
265
m_possibleSelections = boost::shared_ptr< WItemSelection >( new WItemSelection() );
267
for(size_t i = 1; i < m_dataSet->getMax() + 1; ++i )
269
std::string label = string_utils::toString( i ) + std::string( " " ) + m_labels[i].second;
270
m_possibleSelections->addItem( label, "" );
273
m_properties->removeProperty( m_aMultiSelection ); // clear before re-adding
274
m_aMultiSelection = m_properties->addProperty( "Regions", "Regions", m_possibleSelections->getSelectorAll(),
278
void WMAtlasSurfaces::createOSGNode()
280
for( size_t i = 1; i < m_regionMeshes2->size(); ++i )
282
osg::Geometry* surfaceGeometry = new osg::Geometry();
283
osg::ref_ptr< osg::Geode > outputGeode = osg::ref_ptr< osg::Geode >( new osg::Geode );
285
std::string label = string_utils::toString( i ) + std::string( " " ) + m_labels[i].second;
286
outputGeode->setName( label );
288
surfaceGeometry->setUseDisplayList( false );
289
surfaceGeometry->setUseVertexBufferObjects( true );
291
surfaceGeometry->setVertexArray( ( *m_regionMeshes2 )[i]->getVertexArray() );
293
// ------------------------------------------------
295
surfaceGeometry->setNormalArray( ( *m_regionMeshes2 )[i]->getVertexNormalArray() );
296
surfaceGeometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
298
// ------------------------------------------------
300
osg::Vec4Array* colors = new osg::Vec4Array;
302
colors->push_back( wge::createColorFromIndex( i ) );
304
surfaceGeometry->setColorArray( colors );
305
surfaceGeometry->setColorBinding( osg::Geometry::BIND_OVERALL );
307
osg::DrawElementsUInt* surfaceElement = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES, 0 );
309
std::vector< size_t >tris = ( *m_regionMeshes2 )[i]->getTriangles();
310
surfaceElement->reserve( tris.size() );
312
for( unsigned int vertId = 0; vertId < tris.size(); ++vertId )
314
surfaceElement->push_back( tris[vertId] );
316
surfaceGeometry->addPrimitiveSet( surfaceElement );
317
outputGeode->addDrawable( surfaceGeometry );
319
osg::StateSet* state = outputGeode->getOrCreateStateSet();
320
osg::ref_ptr<osg::LightModel> lightModel = new osg::LightModel();
321
lightModel->setTwoSided( true );
322
state->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
323
state->setMode( GL_BLEND, osg::StateAttribute::ON );
325
m_moduleNode->insert( outputGeode );
327
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_moduleNode );
328
m_moduleNode->addUpdateCallback( new WGEFunctorCallback< osg::Node >( boost::bind( &WMAtlasSurfaces::updateGraphics, this ) ) );
331
void WMAtlasSurfaces::propertyChanged()
336
void WMAtlasSurfaces::updateGraphics()
338
if( !m_dirty && !m_aMultiSelection->changed() )
343
WItemSelector s = m_aMultiSelection->get( true );
344
for( size_t i = 0; i < m_moduleNode->getNumChildren(); ++i )
346
m_moduleNode->getChild( i )->setNodeMask( 0x0 );
348
for( size_t j = 0; j < s.size(); ++j )
350
if( s.getItemIndexOfSelected(j) == i )
352
m_moduleNode->getChild( i )->setNodeMask( 0xFFFFFFFF );
360
std::vector< std::string > WMAtlasSurfaces::readFile( const std::string fileName )
362
std::ifstream ifs( fileName.c_str(), std::ifstream::in );
364
std::vector< std::string > lines;
370
getline( ifs, line );
372
lines.push_back( std::string( line ) );
380
void WMAtlasSurfaces::loadLabels( std::string fileName )
382
std::vector<std::string> lines;
384
lines = readFile( fileName );
386
if( lines.size() == 0 )
388
m_labelsLoaded = false;
392
std::vector<std::string>svec;
396
for( size_t i = 0; i < lines.size(); ++i )
399
boost::regex reg( "," );
400
boost::sregex_token_iterator it( lines[i].begin(), lines[i].end(), reg, -1 );
401
boost::sregex_token_iterator end;
404
svec.push_back( *it++ );
406
if( svec.size() == 3 )
408
std::pair< std::string, std::string >newLabel( svec[1], svec[2] );
409
m_labels[ string_utils::fromString< size_t >( svec[0] )] = newLabel;
412
m_labelsLoaded = true;
414
catch( const std::exception& e )
416
// print this message AFTER creation of WException to have the backtrace before the message
417
WLogger::getLogger()->addLogMessage(
418
std::string( "Problem while loading label file. Probably not suitable content. Message: " ) + e.what(),
419
"Module (" + getName() + ")", LL_ERROR );
421
m_labelsLoaded = false;
425
void WMAtlasSurfaces::createRoi()
427
WItemSelector s = m_aMultiSelection->get( true );
428
for( size_t i = 0; i < m_moduleNode->getNumChildren(); ++i )
430
for( size_t j = 0; j < s.size(); ++j )
432
if( s.getItemIndexOfSelected(j) == i )
434
debugLog() << i << " selected";
441
void WMAtlasSurfaces::cutArea( int index )
443
boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( m_dataSet->getGrid() );
445
size_t order = ( *m_dataSet ).getValueSet()->order();
446
size_t vDim = ( *m_dataSet ).getValueSet()->dimension();
448
boost::shared_ptr< WValueSet< unsigned char > > vals;
449
vals = boost::shared_dynamic_cast< WValueSet< unsigned char > >( ( *m_dataSet ).getValueSet() );
451
boost::shared_ptr< std::vector< float > > newVals = boost::shared_ptr< std::vector< float > >( new std::vector< float >( grid->size(), 0 ) );
453
for( size_t i = 0; i < newVals->size(); ++i )
455
if( static_cast<int>( vals->getScalar( i ) ) == index )
457
( *newVals )[i] = 1.0;
461
boost::shared_ptr< WValueSet< float > > newValueSet =
462
boost::shared_ptr< WValueSet< float > >( new WValueSet< float >( order, vDim, newVals, W_DT_FLOAT ) );
463
WMarchingLegoAlgorithm mlAlgo;
465
osg::ref_ptr< WROI > newRoi = osg::ref_ptr< WROI >( new WROIArbitrary( grid->getNbCoordsX(), grid->getNbCoordsY(), grid->getNbCoordsZ(),
466
grid->getTransformationMatrix(),
467
*newValueSet->rawDataVectorPointer(),
468
1.0, wge::createColorFromIndex( index ) ) );
471
newRoi->setName( m_labels[index].second );
475
newRoi->setName( std::string( "region " ) + string_utils::toString( index ) );
478
if( WKernel::getRunningKernel()->getRoiManager()->getSelectedRoi() == NULL )
480
WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi );
484
WKernel::getRunningKernel()->getRoiManager()->addRoi( newRoi, WKernel::getRunningKernel()->getRoiManager()->getSelectedRoi() );