Commit 312af7d3 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE] - now WProperties2 uses WSharedObject

[CHANGE] - updating texture is now done using conditions
[CHANGE] - datasets now can propagate change events
parent e4c4b1c7
......@@ -33,9 +33,8 @@
#include "WProperties2.h"
WProperties2::WProperties2():
m_iterationLock( boost::shared_lock< boost::shared_mutex >( m_updateLock ) )
m_propAccess( m_properties.getAccessObject() )
{
m_iterationLock.unlock();
}
WProperties2::~WProperties2()
......@@ -44,33 +43,19 @@ WProperties2::~WProperties2()
void WProperties2::addProperty( boost::shared_ptr< WPropertyBase > prop )
{
boost::unique_lock< boost::shared_mutex > lock = boost::unique_lock< boost::shared_mutex >( m_updateLock );
m_properties.push_back( prop );
lock.unlock();
}
bool WProperties2::existsProperty( std::string name )
{
return ( findProperty( name ) != boost::shared_ptr< WPropertyBase >() );
}
boost::shared_ptr< WPropertyBase > WProperties2::getProperty( std::string name )
{
boost::shared_ptr< WPropertyBase > p = findProperty( name );
if ( findProperty( name ) == boost::shared_ptr< WPropertyBase >() )
{
throw WPropertyUnknown( "Property \"" + name + "\" can't be found." );
}
return p;
m_propAccess->beginWrite();
m_propAccess->get().push_back( prop );
m_propAccess->endWrite();
}
boost::shared_ptr< WPropertyBase > WProperties2::findProperty( std::string name )
{
boost::shared_ptr< WPropertyBase > result = boost::shared_ptr< WPropertyBase >();
m_propAccess->beginRead();
// iterate over the items
for ( PropertyIterator it = beginIteration(); it != getPropertyIteratorEnd(); ++it )
for ( PropertyContainerType::const_iterator it = m_propAccess->get().begin(); it != m_propAccess->get().end(); ++it )
{
if ( ( *it )->getName() == name )
{
......@@ -78,28 +63,32 @@ boost::shared_ptr< WPropertyBase > WProperties2::findProperty( std::string name
break;
}
}
endIteration();
m_propAccess->endRead();
return result;
}
const WProperties2::PropertyIterator WProperties2::beginIteration()
bool WProperties2::existsProperty( std::string name )
{
m_iterationLock.lock();
return m_properties.begin();
return ( findProperty( name ) != boost::shared_ptr< WPropertyBase >() );
}
void WProperties2::endIteration()
boost::shared_ptr< WPropertyBase > WProperties2::getProperty( std::string name )
{
m_iterationLock.unlock();
boost::shared_ptr< WPropertyBase > p = findProperty( name );
if ( p == boost::shared_ptr< WPropertyBase >() )
{
throw WPropertyUnknown( "Property \"" + name + "\" can't be found." );
}
return p;
}
const WProperties2::PropertyIterator WProperties2::getPropertyIteratorEnd() const
WProperties2::PropertySharedContainerType::WSharedAccess WProperties2::getAccessObject()
{
return m_properties.end();
return m_properties.getAccessObject();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// convenience methods for
// template< typename T>
......
......@@ -34,6 +34,7 @@
#include <boost/thread/locks.hpp>
#include <boost/thread.hpp>
#include "WSharedObject.h"
#include "WPropertyBase.h"
#include "WPropertyVariable.h"
......@@ -45,10 +46,32 @@ class WProperties2
{
public:
// the following typedefs are for convenience.
/**
* For shortening: a type defining a shared vector of WSubject pointers.
*/
typedef std::vector< boost::shared_ptr< WPropertyBase > > PropertyContainerType;
/**
* The alias for a shared container.
*/
typedef WSharedObject< PropertyContainerType > PropertySharedContainerType;
/**
* The access type
*/
typedef PropertySharedContainerType::WSharedAccess PropertyAccessType;
/**
* The iterator used to iterate over the property set
* The const iterator type of the container.
*/
typedef std::vector< boost::shared_ptr< WPropertyBase > >::const_iterator PropertyIterator;
typedef PropertyContainerType::const_iterator PropertyConstIterator;
/**
* The iterator type of the container.
*/
typedef PropertyContainerType::iterator PropertyIterator;
/**
* standard constructor
......@@ -94,23 +117,11 @@ public:
boost::shared_ptr< WPropertyBase > findProperty( std::string name );
/**
* Iterator over all property elements. This locks the property set for writing. endIteration() frees the lock.
* Returns the access object usable to iterate/modify the property list in a thread safe manner.
*
* \return the list of properties.
*/
const PropertyIterator beginIteration();
/**
* To iterate over all set elements. Use this method to denote the end of iteration. This allows others to write to the set again.
* \return the access control object.
*/
void endIteration();
/**
* Iterator denoting the end of the property set.
*
* \return the list of properties.
*/
const PropertyIterator getPropertyIteratorEnd() const;
PropertySharedContainerType::WSharedAccess getAccessObject();
///////////////////////////////////////////////////////////////////////////////////////////////////
// Convenience methods to create and add properties
......@@ -743,19 +754,14 @@ public:
private:
/**
* The set of proerties. This uses the operators ==,<,> WProperty to determine equalnes.
*/
std::vector< boost::shared_ptr< WPropertyBase > > m_properties;
/**
* boost mutex object for thread safety of updating of properties
* The set of proerties. This uses the operators ==,<,> WProperty to determine equalness.
*/
boost::shared_mutex m_updateLock;
PropertySharedContainerType m_properties;
/**
* The lock for a thread safe iteration.
* Access to the above property list.
*/
boost::shared_lock< boost::shared_mutex > m_iterationLock;
PropertySharedContainerType::WSharedAccess m_propAccess;
};
template< typename T>
......
......@@ -27,8 +27,12 @@
#include <boost/thread.hpp>
#include "WCondition.h"
/**
* Wrapper around an object/type for thread safe sharing of objects among multiple threads.
* Wrapper around an object/type for thread safe sharing of objects among multiple threads. The advantage of this class over WFlag
* is, that WFlag just protects simple get/set operations, while this class can protect a whole bunch of operations on the
* encapsulated object.
*/
template < typename T >
class WSharedObject
......@@ -56,8 +60,18 @@ public:
* Constructor. It uses the specified mutex which is shared among all access objects of the same WSharedObject.
*
* \param mutex the mutex used to lock the access.
* \param object the object to be shared.
* \param condition the condition that should be used for notifying changes.
*/
WSharedObjectAccess( T& object, boost::shared_ptr< boost::shared_mutex > mutex, boost::shared_ptr< WCondition > condition );
/**
* Constructor. It uses the specified mutex which is shared among all access objects of the same WSharedObject.
*
* \param mutex the mutex used to lock the access.
* \param object the object to be shared.
*/
explicit WSharedObjectAccess( T& object, boost::shared_ptr< boost::shared_mutex > mutex );
WSharedObjectAccess( T& object, boost::shared_ptr< boost::shared_mutex > mutex );
/**
* Desctructor.
......@@ -91,8 +105,10 @@ public:
/**
* Frees the lock to the object. If you do not free the lock, no read or write access will be granted in the future. To nobody!
* So always free the lock.
*
* \param suppressNotify if true, the change condition won't fire.
*/
void endWrite();
void endWrite( bool suppressNotify = false );
protected:
......@@ -115,6 +131,11 @@ public:
* the object protected.
*/
T& m_object;
/**
* The pointer to the global change condition. Fired whenever endWrite() got called.
*/
boost::shared_ptr< WCondition > m_objectChangeCondition;
};
/**
......@@ -130,6 +151,13 @@ public:
*/
WSharedAccess getAccessObject();
/**
* This condition fires whenever the encapsulated object changed. This is fired automatically by endWrite().
*
* \return the condition
*/
boost::shared_ptr< WCondition > getChangeCondition();
protected:
/**
......@@ -142,12 +170,18 @@ protected:
*/
boost::shared_ptr< boost::shared_mutex > m_lock;
/**
* This condition set fires whenever the contained object changes. This corresponds to the Observable pattern.
*/
boost::shared_ptr< WCondition > m_changeCondition;
private:
};
template < typename T >
WSharedObject< T >::WSharedObject():
m_lock( new boost::shared_mutex )
m_lock( new boost::shared_mutex ),
m_changeCondition( new WCondition() )
{
// init members
}
......@@ -161,14 +195,24 @@ WSharedObject< T >::~WSharedObject()
template < typename T >
typename WSharedObject< T >::WSharedAccess WSharedObject< T >::getAccessObject()
{
return WSharedObject< T >::WSharedAccess( new WSharedObject< T>::WSharedObjectAccess( m_object, m_lock ) );
return WSharedObject< T >::WSharedAccess( new WSharedObject< T>::WSharedObjectAccess( m_object, m_lock, m_changeCondition ) );
}
template < typename T >
WSharedObject< T >::WSharedObjectAccess::WSharedObjectAccess( T& object, boost::shared_ptr< boost::shared_mutex > mutex ):
m_lock( mutex ),
m_object( object )
m_object( object ),
m_objectChangeCondition()
{
}
template < typename T >
WSharedObject< T >::WSharedObjectAccess::WSharedObjectAccess( T& object, boost::shared_ptr< boost::shared_mutex > mutex,
boost::shared_ptr< WCondition > condition ):
m_lock( mutex ),
m_object( object ),
m_objectChangeCondition( condition )
{
}
......@@ -199,9 +243,14 @@ void WSharedObject< T >::WSharedObjectAccess::beginWrite()
}
template < typename T >
void WSharedObject< T >::WSharedObjectAccess::endWrite()
void WSharedObject< T >::WSharedObjectAccess::endWrite( bool suppressNotify )
{
m_writeLock.unlock();
if ( !suppressNotify && m_objectChangeCondition.get() )
{
m_objectChangeCondition->notify();
}
}
template < typename T >
......@@ -210,5 +259,11 @@ T& WSharedObject< T >::WSharedObjectAccess::get()
return m_object;
}
template < typename T >
boost::shared_ptr< WCondition > WSharedObject< T >::getChangeCondition()
{
return m_changeCondition;
}
#endif // WSHAREDOBJECT_H
......@@ -105,6 +105,7 @@ void WSharedSequenceContainer< T, S >::push_back( const T& x )
typename WSharedObject< S >::WSharedAccess a = WSharedObject< S >::getAccessObject();
a->beginWrite();
a->get().push_back( x );
a->endWrite();
}
template < typename T, typename S >
......@@ -113,6 +114,7 @@ void WSharedSequenceContainer< T, S >::pop_back()
typename WSharedObject< S >::WSharedAccess a = WSharedObject< S >::getAccessObject();
a->beginWrite();
a->get().pop_back();
a->endWrite();
}
template < typename T, typename S >
......@@ -121,6 +123,7 @@ void WSharedSequenceContainer< T, S >::clear()
typename WSharedObject< S >::WSharedAccess a = WSharedObject< S >::getAccessObject();
a->beginWrite();
a->get().clear();
a->endWrite();
}
template < typename T, typename S >
......@@ -130,6 +133,7 @@ size_t WSharedSequenceContainer< T, S >::size()
a->beginRead();
size_t size = a->get().size();
return size;
a->endRead();
// NOTE: the lock in access object a is freed automatically
}
......
......@@ -43,6 +43,7 @@ WDataHandler::WDataHandler():
m_subjectAccess( m_subjects.getAccessObject() )
{
WLogger::getLogger()->addLogMessage( "Initializing Data Handler", "Data Handler", LL_INFO );
addSubject( boost::shared_ptr< WSubject >( new WSubject( WPersonalInformation::createDummyInformation() ) ) );
}
WDataHandler::~WDataHandler()
......@@ -116,7 +117,7 @@ boost::shared_ptr< WSubject > WDataHandler::getSubjectByID( size_t subjectID )
throw WDHNoSuchSubject();
}
m_subjectAccess->endWrite();
m_subjectAccess->endRead();
return result;
}
......@@ -131,3 +132,18 @@ boost::shared_ptr< WDataHandler > WDataHandler::getDataHandler()
return m_instance;
}
boost::shared_ptr< WSubject > WDataHandler::getDefaultSubject()
{
return getDataHandler()->getSubjectByID( WSubject::SUBJECT_UNKNOWN );
}
void WDataHandler::registerDataSet( boost::shared_ptr< WDataSet > dataset )
{
getDefaultSubject()->addDataSet( dataset );
}
void WDataHandler::deregisterDataSet( boost::shared_ptr< WDataSet > dataset )
{
getDefaultSubject()->removeDataSet( dataset );
}
......@@ -82,6 +82,24 @@ public:
*/
static boost::shared_ptr< WDataHandler > getDataHandler();
// TODO(all): the following two methods are only useful with our current single-subject stuff. You should consider redesigning
// it in conjunction with the multi subject stuff.
/**
* Register a dataset to the "UNKNOWN" subject. This is a convenience class which is useful as long as we do not have proper
* multi subject facilities.
*
* \param dataset the dataset to register.
*/
static void registerDataSet( boost::shared_ptr< WDataSet > dataset );
/**
* Deregister a dataset to the "UNKNOWN" subject. This is a convenience class which is useful as long as we do not have proper
* multi subject facilities.
*
* \param dataset the dataset to deregister.
*/
static void deregisterDataSet( boost::shared_ptr< WDataSet > dataset );
/**
* Insert a new subject referenced by a pointer.
*
......@@ -104,6 +122,8 @@ public:
/**
* Returns the subject which corresponds to the specified ID. It throws an exception, if the subject does not exists anymore.
*
* \note the ID might be not equal to the ID in the subjects personal information. This will (maybe) be changed later.
*
* \param subjectID the ID to search the subject for
*
* \return the subject.
......@@ -112,6 +132,15 @@ public:
*/
boost::shared_ptr< WSubject > getSubjectByID( size_t subjectID );
/**
* Gets the subject with the ID SUBJECT_UNKNOWN.
*
* \note this may be removed whenever we have a proper multi subject handling.
*
* \return the subject.
*/
static boost::shared_ptr< WSubject > getDefaultSubject();
/**
* Gets an access object which allows thread save iteration over the subjects.
*
......
......@@ -28,6 +28,7 @@
#include "WDataTexture3D.h"
#include "../common/WTransferable.h"
#include "../common/WCondition.h"
#include "WDataSet.h"
// prototype instance as singleton
......@@ -80,3 +81,15 @@ boost::shared_ptr< WPrototyped > WDataSet::getPrototype()
return m_prototype;
}
boost::shared_ptr< WCondition > WDataSet::getChangeCondition()
{
// this just forwards to the texture condition. In the future maybe datasets may also change so we need an separate condition in every
// dataset.
if ( isTexture() )
{
return getTexture()->getChangeCondition();
}
return boost::shared_ptr< WCondition >();
}
......@@ -31,6 +31,7 @@
#include "../common/WTransferable.h"
class WDataTexture3D;
class WCondition;
/**
* Base class for all data set types. This class has a number of subclasses
......@@ -103,6 +104,13 @@ public:
*/
static boost::shared_ptr< WPrototyped > getPrototype();
/**
* Gets the condition which is fired whenever the dataset gets some kind of dirty (threshold, opacity, ...)
*
* \return the condition, or NULL if the dataset has no texture.
*/
boost::shared_ptr< WCondition > getChangeCondition();
protected:
/**
......
......@@ -25,17 +25,18 @@
#include <vector>
#include "WDataSetSingle.h"
#include "../common/WLogger.h"
#include "../common/WCondition.h"
#include "WDataTexture3D.h"
#include "../common/WLogger.h"
WDataTexture3D::WDataTexture3D( boost::shared_ptr<WValueSetBase> valueSet, boost::shared_ptr<WGrid> grid ):
m_alpha( 1.0 ),
m_threshold( 0.0 ),
m_texture( osg::ref_ptr< osg::Texture3D >() ),
m_valueSet( valueSet ),
m_grid( boost::shared_dynamic_cast< WGridRegular3D >( grid ) )
m_grid( boost::shared_dynamic_cast< WGridRegular3D >( grid ) ),
m_changeCondition( new WCondition() )
{
// initialize members
}
......@@ -51,6 +52,11 @@ float WDataTexture3D::getAlpha() const
return m_alpha;
}
void WDataTexture3D::setOpacity( float opacity )
{
setAlpha( opacity / 100.0 );
}
void WDataTexture3D::setAlpha( float alpha )
{
if ( ( alpha > 1.0 ) || ( alpha < 0.0 ) )
......@@ -59,6 +65,7 @@ void WDataTexture3D::setAlpha( float alpha )
}
m_alpha = alpha;
notifyChange();
}
float WDataTexture3D::getThreshold() const
......@@ -69,6 +76,7 @@ float WDataTexture3D::getThreshold() const
void WDataTexture3D::setThreshold( float threshold )
{
m_threshold = threshold;
notifyChange();
}
osg::ref_ptr< osg::Texture3D > WDataTexture3D::getTexture()
......@@ -233,3 +241,13 @@ void WDataTexture3D::createTexture()
}
}
boost::shared_ptr< WCondition > WDataTexture3D::getChangeCondition()
{
return m_changeCondition;
}
void WDataTexture3D::notifyChange()
{
m_changeCondition->notify();
}
......@@ -35,6 +35,8 @@
#include "WValueSetBase.h"
#include "WGridRegular3D.h"
class WCondition;
/**
* Class encapsulating a 3D texture. It is able to use a value set and grid to create an OpenSceneGraph texture, that can be used
* directly by modules.
......@@ -69,6 +71,13 @@ public:
*/
void setAlpha( float alpha );
/**
* Sets the opacity value. The value must be in [0,100]. Otherwise nothing will happen.
*
* \param opacity the opacity value.
*/
void setOpacity( float opacity );
/**
* Returns the currently set threshold.
*
......@@ -89,6 +98,14 @@ public:
* \return the texture
*/
osg::ref_ptr< osg::Texture3D > getTexture();
/**
* Gets the condition which is fired whenever the texture gets some kind of dirty (threshold, opacity, ...)
*
* \return the condition
*/
boost::shared_ptr< WCondition > getChangeCondition();
protected:
/**
......@@ -124,6 +141,11 @@ protected:
*/
osg::ref_ptr< osg::Image > createTexture3D( float* source, int components = 1 );
/**
* Notifies about changes. Mainly this will be used by the textures whenever the threshold/opacity change.
*/
void notifyChange();
/**
* Creates a 3D texture for the data set.
*/
......@@ -153,6 +175,12 @@ protected:
* The grid used to set up the texture.
*/
boost::shared_ptr< WGridRegular3D > m_grid;
/**
* The condition which is fired whenever the dataset gets some kind of dirty (threshold, opacity, ...)
*/
boost::shared_ptr< WCondition > m_changeCondition;
private:
};
......
......@@ -24,6 +24,8 @@
#include <string>
#include "WSubject.h"
#include "WPersonalInformation.h"
WPersonalInformation WPersonalInformation::createDummyInformation()
......@@ -32,9 +34,9 @@ WPersonalInformation WPersonalInformation::createDummyInformation()
}
WPersonalInformation::WPersonalInformation()