WMData.cpp 17.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
//---------------------------------------------------------------------------
//
// 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 <string>
26
#include <vector>
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#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"
43

44 45 46 47 48 49
#include "io/WReaderBiosig.h"
#include "io/WReaderEEGASCII.h"
#include "io/WReaderNIfTI.h"
#include "io/WReaderELC.h"
#include "io/WReaderFiberVTK.h"
#include "io/WReaderLibeep.h"
50
#include "io/WReaderVTK.h"
51 52 53 54
#include "io/WPagerEEGLibeep.h"

#include "WMData.h"
#include "WMData.xpm"
55

56
WMData::WMData():
57
    WDataModule(),
58
    m_fileNameSet( false ),
59 60 61 62
    m_isTexture(),
    m_transformNoMatrix( 4, 4 ),
    m_transformSForm( 4, 4 ),
    m_transformQForm( 4, 4 )
63 64 65
{
    // initialize members
}
66

67
WMData::~WMData()
68
{
69
    // cleanup
70 71
}

72
boost::shared_ptr< WModule > WMData::factory() const
73
{
74
    return boost::shared_ptr< WModule >( new WMData() );
75 76
}

77 78
const char** WMData::getXPMIcon() const
{
79
    return WMData_xpm;
80 81
}

82
const std::string WMData::getName() const
83
{
84
    return "Data Module";
85 86
}

87
const std::string WMData::getDescription() const
88
{
89
    return "This module encapsulates data.";
90 91
}

92
boost::shared_ptr< WDataSet > WMData::getDataSet()
93
{
94
    return m_dataSet;
95 96
}

97 98
void WMData::setFilename( boost::filesystem::path fname )
{
99
    if( !m_fileNameSet )
100 101 102 103 104 105 106 107 108 109 110
    {
        m_fileNameSet = true;
        m_fileName = fname;
    }
}

boost::filesystem::path WMData::getFilename() const
{
    return m_fileName;
}

111
void WMData::connectors()
112 113
{
    // initialize connectors
114 115
    m_output= boost::shared_ptr< WModuleOutputData< WDataSet > >( new WModuleOutputData< WDataSet >(
                shared_from_this(), "out", "A loaded dataset." )
116
            );
117 118 119 120 121

    // 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
122
    WDataModule::connectors();
123 124
}

125
void WMData::properties()
126
{
127
    m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
128 129

    // properties
130
    m_dataName = m_infoProperties->addProperty( "Filename", "The filename of the dataset.", std::string( "" ) );
131 132
    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( "" ) );
133

134
    m_matrixSelectionsList = boost::shared_ptr< WItemSelection >( new WItemSelection() );
135
    m_matrixSelectionsList->addItem( "No matrix", "" );
136
    m_matrixSelectionsList->addItem( "sform", "" );
137
    m_matrixSelectionsList->addItem( "qform", "" );
138

139
    m_matrixSelection = m_properties->addProperty( "Transformation matrix",  "matrix",
140
            m_matrixSelectionsList->getSelectorFirst(), m_propCondition );
141
    WPropertyHelper::PC_SELECTONLYONE::addTo( m_matrixSelection );
142 143 144

    // use this callback for the other properties
    WPropertyBase::PropertyChangeNotifierType propertyCallback = boost::bind( &WMData::propertyChanged, this, _1 );
145 146
}

147 148
void WMData::propertyChanged( boost::shared_ptr< WPropertyBase > property )
{
149
    if( m_isTexture )
150
    {
151
        if( property == m_active )
152
        {
153
            // forward to texture
154
            m_dataSet->getTexture()->active()->set( m_active->get( true ) );
155
        }
156
    }
157
    else
158
    {
159
        if( property == m_active )
160 161 162 163 164 165 166 167 168 169
        {
            if( m_active->get() )
            {
                m_output->updateData( m_dataSet );
            }
            else
            {
                m_output->updateData( boost::shared_ptr< WDataSet >() );
            }
        }
170
    }
171
}
172

