Commit a679dfb2 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE] - seperated marching cubes and distance map modules

[ADD] - added possibility to combine modules inside of modules
parent eb108974
......@@ -40,6 +40,7 @@
#include "exceptions/WModuleSignalUnknown.h"
#include "exceptions/WModuleSignalSubscriptionFailed.h"
#include "exceptions/WModuleConnectorInitFailed.h"
#include "exceptions/WModuleConnectorNotFound.h"
#include "exceptions/WModuleUninitialized.h"
#include "../common/WException.h"
#include "../common/WLogger.h"
......@@ -171,6 +172,38 @@ const std::set<boost::shared_ptr< WModuleOutputConnector > >& WModule::getOutput
return m_outputConnectors;
}
boost::shared_ptr< WModuleInputConnector > WModule::getInputConnector( std::string name ) const
{
// simply search
for( std::set<boost::shared_ptr< WModuleInputConnector > >::iterator listIter = m_inputConnectors.begin();
listIter != m_inputConnectors.end(); ++listIter )
{
// try the canonical name
if ( ( name == ( *listIter )->getCanonicalName() ) || ( name == ( *listIter )->getName() ) )
{
return ( *listIter );
}
}
throw WModuleConnectorNotFound( "The connector \"" + name + "\" does not exist in the module \"" + getName() + "\"." );
}
boost::shared_ptr< WModuleOutputConnector > WModule::getOutputConnector( std::string name ) const
{
// simply search
for( std::set<boost::shared_ptr< WModuleOutputConnector > >::iterator listIter = m_outputConnectors.begin();
listIter != m_outputConnectors.end(); ++listIter )
{
// try the canonical name
if ( ( name == ( *listIter )->getCanonicalName() ) || ( name == ( *listIter )->getName() ) )
{
return ( *listIter );
}
}
throw WModuleConnectorNotFound( "The connector \"" + name + "\" does not exist in the module \"" + getName() + "\"." );
}
boost::signals2::connection WModule::subscribeSignal( MODULE_SIGNAL signal, t_ModuleGenericSignalHandlerType notifier )
{
switch ( signal )
......
......@@ -88,6 +88,16 @@ public:
*/
const std::set< boost::shared_ptr< WModuleInputConnector > >& getInputConnectors() const;
/**
* Finds the named connector for the module.
*
* \param name the name. This can be a canonical name or the connector name.
*
* \return the connector.
* \throw WModuleConnectorNotFound thrown whenever the module does not provide the specified connector.
*/
boost::shared_ptr< WModuleInputConnector > getInputConnector( std::string name ) const;
/**
* Gives back output connectors.
*
......@@ -95,6 +105,16 @@ public:
*/
const std::set< boost::shared_ptr< WModuleOutputConnector > >& getOutputConnectors() const;
/**
* Finds the named connector for the module.
*
* \param name the name. This can be a canonical name or the connector name.
*
* \return the connector.
* \throw WModuleConnectorNotFound thrown whenever the module does not provide the specified connector.
*/
boost::shared_ptr< WModuleOutputConnector > getOutputConnector( std::string name ) const;
/**
* Return a pointer to the properties object of the module
*/
......
......@@ -33,6 +33,7 @@
#include <boost/signals2/connection.hpp>
#include "WModule.h"
#include "WModuleContainer.h"
#include "exceptions/WModuleConnectionFailed.h"
#include "exceptions/WModuleConnectionInvalid.h"
#include "exceptions/WModuleDisconnectFailed.h"
......@@ -91,6 +92,10 @@ bool WModuleConnector::isConnectedTo( boost::shared_ptr<WModuleConnector> con )
void WModuleConnector::connect( boost::shared_ptr<WModuleConnector> con )
{
WLogger::getLogger()->addLogMessage( "Connecting " + con->getCanonicalName() + " with " + getCanonicalName()
, "ModuleContainer (" + m_module->getAssociatedContainer()->getName() + ")", LL_INFO );
// are both partners compatible to each other?
if ( !( con->connectable( shared_from_this() ) && connectable( con ) ) )
{
......
......@@ -131,7 +131,8 @@ public:
const std::string getName() const;
/**
* Gives canonical name of connection. The canonical name is a descriptor including module name.
* Gives canonical name of connection. The canonical name is a descriptor including module name. The description is
* ModuleName:ConnectorName.
*
* \return The name of this connection
*/
......
......@@ -43,11 +43,11 @@
#include "WModuleContainer.h"
WModuleContainer::WModuleContainer( std::string name, std::string description ):
boost::enable_shared_from_this< WModuleContainer >(),
WModule(),
m_name( name ),
m_description( description )
{
WLogger::getLogger()->addLogMessage( "Constructing module container." , "ModuleContainer (" + m_name + ")", LL_INFO );
WLogger::getLogger()->addLogMessage( "Constructing module container." , "ModuleContainer (" + getName() + ")", LL_INFO );
// initialize members
}
......@@ -56,14 +56,28 @@ WModuleContainer::~WModuleContainer()
// cleanup
}
void WModuleContainer::moduleMain()
{
// do nothing here. The WModule class enforces us to overwrite this method here, but we do not need it.
// Only set the ready flag.
ready();
}
boost::shared_ptr< WModule > WModuleContainer::factory() const
{
// this factory is not used actually.
return boost::shared_ptr< WModule >( new WModuleContainer( getName(), getDescription() ) );
}
void WModuleContainer::add( boost::shared_ptr< WModule > module, bool run )
{
WLogger::getLogger()->addLogMessage( "Adding module \"" + module->getName() + "\" to container." , "ModuleContainer (" + m_name + ")", LL_INFO );
WLogger::getLogger()->addLogMessage( "Adding module \"" + module->getName() + "\" to container." ,
"ModuleContainer (" + getName() + ")", LL_INFO );
if ( !module->isInitialized()() )
{
std::ostringstream s;
s << "Could not add module \"" << module->getName() << "\" to container \"" + m_name + "\". Reason: module not initialized.";
s << "Could not add module \"" << module->getName() << "\" to container \"" + getName() + "\". Reason: module not initialized.";
throw WModuleUninitialized( s.str() );
}
......@@ -84,8 +98,8 @@ void WModuleContainer::add( boost::shared_ptr< WModule > module, bool run )
boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_moduleSetLock );
m_modules.insert( module );
lock.unlock();
module->setAssociatedContainer( shared_from_this() );
WLogger::getLogger()->addLogMessage( "Associated module \"" + module->getName() + "\" with container." , "ModuleContainer (" + m_name + ")",
module->setAssociatedContainer( boost::shared_static_cast< WModuleContainer >( shared_from_this() ) );
WLogger::getLogger()->addLogMessage( "Associated module \"" + module->getName() + "\" with container." , "ModuleContainer (" + getName() + ")",
LL_INFO );
// now module->isUsable() is true
......@@ -110,6 +124,9 @@ void WModuleContainer::add( boost::shared_ptr< WModule > module, bool run )
}
slock.unlock();
// add the modules progress to local progress combiner
m_progress->addSubProgress( module->getRootProgressCombiner() );
// run it
if ( run )
{
......@@ -119,7 +136,7 @@ void WModuleContainer::add( boost::shared_ptr< WModule > module, bool run )
void WModuleContainer::remove( boost::shared_ptr< WModule > module )
{
WLogger::getLogger()->addLogMessage( "Removing module \"" + module->getName() + "\" from container." , "ModuleContainer (" + m_name + ")",
WLogger::getLogger()->addLogMessage( "Removing module \"" + module->getName() + "\" from container." , "ModuleContainer (" + getName() + ")",
LL_DEBUG );
if ( module->getAssociatedContainer() != shared_from_this() )
......@@ -128,7 +145,7 @@ void WModuleContainer::remove( boost::shared_ptr< WModule > module )
}
// stop module
WLogger::getLogger()->addLogMessage( "Waiting for module \"" + module->getName() + "\" to finish." , "ModuleContainer (" + m_name + ")",
WLogger::getLogger()->addLogMessage( "Waiting for module \"" + module->getName() + "\" to finish." , "ModuleContainer (" + getName() + ")",
LL_DEBUG );
module->wait( true );
......@@ -145,7 +162,7 @@ void WModuleContainer::remove( boost::shared_ptr< WModule > module )
void WModuleContainer::stop()
{
WLogger::getLogger()->addLogMessage( "Stopping pending threads." , "ModuleContainer (" + m_name + ")", LL_INFO );
WLogger::getLogger()->addLogMessage( "Stopping pending threads." , "ModuleContainer (" + getName() + ")", LL_INFO );
// read lock
boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_pendingThreadsLock );
......@@ -156,14 +173,14 @@ void WModuleContainer::stop()
}
slock.unlock();
WLogger::getLogger()->addLogMessage( "Stopping modules." , "ModuleContainer (" + m_name + ")", LL_INFO );
WLogger::getLogger()->addLogMessage( "Stopping modules." , "ModuleContainer (" + getName() + ")", LL_INFO );
// read lock
slock = boost::shared_lock<boost::shared_mutex>( m_moduleSetLock );
for( std::set< boost::shared_ptr< WModule > >::iterator listIter = m_modules.begin(); listIter != m_modules.end(); ++listIter )
{
WLogger::getLogger()->addLogMessage( "Waiting for module \"" + ( *listIter )->getName() + "\" to finish." ,
"ModuleContainer (" + m_name + ")", LL_INFO );
"ModuleContainer (" + getName() + ")", LL_INFO );
( *listIter )->wait( true );
}
slock.unlock();
......@@ -250,8 +267,6 @@ boost::shared_ptr< WModule > WModuleContainer::applyModule( boost::shared_ptr< W
std::set<boost::shared_ptr<WModuleOutputConnector> > outs = applyOn->getOutputConnectors();
// TODO(ebaum): search best matching instead of simply connecting both
WLogger::getLogger()->addLogMessage( "Connecting " + ( *outs.begin() )->getCanonicalName() + " with " + ( *ins.begin() )->getCanonicalName()
, "ModuleContainer", LL_INFO );
( *ins.begin() )->connect( ( *outs.begin() ) );
return m;
......@@ -260,7 +275,9 @@ boost::shared_ptr< WModule > WModuleContainer::applyModule( boost::shared_ptr< W
boost::shared_ptr< WBatchLoader > WModuleContainer::loadDataSets( std::vector< std::string > fileNames )
{
// create thread which actually loads the data
boost::shared_ptr< WBatchLoader > t = boost::shared_ptr< WBatchLoader >( new WBatchLoader( fileNames, shared_from_this() ) );
boost::shared_ptr< WBatchLoader > t = boost::shared_ptr< WBatchLoader >( new WBatchLoader( fileNames,
boost::shared_static_cast< WModuleContainer >( shared_from_this() ) )
);
t->run();
return t;
}
......@@ -268,7 +285,9 @@ boost::shared_ptr< WBatchLoader > WModuleContainer::loadDataSets( std::vector< s
void WModuleContainer::loadDataSetsSynchronously( std::vector< std::string > fileNames )
{
// create thread which actually loads the data
boost::shared_ptr< WBatchLoader > t = boost::shared_ptr< WBatchLoader >( new WBatchLoader( fileNames, shared_from_this() ) );
boost::shared_ptr< WBatchLoader > t = boost::shared_ptr< WBatchLoader >( new WBatchLoader( fileNames,
boost::shared_static_cast< WModuleContainer >( shared_from_this() ) )
);
t->run();
t->wait();
}
......
......@@ -45,7 +45,7 @@ class WModule;
*
* \ingroup Kernel
*/
class WModuleContainer: public boost::enable_shared_from_this< WModuleContainer >
class WModuleContainer: public WModule
{
public:
......@@ -55,7 +55,8 @@ public:
* \param name name of the container
* \param description short description.
*/
WModuleContainer( std::string name, std::string description );
WModuleContainer( std::string name = "Unnamed Module Container",
std::string description = "Used as container for several modules." );
/**
* Destructor.
......@@ -167,8 +168,22 @@ public:
*/
void finishedPendingThread( boost::shared_ptr< WThreadedRunner > thread );
/**
* Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
* should never be initialized or modified in some other way. A simple new instance is required.
*
* \return the prototype used to create every module in OpenWalnut.
*/
virtual boost::shared_ptr< WModule > factory() const;
protected:
/**
* Entry point after loading the module. Runs in separate thread. The module container does not use this method. It simply
* returns.
*/
virtual void moduleMain();
/**
* Lock for module set.
*/
......
......@@ -31,6 +31,7 @@
#include "../modules/coordinateSystem/WMCoordinateSystem.h"
#include "../modules/boundingBox/WMBoundingBox.h"
#include "../modules/data/WMData.h"
#include "../modules/distanceMap/WMDistanceMapIsosurface.h"
#include "../modules/distanceMap/WMDistanceMap.h"
#include "../modules/eegView/WMEEGView.h"
#include "../modules/fiberClustering/WMFiberClustering.h"
......@@ -79,6 +80,7 @@ void WModuleFactory::load()
m_prototypes.insert( boost::shared_ptr< WModule >( new WMFiberClustering() ) );
m_prototypes.insert( boost::shared_ptr< WModule >( new WMCoordinateSystem() ) );
m_prototypes.insert( boost::shared_ptr< WModule >( new WMMarchingCubes() ) );
m_prototypes.insert( boost::shared_ptr< WModule >( new WMDistanceMapIsosurface() ) );
m_prototypes.insert( boost::shared_ptr< WModule >( new WMDistanceMap() ) );
m_prototypes.insert( boost::shared_ptr< WModule >( new WMTextureList() ) );
m_prototypes.insert( boost::shared_ptr< WModule >( new WMGaussFiltering() ) );
......@@ -108,7 +110,7 @@ void WModuleFactory::load()
}
names.insert( ( *listIter )->getName() );
( *listIter )->initialize();
initializeModule( ( *listIter ) );
}
slock.unlock();
......@@ -129,11 +131,16 @@ boost::shared_ptr< WModule > WModuleFactory::create( boost::shared_ptr< WModule
// call prototypes factory function
boost::shared_ptr< WModule > clone = boost::shared_ptr< WModule >( prototype->factory() );
clone->initialize();
initializeModule( clone );
return clone;
}
void WModuleFactory::initializeModule( boost::shared_ptr< WModule > module )
{
module->initialize();
}
boost::shared_ptr< WModuleFactory > WModuleFactory::getModuleFactory()
{
if ( !m_instance )
......
......@@ -120,6 +120,15 @@ public:
* \return set of compatible prototypes.
*/
std::set< boost::shared_ptr< WModule > > getCompatiblePrototypes( boost::shared_ptr< WModule > module );
/**
* This method uses a newly created instance of WModule and initializes it properly. After using this method, the module is
* properly initialized and ready to be used.
*
* \param module the module to initialize.
*/
static void initializeModule( boost::shared_ptr< WModule > module );
protected:
/**
......
//---------------------------------------------------------------------------
//
// 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>
#include "WModuleConnectorNotFound.h"
WModuleConnectorNotFound::WModuleConnectorNotFound( const std::string& msg ): WModuleException( msg )
{
// initialize members
}
WModuleConnectorNotFound::~WModuleConnectorNotFound() throw()
{
// cleanup
}
//---------------------------------------------------------------------------
//
// 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/>.
//
//---------------------------------------------------------------------------
#ifndef WMODULECONNECTORNOTFOUND_H
#define WMODULECONNECTORNOTFOUND_H
#include <string>
#include "WModuleException.h"
/**
* General purpose exception and therefore base class for all kernel related exceptions.
* \ingroup kernel
*/
class WModuleConnectorNotFound: public WModuleException
{
public:
/**
* Default constructor.
* \param msg the exception message.
*/
explicit WModuleConnectorNotFound( const std::string& msg = "Module connector could not be found." );
/**
* Destructor.
*/
virtual ~WModuleConnectorNotFound() throw();
protected:
private:
};
#endif // WMODULECONNECTORNOTFOUND_H
......@@ -28,18 +28,21 @@
#include <vector>
#include "WMDistanceMap.h"
#include "../marchingCubes/WMMarchingCubes.h"
#include "../../kernel/WKernel.h"
#include "../../kernel/WModuleFactory.h"
#include "../../dataHandler/WSubject.h"
#include "../../dataHandler/WGridRegular3D.h"
#include "../../common/WProgress.h"
WMDistanceMap::WMDistanceMap():
WModule()
{
// WARNING: initializing connectors inside the constructor will lead to an exception.
// Implement WModule::initializeConnectors instead.
// 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).
}
WMDistanceMap::~WMDistanceMap()
{
// cleanup
......@@ -59,15 +62,14 @@ const std::string WMDistanceMap::getName() const
const std::string WMDistanceMap::getDescription() const
{
return "This description has to be improved when the module is completed."
" By now lets say the following: Computes a smoothed version of the dataset"
" and a distance map on it. Finally it renders this distance map using MarchinCubes";
" By now lets say the following: Computes a smoothed version of the dataset"
" and a distance map on it. Finally it renders this distance map using MarchinCubes";
}
void WMDistanceMap::moduleMain()
{
// use the m_input "data changed" flag
m_moduleState.setResetable( true, true );
m_moduleState.add( m_input->getDataChangedCondition() );
// signal ready state
......@@ -76,21 +78,28 @@ void WMDistanceMap::moduleMain()
// loop until the module container requests the module to quit
while ( !m_shutdownFlag() )
{
boost::shared_ptr< const WDataSetSingle > dataSet = m_input->getData();
boost::shared_ptr< WValueSet< float > > distanceMapValueSet = createOffset( dataSet );
boost::shared_ptr< WMMarchingCubes > mc = boost::shared_ptr< WMMarchingCubes >( new WMMarchingCubes() );
mc->generateSurface( dataSet->getGrid(), distanceMapValueSet, .4 );
WLogger::getLogger()->addLogMessage( "Rendering surface ...", "Distance Map", LL_INFO );
// acquire data from the input connector
m_dataSet = m_input->getData();
if ( !m_dataSet.get() )
{
// OK, the output has not yet sent data
// NOTE: see comment at the end of this while loop for m_moduleState
debugLog() << "Waiting for data ...";
m_moduleState.wait();
continue;
}
mc->renderSurface();
// found some data
debugLog() << "Data changed. Updating ...";
boost::shared_ptr< WValueSet< float > > distanceMapValueSet = createOffset( m_dataSet );
m_distanceMapDataSet = boost::shared_ptr< WDataSetSingle >( new WDataSetSingle( distanceMapValueSet, m_dataSet->getGrid() ) );
WLogger::getLogger()->addLogMessage( "Done!", "Distance Map", LL_INFO );
// this waits for m_moduleState to fire. By default, this is only the m_shutdownFlag condition.
// NOTE: you can add your own conditions to m_moduleState using m_moduleState.add( ... )
// update the output
m_output->updateData( m_distanceMapDataSet );
// wait for new data change event or quit event
m_moduleState.wait();
}
}
......@@ -107,13 +116,21 @@ void WMDistanceMap::connectors()
// add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
addConnector( m_input );
// call WModules initialization
m_output = boost::shared_ptr<WModuleOutputData< WDataSetSingle > >(
new WModuleOutputData< WDataSetSingle >( shared_from_this(),
"out", "Distance map for the input data set." )
);
// 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 WModule's initialization
WModule::connectors();
}
void WMDistanceMap::properties()
{
// ( m_properties->addDouble( "isoValue", 80 ) )->connect( boost::bind( &WMMarchingCubes::slotPropertyChanged, this, _1 ) );
// no properties
}
template< typename T > boost::shared_ptr< WValueSet< float > > makeFloatValueSetHelper( boost::shared_ptr< WValueSet< T > > inSet )
......@@ -157,8 +174,6 @@ boost::shared_ptr< WValueSet< float > > makeFloatValueSet( boost::shared_ptr< WV
}
}
boost::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( boost::shared_ptr< const WDataSetSingle > dataSet )
{
std::vector<float> floatDataset;
......@@ -213,8 +228,14 @@ boost::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( boost::shar
dmax = 999999999.0;
// first pass
boost::shared_ptr< WProgress > progress1 = boost::shared_ptr< WProgress >(
new WProgress( "Distance Map", nbands + nbands + nrows + nbands + nbands + nbands )
);
m_progress->addSubProgress( progress1 );
for( b = 0; b < nbands; ++b)
{
++*progress1;
for( r = 0; r < nrows; ++r)
{
for( c = 0; c < ncols; ++c)
......@@ -256,6 +277,7 @@ boost::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( boost::shar
// second pass
for( b = 0; b < nbands; b++ )
{
++*progress1;
for( c = 0; c < ncols; c++ )
{
for( r = 0; r < nrows; r++ )
......@@ -291,9 +313,9 @@ boost::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( boost::shar
}
// third pass
for( r = 0; r < nrows; r++ )
{
++*progress1;
for( c = 0; c < ncols; c++ )
{
for( b = 0; b < nbands; b++ )
......@@ -385,6 +407,7 @@ boost::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( boost::shar
for( b = 0; b < nbands; ++b )
{
++*progress1;
for( r = 0; r < nrows; ++r )
{
for( c = d; c < ncols - d; ++c )
......@@ -405,6 +428,7 @@ boost::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( boost::shar
int r1;
for( b = 0; b < nbands; ++b )
{
++*progress1;
for( r = d; r < nrows - d; ++r )
{
for( c = 0; c < ncols; ++c )
......@@ -425,6 +449,7 @@ boost::shared_ptr< WValueSet< float > > WMDistanceMap::createOffset( boost::shar
int b1;
for( b = d; b < nbands - d; ++b )