Commit 8d0a3d7a authored by cornimueller's avatar cornimueller
Browse files

[ADD] Many changes to the EEG view module to support paging:

 * Viewing parameters are stored as properties.
 * Adjusted structure of the scene graph.
 * Viewing changes are done by numerous callbacks which load the needed data from the EEG classes.
 * Replaced WGE2DManipulator by a new WEEGViewHandler which translates the controls into changes of the new properties.
Now it is possible to see the whole file, but it is just loaded when needed.
In addition to that, some other changes ensued:
 * Electrode labels are always at the left independent from the panning in time.
 * The controls were changed and extended (MMB: panning, RMB: zooming in time, Wheel: scaling of voltage, Wheel+RMB: change spacing of graphs)
 * Resize-window-events are forwarded to a osgViewer::View to be used by a GUIEventHandler attached to this View.
 * Now the EEG view module is automatically added after loading a WEEG2 dataset instead of a WEEG dataset.
 * When adding a new custom dock widget, it is floating with a windows size of 1024x768.

Note that the marked event positions are currently not synchronized with the display, this still has to be adapted.
parent edc42b8c
......@@ -66,10 +66,13 @@ WGEViewer::WGEViewer( std::string name, osg::ref_ptr<osg::Referenced> wdata, int
case( WGECamera::PERSPECTIVE ):
// camera manipulator
m_View->setCameraManipulator( new WGEZoomTrackballManipulator() );
m_View->setLightingMode( osg::View::HEADLIGHT ); // this is the default anyway
m_pickHandler = new WPickHandler();
m_View->addEventHandler( m_pickHandler );
break;
case( WGECamera::TWO_D ):
m_View->setCameraManipulator( new WGE2DManipulator() );
m_markHandler = new WMarkHandler();
m_View->addEventHandler( m_markHandler );
break;
......@@ -79,11 +82,6 @@ WGEViewer::WGEViewer( std::string name, osg::ref_ptr<osg::Referenced> wdata, int
// add the stats handler
m_View->addEventHandler( new osgViewer::StatsHandler );
m_View->setLightingMode( osg::View::HEADLIGHT ); // this is the default anyway
m_pickHandler = new WPickHandler();
m_View->addEventHandler( m_pickHandler );
}
catch( ... )
{
......@@ -142,6 +140,8 @@ void WGEViewer::setBgColor( WColor bgColor )
void WGEViewer::resize( int width, int height )
{
m_View->getEventQueue()->windowResize( 0, 0, width, height );
WGEGraphicsWindow::resize( width, height );
// also update the camera
......
......@@ -56,7 +56,7 @@
#include "../../modules/data/WMData.h"
#include "../../modules/navSlices/WMNavSlices.h"
#include "../../dataHandler/WEEG.h"
#include "../../dataHandler/WEEG2.h"
#include "../../dataHandler/WDataSetSingle.h"
#include "../../dataHandler/WDataSetFibers.h"
......@@ -237,9 +237,9 @@ void WMainWindow::moduleSpecificSetup( boost::shared_ptr< WModule > module )
// it is a fiber dataset -> add the FiberDisplay module
autoAdd( module, "Fiber Display" );
}
else if ( dataModule->getDataSet()->isA< WEEG >() )
else if ( dataModule->getDataSet()->isA< WEEG2 >() )
{
// it is a eeg dataset -> add the eegView module?
// it is a eeg dataset -> add the eegView module
autoAdd( module, "EEG View" );
}
}
......
......@@ -35,6 +35,8 @@ WQtCustomDockWidget::WQtCustomDockWidget( std::string title, QWidget* parent, WG
{
// setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea );
setFeatures( QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable );
setFloating( true );
resize( 1024, 768 );
m_glWidget = boost::shared_ptr< WQtGLWidget >( new WQtGLWidget( title, this, projectionMode ) );
m_glWidget->initialize();
......
//---------------------------------------------------------------------------
//
// 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 <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <osgGA/GUIActionAdapter>
#include <osgGA/GUIEventAdapter>
#include "../../common/WPropertyTypes.h"
#include "../../common/WPropertyVariable.h"
#include "WEEGViewHandler.h"
WEEGViewHandler::WEEGViewHandler( WPropInt labelsWidth,
WPropDouble timePos,
WPropDouble timeRange,
WPropInt graphWidth,
WPropDouble yPos,
WPropDouble ySpacing,
WPropDouble ySensitivity )
: m_labelsWidth( labelsWidth ),
m_timePos( timePos ),
m_timeRange( timeRange ),
m_graphWidth( graphWidth ),
m_yPos( yPos ),
m_ySpacing( ySpacing ),
m_ySensitivity( ySensitivity )
{
}
bool WEEGViewHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /*aa*/ )
{
bool handled = false;
switch( ea.getEventType() )
{
case osgGA::GUIEventAdapter::PUSH:
{
if( ea.getButton() == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON
|| ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON )
{
// save old mouse positions for panning and zooming
m_oldX = ea.getX();
m_oldY = ea.getY();
handled = true;
}
break;
}
case osgGA::GUIEventAdapter::DRAG:
{
if( ea.getButtonMask() & ( osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON | osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) )
{
if( ea.getButtonMask() & osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON )
{
// panning
m_timePos->set( m_timePos->get() - ( ea.getX() - m_oldX ) * m_timeRange->get() / m_graphWidth->get() );
m_yPos->set( m_yPos->get() - ( ea.getY() - m_oldY ) );
}
if( ea.getButtonMask() & osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON )
{
// zooming in time
const int labelsWidth = m_labelsWidth->get();
if( labelsWidth < m_oldX && labelsWidth < ea.getX() )
{
m_timeRange->set( m_timeRange->get() * ( ( m_oldX - labelsWidth ) / ( ea.getX() - labelsWidth ) ) );
}
}
// save old mouse positions
m_oldX = ea.getX();
m_oldY = ea.getY();
handled = true;
}
break;
}
case osgGA::GUIEventAdapter::RESIZE:
{
// windows resize
m_graphWidth->set( ea.getWindowWidth() - m_labelsWidth->get() );
handled = true;
break;
}
case osgGA::GUIEventAdapter::SCROLL:
{
float delta;
switch( ea.getScrollingMotion() )
{
case osgGA::GUIEventAdapter::SCROLL_UP:
{
delta = 120.0f;
break;
}
case osgGA::GUIEventAdapter::SCROLL_DOWN:
{
delta = -120.0f;
break;
}
case osgGA::GUIEventAdapter::SCROLL_2D:
{
delta = ea.getScrollingDeltaY();
break;
}
default:
{
delta = 0.0f;
break;
}
}
if( delta != 0.0f )
{
if( ea.getButtonMask() & osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON )
{
// change the spacing of the different graphs
const float addend = -0.001f * delta;
m_ySpacing->set( m_ySpacing->get() * ( 1.0f + addend ) );
// adjust yPos to zoom into the current mouse position
m_yPos->set( m_yPos->get() * ( 1.0f + addend ) + ea.getY() * addend );
}
else
{
// change the sensitivity of the graphs
m_ySensitivity->set( m_ySensitivity->get() * ( 1.0f + 0.001f * delta ) );
}
handled = true;
}
break;
}
default:
{
// do nothing
break;
}
}
return handled;
}
//---------------------------------------------------------------------------
//
// 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 <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WEEGVIEWHANDLER_H
#define WEEGVIEWHANDLER_H
#include <osgGA/GUIActionAdapter>
#include <osgGA/GUIEventAdapter>
#include <osgGA/GUIEventHandler>
#include "../../common/WPropertyTypes.h"
/**
* GUI event handler class used for the 2D EEG view.
*/
class WEEGViewHandler : public osgGA::GUIEventHandler
{
public:
/**
* Constructor
*
* \param labelsWidth the width of the label display in pixel as property
* \param timePos the time position in seconds where to start the graph
* at the left edge as property
* \param timeRange the width of the graph in seconds as property
* \param graphWidth the width of the graph in pixel as property
* \param yPos the y position in pixel at the lower edge as property
* \param ySpacing the distance between two curves of the graph in pixel
* as property
* \param ySensitivity the sensitivity of the graph in microvolt per pixel
* as property
*/
WEEGViewHandler( WPropInt labelsWidth,
WPropDouble timePos,
WPropDouble timeRange,
WPropInt graphWidth,
WPropDouble yPos,
WPropDouble ySpacing,
WPropDouble ySensitivity );
/**
* Handle events.
*
* \param ea event class for storing keyboard, mouse and window events
* \return true if handled, false otherwise
*/
virtual bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /*aa*/ );
protected:
private:
/**
* the width of the label display in pixel as property
*/
WPropInt m_labelsWidth;
/**
* the time position in seconds where to start the graph at the left edge as
* property
*/
WPropDouble m_timePos;
/**
* the width of the graph in seconds as property
*/
WPropDouble m_timeRange;
/**
* the width of the graph in pixel as property
*/
WPropInt m_graphWidth;
/**
* the y position in pixel at the lower edge as property
*/
WPropDouble m_yPos;
/**
* the distance between two curves of the graph in pixel as property
*/
WPropDouble m_ySpacing;
/**
* the sensitivity of the graph in microvolt per pixel as property
*/
WPropDouble m_ySensitivity;
float m_oldX; //!< previous mouse x position
float m_oldY; //!< previous mouse y position
};
#endif // WEEGVIEWHANDLER_H
//---------------------------------------------------------------------------
//
// 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 <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <osg/Matrix>
#include <osg/MatrixTransform>
#include <osg/Node>
#include <osg/NodeVisitor>
#include "../../common/WPropertyTypes.h"
#include "../../common/WPropertyVariable.h"
#include "WLabelsTransformCallback.h"
WLabelsTransformCallback::WLabelsTransformCallback( WPropDouble yPos, WPropDouble ySpacing )
: m_currentYPos( 0.0 ),
m_currentYSpacing( 1.0 ),
m_yPos( yPos ),
m_ySpacing( ySpacing )
{
}
void WLabelsTransformCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
{
const double yPos = m_yPos->get();
const double ySpacing = m_ySpacing->get();
if( yPos != m_currentYPos || ySpacing != m_currentYSpacing )
{
osg::MatrixTransform* transform = static_cast< osg::MatrixTransform* >( node );
if( transform )
{
transform->setMatrix( osg::Matrix::scale( 1.0, ySpacing, 1.0 ) * osg::Matrix::translate( 0.0, -yPos, 0.0 ) );
}
m_currentYPos = yPos;
m_currentYSpacing = ySpacing;
}
traverse( node, nv );
}
//---------------------------------------------------------------------------
//
// 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 <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WLABELSTRANSFORMCALLBACK_H
#define WLABELSTRANSFORMCALLBACK_H
#include <osg/Node>
#include <osg/NodeCallback>
#include <osg/NodeVisitor>
#include "../../common/WPropertyTypes.h"
/**
* OSG Node Callback to update the MatrixTransform Node of the labels used for
* panning and zooming.
*/
class WLabelsTransformCallback : public osg::NodeCallback
{
public:
/**
* Constructor
*
* \param yPos the y position in pixel at the lower edge as property
* \param ySpacing the distance between two curves of the graph in pixel as
* property
*/
WLabelsTransformCallback( WPropDouble yPos, WPropDouble ySpacing );
/**
* Callback method called by the NodeVisitor when visiting a node.
* Change the matrix according to the properties.
*
* \param node The node this callback is connected to. Should be a
* MatrixTransform node.
* \param nv The node visitor which performs the traversal. Should be an
* update visitor.
*/
virtual void operator()( osg::Node* node, osg::NodeVisitor* nv );
protected:
private:
/**
* the y position in pixel at the lower edge which is currently used
*/
double m_currentYPos;
/**
* the distance between two curves of the graph in pixel which is currently
* used
*/
double m_currentYSpacing;
/**
* the y position in pixel at the lower edge as property
*/
WPropDouble m_yPos;
/**
* the distance between two curves of the graph in pixel as property
*/
WPropDouble m_ySpacing;
};
#endif // WLABELSTRANSFORMCALLBACK_H
//---------------------------------------------------------------------------
//
// 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 <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <cmath>
#include <cstddef>
#include <algorithm>
#include <boost/shared_ptr.hpp>
#include <osg/Array>
#include <osg/Drawable>
#include <osg/Geometry>
#include <osg/NodeVisitor>
#include <osg/PrimitiveSet>
#include <osg/Vec3>
#include "../../common/WPropertyTypes.h"
#include "../../common/WPropertyVariable.h"
#include "../../dataHandler/WEEG2Segment.h"
#include "../../dataHandler/WEEGValueMatrix.h"
#include "WLineStripCallback.h"
WLineStripCallback::WLineStripCallback( std::size_t channelID,
WPropDouble timePos,
WPropDouble timeRange,
boost::shared_ptr< WEEG2Segment > segment,
double samplingRate )
: m_channelID( channelID ),
m_currentTimePos( 0.0 ),
m_currentTimeRange( -1.0 ),
m_timePos( timePos ),
m_timeRange( timeRange ),
m_segment( segment ),
m_samplingRate( samplingRate )
{
}
void WLineStripCallback::update( osg::NodeVisitor* /*nv*/, osg::Drawable* drawable )
{
const double timePos = m_timePos->get();
const double timeRange = m_timeRange->get();
if( timePos != m_currentTimePos || timeRange != m_currentTimeRange )
{
osg::Geometry* geometry = static_cast< osg::Geometry* >( drawable );
if( geometry )
{
const std::size_t startSample = timePos * m_samplingRate;
const std::size_t endSample = std::ceil( ( timePos + timeRange ) * m_samplingRate ) + 1;
const std::size_t currentStartSample = m_currentTimePos * m_samplingRate;
const std::size_t currentEndSample = ( 0.0 <= m_currentTimeRange ) ?
std::ceil( ( m_currentTimePos + m_currentTimeRange ) * m_samplingRate ) + 1 :
currentStartSample;
osg::Vec3Array* vertices = new osg::Vec3Array();
vertices->reserve( endSample - startSample );
// load the values before the current vertices from WEEG
std::size_t start = startSample;
std::size_t end = std::min( endSample, currentStartSample );
if( start < end )
{
const std::size_t length = end - start;
boost::shared_ptr< const WEEGValueMatrix > values = m_segment->getValues( start, length );
for( std::size_t i = 0; i < length; ++i )
{
vertices->push_back( osg::Vec3( ( start + i ) / m_samplingRate, (*values)[m_channelID][i], 0.0 ) );
}
}
// copy the values from the current vertices
start = std::max( startSample, currentStartSample );
end = std::min( endSample, currentEndSample );
if( start < end )
{
const osg::Vec3Array* currentVertices = static_cast< osg::Vec3Array* >( geometry->getVertexArray() );
vertices->insert( vertices->end(),
currentVertices->begin() + ( start - currentStartSample ),
currentVertices->begin() + ( end - currentStartSample ) );
}
// load the values after the current vertices from WEEG
start = std::max( startSample, currentEndSample );
end = endSample;
if( start < end )
{
const std::size_t length = end - start;
boost::shared_ptr< const WEEGValueMatrix > values = m_segment->getValues( start, length );
for( std::size_t i = 0; i < length; ++i )
{