173
void WMData::moduleMain()
174
{
175 176
    WAssert( m_fileNameSet, "No filename specified." );

177 178 179 180
    m_transformNoMatrix.makeIdentity();
    m_transformSForm.makeIdentity();
    m_transformQForm.makeIdentity();

181 182
    m_moduleState.setResetable( true, true );
    m_moduleState.add( m_propCondition );
reichenbach's avatar
reichenbach committed
183

184
    std::string fileName = m_fileName.string();
185

186
    debugLog() << "Loading data from \"" << fileName << "\".";
187
    m_dataName->set( fileName );
188

189
    // remove the path up to the file name and set it as a convenient name for this module instance
190
    if( fileName != "" )
191 192 193 194
    {
        m_runtimeName->set( string_utils::tokenize( fileName, "/" ).back() );
    }

195 196 197
    // load it now
    std::string suffix = getSuffix( fileName );

Mathias Goldau's avatar
Mathias Goldau committed
198
    if( suffix == ".nii" || ( suffix == ".gz" && ::nifti_compiled_with_zlib() ) )
199 200 201 202 203
    {
        if( suffix == ".gz" )  // it may be a NIfTI file too
        {
            boost::filesystem::path p( fileName );
            p.replace_extension( "" );
204 205 206

            if( boost::filesystem::exists( p ) && !boost::filesystem::is_directory( p ) )
            {
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
207 208
                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.";
209
            }
Mathias Goldau's avatar
Mathias Goldau committed
210

211
            suffix = getSuffix( p.string() );
212
            WAssert( suffix == ".nii", "Currently only nii files may be gzipped." );
213
        }
214

215
        WReaderNIfTI niiLoader( fileName );
216
        m_dataSet = niiLoader.load();
217 218 219
        m_transformNoMatrix = niiLoader.getStandardTransform();
        m_transformSForm = niiLoader.getSFormTransform();
        m_transformQForm = niiLoader.getQFormTransform();
reichenbach's avatar
reichenbach committed
220

221
        m_isTexture = m_dataSet->isTexture();
222

223
        boost::shared_ptr< WDataSetSingle > dss = boost::shared_dynamic_cast< WDataSetSingle >( m_dataSet );
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
224
        if( dss )
225
        {
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
226
            m_dataType->set( getDataTypeString( dss ) );
227
            if( dss->isTexture() )
228
            {
229 230 231 232
                switch( (*dss).getValueSet()->getDataType() )
                {
                    case W_DT_UNSIGNED_CHAR:
                    case W_DT_INT16:
233
                    case W_DT_UINT16:
234
                    case W_DT_UINT32:
235
                    case W_DT_SIGNED_INT:
236
                        m_dataSet->getTexture()->colormap()->set(
237
                            m_dataSet->getTexture()->colormap()->get().newSelector( WItemSelector::IndexList( 1, 0 ) )
238
                        );
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
                        break;
                    case W_DT_FLOAT:
                    case W_DT_DOUBLE:
                        if( boost::shared_dynamic_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:
257
                        WAssert( false, "Could not load \"" + fileName + "\". Reason: unknown data type in Data module" );
258
                }
259 260
            }
        }
261 262 263
    }
    else if( suffix == ".edf" )
    {
264
        WReaderBiosig biosigLoader( fileName );
265 266 267 268
        m_dataSet = biosigLoader.load();
    }
    else if( suffix == ".asc" )
    {
269
        WReaderEEGASCII eegAsciiLoader( fileName );
270 271
        m_dataSet = eegAsciiLoader.load();
    }
272 273
    else if( suffix == ".cnt" )
    {
274 275 276 277 278 279 280 281 282
        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 ) );
283
    }
284 285
    else if( suffix == ".fib" )
    {
Mathias Goldau's avatar
Mathias Goldau committed
286 287
        WReaderFiberVTK fibReader( fileName );
        m_dataSet = fibReader.read();
288
    }
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
289
    else if( suffix == ".vtk" )
