WMEffectiveConnectivityCluster.cpp 16.3 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
//---------------------------------------------------------------------------
//
// 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/>.
//
//---------------------------------------------------------------------------

25 26
#include <iostream>
#include <fstream>
27
#include <string>
28 29 30 31
#include <vector>

#include <cmath>

32 33
#include <boost/shared_ptr.hpp>

34
#include "WMEffectiveConnectivityCluster.h"
35 36

#include <osg/Geode>
37
#include <osg/Geometry>
38 39
#include <osgText/Text>
#include <osgText/FadeText>
40
#include <osg/StateSet>
41
#include <osg/StateAttribute>
42 43 44 45 46 47 48 49 50 51
#include <osg/PolygonMode>
#include <osg/LightModel>
#include <osgDB/WriteFile>

#include "../../common/WProgress.h"
#include "../../common/WPreferences.h"
#include "../../common/math/WVector3D.h"
#include "../../dataHandler/WSubject.h"
#include "../../dataHandler/WGridRegular3D.h"
#include "../../dataHandler/WDataTexture3D.h"
52
#include "../../dataHandler/datastructures/WFiberCluster.h"
53
#include "../../kernel/WKernel.h"
54
#include "../../kernel/WModuleOutputData.h"
55 56
#include "../../graphicsEngine/WGEBorderLayout.h"
#include "../../graphicsEngine/WGraphicsEngine.h"
57
#include "../../graphicsEngine/WGELabel.h"
58
#include "../../graphicsEngine/WGEUtils.h"
59

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
60
#include "effectiveConnectivityCluster.xpm"
61

62 63 64
// This line is needed by the module loader to actually find your module.
W_LOADABLE_MODULE( WMEffectiveConnectivityCluster )

65
WMEffectiveConnectivityCluster::WMEffectiveConnectivityCluster():
66
    WModuleContainer( "Effective Connectivity Cluster", "This module is able to visualize effective connectivity cluster." ),
67
    m_labelActive( false ),
68
    m_rootNode( new WGEGroupNode() )
69
{
70 71 72 73
    // WARNING: initializing connectors inside the constructor will lead to an exception.
    // NOTE: Do not use the module factory inside this constructor. This will cause a dead lock as the module factory is locked
    // during construction of this instance and can then not be used to create another instance (Isosurface in this case). If you
    // want to initialize some modules using the module factory BEFORE the moduleMain() call, overwrite WModule::initialize().
74 75 76 77
}

WMEffectiveConnectivityCluster::~WMEffectiveConnectivityCluster()
{
78 79
    // cleanup
    removeConnectors();
80 81 82 83 84 85 86
}

boost::shared_ptr< WModule > WMEffectiveConnectivityCluster::factory() const
{
    return boost::shared_ptr< WModule >( new WMEffectiveConnectivityCluster() );
}

Sebastian Eichelbaum's avatar
Sebastian Eichelbaum committed
87 88 89 90 91
const char** WMEffectiveConnectivityCluster::getXPMIcon() const
{
    return effectiveConnectivityCluster_xpm;
}

92 93
const std::string WMEffectiveConnectivityCluster::getName() const
{
94
    return WModuleContainer::getName();
95 96 97 98
}

const std::string WMEffectiveConnectivityCluster::getDescription() const
{
99
    return WModuleContainer::getDescription();
100 101
}

102 103 104 105 106
void WMEffectiveConnectivityCluster::fiberDataChange( boost::shared_ptr< WModuleConnector > /*input*/,
                                                      boost::shared_ptr< WModuleConnector > output )
{
    if ( !output )
    {
107 108 109
        m_labelActive = false;
        m_propCondition->notify();

110 111 112 113 114 115 116 117 118 119 120 121 122
        // if the connector gets reset -> ignore this case
        return;
    }

    // cast it to the target type
    boost::shared_ptr< WModuleOutputData < WFiberCluster > > o = boost::shared_static_cast< WModuleOutputData< WFiberCluster > >( output );
    if ( !o )
    {
        errorLog() << "New data is not a WFiberCluster? That should not happen!";
    }

    // grab data
    boost::shared_ptr< WFiberCluster > fibs = o->getData();
123
    boost::shared_ptr< wmath::WFiber > lline = fibs->getLongestLine();
124 125 126 127 128

    // the first and the last point of the longest line are required:
    m_labelPos2 = ( *lline )[ lline->size() - 2 ];
    m_labelPos1 = ( *lline )[ 1 ];

129 130
    m_labelActive = true;

131 132 133
    m_propCondition->notify();
}

