//--------------------------------------------------------------------------- // // 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 "core/common/WAssert.h" #include "core/common/WIOTools.h" #include "core/common/WPropertyHelper.h" #include "core/dataHandler/WDataSet.h" #include "core/dataHandler/WDataSetSingle.h" #include "core/dataHandler/WDataSetScalar.h" #include "core/dataHandler/WDataSetTimeSeries.h" #include "core/dataHandler/WDataSetVector.h" #include "core/dataHandler/WSubject.h" #include "core/dataHandler/WDataHandler.h" #include "core/dataHandler/WDataTexture3D.h" #include "core/dataHandler/WEEG2.h" #include "core/dataHandler/exceptions/WDHException.h" #include "core/graphicsEngine/WGEColormapping.h" #include "core/kernel/WModuleOutputData.h" #ifdef WBIOSIG_ENABLED #include "io/WReaderBiosig.h" #endif #include "io/WReaderEEGASCII.h" #include "io/WReaderNIfTI.h" #include "io/WReaderELC.h" #include "io/WReaderFiberVTK.h" #include "io/WReaderLibeep.h" #include "io/WReaderVTK.h" #include "io/WPagerEEGLibeep.h" #include "WMData.h" #include "WMData.xpm" WMData::WMData(): WDataModule(), m_fileNameSet( false ), m_isTexture(), m_transformNoMatrix( 4, 4 ), m_transformSForm( 4, 4 ), m_transformQForm( 4, 4 ) { // initialize members } WMData::~WMData() { // cleanup } boost::shared_ptr< WModule > WMData::factory() const { return boost::shared_ptr< WModule >( new WMData() ); } const char** WMData::getXPMIcon() const { return WMData_xpm; } const std::string WMData::getName() const { return "Data Module"; } const std::string WMData::getDescription() const { return "This module encapsulates data."; } boost::shared_ptr< WDataSet > WMData::getDataSet() { return m_dataSet; } void WMData::setFilename( boost::filesystem::path fname ) { if( !m_fileNameSet ) { m_fileNameSet = true; m_fileName = fname; } } boost::filesystem::path WMData::getFilename() const { return m_fileName; } void WMData::connectors() { // initialize connectors m_output= boost::shared_ptr< WModuleOutputData< WDataSet > >( new WModuleOutputData< WDataSet >( shared_from_this(), "out", "A loaded dataset." ) ); // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. addConnector( m_output ); // call WModules initialization WDataModule::connectors(); } void WMData::properties() { m_propCondition = boost::shared_ptr< WCondition >( new WCondition() ); // properties m_dataName = m_infoProperties->addProperty( "Filename", "The filename of the dataset.", std::string( "" ) ); m_dataType = m_infoProperties->addProperty( "Data type", "The type of the single data values.", std::string( "" ) ); m_dataSetType = m_infoProperties->addProperty( "Dataset type", "The name of the dataset type.", std::string( "" ) ); m_matrixSelectionsList = boost::shared_ptr< WItemSelection >( new WItemSelection() ); m_matrixSelectionsList->addItem( "No matrix", "" ); m_matrixSelectionsList->addItem( "sform", "" ); m_matrixSelectionsList->addItem( "qform", "" ); m_matrixSelection = m_properties->addProperty( "Transformation matrix", "matrix", m_matrixSelectionsList->getSelectorFirst(), m_propCondition ); WPropertyHelper::PC_SELECTONLYONE::addTo( m_matrixSelection ); // use this callback for the other properties WPropertyBase::PropertyChangeNotifierType propertyCallback = boost::bind( &WMData::propertyChanged, this, _1 ); } void WMData::propertyChanged( boost::shared_ptr< WPropertyBase > property ) { if( m_isTexture ) { if( property == m_active ) { // forward to texture m_dataSet->getTexture()->active()->set( m_active->get( true ) ); } } else { if( property == m_active ) { if( m_active->get() ) { m_output->updateData( m_dataSet ); } else { m_output->updateData( boost::shared_ptr< WDataSet >() ); } } } } void WMData::moduleMain() { WAssert( m_fileNameSet, "No filename specified." ); m_transformNoMatrix.makeIdentity(); m_transformSForm.makeIdentity(); m_transformQForm.makeIdentity(); m_moduleState.setResetable( true, true ); m_moduleState.add( m_propCondition ); std::string fileName = m_fileName.string(); debugLog() << "Loading data from \"" << fileName << "\"."; m_dataName->set( fileName ); // remove the path up to the file name and set it as a convenient name for this module instance if( fileName != "" ) { m_runtimeName->set( string_utils::tokenize( fileName, "/" ).back() ); } // load it now std::string suffix = getSuffix( fileName ); if( suffix == ".nii" || ( suffix == ".gz" && ::nifti_compiled_with_zlib() ) ) { if( suffix == ".gz" ) // it may be a NIfTI file too { boost::filesystem::path p( fileName ); p.replace_extension( "" ); if( boost::filesystem::exists( p ) && !boost::filesystem::is_directory( p ) ) { warnLog() << "Loading file " << fileName << " and a file with the name " << p << " was found. This may lead to problems loading the data due to an issue with the niftiio-lib."; } suffix = getSuffix( p.string() ); WAssert( suffix == ".nii", "Currently only nii files may be gzipped." ); } WReaderNIfTI niiLoader( fileName ); m_dataSet = niiLoader.load(); m_transformNoMatrix = niiLoader.getStandardTransform(); m_transformSForm = niiLoader.getSFormTransform(); m_transformQForm = niiLoader.getQFormTransform(); m_isTexture = m_dataSet->isTexture(); boost::shared_ptr< WDataSetSingle > dss = boost::dynamic_pointer_cast< WDataSetSingle >( m_dataSet ); if( dss ) { m_dataType->set( getDataTypeString( dss ) ); if( dss->isTexture() ) { switch( (*dss).getValueSet()->getDataType() ) { case W_DT_UNSIGNED_CHAR: case W_DT_INT16: case W_DT_UINT16: case W_DT_UINT32: case W_DT_SIGNED_INT: m_dataSet->getTexture()->colormap()->set( m_dataSet->getTexture()->colormap()->get().newSelector( WItemSelector::IndexList( 1, 0 ) ) ); break; case W_DT_FLOAT: case W_DT_DOUBLE: if( boost::dynamic_pointer_cast< WDataSetVector >( m_dataSet ) ) { m_dataSet->getTexture()->colormap()->set( m_dataSet->getTexture()->colormap()->get().newSelector( WItemSelector::IndexList( 1, 6 ) ) ); m_dataSet->getTexture()->interpolation()->set( false ); } else { m_dataSet->getTexture()->colormap()->set( m_dataSet->getTexture()->colormap()->get().newSelector( WItemSelector::IndexList( 1, 5 ) ) ); } break; default: WAssert( false, "Could not load \"" + fileName + "\". Reason: unknown data type in Data module" ); } } } } #ifdef WBIOSIG_ENABLED else if( suffix == ".edf" ) // NOLINT: An else should appear after closing } in previous line { WReaderBiosig biosigLoader( fileName ); m_dataSet = biosigLoader.load(); } #endif else if( suffix == ".asc" ) // NOLINT: An else should appear after closing } in previous line { WReaderEEGASCII eegAsciiLoader( fileName ); m_dataSet = eegAsciiLoader.load(); } else if( suffix == ".cnt" ) { boost::shared_ptr< WPagerEEG > pager( new WPagerEEGLibeep( fileName ) ); std::string elcFileName = fileName; elcFileName.resize( elcFileName.size() - 3 ); // drop suffix elcFileName += "elc"; // add new suffix WReaderELC elcReader( elcFileName ); boost::shared_ptr< WEEGPositionsLibrary > eegPositionsLibrary = elcReader.read(); m_dataSet = boost::shared_ptr< WEEG2 >( new WEEG2( pager, eegPositionsLibrary ) ); } else if( suffix == ".fib" ) { WReaderFiberVTK fibReader( fileName ); m_dataSet = fibReader.read(); } else if( suffix == ".vtk" ) { WReaderVTK vtkReader( fileName ); m_dataSet = vtkReader.read(); } else { throw WDHException( std::string( "Could not load \"" + fileName + "\". Reason: unknown file type: \"" + suffix + "\"" ) ); } debugLog() << "Loading data done."; // register the dataset properties m_properties->addProperty( m_dataSet->getProperties() ); m_infoProperties->addProperty( m_dataSet->getInformationProperties() ); m_infoProperties->addProperty( getTransformationProperties() ); // set the dataset name m_dataSetType->set( m_dataSet->getName() ); // I am interested in the active property ( manually subscribe signal ) m_active->getCondition()->subscribeSignal( boost::bind( &WMData::propertyChanged, this, m_active ) ); // textures also provide properties if( m_dataSet->isTexture() ) { if( !getSuppressColormaps() ) { WGEColormapping::registerTexture( m_dataSet->getTexture(), m_runtimeName->get() ); } else { debugLog() << "Suppressing colormap \"" << m_runtimeName->get() << "\"."; } m_properties->addProperty( m_dataSet->getTexture()->getProperties() ); m_infoProperties->addProperty( m_dataSet->getTexture()->getInformationProperties() ); } // notify m_output->updateData( m_dataSet ); ready(); WDataSetSingle::SPtr dataSetAsSingle = boost::dynamic_pointer_cast< WDataSetSingle >( m_dataSet ); while( !m_shutdownFlag() ) { m_moduleState.wait(); if( m_shutdownFlag() ) { break; } // change transform matrix (only if we have a dataset single which contains the grid) if( m_matrixSelection->changed() && dataSetAsSingle ) { if( m_dataSet && m_isTexture ) { // remove dataset from datahandler if( m_dataSet->isTexture() ) { m_properties->removeProperty( m_dataSet->getTexture()->getProperties() ); m_infoProperties->removeProperty( m_dataSet->getTexture()->getInformationProperties() ); WGEColormapping::deregisterTexture( m_dataSet->getTexture() ); } } // a new grid boost::shared_ptr< WGrid > newGrid; boost::shared_ptr< WGridRegular3D > oldGrid = boost::dynamic_pointer_cast< WGridRegular3D >( dataSetAsSingle->getGrid() ); switch( m_matrixSelection->get( true ).getItemIndexOfSelected( 0 ) ) { case 0: newGrid = boost::shared_ptr< WGrid >( new WGridRegular3D( oldGrid->getNbCoordsX(), oldGrid->getNbCoordsY(), oldGrid->getNbCoordsZ(), WGridTransformOrtho( m_transformNoMatrix ) ) ); break; case 1: newGrid = boost::shared_ptr< WGrid >( new WGridRegular3D( oldGrid->getNbCoordsX(), oldGrid->getNbCoordsY(), oldGrid->getNbCoordsZ(), WGridTransformOrtho( m_transformSForm ) ) ); break; case 2: newGrid = boost::shared_ptr< WGrid >( new WGridRegular3D( oldGrid->getNbCoordsX(), oldGrid->getNbCoordsY(), oldGrid->getNbCoordsZ(), WGridTransformOrtho( m_transformQForm ) ) ); break; } m_dataSet = dataSetAsSingle->clone( newGrid ); // the clone() may have returned a zero-pointer, only update if it hasn't // this may happen if the clone() operation has not been implemented in the derived dataset class if( m_dataSet ) { m_output->updateData( m_dataSet ); if( m_isTexture ) { if( !getSuppressColormaps() ) { WGEColormapping::registerTexture( m_dataSet->getTexture(), m_runtimeName->get() ); } m_properties->addProperty( m_dataSet->getTexture()->getProperties() ); m_infoProperties->addProperty( m_dataSet->getTexture()->getInformationProperties() ); } } } } // remove dataset from datahandler if( m_dataSet->isTexture() ) { m_properties->removeProperty( m_dataSet->getTexture()->getProperties() ); m_infoProperties->removeProperty( m_dataSet->getTexture()->getInformationProperties() ); WGEColormapping::deregisterTexture( m_dataSet->getTexture() ); } } // TODO(wiebel): move this to some central place. std::string WMData::getDataTypeString( boost::shared_ptr< WDataSetSingle > dss ) { std::string result; switch( (*dss).getValueSet()->getDataType() ) { case W_DT_NONE: result = "none"; break; case W_DT_BINARY: result = "binary (1 bit)"; break; case W_DT_UNSIGNED_CHAR: result = "unsigned char (8 bits)"; break; case W_DT_SIGNED_SHORT: result = "signed short (16 bits)"; break; case W_DT_SIGNED_INT: result = "signed int (32 bits)"; break; case W_DT_FLOAT: result = "float (32 bits)"; break; case W_DT_COMPLEX: result = "complex"; break; case W_DT_DOUBLE: result = "double (64 bits)"; break; case W_DT_RGB: result = "RGB triple (24 bits)"; break; case W_DT_ALL: result = "ALL (not very useful)"; break; case W_DT_INT8: result = "signed char (8 bits)"; break; case W_DT_UINT16: result = "unsigned short (16 bits)"; break; case W_DT_UINT32 : result = "unsigned int (32 bits)"; break; case W_DT_INT64: result = "int64"; break; case W_DT_UINT64: result = "unsigned long long (64 bits)"; break; case W_DT_FLOAT128: result = "float (128 bits)"; break; case W_DT_COMPLEX128: result = "double pair (128 bits)"; break; case W_DT_COMPLEX256: result = " long double pair (256 bits)"; break; case W_DT_RGBA32: result = "4 byte RGBA (32 bits)"; break; default: WAssert( false, "Unknow data type in getDataTypeString" ); } return result; } namespace { // helper which gets a WMatrix< double > and returns a WMatrix4d WMatrix4d WMatrixDoubleToWMatrix4d( const WMatrix< double >& matrix ) { WAssert( matrix.getNbRows() == 4, "" ); WAssert( matrix.getNbCols() == 4, "" ); WMatrix4d result; for( size_t i = 0; i < 4; ++i ) { for( size_t j = 0; j < 4; ++j ) { result( i, j ) = matrix( i, j ); } } return result; } } boost::shared_ptr< WProperties > WMData::getTransformationProperties() const { boost::shared_ptr< WProperties > result( new WProperties( "Transformations", "Availabe transformation matrices for data-set " ) ); WPropGroup transformation = result->addPropertyGroup( "Transformation", "The transformation of this grid." ); WPropMatrix4X4 noMatrixTransformation = result->addProperty( "No matrix transformation", "The no matrix transformation for this data set.", WMatrixDoubleToWMatrix4d( m_transformNoMatrix ) ); WPropMatrix4X4 sformMatrixTransformation = result->addProperty( "sform matrix transformation", "The sform matrix transformation for this data set.", WMatrixDoubleToWMatrix4d( m_transformSForm ) ); WPropMatrix4X4 qformMatrixTransformation = result->addProperty( "qform matrix transformation", "The qform matrix transformation for this data set.", WMatrixDoubleToWMatrix4d( m_transformQForm ) ); return result; }