290 291 292 293
    {
        WReaderVTK vtkReader( fileName );
        m_dataSet = vtkReader.read();
    }
294 295
    else
    {
296
        throw WDHException( std::string( "Could not load \"" + fileName + "\". Reason: unknown file type: \"" + suffix + "\"" ) );
297 298
    }

299
    debugLog() << "Loading data done.";
300

301 302 303
    // register the dataset properties
    m_properties->addProperty( m_dataSet->getProperties() );
    m_infoProperties->addProperty( m_dataSet->getInformationProperties() );
304
    m_infoProperties->addProperty( getTransformationProperties() );
305

306 307 308
    // set the dataset name
    m_dataSetType->set( m_dataSet->getName() );

309 310 311
    // I am interested in the active property ( manually subscribe signal )
    m_active->getCondition()->subscribeSignal( boost::bind( &WMData::propertyChanged, this, m_active ) );

312
    // textures also provide properties
313
    if( m_dataSet->isTexture() )
314
    {
315 316 317 318
        if( !getSuppressColormaps() )
        {
            WGEColormapping::registerTexture( m_dataSet->getTexture(), m_runtimeName->get() );
        }
319 320
        m_properties->addProperty( m_dataSet->getTexture()->getProperties() );
        m_infoProperties->addProperty( m_dataSet->getTexture()->getInformationProperties() );
321 322
    }

323
    // notify
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
324
    m_output->updateData( m_dataSet );
325 326
    ready();

327 328
    WDataSetSingle::SPtr dataSetAsSingle = boost::shared_dynamic_cast< WDataSetSingle >( m_dataSet );

329 330 331 332 333 334 335 336
    while( !m_shutdownFlag() )
    {
        m_moduleState.wait();
        if( m_shutdownFlag() )
        {
            break;
        }

337 338
        // change transform matrix (only if we have a dataset single which contains the grid)
        if( m_matrixSelection->changed() && dataSetAsSingle )
339
        {
340 341 342
            if( m_dataSet && m_isTexture )
            {
                // remove dataset from datahandler
343
                if( m_dataSet->isTexture() )
344
                {
345 346 347
                    m_properties->removeProperty( m_dataSet->getTexture()->getProperties() );
                    m_infoProperties->removeProperty( m_dataSet->getTexture()->getInformationProperties() );
                    WGEColormapping::deregisterTexture( m_dataSet->getTexture() );
348 349
                }
            }
reichenbach's avatar
reichenbach committed
350

351 352
            // a new grid
            boost::shared_ptr< WGrid > newGrid;
353
            boost::shared_ptr< WGridRegular3D > oldGrid = boost::shared_dynamic_cast< WGridRegular3D >( dataSetAsSingle->getGrid() );
reichenbach's avatar
reichenbach committed
354

355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
            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;
            }

371
            m_dataSet = dataSetAsSingle->clone( newGrid );
372 373 374 375 376 377

            // 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 );
378 379 380

                if( m_isTexture )
                {
381 382 383 384
                    if( !getSuppressColormaps() )
                    {
                        WGEColormapping::registerTexture( m_dataSet->getTexture(), m_runtimeName->get() );
                    }
385 386
                    m_properties->addProperty( m_dataSet->getTexture()->getProperties() );
                    m_infoProperties->addProperty( m_dataSet->getTexture()->getInformationProperties() );
387
                }
388 389 390
            }
        }
    }
391 392

    // remove dataset from datahandler
393
    if( m_dataSet->isTexture() )
394
    {
395 396 397
        m_properties->removeProperty( m_dataSet->getTexture()->getProperties() );
        m_infoProperties->removeProperty( m_dataSet->getTexture()->getInformationProperties() );
        WGEColormapping::deregisterTexture( m_dataSet->getTexture() );
398
    }
399
}
400

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
// 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;
}
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
469

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
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;
}