134
void WMEffectiveConnectivityCluster::moduleMain()
135
{
136 137 138
    //////////////////////////////////////////////////////////////////////////////////
    // Fiber Selection
    //////////////////////////////////////////////////////////////////////////////////
139

140 141
    // create an instance using the prototypes
    m_fiberSelection = WModuleFactory::getModuleFactory()->create( WModuleFactory::getModuleFactory()->getPrototypeByName( "Fiber Selection" ) );
142

143 144
    // add to container
    add( m_fiberSelection );
145

146 147
    // now wait for it to be ready
    m_fiberSelection->isReady().wait();
148

149
    // set some props
150
    boost::shared_ptr< WProperties >  props = m_fiberSelection->getProperties();
151 152 153 154 155 156
    props->getProperty( "VOI1 threshold" )->toPropDouble()->set( 50.0 );
    props->getProperty( "VOI2 threshold" )->toPropDouble()->set( 50.0 );
    props->getProperty( "Cut fibers" )->toPropBool()->set( true );
    m_properties->addProperty( props->getProperty( "Cut fibers" ) );
    props->getProperty( "Prefer shortest path" )->toPropBool()->set( false );
    m_properties->addProperty( props->getProperty( "Prefer shortest path" ) );
157

158 159 160 161 162
    // as this module needs the centerline / longest line -> subscribe to the output connector DATA_CHANGE signal
    m_fiberSelection->getOutputConnector( "cluster" )->subscribeSignal( DATA_CHANGED,
        boost::bind( &WMEffectiveConnectivityCluster::fiberDataChange, this, _1, _2 )
    );

163 164 165
    //////////////////////////////////////////////////////////////////////
    // Voxelize
    //////////////////////////////////////////////////////////////////////
166

167 168
    // create an instance using the prototypes
    m_voxelizer = WModuleFactory::getModuleFactory()->create( WModuleFactory::getModuleFactory()->getPrototypeByName( "Voxelizer" ) );
169

170 171 172 173 174 175
    // add to container
    add( m_voxelizer );

    // now wait for it to be ready
    m_voxelizer->isReady().wait();

176
    // set/forward some props
177
    props = m_voxelizer->getProperties();
178
    props->getProperty( "Center line" )->toPropBool()->set( false );
179
    props->getProperty( "active" )->toPropBool()->set( false );
180 181
    props->getProperty( "Fiber tracts" )->toPropBool()->set( false );
    props->getProperty( "Display voxels" )->toPropBool()->set( false );
182 183
    props->getProperty( "Lighting" )->toPropBool()->set( false );

184
    // set longest line based parameterization
185
    props->getProperty( "Voxels per unit" )->toPropInt()->set( 2 );
186 187 188 189 190
    WItemSelector::IndexList idx;
    idx.push_back( 1 );
    props->getProperty( "Parameterization" )->toPropSelection()->set( props->getProperty( "Parameterization"
                )->toPropSelection()->get().newSelector( idx ) );

191
    m_properties->addProperty( props->getProperty( "Voxels per unit" ) );
192 193 194 195 196 197 198 199 200 201 202 203 204 205

    //////////////////////////////////////////////////////////////////////
    // Gauss Filter the voxel output
    //////////////////////////////////////////////////////////////////////

    // create an instance using the prototypes
    m_gauss = WModuleFactory::getModuleFactory()->create( WModuleFactory::getModuleFactory()->getPrototypeByName( "Gauss Filtering" ) );

    // add to container
    add( m_gauss );

    // now wait for it to be ready
    m_gauss->isReady().wait();

206
    // set/forward some props
207
    props = m_gauss->getProperties();
208
    props->getProperty( "Iterations" )->toPropInt()->set( 2 );
209 210 211 212 213 214

    //////////////////////////////////////////////////////////////////////
    // Animation
    //////////////////////////////////////////////////////////////////////

    // create an instance using the prototypes
Sebastian Eichelbaum's avatar
[STYLE]  
Sebastian Eichelbaum committed
215 216 217
    m_animation = WModuleFactory::getModuleFactory()->create(
            WModuleFactory::getModuleFactory()->getPrototypeByName( "Surface Parameter Animator" )
    );
218 219 220 221 222 223 224

    // add to container
    add( m_animation );

    // now wait for it to be ready
    m_animation->isReady().wait();

225
    // set/forward some props
226
    props = m_animation->getProperties();
227
    props->getProperty( "Isovalue" )->toPropInt()->set( 32 );
228
    m_properties->addProperty( props->getProperty( "Isovalue" ) );
229 230 231 232
    props->getProperty( "Step count" )->toPropInt()->set( 500 );
    m_properties->addProperty( props->getProperty( "Step count" ) );
    props->getProperty( "Iso color" )->toPropColor()->set( WColor( 0.0, 0.5, 1.0, 1.0 ) );
    m_properties->addProperty( props->getProperty( "Iso color" ) );
233
    props->getProperty( "Opacity %" )->toPropInt()->set( 100 );
234 235
    m_properties->addProperty( props->getProperty( "Opacity %" ) );
    m_properties->addProperty( props->getProperty( "Saturation %" ) );
236 237 238 239 240
    m_properties->addProperty( props->getProperty( "Beam1 size" ) );
    m_properties->addProperty( props->getProperty( "Beam2 size" ) );
    m_properties->addProperty( props->getProperty( "Beam1 speed" ) );
    m_properties->addProperty( props->getProperty( "Beam2 speed" ) );
    m_properties->addProperty( props->getProperty( "Parameter scale" ) );
241

242

243 244 245 246 247 248 249 250 251 252 253 254
    //////////////////////////////////////////////////////////////////////////////////
    // Hard wire the modules
    //////////////////////////////////////////////////////////////////////////////////

    // Connect voxelizer input with the selected fibers
    m_voxelizer->getInputConnector( "voxelInput" )->connect( m_fiberSelection->getOutputConnector( "cluster" ) );

    // Connect voxelizer output with the gauss filter
    m_gauss->getInputConnector( "in" )->connect( m_voxelizer->getOutputConnector( "voxelOutput" ) );

    // Connect voxelizer output with the animation
    m_animation->getInputConnector( "in" )->connect( m_gauss->getOutputConnector( "out" ) );
255
    m_animation->getInputConnector( "traces" )->connect( m_voxelizer->getOutputConnector( "parameterizationOutput" ) );
256 257 258 259 260 261

    // Connect inputs
    m_fiberInput->forward( m_fiberSelection->getInputConnector( "fibers" ) );
    m_VOI1->forward( m_fiberSelection->getInputConnector( "VOI1" ) );
    m_VOI2->forward( m_fiberSelection->getInputConnector( "VOI2" ) );

262 263 264
    // forward some results
    m_paramOutput->forward( m_voxelizer->getOutputConnector( "parameterizationOutput" ) );
    m_voxelOutput->forward( m_gauss->getOutputConnector( "out" ) );
265
    m_fiberOutput->forward( m_fiberSelection->getOutputConnector( "out" ) );
266

267 268 269 270 271
    //////////////////////////////////////////////////////////////////////////////////
    // Done!
    //////////////////////////////////////////////////////////////////////////////////

    // signal ready state
272 273
    ready();

274 275 276 277 278 279 280 281 282 283 284 285
    // wake up on property change
    m_moduleState.setResetable( true, true );
    m_moduleState.add( m_propCondition );

    // Signal ready state.
    ready();

    // add this module's group node
    m_rootNode->setNodeMask( m_active->get() ? 0xFFFFFFFF : 0x0 );
    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );

    // Now wait for data
