//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see .
//
//---------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include //NOLINT
#include //NOLINT
#include //NOLINT
#include "core/kernel/WKernel.h"
#include "core/kernel/WSelectionManager.h"
#include "WMDatasetProfile.h"
#include "WMDatasetProfile.xpm" // Please put a real icon here.
// This line is needed by the module loader to actually find your module. Do not remove. Do NOT add a ";" here.
W_LOADABLE_MODULE( WMDatasetProfile )
WMDatasetProfile::WMDatasetProfile():
WModule(),
m_dirty( true )
{
}
WMDatasetProfile::~WMDatasetProfile()
{
// Cleanup!
}
boost::shared_ptr< WModule > WMDatasetProfile::factory() const
{
// See "src/modules/template/" for an extensively documented example.
return boost::shared_ptr< WModule >( new WMDatasetProfile() );
}
const char** WMDatasetProfile::getXPMIcon() const
{
return WMDatasetProfile_xpm; // Please put a real icon here.
}
const std::string WMDatasetProfile::getName() const
{
return "Dataset Profile";
}
const std::string WMDatasetProfile::getDescription() const
{
// Specify your module description here. Be detailed. This text is read by the user.
// See "src/modules/template/" for an extensively documented example.
return "No documentation yet. "
"The best person to ask for documenation is probably the modules's creator, i.e. \"schurade\"";
}
void WMDatasetProfile::connectors()
{
// the input dataset is just used as source for resolurtion and transformation matrix
m_input = boost::shared_ptr< WModuleInputData < WDataSetScalar > >(
new WModuleInputData< WDataSetScalar >( shared_from_this(), "in", "The input dataset." ) );
addConnector( m_input );
WModule::connectors();
}
void WMDatasetProfile::properties()
{
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
m_snapSelectionsList = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_snapSelectionsList->addItem( "free", "" );
m_snapSelectionsList->addItem( "axial", "" );
m_snapSelectionsList->addItem( "coronal", "" );
m_snapSelectionsList->addItem( "sagittal", "" );
m_snapSelection = m_properties->addProperty( "Snap to", "snap",
m_snapSelectionsList->getSelectorFirst(), m_propCondition );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_snapSelection );
m_propAddKnobTrigger = m_properties->addProperty( "Add knob", "Press!", WPVBaseTypes::PV_TRIGGER_READY, m_propCondition );
m_graphColor = m_properties->addProperty( "Graph color", "Description.", WColor( 0.2, 0.2, 0.2, 1.0 ) );
m_propLength = m_properties->addProperty( "Length", "Description.", 60.0 );
m_propLength->setMin( 1 );
m_propLength->setMax( 500 );
m_propUseLength = m_properties->addProperty( "Use length", "Description.", false );
m_propInterpolate = m_properties->addProperty( "Interpolate", "Description.", true );
m_propNumSamples = m_properties->addProperty( "Number of sample points", "Description.", 100 );
m_propNumSamples->setMin( 1 );
m_propNumSamples->setMax( 500 );
WModule::properties();
}
void WMDatasetProfile::requirements()
{
// Put the code for your requirements here. See "src/modules/template/" for an extensively documented example.
}
void WMDatasetProfile::moduleMain()
{
m_moduleState.setResetable( true, true );
m_moduleState.add( m_input->getDataChangedCondition() );
m_moduleState.add( m_propCondition );
m_moduleState.add( m_active->getUpdateCondition() );
init();
ready();
m_dirty = true;
// wait for a dataset to be connected, most likely an anatomy dataset
while( !m_shutdownFlag() )
{
m_moduleState.wait();
if( m_shutdownFlag() )
{
break;
}
boost::shared_ptr< WDataSetScalar > newDataSet = m_input->getData();
bool dataChanged = ( m_dataSet != newDataSet );
bool dataValid = ( newDataSet != NULL );
if( dataValid )
{
if( dataChanged )
{
m_dataSet = newDataSet;
m_grid = boost::dynamic_pointer_cast< WGridRegular3D >( m_dataSet->getGrid() );
}
}
if( m_snapSelection->changed( true ) )
{
m_dirty = true;
}
if( m_propAddKnobTrigger->changed( true ) )
{
WPosition center = WKernel::getRunningKernel()->getSelectionManager()->getCrosshair()->getPosition();
addKnob( center );
m_propAddKnobTrigger->set( WPVBaseTypes::PV_TRIGGER_READY, true );
}
if( m_propUseLength->changed() || m_propLength->changed() || m_propInterpolate->changed( true ) || m_propNumSamples->changed( true ) )
{
m_dirty = true;
}
}
for( size_t i = 0; i < knobs.size(); ++i )
{
WGraphicsEngine::getGraphicsEngine()->getScene()->remove( &( *knobs[i] ) );
knobs[i]->removeROIChangeNotifier( m_changeRoiSignal );
}
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
}
void WMDatasetProfile::updateCallback()
{
WPosition center = WKernel::getRunningKernel()->getSelectionManager()->getCrosshair()->getPosition();
for( size_t i = 0; i < knobs.size(); ++i )
{
knobs[i]->setLockX( false );
knobs[i]->setLockY( false );
knobs[i]->setLockZ( false );
}
switch( m_snapSelection->get( true ).getItemIndexOfSelected( 0 ) )
{
case 0:
break;
case 1:
for( size_t i = 0; i < knobs.size(); ++i )
{
knobs[i]->setZ( center[2] );
knobs[i]->setLockZ( true );
}
break;
case 2:
for( size_t i = 0; i < knobs.size(); ++i )
{
knobs[i]->setY( center[1] );
knobs[i]->setLockY( true );
}
break;
case 3:
for( size_t i = 0; i < knobs.size(); ++i )
{
knobs[i]->setX( center[0] );
knobs[i]->setLockX( true );
}
break;
default:
break;
}
if( m_propUseLength->get( true ) )
{
for( size_t i = 0; i < knobs.size() - 1; ++i )
{
WPosition p1 = knobs[i]->getPosition();
WPosition p2 = knobs[i+1]->getPosition();
float l = sqrt( ( p1[0] - p2[0] ) * ( p1[0] - p2[0] ) +
( p1[1] - p2[1] ) * ( p1[1] - p2[1] ) +
( p1[2] - p2[2] ) * ( p1[2] - p2[2] ) );
float mult = m_propLength->get( true ) / l;
WPosition vec = p2 - p1;
if( ( fabs( l - static_cast( m_propLength->get( true ) ) ) ) > 0.001 )
{
knobs[i+1]->setPosition( p1 + vec * mult );
}
}
}
m_dirty = true;
update();
}
void WMDatasetProfile::setDirty()
{
m_dirty = true;
}
void WMDatasetProfile::init()
{
m_rootNode = new WGEManagedGroupNode( m_active );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
m_lineGeode = osg::ref_ptr< osg::Geode >( new osg::Geode() );
m_lineGeode->setName( "_line" );
m_rootNode->insert( m_lineGeode );
m_changeRoiSignal
= boost::shared_ptr< boost::function< void() > >( new boost::function< void() >( boost::bind( &WMDatasetProfile::setDirty, this ) ) );
WPosition center = WKernel::getRunningKernel()->getSelectionManager()->getCrosshair()->getPosition();
addKnob( WPosition( center[0] + 30, center[1], center[2] ) );
addKnob( WPosition( center[0] - 30, center[1], center[2] ) );
osg::ref_ptr viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getView();
int height = viewer->getCamera()->getViewport()->height();
int width = viewer->getCamera()->getViewport()->width();
m_oldViewHeight = height;
m_oldViewWidth = width;
m_graphNode = osg::ref_ptr< WGEManagedGroupNode >( new WGEManagedGroupNode( m_active ) );
m_rootNode->insert( m_graphNode );
m_wm = new osgWidget::WindowManager( viewer, 0.0f, 0.0f, MASK_2D );
m_camera = new WGECamera();
m_camera->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF );
m_camera->setProjectionMatrix( osg::Matrix::ortho2D( 0.0, width, 0.0f, height ) );
m_camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
m_camera->setViewMatrix( osg::Matrix::identity() );
m_camera->setClearMask( GL_DEPTH_BUFFER_BIT );
m_camera->setRenderOrder( WGECamera::POST_RENDER );
m_graphNode->addChild( m_camera );
m_camera->addChild( m_wm );
viewer->addEventHandler( new osgWidget::MouseHandler( m_wm ) );
viewer->addEventHandler( new osgWidget::KeyboardHandler( m_wm ) );
viewer->addEventHandler( new osgWidget::ResizeHandler( m_wm, m_camera ) );
viewer->addEventHandler( new osgWidget::CameraSwitchHandler( m_wm, m_camera ) );
viewer->addEventHandler( new osgViewer::StatsHandler() );
viewer->addEventHandler( new osgViewer::WindowSizeHandler() );
viewer->addEventHandler( new osgGA::StateSetManipulator( viewer->getCamera()->getOrCreateStateSet() ) );
m_wm->resizeAllWindows();
m_rootNode->addUpdateCallback( new WGEFunctorCallback< osg::Node >( boost::bind( &WMDatasetProfile::updateCallback, this ) ) );
}
void WMDatasetProfile::addKnob( WPosition pos )
{
osg::ref_ptr s = osg::ref_ptr( new WROISphere( pos, 2.5 ) );
WGraphicsEngine::getGraphicsEngine()->getScene()->addChild( &( *s ) );
knobs.push_back( s );
s->addROIChangeNotifier( m_changeRoiSignal );
for( size_t i = 0; i < knobs.size(); ++i )
{
knobs[i]->setColor( osg::Vec4( 0.0, 1.0, 1.0, 1.0 ) );
}
knobs[0]->setColor( osg::Vec4( 0.0, 1.0, 0.0, 1.0 ) );
knobs[knobs.size()- 1]->setColor( osg::Vec4( 1.0, 0.0, 0.0, 1.0 ) );
}
void WMDatasetProfile::update()
{
m_lineGeode->removeDrawables( 0, 1 );
if( m_active->get() )
{
osg::ref_ptr< osg::Vec3Array > vertices = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array );
osg::ref_ptr< osg::Vec4Array > colors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
osg::ref_ptr< osg::Geometry > geometry = osg::ref_ptr< osg::Geometry >( new osg::Geometry );
for( size_t i = 0; i < knobs.size(); ++i )
{
vertices->push_back( osg::Vec3( knobs[i]->getPosition() ) );
}
geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, vertices->size() ) );
geometry->setVertexArray( vertices );
colors->push_back( m_graphColor->get() );
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
// disable light for this geode as lines can't be lit properly
osg::StateSet* state = m_lineGeode->getOrCreateStateSet();
state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
m_lineGeode->addDrawable( geometry );
osg::ref_ptr viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getView();
int height = viewer->getCamera()->getViewport()->height();
int width = viewer->getCamera()->getViewport()->width();
if( ( height != m_oldViewHeight ) || width != m_oldViewWidth || m_active->changed( true ) )
{
m_oldViewHeight = height;
m_oldViewWidth = width;
m_camera->removeChild( m_graphGridGeode );
m_graphGridGeode = createGraphGridGeode();
m_camera->addChild( m_graphGridGeode );
}
m_camera->removeChild( m_graphGeode );
m_graphGeode = createGraphGeode();
m_camera->addChild( m_graphGeode );
for( size_t i = 0; i < knobs.size(); ++i )
{
knobs[i]->unhide();
}
m_dirty = false;
}
else
{
for( size_t i = 0; i < knobs.size(); ++i )
{
knobs[i]->hide();
}
m_camera->removeChild( m_graphGridGeode );
m_camera->removeChild( m_graphGeode );
}
}
osg::ref_ptr< osg::Geode > WMDatasetProfile::createGraphGridGeode()
{
osg::ref_ptr< osg::Geode > newGeode = osg::ref_ptr< osg::Geode >( new osg::Geode() );
osg::ref_ptr< osg::Vec3Array > vertices = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array );
osg::ref_ptr< osg::Vec4Array > colors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
osg::ref_ptr< osg::Geometry > geometry = osg::ref_ptr< osg::Geometry >( new osg::Geometry );
int step = ( m_oldViewWidth - 20 ) / 10;
int i;
for( i = 10; i < m_oldViewWidth; i += step )
{
vertices->push_back( osg::Vec3( i, m_oldViewHeight / 2, 0 ) );
vertices->push_back( osg::Vec3( i, 10, 0 ) );
}
i -= step;
int yStep = ( m_oldViewHeight / 2 - 10 ) / 4;
vertices->push_back( osg::Vec3( 10, 10, 0 ) );
vertices->push_back( osg::Vec3( i, 10, 0 ) );
vertices->push_back( osg::Vec3( 10, yStep, 0 ) );
vertices->push_back( osg::Vec3( i, yStep, 0 ) );
vertices->push_back( osg::Vec3( 10, yStep * 2, 0 ) );
vertices->push_back( osg::Vec3( i, yStep * 2, 0 ) );
vertices->push_back( osg::Vec3( 10, yStep * 3, 0 ) );
vertices->push_back( osg::Vec3( i, yStep * 3, 0 ) );
vertices->push_back( osg::Vec3( 10, m_oldViewHeight / 2, 0 ) );
vertices->push_back( osg::Vec3( i, m_oldViewHeight / 2, 0 ) );
vertices->push_back( osg::Vec3( 10, 10, 0 ) );
vertices->push_back( osg::Vec3( i, 10, 0 ) );
geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, 0, vertices->size() ) );
geometry->setVertexArray( vertices );
WColor color( 0.7, 0.7, 0.7, 1.0 );
colors->push_back( color );
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
// disable light for this geode as lines can't be lit properly
osg::StateSet* state = m_lineGeode->getOrCreateStateSet();
state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
newGeode->addDrawable( geometry );
return newGeode;
}
osg::ref_ptr< osg::Geode > WMDatasetProfile::createGraphGeode()
{
osg::ref_ptr< osg::Geode > newGeode = osg::ref_ptr< osg::Geode >( new osg::Geode() );
osg::ref_ptr< osg::Vec3Array > vertices = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array );
osg::ref_ptr< osg::Vec4Array > colors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
osg::ref_ptr< osg::Geometry > geometry = osg::ref_ptr< osg::Geometry >( new osg::Geometry );
std::vectorknobPositions;
float max = m_dataSet->getValueSet()->getMaximumValue();
float value;
float overallLength = 0;
std::vectorsegmentLengths;
for( size_t k = 0; k < knobs.size() - 1 ; ++k )
{
WPosition p = ( knobs[k+1]->getPosition() - knobs[k]->getPosition() );
segmentLengths.push_back( length( p ) );
overallLength += length( p );
}
float x = 12;
float y;
for( size_t k = 0; k < knobs.size() - 1 ; ++k )
{
float l1 = segmentLengths[k] / overallLength;
int steps = 100 * l1;
knobPositions.push_back( x );
WPosition p1 = ( knobs[k+1]->getPosition() - knobs[k]->getPosition() ) / static_cast( steps );
for( int i = 0; i < steps; ++i )
{
if( m_propInterpolate->get() )
{
bool success;
value = m_dataSet->interpolate( knobs[k]->getPosition() + p1 * i, &success );
}
else
{
value = m_dataSet->getValueAt( m_grid->getVoxelNum( knobs[k]->getPosition() + p1 * i ) );
}
x = x + ( m_oldViewWidth / 100 );
y = 10 + ( value / max * ( m_oldViewHeight - 20 ) / 2 );
vertices->push_back( osg::Vec3( x, y, 0 ) );
}
}
knobPositions.push_back( x );
for( size_t j = 0; j < knobPositions.size(); ++j )
{
vertices->push_back( osg::Vec3( knobPositions[j], m_oldViewHeight / 2, 0 ) );
vertices->push_back( osg::Vec3( knobPositions[j], 10, 0 ) );
}
geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, vertices->size() - knobPositions.size() * 2 ) );
geometry->setVertexArray( vertices );
geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, vertices->size() - ( knobPositions.size() ) * 2,
( knobPositions.size() + 1 ) * 2 ) );
colors->push_back( m_graphColor->get() );
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
// disable light for this geode as lines can't be lit properly
osg::StateSet* state = m_lineGeode->getOrCreateStateSet();
state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
newGeode->addDrawable( geometry );
return newGeode;
}