Commit 0ac65c4f authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Started refactoring the ImageData conversion API:

Conversions between image representations are now managed at one central place: The ImageRepresentationConverter singleton uses the proven and established registration through static template instantiation idiom to register conversion functors during static initialization. Therefore, the ConversionFunctionRegistrar registers a conversion functor to a target representation type.

As proof-of-concept implementation, the former conversion API through T::tryConvertFrom, where T is a specific image representation, has been converted to the new API and merged into imagerepresentationconversioncore.h providing a conversion functor for each campvis-core representation.

Furthermore, implemented conversion from ImageRepresentationGL to GenericImageRepresentationLocal<>.

refs #553
refs #474
parent db69d006
......@@ -159,15 +159,6 @@ namespace campvis {
virtual ~GenericImageRepresentationLocal();
/**
* Performs a conversion of \a source to an ImageRepresentationLocal if feasible.
* Returns 0 if conversion was not successful or source representation type is not compatible.
* \note The callee, respectively the callee's parent, has the ownership of the returned pointer.
* \param source Source image representation for conversion.
* \return A pointer to a local representation of \a source or 0 on failure. The caller does \b not have ownership.
*/
static GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* tryConvertFrom(const AbstractImageRepresentation* source);
/// \see AbstractImageRepresentation::clone()
virtual ThisType* clone(ImageData* newParent) const;
......@@ -307,61 +298,6 @@ namespace campvis {
delete [] _data;
}
template<typename BASETYPE, size_t NUMCHANNELS>
GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* campvis::GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::tryConvertFrom(const AbstractImageRepresentation* source) {
if (const ImageRepresentationDisk* tester = dynamic_cast<const ImageRepresentationDisk*>(source)) {
// converting from disk representation
if (tester->getBaseType() == TypeTraits<BASETYPE, NUMCHANNELS>::weaklyTypedPointerBaseType && tester->getParent()->getNumChannels() == NUMCHANNELS) {
WeaklyTypedPointer wtp = tester->getImageData();
return create(tester->getParent(), static_cast<ElementType*>(wtp._pointer));
}
else {
LWARNING("Could not convert since base type or number of channels mismatch.");
}
}
if (const ImageRepresentationDisk* tester = dynamic_cast<const ImageRepresentationDisk*>(source)) {
// converting from disk representation
if (tester->getBaseType() == TypeTraits<BASETYPE, NUMCHANNELS>::weaklyTypedPointerBaseType && tester->getParent()->getNumChannels() == NUMCHANNELS) {
WeaklyTypedPointer wtp = tester->getImageData();
return create(tester->getParent(), static_cast<ElementType*>(wtp._pointer));
}
else {
LWARNING("Could not convert since base type or number of channels mismatch.");
}
}
else if (const ThisType* tester = dynamic_cast<const ThisType*>(source)) {
// just to ensure that the following else if case is really a conversion
LDEBUG("Trying to convert into the same type - this should not happen, since it there is no conversion needed...");
return tester->clone(const_cast<ImageData*>(tester->getParent()));
}
else if (const ImageRepresentationLocal* tester = dynamic_cast<const ImageRepresentationLocal*>(source)) {
// converting from other local representation of different data type
// (we ensured with the else if above that at least one of the template parameters does not match)
if (tester->getParent()->getNumChannels() == NUMCHANNELS) {
LDEBUG("Performing conversion between data types, you may lose information or the resulting data may show other unexpected features.");
size_t numElements = tester->getNumElements();
ElementType* newData = new ElementType[numElements];
// traverse each channel of each element and convert the value
for (size_t i = 0; i < numElements; ++i) {
for (size_t channel = 0; channel < NUMCHANNELS; ++channel) {
// get original value normalized to float
float tmp = tester->getElementNormalized(i, channel);
// save new value denormalized from float
TypeTraits<BASETYPE, NUMCHANNELS>::setChannel(newData[i], channel, TypeNormalizer::denormalizeFromFloat<BASETYPE>(tmp));
}
}
return create(tester->getParent(), newData);
}
else {
LWARNING("Could not convert since number of channels mismatch.");
}
}
return 0;
}
template<typename BASETYPE, size_t NUMCHANNELS>
GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* campvis::GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::clone(ImageData* newParent) const {
size_t numElements = getNumElements();
......
......@@ -33,6 +33,7 @@
#include "core/datastructures/abstractdata.h"
#include "core/datastructures/abstractimagerepresentation.h"
#include "core/datastructures/imagemappinginformation.h"
#include "core/datastructures/imagerepresentationconverter.h"
#include <vector>
......@@ -237,7 +238,7 @@ namespace campvis {
// target type. This does not harm thread-safety but may lead to multiple
// representations of the same type for a single image.
for (tbb::concurrent_vector<const AbstractImageRepresentation*>::const_iterator it = _representations.begin(); it != _representations.end(); ++it) {
const T* tester = T::tryConvertFrom(*it);
const T* tester = ImageRepresentationConverter::getRef().tryConvertFrom<T>(*it);
if (tester != 0) {
return tester;
}
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitt Mnchen
// Boltzmannstr. 3, 85748 Garching b. Mnchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "imagerepresentationconversioncore.h"
#include "tgt/assert.h"
#include "tgt/logmanager.h"
#include "tgt/glcontextmanager.h"
#include "core/tools/opengljobprocessor.h"
#include "core/tools/job.h"
namespace campvis {
namespace conversion {
ImageRepresentationGL* GlConversion::tryConvertFrom(const AbstractImageRepresentation* source) {
if (source == nullptr)
return nullptr;
// test source image type via dynamic cast
if (const ImageRepresentationDisk* tester = dynamic_cast<const ImageRepresentationDisk*>(source)) {
WeaklyTypedPointer wtp = tester->getImageData();
if (wtp._pointer == nullptr) {
LERRORC("CAMPVis.core.datastructures.GlConversion", "Could not load image from disk during conversion.");
return nullptr;
}
ImageRepresentationGL* toReturn = ImageRepresentationGL::create(const_cast<ImageData*>(tester->getParent()), wtp);
switch (wtp._baseType) {
case WeaklyTypedPointer::UINT8:
delete [] static_cast<uint8_t*>(wtp._pointer);
break;
case WeaklyTypedPointer::INT8:
delete [] static_cast<int8_t*>(wtp._pointer);
break;
case WeaklyTypedPointer::UINT16:
delete [] static_cast<uint16_t*>(wtp._pointer);
break;
case WeaklyTypedPointer::INT16:
delete [] static_cast<int16_t*>(wtp._pointer);
break;
case WeaklyTypedPointer::UINT32:
delete [] static_cast<uint32_t*>(wtp._pointer);
break;
case WeaklyTypedPointer::INT32:
delete [] static_cast<int32_t*>(wtp._pointer);
break;
case WeaklyTypedPointer::FLOAT:
delete [] static_cast<float*>(wtp._pointer);
break;
default:
tgtAssert(false, "Should not reach this - wrong base data type!");
break;
}
return toReturn;
}
else if (const ImageRepresentationLocal* tester = dynamic_cast<const ImageRepresentationLocal*>(source)) {
ImageRepresentationGL* toReturn = ImageRepresentationGL::create(const_cast<ImageData*>(tester->getParent()), tester->getWeaklyTypedPointer());
return toReturn;
}
#ifdef CAMPVIS_HAS_MODULE_ITK
else if (const AbstractImageRepresentationItk* tester = dynamic_cast<const AbstractImageRepresentationItk*>(source)) {
ImageRepresentationGL* toReturn = ImageRepresentationGL::create(const_cast<ImageData*>(tester->getParent()), tester->getWeaklyTypedPointer());
return toReturn;
}
#endif
return nullptr;
}
ImageRepresentationLocal* LocalConversion::tryConvertFrom(const AbstractImageRepresentation* source) {
if (source == 0)
return 0;
// test source image type via dynamic cast
if (const ImageRepresentationDisk* tester = dynamic_cast<const ImageRepresentationDisk*>(source)) {
return ImageRepresentationLocal::create(tester->getParent(), tester->getImageData());
}
else if (const ImageRepresentationGL* tester = dynamic_cast<const ImageRepresentationGL*>(source)) {
OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard;
WeaklyTypedPointer wtp = tester->getWeaklyTypedPointerCopy();
if (wtp._pointer != nullptr)
return ImageRepresentationLocal::create(source->getParent(), wtp);
return nullptr;
}
#ifdef CAMPVIS_HAS_MODULE_ITK
// There is no way to determine basetype, number of channels and dimensionality of
// an ITK image at runtime. So there are currently 7*4*2 = 56 different possibilities
// what source could be. Thank god, there exists macro magic to create the 56
// different templated conversion codes.
#define CONVERT_ITK_TO_GENERIC_LOCAL(basetype, numchannels, dimensionality) \
if (const GenericImageRepresentationItk<basetype, numchannels, dimensionality>* tester = dynamic_cast< const GenericImageRepresentationItk<basetype, numchannels, dimensionality>* >(source)) { \
typedef GenericImageRepresentationItk<basetype, numchannels, dimensionality>::ItkImageType ItkImageType; \
typedef ItkImageType::PixelType ItkElementType; \
typedef GenericImageRepresentationItk<basetype, numchannels, dimensionality>::ElementType ElementType; \
const ItkElementType* pixelData = tester->getItkImage()->GetBufferPointer(); \
\
ItkImageType::RegionType region; \
region = tester->getItkImage()->GetBufferedRegion(); \
\
ItkImageType::SizeType s = region.GetSize(); \
tgt::svec3 size(s[0], 1, 1); \
if (dimensionality >= 2) \
size.y = s[1]; \
if (dimensionality == 3) \
size.z = s[2]; \
\
ElementType* pixelDataCopy = new ElementType[tgt::hmul(size)]; \
memcpy(pixelDataCopy, pixelData, tgt::hmul(size) * TypeTraits<basetype, numchannels>::elementSize); \
return GenericImageRepresentationLocal<basetype, numchannels>::create(const_cast<ImageData*>(source->getParent()), pixelDataCopy); \
}
#define DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_ND(numchannels, dimensionality) \
CONVERT_ITK_TO_GENERIC_LOCAL(uint8_t, numchannels, dimensionality) \
else CONVERT_ITK_TO_GENERIC_LOCAL(int8_t, numchannels, dimensionality) \
else CONVERT_ITK_TO_GENERIC_LOCAL(uint16_t, numchannels, dimensionality) \
else CONVERT_ITK_TO_GENERIC_LOCAL(int16_t, numchannels, dimensionality) \
else CONVERT_ITK_TO_GENERIC_LOCAL(uint32_t, numchannels, dimensionality) \
else CONVERT_ITK_TO_GENERIC_LOCAL(int32_t, numchannels, dimensionality) \
else CONVERT_ITK_TO_GENERIC_LOCAL(float, numchannels, dimensionality)
#define DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_D(dimensionality) \
DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_ND(1, dimensionality) \
else DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_ND(2, dimensionality) \
else DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_ND(3, dimensionality) \
else DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_ND(4, dimensionality)
// okay we've defined our macros. Now we just need to call them so that they call
// each other and create 56 different conversion checks - hooray
DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_D(2)
else DISPATCH_ITK_TO_GENERIC_LOCAL_CONVERSION_D(3)
#endif
return 0;
}
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#ifndef IMAGEREPRESENTATIONCONVERSIONCORE_H__
#define IMAGEREPRESENTATIONCONVERSIONCORE_H__
#include "core/coreapi.h"
#include "core/datastructures/imagerepresentationconverter.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/datastructures/imagerepresentationlocal.h"
#include "core/datastructures/imagerepresentationgl.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
namespace campvis {
namespace conversion {
// = Declare converter classes ====================================================================
/// Conversion class to convert to ImageRepresentationGL.
struct CAMPVIS_CORE_API GlConversion {
static ImageRepresentationGL* tryConvertFrom(const AbstractImageRepresentation* source);
};
/// Conversion class to convert to ImageRepresentationLocal.
struct CAMPVIS_CORE_API LocalConversion {
static ImageRepresentationLocal* tryConvertFrom(const AbstractImageRepresentation* source);
};
/// Conversion class to convert to GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>.
template<typename BASETYPE, size_t NUMCHANNELS>
struct GenericLocalConversion {
static GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* tryConvertFrom(const AbstractImageRepresentation* source);
};
// = Instantiate converter templates to register converters =======================================
// Register converters with corresponding target representations
template class ConversionFunctionRegistrar<ImageRepresentationGL, GlConversion>;
template class ConversionFunctionRegistrar<ImageRepresentationLocal, LocalConversion>;
// for GenericImageRepresentationLocal we use some macro magic to instantiate all necessary converters:
#define INSTANTIATE_TEMPLATE_BN(BASETYPE, NUMCHANNELS) template class ConversionFunctionRegistrar< GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS> , GenericLocalConversion<BASETYPE, NUMCHANNELS> >
#define INSTANTIATE_TEMPLATE_N(NUMCHANNELS) \
INSTANTIATE_TEMPLATE_BN(uint8_t, NUMCHANNELS); INSTANTIATE_TEMPLATE_BN(int8_t, NUMCHANNELS); \
INSTANTIATE_TEMPLATE_BN(uint16_t, NUMCHANNELS); INSTANTIATE_TEMPLATE_BN(int16_t, NUMCHANNELS); \
INSTANTIATE_TEMPLATE_BN(uint32_t, NUMCHANNELS); INSTANTIATE_TEMPLATE_BN(int32_t, NUMCHANNELS); \
INSTANTIATE_TEMPLATE_BN(float, NUMCHANNELS);
INSTANTIATE_TEMPLATE_N(1);
INSTANTIATE_TEMPLATE_N(2);
INSTANTIATE_TEMPLATE_N(3);
INSTANTIATE_TEMPLATE_N(4);
// = Template definition ==========================================================================
template<typename BASETYPE, size_t NUMCHANNELS>
GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* GenericLocalConversion<BASETYPE, NUMCHANNELS>::tryConvertFrom(const AbstractImageRepresentation* source) {
if (const ImageRepresentationDisk* tester = dynamic_cast<const ImageRepresentationDisk*>(source)) {
// converting from disk representation
if (tester->getBaseType() == TypeTraits<BASETYPE, NUMCHANNELS>::weaklyTypedPointerBaseType && tester->getParent()->getNumChannels() == NUMCHANNELS) {
WeaklyTypedPointer wtp = tester->getImageData();
return GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::create(tester->getParent(), static_cast<GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::ElementType*>(wtp._pointer));
}
else {
LWARNINGC("CAMPVis.core.datastructures.GenericLocalConversion", "Could not convert since base type or number of channels mismatch.");
}
}
else if (const ImageRepresentationGL* tester = dynamic_cast<const ImageRepresentationGL*>(source)) {
// converting from GL representation
OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard;
if (tester->getTexture()->getDataType() != TypeTraits<BASETYPE, NUMCHANNELS>::glDataType)
LDEBUGC("CAMPVis.core.datastructures.GenericLocalConversion", "Performing conversion between data types, you may lose information or the resulting data may show other unexpected features.");
WeaklyTypedPointer wtp = tester->getWeaklyTypedPointerConvert(TypeTraits<BASETYPE, NUMCHANNELS>::glDataType);
if (wtp._pointer != nullptr)
return GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::create(tester->getParent(), static_cast<GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::ElementType*>(wtp._pointer));
return nullptr;
}
else if (const GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::ThisType* tester = dynamic_cast<const GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::ThisType*>(source)) {
// just to ensure that the following else if case is really a conversion
LDEBUGC("CAMPVis.core.datastructures.GenericLocalConversion", "Trying to convert into the same type - this should not happen, since it there is no conversion needed...");
return tester->clone(const_cast<ImageData*>(tester->getParent()));
}
else if (const ImageRepresentationLocal* tester = dynamic_cast<const ImageRepresentationLocal*>(source)) {
// converting from other local representation of different data type
// (we ensured with the else if above that at least one of the template parameters does not match)
if (tester->getParent()->getNumChannels() == NUMCHANNELS) {
LDEBUGC("CAMPVis.core.datastructures.GenericLocalConversion", "Performing conversion between data types, you may lose information or the resulting data may show other unexpected features.");
size_t numElements = tester->getNumElements();
GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::ElementType* newData = new GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::ElementType[numElements];
// traverse each channel of each element and convert the value
for (size_t i = 0; i < numElements; ++i) {
for (size_t channel = 0; channel < NUMCHANNELS; ++channel) {
// get original value normalized to float
float tmp = tester->getElementNormalized(i, channel);
// save new value denormalized from float
TypeTraits<BASETYPE, NUMCHANNELS>::setChannel(newData[i], channel, TypeNormalizer::denormalizeFromFloat<BASETYPE>(tmp));
}
}
return GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::create(tester->getParent(), newData);
}
else {
LWARNINGC("CAMPVis.core.datastructures.GenericLocalConversion", "Could not convert since number of channels mismatch.");
}
}
return nullptr;
}
}
}
#endif // IMAGEREPRESENTATIONCONVERSIONCORE_H__
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "imagerepresentationconverter.h"
#include <functional>
#include "core/properties/abstractproperty.h"
namespace campvis {
tbb::atomic<ImageRepresentationConverter*> ImageRepresentationConverter::_singleton;
ImageRepresentationConverter& ImageRepresentationConverter::getRef() {
if (_singleton == 0) {
std::cout << "creating ImageRepresentationConverter...\n";
ImageRepresentationConverter* tmp = new ImageRepresentationConverter();
if (_singleton.compare_and_swap(tmp, 0) != 0) {
delete tmp;
}
}
return *_singleton;
}
void ImageRepresentationConverter::deinit() {
delete _singleton;
_singleton = nullptr;
}
size_t ImageRepresentationConverter::registerConversionFunction(const std::type_info& type, ConversionFunctionPointer funcPtr) {
tbb::spin_mutex::scoped_lock lock(_mutex);
std::type_index typeIndex(type);
if (funcPtr != nullptr) {
_conversionFunctionMap.insert(std::make_pair(typeIndex, funcPtr));
}
return _conversionFunctionMap.size();
}
}
\ No newline at end of file
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universität München
// Boltzmannstr. 3, 85748 Garching b. München, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#ifndef IMAGEREPRESENTATIONCONVERTER_H__
#define IMAGEREPRESENTATIONCONVERTER_H__
#include "tgt/logmanager.h"
#include "tgt/singleton.h"
#include <tbb/atomic.h>
#include <tbb/spin_mutex.h>
#include "core/coreapi.h"
#include "core/datastructures/abstractimagerepresentation.h"
#include <map>
#include <string>
#include <typeindex>
#include <typeinfo>
#include <vector>
class QWidget;
namespace campvis {
/**
* Factory for creating PropertyWidgets depending on the Property type.
* Using some template-magic, ImageRepresentationConverter is able to register PropertyWidgets during static
* initialization in cooperation with the ConversionFunctionRegistrar.
*
* \note ImageRepresentationConverter is a thread-safe lazy-instantiated singleton.
*/
class CAMPVIS_CORE_API ImageRepresentationConverter {
public:
/// Typedef for a function pointer to convert between image representations.
typedef const AbstractImageRepresentation* (*ConversionFunctionPointer) (const AbstractImageRepresentation*);
/**
* Returns a reference to the PipelineFactory singleton.
* Creates the singleton in a thread-safe fashion, if necessary.
* \return *_singleton
*/
static ImageRepresentationConverter& getRef();
/**
* Deinitializes the Singleton.
*/
static void deinit();
/**
* Registers the the property of type \a type to have widgets created with the given function pointers.
* \note The template instantiation of ConversionFunctionRegistrar takes care of calling this method.
* \param type Property type to register.
* \param funcPtr Pointer to a conversion function.
* \return
*/
size_t registerConversionFunction(const std::type_info& type, ConversionFunctionPointer funcPtr);
template<typename T>
const T* tryConvertFrom(const AbstractImageRepresentation* source) {
auto itPair = _conversionFunctionMap.equal_range(std::type_index(typeid(T)));
// try conversion with all registered convertes for the given target type
for (auto it = itPair.first; it != itPair.second; ++it) {
const T* tester = static_cast<const T*>(it->second(source));
if (tester != nullptr)
return tester;
}
return nullptr;
};
private:
mutable tbb::spin_mutex _mutex; ///< Mutex protecting the singleton during initialization
static tbb::atomic<ImageRepresentationConverter*> _singleton; ///< the singleton object
/// Typedef for the map associating property types with conversion function pointers
typedef std::multimap<std::type_index, ConversionFunctionPointer> ConversionFunctionMapType;
/// map associating property types with creator function pointers
ConversionFunctionMapType _conversionFunctionMap;
};
// ================================================================================================
/**
* Templated class exploiting the CRTP to allow easy registration of property widgets crossing
* DLL bounds using a single template instantiation.
* \tparam WidgetType Property widget type to register.
*/
template<typename ConversionTarget, typename ConverterClass>
class ConversionFunctionRegistrar {
public:
static const AbstractImageRepresentation* tryConvertFrom(const AbstractImageRepresentation* source) {
return ConverterClass::tryConvertFrom(source);
}
private:
/// static helper field to ensure registration at static initialization time.
static const size_t _factoryId;
};