WMData.cpp 18.1 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
#ifdef WBIOSIG_ENABLED
    #include "io/WReaderBiosig.h"
#endif
47 48 49 50 51
#include "io/WReaderEEGASCII.h"
#include "io/WReaderNIfTI.h"
#include "io/WReaderELC.h"
#include "io/WReaderFiberVTK.h"
#include "io/WReaderLibeep.h"
52
#include "io/WReaderVTK.h"
53 54 55 56
#include "io/WPagerEEGLibeep.h"

#include "WMData.h"
#include "WMData.xpm"
57

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

69
WMData::~WMData()
70
{
71
    // cleanup
72 73
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

179 180 181 182
    m_transformNoMatrix.makeIdentity();
    m_transformSForm.makeIdentity();
    m_transformQForm.makeIdentity();

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

186
    std::string fileName = m_fileName.string();
187

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

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

197 198 199
    // load it now
    std::string suffix = getSuffix( fileName );

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

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

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

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

223
        m_isTexture = m_dataSet->isTexture();
224

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

303
    debugLog() << "Loading data done.";
304

305 306 307
    // register the dataset properties
    m_properties->addProperty( m_dataSet->getProperties() );
    m_infoProperties->addProperty( m_dataSet->getInformationProperties() );
308
    m_infoProperties->addProperty( getTransformationProperties() );
309

310 311 312
    // set the dataset name
    m_dataSetType->set( m_dataSet->getName() );

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

316
    // textures also provide properties
317
    if( m_dataSet->isTexture() )
318
    {
319 320 321 322
        if( !getSuppressColormaps() )
        {
            WGEColormapping::registerTexture( m_dataSet->getTexture(), m_runtimeName->get() );
        }
323 324 325 326
        else
        {
            debugLog() << "Suppressing colormap \"" << m_runtimeName->get() << "\".";
        }
327 328
        m_properties->addProperty( m_dataSet->getTexture()->getProperties() );
        m_infoProperties->addProperty( m_dataSet->getTexture()->getInformationProperties() );
329 330
    }

331
    // notify
Sebastian Eichelbaum's avatar
[MERGE]  
Sebastian Eichelbaum committed
332
    m_output->updateData( m_dataSet );
333 334
    ready();

335
    WDataSetSingle::SPtr dataSetAsSingle = boost::dynamic_pointer_cast< WDataSetSingle >( m_dataSet );
336

337 338 339 340 341 342 343 344
    while( !m_shutdownFlag() )
    {
        m_moduleState.wait();
        if( m_shutdownFlag() )
        {
            break;
        }

345 346
        // change transform matrix (only if we have a dataset single which contains the grid)
        if( m_matrixSelection->changed() && dataSetAsSingle )
347
        {
348 349 350
            if( m_dataSet && m_isTexture )
            {
                // remove dataset from datahandler
351
                if( m_dataSet->isTexture() )
352
                {
353 354 355
                    m_properties->removeProperty( m_dataSet->getTexture()->getProperties() );
                    m_infoProperties->removeProperty( m_dataSet->getTexture()->getInformationProperties() );
                    WGEColormapping::deregisterTexture( m_dataSet->getTexture() );
356 357
                }
            }
reichenbach's avatar
reichenbach committed
358

359 360
            // a new grid
            boost::shared_ptr< WGrid > newGrid;
361
            boost::shared_ptr< WGridRegular3D > oldGrid = boost::dynamic_pointer_cast< WGridRegular3D >( dataSetAsSingle->getGrid() );
reichenbach's avatar
reichenbach committed
362

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
            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;
            }

379
            m_dataSet = dataSetAsSingle->clone( newGrid );
380 381 382 383 384 385

            // 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 );
386 387 388

                if( m_isTexture )
                {
389 390 391 392
                    if( !getSuppressColormaps() )
                    {
                        WGEColormapping::registerTexture( m_dataSet->getTexture(), m_runtimeName->get() );
                    }
393 394
                    m_properties->addProperty( m_dataSet->getTexture()->getProperties() );
                    m_infoProperties->addProperty( m_dataSet->getTexture()->getInformationProperties() );
395
                }
396 397 398
            }
        }
    }
399 400

    // remove dataset from datahandler
401
    if( m_dataSet->isTexture() )
402
    {
403 404 405
        m_properties->removeProperty( m_dataSet->getTexture()->getProperties() );
        m_infoProperties->removeProperty( m_dataSet->getTexture()->getInformationProperties() );
        WGEColormapping::deregisterTexture( m_dataSet->getTexture() );
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 469 470 471 472 473 474 475 476
// 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
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 505 506 507 508 509 510 511 512
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;
}