diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.cpp new file mode 100644 index 0000000000..cc368b19cb --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.cpp @@ -0,0 +1,71 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkDataGenerationJobBase.h" + + +mitk::DataStorage::SetOfObjects::ConstPointer QmitkDataGenerationJobBase::GetOutputDataNodes() const +{ + return m_OutputDataNodes; +} + +QmitkDataGenerationJobBase::QmitkDataGenerationJobBase(const mitk::DataStorage::SetOfObjects* outputDataNodes, const std::vector& inputBaseData) :m_OutputDataNodes(outputDataNodes), m_InputBaseData(inputBaseData) +{ +} + +QmitkDataGenerationJobBase::QmitkDataGenerationJobBase(mitk::DataNode* outputDataNode, const std::vector& inputBaseData): m_InputBaseData(inputBaseData) +{ + if (!outputDataNode) { + mitkThrow() << "No output data node defined."; + } + + auto nodes = mitk::DataStorage::SetOfObjects::New(); + nodes->InsertElement(0, outputDataNode); + m_OutputDataNodes = nodes; +} + +QmitkDataGenerationJobBase::QmitkDataGenerationJobBase(const mitk::DataStorage::SetOfObjects* outputDataNodes) : m_OutputDataNodes(outputDataNodes) +{ +} + +QmitkDataGenerationJobBase::QmitkDataGenerationJobBase(mitk::DataNode* outputDataNode) : QmitkDataGenerationJobBase(outputDataNode, std::vector()) +{ +} + +QmitkDataGenerationJobBase::~QmitkDataGenerationJobBase() +{ +} + +void QmitkDataGenerationJobBase::SetInputBaseData(const std::vector& baseData) +{ + m_InputBaseData = baseData; +} + +void QmitkDataGenerationJobBase::run() +{ + try + { + if (this->RunComputation()) + { + emit ResultsAvailable(m_OutputDataNodes, this); + } + } + catch (std::exception& e) + { + emit Error(QString("Error while running computation. Error description: ") + QString::fromLatin1( + e.what()), this); + } + catch (...) + { + emit Error(QString("Unknown error while running computation."), this); + } +} diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.h b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.h new file mode 100644 index 0000000000..65096f5381 --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.h @@ -0,0 +1,91 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef __QMITK_DATA_GENERATION_JOB_BASE_H +#define __QMITK_DATA_GENERATION_JOB_BASE_H + + +//QT +#include +#include +#include + +//MITK +#include +#include +#include + + +#include + +/*! +\brief QmitkDataGenerationJobBase +Base class for all jobs. Each job wraps an implementation of DataGenerationComputationInterface to compute a computation in a multi threaded environment with Qt +\details the signal ResultsAvailable is emitted when the job is finished +the signal Error is emitted in case of an error +The resulting data should be written to the provided outputDataNodes +\warning it's the responsibility of the job to store the data in the dataNode. +\example +QThreadPool* threadPool = QThreadPool::globalInstance(); +auto voxelizationJob = new QmitkVoxelizationJob(doseImage, structContourModelSet, voxelizationNode); +connect(job, SIGNAL(ResultsAvailable(const mitk::DataStorage::SetOfObjects*, const QmitkDataGenerationJobBase*)), this, SLOT(OnFinalResultsAvailable(const mitk::DataStorage::SetOfObjects*, const QmitkDataGenerationJobBase*))); +threadPool->start(job); +*/ +class MITKIMAGESTATISTICSUI_EXPORT QmitkDataGenerationJobBase : public QObject, public QRunnable +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + QmitkDataGenerationJobBase(const QmitkDataGenerationJobBase& other) = delete; + QmitkDataGenerationJobBase& operator=(const QmitkDataGenerationJobBase& other) = delete; + + mitk::DataStorage::SetOfObjects::ConstPointer GetOutputDataNodes() const; + + void run() override; + +signals: + void Error(QString err, const QmitkDataGenerationJobBase* job); + /*! @brief Signal is emitted when results are available. + @param results a vector of DataNode objects produces by the job and ready tu use, put into storage. + @param the job that produced the data + */ + void ResultsAvailable(const mitk::DataStorage::SetOfObjects* results, const QmitkDataGenerationJobBase* job); + +protected: + /*! @brief constructor with inputData and outputNodes + @param inputBaseData the input BaseData that is required for computation + @param outputDataNodes the nodes where the results should be stored + */ + QmitkDataGenerationJobBase(const mitk::DataStorage::SetOfObjects* outputDataNodes, const std::vector& inputBaseData); + QmitkDataGenerationJobBase(mitk::DataNode* outputDataNode, const std::vector& inputBaseData); + + /*! @brief constructor with outputNodes only + @param outputDataNodes the nodes where the results should be stored + */ + QmitkDataGenerationJobBase(const mitk::DataStorage::SetOfObjects* outputDataNodes); + QmitkDataGenerationJobBase(mitk::DataNode* outputDataNode); + + virtual ~QmitkDataGenerationJobBase(); + + void SetInputBaseData(const std::vector& baseData); + + /**Does the real computation. Returns true if there where results produced.*/ + virtual bool RunComputation() = 0; + + mitk::DataStorage::SetOfObjects::ConstPointer m_OutputDataNodes; + std::vector m_InputBaseData; +}; + +#endif diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationRuleBase.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationRuleBase.cpp new file mode 100644 index 0000000000..b63abcbbf3 --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationRuleBase.cpp @@ -0,0 +1,91 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkTaskGenerationRuleBase.h" + +#include "mitkRTHelper.h" +#include "mitkProperties.h" +#include "mitkRTPropertyConstants.h" +#include "mitkImage.h" +#include "mitkContourModelSet.h" +#include "mitkRTPredicates.h" +#include "QmitkVoxelizationJob.h" + +bool QmitkTaskGenerationRuleBase::IsResultAvailable(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const { + auto resultNode = GetLatestResult(storage, doseNode, structNode); + if (!resultNode) { + return false; + } + else { + //use BaseData as DataNode may have different MTime due to visualization changes + auto resultNeedsUpdate = resultNode && (doseNode->GetData()->GetMTime() > resultNode->GetData()->GetMTime() || structNode->GetData()->GetMTime() > resultNode->GetData()->GetMTime()); + return !resultNeedsUpdate; + } +} + +mitk::DataNode::Pointer QmitkTaskGenerationRuleBase::CreateDataNodeInterimResults(mitk::BaseData::Pointer data) const { + if (!data) { + mitkThrow() << "data is nullptr"; + } + + auto interimResultsNode = mitk::DataNode::New(); + interimResultsNode->SetProperty("helper object", mitk::BoolProperty::New(true)); + data->SetProperty(mitk::RT_CACHE_STATUS_NAME.c_str(), mitk::StringProperty::New(mitk::BASE_DATA_WORK_IN_PROGRESS_VALUE)); + interimResultsNode->SetVisibility(false); + interimResultsNode->SetData(data); + return interimResultsNode; +} + +QmitkRTJobBase* QmitkTaskGenerationRuleBase::GetVoxelizationJob(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const { + auto doseImage = dynamic_cast(doseNode->GetData()); + auto structContourModelSet = dynamic_cast(structNode->GetData()); + if (!doseImage || !structContourModelSet) { + mitkThrow() << "could not cast dose nodes to baseData"; + } + //QmitkVoxelizationJob needs image as input, but will be changed to geometry input + auto referenceGeometry = doseImage->GetSlicedGeometry(); + + //image as data placeholder (prevents rendering problems as GetData() never returns nullptr) + mitk::Image::Pointer imageBaseData = mitk::Image::New(); + mitk::PixelType pt = mitk::MakeScalarPixelType(); + unsigned int dim[] = { 1,1,1 }; + imageBaseData->Initialize(pt, 3, dim); + auto voxelizationNode = CreateDataNodeInterimResults(imageBaseData.GetPointer()); + voxelizationNode->SetName(doseNode->GetName()+"_"+structNode->GetName()); + auto voxelizationJob = new QmitkVoxelizationJob(doseImage, structContourModelSet, voxelizationNode); + voxelizationJob->connectDataToInputData(imageBaseData); + return voxelizationJob; +} + +const mitk::DataNode* QmitkTaskGenerationRuleBase::GetLatestVoxelization(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const { + auto voxelizationPredicate = mitk::GetVoxelizationPredicate(doseNode->GetData(), structNode->GetData()); + + auto resultNodes = storage->GetSubset(voxelizationPredicate); + if (resultNodes->empty()) { + return nullptr; + } + if (resultNodes->size() > 1) { + MITK_INFO << "multiple voxelization nodes found. Return only the newest one."; + } + //get newest element + auto latestNode = mitk::GetLatestDataNode(resultNodes); + return latestNode; +} + +mitk::BaseData::Pointer QmitkTaskGenerationRuleBase::GetVoxelizedResultTypeBaseData() const +{ + return mitk::Image::New().GetPointer(); +} diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationRuleBase.h b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationRuleBase.h new file mode 100644 index 0000000000..b669fb7230 --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationRuleBase.h @@ -0,0 +1,64 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __QMITK_WORKFLOW_BASE_H +#define __QMITK_WORKFLOW_BASE_H + +//MITK +#include +#include + +//MITK-RTTB +#include + +#include + +/*! +\brief QmitkTaskGenerationRuleBase +Base class for a Task generation rule +\details With task generation rule, we denote the process of defining a sequence of jobs (that encapsulate computation classes) to produce a desired output. +We require the following information: +- GetNextMissingJob(): determine the next job that has to be computed to compute the final result +- GetResultTypePredicate() and GetResultTypeBaseData(): information about the to-be-produced output data +\example to compute a DVH, dose and voxelization are required. If the voxelization is not available, a job has to be triggered to compute it. +*/ + +class MITKRTTOOLBOXUI_EXPORT QmitkTaskGenerationRuleBase +{ +public: + /*! @brief Returns if the (final or interim) result node is already available in the storage and up-to-date + */ + bool IsResultAvailable(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const; + + virtual mitk::DataNode::Pointer GetLatestResult(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const = 0; + /*! @brief Returns the next job that needs to be done in order to complete the workflow + */ + virtual QmitkRTJobBase* GetNextMissingJob(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const =0; +protected: + /*! @brief Creates a data node for interim results + @details It's the jobs responsibility to write the final results to the data of the DataNode. + */ + mitk::DataNode::Pointer CreateDataNodeInterimResults(mitk::BaseData::Pointer data) const; + /*! @brief Returns the voxelization job + @details is required by two workflows (QmitkDoseStatisticsWorkflow and QmitkDVHWorkflow) and therefore provided in the base class + */ + QmitkRTJobBase* GetVoxelizationJob(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const; + const mitk::DataNode* GetLatestVoxelization(mitk::DataStorage::Pointer storage, mitk::DataNode::ConstPointer doseNode, mitk::DataNode::ConstPointer structNode) const; + mitk::BaseData::Pointer GetVoxelizedResultTypeBaseData() const; +}; + +#endif diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerator.h b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerator.h new file mode 100644 index 0000000000..9bc770e913 --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerator.h @@ -0,0 +1,70 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef __QMITK_DATA_GENERATOR_H +#define __QMITK_DATA_GENERATOR_H + +#include "QmitkDataGeneratorBase.h" + +/*! +\brief QmitkRTDataGenerator +Class that implements the generation of the required data +\tparam taskgenerationRule a specific taskgenerationRule class, where details about (job) requirements and dependencies +are defined (e.g. which jobs needs to compute the DVH) +\details Required inputs are: +- storage, +- doseNodes (>=1) +- structNodes (>=1). +The given dataStorage is used to save all generated data. +The taskgenerationRule is executed on all combinations of doseNodes and structNodes. +If new data is generated, the signal NewDataAvailable is emitted. +\note has a base class, because templated classes can't have QObject as parent class. +@sa QmitkRTDataGeneratorBase +*/ +template +class QmitkRTDataGenerator : public QmitkRTDataGeneratorBase +{ + public: + /*! @brief Constructor + @param storage the data storage that should be used + */ + QmitkRTDataGenerator(mitk::DataStorage::Pointer storage) : QmitkRTDataGeneratorBase(storage) {}; + QmitkRTDataGenerator() : QmitkRTDataGeneratorBase() {}; + ~QmitkRTDataGenerator() override {}; + + mitk::DataStorage::SetOfObjects::ConstPointer GetImageNodes() const; + mitk::DataStorage::SetOfObjects::ConstPointer GetStructureNodes() const; + +public slots: + /*! @brief Setter for dose nodes + */ + void SetImageNodes(mitk::DataStorage::SetOfObjects::ConstPointer imageNodes); + /*! @brief Setter for struct nodes + */ + void SetStructureNodes(mitk::DataStorage::SetOfObjects::ConstPointer structureNodes); + +protected: + /*! @brief Generate the data (by default all combinations of doseNodes and structNodes with the specified taskgenerationRule) + */ + void DoGenerate() override; + bool NodeChangeIsRelevant(const mitk::DataNode* changedNode) const override; + std::vector> GetAllImageStructCombinations() const override; + + mitk::DataStorage::SetOfObjects::ConstPointer m_DoseNodes = nullptr; + mitk::DataStorage::SetOfObjects::ConstPointer m_StructureNodes = nullptr; +}; + +#ifndef ITK_MANUAL_INSTANTIATION +#include "QmitkDataGenerator.tpp" +#endif + +#endif diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerator.tpp b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerator.tpp new file mode 100644 index 0000000000..391cd19b20 --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerator.tpp @@ -0,0 +1,94 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef __QMITK_DATA_GENERATOR_TPP +#define __QMITK_DATA_GENERATOR_TPP + +#include +#include "mitkDataNode.h" +#include "mitkRTPredicates.h" +#include "QmitkDataGenerationJobBase.h" +#include "mitkPropertyConstants.h" + +#include "QmitkDataGenerator.h" + +mitk::DataStorage::SetOfObjects::ConstPointer QmitkDataGeneratorBase::GetStructureNodes() const +{ + return m_StructureNodes; +} + +mitk::DataStorage::SetOfObjects::ConstPointer QmitkDataGeneratorBase::GetDoseNodes() const +{ + return m_DoseNodes; +} + +void QmitkDataGeneratorBase::SetDoseNodes(mitk::DataStorage::SetOfObjects::ConstPointer doseNodes) +{ + m_DoseNodes = doseNodes; +} + +void QmitkDataGeneratorBase::SetStructureNodes(mitk::DataStorage::SetOfObjects::ConstPointer structureNodes) +{ + m_StructureNodes = structureNodes; +} + +std::vector > +QmitkDataGeneratorBase::GetAllDoseStructCombinations() const { + std::vector > allCombinations; + for (auto& doseNode : *m_DoseNodes) { + for (auto& structNode : *m_StructureNodes) { + allCombinations.push_back(std::make_pair(doseNode, structNode)); + } + } + return allCombinations; +} + + +template +void +QmitkRTDataGenerator::DoGenerate() { + auto doseAndStructCombinations = GetAllDoseStructCombinations(); + + QThreadPool* threadPool = QThreadPool::globalInstance(); + bool jobSpawned = false; + for (const auto& doseAndStruct : doseAndStructCombinations) { + MITK_INFO << "processing node " << doseAndStruct.first->GetName() << " and struct " << doseAndStruct.second->GetName(); + taskGenerationRule aTaskGenerationRule = taskGenerationRule(); + if (!aTaskGenerationRule.IsResultAvailable(m_Storage.GetPointer(), doseAndStruct.first.GetPointer(), doseAndStruct.second.GetPointer())) { + MITK_INFO << "no result available. Triggering computation of necessary jobs."; + auto job = aTaskGenerationRule.GetNextMissingJob(m_Storage, doseAndStruct.first.GetPointer(), doseAndStruct.second.GetPointer()); + //other jobs are pending, nothing has to be done + if (!job) { + MITK_INFO << "waiting for other jobs to finish"; + return; + } + job->setAutoDelete(true); + for (auto& dataNode : *(job->GetDataNodes())) { + //only add interim nodes, their data get updated as soon as it's computed + if (dataNode->GetData()->GetProperty(mitk::RT_CACHE_STATUS_NAME.c_str())) { + m_Storage->Add(dataNode); + } + } + connect(job, SIGNAL(Error(QString, const QmitkRTJobBase*)), this, SLOT(OnJobError(QString, const QmitkRTJobBase*))); + connect(job, SIGNAL(ResultsAvailable(const mitk::DataStorage::SetOfObjects*, const QmitkRTJobBase*)), this, SLOT(OnFinalResultsAvailable(const mitk::DataStorage::SetOfObjects*, const QmitkRTJobBase*))); + threadPool->start(job); + jobSpawned = true; + } + } + if (!jobSpawned) { + emit AllJobsGenerated(); + } +} + + +#endif diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.cpp new file mode 100644 index 0000000000..3c49c7fb9a --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.cpp @@ -0,0 +1,118 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#include "QmitkDataGeneratorBase.h" + +#include "QmitkDataGenerationJobBase.h" +#include "mitkDataNode.h" + +QmitkDataGeneratorBase::QmitkDataGeneratorBase(mitk::DataStorage::Pointer storage) : + m_Storage(storage) +{} + +QmitkDataGeneratorBase::QmitkDataGeneratorBase() +{} + +QmitkDataGeneratorBase::~QmitkDataGeneratorBase() +{ + auto dataStorage = m_Storage.Lock(); + if (dataStorage.IsNotNull()) + { + // remove "add node listener" from data storage + dataStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkDataGeneratorBase::NodeAddedToStorage)); + + // remove "remove node listener" from data storage + dataStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkDataGeneratorBase::NodeModified)); + } +} + +mitk::DataStorage* QmitkDataGeneratorBase::GetDataStorage() const +{ + return m_Storage; +} + +bool QmitkDataGeneratorBase::GetAutoUpdate() const +{ + return m_AutoUpdate; +} + +void QmitkDataGeneratorBase::SetDataStorage(mitk::DataStorage* storage) +{ + if (storage == m_Storage) return; + + std::shared_lock mutexguard(m_DataMutex); + + auto oldStorage = m_Storage.Lock(); + if (oldStorage.IsNotNull()) + { + // remove "add node listener" from old data storage + oldStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkDataGeneratorBase::NodeAddedToStorage)); + + // remove "remove node listener" from old data storage + oldStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkDataGeneratorBase::NodeModified)); + } + + m_Storage = storage; + + auto newStorage = m_Storage.Lock(); + + if (newStorage.IsNotNull()) + { + // add "add node listener" for new data storage + newStorage->AddNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkDataGeneratorBase::NodeAddedToStorage)); + + // add remove node listener for new data storage + newStorage->ChangedNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkDataGeneratorBase::NodeModified)); + } +} + +void QmitkDataGeneratorBase::SetAutoUpdate(bool autoUpdate) +{ + m_AutoUpdate = autoUpdate; +} + +void QmitkDataGeneratorBase::OnJobError(QString error, const QmitkRTJobBase* failedJob) +{ + emit JobError(error, failedJob); +} + +void QmitkDataGeneratorBase::OnFinalResultsAvailable(const mitk::DataStorage::SetOfObjects* results, const QmitkRTJobBase *job) +{ + if (results) + { + TODO go through the results and ensure that the cache status property is removed + //no need to remove the WIP property (mitk::RT_CACHE_STATUS_NAME) again, as directly set the BaseData in the job (where this property is not set) + emit NewDataAvailable(results); + } +} + +TODO if storage is set the generator should register observers for node changes of datastorage. See e.g. node selection widget how to do it. +If some node has changed that is relevant it flags new generation if a doGeneration is ongoing or triggers a new one. + +void QmitkDataGeneratorBase::Generate() +{ + m_RunningGeneration = true; + while (m_RestartGeneration) + { + m_RestartGeneration = false; + DoGeneration(); + } + + m_RunningGeneration = false; +} \ No newline at end of file diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.h b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.h new file mode 100644 index 0000000000..beefffde10 --- /dev/null +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.h @@ -0,0 +1,96 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef __QMITK_DATA_GENERATOR_BASE_H +#define __QMITK_DATA_GENERATOR_BASE_H + +#include + +//QT +#include + +//MITK +#include + +#include + +class QmitkRTJobBase; + +/*! +\brief QmitkDataGeneratorBase +BaseClass that implements the organisation of data generation. +Use/see the class QmitkDataGenerator for more details. +*/ +class MITKIMAGESTATISTICSUI_EXPORT QmitkDataGeneratorBase : public QObject +{ + Q_OBJECT +public: + QmitkDataGeneratorBase(const QmitkDataGeneratorBase& other) = delete; + QmitkDataGeneratorBase& operator=(const QmitkDataGeneratorBase& other) = delete; + + ~QmitkDataGeneratorBase(); + + mitk::DataStorage* GetDataStorage() const; + bool GetAutoUpdate() const; + + void Generate() const; + +public slots: + void SetDataStorage(mitk::DataStorage* storage); + void SetAutoUpdate(bool autoUpdate); + +protected slots: + void OnJobError(QString error, const QmitkRTJobBase* failedJob); + /*! @brief Wraps the resulting BaseData* into DataNode objects + */ + void OnFinalResultsAvailable(const mitk::DataStorage::SetOfObjects* results, const QmitkRTJobBase *job); + +signals: + /*! @brief Signal that is emitted if new final data is produced. + */ + void NewDataAvailable(const mitk::DataStorage::SetOfObjects* data); + /*! @brief Signal that is emitted if all jobs are finished. + */ + void AllJobsGenerated(); + /*! @brief Signal that is emitted in case of job errors. + */ + void JobError(QString error, const QmitkRTJobBase* failedJob); +protected: + /*! @brief Constructor + @param storage the data storage where all produced data should be stored + */ + QmitkDataGeneratorBase(mitk::DataStorage::Pointer storage); + QmitkDataGeneratorBase(); + + virtual bool NodeChangeIsRelevant(const mitk::DataNode* changedNode) const = 0; + virtual std::vector> GetAllImageStructCombinations() const = 0; + virtual void DoGenerate() const = 0; + + mitk::WeakPointer m_Storage; + + bool m_AutoUpdate = false; + + mutable std::shared_mutex m_DataMutex; + mutable bool m_RunningGeneration = false; + mutable bool m_RestartGeneration = false; + + /**Member is called when a node is added to the storage.*/ + void NodeAddedToStorage(const mitk::DataNode* node); + + /**Member is called when a node modified.*/ + void NodeModified(const mitk::DataNode* node); + + unsigned long m_DataStorageDeletedTag; + +}; + +#endif diff --git a/Modules/ImageStatisticsUI/files.cmake b/Modules/ImageStatisticsUI/files.cmake index d94da90986..4bfd046355 100644 --- a/Modules/ImageStatisticsUI/files.cmake +++ b/Modules/ImageStatisticsUI/files.cmake @@ -1,33 +1,41 @@ set(CPP_FILES Qmitk/QmitkHistogramVisualizationWidget.cpp Qmitk/QmitkImageStatisticsCalculationRunnable.cpp Qmitk/QmitkIntensityProfileVisualizationWidget.cpp Qmitk/QmitkImageStatisticsTreeModel.cpp Qmitk/QmitkImageStatisticsCalculationJob.cpp Qmitk/QmitkStatisticsModelToStringConverter.cpp Qmitk/QmitkImageStatisticsWidget.cpp Qmitk/QmitkImageStatisticsTreeItem.cpp + Qmitk/QmitkDataGenerationJobBase.cpp + Qmitk/QmitkDataGenerationRuleBase.cpp + Qmitk/QmitkDataGeneratorBase.cpp ) set(H_FILES Qmitk/QmitkStatisticsModelToStringConverter.h Qmitk/QmitkImageStatisticsTreeItem.h + Qmitk/QmitkDataGenerationRuleBase.h + Qmitk/QmitkDataGenerator.h ) set(TPP_FILES + Qmitk/QmitkDataGenerator.tpp ) set(UI_FILES Qmitk/QmitkHistogramVisualizationWidget.ui Qmitk/QmitkIntensityProfileVisualizationWidget.ui Qmitk/QmitkImageStatisticsWidget.ui ) set(MOC_H_FILES Qmitk/QmitkHistogramVisualizationWidget.h Qmitk/QmitkImageStatisticsCalculationRunnable.h Qmitk/QmitkIntensityProfileVisualizationWidget.h Qmitk/QmitkImageStatisticsTreeModel.h Qmitk/QmitkImageStatisticsCalculationJob.h Qmitk/QmitkImageStatisticsWidget.h + Qmitk/QmitkDataGenerationJobBase.h + Qmitk/QmitkDataGeneratorBase.h )