diff --git a/.gitsubprojects b/.gitsubprojects index d2c6037390be2097ffc268e75b8f8236daf9ab93..829f7db019ccc541c7d0160585d850591e544a80 100644 --- a/.gitsubprojects +++ b/.gitsubprojects @@ -6,4 +6,4 @@ git_subproject(neurolots https://github.com/gmrvvis/neurolots.git f8ea6d1e) git_subproject(ReTo https://github.com/gmrvvis/ReTo.git 211c49a) git_subproject(acuterecorder https://github.com/vg-lab/AcuteRecorder.git 0b84c2b1) -#git_subproject( SimIL https://github.com/gmrvvis/SimIL.git 1921f818 ) +#git_subproject( SimIL https://github.com/gmrvvis/SimIL.git a1b1be1d) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6869902bec97188a281e30291ed1a68e531a89f4..d419c375649aa7d922e667c448564063ef0d78bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # cmake_minimum_required(VERSION 3.1 FATAL_ERROR) -project(NeuroTessMesh VERSION 0.4.0) +project(NeuroTessMesh VERSION 0.4.1) set(NeuroTessMesh_VERSION_ABI 1) # Disable in source building diff --git a/neurotessmesh/LoaderThread.cpp b/neurotessmesh/LoaderThread.cpp index c65474680fa31675a97703daab7ad786839fd0e9..b2fe37bd090cd034765bfaa99facbb89b1d042fa 100644 --- a/neurotessmesh/LoaderThread.cpp +++ b/neurotessmesh/LoaderThread.cpp @@ -24,10 +24,16 @@ // deps #include <nsol/nsol.h> + #ifdef NEUROTESSMESH_USE_SIMIL - #include <simil/simil.h> + +#include <simil/simil.h> + #endif +#include <Eigen/Geometry> +#include <Eigen/Eigen> + // Qt #include <QString> #include <QFileInfo> @@ -37,115 +43,259 @@ using namespace neurotessmesh; -LoaderThread::LoaderThread(const std::string &arg1, const std::string &arg2, - const LoaderThread::DataFileType type) -: QThread() -, m_fileName{arg1} -, m_target{arg2} -, m_type{type} -, m_dataset{nullptr} -, m_player{nullptr} +LoaderThread::LoaderThread( const std::string& arg1 , const std::string& arg2 , + const LoaderThread::DataFileType type ) + : QThread( ) + , m_fileName{ arg1 } + , m_target{ arg2 } + , m_type{ type } + , m_dataset{ nullptr } + , m_player{ nullptr } { } -void LoaderThread::run() +void LoaderThread::run( ) { try { - m_dataset = new nsol::DataSet(); - QFileInfo fi(QString::fromStdString(m_fileName)); - emit progress(QString("Loading %1").arg(fi.fileName()), 10); + m_dataset = new nsol::DataSet( ); + QFileInfo fi( QString::fromStdString( m_fileName )); + emit progress( QString( "Loading %1" ).arg( fi.fileName( )) , 10 ); - switch(m_type) + switch ( m_type ) { - case DataFileType::BlueConfig: + case DataFileType::BlueConfig: #ifdef NSOL_USE_BRION - emit progress(tr("Loading Hierarchy"), 25); - - m_dataset->loadBlueConfigHierarchy< nsol::Node, - nsol::NeuronMorphologySection, - nsol::Dendrite, - nsol::Axon, - nsol::Soma, - nsol::NeuronMorphology, - nsol::Neuron, - nsol::MiniColumn, - nsol::Column >( m_fileName, m_target ); - - emit progress(tr("Loading Morphologies"), 50); - - m_dataset->loadAllMorphologies< nsol::Node, - nsol::NeuronMorphologySection, - nsol::Dendrite, - nsol::Axon, - nsol::Soma, - nsol::NeuronMorphology, - nsol::Neuron, - nsol::MiniColumn, - nsol::Column >( ); - - emit progress(tr("Loading Spikes"), 75); + emit progress( tr( "Loading Hierarchy" ) , 25 ); + + m_dataset->loadBlueConfigHierarchy< nsol::Node , + nsol::NeuronMorphologySection , + nsol::Dendrite , + nsol::Axon , + nsol::Soma , + nsol::NeuronMorphology , + nsol::Neuron , + nsol::MiniColumn , + nsol::Column >( m_fileName , m_target ); + + emit progress( tr( "Loading Morphologies" ) , 50 ); + + m_dataset->loadAllMorphologies< nsol::Node , + nsol::NeuronMorphologySection , + nsol::Dendrite , + nsol::Axon , + nsol::Soma , + nsol::NeuronMorphology , + nsol::Neuron , + nsol::MiniColumn , + nsol::Column >( ); + + emit progress( tr( "Loading Spikes" ) , 75 ); #ifdef NEUROTESSMESH_USE_SIMIL - { // load the spikes data with SimIL, only for blueconfig. - auto spikesData = new simil::SpikeData(m_fileName, simil::TDataType::TBlueConfig, m_target); - spikesData->reduceDataToGIDS(); + { // load the spikes data with SimIL, only for blueconfig. + auto spikesData = new simil::SpikeData( m_fileName , + simil::TDataType::TBlueConfig , + m_target ); + spikesData->reduceDataToGIDS( ); - m_player = new simil::SpikesPlayer( ); - m_player->LoadData( spikesData ); - } + m_player = new simil::SpikesPlayer( ); + m_player->LoadData( spikesData ); + } #endif #else - std::cerr << "Error: Brion support not built-in" << std::endl; + std::cerr << "Error: Brion support not built-in" << std::endl; +#endif + break; + + case DataFileType::SWC: + emit progress( tr( "Loading Neuron" ) , 50 ); + m_dataset->loadNeuronFromFile< nsol::Node , + nsol::NeuronMorphologySection , + nsol::Dendrite , + nsol::Axon , + nsol::Soma , + nsol::NeuronMorphology , + nsol::Neuron >( m_fileName , 1 ); + break; + + case DataFileType::NsolScene: + emit progress( tr( "Loading Scene" ) , 50 ); + m_dataset->loadXmlScene< nsol::Node , + nsol::NeuronMorphologySection , + nsol::Dendrite , + nsol::Axon , + nsol::Soma , + nsol::NeuronMorphology , + nsol::Neuron >( m_fileName ); + break; + + case DataFileType::HDF5: +#ifdef NEUROTESSMESH_USE_SIMIL + loadH5Morphology( ); #endif - break; - - case DataFileType::SWC: - emit progress(tr("Loading Neuron"), 50); - m_dataset->loadNeuronFromFile< nsol::Node, - nsol::NeuronMorphologySection, - nsol::Dendrite, - nsol::Axon, - nsol::Soma, - nsol::NeuronMorphology, - nsol::Neuron >( m_fileName, 1 ); - break; - - case DataFileType::NsolScene: - emit progress(tr("Loading Scene"), 50); - m_dataset->loadXmlScene< nsol::Node, - nsol::NeuronMorphologySection, - nsol::Dendrite, - nsol::Axon, - nsol::Soma, - nsol::NeuronMorphology, - nsol::Neuron >( m_fileName ); - break; - - default: - throw std::runtime_error( "Data file type not supported" ); + break; + + default: + throw std::runtime_error( "Data file type not supported" ); } - emit progress("Generating Meshes", 100); + emit progress( "Generating Meshes" , 100 ); + + } + catch ( const std::exception& e ) + { + delete m_dataset; + m_errors = QString::fromStdString( e.what( )); + } +} + +#ifdef NEUROTESSMESH_USE_SIMIL +uint8_t LoaderThread::getTypeFromLoaderType( const NeuronType& type ) +{ + switch ( type ) + { + case NeuronType::GRANULE_CELL: + return nsol::Neuron::GRANULE; + case NeuronType::GOLGI_CELL: + return nsol::Neuron::GOLGI; + case NeuronType::PURKINJE_CELL: + return nsol::Neuron::PURKINJE; + case NeuronType::STELLATE_CELL: + return nsol::Neuron::STELLATE; + case NeuronType::BASKET_CELL: + return nsol::Neuron::BASKET; + } + return nsol::Neuron::UNDEFINED; +} + +void LoaderThread::loadH5Morphology( ) +{ + H5Morphologies loader( m_fileName , "" ); + loader.load( ); + + std::map< NeuronType , nsol::NeuronMorphology* > morphologiesByType; + + uint32_t neuronId = 0; + for ( const auto& pair: loader.getMorphologies( )) + { + auto& neuron = pair.second; + + auto* soma = new nsol::Soma( ); + auto* morphology = new nsol::NeuronMorphology( soma ); + + std::vector< nsol::NeuronMorphologySection* > sections; + sections.resize( neuron.neurites.size( )); + + for ( uint32_t id = 0; id < neuron.neurites.size( ); ++id ) + { + auto& item = neuron.neurites[ id ]; + if ( item.type == MorphologyType::SOMA ) + { + for ( uint32_t i = 0; i < item.radii.size( ); ++i ) + { + soma->addNode( new nsol::Node( + nsol::Vec3f( + static_cast< float >(item.x[ i ]) , + static_cast< float >(item.y[ i ]) , + static_cast< float >(item.z[ i ]) + ) , + 0 , + static_cast< float >(item.radii[ i ]) + )); + } + } + else + { + auto* section = new nsol::NeuronMorphologySection( ); + sections[ id ] = section; + + if ( item.radii.empty( )) + { + std::cout << "WARNING! Neurite " << id << " has no nodes!" + << std::endl; + section->addNode( new nsol::Node( + nsol::Vec3f( 0.0f , 0.0f , 0.0f ) , 0 , 0.0f + )); + } + + // Add nodes + for ( uint32_t i = 0; i < item.radii.size( ); ++i ) + { + section->addNode( new nsol::Node( + nsol::Vec3f( + static_cast< float >(item.x[ i ]) , + static_cast< float >(item.y[ i ]) , + static_cast< float >(item.z[ i ]) + ) , + 0 , + static_cast< float >(item.radii[ i ]) + )); + } + + auto parentType = neuron.neurites[ item.parent ].type; + if ( parentType == item.type ) + { + auto* parent = sections[ item.parent ]; + if ( parent != nullptr ) + { + section->parent( parent ); + parent->addChild( section ); + } + else + { + std::cout << "WARNING! Neurite " << id << " has no nodes!" + << std::endl; + } + } + else + { + nsol::Neurite* neurite; + if ( item.type == MorphologyType::AXON ) neurite = new nsol::Axon( ); + else neurite = new nsol::Dendrite( ); + neurite->firstSection( section ); + morphology->addNeurite( neurite ); + } + } + } + morphologiesByType[ pair.first ] = morphology; } - catch(const std::exception &e) + + for ( const auto& neuron: loader.getNeurons( )) { - if(m_dataset) delete m_dataset; - m_errors = QString::fromStdString(e.what()); + auto morphology = morphologiesByType[ neuron.type ]; + + Eigen::Affine3f transform(Eigen::Translation3f(neuron.x, neuron.y, neuron.z)); + + + auto* result = new nsol::Neuron( + morphology , + 0 , + neuronId++ , + transform.matrix(), + nullptr , + static_cast<nsol::Neuron::TMorphologicalType>( + getTypeFromLoaderType( neuron.type )) , + nsol::Neuron::UNDEFINED_FUNCTIONAL_TYPE + ); + + m_dataset->addNeuron( result ); } } +#endif + LoadingDialog::LoadingDialog( QWidget* p ) : QDialog( p , Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint ) { - setWindowIcon(QIcon( ":/icons/rsc/neurotessmesh.png" )); + setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" )); auto layout = new QVBoxLayout( ); m_progress = new QProgressBar( this ); m_progress->setMinimumWidth( 590 ); - m_progress->setValue(0); - m_progress->setFormat(""); + m_progress->setValue( 0 ); + m_progress->setFormat( "" ); layout->addWidget( m_progress , 1 , Qt::AlignHCenter | Qt::AlignVCenter ); layout->setMargin( 4 ); setLayout( layout ); @@ -155,14 +305,15 @@ LoadingDialog::LoadingDialog( QWidget* p ) setFixedSize( 600 , sizeHint( ).height( )); } -void LoadingDialog::progress( const QString& message , const unsigned int value ) +void +LoadingDialog::progress( const QString& message , const unsigned int value ) { m_progress->setValue( value ); if ( !message.isEmpty( )) m_progress->setFormat( tr( "%1 - %p%" ).arg( message )); else - m_progress->setFormat("%p%"); + m_progress->setFormat( "%p%" ); } void LoadingDialog::closeDialog( ) diff --git a/neurotessmesh/LoaderThread.h b/neurotessmesh/LoaderThread.h index 153772e8032ffa929aa9fc1ba9c4760468697378..d00df883032c2050c8f417b6a3525e79c8ce5572 100644 --- a/neurotessmesh/LoaderThread.h +++ b/neurotessmesh/LoaderThread.h @@ -28,8 +28,11 @@ #include <QDialog> class QString; + class QProgressBar; +enum class NeuronType; + namespace nsol { class DataSet; @@ -47,96 +50,103 @@ namespace neurotessmesh * */ class LoaderThread - : public QThread + : public QThread { - Q_OBJECT - public: - enum class DataFileType - { BlueConfig, SWC, NsolScene }; - - /** \brief LoaderThread class constructor. - * \param[in] arg1 Dataset filename. - * \param[in] arg1 Blueconfig target. - * \param[in] type Dataset type. - * - */ - explicit LoaderThread(const std::string &arg1, const std::string &arg2, - const DataFileType type); - - /** \brief LoaderThread class virtual destructor. - * - */ - virtual ~LoaderThread() - {}; - - /** \brief Returns the dataset. - * - */ - nsol::DataSet *getDataset() const - { return m_dataset; } - - /** \brief Returns the spikes player. - * - */ - simil::SpikesPlayer *getPlayer() const - { return m_player; } - - virtual void run(); - - /** \brief Returns the error description or empty if none. - * - */ - QString errors() const - { return m_errors; } - - signals: - void progress(const QString &text, const unsigned int value); - - private: - const std::string m_fileName; /** name of file to load. */ - const std::string m_target; /** blueconfig target. */ - const DataFileType m_type; /** type of file to load. */ - - nsol::DataSet *m_dataset; /** nsol dataset with data. */ - simil::SpikesPlayer *m_player; /** spikes data or null if none. */ - - QString m_errors; + Q_OBJECT + public: + enum class DataFileType + { + BlueConfig , SWC , NsolScene , HDF5 + }; + + /** \brief LoaderThread class constructor. + * \param[in] arg1 Dataset filename. + * \param[in] arg1 Blueconfig target. + * \param[in] type Dataset type. + * + */ + explicit LoaderThread( const std::string& arg1 , const std::string& arg2 , + const DataFileType type ); + + /** \brief LoaderThread class virtual destructor. + * + */ + virtual ~LoaderThread( ) + { }; + + /** \brief Returns the dataset. + * + */ + nsol::DataSet* getDataset( ) const + { return m_dataset; } + + /** \brief Returns the spikes player. + * + */ + simil::SpikesPlayer* getPlayer( ) const + { return m_player; } + + virtual void run( ); + + /** \brief Returns the error description or empty if none. + * + */ + QString errors( ) const + { return m_errors; } + + signals: + + void progress( const QString& text , const unsigned int value ); + + private: + const std::string m_fileName; /** name of file to load. */ + const std::string m_target; /** blueconfig target. */ + const DataFileType m_type; /** type of file to load. */ + + nsol::DataSet* m_dataset; /** nsol dataset with data. */ + simil::SpikesPlayer* m_player; /** spikes data or null if none. */ + + QString m_errors; + + uint8_t getTypeFromLoaderType( const NeuronType& type ); + + void loadH5Morphology( ); }; class LoadingDialog : public QDialog { - Q_OBJECT - public: - /** \brief LoadingDialog class constructor. - * \param[in] p Raw pointer of the widget parent of this one. - * \param[in] f QDialog flags. - * - */ - explicit LoadingDialog( QWidget* p = nullptr ); - - /** \brief LoadingDialog class virtual destructor. - * - */ - virtual ~LoadingDialog( ) - { }; - - public slots: - - /** \brief Updates the dialog with the message and progress value - * \param[in] message Progress message. - * \param[in] value Progress value in [0,100]. - * - */ - void progress( const QString& message , const unsigned int value ); - - /** \brief Closes and deletes the dialog. - * - */ - void closeDialog( ); - - private: - QProgressBar* m_progress; /** progress bar. */ + Q_OBJECT + public: + /** \brief LoadingDialog class constructor. + * \param[in] p Raw pointer of the widget parent of this one. + * \param[in] f QDialog flags. + * + */ + explicit LoadingDialog( QWidget* p = nullptr ); + + /** \brief LoadingDialog class virtual destructor. + * + */ + virtual ~LoadingDialog( ) + { }; + + public slots: + + /** \brief Updates the dialog with the message and progress value + * \param[in] message Progress message. + * \param[in] value Progress value in [0,100]. + * + */ + void progress( const QString& message , const unsigned int value ); + + /** \brief Closes and deletes the dialog. + * + */ + void closeDialog( ); + + private: + QProgressBar* m_progress; /** progress bar. */ }; } diff --git a/neurotessmesh/MainWindow.cpp b/neurotessmesh/MainWindow.cpp index 06c0402cef85ac8ffdc1b0de1d394a62e8107eaa..075575f94e5eb956b1c635756e6e339b96cc1f1e 100644 --- a/neurotessmesh/MainWindow.cpp +++ b/neurotessmesh/MainWindow.cpp @@ -23,9 +23,12 @@ #endif #include <acuterecorder/acuterecorder.h> + #ifdef NEUROTESSMESH_USE_SIMIL - #include <qsimil/qsimil.h> - #include <simil/simil.h> + +#include <qsimil/qsimil.h> +#include <simil/simil.h> + #endif #include <QFileDialog> @@ -57,7 +60,7 @@ MainWindow::MainWindow( QWidget* parent_ , bool updateOnIdle_ ) _ui->toolBar->addAction( recorderAction ); connect( recorderAction , SIGNAL( triggered( bool )) , - this , SLOT( openRecorder( ))); + this , SLOT( openRecorder( )) ); _ui->actionUpdateOnIdle->setChecked( updateOnIdle_ ); _ui->actionShowFPSOnIdleUpdate->setChecked( false ); @@ -75,10 +78,10 @@ MainWindow::MainWindow( QWidget* parent_ , bool updateOnIdle_ ) #endif connect( _ui->actionQuit , SIGNAL( triggered( )) , - QApplication::instance( ) , SLOT( quit( ))); + QApplication::instance( ) , SLOT( quit( )) ); connect( _ui->actionAbout , SIGNAL( triggered( )) , - this , SLOT( showAbout( ))); + this , SLOT( showAbout( )) ); _openGLWidget = new OpenGLWidget( ); this->setCentralWidget( _openGLWidget ); @@ -114,78 +117,86 @@ void MainWindow::init( const std::string& zeqSession_ ) _openGLWidget->setZeqSession( zeqSession_ ); connect( _ui->actionHome , SIGNAL( triggered( )) , - this , SLOT( home( ))); + this , SLOT( home( )) ); connect( _ui->actionUpdateOnIdle , SIGNAL( triggered( )) , - _openGLWidget , SLOT( toggleUpdateOnIdle( ))); + _openGLWidget , SLOT( toggleUpdateOnIdle( )) ); connect( _ui->actionShowFPSOnIdleUpdate , SIGNAL( triggered( )) , - _openGLWidget , SLOT( toggleShowFPS( ))); + _openGLWidget , SLOT( toggleShowFPS( )) ); connect( _ui->actionWireframe , SIGNAL( triggered( )) , - _openGLWidget , SLOT( toggleWireframe( ))); + _openGLWidget , SLOT( toggleWireframe( )) ); connect( _ui->actionOpenBlueConfig , SIGNAL( triggered( )) , - this , SLOT( openBlueConfigThroughDialog( ))); + this , SLOT( openBlueConfigThroughDialog( )) ); connect( _ui->actionOpenXMLScene , SIGNAL( triggered( )) , - this , SLOT( openXMLSceneThroughDialog( ))); + this , SLOT( openXMLSceneThroughDialog( )) ); connect( _ui->actionOpenSWCFile , SIGNAL( triggered( )) , - this , SLOT( openSWCFileThroughDialog( ))); + this , SLOT( openSWCFileThroughDialog( )) ); + + connect( _ui->actionOpenHDF5File , SIGNAL( triggered( )) , + this , SLOT( openHDF5FileThroughDialog( )) ); connect( _radiusSlider , SIGNAL( valueChanged( int )) , - this , SLOT( onActionGenerate( int ))); + this , SLOT( onActionGenerate( int )) ); connect( _extractButton , SIGNAL( clicked( )) , - _openGLWidget , SLOT( extractEditNeuronMesh( ))); + _openGLWidget , SLOT( extractEditNeuronMesh( )) ); connect( _lotSlider , SIGNAL( valueChanged( int )) , - _openGLWidget , SLOT( onLotValueChanged( int ))); + _openGLWidget , SLOT( onLotValueChanged( int )) ); _lotSlider->valueChanged( _lotSlider->value( )); connect( _distanceSlider , SIGNAL( valueChanged( int )) , - _openGLWidget , SLOT( onDistanceValueChanged( int ))); + _openGLWidget , SLOT( onDistanceValueChanged( int )) ); _distanceSlider->valueChanged( _distanceSlider->value( )); connect( _radioHomogeneous , SIGNAL( clicked( )) , - _openGLWidget , SLOT( onHomogeneousClicked( ))); + _openGLWidget , SLOT( onHomogeneousClicked( )) ); connect( _radioLinear , SIGNAL( clicked( )) , - _openGLWidget , SLOT( onLinearClicked( ))); + _openGLWidget , SLOT( onLinearClicked( )) ); _radioLinear->clicked( ); connect( _neuronRender , SIGNAL( currentIndexChanged( int )) , - _openGLWidget , SLOT( changeNeuronPiece( int ))); + _openGLWidget , SLOT( changeNeuronPiece( int )) ); _neuronRender->currentIndexChanged( 1 ); connect( _selectedNeuronRender , SIGNAL( currentIndexChanged( int )) , - _openGLWidget , SLOT( changeSelectedNeuronPiece( int ))); + _openGLWidget , SLOT( changeSelectedNeuronPiece( int )) ); _selectedNeuronRender->currentIndexChanged( 0 ); connect( _ui->actionLoad_camera_positions , SIGNAL( triggered( bool )) , this , - SLOT( loadCameraPositions( ))); + SLOT( loadCameraPositions( )) ); connect( _ui->actionSave_camera_positions , SIGNAL( triggered( bool )) , this , - SLOT( saveCameraPositions( ))); + SLOT( saveCameraPositions( )) ); connect( _ui->actionAdd_camera_position , SIGNAL( triggered( bool )) , this , - SLOT( addCameraPosition( ))); + SLOT( addCameraPosition( )) ); connect( _ui->actionRemove_camera_position , SIGNAL( triggered( bool )) , this , - SLOT( removeCameraPosition( ))); + SLOT( removeCameraPosition( )) ); connect( _backGroundColor , SIGNAL( colorChanged( QColor )) , - _openGLWidget , SLOT( changeClearColor( QColor ))); + _openGLWidget , SLOT( changeClearColor( QColor )) ); connect( _neuronColor , SIGNAL( colorChanged( QColor )) , - _openGLWidget , SLOT( changeNeuronColor( QColor ))); + _openGLWidget , SLOT( changeNeuronColor( QColor )) ); connect( _selectedNeuronColor , SIGNAL( colorChanged( QColor )) , - _openGLWidget , SLOT( changeSelectedNeuronColor( QColor ))); + _openGLWidget , SLOT( changeSelectedNeuronColor( QColor )) ); + + +#ifndef NEUROTESSMESH_USE_SIMIL + _ui->actionOpenHDF5File->setEnabled( false ); +#endif } void MainWindow::showStatusBarMessage( const QString& message ) @@ -212,6 +223,12 @@ void MainWindow::openSWCFile( const std::string& fileName ) neurotessmesh::LoaderThread::DataFileType::SWC ); } +void MainWindow::openHDF5File( const std::string& fileName ) +{ + loadData( fileName , std::string( ) , + neurotessmesh::LoaderThread::DataFileType::HDF5 ); +} + void MainWindow::updateNeuronList( ) { _neuronList->clear( ); @@ -219,7 +236,8 @@ void MainWindow::updateNeuronList( ) for ( const auto& id: ids ) { - _neuronList->addItem( QString::number( id )); + auto item = new NeuronListItem(id); + _neuronList->addItem(item); } } @@ -237,23 +255,23 @@ void MainWindow::openBlueConfigThroughDialog( ) #ifdef NSOL_USE_BRION QString path = QFileDialog::getOpenFileName( - this, tr( "Open BlueConfig" ), _lastOpenedFileName, - tr( "BlueConfig ( BlueConfig CircuitConfig);; All files (*)" ), - nullptr, QFileDialog::DontUseNativeDialog ); + this , tr( "Open BlueConfig" ) , _lastOpenedFileName , + tr( "BlueConfig ( BlueConfig CircuitConfig);; All files (*)" ) , + nullptr , QFileDialog::DontUseNativeDialog ); - if (path != QString( "" )) + if ( path != QString( "" )) { bool ok; QString text = QInputDialog::getText( - this, tr( "Please select target" ), - tr( "Cell target:" ), QLineEdit::Normal, - "Column", &ok ); + this , tr( "Please select target" ) , + tr( "Cell target:" ) , QLineEdit::Normal , + "Column" , &ok ); if ( ok && !text.isEmpty( )) { std::string targetLabel = text.toStdString( ); - _lastOpenedFileName = QFileInfo(path).path( ); + _lastOpenedFileName = QFileInfo( path ).path( ); std::string fileName = path.toStdString( ); - openBlueConfig( fileName, targetLabel ); + openBlueConfig( fileName , targetLabel ); } } #endif @@ -290,6 +308,20 @@ void MainWindow::openSWCFileThroughDialog( ) } } +void MainWindow::openHDF5FileThroughDialog( ) +{ + QString path = QFileDialog::getOpenFileName( + this , tr( "Open HD5 File" ) , _lastOpenedFileName , + tr( "hdf5 ( *.hdf5);; All files (*)" ) , nullptr , + QFileDialog::DontUseNativeDialog ); + + if ( path != QString( "" )) + { + std::string fileName = path.toStdString( ); + openHDF5File( fileName ); + } +} + void MainWindow::showAbout( ) { @@ -314,7 +346,7 @@ void MainWindow::showAbout( ) tr( " (" ) + tr( std::to_string( brion::Version::getRevision( )).c_str( )) + tr( ")" ) + - tr ( "</li> " ) + + tr( "</li> " ) + #endif #ifdef NEUROLOTS_USE_ZEROEQ tr( "<li>ZEQ " ) + @@ -394,9 +426,9 @@ void MainWindow::openRecorder( ) { _recorder = dialog.getRecorder( ); connect( _recorder , SIGNAL( finished( )) , - _recorder , SLOT( deleteLater( ))); + _recorder , SLOT( deleteLater( )) ); connect( _recorder , SIGNAL( finished( )) , - this , SLOT( finishRecording( ))); + this , SLOT( finishRecording( )) ); if ( action ) action->setChecked( true ); } else @@ -622,7 +654,7 @@ void MainWindow::loadCameraPositions( ) position + ";" + radius + ";" + rotation ); connect( action , SIGNAL( triggered( bool )) , - this , SLOT( applyCameraPosition( ))); + this , SLOT( applyCameraPosition( )) ); _ui->actionCamera_Positions->menu( )->addAction( action ); }; @@ -762,6 +794,8 @@ void MainWindow::addCameraPosition( ) QLineEdit::Normal , tr( "New position" ) , &ok ); + if(!ok) return; + if ( ok && !name.isEmpty( )) { QString tempName( name ); @@ -782,7 +816,7 @@ void MainWindow::addCameraPosition( ) action->setProperty( POSITION_KEY , position.toString( )); connect( action , SIGNAL( triggered( bool )) , - this , SLOT( applyCameraPosition( ))); + this , SLOT( applyCameraPosition( )) ); _ui->actionCamera_Positions->menu( )->addAction( action ); _ui->actionCamera_Positions->setEnabled( true ); _ui->actionSave_camera_positions->setEnabled( true ); @@ -838,7 +872,7 @@ void MainWindow::_generateNeuritesLayout( ) _neuriteSliders.clear( ); - QLayoutItem * child; + QLayoutItem* child; while (( child = _neuritesLayout->takeAt( 0 )) != 0 ) { delete child->widget( ); @@ -865,7 +899,7 @@ void MainWindow::_generateNeuritesLayout( ) _neuritesLayout->addWidget( _neuriteSlider ); _neuriteSliders.push_back( _neuriteSlider ); connect( _neuriteSlider , SIGNAL( valueChanged( int )) , - this , SLOT( onActionGenerate( int ))); + this , SLOT( onActionGenerate( int )) ); } _radiusSlider->setValue( 100 ); } @@ -900,6 +934,7 @@ void MainWindow::_initExtractionDock( ) _meshDockLayout->addWidget( _neuronsGroup ); _neuronList = new QListWidget( ); + _neuronList->setSortingEnabled(true); _neuronsLayout->addWidget( new QLabel( QString( "Neurons" ))); _neuronsLayout->addWidget( _neuronList ); @@ -941,13 +976,13 @@ void MainWindow::_initExtractionDock( ) _meshDockLayout->addWidget( _extractButton ); connect( _neuronList , SIGNAL( itemClicked( QListWidgetItem * )) , - this , SLOT( onListClicked( QListWidgetItem * ))); + this , SLOT( onListClicked( QListWidgetItem * )) ); connect( _extractMeshDock->toggleViewAction( ) , SIGNAL( toggled( bool )) , - _ui->actionEditSave , SLOT( setChecked( bool ))); + _ui->actionEditSave , SLOT( setChecked( bool )) ); connect( _ui->actionEditSave , SIGNAL( triggered( )) , - this , SLOT( updateExtractMeshDock( ))); + this , SLOT( updateExtractMeshDock( )) ); } @@ -1017,13 +1052,13 @@ void MainWindow::_initConfigurationDock( ) _radioLinear->setChecked( true ); connect( _radioLinear , SIGNAL( toggled( bool )) , - _distanceSlider , SLOT( setEnabled( bool ))); + _distanceSlider , SLOT( setEnabled( bool )) ); connect( _configurationDock->toggleViewAction( ) , SIGNAL( toggled( bool )) , - _ui->actionConfiguration , SLOT( setChecked( bool ))); + _ui->actionConfiguration , SLOT( setChecked( bool )) ); connect( _ui->actionConfiguration , SIGNAL( triggered( )) , - this , SLOT( updateConfigurationDock( ))); + this , SLOT( updateConfigurationDock( )) ); } void MainWindow::_initRenderOptionsDock( ) @@ -1093,10 +1128,10 @@ void MainWindow::_initRenderOptionsDock( ) _selectedNeuronRender->addItem( QString( "neurites" )); connect( _renderOptionsDock->toggleViewAction( ) , SIGNAL( toggled( bool )) , - _ui->actionRenderOptions , SLOT( setChecked( bool ))); + _ui->actionRenderOptions , SLOT( setChecked( bool )) ); connect( _ui->actionRenderOptions , SIGNAL( triggered( )) , - this , SLOT( updateRenderOptionsDock( ))); + this , SLOT( updateRenderOptionsDock( )) ); } void MainWindow::closeEvent( QCloseEvent* e ) @@ -1134,8 +1169,9 @@ void MainWindow::_initPlayerDock( ) _playerDock->setFeatures( QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable ); - _playerDock->setAllowedAreas(Qt::DockWidgetAreas::enum_type::BottomDockWidgetArea| - Qt::DockWidgetAreas::enum_type::TopDockWidgetArea); + _playerDock->setAllowedAreas( + Qt::DockWidgetAreas::enum_type::BottomDockWidgetArea | + Qt::DockWidgetAreas::enum_type::TopDockWidgetArea ); _playerDock->setWindowTitle( QString( "Player Options" )); _playerDock->show( ); _playerDock->close( ); @@ -1145,13 +1181,13 @@ void MainWindow::_initPlayerDock( ) _playerDock->setWidget( playerControls ); connect( playerControls , SIGNAL( frame( )) , - _openGLWidget , SLOT( update( ))); + _openGLWidget , SLOT( update( )) ); connect( _playerDock->toggleViewAction( ) , SIGNAL( toggled( bool )) , - _ui->actionSimulation_player_options , SLOT( setChecked( bool ))); + _ui->actionSimulation_player_options , SLOT( setChecked( bool )) ); connect( _ui->actionSimulation_player_options , SIGNAL( triggered( )) , - this , SLOT( updatePlayerOptionsDock( ))); + this , SLOT( updatePlayerOptionsDock( )) ); #endif } @@ -1168,11 +1204,11 @@ void MainWindow::loadData( const std::string& arg1 , const std::string& arg2 , this , SLOT( onDataLoaded( )) , Qt::QueuedConnection ); connect( m_dataLoader.get( ) , SIGNAL( destroyed( QObject * )) , - dialog , SLOT( closeDialog( ))); + dialog , SLOT( closeDialog( )) ); connect( m_dataLoader.get( ) , SIGNAL( progress(const QString & , const unsigned int)) , - dialog , SLOT( progress(const QString & , const unsigned int))); + dialog , SLOT( progress(const QString & , const unsigned int)) ); dialog->show( ); @@ -1198,7 +1234,7 @@ void MainWindow::onDataLoaded( ) try { - _openGLWidget->makeCurrent(); + _openGLWidget->makeCurrent( ); _openGLWidget->update( ); _scene = std::make_shared< neurotessmesh::Scene >( @@ -1206,7 +1242,7 @@ void MainWindow::onDataLoaded( ) #ifdef NEUROTESSMESH_USE_SIMIL , m_dataLoader->getPlayer( ) #endif - ); + ); _openGLWidget->setScene( _scene ); } catch ( const std::exception& e ) @@ -1240,7 +1276,7 @@ void MainWindow::onDataLoaded( ) { // disable hasta que hagamos el merge a master de SimIL - playerWidget->init( m_dataLoader->getPlayer( )); + //playerWidget->init( m_dataLoader->getPlayer( )); } #endif diff --git a/neurotessmesh/MainWindow.h b/neurotessmesh/MainWindow.h index d76464f6175e1c2ea1b02cc724eb104223f2ca89..a788541325be0e6371b84bb3d6b244faff533f42 100644 --- a/neurotessmesh/MainWindow.h +++ b/neurotessmesh/MainWindow.h @@ -59,6 +59,8 @@ public: void openSWCFile( const std::string& fileName ); + void openHDF5File( const std::string& fileName ); + void updateNeuronList( ); public slots: @@ -71,6 +73,8 @@ public slots: void openSWCFileThroughDialog( ); + void openHDF5FileThroughDialog( ); + void showAbout( ); void openRecorder( ); @@ -183,3 +187,25 @@ private: Recorder* _recorder; std::shared_ptr< neurotessmesh::LoaderThread > m_dataLoader; }; + +/** \brief List item to sort neuron list correctly. + * + */ +class NeuronListItem: public QListWidgetItem +{ + public: + explicit NeuronListItem(uint32_t id) + : QListWidgetItem(QString::number(id)) + , m_id{id} + {} + + virtual ~NeuronListItem() {}; + + bool operator <(const QListWidgetItem &other) const override + { + return this->m_id < static_cast<const NeuronListItem&>(other).m_id; + } + + uint32_t m_id; +}; + diff --git a/neurotessmesh/Scene.cpp b/neurotessmesh/Scene.cpp index 66ce7f645a3592eb62b26699107537c0c2a3db46..831647bcb5b56bea6f6462708220cdd5b6452791 100644 --- a/neurotessmesh/Scene.cpp +++ b/neurotessmesh/Scene.cpp @@ -136,7 +136,7 @@ namespace neurotessmesh const auto timeStamp = _simulationPlayer->currentTime(); _renderer->render( std::get< 0 >( _unselectedNeurons ) , std::get< 1 >( _unselectedNeurons ) , - _unselectedColor, + _selectedColor, calculateUnselectedColors(timeStamp) , true , _paintUnselectedSoma , _paintUnselectedNeurites ); diff --git a/neurotessmesh/mainwindow.ui b/neurotessmesh/mainwindow.ui index 9f16aca12530b7ea84b70d02e76bccc2c9493521..bdeacf0419c7ae2bb214aaeb45d3ec6206023061 100644 --- a/neurotessmesh/mainwindow.ui +++ b/neurotessmesh/mainwindow.ui @@ -34,6 +34,7 @@ <addaction name="actionOpenBlueConfig"/> <addaction name="actionOpenXMLScene"/> <addaction name="actionOpenSWCFile"/> + <addaction name="actionOpenHDF5File"/> <addaction name="actionCloseData"/> <addaction name="separator"/> <addaction name="actionLoad_camera_positions"/> @@ -88,6 +89,7 @@ <addaction name="actionOpenBlueConfig"/> <addaction name="actionOpenXMLScene"/> <addaction name="actionOpenSWCFile"/> + <addaction name="actionOpenHDF5File"/> <addaction name="separator"/> <addaction name="actionHome"/> <addaction name="actionConfiguration"/> @@ -227,6 +229,21 @@ <string>Ctrl+Shift+S</string> </property> </action> + <action name="actionOpenHDF5File"> + <property name="icon"> + <iconset resource="resources.qrc"> + <normaloff>:/icons/rsc/open_H5.png</normaloff>:/icons/rsc/open_H5.png</iconset> + </property> + <property name="text"> + <string>Open HDF5</string> + </property> + <property name="toolTip"> + <string>Open HDF5</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+S</string> + </property> + </action> <action name="actionShowFPSOnIdleUpdate"> <property name="checkable"> <bool>true</bool> diff --git a/neurotessmesh/resources.qrc b/neurotessmesh/resources.qrc index 535db9d3199d79664d5887f074fd72bcf6c4c016..ea72bbd1c359d7b68800ceac6f2ac4aa334b4707 100644 --- a/neurotessmesh/resources.qrc +++ b/neurotessmesh/resources.qrc @@ -7,6 +7,7 @@ <file>rsc/open_swc.png</file> <file>rsc/close.png</file> <file>rsc/open_xml.png</file> + <file>rsc/open_H5.png</file> <file>rsc/open_bc.png</file> <file>rsc/colorpicker.png</file> <file>rsc/reconstruction.png</file> diff --git a/neurotessmesh/rsc/open_H5.png b/neurotessmesh/rsc/open_H5.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f232273b9bcbba76ba9a9ce53c25ff835532b4 Binary files /dev/null and b/neurotessmesh/rsc/open_H5.png differ