//---------------------------------------------------------------------------
//
// 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
#include
#include
#include
#include
#include "../../common/WAssert.h"
#include "../../common/math/WVector3D.h"
#include "../../dataHandler/WDataSet.h"
#include "../../dataHandler/WDataHandler.h"
#include "../../dataHandler/WDataSetSingle.h"
#include "../../dataHandler/WDataTexture3D.h"
#include "../../dataHandler/WGridRegular3D.h"
#include "../../dataHandler/WSubject.h"
#include "../../dataHandler/WValueSet.h"
#include "../../graphicsEngine/WShader.h"
#include "../../graphicsEngine/WGraphicsEngine.h"
#include "../../graphicsEngine/WGEUtils.h"
#include "../../kernel/WKernel.h"
#include "../../kernel/WModule.h"
#include "../../kernel/WModuleConnector.h"
#include "../../kernel/WModuleInputData.h"
#include "WMNavSlices.h"
#include "navslices.xpm"
bool WMNavSlices::m_navsliceRunning = false;
WMNavSlices::WMNavSlices():
WModule(),
m_textureChanged( true ),
m_isPicked( false ),
m_isPickedSagittal( false ),
m_isPickedCoronal( false ),
m_isPickedAxial( false )
{
// WARNING: initializing connectors inside the constructor will lead to an exception.
// Implement WModule::initializeConnectors instead.
// initialize members
std::string shaderPath = WKernel::getRunningKernel()->getGraphicsEngine()->getShaderPath();
m_shader = osg::ref_ptr< WShader > ( new WShader( "slice" ) );
}
WMNavSlices::~WMNavSlices()
{
// cleanup
removeConnectors();
}
boost::shared_ptr< WModule > WMNavSlices::factory() const
{
m_navsliceRunning = true;
return boost::shared_ptr< WModule >( new WMNavSlices() );
}
bool WMNavSlices::isRunning()
{
return m_navsliceRunning;
}
const char** WMNavSlices::getXPMIcon() const
{
return navslices_xpm;
}
const std::string WMNavSlices::getName() const
{
return "Navigation Slices";
}
const std::string WMNavSlices::getDescription() const
{
return "This module shows 3 orthogonal navigation slices.";
}
void WMNavSlices::connectors()
{
// initialize connectors
// call WModules initialization
WModule::connectors();
}
void WMNavSlices::properties()
{
// NOTE: the appropriate type of addProperty is chosen by the type of the specified initial value.
// So if you specify a bool as initial value, addProperty will create a WPropBool.
m_showAxial = m_properties->addProperty( "showAxial", "Determines whether the axial slice should be visible.", true, true );
m_showCoronal = m_properties->addProperty( "showCoronal", "Determines whether the coronal slice should be visible.", true, true );
m_showSagittal = m_properties->addProperty( "showSagittal", "Determines whether the sagittal slice should be visible.", true, true );
m_axialPos = m_properties->addProperty( "Axial Slice", "Position of axial slice.", 80 );
m_axialPos->setMin( 0 );
m_axialPos->setMax( 160 );
m_coronalPos = m_properties->addProperty( "Coronal Slice", "Position of coronal slice.", 100 );
m_coronalPos->setMin( 0 );
m_coronalPos->setMax( 200 );
m_sagittalPos = m_properties->addProperty( "Sagittal Slice", "Position of sagittal slice.", 80 );
m_sagittalPos->setMin( 0 );
m_sagittalPos->setMax( 160 );
m_axialPos->setHidden();
m_coronalPos->setHidden();
m_sagittalPos->setHidden();
}
void WMNavSlices::notifyDataChange( boost::shared_ptr input,
boost::shared_ptr output )
{
WModule::notifyDataChange( input, output );
// in this case input==m_input
}
void WMNavSlices::notifyTextureChange()
{
m_textureChanged = true;
}
void WMNavSlices::moduleMain()
{
boost::shared_ptr< WGraphicsEngine > ge = WGraphicsEngine::getGraphicsEngine();
WAssert( ge, "No graphics engine present." );
m_viewer = ge->getViewerByName( "main" );
WAssert( m_viewer, "Requested viewer not found." );
m_viewer->getPickHandler()->getPickSignal()->connect( boost::bind( &WMNavSlices::setSlicePosFromPick, this, _1 ) );
m_viewer = ge->getViewerByName( "axial" );
if( m_viewer )
{
m_viewer->getPickHandler()->getPickSignal()->connect( boost::bind( &WMNavSlices::setSlicePosFromPick, this, _1 ) );
}
m_viewer = ge->getViewerByName( "sagittal" );
if( m_viewer )
{
m_viewer->getPickHandler()->getPickSignal()->connect( boost::bind( &WMNavSlices::setSlicePosFromPick, this, _1 ) );
}
m_viewer = ge->getViewerByName( "coronal" );
if( m_viewer )
{
m_viewer->getPickHandler()->getPickSignal()->connect( boost::bind( &WMNavSlices::setSlicePosFromPick, this, _1 ) );
}
m_viewer = ge->getViewerByName( "main" );
// signal ready state
ready();
// now, to watch changing/new textures use WSubject's change condition
boost::signals2::connection con = WDataHandler::getDefaultSubject()->getChangeCondition()->subscribeSignal(
boost::bind( &WMNavSlices::notifyTextureChange, this )
);
setMaxMinFromBoundingBox();
m_sagittalPos->set( 0.5 * ( m_bb.first[0] + m_bb.second[0] ) );
m_coronalPos->set( 0.5 * ( m_bb.first[1] + m_bb.second[1] ) );
m_axialPos->set( 0.5 * ( m_bb.first[2] + m_bb.second[2] ) );
create();
// Since the modules run in a separate thread: wait
waitForStop();
// clean up stuff
// NOTE: ALAWAYS remove your osg nodes!
// Please, please always check for NULL
boost::shared_ptr< WGEViewer > viewer;
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "axial" );
if( viewer )
{
viewer->getScene()->remove( m_zSliceNode );
viewer->getScene()->remove( m_zCrossNode );
}
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "sagittal" );
if( viewer )
{
viewer->getScene()->remove( m_xSliceNode );
viewer->getScene()->remove( m_xCrossNode );
}
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "coronal" );
if( viewer )
{
viewer->getScene()->remove( m_ySliceNode );
viewer->getScene()->remove( m_yCrossNode );
}
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_slicesNode );
// deregister from WSubject's change condition
con.disconnect();
}
void WMNavSlices::create()
{
m_rootNode = osg::ref_ptr< WGEGroupNode >( new WGEGroupNode() );
m_slicesNode = osg::ref_ptr< WGEGroupNode >( new WGEGroupNode() );
m_xSliceNode = osg::ref_ptr( new osg::Geode() );
m_xSliceNode->setName( "Sagittal Slice" );
m_ySliceNode = osg::ref_ptr( new osg::Geode() );
m_ySliceNode->setName( "Coronal Slice" );
m_zSliceNode = osg::ref_ptr( new osg::Geode() );
m_zSliceNode->setName( "Axial Slice" );
m_xSliceNode->addDrawable( createGeometry( 0 ) );
m_ySliceNode->addDrawable( createGeometry( 1 ) );
m_zSliceNode->addDrawable( createGeometry( 2 ) );
m_xCrossNode = osg::ref_ptr( new osg::Geode() );
m_yCrossNode = osg::ref_ptr( new osg::Geode() );
m_zCrossNode = osg::ref_ptr( new osg::Geode() );
m_xCrossNode->addDrawable( createCrossGeometry( 0 ) );
m_yCrossNode->addDrawable( createCrossGeometry( 1 ) );
m_zCrossNode->addDrawable( createCrossGeometry( 2 ) );
m_rootNode->insert( m_xCrossNode );
m_rootNode->insert( m_yCrossNode );
m_rootNode->insert( m_zCrossNode );
m_rootNode->insert( m_slicesNode );
m_slicesNode->insert( m_xSliceNode );
m_slicesNode->insert( m_ySliceNode );
m_slicesNode->insert( m_zSliceNode );
m_shader->apply( m_slicesNode );
m_shader->apply( m_xSliceNode );
m_shader->apply( m_ySliceNode );
m_shader->apply( m_zSliceNode );
osg::StateSet* rootState = m_slicesNode->getOrCreateStateSet();
initUniforms( rootState );
rootState->setMode( GL_BLEND, osg::StateAttribute::ON );
m_rootNode->setUserData( this );
m_slicesNode->setUserData( this );
m_xSliceNode->setUserData( this );
m_ySliceNode->setUserData( this );
m_zSliceNode->setUserData( this );
m_xCrossNode->setUserData( this );
m_yCrossNode->setUserData( this );
m_zCrossNode->setUserData( this );
m_slicesNode->addUpdateCallback( new sliceNodeCallback );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_slicesNode );
// Please, please always check for NULL
boost::shared_ptr< WGEViewer > viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "axial" );
if( viewer )
{
viewer->getScene()->insert( m_zSliceNode );
viewer->getScene()->insert( m_zCrossNode );
viewer->setCameraManipulator( 0 );
}
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "sagittal" );
if( viewer )
{
viewer->getScene()->insert( m_xSliceNode );
viewer->getScene()->insert( m_xCrossNode );
viewer->setCameraManipulator( 0 );
}
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "coronal" );
if( viewer )
{
viewer->getScene()->insert( m_ySliceNode );
viewer->getScene()->insert( m_yCrossNode );
viewer->setCameraManipulator( 0 );
}
}
void WMNavSlices::setSlicePosFromPick( WPickInfo pickInfo )
{
// handle the pick information on the slice views
if ( pickInfo.getViewerName() != "main" && pickInfo.getViewerName() != "" )
{
// this uses fixed windows size of 150x150 pixel
boost::unique_lock< boost::shared_mutex > lock;
lock = boost::unique_lock< boost::shared_mutex >( m_updateLock );
float x = pickInfo.getPickPixelPosition().first;
float y = pickInfo.getPickPixelPosition().second;
float xPos;
float yPos;
float width;
float height;
// z slice
if ( pickInfo.getViewerName() == "axial" )
{
width = m_bb.second[0] - m_bb.first[0];
height = m_bb.second[1] - m_bb.first[1];
if ( width > height )
{
xPos = ( x / 150 ) * width;
yPos = ( y / 150 ) * width - ( width - height ) / 2;
}
else
{
xPos = ( x / 150 ) * height - ( height - width ) / 2;
yPos = ( y / 150 ) * height;
}
xPos = xPos < m_bb.first[0] ? m_bb.first[0] : xPos;
xPos = xPos > m_bb.second[0] ? m_bb.second[0] : xPos;
yPos = yPos < m_bb.first[1] ? m_bb.first[1] : yPos;
yPos = yPos > m_bb.second[1] ? m_bb.second[1] : yPos;
m_sagittalPos->set( xPos );
m_coronalPos->set( yPos );
}
// x slice
if ( pickInfo.getViewerName() == "sagittal" )
{
width = m_bb.second[1] - m_bb.first[1];
height = m_bb.second[2] - m_bb.first[2];
if ( width > height )
{
xPos = ( x / 150 ) * width;
yPos = ( y / 150 ) * width - ( width - height ) / 2;
}
else
{
xPos = ( x / 150 ) * height - ( height - width ) / 2;
yPos = ( y / 150 ) * height;
}
xPos = m_bb.second[1] - xPos;
xPos = xPos < m_bb.first[1] ? m_bb.first[1] : xPos;
xPos = xPos > m_bb.second[1] ? m_bb.second[1] : xPos;
yPos = yPos < m_bb.first[2] ? m_bb.first[2] : yPos;
yPos = yPos > m_bb.second[2] ? m_bb.second[2] : yPos;
m_coronalPos->set( xPos );
m_axialPos->set( yPos );
}
// y slice
if ( pickInfo.getViewerName() == "coronal" )
{
width = m_bb.second[0] - m_bb.first[0];
height = m_bb.second[2] - m_bb.first[2];
if ( width > height )
{
xPos = ( x / 150 ) * width;
yPos = ( y / 150 ) * width - ( width - height ) / 2;
}
else
{
xPos = ( x / 150 ) * height - ( height - width ) / 2;
yPos = ( y / 150 ) * height;
}
xPos = xPos < m_bb.first[0] ? m_bb.first[0] : xPos;
xPos = xPos > m_bb.second[0] ? m_bb.second[0] : xPos;
yPos = yPos < m_bb.first[2] ? m_bb.first[2] : yPos;
yPos = yPos > m_bb.second[2] ? m_bb.second[2] : yPos;
m_sagittalPos->set( xPos );
m_axialPos->set( yPos );
}
return;
}
if ( pickInfo.getName() == "Axial Slice"
|| pickInfo.getName() == "Coronal Slice"
|| pickInfo.getName() == "Sagittal Slice" )
{
boost::unique_lock< boost::shared_mutex > lock;
lock = boost::unique_lock< boost::shared_mutex >( m_updateLock );
wmath::WVector3D normal = pickInfo.getPickNormal();
std::pair< float, float > newPixelPos( pickInfo.getPickPixelPosition() );
if ( m_isPicked )
{
osg::Vec3 startPosScreen( m_oldPixelPosition.first, m_oldPixelPosition.second, 0.0 );
osg::Vec3 endPosScreen( newPixelPos.first, newPixelPos.second, 0.0 );
osg::Vec3 startPosWorld = wge::unprojectFromScreen( startPosScreen, m_viewer->getCamera() );
osg::Vec3 endPosWorld = wge::unprojectFromScreen( endPosScreen, m_viewer->getCamera() );
osg::Vec3 moveDirWorld = endPosWorld - startPosWorld;
float diff = wge::wv3D2ov3( normal ) * moveDirWorld;
// recognize also small values.
if( diff < 0 && diff > -1 )
{
diff = -1;
}
if( diff > 0 && diff < 1 )
{
diff = 1;
}
if ( pickInfo.getName() == "Axial Slice" )
{
m_axialPos->set( m_axialPos->get() + diff );
}
if ( pickInfo.getName() == "Coronal Slice" )
{
m_coronalPos->set( m_coronalPos->get() + diff );
}
if ( pickInfo.getName() == "Sagittal Slice" )
{
m_sagittalPos->set( m_sagittalPos->get() + diff );
}
lock.unlock();
}
m_oldPixelPosition = newPixelPos;
m_isPicked |= true;
if ( pickInfo.getName() == "Axial Slice" )
{
m_isPickedAxial |= true;
}
if ( pickInfo.getName() == "Coronal Slice" )
{
m_isPickedCoronal |= true;
}
if ( pickInfo.getName() == "Sagittal Slice" )
{
m_isPickedSagittal |= true;
}
}
else
{
m_isPicked &= false;
m_isPickedCoronal &= false;
m_isPickedAxial &= false;
m_isPickedSagittal &= false;
}
}
void WMNavSlices::setMaxMinFromBoundingBox()
{
// grab a list of data textures
std::vector< boost::shared_ptr< WDataTexture3D > > tex = WDataHandler::getDefaultSubject()->getDataTextures( true );
if ( tex.size() > 0 )
{
std::pair< wmath::WPosition, wmath::WPosition > bb = tex[0]->getGrid()->getBoundingBox();
for( size_t i = 1; i < tex.size(); ++i )
{
std::pair< wmath::WPosition, wmath::WPosition > bbTmp = tex[i]->getGrid()->getBoundingBox();
bb.first[0] = bb.first[0] < bbTmp.first[0] ? bb.first[0] : bbTmp.first[0];
bb.first[1] = bb.first[1] < bbTmp.first[1] ? bb.first[1] : bbTmp.first[1];
bb.first[2] = bb.first[2] < bbTmp.first[2] ? bb.first[2] : bbTmp.first[2];
bb.second[0] = bb.second[0] > bbTmp.second[0] ? bb.second[0] : bbTmp.second[0];
bb.second[1] = bb.second[1] > bbTmp.second[1] ? bb.second[1] : bbTmp.second[1];
bb.second[2] = bb.second[2] > bbTmp.second[2] ? bb.second[2] : bbTmp.second[2];
}
m_bb = bb;
m_sagittalPos->setMin( bb.first[0] );
m_sagittalPos->setMax( bb.second[0] );
m_coronalPos->setMin( bb.first[1] );
m_coronalPos->setMax( bb.second[1] );
m_axialPos->setMin( bb.first[2] );
m_axialPos->setMax( bb.second[2] );
}
}
osg::ref_ptr WMNavSlices::createGeometry( int slice )
{
const size_t nbVerts = 4;
float xSlice = static_cast< float >( m_sagittalPos->get( true ) );
float ySlice = static_cast< float >( m_coronalPos->get( true ) );
float zSlice = static_cast< float >( m_axialPos->get( true ) );
float xPos = xSlice + 0.5f;
float yPos = ySlice + 0.5f;
float zPos = zSlice + 0.5f;
osg::ref_ptr sliceGeometry = osg::ref_ptr( new osg::Geometry() );
osg::Vec3Array* sliceVertices = new osg::Vec3Array;
// grab a list of data textures
std::vector< boost::shared_ptr< WDataTexture3D > > tex = WDataHandler::getDefaultSubject()->getDataTextures( true );
if ( tex.size() > 0 )
{
setMaxMinFromBoundingBox();
switch ( slice )
{
case 0:
{
std::vector< wmath::WPosition > vertices;
vertices.push_back( wmath::WPosition( xPos, m_bb.first[1], m_bb.first[2] ) );
vertices.push_back( wmath::WPosition( xPos, m_bb.first[1], m_bb.second[2] ) );
vertices.push_back( wmath::WPosition( xPos, m_bb.second[1], m_bb.second[2] ) );
vertices.push_back( wmath::WPosition( xPos, m_bb.second[1], m_bb.first[2] ) );
for( size_t i = 0; i < nbVerts; ++i )
{
sliceVertices->push_back( wge::wv3D2ov3( vertices[i] ) );
}
sliceGeometry->setVertexArray( sliceVertices );
int c = 0;
for ( std::vector< boost::shared_ptr< WDataTexture3D > >::const_iterator iter = tex.begin(); iter != tex.end(); ++iter )
{
boost::shared_ptr< WGridRegular3D > grid = ( *iter )->getGrid();
osg::Vec3Array* texCoords = new osg::Vec3Array;
for( size_t i = 0; i < nbVerts; ++i )
{
texCoords->push_back( wge::wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
}
sliceGeometry->setTexCoordArray( c, texCoords );
++c;
}
break;
}
case 1:
{
std::vector< wmath::WPosition > vertices;
vertices.push_back( wmath::WPosition( m_bb.first[0], yPos, m_bb.first[2] ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], yPos, m_bb.first[2] ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], yPos, m_bb.second[2] ) );
vertices.push_back( wmath::WPosition( m_bb.first[0], yPos, m_bb.second[2] ) );
for( size_t i = 0; i < nbVerts; ++i )
{
sliceVertices->push_back( wge::wv3D2ov3( vertices[i] ) );
}
sliceGeometry->setVertexArray( sliceVertices );
int c = 0;
for ( std::vector< boost::shared_ptr< WDataTexture3D > >::const_iterator iter = tex.begin(); iter != tex.end(); ++iter )
{
boost::shared_ptr< WGridRegular3D > grid = ( *iter )->getGrid();
osg::Vec3Array* texCoords = new osg::Vec3Array;
for( size_t i = 0; i < nbVerts; ++i )
{
texCoords->push_back( wge::wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
}
sliceGeometry->setTexCoordArray( c, texCoords );
++c;
}
break;
}
case 2:
{
std::vector< wmath::WPosition > vertices;
vertices.push_back( wmath::WPosition( m_bb.first[0], m_bb.first[1], zPos ) );
vertices.push_back( wmath::WPosition( m_bb.first[0], m_bb.second[1], zPos ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], m_bb.second[1], zPos ) );
vertices.push_back( wmath::WPosition( m_bb.second[0], m_bb.first[1], zPos ) );
for( size_t i = 0; i < nbVerts; ++i )
{
sliceVertices->push_back( wge::wv3D2ov3( vertices[i] ) );
}
sliceGeometry->setVertexArray( sliceVertices );
int c = 0;
for ( std::vector< boost::shared_ptr< WDataTexture3D > >::const_iterator iter = tex.begin(); iter != tex.end(); ++iter )
{
boost::shared_ptr< WGridRegular3D > grid = ( *iter )->getGrid();
osg::Vec3Array* texCoords = new osg::Vec3Array;
for( size_t i = 0; i < nbVerts; ++i )
{
texCoords->push_back( wge::wv3D2ov3( grid->worldCoordToTexCoord( vertices[i] ) ) );
}
sliceGeometry->setTexCoordArray( c, texCoords );
++c;
}
break;
}
}
osg::DrawElementsUInt* quad = new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS, 0 );
quad->push_back( 3 );
quad->push_back( 2 );
quad->push_back( 1 );
quad->push_back( 0 );
sliceGeometry->addPrimitiveSet( quad );
}
WKernel::getRunningKernel()->getSelectionManager()->getCrosshair()->setPosition(
wmath::WPosition( m_sagittalPos->get(), m_coronalPos->get(), m_axialPos->get() ) );
return sliceGeometry;
}
osg::ref_ptr WMNavSlices::createCrossGeometry( int slice )
{
float xSlice = static_cast< float >( m_sagittalPos->get( true ) );
float ySlice = static_cast< float >( m_coronalPos->get( true ) );
float zSlice = static_cast< float >( m_axialPos->get( true ) );
float xPos = xSlice + 0.5f;
float yPos = ySlice + 0.5f;
float zPos = zSlice + 0.5f;
osg::ref_ptr geometry = osg::ref_ptr( new osg::Geometry() );
osg::Vec3Array* crossVertices = new osg::Vec3Array;
osg::Vec3Array* colorArray = new osg::Vec3Array;
float minx = m_bb.first[0];
float miny = m_bb.first[1];
float minz = m_bb.first[2];
float maxx = m_bb.second[0];
float maxy = m_bb.second[1];
float maxz = m_bb.second[2];
std::vector< wmath::WPosition > vertices;
switch ( slice )
{
case 0:
{
vertices.push_back( wmath::WPosition( xPos - 0.5f, miny, zPos ) );
vertices.push_back( wmath::WPosition( xPos - 0.5f, maxy, zPos ) );
vertices.push_back( wmath::WPosition( xPos - 0.5f, yPos, minz ) );
vertices.push_back( wmath::WPosition( xPos - 0.5f, yPos, maxz ) );
break;
}
case 1:
{
vertices.push_back( wmath::WPosition( minx, yPos - 0.5f, zPos ) );
vertices.push_back( wmath::WPosition( maxx, yPos - 0.5f, zPos ) );
vertices.push_back( wmath::WPosition( xPos, yPos - 0.5f, minz ) );
vertices.push_back( wmath::WPosition( xPos, yPos - 0.5f, maxz ) );
break;
}
case 2:
{
vertices.push_back( wmath::WPosition( minx, yPos, zPos + 0.5f ) );
vertices.push_back( wmath::WPosition( maxx, yPos, zPos + 0.5f ) );
vertices.push_back( wmath::WPosition( xPos, miny, zPos + 0.5f ) );
vertices.push_back( wmath::WPosition( xPos, maxy, zPos + 0.5f ) );
break;
}
}
for( size_t i = 0; i < 4; ++i )
{
crossVertices->push_back( wge::wv3D2ov3( vertices[i] ) );
}
colorArray->push_back( osg::Vec3( 1.0f, 0.0f, 0.0f ) );
geometry->setColorArray( colorArray );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
geometry->setVertexArray( crossVertices );
unsigned int rawIndexData[] = { 0, 1, 2, 3 }; // NOLINT
std::vector< unsigned int > indexData( rawIndexData, rawIndexData + sizeof( rawIndexData ) / sizeof( unsigned int ) );
osg::DrawElementsUInt* lines = new osg::DrawElementsUInt( osg::PrimitiveSet::LINES, indexData.begin(), indexData.end() );
geometry->addPrimitiveSet( lines );
// disable light for this geode as lines can't be lit properly
osg::StateSet* state = geometry->getOrCreateStateSet();
state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
state->setMode( GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
osg::LineWidth* linewidth = new osg::LineWidth();
linewidth->setWidth( 1.1f );
state->setAttributeAndModes( linewidth, osg::StateAttribute::ON );
return geometry;
}
void WMNavSlices::updateGeometry()
{
boost::shared_lock slock;
slock = boost::shared_lock( m_updateLock );
if ( m_textureChanged // Depends on call order of update routines in callback.
|| m_sagittalPos->changed()
|| m_coronalPos->changed()
|| m_axialPos->changed()
)
{
// if the texture got changed we want to rearange the scene Matrix for the SliceViewports to be centered
updateViewportMatrix();
osg::ref_ptr xSliceGeometry = createGeometry( 0 );
osg::ref_ptr ySliceGeometry = createGeometry( 1 );
osg::ref_ptr zSliceGeometry = createGeometry( 2 );
osg::ref_ptr oldx = osg::ref_ptr( m_xSliceNode->getDrawable( 0 ) );
m_xSliceNode->replaceDrawable( oldx, xSliceGeometry );
osg::ref_ptr oldy = osg::ref_ptr( m_ySliceNode->getDrawable( 0 ) );
m_ySliceNode->replaceDrawable( oldy, ySliceGeometry );
osg::ref_ptr oldz = osg::ref_ptr( m_zSliceNode->getDrawable( 0 ) );
m_zSliceNode->replaceDrawable( oldz, zSliceGeometry );
osg::ref_ptr xCrossGeometry = createCrossGeometry( 0 );
osg::ref_ptr yCrossGeometry = createCrossGeometry( 1 );
osg::ref_ptr zCrossGeometry = createCrossGeometry( 2 );
osg::ref_ptr oldcx = osg::ref_ptr( m_xCrossNode->getDrawable( 0 ) );
m_xCrossNode->replaceDrawable( oldcx, xCrossGeometry );
osg::ref_ptr oldcy = osg::ref_ptr( m_yCrossNode->getDrawable( 0 ) );
m_yCrossNode->replaceDrawable( oldcy, yCrossGeometry );
osg::ref_ptr oldcz = osg::ref_ptr( m_zCrossNode->getDrawable( 0 ) );
m_zCrossNode->replaceDrawable( oldcz, zCrossGeometry );
}
std::vector< boost::shared_ptr< WDataTexture3D > > tex = WDataHandler::getDefaultSubject()->getDataTextures( true );
bool noSlices = ( tex.size() == 0 ) || !m_active->get();
if ( m_showAxial->get() && !noSlices )
{
m_zSliceNode->setNodeMask( 0xFFFFFFFF );
}
else
{
m_zSliceNode->setNodeMask( 0x0 );
}
if ( m_showCoronal->get() && !noSlices )
{
m_ySliceNode->setNodeMask( 0xFFFFFFFF );
}
else
{
m_ySliceNode->setNodeMask( 0x0 );
}
if ( m_showSagittal->get() && !noSlices )
{
m_xSliceNode->setNodeMask( 0xFFFFFFFF );
}
else
{
m_xSliceNode->setNodeMask( 0x0 );
}
slock.unlock();
}
void WMNavSlices::updateTextures()
{
osg::StateSet* rootState = m_slicesNode->getOrCreateStateSet();
if ( m_textureChanged )
{
m_textureChanged = false;
// grab a list of data textures
std::vector< boost::shared_ptr< WDataTexture3D > > tex = WDataHandler::getDefaultSubject()->getDataTextures( true );
if ( tex.size() > 0 )
{
// reset all uniforms
for ( int i = 0; i < m_maxNumberOfTextures; ++i )
{
m_typeUniforms[i]->set( 0 );
}
// for each texture -> apply
int c = 0;
for ( std::vector< boost::shared_ptr< WDataTexture3D > >::const_iterator iter = tex.begin(); iter != tex.end(); ++iter )
{
osg::ref_ptr texture3D = ( *iter )->getTexture();
if ( ( *iter )->isInterpolated() )
{
texture3D->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR );
texture3D->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
}
else
{
texture3D->setFilter( osg::Texture::MIN_FILTER, osg::Texture::NEAREST );
texture3D->setFilter( osg::Texture::MAG_FILTER, osg::Texture::NEAREST );
}
rootState->setTextureAttributeAndModes( c, texture3D, osg::StateAttribute::ON );
// set threshold/opacity as uniforms
float t = ( *iter )->getThreshold() / 255.0;
float a = ( *iter )->getAlpha();
int cmap = ( *iter )->getSelectedColormap();
m_typeUniforms[c]->set( ( *iter )->getDataType() );
m_thresholdUniforms[c]->set( t );
m_alphaUniforms[c]->set( a );
m_cmapUniforms[c]->set( cmap );
++c;
if( c == m_maxNumberOfTextures )
{
break;
}
}
}
}
m_highlightUniformSagittal->set( m_isPickedSagittal );
m_highlightUniformCoronal->set( m_isPickedCoronal );
m_highlightUniformAxial->set( m_isPickedAxial );
m_xSliceNode->getOrCreateStateSet()->merge( *rootState );
m_ySliceNode->getOrCreateStateSet()->merge( *rootState );
m_zSliceNode->getOrCreateStateSet()->merge( *rootState );
}
void WMNavSlices::initUniforms( osg::StateSet* rootState )
{
boost::shared_lock slock;
slock = boost::shared_lock( m_updateLock );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type0", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type1", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type2", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type3", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type4", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type5", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type6", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type7", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type8", 0 ) ) );
m_typeUniforms.push_back( osg::ref_ptr( new osg::Uniform( "type9", 0 ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha0", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha1", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha2", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha3", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha4", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha5", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha6", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha7", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha8", 1.0f ) ) );
m_alphaUniforms.push_back( osg::ref_ptr( new osg::Uniform( "alpha9", 1.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold0", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold1", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold2", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold3", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold4", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold5", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold6", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold7", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold8", 0.0f ) ) );
m_thresholdUniforms.push_back( osg::ref_ptr( new osg::Uniform( "threshold9", 0.0f ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex0", 0 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex1", 1 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex2", 2 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex3", 3 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex4", 4 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex5", 5 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex6", 6 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex7", 7 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex8", 8 ) ) );
m_samplerUniforms.push_back( osg::ref_ptr( new osg::Uniform( "tex9", 9 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap0", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap1", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap2", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap3", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap4", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap5", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap6", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap7", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap8", 0 ) ) );
m_cmapUniforms.push_back( osg::ref_ptr( new osg::Uniform( "useCmap9", 0 ) ) );
for ( int i = 0; i < m_maxNumberOfTextures; ++i )
{
rootState->addUniform( m_typeUniforms[i] );
rootState->addUniform( m_thresholdUniforms[i] );
rootState->addUniform( m_alphaUniforms[i] );
rootState->addUniform( m_samplerUniforms[i] );
rootState->addUniform( m_cmapUniforms[i] );
}
m_highlightUniformSagittal = osg::ref_ptr( new osg::Uniform( "highlighted", 0 ) );
m_highlightUniformCoronal = osg::ref_ptr( new osg::Uniform( "highlighted", 0 ) );
m_highlightUniformAxial = osg::ref_ptr( new osg::Uniform( "highlighted", 0 ) );
m_xSliceNode->getOrCreateStateSet()->addUniform( m_highlightUniformSagittal );
m_ySliceNode->getOrCreateStateSet()->addUniform( m_highlightUniformCoronal );
m_zSliceNode->getOrCreateStateSet()->addUniform( m_highlightUniformAxial );
slock.unlock();
}
void WMNavSlices::updateViewportMatrix()
{
setMaxMinFromBoundingBox();
double aspectR;
double top, left, width, height;
double scale;
boost::shared_ptr< WGEViewer > viewer;
osg::ref_ptr< WGEGroupNode > currentScene;
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "axial" );
if( viewer )
{
currentScene = viewer->getScene();
aspectR = viewer->getCamera()->getViewport()->aspectRatio();
left = m_bb.first[0];
top = m_bb.first[1];
width = m_bb.second[0] - m_bb.first[0];
height = m_bb.second[1] - m_bb.first[1];
if ( width > height )
{
double windowWidht = 240 * aspectR;
scale = windowWidht / width;
}
else
{
double windowHeight = 240;
scale = windowHeight / height;
}
// 1. translate to center
// 2. rotate around center
// 3. scale to maximum
// 4. translate to camera center
// this is necessary because of some reason, which i couldn't determine,
// the viewmatrix of the camera is:
// 1 0 0 -80
// 0 0 -1 -80
// 0 1 0 -250
osg::Matrix sm;
osg::Matrix rm;
osg::Matrix tm;
osg::Matrix tm2;
tm.makeTranslate( osg::Vec3( -left - width / 2, -top - height / 2, 0.0 ) );
rm.makeRotate( 90.0 * 3.141 / 180, 1.0, 0.0, 0.0 );
sm.makeScale( scale, scale, scale );
tm2.makeTranslate( osg::Vec3( 80.0, 250.0, 80.0 ) );
tm *= rm;
tm *= sm;
tm *= tm2;
currentScene->setMatrix( tm );
}
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "sagittal" );
if( viewer )
{
currentScene = viewer->getScene();
aspectR = viewer->getCamera()->getViewport()->aspectRatio();
left = m_bb.first[1];
top = m_bb.first[2];
width = m_bb.second[1] - m_bb.first[1];
height = m_bb.second[2] - m_bb.first[2];
if ( width > height )
{
double windowWidht = 240 * aspectR;
scale = windowWidht / width;
}
else
{
double windowHeight = 240;
scale = windowHeight / height;
}
osg::Matrix rm;
osg::Matrix sm;
osg::Matrix tm;
osg::Matrix tm2;
tm.makeTranslate( osg::Vec3( 0.0, -left - width / 2, -top - height / 2 ) );
rm.makeRotate( 90.0 * 3.141 / 180, 0.0, 0.0, 1.0 );
sm.makeScale( scale, scale, scale );
tm2.makeTranslate( osg::Vec3( 80.0, 250.0, 80.0 ) );
tm *= rm;
tm *= sm;
tm *= tm2;
currentScene->setMatrix( tm );
}
viewer = WKernel::getRunningKernel()->getGraphicsEngine()->getViewerByName( "coronal" );
if( viewer )
{
currentScene = viewer->getScene();
aspectR = viewer->getCamera()->getViewport()->aspectRatio();
left = m_bb.first[0];
top = m_bb.first[2];
width = m_bb.second[0] - m_bb.first[0];
height = m_bb.second[2] - m_bb.first[2];
if ( width > height )
{
double windowWidht = 240 * aspectR;
scale = windowWidht / width;
}
else
{
double windowHeight = 240;
scale = windowHeight / height;
}
osg::Matrix sm;
osg::Matrix tm;
osg::Matrix tm2;
tm.makeTranslate( osg::Vec3( -left - width / 2, 0.0, -top - height / 2 ) );
sm.makeScale( scale, scale, scale );
tm2.makeTranslate( osg::Vec3( 80.0, 250.0, 80.0 ) );
tm *= sm;
tm *= tm2;
currentScene->setMatrix( tm );
}
}