286
    bool lastLabelActiveState = m_labelActive;
287 288 289 290 291 292 293 294 295 296
    while ( !m_shutdownFlag() )
    {
        m_moduleState.wait();

        // woke up since the module is requested to finish
        if ( m_shutdownFlag() )
        {
            break;
        }
        // has one of the properties changed?
297 298 299
        if ( m_labelActive && (
                    ( lastLabelActiveState != m_labelActive ) || m_voi1Name->changed() || m_voi2Name->changed() || m_labelCharacterSize->changed() )
           )
300
        {
301
            lastLabelActiveState = true;
302
            osg::ref_ptr< WGEBorderLayout > layouter = new WGEBorderLayout();
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
            std::string voi1 = m_voi1Name->get( true );
            std::string voi2 = m_voi2Name->get( true );
            if ( !voi1.empty() )
            {
                osg::ref_ptr< WGELabel > label1 = new WGELabel();
                label1->setText( voi1 );
                label1->setAnchor( wge::osgVec3( m_labelPos1 ) ); // the position relative to the current world coordinate system
                label1->setCharacterSize( m_labelCharacterSize->get( true ) );
                layouter->addLayoutable( label1 );
            }

            if ( !voi2.empty() )
            {
                osg::ref_ptr< WGELabel > label2 = new WGELabel();
                label2->setText( voi2 );
                label2->setAnchor( wge::osgVec3( m_labelPos2 ) ); // the position relative to the current world coordinate system
                label2->setCharacterSize( m_labelCharacterSize->get( true ) );
                layouter->addLayoutable( label2 );
            }
323 324

            m_rootNode->clear();
325
            m_rootNode->insert( layouter );
326 327
        }

328 329 330 331 332
        // remove labels if no dataset is connected anymore
        if ( !m_labelActive )
        {
            m_rootNode->clear();
        }
333 334 335 336 337
    }

    // At this point, the container managing this module signalled to shutdown. The main loop has ended and you should clean up. Always remove
    // allocated memory and remove all OSG nodes.
    WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
