diff --git a/.gitignore b/.gitignore index b0dbf28e941b0a4a4fde657fe061991c4f70f09b..98c3223e4577c62a918cc997b5218d8a5c71ac73 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ gmrvlex prefr scoop vmmlib +HighFive diff --git a/sumrice/types.h b/sumrice/types.h index 055e255d8e0f6b45f33714aeb5e8cf38c64dc8d7..60a1fe9cf2c537761550c1e3d5b6668e8a37909a 100644 --- a/sumrice/types.h +++ b/sumrice/types.h @@ -37,6 +37,8 @@ namespace visimpl typedef simil::Spike Spike; typedef simil::TSpikes TSpikes; + typedef std::unordered_map< unsigned int, unsigned int > TUIntUintMap; + typedef std::set< uint32_t > TGIDSet; typedef std::vector< vmml::Vector3f > TPosVect; diff --git a/visimpl/CMakeLists.txt b/visimpl/CMakeLists.txt index f8abca0da3fdd050de07a0895572d572a34bc724..3382c372db1dfd2cec6c4f16948255f972980942 100644 --- a/visimpl/CMakeLists.txt +++ b/visimpl/CMakeLists.txt @@ -1,6 +1,6 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ViSimpl -# 2015-2016 (c) ViSimpl / Universidad Rey Juan Carlos +# 2015-2019 (c) ViSimpl / Universidad Rey Juan Carlos # sergio.galindo@urjc.es # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -25,47 +25,51 @@ configure_file(${CMAKE_SOURCE_DIR}/CMake/common/cpp/version.cpp set(UIDIR ${PROJECT_SOURCE_DIR}/ui) set(QRCDIR ${PROJECT_SOURCE_DIR}/qrc) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTOUIC ON) +#set(CMAKE_AUTOMOC ON) +#set(CMAKE_AUTOUIC ON) set(VISIMPL_SOURCES ${PROJECT_BINARY_DIR}/src/visimpl/version.cpp CMakeSetup.rc - + visimpl.ui resources.qrc - + visimpl.cpp MainWindow.cpp OpenGLWidget.cpp - + VisualGroup.cpp DomainManager.cpp - + + SelectionManagerWidget.cpp + prefr/ColorSource.cpp prefr/ColorOperationModel.cpp prefr/SourceMultiPosition.cpp prefr/UpdaterStaticPosition.cpp - + render/Plane.cpp - + ) set(VISIMPL_HEADERS ${PROJECT_BINARY_DIR}/include/visimpl/version.h OpenGLWidget.h MainWindow.h - + VisualGroup.h DomainManager.h - + + SelectionManagerWidget.h + prefr/PrefrShaders.h prefr/ColorSource.h prefr/ColorOperationModel.h prefr/SourceMultiPosition.h prefr/UpdaterStaticPosition.h - + render/Plane.cpp ) diff --git a/visimpl/DomainManager.cpp b/visimpl/DomainManager.cpp index 0882fd05f998e7be7b9bd964a617d1c6645b3d40..44ec85191dc07a8468d7dbf9f83046a767186a1d 100644 --- a/visimpl/DomainManager.cpp +++ b/visimpl/DomainManager.cpp @@ -150,6 +150,16 @@ namespace visimpl _particleSystem->start(); } + const tGidPosMap& DomainManager::positions( void ) const + { + return _gidPositions; + } + + const TGIDSet& DomainManager::gids( void ) const + { + return _gids; + } + void DomainManager::mode( tVisualMode newMode ) { clearView( ); diff --git a/visimpl/DomainManager.h b/visimpl/DomainManager.h index 5f674821fc27a031b8e09bc02c135f2941c11eb0..8d553985eba31bb1587a91c3fcc2e5622891622e 100644 --- a/visimpl/DomainManager.h +++ b/visimpl/DomainManager.h @@ -87,6 +87,8 @@ namespace visimpl const std::vector< VisualGroup* >& groups( void ) const; const std::vector< VisualGroup* >& attributeGroups( void ) const; + const tGidPosMap& positions( void ) const; + const TGIDSet& gids( void ) const; tBoundingBox boundingBox( void ) const; diff --git a/visimpl/MainWindow.cpp b/visimpl/MainWindow.cpp index 731774f615eb14d35a051229c439802f6fd3d7a5..0edcf8427f834538bc105a84b27e803ea53f1adb 100644 --- a/visimpl/MainWindow.cpp +++ b/visimpl/MainWindow.cpp @@ -88,8 +88,8 @@ namespace visimpl , _modeSelectionWidget( nullptr ) , _toolBoxOptions( nullptr ) , _groupBoxTransferFunction( nullptr ) - , _tfEditor( nullptr ) , _tfWidget( nullptr ) + , _selectionManager( nullptr ) , _autoNameGroups( false ) , _groupBoxGroups( nullptr ) , _groupLayout( nullptr ) @@ -115,6 +115,7 @@ namespace visimpl , _spinBoxClippingWidth( nullptr ) , _spinBoxClippingDist( nullptr ) , _frameClippingColor( nullptr ) + , _buttonSelectionFromClippingPlanes( nullptr ) { _ui->setupUi( this ); @@ -163,7 +164,7 @@ namespace visimpl // Connect about dialog connect( _ui->actionAbout, SIGNAL( triggered( )), - this, SLOT( aboutDialog( ))); + this, SLOT( dialogAbout( ))); connect( _ui->actionHome, SIGNAL( triggered( )), @@ -249,6 +250,8 @@ namespace visimpl QStringList attributes = { "Morphological type", "Functional type" }; _comboAttribSelection->addItems( attributes ); + + _selectionManager->setGIDs( _domainManager->gids( )); } void MainWindow::openBlueConfigThroughDialog( void ) @@ -361,7 +364,7 @@ namespace visimpl } - void MainWindow::aboutDialog( void ) + void MainWindow::dialogAbout( void ) { QString msj = @@ -443,6 +446,14 @@ namespace visimpl QMessageBox::about(this, tr( "About ViSimpl" ), msj ); } + void MainWindow::dialogSelectionManagement( void ) + { + if( !_selectionManager ) + return; + + _selectionManager->show( ); + } + void MainWindow::togglePlaybackDock( void ) { if( _ui->actionTogglePlaybackDock->isChecked( )) @@ -620,6 +631,15 @@ namespace visimpl _tfWidget = new TransferFunctionWidget( ); _tfWidget->setMinimumHeight( 150 ); + _selectionManager = new SelectionManagerWidget( ); +// _selectionManager->setWindowFlags( Qt::D ); + _selectionManager->setWindowModality( Qt::WindowModal ); + _selectionManager->setMinimumHeight( 300 ); + _selectionManager->setMinimumWidth( 500 ); + + connect( _selectionManager, SIGNAL( selectionChanged( void )), + this, SLOT( selectionManagerChanged( void ))); + _deltaTimeBox = new QDoubleSpinBox( ); _deltaTimeBox->setMinimum( 0.00000001 ); _deltaTimeBox->setMaximum( 50 ); @@ -689,6 +709,10 @@ namespace visimpl _frameClippingColor->setMinimumSize( 20, 20 ); _frameClippingColor->setMaximumSize( 20, 20 ); + _buttonSelectionFromClippingPlanes = new QPushButton( "To selection"); + _buttonSelectionFromClippingPlanes->setToolTip( tr( "Create a selection set from elements between planes" )); + + QWidget* topContainer = new QWidget( ); QVBoxLayout* verticalLayout = new QVBoxLayout( ); @@ -743,12 +767,16 @@ namespace visimpl vcLayout->addWidget( rFunctionGB ); vcContainer->setLayout( vcLayout ); + QPushButton* buttonSelectionManager = new QPushButton( "..." ); + buttonSelectionManager->setToolTip( tr( "Show the selection management dialog" )); + buttonSelectionManager->setMaximumWidth( 30 ); QGroupBox* selFunctionGB = new QGroupBox( "Current selection"); QHBoxLayout* selLayout = new QHBoxLayout( ); selLayout->setAlignment( Qt::AlignTop ); - selLayout->addWidget( new QLabel( "Selection size: " )); + selLayout->addWidget( new QLabel( "Size: " )); selLayout->addWidget( _selectionSizeLabel ); + selLayout->addWidget( buttonSelectionManager ); selLayout->addWidget( _addGroupButton ); selLayout->addWidget( _clearSelectionButton ); selFunctionGB->setLayout( selLayout ); @@ -760,8 +788,9 @@ namespace visimpl QGroupBox* gbClippingPlanes = new QGroupBox( "Clipping planes" ); QGridLayout* layoutClippingPlanes = new QGridLayout( ); gbClippingPlanes->setLayout( layoutClippingPlanes ); - layoutClippingPlanes->addWidget( _checkClipping, 0, 0, 1, 2 ); - layoutClippingPlanes->addWidget( _checkShowPlanes, 0, 2, 1, 2 ); + layoutClippingPlanes->addWidget( _checkClipping, 0, 0, 1, 1 ); + layoutClippingPlanes->addWidget( _checkShowPlanes, 0, 1, 1, 2 ); + layoutClippingPlanes->addWidget( _buttonSelectionFromClippingPlanes, 0, 3, 1, 1 ); layoutClippingPlanes->addWidget( line, 1, 0, 1, 4 ); layoutClippingPlanes->addWidget( _frameClippingColor, 2, 0, 1, 1 ); layoutClippingPlanes->addWidget( _buttonResetPlanes, 2, 1, 1, 1 ); @@ -926,6 +955,9 @@ namespace visimpl connect( _tfWidget, SIGNAL( previewColor( void )), this, SLOT( PreviewSimulationSizeFunction( void ))); + connect( buttonSelectionManager, SIGNAL( clicked( void )), + this, SLOT( dialogSelectionManagement( void ))); + connect( _deltaTimeBox, SIGNAL( valueChanged( double )), this, SLOT( updateSimDeltaTime( void ))); @@ -952,6 +984,9 @@ namespace visimpl connect( _checkShowPlanes, SIGNAL( stateChanged( int )), _openGLWidget, SLOT( paintClippingPlanes( int ))); + connect( _buttonSelectionFromClippingPlanes, SIGNAL( clicked( void )), + this, SLOT( selectionFromPlanes( void ))); + connect( _buttonResetPlanes, SIGNAL( clicked( void )), this, SLOT( clippingPlanesReset( void ))); @@ -968,13 +1003,8 @@ namespace visimpl connect( _frameClippingColor, SIGNAL( clicked( )), this, SLOT( colorSelectionClicked())); - -#ifdef VISIMPL_USE_ZEROEQ -#ifdef VISIMPL_USE_GMRVLEX connect( _clearSelectionButton, SIGNAL( clicked( void )), - this, SLOT( ClearSelection( void ))); -#endif -#endif + this, SLOT( clearSelection( void ))); connect( _addGroupButton, SIGNAL( clicked( void )), this, SLOT( addGroupFromSelection( ))); @@ -1218,6 +1248,7 @@ namespace visimpl _spinBoxClippingWidth->setEnabled( active ); _spinBoxClippingDist->setEnabled( active ); _frameClippingColor->setEnabled( active ); + _buttonSelectionFromClippingPlanes->setEnabled( active ); _openGLWidget->clippingPlanes( active ); @@ -1301,6 +1332,65 @@ namespace visimpl } } + void MainWindow::selectionFromPlanes( void ) + { + if( !_openGLWidget ) + return; + + auto ids = _openGLWidget->getPlanesContainedElements( ); + visimpl::GIDUSet selectedSet( ids.begin( ), ids.end( )); + + if( selectedSet.empty( )) + return; + + setSelection( selectedSet, SRC_PLANES ); + + } + + void MainWindow::selectionManagerChanged( void ) + { + setSelection( _selectionManager->selected( ), SRC_WIDGET ); + } + + void MainWindow::_updateSelectionGUI( void ) + { + auto selection = _domainManager->selection( ); + + _addGroupButton->setEnabled( true ); + _clearSelectionButton->setEnabled( true ); + _selectionSizeLabel->setText( QString::number( selection.size( ))); + _selectionSizeLabel->update( ); + + } + + void MainWindow::setSelection( const GIDUSet& selectedSet, + TSelectionSource source_ ) + { + if( source_ == SRC_UNDEFINED ) + return; + + _domainManager->selection( selectedSet ); + _openGLWidget->setSelectedGIDs( selectedSet ); + + if( source_ != SRC_WIDGET ) + _selectionManager->setSelected( selectedSet ); + + _updateSelectionGUI( ); + } + + void MainWindow::clearSelection( void ) + { + if( _openGLWidget ) + { + _domainManager->clearSelection( ); + _openGLWidget->clearSelection( ); + _selectionManager->clearSelection( ); + + _addGroupButton->setEnabled( false ); + _clearSelectionButton->setEnabled( false ); + _selectionSizeLabel->setText( "0" ); + } + } #ifdef VISIMPL_USE_ZEROEQ @@ -1380,17 +1470,7 @@ namespace visimpl // pthread_exit( NULL ); //} - void MainWindow::ClearSelection( void ) - { - if( _openGLWidget ) - { - _openGLWidget->clearSelection( ); - _addGroupButton->setEnabled( false ); - _clearSelectionButton->setEnabled( false ); - _selectionSizeLabel->setText( "0" ); - } - } void MainWindow::_onSelectionEvent( lexis::data::ConstSelectedIDsPtr selected ) { @@ -1403,18 +1483,9 @@ namespace visimpl std::vector< uint32_t > ids = selected->getIdsVector( ); - - visimpl::GIDUSet selectedSet( ids.begin( ), ids.end( )); - if( selectedSet.size( ) == 0 ) - return; - - _openGLWidget->setSelectedGIDs( selectedSet ); - - _addGroupButton->setEnabled( true ); - _clearSelectionButton->setEnabled( true ); - _selectionSizeLabel->setText( QString::number( selectedSet.size( ))); + setSelection( selectedSet, SRC_EXTERNAL ); } } diff --git a/visimpl/MainWindow.h b/visimpl/MainWindow.h index b2dea1320e30282be2151c8541a05e983cc7c893..7204d804a6ad6e8b2068a008efb63ec8d23a9137 100644 --- a/visimpl/MainWindow.h +++ b/visimpl/MainWindow.h @@ -18,6 +18,7 @@ #include <QToolBox> #include "OpenGLWidget.h" +#include "SelectionManagerWidget.h" #include <sumrice/sumrice.h> @@ -31,6 +32,14 @@ class MainWindow; namespace visimpl { + enum TSelectionSource + { + SRC_EXTERNAL = 0, + SRC_PLANES, + SRC_WIDGET, + SRC_UNDEFINED + }; + class MainWindow : public QMainWindow { @@ -63,7 +72,8 @@ namespace visimpl void openSubsetEventFile( const std::string& fileName, bool append = false ); - void aboutDialog( void ); + void dialogAbout( void ); + void dialogSelectionManagement( void ); void togglePlaybackDock( void ); void toggleSimConfigDock( void ); @@ -125,6 +135,11 @@ namespace visimpl void colorSelectionClicked( void ); + void selectionManagerChanged( void ); + void setSelection( const GIDUSet& selection_, TSelectionSource source_ = SRC_UNDEFINED ); + void clearSelection( void ); + void selectionFromPlanes( void ); + protected: void _initSimControlDock( void ); @@ -134,6 +149,8 @@ namespace visimpl void _configurePlayer( void ); void _resetClippingParams( void ); + void _updateSelectionGUI( void ); + bool _showDialog( QColor& current, const QString& message = "" ); @@ -147,7 +164,6 @@ namespace visimpl #endif - void ClearSelection( void ); protected: @@ -188,8 +204,8 @@ namespace visimpl QToolBox* _toolBoxOptions; QGroupBox* _groupBoxTransferFunction; - TransferFunctionEditor* _tfEditor; TransferFunctionWidget* _tfWidget; + SelectionManagerWidget* _selectionManager; bool _autoNameGroups; QGroupBox* _groupBoxGroups; @@ -225,6 +241,7 @@ namespace visimpl QDoubleSpinBox* _spinBoxClippingWidth; QDoubleSpinBox* _spinBoxClippingDist; QPushButton* _frameClippingColor; + QPushButton* _buttonSelectionFromClippingPlanes; }; diff --git a/visimpl/OpenGLWidget.cpp b/visimpl/OpenGLWidget.cpp index 214625a9e57dc798085cfa2c32337c495b6bbb60..ff1440994d715392b8671dc9b59c3534777795b1 100644 --- a/visimpl/OpenGLWidget.cpp +++ b/visimpl/OpenGLWidget.cpp @@ -123,6 +123,7 @@ namespace visimpl , _flagUpdateAttributes( false ) , _flagPickingSingle( false ) , _flagChangeShader( false ) + , _flagUpdateRender( false ) , _flagModeChange( false ) , _newMode( TMODE_UNDEFINED ) , _flagAttribChange( false ) @@ -594,9 +595,15 @@ namespace visimpl _camera->position( )[ 1 ], _camera->position( )[ 2 ] ); - _particleSystem->updateCameraDistances( cameraPosition ); + if( _player->isPlaying( ) || _lastCameraPosition != cameraPosition || _flagUpdateRender ) + { + _particleSystem->updateCameraDistances( cameraPosition ); + _lastCameraPosition = cameraPosition; + + _particleSystem->updateRender( ); - _lastCameraPosition = cameraPosition; + _flagUpdateRender = false; + } if( _clipping ) { @@ -604,8 +611,6 @@ namespace visimpl _clippingPlaneRight->activate( _shaderParticlesCurrent, 1 ); } - - _particleSystem->updateRender( ); _particleSystem->render( ); if( _clipping ) @@ -863,6 +868,7 @@ namespace visimpl _domainManager->mode( _newMode ); _flagModeChange = false; + _flagUpdateRender = true; if( _domainManager->mode( ) == TMODE_ATTRIBUTE ) emit attributeStatsComputed( ); @@ -886,14 +892,13 @@ namespace visimpl { _particleSystem->run( false ); - _domainManager->selection( _selectedGIDs ); - updateCameraBoundingBox( ); _particleSystem->run( true ); _particleSystem->update( 0.0f ); _flagUpdateSelection = false; + _flagUpdateRender = true; } } @@ -972,7 +977,6 @@ namespace visimpl void OpenGLWidget::clearSelection( void ) { - _domainManager->clearSelection( ); _selectedGIDs.clear( ); _flagUpdateSelection = true; } @@ -1133,7 +1137,7 @@ namespace visimpl _planesCenter = glmToEigen( currentBoundingBox.first + currentBoundingBox.second ) * 0.5f; - _planeDistance = std::abs( currentBoundingBox.second.x - currentBoundingBox.first.x ); + _planeDistance = std::abs( currentBoundingBox.second.x - currentBoundingBox.first.x ) + 1; _planeHeight = std::abs( currentBoundingBox.second.y - currentBoundingBox.first.y ); _planeWidth = std::abs( currentBoundingBox.second.z - currentBoundingBox.first.z ); @@ -1213,23 +1217,23 @@ namespace visimpl centerLeft = transform( centerLeft, center, _planeRotation ); centerRight = transform( centerRight, center, _planeRotation ); - evec3 leftNormal = ( center - centerLeft ).normalized( ); - evec3 rightNormal = ( center - centerRight ).normalized( ); + _planeNormalLeft = ( center - centerLeft ).normalized( ); + _planeNormalRight = ( center - centerRight ).normalized( ); - _clippingPlaneLeft->setEquationByPointAndNormal( centerLeft, leftNormal ); - _clippingPlaneRight->setEquationByPointAndNormal( centerRight, rightNormal ); + _clippingPlaneLeft->setEquationByPointAndNormal( centerLeft, _planeNormalLeft ); + _clippingPlaneRight->setEquationByPointAndNormal( centerRight, _planeNormalRight ); - std::cout << "Planes:" << std::endl - << " Left: " - << std::endl << vecToStr( transformedPoints[ 0 ]) - << std::endl << vecToStr( transformedPoints[ 1 ]) - << std::endl << vecToStr( transformedPoints[ 2 ]) - << std::endl - << " Right: " - << std::endl << vecToStr( transformedPoints[ 3 ]) - << std::endl << vecToStr( transformedPoints[ 4 ]) - << std::endl << vecToStr( transformedPoints[ 5 ]) - << std::endl; +// std::cout << "Planes:" << std::endl +// << " Left: " +// << std::endl << vecToStr( transformedPoints[ 0 ]) +// << std::endl << vecToStr( transformedPoints[ 1 ]) +// << std::endl << vecToStr( transformedPoints[ 2 ]) +// << std::endl +// << " Right: " +// << std::endl << vecToStr( transformedPoints[ 3 ]) +// << std::endl << vecToStr( transformedPoints[ 4 ]) +// << std::endl << vecToStr( transformedPoints[ 5 ]) +// << std::endl; @@ -1353,6 +1357,41 @@ namespace visimpl _updatePlanes( ); } + GIDVec OpenGLWidget::getPlanesContainedElements( void ) const + { + GIDVec result; + + // Project elements + evec3 normal = - _planeNormalLeft; + normal.normalize( ); + + auto positions = _domainManager->positions( ); + + result.reserve( positions.size( )); + + float distance = 0.0f; + + std::cout << "Contained elements: "; + for( auto neuronPos : positions ) + { + distance = normal.dot( _planeLeft.points( )[ 0 ] ) - + normal.dot( glmToEigen( neuronPos.second )); + + if( distance > 0.0f && distance <= _planeDistance ) + { + result.emplace_back( neuronPos.first ); +// std::cout << " [" << neuronPos.first << ":" << distance << "]"; + } + } + + result.shrink_to_fit( ); + + std::cout << " " << result.size( ) << std::endl; + + return result; + } + + void OpenGLWidget::mousePressEvent( QMouseEvent* event_ ) { diff --git a/visimpl/OpenGLWidget.h b/visimpl/OpenGLWidget.h index ae2ec7dae8f7a90761f30aab305dfb6d80b89867..0dd3c950c426f5049199e858b84880fa7501cc25 100644 --- a/visimpl/OpenGLWidget.h +++ b/visimpl/OpenGLWidget.h @@ -201,6 +201,8 @@ namespace visimpl void changeSimulationDecayValue( float value ); float getSimulationDecayValue( void ); + GIDVec getPlanesContainedElements( void ) const; + protected: void _resolveFlagsOperations( void ); @@ -314,6 +316,8 @@ namespace visimpl reto::ClippingPlane* _clippingPlaneLeft; reto::ClippingPlane* _clippingPlaneRight; evec3 _planesCenter; + evec3 _planeNormalLeft; + evec3 _planeNormalRight; std::vector< Eigen::Vector3f > _planePosLeft; std::vector< Eigen::Vector3f > _planePosRight; Eigen::Matrix4f _planeRotation; @@ -376,6 +380,7 @@ namespace visimpl bool _flagUpdateAttributes; bool _flagPickingSingle; bool _flagChangeShader; + bool _flagUpdateRender; bool _flagModeChange; tVisualMode _newMode; diff --git a/visimpl/SelectionManagerWidget.cpp b/visimpl/SelectionManagerWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8802905336871be55f9a4ccc214fb74984d325af --- /dev/null +++ b/visimpl/SelectionManagerWidget.cpp @@ -0,0 +1,433 @@ +/* + * @file SelectionManagerWidget.cpp + * @brief + * @author Sergio E. Galindo <sergio.galindo@urjc.es> + * @date + * @remarks Copyright (c) GMRV/URJC. All rights reserved. + * Do not distribute without further notice. + */ + +#include "SelectionManagerWidget.h" + +#include <QGridLayout> +#include <QGroupBox> +#include <QLabel> +#include <QFileDialog> +#include <QMessageBox> +#include <QTextStream> +#include <QShortcut> + +namespace visimpl +{ + + SelectionManagerWidget::SelectionManagerWidget( QWidget* parent_ ) + : QWidget( parent_ ) + , _listViewAvailable( nullptr ) + , _listViewSelected( nullptr ) + , _modelAvailable( nullptr ) + , _modelSelected( nullptr ) + , _buttonAddToSelection( nullptr ) + , _buttonRemoveFromSelection( nullptr ) + { + init( ); + } + + SelectionManagerWidget::~SelectionManagerWidget( void ) + { + + } + + void SelectionManagerWidget::init( void ) + { + + QVBoxLayout* layoutTop = new QVBoxLayout( ); + + this->setLayout( layoutTop ); + + _tabWidget = new QTabWidget( ); + QWidget* containerFoot = new QWidget( ); + QGridLayout* layoutFoot = new QGridLayout( ); + containerFoot->setLayout( layoutFoot ); + + layoutTop->addWidget( _tabWidget ); + layoutTop->addWidget( containerFoot ); + + _initTabSelection( ); + _initTabExport( ); + // Foot + + QPushButton* buttonCancel = new QPushButton( "Cancel" ); + buttonCancel->setMaximumWidth( 100 ); + QPushButton* buttonAccept = new QPushButton( "Accept" ); + buttonAccept->setMaximumWidth( 100 ); + + layoutFoot->addWidget( buttonCancel, 0, 0, 1, 1 ); + layoutFoot->addWidget( buttonAccept, 0, 2, 1, 1 ); + + connect( buttonCancel, SIGNAL( clicked( void )), + this, SLOT( _buttonCancelClicked( void ))); + connect( buttonAccept, SIGNAL( clicked( void )), + this, SLOT( _buttonAcceptClicked( void ))); + + new QShortcut( QKeySequence( Qt::Key_Escape ), this, SLOT( _buttonCancelClicked( ))); + } + + void SelectionManagerWidget::_initTabSelection( void ) + { + + QWidget* containerSelection = new QWidget( ); + + QGridLayout* layoutSelection = new QGridLayout( ); + containerSelection->setLayout( layoutSelection ); + + _labelAvailable = new QLabel( "Available GIDs: 0" ); + _labelSelection = new QLabel( "Selected GIDs: 0" ); + + layoutSelection->addWidget( _labelAvailable, 0, 0, 1, 1 ); + layoutSelection->addWidget( _labelSelection, 0, 2, 1, 1 ); + + _listViewAvailable = new QListView( ); + _listViewAvailable->setSelectionMode( QAbstractItemView::ExtendedSelection ); + _listViewAvailable->setUniformItemSizes( true ); + + _listViewSelected = new QListView( ); + _listViewSelected->setSelectionMode( QAbstractItemView::ExtendedSelection ); + _listViewSelected->setUniformItemSizes( true ); + + _modelAvailable = new QStandardItemModel( ); + _modelSelected = new QStandardItemModel( ); + + _listViewAvailable->setModel( _modelAvailable ); + _listViewSelected->setModel( _modelSelected ); + + _buttonAddToSelection = new QPushButton( "-->" ); + _buttonAddToSelection->setToolTip( tr( "Add to selected GIDs" )); + + _buttonRemoveFromSelection = new QPushButton( "<--" ); + _buttonRemoveFromSelection->setToolTip( tr( "Remove from selected GIDs" )); + + layoutSelection->addWidget( _listViewAvailable, 1, 0, 5, 1 ); + layoutSelection->addWidget( _buttonAddToSelection, 2, 1, 1, 1 ); + layoutSelection->addWidget( _buttonRemoveFromSelection, 4, 1, 1, 1 ); + layoutSelection->addWidget( _listViewSelected, 1, 2, 5, 1 ); + + connect( _buttonAddToSelection, SIGNAL( clicked( void )), + this, SLOT( _addToSelected( void ))); + + connect( _buttonRemoveFromSelection, SIGNAL( clicked( void )), + this, SLOT( _removeFromSelected( void ))); + + _tabWidget->addTab( containerSelection, "Selection" ); + } + + void SelectionManagerWidget::_initTabExport( void ) + { + QWidget* containerExport = new QWidget( ); + QGridLayout* layoutExport = new QGridLayout( ); + containerExport->setLayout( layoutExport ); + + _pathExportDefault = QString::fromStdString( std::getenv( "PWD" )); + _lineEditFilePath = new QLineEdit( _pathExportDefault.append( "/output.txt")); + + _lineEditPrefix = new QLineEdit( ); + _lineEditSuffix = new QLineEdit( ); + _lineEditSeparator = new QLineEdit( ); + + _radioNewLine = new QRadioButton( "New line" ); + _radioSpace = new QRadioButton( "Space" ); + _radioTab = new QRadioButton( "Tab" ); + _radioOther = new QRadioButton( "Other:" ); + + _buttonBrowse = new QPushButton( "Browse..." ); + _buttonSave = new QPushButton( "Save" ); + + QGroupBox* groupBoxPrefix = new QGroupBox( "Prefix/Suffix" ); + QGridLayout* layoutPrefix = new QGridLayout( ); + groupBoxPrefix->setLayout( layoutPrefix ); + layoutPrefix->addWidget( new QLabel( "Prefix:" ), 0, 0, 1, 1 ); + layoutPrefix->addWidget( _lineEditPrefix, 0, 1, 1, 1 ); + layoutPrefix->addWidget( new QLabel( "Suffix:" ), 1, 0, 1, 1 ); + layoutPrefix->addWidget( _lineEditSuffix, 1, 1, 1, 1 ); + + QGroupBox* groupBoxSeparator = new QGroupBox( "Separator" ); + QGridLayout* layoutSeparator = new QGridLayout( ); + layoutSeparator->addWidget( _radioNewLine, 0, 0, 1, 2 ); + layoutSeparator->addWidget( _radioSpace, 1, 0, 1, 2 ); + layoutSeparator->addWidget( _radioTab, 2, 0, 1, 2 ); + layoutSeparator->addWidget( _radioOther, 3, 0, 1, 1 ); + layoutSeparator->addWidget( _lineEditSeparator, 3, 1, 1, 1 ); + + _radioNewLine->setChecked( true ); + + groupBoxSeparator->setLayout( layoutSeparator ); + + + + layoutExport->addWidget( new QLabel( "File path:"), 0, 0, 1, 1 ); + layoutExport->addWidget( _lineEditFilePath, 0, 1, 1, 4 ); + layoutExport->addWidget( _buttonBrowse, 0, 5, 1, 1 ); + layoutExport->addWidget( groupBoxPrefix, 1, 0, 4, 2 ); + layoutExport->addWidget( groupBoxSeparator, 1, 2, 4, 3 ); + layoutExport->addWidget( _buttonSave, 4, 5, 1, 1 ); + + + + connect( _buttonBrowse, SIGNAL( clicked( void )), + this, SLOT( _buttonBrowseClicked( void ))); + + connect( _buttonSave, SIGNAL( clicked( void )), + this, SLOT( _buttonSaveClicked( void ))); + + _tabWidget->addTab( containerExport, "Export" ); + + } + + void SelectionManagerWidget::setGIDs( const TGIDSet& all_, + const TGIDUSet& selected_ ) + { + _gidsAll.clear( ); + _gidsAll.insert( all_.begin( ), all_.end( )); + + _fillLists( ); + + setSelected( selected_ ); + + } + + const TGIDUSet& SelectionManagerWidget::selected( void ) const + { + return _gidsSelected; + } + + void SelectionManagerWidget::clearSelection( void ) + { + _gidsSelected.clear( ); + _gidsAvailable = _gidsAll; + + _reloadLists( ); + } + + void SelectionManagerWidget::setSelected( const TGIDUSet& selected_ ) + { + if( selected_ == _gidsSelected && !_gidsAvailable.empty( )) + return; + + _gidsSelected = selected_; + + _gidsAvailable.clear( ); + for( auto gid : _gidsAll ) + { + if( _gidsSelected.find( gid ) == _gidsSelected.end( )) + _gidsAvailable.insert( gid ); + } + + _reloadLists( ); + } + + void SelectionManagerWidget::_fillLists( void ) + { + _modelAvailable->clear( ); + _modelSelected->clear( ); + + unsigned int index = 0; + GIDVec gids( _gidsAll.size( )); + std::copy( _gidsAll.begin( ), _gidsAll.end( ), gids.begin( )); + std::sort( gids.begin( ), gids.end( )); + + for( auto gid : gids ) + { + QStandardItem* itemAvailable = new QStandardItem( ); + QVariant value = QVariant::fromValue( gid ); + + itemAvailable->setData( value, Qt::DisplayRole ); + + QStandardItem* itemSelected = new QStandardItem( ); + itemSelected->setData( value, Qt::DisplayRole ); + + _modelAvailable->appendRow( itemAvailable ); + _modelSelected->appendRow( itemSelected ); + + _gidIndex.insert( std::make_pair( gid, index )); + + ++index; + } + + } + + void SelectionManagerWidget::_reloadLists( void ) + { + + for( auto gid : _gidsAll ) + { + bool stateSelected = ( _gidsSelected.find( gid ) != _gidsSelected.end( )); + + auto gidIndex = _gidIndex.find( gid ); + assert( gidIndex != _gidIndex.end( )); + + unsigned int row = gidIndex->second; + + _listViewAvailable->setRowHidden( row, stateSelected ); + _listViewSelected->setRowHidden( row, !stateSelected ); + } + + _updateListsLabelNumbers( ); + + } + + void SelectionManagerWidget::_updateListsLabelNumbers( void ) + { + _labelAvailable->setText( QString( "Available GIDs: ").append( + QString::number( _gidsAvailable.size( )))); + + _labelSelection->setText( QString( "Selected GIDs: ").append( + QString::number( _gidsSelected.size( )))); + } + + void SelectionManagerWidget::_addToSelected( void ) + { + + auto selectedIndices = + _listViewAvailable->selectionModel( )->selectedIndexes( ); + + if( selectedIndices.size( ) <= 0 ) + return; + + for( auto index : selectedIndices ) + { + if( index.row( ) < 0 ) + continue; + + auto item = _modelAvailable->itemFromIndex( index ); + + bool ok; + unsigned int gid = item->data( Qt::DisplayRole ).toUInt( &ok ); + + _gidsAvailable.erase( gid ); + _gidsSelected.insert( gid ); + + auto gidIndex = _gidIndex.find( gid ); + assert( gidIndex != _gidIndex.end( )); + + + + _listViewAvailable->setRowHidden( gidIndex->second, true ); + _listViewSelected->setRowHidden( gidIndex->second, false ); + + } + + _listViewAvailable->selectionModel( )->clearSelection( ); + + _updateListsLabelNumbers( ); + } + + void SelectionManagerWidget::_removeFromSelected( void ) + { + + auto selectedIndices = + _listViewSelected->selectionModel( )->selectedIndexes( ); + + for( auto index : selectedIndices ) + { + if( index.row( ) < 0 ) + continue; + + auto item = _modelSelected->itemFromIndex( index ); + unsigned int gid = item->data( Qt::DisplayRole ).toUInt( ); + + _gidsSelected.erase( gid ); + _gidsAvailable.insert( gid ); + + auto gidIndex = _gidIndex.find( gid ); + assert( gidIndex != _gidIndex.end( )); + + _listViewAvailable->setRowHidden( gidIndex->second, false ); + _listViewSelected->setRowHidden( gidIndex->second, true ); + + } + + _listViewSelected->selectionModel( )->clearSelection( ); + + _updateListsLabelNumbers( ); + } + + void SelectionManagerWidget::_saveToFile( const QString& filePath, + const QString& separator, + const QString& prefix, + const QString& suffix ) + { + QFile file; + + if( file.exists( filePath )) + { + + QMessageBox msgBox( this ); + msgBox.setText( "The selected file already exists." ); + msgBox.setInformativeText( "Do you want to overwrite?" ); + msgBox.setStandardButtons( QMessageBox::Save | QMessageBox::Cancel ); + msgBox.setDefaultButton( QMessageBox::Save ); + int ret = msgBox.exec( ); + + if((( QMessageBox::StandardButton ) ret ) == QMessageBox::Cancel ) + return; + } + + file.setFileName( filePath ); + file.open( QFile::WriteOnly | QFile::Truncate ); + QTextStream outStream( &file ); + + GIDVec gids( _gidsSelected.size( )); + std::copy( _gidsSelected.begin( ), _gidsSelected.end( ), gids.begin( )); + std::sort( gids.begin( ), gids.end( )); + + for( auto gid : gids ) + { + outStream << prefix << gid << suffix << separator; + } + + file.close( ); + + QMessageBox::information( this, QString( "Save successful" ), QString( "Selection saved to file." )); + + } + + void SelectionManagerWidget::_buttonAcceptClicked( void ) + { + this->close( ); + + emit selectionChanged( ); + } + + void SelectionManagerWidget::_buttonCancelClicked( void ) + { + this->close( ); + } + + void SelectionManagerWidget::_buttonBrowseClicked( void ) + { + QString path = QFileDialog::getSaveFileName( + this, tr( "Save to file" ), _lineEditFilePath->text( ), + tr( "Text files (.txt);;All files (*)" ), + nullptr, QFileDialog::DontUseNativeDialog ); + + if( !path.isEmpty( )) + _lineEditFilePath->setText( path ); + } + + void SelectionManagerWidget::_buttonSaveClicked( void ) + { + QString separator; + if( _radioNewLine->isChecked( )) + separator = "\n"; + else if( _radioSpace->isChecked( )) + separator = " "; + else if( _radioTab->isChecked( )) + separator = "\t"; + else + separator = _lineEditSeparator->text( ); + + _saveToFile( _lineEditFilePath->text( ), separator, + _lineEditPrefix->text( ), _lineEditSuffix->text( )); + + } + +} diff --git a/visimpl/SelectionManagerWidget.h b/visimpl/SelectionManagerWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..d713d0ad7b4f72b444387e6565262f25e373ace9 --- /dev/null +++ b/visimpl/SelectionManagerWidget.h @@ -0,0 +1,130 @@ +/* + * @file SelectionManagerWidget.h + * @brief + * @author Sergio E. Galindo <sergio.galindo@urjc.es> + * @date + * @remarks Copyright (c) GMRV/URJC. All rights reserved. + * Do not distribute without further notice. + */ + +#ifndef SELECTIONMANAGERWIDGET_H_ +#define SELECTIONMANAGERWIDGET_H_ + +#include <QListView> +#include <QStandardItemModel> +#include <QPushButton> +#include <QLineEdit> +#include <QRadioButton> + +#include <unordered_set> + +#include "types.h" + +namespace visimpl +{ + + class SelectionManagerWidget : public QWidget + { + Q_OBJECT; + + public: + + enum TSeparator + { + TSEP_NEWLINE = 0, + TSEP_SPACE, + TSEP_TAB, + TSEP_OTHER + }; + + SelectionManagerWidget( QWidget* parent = 0 ); + ~SelectionManagerWidget( void ); + + void init( void ); + + void setGIDs( const TGIDSet& all_, + const TGIDUSet& selected_ = { }); + + void setSelected( const TGIDUSet& selected_ ); + const TGIDUSet& selected( void ) const; + + void clearSelection( void ); + + signals: + + void selectionChanged( void ); + + protected slots: + + void _addToSelected( void ); + void _removeFromSelected( void ); + + void _buttonBrowseClicked( void ); + void _buttonSaveClicked( void ); + + void _buttonCancelClicked( void ); + void _buttonAcceptClicked( void ); + + + protected: + + void _initTabSelection( void ); + void _initTabExport( void ); + + void _fillLists( void ); + void _reloadLists( void ); + + void _updateListsLabelNumbers( void ); + + void _saveToFile( const QString& filePath, + const QString& separator = "\n", + const QString& prefix = "", + const QString& suffix = "" ); + + + TGIDUSet _gidsAll; + TGIDUSet _gidsSelected; + TGIDUSet _gidsAvailable; + + QTabWidget* _tabWidget; + + // Selection tab + + QListView* _listViewAvailable; + QListView* _listViewSelected; + + QStandardItemModel* _modelAvailable; + QStandardItemModel* _modelSelected; + + QPushButton* _buttonAddToSelection; + QPushButton* _buttonRemoveFromSelection; + + QLabel* _labelAvailable; + QLabel* _labelSelection; + + TUIntUintMap _gidIndex; + + // Export tab + + QLineEdit* _lineEditFilePath; + QLineEdit* _lineEditPrefix; + QLineEdit* _lineEditSuffix; + QLineEdit* _lineEditSeparator; + + QRadioButton* _radioNewLine; + QRadioButton* _radioSpace; + QRadioButton* _radioTab; + QRadioButton* _radioOther; + + QPushButton* _buttonBrowse; + QPushButton* _buttonSave; + + QString _pathExportDefault; + + }; + +} + + + +#endif /* SELECTIONMANAGERWIDGET_H_ */ diff --git a/visimpl/render/Plane.cpp b/visimpl/render/Plane.cpp index 905ae93ff309ccb1c02f3bed9e8f1509d7f1cd7d..a9d43a217204f31c76d9a6cdc395aaf8c790aef0 100644 --- a/visimpl/render/Plane.cpp +++ b/visimpl/render/Plane.cpp @@ -80,6 +80,11 @@ namespace visimpl glBindVertexArray( 0 ); } + const std::vector< evec3 >& Plane::points( void ) const + { + return _points; + } + void Plane::render( reto::ShaderProgram* program_ ) { assert( _camera ); diff --git a/visimpl/render/Plane.h b/visimpl/render/Plane.h index 2c017adf6aa9dffcfcf28839023c2689fd56cda2..a3e2698bebae3d63f4c58dcbc75130e903b9e31d 100644 --- a/visimpl/render/Plane.h +++ b/visimpl/render/Plane.h @@ -23,6 +23,8 @@ namespace visimpl void points( evec3 first, evec3 second, evec3 third, evec3 fourth ); + const std::vector< evec3 >& points( void ) const; + void init( reto::Camera* camera ); void render( reto::ShaderProgram* program_ );