338 339 340

    // stop container and the contained modules.
    stop();
341 342
}

343
void WMEffectiveConnectivityCluster::connectors()
344
{
345 346 347 348 349 350 351 352 353 354 355 356 357 358
    // this is the scalar field input
    m_VOI1 = boost::shared_ptr< WModuleInputForwardData< WDataSetSingle > >(
        new WModuleInputForwardData< WDataSetSingle >( shared_from_this(),
                              "VOI1", "The first volume of interest." )
        );

    // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
    addConnector( m_VOI1 );

    // this is the scalar field input
    m_VOI2 = boost::shared_ptr< WModuleInputForwardData< WDataSetSingle > >(
        new WModuleInputForwardData< WDataSetSingle >( shared_from_this(),
                              "VOI2", "The second volume of interest." )
        );
359

360 361 362 363 364 365 366 367 368 369 370 371
    // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
    addConnector( m_VOI2 );

    // this is the scalar field input
    m_fiberInput = boost::shared_ptr< WModuleInputForwardData< WDataSetFibers > >(
        new WModuleInputForwardData< WDataSetFibers >( shared_from_this(),
                              "fibers", "The fiber dataset used to find connection path." )
        );

    // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
    addConnector( m_fiberInput );

372 373 374 375
    // forwarder for some results
    // this is the parameter field
    m_paramOutput = boost::shared_ptr< WModuleOutputForwardData< WDataSetScalar > >(
        new WModuleOutputForwardData< WDataSetScalar >( shared_from_this(),
376
                              "paramOut", "The voxelized fiber parameterization field." )
377 378 379
        );
    addConnector( m_paramOutput );

380
    // this is the voxel field
381 382
    m_voxelOutput = boost::shared_ptr< WModuleOutputForwardData< WDataSetScalar > >(
        new WModuleOutputForwardData< WDataSetScalar >( shared_from_this(),
383
                              "voxelsOut", "The voxelized fibers." )
384 385 386
        );
    addConnector( m_voxelOutput );

387 388 389 390 391 392 393
    // these are the fibers
    m_fiberOutput = boost::shared_ptr< WModuleOutputForwardData< WDataSetFibers > >(
        new WModuleOutputForwardData< WDataSetFibers >( shared_from_this(),
                              "fibersOut", "The voxelized fibers." )
        );
    addConnector( m_fiberOutput );

394 395
    // call WModules initialization
    WModule::connectors();
396 397
}

398 399 400 401 402
void WMEffectiveConnectivityCluster::properties()
{
    // Initialize the properties
    m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );

403 404
    m_voi1Name = m_properties->addProperty( "Name of VOI1", "The name of the VOI1.", std::string( "" ), m_propCondition );
    m_voi2Name = m_properties->addProperty( "Name of VOI2", "The name of the VOI2.", std::string( "" ), m_propCondition );
405

406
    m_labelCharacterSize = m_properties->addProperty( "Font size", "The size of the label fonts.", 20, m_propCondition );
407 408
}

409
void WMEffectiveConnectivityCluster::activate()
410
{
411
    m_animation->getProperties()->getProperty( "active" )->toPropBool()->set( m_active->get() );
412 413
}