diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp
index a078239b81..e5a695957e 100644
--- a/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp
+++ b/Modules/QtWidgets/src/QmitkMultiWidgetConfigurationToolBar.cpp
@@ -1,82 +1,82 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical Image Computing.
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 "QmitkMultiWidgetConfigurationToolBar.h"
QmitkMultiWidgetConfigurationToolBar::QmitkMultiWidgetConfigurationToolBar()
: QToolBar()
{
QToolBar::setOrientation(Qt::Vertical);
QToolBar::setIconSize(QSize(17, 17));
InitializeToolBar();
}
QmitkMultiWidgetConfigurationToolBar::~QmitkMultiWidgetConfigurationToolBar()
{
// nothing here
}
void QmitkMultiWidgetConfigurationToolBar::InitializeToolBar()
{
// create popup to show a widget to modify the multi widget layout
m_LayoutSelectionPopup = new QmitkMultiWidgetLayoutSelectionWidget(this);
m_LayoutSelectionPopup->hide();
AddButtons();
connect(m_LayoutSelectionPopup, &QmitkMultiWidgetLayoutSelectionWidget::LayoutSet, this, &QmitkMultiWidgetConfigurationToolBar::LayoutSet);
}
void QmitkMultiWidgetConfigurationToolBar::AddButtons()
{
QAction* setLayoutAction = new QAction(QIcon(":/Qmitk/mwLayout.png"), tr("Set multi widget layout"), this);
connect(setLayoutAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSetLayout);
QToolBar::addAction(setLayoutAction);
m_SynchronizeAction = new QAction(QIcon(":/Qmitk/mwSynchronized.png"), tr("Desynchronize render windows"), this);
m_SynchronizeAction->setCheckable(true);
m_SynchronizeAction->setChecked(true);
connect(m_SynchronizeAction, &QAction::triggered, this, &QmitkMultiWidgetConfigurationToolBar::OnSynchronize);
QToolBar::addAction(m_SynchronizeAction);
}
void QmitkMultiWidgetConfigurationToolBar::OnSetLayout()
{
m_LayoutSelectionPopup->setWindowFlags(Qt::Popup);
- m_LayoutSelectionPopup->move(this->cursor().pos());
+ m_LayoutSelectionPopup->move(this->cursor().pos().x() - m_LayoutSelectionPopup->width(), this->cursor().pos().y());
m_LayoutSelectionPopup->show();
}
void QmitkMultiWidgetConfigurationToolBar::OnSynchronize()
{
bool synchronized = m_SynchronizeAction->isChecked();
if (synchronized)
{
m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwSynchronized.png"));
m_SynchronizeAction->setText(tr("Desynchronize render windows"));
}
else
{
m_SynchronizeAction->setIcon(QIcon(":/Qmitk/mwDesynchronized.png"));
m_SynchronizeAction->setText(tr("Synchronize render windows"));
}
m_SynchronizeAction->setChecked(synchronized);
emit Synchronized(synchronized);
}
diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
index 687ad5a934..17081206c4 100644
--- a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
+++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.cpp
@@ -1,76 +1,80 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical Image Computing.
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 "QmitkMultiWidgetLayoutSelectionWidget.h"
QmitkMultiWidgetLayoutSelectionWidget::QmitkMultiWidgetLayoutSelectionWidget(QWidget* parent/* = 0*/)
: QWidget(parent)
{
Init();
}
void QmitkMultiWidgetLayoutSelectionWidget::Init()
{
ui.setupUi(this);
+
+ auto stylesheet = "QTableWidget::item{background-color: white;}\nQTableWidget::item:selected{background-color: #1C97EA;}";
+ ui.tableWidget->setStyleSheet(stylesheet);
+
connect(ui.tableWidget, &QTableWidget::itemSelectionChanged, this, &QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged);
connect(ui.setLayoutPushButton, &QPushButton::clicked, this, &QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked);
}
void QmitkMultiWidgetLayoutSelectionWidget::OnTableItemSelectionChanged()
{
QItemSelectionModel* selectionModel = ui.tableWidget->selectionModel();
int row = 0;
int column = 0;
QModelIndexList indices = selectionModel->selectedIndexes();
if (indices.size() > 0)
{
row = indices[0].row();
column = indices[0].column();
QModelIndex topLeft = ui.tableWidget->model()->index(0, 0, QModelIndex());
QModelIndex bottomRight = ui.tableWidget->model()->index(row, column, QModelIndex());
QItemSelection cellSelection;
cellSelection.select(topLeft, bottomRight);
selectionModel->select(cellSelection, QItemSelectionModel::Select);
}
}
void QmitkMultiWidgetLayoutSelectionWidget::OnSetLayoutButtonClicked()
{
int row = 0;
int column = 0;
QModelIndexList indices = ui.tableWidget->selectionModel()->selectedIndexes();
if (indices.size() > 0)
{
// find largest row and column
for (const QModelIndex modelIndex : indices)
{
if (modelIndex.row() > row)
{
row = modelIndex.row();
}
if (modelIndex.column() > column)
{
column = modelIndex.column();
}
}
close();
emit LayoutSet(row+1, column+1);
}
}
diff --git a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui
index 34d3e62dfd..5c2d9e4af1 100644
--- a/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui
+++ b/Modules/QtWidgets/src/QmitkMultiWidgetLayoutSelectionWidget.ui
@@ -1,72 +1,70 @@
QmitkMultiWidgetLayoutSelectionWidget
0
0
230
230
-
QAbstractItemView::NoEditTriggers
false
false
3
4
false
50
50
false
50
50
-
-
-
Set multi widget layout
diff --git a/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h b/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h
index 6e30a38584..23af38d3c3 100644
--- a/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h
+++ b/Modules/RenderWindowManager/include/mitkRenderWindowLayerUtilities.h
@@ -1,71 +1,79 @@
/*===================================================================
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 MITKRENDERWINDOWLAYERUTILITIES_H
#define MITKRENDERWINDOWLAYERUTILITIES_H
// render window manager module
#include "MitkRenderWindowManagerExports.h"
// mitk core
#include
#include
#include
#include
/**
* @brief Render window layer helper functions to retrieve the currently valid layer stack
*/
namespace mitk
{
namespace RenderWindowLayerUtilities
{
typedef std::vector RendererVector;
typedef std::map> LayerStack;
/**
* The base data node of a renderer is supposed to be on layer 0 (zero), which should be the lowest layer in a render window.
*/
const int BASE_LAYER_INDEX = 0;
/**
* The top layer index, denoting that no valid (positive) layer index is given and therefore the index should be resolved into the topmost layer index.
*/
const int TOP_LAYER_INDEX = -1;
/**
* @brief Return the stack of layers of the given renderer as std::map, which guarantees ordering of the layers.
* Stacked layers are only included if they have their "fixedLayer" property set to true and their "layer" property set.
*
* If "renderer" = nullptr: a layer stack won't be created and an empty "LayerStack" will be returned.
* If "withBaseNode" = true: include the base node in the layer stack, if existing.
* If "withBaseNode" = false: exclude the base node from the layer stack.
*
* @param dataStorage Pointer to a data storage instance whose data nodes should be checked and possibly be included.
* @param renderer Pointer to the renderer instance for which the layer stack should be generated.
* @param withBaseNode Boolean to decide whether the base node should be included in or excluded from the layer stack.
*/
MITKRENDERWINDOWMANAGER_EXPORT LayerStack GetLayerStack(const DataStorage* dataStorage, const BaseRenderer* renderer, bool withBaseNode);
/**
* @brief Helper function to get a node predicate that can be used to filter render window specific data nodes.
*
* The data nodes must not be 'helper objects'. The must have set a 'fixed layer' property for the given renderer.
*/
MITKRENDERWINDOWMANAGER_EXPORT NodePredicateAnd::Pointer GetRenderWindowPredicate(const BaseRenderer* renderer);
-
+ /**
+ * @brief Set renderer-specific properties to mark a data node as 'managed by the specific renderer'.
+ * In order for a renderer to manage a data node, the 'fixedLayer' property has to be set for the given renderer.
+ * Additionally, the 'visible' and the 'layer' property are set and allow to individually render a set of nodes
+ * with a specific renderer.
+ * The last two mentioned properties are set so that they initially have the same value as the corresponding
+ * global property.
+ */
+ MITKRENDERWINDOWMANAGER_EXPORT void SetRenderWindowProperties(mitk::DataNode* dataNode, const BaseRenderer* renderer);
} // namespace RenderWindowLayerUtilities
} // namespace mitk
#endif // MITKRENDERWINDOWLAYERUTILITIES_H
diff --git a/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp b/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp
index 2ba1043c82..4ca3aa6af3 100644
--- a/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp
+++ b/Modules/RenderWindowManager/src/mitkRenderWindowLayerController.cpp
@@ -1,575 +1,567 @@
/*===================================================================
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.
===================================================================*/
// render window manager module
#include "mitkRenderWindowLayerController.h"
mitk::RenderWindowLayerController::RenderWindowLayerController()
: m_DataStorage(nullptr)
{
// nothing here
}
void mitk::RenderWindowLayerController::SetDataStorage(DataStorage::Pointer dataStorage)
{
if (m_DataStorage != dataStorage)
{
// set the new data storage
m_DataStorage = dataStorage;
}
}
void mitk::RenderWindowLayerController::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer)
{
if (m_ControlledRenderer != controlledRenderer)
{
// set the new set of controlled renderer
m_ControlledRenderer = controlledRenderer;
}
}
void mitk::RenderWindowLayerController::SetBaseDataNode(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return;
}
if (nullptr == renderer)
{
// set the data node as base data node in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
SetBaseDataNode(dataNode, renderer);
}
}
}
else
{
// get the layer stack with the base data node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, true);
if (!stackedLayers.empty())
{
// see if base layer exists
RenderWindowLayerUtilities::LayerStack::iterator layerStackIterator = stackedLayers.find(RenderWindowLayerUtilities::BASE_LAYER_INDEX);
if (layerStackIterator != stackedLayers.end())
{
// remove the current base data node from the current renderer
layerStackIterator->second->GetPropertyList(renderer)->DeleteProperty("layer");
layerStackIterator->second->SetBoolProperty("fixedLayer", false, renderer);
layerStackIterator->second->SetVisibility(false, renderer);
}
}
// "RenderWindowLayerUtilities::BASE_LAYER_INDEX" indicates the base data node --> set as new background
dataNode->SetIntProperty("layer", RenderWindowLayerUtilities::BASE_LAYER_INDEX, renderer);
dataNode->SetBoolProperty("fixedLayer", true, renderer);
dataNode->SetVisibility(true, renderer);
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
}
}
void mitk::RenderWindowLayerController::InsertLayerNode(DataNode* dataNode, int layer /*= RenderWindowLayerUtilities::TOP_LAYER_INDEX*/, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return;
}
if (nullptr == renderer)
{
// insert data node in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
InsertLayerNode(dataNode, layer, renderer);
}
}
}
else
{
if (RenderWindowLayerUtilities::BASE_LAYER_INDEX == layer)
{
// "RenderWindowLayerUtilities::BASE_LAYER_INDEX" indicates the base data node --> set as new background (overwrite current base node if needed)
SetBaseDataNode(dataNode, renderer);
}
else
{
InsertLayerNodeInternal(dataNode, layer, renderer);
}
}
}
void mitk::RenderWindowLayerController::InsertLayerNodeInternal(DataNode* dataNode, int newLayer, const BaseRenderer* renderer /*= nullptr*/)
{
- dataNode->SetBoolProperty("fixedLayer", true, renderer);
- // use visibility of existing renderer or common renderer
- bool visible = false;
- bool visibilityProperty = dataNode->GetVisibility(visible, renderer);
- if (true == visibilityProperty)
- {
- // found a visibility property
- dataNode->SetVisibility(visible, renderer);
- }
+ RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, renderer);
// get the layer stack without the base node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false);
if (stackedLayers.empty())
{
// no layer stack for the current renderer
if (RenderWindowLayerUtilities::TOP_LAYER_INDEX == newLayer)
{
// set given layer as first layer above base layer (= 1)
newLayer = 1;
// alternatively: no layer stack for the current renderer -> insert as background node
//SetBaseDataNode(dataNode, renderer);
}
}
else
{
if (RenderWindowLayerUtilities::TOP_LAYER_INDEX == newLayer)
{
// get the first value (highest int-key -> topmost layer)
// + 1 indicates inserting the node above the topmost layer
newLayer = stackedLayers.begin()->first + 1;
}
else
{
MoveNodeToPosition(dataNode, newLayer, renderer);
return;
}
}
// update data storage (the "data node model")
dataNode->SetIntProperty("layer", newLayer, renderer);
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
}
void mitk::RenderWindowLayerController::RemoveLayerNode(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return;
}
if (nullptr == renderer)
{
// remove data node from all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
RemoveLayerNode(dataNode, renderer);
}
}
}
else
{
// "remove" node from the renderer list
dataNode->GetPropertyList(renderer)->DeleteProperty("layer");
dataNode->SetBoolProperty("fixedLayer", false, renderer);
dataNode->SetVisibility(false, renderer);
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
}
}
bool mitk::RenderWindowLayerController::MoveNodeToPosition(DataNode* dataNode, int newLayer, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return false;
}
if (nullptr == renderer)
{
// move data node to position in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
MoveNodeToPosition(dataNode, newLayer, renderer);
// we don't store/need the returned boolean value
return false;
}
}
}
else
{
// get the layer stack without the base node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false);
if (!stackedLayers.empty())
{
// get the current layer value of the given data node
int currentLayer;
bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer);
if (wasFound && currentLayer != newLayer)
{
// move the given data node to the specified layer
dataNode->SetIntProperty("layer", newLayer, renderer);
int upperBound;
int lowerBound;
int step;
if (currentLayer < newLayer)
{
// move node up
upperBound = newLayer + 1;
lowerBound = currentLayer + 1;
step = -1; // move all other nodes one step down
}
else
{
upperBound = currentLayer;
lowerBound = newLayer;
step = 1; // move all other nodes one step up
}
// move all other data nodes between the upper and the lower bound
for (auto& layer : stackedLayers)
{
if (layer.second != dataNode && layer.first < upperBound && layer.first >= lowerBound)
{
layer.second->SetIntProperty("layer", layer.first + step, renderer);
}
// else: current data node is the selected data node or
// was previously already above the selected data node or
// was previously already below the new layer position
}
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
return true;
}
// else: data node has no layer information or is already at the specified position
}
// else: do not work with empty layer stack
}
return false;
}
bool mitk::RenderWindowLayerController::MoveNodeToFront(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return false;
}
if (nullptr == renderer)
{
// move data node to front in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
MoveNodeToFront(dataNode, renderer);
// we don't store/need the returned boolean value
return false;
}
}
}
else
{
// get the layer stack without the base node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false);
if (!stackedLayers.empty())
{
// get the first value (highest int-key -> topmost layer)
int topmostLayer = stackedLayers.begin()->first;
// get the current layer value of the given data node
int currentLayer;
bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer);
if (wasFound && currentLayer < topmostLayer)
{
// move the current data node above the current topmost layer
dataNode->SetIntProperty("layer", topmostLayer+1, renderer);
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
return true;
}
// else: data node has no layer information or is already the topmost layer node
}
// else: do not work with empty layer stack
}
return false;
}
bool mitk::RenderWindowLayerController::MoveNodeToBack(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return false;
}
if (nullptr == renderer)
{
// move data node to back in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
MoveNodeToBack(dataNode, renderer);
// we don't store/need the returned boolean value
return false;
}
}
}
else
{
// get the layer stack without the base node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false);
if (!stackedLayers.empty())
{
// get the last value (lowest int-key)
// cannot be the base layer as the base node was excluded by the 'GetLayerStack'-function
int lowermostLayer = stackedLayers.rbegin()->first;
// get the current layer value of the given data node
int currentLayer;
bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer);
if (wasFound && currentLayer > lowermostLayer)
{
// move the current data node to the current lowermost layer
dataNode->SetIntProperty("layer", lowermostLayer, renderer);
// move all other data nodes one layer up
for (auto& layer : stackedLayers)
{
if (layer.second != dataNode && layer.first < currentLayer)
{
layer.second->SetIntProperty("layer", layer.first + 1, renderer);
}
// else: current data node is the selected data node or
// was previously already above the selected data node
}
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
return true;
}
// else: data node has no layer information or is already the lowermost layer node
}
// else: do not work with empty layer stack
}
return false;
}
bool mitk::RenderWindowLayerController::MoveNodeUp(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return false;
}
if (nullptr == renderer)
{
// move data node down in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
MoveNodeUp(dataNode, renderer);
// we don't store/need the returned boolean value
return false;
}
}
}
else
{
// get the layer stack without the base node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false);
if (!stackedLayers.empty())
{
// get the current layer value of the given data node
int currentLayer;
bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer);
if (wasFound)
{
// get the current layer in the map of stacked layers
RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIterator = stackedLayers.find(currentLayer);
if (layerStackIterator != stackedLayers.end() && layerStackIterator != stackedLayers.begin())
{
// found the element in the map, at different position than 'begin' ->
// current node is not on the topmost layer and therefore can be moved one layer up
// swap the layers of the dataNode and the dataNode on the next higher layer (previous map element)
RenderWindowLayerUtilities::LayerStack::const_iterator prevLayerStackIterator = std::prev(layerStackIterator);
dataNode->SetIntProperty("layer", prevLayerStackIterator->first, renderer);
prevLayerStackIterator->second->SetIntProperty("layer", currentLayer, renderer);
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
return true;
}
// else: layer stack does not contain a layer with the 'currentLayer'data node or
// layer is already the topmost layer node
}
// else: data node has no layer information
}
// else: do not work with empty layer stack
}
return false;
}
bool mitk::RenderWindowLayerController::MoveNodeDown(DataNode* dataNode, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == dataNode)
{
return false;
}
if (nullptr == renderer)
{
// move data node up in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
MoveNodeDown(dataNode, renderer);
// we don't store/need the returned boolean value
return false;
}
}
}
else
{
// get the layer stack without the base node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, false);
if (!stackedLayers.empty())
{
// get the current layer value of the given data node
int currentLayer;
bool wasFound = dataNode->GetIntProperty("layer", currentLayer, renderer);
if (wasFound)
{
// get the current layer in the map of stacked layers
RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIterator = stackedLayers.find(currentLayer);
if (layerStackIterator != stackedLayers.end())
{
// found the element in the map ...
RenderWindowLayerUtilities::LayerStack::const_iterator nextLayerStackIterator = std::next(layerStackIterator);
if (nextLayerStackIterator != stackedLayers.end())
{
// ... and found a successor ->
// current node is not on the lowermost layer and therefore can be moved one layer down
// swap the layers of the dataNode and the dataNode on the next lower layer (next map element)
dataNode->SetIntProperty("layer", nextLayerStackIterator->first, renderer);
nextLayerStackIterator->second->SetIntProperty("layer", currentLayer, renderer);
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
return true;
}
// else: data node is already the lowermost layer node
}
// else: layer stack does not contain a layer with the 'currentLayer'
}
// else: data node has no layer information
}
// else: do not work with empty layer stack
}
return false;
}
void mitk::RenderWindowLayerController::SetVisibilityOfDataNode(bool visibility, DataNode* dataNode, const BaseRenderer* renderer /*=nullptr*/)
{
if (nullptr == dataNode)
{
return;
}
if (nullptr == renderer)
{
// set visibility of data node in all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
SetVisibilityOfDataNode(visibility, dataNode, renderer);
}
}
}
else
{
dataNode->SetVisibility(visibility, renderer);
dataNode->Modified();
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
}
}
void mitk::RenderWindowLayerController::HideDataNodeInAllRenderer(const DataNode* dataNode)
{
if (nullptr == dataNode)
{
return;
}
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
dataNode->GetPropertyList(renderer)->SetBoolProperty("visible", false);
}
}
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}
void mitk::RenderWindowLayerController::ResetRenderer(bool onlyVisibility /*= true*/, const BaseRenderer* renderer /*= nullptr*/)
{
if (nullptr == renderer)
{
// reset all controlled renderer
for (const auto& renderer : m_ControlledRenderer)
{
if (nullptr != renderer)
{
ResetRenderer(onlyVisibility, renderer);
}
}
}
else
{
// get the layer stack with the base node of the current renderer
RenderWindowLayerUtilities::LayerStack stackedLayers = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, renderer, true);
if (!stackedLayers.empty())
{
for (const auto& layer : stackedLayers)
{
int layerLevel;
layer.second->GetIntProperty("layer", layerLevel, renderer);
if (RenderWindowLayerUtilities::BASE_LAYER_INDEX == layerLevel)
{
// set base data node visibility to true
layer.second->SetVisibility(true, renderer);
}
else
{
// set visibility of all other data nodes to false
layer.second->SetVisibility(false, renderer);
// modify layer node
if (!onlyVisibility)
{
// clear mode: additionally remove layer node from current renderer
layer.second->GetPropertyList(renderer)->DeleteProperty("layer");
layer.second->SetBoolProperty("fixedLayer", false, renderer);
}
}
layer.second->Modified();
}
mitk::RenderingManager::GetInstance()->RequestUpdate(renderer->GetRenderWindow());
}
}
}
diff --git a/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp b/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp
index b3fd2e8a12..fd34b0de43 100644
--- a/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp
+++ b/Modules/RenderWindowManager/src/mitkRenderWindowLayerUtilities.cpp
@@ -1,68 +1,92 @@
/*===================================================================
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.
===================================================================*/
// render window manager module
#include "mitkRenderWindowLayerUtilities.h"
// mitk core
#include
#include
mitk::RenderWindowLayerUtilities::LayerStack mitk::RenderWindowLayerUtilities::GetLayerStack(const DataStorage* dataStorage, const BaseRenderer* renderer, bool withBaseNode)
{
LayerStack stackedLayers;
if (nullptr == dataStorage || nullptr == renderer)
{
// no nodes to stack or no renderer selected
return stackedLayers;
}
int layer = -1;
NodePredicateAnd::Pointer combinedNodePredicate = GetRenderWindowPredicate(renderer);
DataStorage::SetOfObjects::ConstPointer filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate);
for (DataStorage::SetOfObjects::ConstIterator it = filteredDataNodes->Begin(); it != filteredDataNodes->End(); ++it)
{
DataNode::Pointer dataNode = it->Value();
if (dataNode.IsNull())
{
continue;
}
bool layerFound = dataNode->GetIntProperty("layer", layer, renderer);
if (layerFound)
{
if (BASE_LAYER_INDEX != layer|| withBaseNode)
{
// data node is not on the base layer or the base layer should be included anyway
stackedLayers.insert(std::make_pair(layer, dataNode));
}
}
}
return stackedLayers;
}
mitk::NodePredicateAnd::Pointer mitk::RenderWindowLayerUtilities::GetRenderWindowPredicate(const BaseRenderer* renderer)
{
NodePredicateAnd::Pointer renderWindowPredicate = NodePredicateAnd::New();
NodePredicateProperty::Pointer helperObject = NodePredicateProperty::New("helper object", BoolProperty::New(true));
NodePredicateProperty::Pointer fixedLayer = NodePredicateProperty::New("fixedLayer", BoolProperty::New(true), renderer);
renderWindowPredicate->AddPredicate(NodePredicateNot::New(helperObject));
renderWindowPredicate->AddPredicate(fixedLayer);
return renderWindowPredicate;
}
+
+void mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(mitk::DataNode* dataNode, const BaseRenderer* renderer)
+{
+ dataNode->SetBoolProperty("fixedLayer", true, renderer);
+ // use visibility of existing renderer or common renderer
+ // common renderer is used if renderer-specific property does not exist
+ bool visible = false;
+ bool visibilityProperty = dataNode->GetVisibility(visible, renderer);
+ if (true == visibilityProperty)
+ {
+ // found a visibility property
+ dataNode->SetVisibility(visible, renderer);
+ }
+
+ // use layer of existing renderer or common renderer
+ // common renderer is used if renderer-specific property does not exist
+ int layer = -1;
+ bool layerProperty = dataNode->GetIntProperty("layer", layer, renderer);
+ if (true == layerProperty)
+ {
+ // found a layer property
+ dataNode->SetIntProperty("layer", layer, renderer);
+ }
+}
diff --git a/Modules/RenderWindowManagerUI/files.cmake b/Modules/RenderWindowManagerUI/files.cmake
index 1637b1a861..bb0d58e96c 100644
--- a/Modules/RenderWindowManagerUI/files.cmake
+++ b/Modules/RenderWindowManagerUI/files.cmake
@@ -1,18 +1,21 @@
set(H_FILES
include/QmitkRenderWindowDataStorageInspector.h
include/QmitkRenderWindowDataStorageListModel.h
+ include/QmitkRenderWindowDataStorageTreeModel.h
)
set(CPP_FILES
QmitkRenderWindowDataStorageInspector.cpp
QmitkRenderWindowDataStorageListModel.cpp
+ QmitkRenderWindowDataStorageTreeModel.cpp
)
set(MOC_H_FILES
include/QmitkRenderWindowDataStorageInspector.h
include/QmitkRenderWindowDataStorageListModel.h
+ include/QmitkRenderWindowDataStorageTreeModel.h
)
set(UI_FILES
src/QmitkRenderWindowDataStorageInspector.ui
)
diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h
index d0078bb2dc..03e54c8a8e 100644
--- a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h
+++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageInspector.h
@@ -1,94 +1,96 @@
/*===================================================================
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 QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H
-#define QMITKRENDERWINDOWDATASTORAGEWINSPECTOR_H
+#define QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H
// render window manager UI module
#include "MitkRenderWindowManagerUIExports.h"
#include "ui_QmitkRenderWindowDataStorageInspector.h"
// render window manager module
#include
#include
-#include
+#include
// qt widgets module
#include
/**
* The 'QmitkRenderWindowDataStorageInspector' offers a GUI to manipulate the base renderer / render windows of the MITK workbench.
*
* In order to use this widget, a (e.g.) plugin has to set the controlled renderer, which will be forwarded to
* a render window view direction controller.
*/
class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowDataStorageInspector : public QmitkAbstractDataStorageInspector
{
Q_OBJECT
public:
QmitkRenderWindowDataStorageInspector(QWidget* parent = nullptr);
// override from 'QmitkAbstractDataStorageInspector'
/**
* @brief See 'QmitkAbstractDataStorageInspector'
*/
virtual QAbstractItemView* GetView() override;
/**
* @brief See 'QmitkAbstractDataStorageInspector'
*/
virtual const QAbstractItemView* GetView() const override;
/**
* @brief See 'QmitkAbstractDataStorageInspector'
*/
virtual void SetSelectionMode(SelectionMode mode) override;
/**
* @brief See 'QmitkAbstractDataStorageInspector'
*/
virtual SelectionMode GetSelectionMode() const override;
/**
* @brief Set the controlled base renderer.
*/
void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer);
/**
* @brief Set the currently selected render window.
*
* @param renderWindowId the text inside the combo box
*/
void SetActiveRenderWindow(const QString& renderWindowId);
private Q_SLOTS:
+ void ModelRowsInserted(const QModelIndex& parent, int start, int end);
+
void SetAsBaseLayer();
void ResetRenderer();
void ChangeViewDirection(const QString& viewDirection);
private:
virtual void Initialize() override;
void SetUpConnections();
Ui::QmitkRenderWindowDataStorageInspector m_Controls;
- std::unique_ptr m_StorageModel;
+ std::unique_ptr m_StorageModel;
std::unique_ptr m_RenderWindowLayerController;
std::unique_ptr m_RenderWindowViewDirectionController;
};
#endif // QMITKRENDERWINDOWDATASTORAGEINSPECTOR_H
diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h
new file mode 100644
index 0000000000..44a37fbf55
--- /dev/null
+++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowDataStorageTreeModel.h
@@ -0,0 +1,136 @@
+/*===================================================================
+
+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 QMITKDATASTORAGERENDERWINDOWTREEMODEL_H
+#define QMITKDATASTORAGERENDERWINDOWTREEMODEL_H
+
+// render window manager UI model
+#include "MitkRenderWindowManagerUIExports.h"
+
+// render window manager module
+#include "mitkRenderWindowLayerController.h"
+#include "mitkRenderWindowLayerUtilities.h"
+
+//mitk core
+#include
+
+// qt widgets module
+#include
+#include
+
+/*
+* @brief The 'QmitkRenderWindowDataStorageTreeModel' is a tree model derived from the 'QmitkAbstractDataStorageModel'.
+*/
+class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowDataStorageTreeModel : public QmitkAbstractDataStorageModel
+{
+ Q_OBJECT
+
+public:
+
+ QmitkRenderWindowDataStorageTreeModel(QObject* parent = nullptr);
+
+ // override from 'QmitkAbstractDataStorageModel'
+ /**
+ * @brief See 'QmitkAbstractDataStorageModel'
+ */
+ void DataStorageChanged() override;
+ /**
+ * @brief See 'QmitkAbstractDataStorageModel'
+ */
+ void NodePredicateChanged() override;
+ /**
+ * @brief See 'QmitkAbstractDataStorageModel'
+ */
+ void NodeAdded(const mitk::DataNode* node) override;
+ /**
+ * @brief See 'QmitkAbstractDataStorageModel'
+ */
+ void NodeChanged(const mitk::DataNode* node) override;
+ /**
+ * @brief See 'QmitkAbstractDataStorageModel'
+ */
+ void NodeRemoved(const mitk::DataNode* node) override;
+
+ // override from 'QAbstractItemModel'
+ QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex& parent) const override;
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex& parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex& index, int role) const override;
+ bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
+
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+ Qt::DropActions supportedDropActions() const override;
+ Qt::DropActions supportedDragActions() const override;
+ QStringList mimeTypes() const override;
+ QMimeData* mimeData(const QModelIndexList& indexes) const override;
+
+ bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override;
+
+ void SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer);
+
+ void SetCurrentRenderer(mitk::BaseRenderer* baseRenderer);
+ mitk::BaseRenderer* GetCurrentRenderer() const;
+
+private:
+
+ void ResetTree();
+ void UpdateModelData();
+ /**
+ * @brief Adjust the layer property according to the current tree.
+ * The function will set the "layer" property of each underlying data node so that it fits the
+ * the actual hierarchy represented by the current tree.
+ */
+ void AdjustLayerProperty();
+ /**
+ * @brief Fill a vector of tree items in a depth-first order (child-first).
+ */
+ void TreeToVector(QmitkDataStorageTreeModelInternalItem* parent, std::vector& treeAsVector) const;
+ /**
+ * @brief Add the given data node to the tree of the given renderer.
+ * The given renderer specifies the "layer"-property that is used for adding the new tree item
+ * to the tree. The "layer"-property may be different for each renderer resulting in a
+ * different tree for each renderer.
+ *
+ * @param dataNode The data node that should be added.
+ * @param renderer The base renderer to which the data node should be added.
+ */
+ void AddNodeInternal(const mitk::DataNode* dataNode, const mitk::BaseRenderer* renderer);
+ /**
+ * @brief Remove the tree item that contains the given data node. Removing an item may
+ * leave the child items of the removed item without a parent. In this case
+ * the children have to be moved inside the tree so the tree has to be rebuild
+ * according to the current status of the data storage.
+ *
+ * @param dataNode The data node that should be removed.
+ */
+ void RemoveNodeInternal(const mitk::DataNode* dataNode);
+
+ mitk::DataNode* GetParentNode(const mitk::DataNode* node) const;
+ QmitkDataStorageTreeModelInternalItem* GetItemByIndex(const QModelIndex& index) const;
+ QModelIndex GetIndexByItem(QmitkDataStorageTreeModelInternalItem* item) const;
+
+ std::unique_ptr m_RenderWindowLayerController;
+ mitk::RenderWindowLayerUtilities::RendererVector m_ControlledRenderer;
+ QmitkDataStorageTreeModelInternalItem* m_Root;
+ mitk::WeakPointer m_BaseRenderer;
+
+};
+
+#endif // QMITKDATASTORAGERENDERWINDOWTREEMODEL_H
diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp
index 018d3441f0..152497dc09 100644
--- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp
+++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.cpp
@@ -1,165 +1,173 @@
/*===================================================================
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.
===================================================================*/
// render window manager UI module
#include "QmitkRenderWindowDataStorageInspector.h"
#include "QmitkCustomVariants.h"
// mitk core
#include
// qt
#include
QmitkRenderWindowDataStorageInspector::QmitkRenderWindowDataStorageInspector(QWidget* parent /*=nullptr*/)
: QmitkAbstractDataStorageInspector(parent)
{
m_Controls.setupUi(this);
// initialize the render window layer controller and the render window view direction controller
m_RenderWindowLayerController = std::make_unique();
m_RenderWindowViewDirectionController = std::make_unique();
- m_StorageModel = std::make_unique(this);
-
- m_Controls.renderWindowListView->setModel(m_StorageModel.get());
- m_Controls.renderWindowListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
- m_Controls.renderWindowListView->setSelectionBehavior(QAbstractItemView::SelectRows);
- m_Controls.renderWindowListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
- m_Controls.renderWindowListView->setAlternatingRowColors(true);
- m_Controls.renderWindowListView->setDragEnabled(true);
- m_Controls.renderWindowListView->setDropIndicatorShown(true);
- m_Controls.renderWindowListView->setAcceptDrops(true);
- m_Controls.renderWindowListView->setContextMenuPolicy(Qt::CustomContextMenu);
+ m_StorageModel = std::make_unique(this);
+
+ m_Controls.renderWindowTreeView->setModel(m_StorageModel.get());
+ m_Controls.renderWindowTreeView->setHeaderHidden(true);
+ m_Controls.renderWindowTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ m_Controls.renderWindowTreeView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_Controls.renderWindowTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ m_Controls.renderWindowTreeView->setAlternatingRowColors(true);
+ m_Controls.renderWindowTreeView->setDragEnabled(true);
+ m_Controls.renderWindowTreeView->setDropIndicatorShown(true);
+ m_Controls.renderWindowTreeView->setAcceptDrops(true);
+ m_Controls.renderWindowTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
SetUpConnections();
}
QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView()
{
- return m_Controls.renderWindowListView;
+ return m_Controls.renderWindowTreeView;
}
const QAbstractItemView* QmitkRenderWindowDataStorageInspector::GetView() const
{
- return m_Controls.renderWindowListView;
+ return m_Controls.renderWindowTreeView;
}
void QmitkRenderWindowDataStorageInspector::SetSelectionMode(SelectionMode mode)
{
- m_Controls.renderWindowListView->setSelectionMode(mode);
+ m_Controls.renderWindowTreeView->setSelectionMode(mode);
}
QmitkRenderWindowDataStorageInspector::SelectionMode QmitkRenderWindowDataStorageInspector::GetSelectionMode() const
{
- return m_Controls.renderWindowListView->selectionMode();
+ return m_Controls.renderWindowTreeView->selectionMode();
}
void QmitkRenderWindowDataStorageInspector::Initialize()
{
if (m_DataStorage.IsExpired())
{
return;
}
auto dataStorage = m_DataStorage.Lock();
m_StorageModel->SetDataStorage(dataStorage);
m_StorageModel->SetNodePredicate(m_NodePredicate);
m_RenderWindowLayerController->SetDataStorage(dataStorage);
m_RenderWindowViewDirectionController->SetDataStorage(dataStorage);
- m_Connector->SetView(m_Controls.renderWindowListView);
+ m_Connector->SetView(m_Controls.renderWindowTreeView);
}
void QmitkRenderWindowDataStorageInspector::SetUpConnections()
{
+ connect(m_StorageModel.get(), &QAbstractItemModel::rowsInserted, this, &QmitkRenderWindowDataStorageInspector::ModelRowsInserted);
+
connect(m_Controls.pushButtonSetAsBaseLayer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::SetAsBaseLayer);
connect(m_Controls.pushButtonResetRenderer, &QPushButton::clicked, this, &QmitkRenderWindowDataStorageInspector::ResetRenderer);
QSignalMapper* changeViewDirectionSignalMapper = new QSignalMapper(this);
changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonAxial, QString("axial"));
changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonCoronal, QString("coronal"));
changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonSagittal, QString("sagittal"));
changeViewDirectionSignalMapper->setMapping(m_Controls.radioButton3D, QString("3D"));
connect(changeViewDirectionSignalMapper, static_cast(&QSignalMapper::mapped), this, &QmitkRenderWindowDataStorageInspector::ChangeViewDirection);
connect(m_Controls.radioButtonAxial, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map));
connect(m_Controls.radioButtonCoronal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map));
connect(m_Controls.radioButtonSagittal, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map));
connect(m_Controls.radioButton3D, &QPushButton::clicked, changeViewDirectionSignalMapper, static_cast(&QSignalMapper::map));
}
void QmitkRenderWindowDataStorageInspector::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer)
{
m_StorageModel->SetControlledRenderer(controlledRenderer);
m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer);
m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer);
}
void QmitkRenderWindowDataStorageInspector::SetActiveRenderWindow(const QString& renderWindowId)
{
mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(renderWindowId.toStdString());
if (nullptr == selectedRenderer)
{
return;
}
m_StorageModel->SetCurrentRenderer(selectedRenderer);
mitk::SliceNavigationController::ViewDirection viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection();
switch (viewDirection)
{
case mitk::SliceNavigationController::Axial:
m_Controls.radioButtonAxial->setChecked(true);
break;
case mitk::SliceNavigationController::Frontal:
m_Controls.radioButtonCoronal->setChecked(true);
break;
case mitk::SliceNavigationController::Sagittal:
m_Controls.radioButtonSagittal->setChecked(true);
break;
default:
break;
}
}
+void QmitkRenderWindowDataStorageInspector::ModelRowsInserted(const QModelIndex& parent, int start, int end)
+{
+ m_Controls.renderWindowTreeView->setExpanded(parent, true);
+}
+
void QmitkRenderWindowDataStorageInspector::SetAsBaseLayer()
{
- QModelIndex selectedIndex = m_Controls.renderWindowListView->currentIndex();
+ QModelIndex selectedIndex = m_Controls.renderWindowTreeView->currentIndex();
if (selectedIndex.isValid())
{
QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, Qt::UserRole);
if (qvariantDataNode.canConvert())
{
mitk::DataNode* dataNode = qvariantDataNode.value();
m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_StorageModel->GetCurrentRenderer());
- m_Controls.renderWindowListView->clearSelection();
+ m_Controls.renderWindowTreeView->clearSelection();
}
}
}
void QmitkRenderWindowDataStorageInspector::ResetRenderer()
{
m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer());
- m_Controls.renderWindowListView->clearSelection();
+ m_Controls.renderWindowTreeView->clearSelection();
}
void QmitkRenderWindowDataStorageInspector::ChangeViewDirection(const QString& viewDirection)
{
m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_StorageModel->GetCurrentRenderer());
}
diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui
index 64c507a340..785e20c50c 100644
--- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui
+++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageInspector.ui
@@ -1,92 +1,92 @@
QmitkRenderWindowDataStorageInspector
0
0
340
246
0
0
0
0
Render window manager
-
Render window overview
-
-
+
-
-
Reset render window
- -
+
-
Set as base layer
- -
+
-
Axial
true
- -
+
-
Coronal
-
Sagittal
-
3D
diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp
new file mode 100644
index 0000000000..87214ffa53
--- /dev/null
+++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageTreeModel.cpp
@@ -0,0 +1,605 @@
+/*===================================================================
+
+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.
+
+===================================================================*/
+
+// render window manager UI module
+#include "QmitkRenderWindowDataStorageTreeModel.h"
+
+// mitk core
+#include
+
+// qt widgets module
+#include "QmitkCustomVariants.h"
+#include "QmitkEnums.h"
+#include "QmitkMimeTypes.h"
+#include "QmitkNodeDescriptorManager.h"
+
+QmitkRenderWindowDataStorageTreeModel::QmitkRenderWindowDataStorageTreeModel(QObject* parent /*= nullptr*/)
+ : QmitkAbstractDataStorageModel(parent)
+ , m_Root(nullptr)
+{
+ m_RenderWindowLayerController = std::make_unique();
+ ResetTree();
+}
+
+void QmitkRenderWindowDataStorageTreeModel::DataStorageChanged()
+{
+ m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock());
+ ResetTree();
+ UpdateModelData();
+}
+
+void QmitkRenderWindowDataStorageTreeModel::NodePredicateChanged()
+{
+ ResetTree();
+ UpdateModelData();
+}
+
+void QmitkRenderWindowDataStorageTreeModel::NodeAdded(const mitk::DataNode* node)
+{
+ for (const auto renderer : m_ControlledRenderer)
+ {
+ // add the node to each render window
+ mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(const_cast(node), renderer);
+ }
+
+ if (!m_BaseRenderer.IsExpired())
+ {
+ auto baseRenderer = m_BaseRenderer.Lock();
+ AddNodeInternal(node, baseRenderer);
+ }
+}
+
+void QmitkRenderWindowDataStorageTreeModel::NodeChanged(const mitk::DataNode* node)
+{
+ auto item = m_Root->Find(node);
+ if (nullptr != item)
+ {
+ auto parentItem = item->GetParent();
+ // as the root node should not be removed one should always have a parent item
+ if (nullptr == parentItem)
+ {
+ return;
+ }
+
+ auto index = createIndex(item->GetIndex(), 0, item);
+ emit dataChanged(index, index);
+ }
+}
+
+void QmitkRenderWindowDataStorageTreeModel::NodeRemoved(const mitk::DataNode* node)
+{
+ RemoveNodeInternal(node);
+}
+
+QModelIndex QmitkRenderWindowDataStorageTreeModel::index(int row, int column, const QModelIndex& parent) const
+{
+ auto item = GetItemByIndex(parent);
+ if (nullptr != item)
+ {
+ item = item->GetChild(row);
+ }
+
+ if (nullptr == item)
+ {
+ return QModelIndex();
+ }
+
+ return createIndex(row, column, item);
+}
+
+QModelIndex QmitkRenderWindowDataStorageTreeModel::parent(const QModelIndex& parent) const
+{
+ auto item = GetItemByIndex(parent);
+ if (nullptr != item)
+ {
+ item = item->GetParent();
+ }
+
+ if(nullptr == item)
+ {
+ return QModelIndex();
+ }
+
+ if (item == m_Root)
+ {
+ return QModelIndex();
+ }
+
+ return createIndex(item->GetIndex(), 0, item);
+}
+
+int QmitkRenderWindowDataStorageTreeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
+{
+ auto item = GetItemByIndex(parent);
+ if (nullptr == item)
+ {
+ return 0;
+ }
+
+ return item->GetChildCount();
+}
+
+int QmitkRenderWindowDataStorageTreeModel::columnCount(const QModelIndex&/* parent = QModelIndex()*/) const
+{
+ if (0 == m_Root->GetChildCount())
+ {
+ // no items stored, no need to display columns
+ return 0;
+ }
+
+ return 1;
+}
+
+QVariant QmitkRenderWindowDataStorageTreeModel::data(const QModelIndex& index, int role) const
+{
+ if (m_BaseRenderer.IsExpired())
+ {
+ return QVariant();
+ }
+
+ auto baseRenderer = m_BaseRenderer.Lock();
+
+ if (!index.isValid() || this != index.model())
+ {
+ return QVariant();
+ }
+
+ auto item = GetItemByIndex(index);
+ if (nullptr == item)
+ {
+ return QVariant();
+ }
+
+ auto dataNode = item->GetDataNode();
+ if (nullptr == dataNode)
+ {
+ return QVariant();
+ }
+
+ if (Qt::CheckStateRole == role)
+ {
+ bool visibility = false;
+ dataNode->GetVisibility(visibility, baseRenderer);
+ if (visibility)
+ {
+ return Qt::Checked;
+ }
+ else
+ {
+ return Qt::Unchecked;
+ }
+ }
+ else if (Qt::DisplayRole == role)
+ {
+ return QVariant(QString::fromStdString(dataNode->GetName()));
+ }
+ else if (Qt::ToolTipRole == role)
+ {
+ return QVariant("Name of the data node.");
+ }
+ else if (Qt::DecorationRole == role)
+ {
+ QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode);
+ return nodeDescriptor->GetIcon(dataNode);
+ }
+ else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role)
+ {
+ // user role always returns a reference to the data node,
+ // which can be used to modify the data node in the data storage
+ return QVariant::fromValue(dataNode);
+ }
+ else if (QmitkDataNodeRole == role)
+ {
+ return QVariant::fromValue(mitk::DataNode::Pointer(dataNode));
+ }
+
+ return QVariant();
+}
+
+bool QmitkRenderWindowDataStorageTreeModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/)
+{
+ if (m_BaseRenderer.IsExpired())
+ {
+ return false;
+ }
+
+ auto baseRenderer = m_BaseRenderer.Lock();
+
+ if (!index.isValid() || this != index.model())
+ {
+ return false;
+ }
+
+ auto item = GetItemByIndex(index);
+ if (nullptr == item)
+ {
+ return false;
+ }
+
+ auto dataNode = item->GetDataNode();
+ if (nullptr == dataNode)
+ {
+ return false;
+ }
+
+ if (Qt::EditRole == role && !value.toString().isEmpty())
+ {
+ dataNode->SetName(value.toString().toStdString().c_str());
+ emit dataChanged(index, index);
+ return true;
+ }
+ if (Qt::CheckStateRole == role)
+ {
+ Qt::CheckState newCheckState = static_cast(value.toInt());
+ bool isVisible = newCheckState;
+ dataNode->SetVisibility(isVisible, baseRenderer);
+
+ emit dataChanged(index, index);
+ mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow());
+ return true;
+ }
+ return false;
+}
+
+Qt::ItemFlags QmitkRenderWindowDataStorageTreeModel::flags(const QModelIndex& index) const
+{
+ if (this != index.model())
+ {
+ return Qt::NoItemFlags;
+ }
+
+ if (!index.isValid())
+ {
+ return Qt::ItemIsDropEnabled;
+ }
+
+ auto item = GetItemByIndex(index);
+ if (nullptr == item)
+ {
+ return Qt::NoItemFlags;
+ }
+
+ const auto dataNode = item->GetDataNode();
+ if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode))
+ {
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
+ }
+
+ return Qt::NoItemFlags;
+}
+
+Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDropActions() const
+{
+ return Qt::CopyAction | Qt::MoveAction;
+}
+
+Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDragActions() const
+{
+ return Qt::CopyAction | Qt::MoveAction;
+}
+
+QStringList QmitkRenderWindowDataStorageTreeModel::mimeTypes() const
+{
+ QStringList types = QAbstractItemModel::mimeTypes();
+ types << QmitkMimeTypes::DataNodePtrs;
+ return types;
+}
+
+QMimeData* QmitkRenderWindowDataStorageTreeModel::mimeData(const QModelIndexList& indexes) const
+{
+ QMimeData* mimeData = new QMimeData();
+ QByteArray encodedData;
+
+ QDataStream stream(&encodedData, QIODevice::WriteOnly);
+
+ for (const auto& index : indexes)
+ {
+ if (index.isValid())
+ {
+ auto dataNode = data(index, QmitkDataNodeRawPointerRole).value();
+ stream << reinterpret_cast(dataNode);
+ }
+ }
+
+ mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData);
+ return mimeData;
+}
+
+bool QmitkRenderWindowDataStorageTreeModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& parent)
+{
+ if (m_BaseRenderer.IsExpired())
+ {
+ return false;
+ }
+
+ auto baseRenderer = m_BaseRenderer.Lock();
+
+ if (action == Qt::IgnoreAction)
+ {
+ return true;
+ }
+
+ if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs))
+ {
+ return false;
+ }
+
+ if (!parent.isValid())
+ {
+ return false;
+ }
+
+ int layer = -1;
+ auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value();
+ if (nullptr != dataNode)
+ {
+ dataNode->GetIntProperty("layer", layer, baseRenderer);
+ }
+
+ auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data);
+ for (const auto& dataNode : dataNodeList)
+ {
+ m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer);
+ }
+
+ ResetTree();
+ UpdateModelData();
+ AdjustLayerProperty();
+ return true;
+}
+
+void QmitkRenderWindowDataStorageTreeModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer)
+{
+ m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer);
+ m_ControlledRenderer = controlledRenderer;
+
+ ResetTree();
+ if (m_DataStorage.IsExpired())
+ {
+ return;
+ }
+
+ auto dataStorage = m_DataStorage.Lock();
+
+ for (const auto& renderer : controlledRenderer)
+ {
+ if (nullptr == renderer)
+ {
+ continue;
+ }
+
+ auto allDataNodes = dataStorage->GetAll();
+ for (const auto& dataNode : *allDataNodes)
+ {
+ // add the node to each render window
+ mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, renderer);
+ }
+ }
+}
+
+void QmitkRenderWindowDataStorageTreeModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer)
+{
+ if (m_BaseRenderer == baseRenderer)
+ {
+ return;
+ }
+
+ // base renderer changed
+ // reset tree to build a new renderer-specific item hierarchy
+ m_BaseRenderer = baseRenderer;
+ ResetTree();
+ UpdateModelData();
+}
+
+mitk::BaseRenderer* QmitkRenderWindowDataStorageTreeModel::GetCurrentRenderer() const
+{
+ if (m_BaseRenderer.IsExpired())
+ {
+ return nullptr;
+ }
+
+ return m_BaseRenderer.Lock().GetPointer();
+}
+
+void QmitkRenderWindowDataStorageTreeModel::ResetTree()
+{
+ beginResetModel();
+ if (nullptr != m_Root)
+ {
+ m_Root->Delete();
+ }
+ endResetModel();
+
+ mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New();
+ rootDataNode->SetName("Data Storage");
+ m_Root = new QmitkDataStorageTreeModelInternalItem(rootDataNode);
+}
+
+void QmitkRenderWindowDataStorageTreeModel::UpdateModelData()
+{
+ if (!m_DataStorage.IsExpired())
+ {
+ auto dataStorage = m_DataStorage.Lock();
+ if (!m_BaseRenderer.IsExpired())
+ {
+ auto baseRenderer = m_BaseRenderer.Lock();
+
+ mitk::NodePredicateAnd::Pointer combinedNodePredicate = mitk::RenderWindowLayerUtilities::GetRenderWindowPredicate(baseRenderer);
+ auto filteredDataNodes = dataStorage->GetSubset(combinedNodePredicate);
+ for (const auto& dataNode : *filteredDataNodes)
+ {
+ AddNodeInternal(dataNode, baseRenderer);
+ }
+ }
+ }
+}
+
+void QmitkRenderWindowDataStorageTreeModel::AdjustLayerProperty()
+{
+ if (m_BaseRenderer.IsExpired())
+ {
+ return;
+ }
+
+ auto baseRenderer = m_BaseRenderer.Lock();
+
+ std::vector treeAsVector;
+ TreeToVector(m_Root, treeAsVector);
+
+ int i = treeAsVector.size() - 1;
+ for (auto it = treeAsVector.begin(); it != treeAsVector.end(); ++it)
+ {
+ auto dataNode = (*it)->GetDataNode();
+ dataNode->SetIntProperty("layer", i, baseRenderer);
+ --i;
+ }
+}
+
+void QmitkRenderWindowDataStorageTreeModel::TreeToVector(QmitkDataStorageTreeModelInternalItem* parent, std::vector& treeAsVector) const
+{
+ QmitkDataStorageTreeModelInternalItem* item;
+ for (int i = 0; i < parent->GetChildCount(); ++i)
+ {
+ item = parent->GetChild(i);
+ TreeToVector(item, treeAsVector);
+ treeAsVector.push_back(item);
+ }
+}
+
+void QmitkRenderWindowDataStorageTreeModel::AddNodeInternal(const mitk::DataNode* dataNode, const mitk::BaseRenderer* renderer)
+{
+ if (nullptr == dataNode
+ || m_DataStorage.IsExpired()
+ || nullptr != m_Root->Find(dataNode))
+ {
+ return;
+ }
+
+ // find out if we have a root node
+ auto parentItem = m_Root;
+ QModelIndex index;
+ auto parentDataNode = GetParentNode(dataNode);
+
+ if (nullptr != parentDataNode) // no top level data node
+ {
+ parentItem = m_Root->Find(parentDataNode);
+ if (nullptr == parentItem)
+ {
+ // parent node not contained in the tree; add it
+ NodeAdded(parentDataNode);
+ parentItem = m_Root->Find(parentDataNode);
+ if (nullptr == parentItem)
+ {
+ // could not find and add the parent tree; abort
+ return;
+ }
+ }
+
+ // get the index of this parent with the help of the grand parent
+ index = createIndex(parentItem->GetIndex(), 0, parentItem);
+ }
+
+ int firstRowWithASiblingBelow = 0;
+ int nodeLayer = -1;
+ dataNode->GetIntProperty("layer", nodeLayer, renderer);
+ for (const auto& siblingItem : parentItem->GetChildren())
+ {
+ int siblingLayer = -1;
+ auto siblingNode = siblingItem->GetDataNode();
+ if (nullptr != siblingNode)
+ {
+ siblingNode->GetIntProperty("layer", siblingLayer, renderer);
+ }
+ if (nodeLayer > siblingLayer)
+ {
+ break;
+ }
+ ++firstRowWithASiblingBelow;
+ }
+
+ beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow);
+ auto newNode = new QmitkDataStorageTreeModelInternalItem(const_cast(dataNode));
+ parentItem->InsertChild(newNode, firstRowWithASiblingBelow);
+ endInsertRows();
+}
+
+void QmitkRenderWindowDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode* dataNode)
+{
+ if (nullptr == dataNode
+ || nullptr == m_Root)
+ {
+ return;
+ }
+
+ auto item = m_Root->Find(dataNode);
+ if (nullptr == item)
+ {
+ return;
+ }
+
+ auto parentItem = item->GetParent();
+ auto parentIndex = GetIndexByItem(parentItem);
+
+ auto children = item->GetChildren();
+ beginRemoveRows(parentIndex, item->GetIndex(), item->GetIndex());
+ parentItem->RemoveChild(item);
+ delete item;
+ endRemoveRows();
+
+ if (!children.empty())
+ {
+ // rebuild tree because children could not be at the top level
+ ResetTree();
+ UpdateModelData();
+ }
+}
+
+mitk::DataNode* QmitkRenderWindowDataStorageTreeModel::GetParentNode(const mitk::DataNode* node) const
+{
+ mitk::DataNode* dataNode = nullptr;
+ if (m_DataStorage.IsExpired())
+ {
+ return dataNode;
+ }
+
+ auto sources = m_DataStorage.Lock()->GetSources(node);
+ if (sources->empty())
+ {
+ return dataNode;
+ }
+
+ return sources->front();
+}
+
+QmitkDataStorageTreeModelInternalItem* QmitkRenderWindowDataStorageTreeModel::GetItemByIndex(const QModelIndex& index) const
+{
+ if (index.isValid())
+ {
+ return static_cast(index.internalPointer());
+ }
+
+ return m_Root;
+}
+
+QModelIndex QmitkRenderWindowDataStorageTreeModel::GetIndexByItem(QmitkDataStorageTreeModelInternalItem* item) const
+{
+ if (item == m_Root)
+ {
+ return QModelIndex();
+ }
+
+ return createIndex(item->GetIndex(), 0, item);
+}
diff --git a/Modules/SemanticRelations/CMakeLists.txt b/Modules/SemanticRelations/CMakeLists.txt
index 72db95214f..aa6819b240 100644
--- a/Modules/SemanticRelations/CMakeLists.txt
+++ b/Modules/SemanticRelations/CMakeLists.txt
@@ -1,7 +1,7 @@
MITK_CREATE_MODULE(
- DEPENDS MitkSceneSerializationBase MitkDICOMReader MitkMultilabel MitkPersistence
+ DEPENDS MitkSceneSerializationBase MitkDICOMReader MitkMultilabel MitkPersistence MitkImageStatisticsUI
)
if(BUILD_TESTING)
ADD_SUBDIRECTORY(Test)
endif(BUILD_TESTING)
diff --git a/Modules/SemanticRelations/include/mitkControlPointManager.h b/Modules/SemanticRelations/include/mitkControlPointManager.h
index c1343ebd8f..d51ac37f9f 100644
--- a/Modules/SemanticRelations/include/mitkControlPointManager.h
+++ b/Modules/SemanticRelations/include/mitkControlPointManager.h
@@ -1,93 +1,123 @@
/*===================================================================
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 MITKCONTROLPOINTMANAGER_H
#define MITKCONTROLPOINTMANAGER_H
#include
// semantic relations module
#include "mitkSemanticTypes.h"
// mitk core
#include
namespace mitk
{
/**
* @brief Provides helper functions that are needed to work with control points.
*
* These functions help to generate new control points, check for overlapping / containing control points or provide functionality
* to find a fitting control point or even extend an already existing control point.
*/
/**
* @brief Generates a control point from a given data node.
* The date is extracted from the data node by using the 'DICOMHelper::GetDICOMDateFromDataNode'-function.
*
* @param datanode A data node pointer, whose date should be included in the newly generated control point.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GenerateControlPoint(const mitk::DataNode* datanode);
/**
* @brief Find and return a whole control point including its date given a specific control point UID.
*
- * @param controlPointUID The control point UID as string.
- * @param allControlPoints All currently known control points of a specific case.
+ * @param caseID The current case identifier is defined by the given string.
+ * @param controlPointUID The control point UID as string.
*
* @return The control point with its UID and the date.
*/
- MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GetControlPointByUID(const SemanticTypes::ID& controlPointUID, const SemanticTypes::ControlPointVector& allControlPoints);
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GetControlPointByUID(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& controlPointUID);
/**
* @brief Returns an already existing control point from the given vector of control points. This existing control point has the
* the same date (year, month, day) as the given single control point.
* If no existing control point can be found an empty control point is returned.
*
- * @param controlPoint The control point to check for existence.
- * @param allControlPoints The vector of already existing control points.
+ * @param caseID The current case identifier is defined by the given string.
+ * @param controlPoint The control point to check for existence.
+ *
+ * @return The existing control point.
*/
- MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint FindExistingControlPoint(const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ControlPointVector& allControlPoints);
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint FindExistingControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
/**
- * @brief Returns an already existing close control point from the given vector of control points. This closest control point has a date
+ * @brief Returns an already existing close control point from the given vector of control points. This closest control point has a
* date that is within a certain distance-in-days to the given control point.
* If no closest control point can be found within the distance threshold an empty control point is returned.
*
- * @param controlPoint The control point to check for distance.
- * @param allControlPoints The vector of already existing control points.
+ * @param caseID The current case identifier is defined by the given string.
+ * @param controlPoint The control point to check for distance.
+ *
+ * @return The closest control point.
*/
- MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint FindClosestControlPoint(const SemanticTypes::ControlPoint& controlPoint, SemanticTypes::ControlPointVector& allControlPoints);
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint FindClosestControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
/**
* @brief Returns the examination period to which the given control point belongs.
* Each examination point holds a vector of control point UIDs so that the UID of the given control point can be compared against the UIDs of the vector.
* An empty examination period is returned if,
* - the given vector of examination periods is empty
* - the examination periods do not contain any control point UIDs
* - the UID of the given control point is not contained in any examination period
*
- * @param controlPoint The control point of which the examination period should be found.
- * @param allExaminationPeriods All currently known examination periods of a specific case.
+ * @param caseID The current case identifier is defined by the given string.
+ * @param controlPoint The control point of which the examination period should be found.
+ *
+ * @return The examination period that contains the given control point.
+ */
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriod FindContainingExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
+ /**
+ * @brief Return the examination period to which the given data node belongs.
+ * The control point is used to find an already existing or the closest control point in the semantic relations storage.
+ * If such a control point is found, the 'FindClosestControlPoint'-function with this control point as an argument is used
+ * to actually find the corresponding examination period.
+ *
+ * @param caseID The current case identifier is defined by the given string.
+ * @param controlPoint The control point of which the examination period should be found.
+ *
+ * @return The examination period that fits the given data node.
*/
- MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriod FindExaminationPeriod(const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriodVector& allExaminationPeriods);
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriod FindFittingExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
+ /**
+ * @brief Return the examination period to which the given data node belongs.
+ * The DICOM date of the data node is used to find an already existing or the closest control point in the semantic relations storage.
+ * If such a control point is found, the 'FindFittingExaminationPeriod'-function with this control point as an argument is used
+ * to actually find the corresponding examination period.
+ *
+ * @param datanode A data node pointer, whose date should be included in the newly generated control point.
+ *
+ * @return The examination period that contains the given data node.
+ */
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriod FindFittingExaminationPeriod(const DataNode* dataNode);
/**
* @brief Sort the given vector of examination periods.
* Each examination period has a vector of control point UIDs (stored in chronological order).
* The examination periods can be sorted by comparing the first control points of the examination periods.
*
- * @param allExaminationPeriods All currently known examination periods of a specific case.
- * @param allControlPoints All currently known control points of a specific case.
+ * @param caseID The current case identifier is defined by the given string.
+ * @param allExaminationPeriods The examination periods to sort.
*/
- MITKSEMANTICRELATIONS_EXPORT void SortExaminationPeriods(SemanticTypes::ExaminationPeriodVector& allExaminationPeriods, const SemanticTypes::ControlPointVector& allControlPoints);
+ MITKSEMANTICRELATIONS_EXPORT void SortAllExaminationPeriods(const SemanticTypes::CaseID& caseID, SemanticTypes::ExaminationPeriodVector& allExaminationPeriods);
+
} // namespace mitk
#endif // MITKCONTROLPOINTMANAGER_H
diff --git a/Modules/SemanticRelations/include/mitkISemanticRelationsObservable.h b/Modules/SemanticRelations/include/mitkISemanticRelationsObservable.h
index 08e50b37ac..a9c78e0f07 100644
--- a/Modules/SemanticRelations/include/mitkISemanticRelationsObservable.h
+++ b/Modules/SemanticRelations/include/mitkISemanticRelationsObservable.h
@@ -1,57 +1,55 @@
/*===================================================================
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 MITKISEMANTICRELATIONSOBSERVABLE_H
#define MITKISEMANTICRELATIONSOBSERVABLE_H
#include "mitkISemanticRelationsObserver.h"
-#include "mitkSemanticTypes.h"
-
namespace mitk
{
/*
* @brief This interface declares three functions each observable subject has to implement
* in order to be observed in the 'Observer pattern' sense.
* The concrete observable class has to store its observer.
*/
class ISemanticRelationsObservable
{
public:
/*
* @brief Adds the given concrete observer to a container that holds all currently registered observer.
*
- * @par observer The concrete observer to register.
+ * @param observer The concrete observer to register.
*/
virtual void AddObserver(ISemanticRelationsObserver* observer) = 0;
/*
* @brief Removes the given concrete observer from the container that holds all currently registered observer.
*
- * @par observer The concrete observer to unregister.
+ * @param observer The concrete observer to unregister.
*/
virtual void RemoveObserver(ISemanticRelationsObserver* observer) = 0;
/*
* @brief Updates all concrete observer in the container that holds all currently registered observer.
* The caseID can be used to only update the observer, if the caseID fulfills a certain condition.
*
- * @par caseID A caseID that identifies the currently active patient / case.
+ * @param caseID A caseID that identifies the currently active patient / case.
*/
- virtual void NotifyObserver(const mitk::SemanticTypes::CaseID& caseID) const = 0;
+ virtual void NotifyObserver(const SemanticTypes::CaseID& caseID) const = 0;
}; // class ISemanticRelationsObservable
} // namespace mitk
#endif // MITKISEMANTICRELATIONSOBSERVABLE_H
diff --git a/Modules/SemanticRelations/include/mitkISemanticRelationsObserver.h b/Modules/SemanticRelations/include/mitkISemanticRelationsObserver.h
index 3fd8651456..d7df63e1f5 100644
--- a/Modules/SemanticRelations/include/mitkISemanticRelationsObserver.h
+++ b/Modules/SemanticRelations/include/mitkISemanticRelationsObserver.h
@@ -1,43 +1,43 @@
/*===================================================================
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 MITKISEMANTICRELATIONSOBSERVER_H
#define MITKISEMANTICRELATIONSOBSERVER_H
#include "mitkSemanticTypes.h"
namespace mitk
{
/*
* @brief This interface declares a functions each observer has to implement
* in order to be notified in the 'Observer pattern' sense.
*/
class ISemanticRelationsObserver
{
public:
/*
* @brief Updates the concrete observer.
* The caseID can be used to get access to a certain patient (case),
* whose data should be used for updating.
*
- * @par caseID The current case ID to identify the currently active patient / case.
+ * @param caseID The current case ID to identify the currently active patient / case.
*/
virtual void Update(const mitk::SemanticTypes::CaseID& caseID) = 0;
}; // class ISemanticRelationsObserver
} // namespace mitk
#endif // MITKISEMANTICRELATIONSOBSERVER_H
diff --git a/Modules/SemanticRelations/include/mitkLesionData.h b/Modules/SemanticRelations/include/mitkLesionData.h
index 7f1beec103..a2818d3422 100644
--- a/Modules/SemanticRelations/include/mitkLesionData.h
+++ b/Modules/SemanticRelations/include/mitkLesionData.h
@@ -1,63 +1,68 @@
/*===================================================================
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 MITKLESIONDATA_H
#define MITKLESIONDATA_H
#include
// mitk semantic relations module
#include "mitkSemanticTypes.h"
// c++
#include
namespace mitk
{
/**
* @brief This class holds the data of each lesion in the lesion tree view.
+ * The data is the lesion itself with its UID, name and lesion class
+ * as well as two vectors for
+ * - lesion presence: bool value for each control-point
+ * inside the semantic relations storage
+ * - lesion volume: double value for each control-point - information type pair
+ * inside the semantic relations storage
*
*/
class MITKSEMANTICRELATIONS_EXPORT LesionData
{
public:
/**
* @brief sets the data members to their initial values
*/
LesionData(const SemanticTypes::Lesion& lesion = SemanticTypes::Lesion());
- ~LesionData();
SemanticTypes::Lesion GetLesion() const { return m_Lesion; };
SemanticTypes::ID GetLesionUID() const { return m_Lesion.UID; }
std::string GetLesionName() const { return m_Lesion.name; }
const std::vector& GetLesionPresence() const { return m_LesionPresence; };
const std::vector& GetLesionVolume() const { return m_LesionVolume; };
void SetLesion(const SemanticTypes::Lesion& lesion);
void SetLesionPresence(const std::vector& lesionPresence);
void SetLesionVolume(const std::vector& lesionVolume);
private:
SemanticTypes::Lesion m_Lesion;
std::vector m_LesionPresence;
std::vector m_LesionVolume;
};
} // end namespace
#endif // MITKLESIONDATA_H
diff --git a/Modules/SemanticRelations/include/mitkLesionManager.h b/Modules/SemanticRelations/include/mitkLesionManager.h
index 790382bc0e..976d8f43de 100644
--- a/Modules/SemanticRelations/include/mitkLesionManager.h
+++ b/Modules/SemanticRelations/include/mitkLesionManager.h
@@ -1,78 +1,75 @@
/*===================================================================
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 MITKLESIONMANAGER_H
#define MITKLESIONMANAGER_H
#include
// semantic relations module
-#include "mitkSemanticTypes.h"
#include "mitkLesionData.h"
-// mitk core
-#include
-
/*
* @brief Provides helper functions that are needed to work with lesions.
*
* These functions help to generate new lesions, check for existing lesions or provide functionality
-* to find existing lesion class types.
+* to generate new and find existing lesion class types.
*/
namespace mitk
{
typedef std::vector LesionClassVector;
/**
* @brief Generate a new lesion and lesion class with UIDs and the given string as lesion class type.
*
* @param lesionClassType The lesion class type as string. Default parameter is "".
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GenerateNewLesion(const std::string& lesionClassType = "");
/**
* @brief Generate a new lesion class with UID and the given string as lesion class type.
*
* @param lesionClassType The lesion class type as string. Default parameter is "".
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionClass GenerateNewLesionClass(const std::string& lesionClassType = "");
/**
* @brief Find and return a whole lesion including its lesion class given a specific lesion UID.
*
* @param lesionUID The lesion UID as string.
* @param allLesions All currently known lesions of a specific case.
*
* @return The lesion with its UID and the lesion class.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetLesionByUID(const SemanticTypes::ID& lesionUID, const std::vector& allLesions);
/**
* @brief Find and return the whole lesion class including its UID given a specific lesion class type.
*
* @param lesionClassType The lesion class type as string.
* @param allLesionClasses All currently known lesion classes of a specific case.
*
* @return The lesion class with its UID and the class type.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionClass FindExistingLesionClass(const std::string& lesionClassType, const std::vector& allLesionClasses);
/**
- * @brief Generate and store additional lesion data such as lesion presence and lesion volume for each control point.
+ * @brief Compute and store lesion presence for all available control points and information types.
*
* @param lesionData The lesion data that holds the lesion and will hold the additional lesion data.
* @param caseID The current case ID.
*/
- MITKSEMANTICRELATIONS_EXPORT void GenerateAdditionalLesionData(LesionData& lesionData, const SemanticTypes::CaseID& caseID);
+ MITKSEMANTICRELATIONS_EXPORT void ComputeLesionPresence(LesionData& lesionData, const SemanticTypes::CaseID& caseID);
+
} // namespace mitk
#endif // MITKLESIONMANAGER_H
diff --git a/Modules/SemanticRelations/include/mitkNodePredicates.h b/Modules/SemanticRelations/include/mitkNodePredicates.h
index 554653b21e..201e9e3838 100644
--- a/Modules/SemanticRelations/include/mitkNodePredicates.h
+++ b/Modules/SemanticRelations/include/mitkNodePredicates.h
@@ -1,47 +1,47 @@
/*===================================================================
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 MITKNODEPREDICATES_H
#define MITKNODEPREDICATES_H
#include
// mitk core
#include
namespace mitk
{
namespace NodePredicates
{
/*
* @brief Helper function to get a node predicate that can be used to filter images.
*
* The images are of type 'mitk::Image' but must not be 'helper objects' or 'segmentation nodes'.
* For the definition of 'segmentation nodes' see 'GetSegmentationPredicate'.
*/
- MITKSEMANTICRELATIONS_EXPORT mitk::NodePredicateAnd::Pointer GetImagePredicate();
+ MITKSEMANTICRELATIONS_EXPORT NodePredicateAnd::Pointer GetImagePredicate();
/*
* @brief Helper function to get a node predicate that can be used to filter segmentations.
*
* The segmentations are of type 'mitk::LabelSetImage' or nodes that have their 'binary' property set to true.
* Segmentations must not be 'helper objects'.
*/
- MITKSEMANTICRELATIONS_EXPORT mitk::NodePredicateAnd::Pointer GetSegmentationPredicate();
+ MITKSEMANTICRELATIONS_EXPORT NodePredicateAnd::Pointer GetSegmentationPredicate();
} // namespace NodePredicates
} // namespace mitk
#endif // MITKNODEPREDICATES_H
diff --git a/Modules/SemanticRelations/include/mitkRelationStorage.h b/Modules/SemanticRelations/include/mitkRelationStorage.h
index 08f6aecc12..0bfc45cbd3 100644
--- a/Modules/SemanticRelations/include/mitkRelationStorage.h
+++ b/Modules/SemanticRelations/include/mitkRelationStorage.h
@@ -1,82 +1,83 @@
/*===================================================================
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 MITKRELATIONSTORAGE_H
#define MITKRELATIONSTORAGE_H
#include
// semantic relations module
#include "mitkSemanticTypes.h"
namespace mitk
{
namespace RelationStorage
{
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID);
SemanticTypes::Lesion GetLesionOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID);
SemanticTypes::ControlPoint GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriodVector GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID);
SemanticTypes::InformationType GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfCase(const SemanticTypes::CaseID& caseID);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllSegmentationIDsOfCase(const SemanticTypes::CaseID& caseID);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllSegmentationIDsOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID);
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
SemanticTypes::ID GetImageIDOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID);
MITKSEMANTICRELATIONS_EXPORT std::vector GetAllCaseIDs();
MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID);
void AddCase(const SemanticTypes::CaseID& caseID);
void AddImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID);
void RemoveImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID);
void AddSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::ID& parentID);
void RemoveSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID);
void AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
void OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
void LinkSegmentationToLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::Lesion& lesion);
void UnlinkSegmentationFromLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID);
void RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
void RemoveLesionClass(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& lesionClassID);
void AddControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
void LinkImageToControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::ControlPoint& controlPoint);
void UnlinkImageFromControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID);
void RemoveControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
void AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod);
+ MITKSEMANTICRELATIONS_EXPORT void RenameExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod);
void AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod);
void RemoveControlPointFromExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod);
void RemoveExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod);
void AddInformationTypeToImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::InformationType& informationType);
void RemoveInformationTypeFromImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID);
void RemoveInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType);
} // namespace RelationStorage
} // namespace mitk
#endif // MITKRELATIONSTORAGE_H
diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationsDataStorageAccess.h b/Modules/SemanticRelations/include/mitkSemanticRelationsDataStorageAccess.h
index 07b2854aaf..e02de8ba66 100644
--- a/Modules/SemanticRelations/include/mitkSemanticRelationsDataStorageAccess.h
+++ b/Modules/SemanticRelations/include/mitkSemanticRelationsDataStorageAccess.h
@@ -1,140 +1,187 @@
/*===================================================================
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 MITKSEMANTICRELATIONSDATASTORAGEACCESS_H
#define MITKSEMANTICRELATIONSDATASTORAGEACCESS_H
#include
// semantic relations module
#include "mitkSemanticTypes.h"
// mitk core
#include
#include
namespace mitk
{
/**
* @brief The API provides functions to query and manipulate image relations and instances,
* that are helpful during follow-up examination, like control-points (time period),
* types of the images or lesions that may be visible on multiple images.
*
* The class is able to generate IDs from given data nodes using DICOM information.
* These IDs are used to identify the corresponding instances of a specific case.
* The case can also be directly identified by the given case ID.
*
* In order for most functions to work the case ID has to be used as a parameter.
* If not, these functions do nothing.
*/
class MITKSEMANTICRELATIONS_EXPORT SemanticRelationsDataStorageAccess
{
public:
using DataNodeVector = std::vector;
SemanticRelationsDataStorageAccess(DataStorage* dataStorage);
- ~SemanticRelationsDataStorageAccess();
/************************************************************************/
/* functions to get instances / attributes */
/************************************************************************/
/**
* @brief Return a vector of all segmentations that are currently available for the given case.
* The segmentations may be connected / not connected to a lesion of the case.
* If no segmentations are stored for the current case, an empty vector is returned.
*
* @pre The data storage member has to be valid (!nullptr).
* @throw SemanticRelationException, if the data storage member is invalid (==nullptr).
*
* @param caseID The current case identifier is defined by the given string.
+ *
* @return A vector of data nodes representing segmentations.
*/
DataNodeVector GetAllSegmentationsOfCase(const SemanticTypes::CaseID& caseID) const;
/**
* @brief Return a vector of all segmentations that define the given lesion. These segmentations don't have to be linked to the same image.
* If the lesion is not referred to by any segmentation, an empty vector is returned.
*
* @pre The data storage member has to be valid (!nullptr).
* @throw SemanticRelationException, if the data storage member is invalid (==nullptr).
* @pre The UID of the lesion has to exist for a lesion instance.
* @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
- * @param lesion A Lesion with a UID that identifies the corresponding lesion instance.
+ * @param lesion A lesion with a UID that identifies the corresponding lesion instance.
+ *
* @return A vector of data nodes representing segmentations that define the given lesion.
*/
DataNodeVector GetAllSegmentationsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const;
/**
* @brief Return a vector of all images that are currently available for the given case.
*
* @pre The data storage member has to be valid (!nullptr).
* @throw SemanticRelationException, if the data storage member is invalid (==nullptr).
*
* @param caseID The current case identifier is defined by the given string.
+ *
* @return A vector of data nodes representing images.
*/
DataNodeVector GetAllImagesOfCase(const SemanticTypes::CaseID& caseID) const;
/**
+ * @brief Return a vector of all images that are specified by the given vector of image IDs.
+ *
+ * @pre The data storage member has to be valid (!nullptr).
+ * @throw SemanticRelationException, if the data storage member is invalid (==nullptr).
+ *
+ * @param imageIDs A vector of image IDs that represent the images in the data storage.
+ *
+ * @return A vector of data nodes representing images.
+ */
+ DataNodeVector GetAllImagesByID(const SemanticTypes::IDVector& imageIDs) const;
+ /**
* @brief Return a vector of all images that are connected to those segmentations that are linked to the given lesion.
* If the lesion is not referred to by any segmentation, an empty vector is returned.
*
* @pre The UID of the lesion has to exist for a lesion instance.
* @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
- * @param lesion A Lesion with a UID that identifies the corresponding lesion instance.
+ * @param lesion A lesion with a UID that identifies the corresponding lesion instance.
+ *
* @return A vector of data nodes representing images on which the lesions are visible.
*/
DataNodeVector GetAllImagesOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const;
/**
- * @brief Return a vector of all image nodes that are defined with the given information type and with the given control point.
+ * @brief Return a vector of all image nodes that are defined with the given control point and the given information type.
*
* @pre The UID of the control point has to exist for a control point instance.
* The information type has to exist for the given case (and is therefore used by at least one data node).
* @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists') or
* if the information type is not used by any data node (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
* @param controlPoint A control point with a UID that identifies the corresponding control point instance.
* @param informationType An information type that identifies the corresponding information type instance.
- * @return A vector of image nodes that are defined with the given information type with the given control point.
+ *
+ * @return A vector of image nodes that are defined with the given control point and the given information type.
*/
DataNodeVector GetAllSpecificImages(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const;
/**
- * @brief Return a vector of all segmentation nodes that are defined with the given information type and with the given control point.
+ * @brief Return a vector of all image nodes that are defined with the given information type and the given examination period.
+ * The function uses the 'SemanticRelationsInference::GetAllImageIDsOfExaminationPeriod'-function to retrieve the imageIDs of the examination period and
+ * then compares the information type of all these images against the given information type.
+ *
+ * @param informationType An information type that identifies the corresponding information type instance.
+ * @param examinationPeriod An examination period that identifies the corresponding examination period instance.
+ *
+ * @return A vector of image nodes that are defined with the given information type with the given control point.
+ */
+ DataNodeVector GetAllSpecificImages(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType, const SemanticTypes::ExaminationPeriod& examinationPeriod) const;
+ /**
+ * @brief Return a vector of all segmentation nodes that are defined with the given control point and the given information type.
* The function uses the 'GetAllSpecificImages'-function to retrieve the specific images and then searches for the derived nodes (segmentation child nodes).
*
* @pre The UID of the control point has to exist for a control point instance.
* The information type has to exist for the given case (and is therefore used by at least one data node).
* @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists') or
* if the information type is not used by any data node (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
* @param controlPoint A control point with a UID that identifies the corresponding control point instance.
* @param informationType An information type that identifies the corresponding information type instance.
- * @return A vector of segmentation nodes that are defined with the given information type with the given control point.
+ *
+ * @return A vector of segmentation nodes that are defined with the given control point and the given information type.
*/
DataNodeVector GetAllSpecificSegmentations(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const;
+ /**
+ * @brief Return the single segmentation node that is defined with the given information type, the given control point and is representing the given lesion.
+ * The function uses the 'GetAllSpecificSegmentations'-function to retrieve the specific segmentations and then checks for the represented lesion.
+ *
+ * @pre The UID of the control point has to exist for a control point instance.
+ * The information type has to exist for the given case (and is therefore used by at least one data node).
+ * The lesion has to exist for the given case.
+ * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists') or
+ * if the information type is not used by any data node (this can be checked via 'InstanceExists') or
+ * if the lesion does not exist for the given case (this can be checked via 'InstanceExists').
+ *
+ * @param caseID The current case identifier is defined by the given string.
+ * @param controlPoint A control point with a UID that identifies the corresponding control point instance.
+ * @param informationType An information type that identifies the corresponding information type instance.
+ * @param lesion A lesion with a UID that identifies the corresponding lesion instance.
+ *
+ * @return A single segmentation node that is defined with the given information type, the given control point and is representing the given lesion.
+ */
+ DataNode::Pointer GetSpecificSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint,
+ const SemanticTypes::InformationType& informationType, const SemanticTypes::Lesion& lesion) const;
private:
WeakPointer m_DataStorage;
};
} // namespace mitk
#endif // MITKSEMANTICRELATIONSDATASTORAGEACCESS_H
diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h
index fa9faeda4d..404edad885 100644
--- a/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h
+++ b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h
@@ -1,292 +1,351 @@
/*===================================================================
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 MITKSEMANTICRELATIONSINFERENCE_H
#define MITKSEMANTICRELATIONSINFERENCE_H
#include
// semantic relations module
#include "mitkSemanticTypes.h"
// mitk core
#include
namespace mitk
{
/**
* @brief The API provides functions to query image relations and instances
* that are helpful during follow-up examination, like control-points (time period),
* types of the images or lesions that may be visible on multiple images.
*
* The class is able to generate IDs from given data nodes using DICOM information.
* These IDs are used to identify the corresponding instances of a specific case.
* The case can also be directly identified by the given case ID.
*
* In order for most functions to work the case ID has to be used as a parameter.
* If not, these functions do nothing.
*/
namespace SemanticRelationsInference
{
/************************************************************************/
/* functions to get instances / attributes */
/************************************************************************/
/**
* @brief Return a vector of lesion classes that are currently available for the given case.
*
* @param caseID The current case identifier is defined by the given string.
+ *
* @return A vector of lesion classes.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionClassVector GetAllLesionClassesOfCase(const SemanticTypes::CaseID& caseID);
/**
* @brief Return the lesion that is defined by the given segmentation.
*
* @pre The given segmentation data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given segmentation is invalid (==nullptr).
* @pre The segmentation data node has to represent a lesion. If not, the retrieved lesion will be empty, which leads to an exception.
* @throw SemanticRelationException, if the segmentation does not represent an existing lesion (this can be checked via 'IsRepresentingALesion').
*
* @param segmentationNode The segmentation identifier is extracted from the given data node.
+ *
* @return The represented lesion.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetLesionOfSegmentation(const DataNode* segmentationNode);
/**
* @brief Returns a vector of all lesions that are currently available for the current case and are connected to the given image (via a segmentation).
* If no lesions are stored for the current case, an empty vector is returned. If no segmentations are
* connected with the image node, no lesions for the specific image will be found and an empty vector is returned.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
*
* @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case.
+ *
* @return A vector of lesions.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfImage(const DataNode* imageNode);
/**
* @brief Returns a vector of all lesions that are valid for the given case, given a specific control point.
*
* @param caseID The current case identifier is defined by the given string.
* @param controlPoint A specific control point which has to be available at a returned (found) lesion:
* Only those lesions are returned for which the image of the associated segmentation is linked to the given control point.
* If the control point instance does not exist, an empty vector is returned.
- * @return A vector of control points.
+ *
+ * @return A vector of lesions.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
/**
+ * @brief Returns a vector of all lesions that are valid for the given case, given a specific information type.
+ *
+ * @param caseID The current case identifier is defined by the given string.
+ * @param informationType A specific information type which has to be available at a returned (found) lesion:
+ * Only those lesions are returned for which the image of the associated segmentation is of the given information type.
+ * If the information type instance does not exist, an empty vector is returned.
+ *
+ * @return A vector of lesions.
+ */
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType);
+ /**
+ * @brief Returns a vector of all lesions that are valid for the given case, given a specific control point and a specific information type.
+ *
+ * @param caseID The current case identifier is defined by the given string.
+ * @param controlPoint A specific control point which has to be available at a returned (found) lesion:
+ * Only those lesions are returned for which the image of the associated segmentation is linked to the given control point.
+ * If the control point instance does not exist, an empty vector is returned.
+ * @param informationType A specific information type which has to be available at a returned (found) lesion:
+ * Only those lesions are returned for which the image of the associated segmentation is of the given information type.
+ * If the information type instance does not exist, an empty vector is returned.
+ *
+ * @return A vector of lesions.
+ */
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllSpecificLesions(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType);
+ /**
* @brief Check if the given segmentation refers to an existing lesion instance.
* This function can be used before calling 'GetRepresentedLesion' in order to avoid a possible exception.
*
* @param segmentationNode The segmentation identifier is extracted from the given data node.
+ *
* @return True, if the segmentation refers to an existing lesion; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool IsRepresentingALesion(const DataNode* segmentationNode);
/**
* @brief Check if the segmentation identified by the given segmentation ID refers to an existing lesion instance.
* This function can be used before calling 'GetRepresentedLesion' in order to avoid a possible exception.
*
* @param caseID The current case identifier is defined by the given string.
* @param segmentationID The segmentation node identifier is defined by the given string.
+ *
* @return True, if the segmentation refers to an existing lesion; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool IsRepresentingALesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID);
/**
* @brief Check if the given lesion is present on the given data node.
* The function receives the case- and the node-ID from the DICOM tags of the node itself.
* It uses node predicates to decide if the node is an image or a segmentation node.
*
* @param lesion A lesion with a UID that identifies the corresponding lesion instance.
* @param dataNode A data node to check.
+ *
* @return True, if the lesion is present on the data node; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresent(const SemanticTypes::Lesion& lesion, const DataNode* dataNode);
/**
* @brief Check if the given lesion is related to the image identified by the given image ID.
* Each lesion is represented by a segmentation which is connected to its parent image.
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion A lesion with a UID that identifies the corresponding lesion instance.
* @param imageID The image node identifier is defined by the given string.
+ *
* @return True, if the lesion is related to image identified by the given image ID; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresentOnImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& imageID);
/**
* @brief Check if the given lesion is present on the segmentation identified by the given segmentation ID.
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion A lesion with a UID that identifies the corresponding lesion instance.
* @param segmentationID The segmentation node identifier is defined by the given string.
+ *
* @return True, if the lesion is present on the segmentation identified by the given segmentation ID; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresentOnSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& segmentationID);
/**
* @brief Check if the given lesion is present at the given control point.
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion A lesion with a UID that identifies the corresponding lesion instance.
* @param controlPoint A control point with a UID that identifies the corresponding control point instance.
+ *
* @return True, if the lesion is present at the given control point; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresentAtControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint);
/**
* @brief Check if the given data node exists in the relation storage.
* The function receives the case- and the node-ID from the DICOM tags of the node itself.
* It uses node predicates to decide if the node is an image or a segmentation node and searches
* through the corresponding relations.
*
* @param dataNode A data node to check.
+ *
* @return True, if the data node exists; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const DataNode* dataNode);
/**
* @brief Check if the given lesion instance exists.
* This function can be used before calling 'AddLesionInstance' in order to avoid a possible exception.
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion A lesion with a UID that identifies the corresponding lesion instance.
+ *
* @return True, if the lesion instance exists; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
/**
* @brief Return a vector of all image IDs that identify images that are related to the given lesion.
* Each lesion is represented by a segmentation which is connected to its parent image.
* If the lesion is not represented by any segmentation, an empty vector is returned.
*
* @pre The UID of the lesion has to exist for a lesion instance.
* @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion A lesion with a UID that identifies the corresponding lesion instance.
- * @return A vector of IDs identifying images that identify images that are related to the given lesion.
+ *
+ * @return A vector of IDs identifying images that are related to the given lesion.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
/**
+ * @brief Return a vector of all image IDs that identify images that are related to the given examination period.
+ * If the examination period is not used by and image, an empty vector is returned.
+ *
+ * @pre The UID of the examination period has to exist for an examination period instance.
+ * @throw SemanticRelationException, if UID of the examination period does not exist for an examination period instance (this can be checked via 'InstanceExists').
+ *
+ * @param caseID The current case identifier is defined by the given string.
+ * @param examinationPeriod An examination period with a UID that identifies the corresponding examination period instance.
+ *
+ * @return A vector of IDs identifying images that are related to the given examination period.
+ */
+ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod);
+ /**
* @brief Return the control point of a data node.
* If the data node is not linked to a control point or the data node refers to a non-existing control point,
* a control point with an empty UID is returned.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
*
* @param dataNode The current case identifier is extracted from the given data node, which contains DICOM information about the case.
+ *
* @return The control point of the given data node.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GetControlPointOfImage(const DataNode* dataNode);
/**
* @brief Return a vector of all control points that are valid for the given case, given a specific lesion
*
- * @param caseID The current case identifier is defined by the given string.
- * @param lesion A specific lesion which has to be available at a returned (found) control point:
- * Only those control points are returned for which an associated data has a segmentation that references the given lesion.
- * If the lesion does not exists, an empty vector is returned.
- * @return A vector of control points.
+ * @param caseID The current case identifier is defined by the given string.
+ * @param lesion A specific lesion which has to be available at a returned (found) control point:
+ * Only those control points are returned for which an associated data has a segmentation that references the given lesion.
+ * If the lesion does not exists, an empty vector is returned.
+ *
+ * @return A vector of control points.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
/**
* @brief Return a vector of all control points that are valid for the given case, given a specific information type.
*
* @param caseID The current case identifier is defined by the given string.
* @param informationType A specific information type which has to be available at a returned (found) control point:
* Only those control points are returned for which an associated data has the given information type.
* If the information type instance does not exists, an empty vector is returned.
+ *
* @return A vector of control points.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType);
/**
* @brief Check if the given control point instance exists.
* This function can be used before adding, linking and unlinking control points to avoid a possible exception.
*
* @param caseID The current case identifier is defined by the given string.
* @param controlPoint A control point with a UID that identifies the corresponding control point instance.
+ *
* @return True, if the control point instance exists; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
/**
* @brief Check if the given examination period instance exists.
* This function can be used before calling 'AddExaminationPeriod' in order to avoid a possible exception.
*
* @param caseID The current case identifier is defined by the given string.
* @param examinationPeriod An examination period with a UID that identifies the corresponding examination period instance.
+ *
* @return True, if the examination period instance exists; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod);
/**
* @brief Return the information type of the given image.
* If the image does not contain any information type, an empty information type is returned.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
*
* @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case.
+ *
* @return The information type of the given data node.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationType GetInformationTypeOfImage(const DataNode* imageNode);
/**
* @brief Return a vector of all information types that are valid for the given case, given a specific control point.
*
* @param caseID The current case identifier is defined by the given string.
* @param controlPoint A specific control point which has to be available at a returned (found) information type:
* Only those information types are returned for which an associated data is linked to the given control point.
* If the control point instance does not exist, an empty vector is returned.
+ *
* @return A vector of information types.
*/
MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationTypeVector GetAllInformationTypesOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint);
/**
* @brief Check if the given information type exists.
*
* @param caseID The current case identifier is defined by the given string.
* @param informationType An information type.
+ *
* @return True, if the information type exists; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType);
/**
* @brief Determine if the given information type contains images, which are connected to segmentations that represent the given lesion.
* If the lesion or the information type are not correctly stored, the function returns false.
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion A Lesion with a UID that identifies the corresponding lesion instance.
* @param informationType An information type that identifies the corresponding information type instance.
*
* @return True, if the given information type contains data that is related to the given lesion; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::InformationType& informationType);
/**
* @brief Determine if the given control point contains images, which are connected to segmentations that represent the given lesion.
* If the lesion or the control point are not correctly stored, the function returns false.
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion A Lesion with a UID that identifies the corresponding lesion instance.
* @param controlPoint A control point with a UID that identifies the corresponding control point instance.
*
* @return True, if the given control point contains data that is related to the given lesion; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint);
/**
* @brief Determine if the given control point contains images, which refer to the given information type.
* If the information type or the control point are not correctly stored, the function returns false.
*
* @param caseID The current case identifier is defined by the given string.
* @param informationType An information type that identifies the corresponding information type instance.
* @param controlPoint A control point with a UID that identifies the corresponding control point instance.
*
* @return True, if the given control point contains data that is related to the given information type; false otherwise.
*/
MITKSEMANTICRELATIONS_EXPORT bool SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType, const SemanticTypes::ControlPoint& controlPoint);
} // namespace SemanticRelationsInference
} // namespace mitk
#endif // MITKSEMANTICRELATIONSINFERENCE_H
diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationsIntegration.h b/Modules/SemanticRelations/include/mitkSemanticRelationsIntegration.h
index f770210fda..0d4426c3d6 100644
--- a/Modules/SemanticRelations/include/mitkSemanticRelationsIntegration.h
+++ b/Modules/SemanticRelations/include/mitkSemanticRelationsIntegration.h
@@ -1,316 +1,326 @@
/*===================================================================
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 MITKSEMANTICRELATIONSINTEGRATION_H
#define MITKSEMANTICRELATIONSINTEGRATION_H
#include
// semantic relations module
#include "mitkISemanticRelationsObservable.h"
#include "mitkISemanticRelationsObserver.h"
#include "mitkSemanticTypes.h"
// mitk core
#include
namespace mitk
{
/**
* @brief The API provides functions to manipulate image relations and instances
* that are helpful during follow-up examination, like control-points (time period),
* types of the images or lesions that may be visible on multiple images.
*
* The class is able to generate IDs from given data nodes using DICOM information.
* These IDs are used to identify the corresponding instances of a specific case.
* The case can also be directly identified by the given case ID.
*
* In order for most functions to work the case ID has to be used as a parameter.
* If not, these functions do nothing.
*
* The class implements the ISemanticRelationsObservable interface to allow observers to
* be informed about changes in the semantic relation storage.
*/
class MITKSEMANTICRELATIONS_EXPORT SemanticRelationsIntegration : public ISemanticRelationsObservable
{
public:
/************************************************************************/
/* functions to implement the observer pattern */
/************************************************************************/
/**
* @brief Adds the given concrete observer to the vector that holds all currently registered observer.
* If the observer is already registered, it will not be added to the observer vector.
*
* @param observer The concrete observer to register.
*/
virtual void AddObserver(ISemanticRelationsObserver* observer) override;
/**
* @brief Removes the given concrete observer from the vector that holds all currently registered observer.
*
* @param observer The concrete observer to unregister.
*/
virtual void RemoveObserver(ISemanticRelationsObserver* observer) override;
virtual ~SemanticRelationsIntegration() {}
/************************************************************************/
/* functions to add / remove instances / attributes */
/************************************************************************/
/**
* @brief Add the given image to the set of already existing images.
* The date is extracted from the DICOM data of the image node and is compared to already existing control points in the semantic relations model.
* The function tries to find a fitting control point or to extend an already existing control point, if the extracted control point is close to
* any other, already existing control point.
* Finally, the image is linked to the correct control point.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
*
* @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node.
*/
void AddImage(const DataNode* imageNode);
/**
* @brief Remove the given image from the set of already existing images.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
*
* @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node.
*/
void RemoveImage(const DataNode* imageNode);
/**
* @brief Add a newly created lesion to the set of already existing lesions - with no connection to a specific image / segmentation of the case data.
*
* @pre The UID of the lesion must not already exist for a lesion instance.
* @throw SemanticRelationException, it the UID of the lesion already exists for a lesion instance (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion The lesion instance to add.
*/
void AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
/**
* @brief Overwrite an already existing lesion instance (this may be useful to overwrite the lesion with a different lesion class).
*
* @pre The UID of the lesion has to exist for a lesion instance.
* @throw SemanticRelationException, if the UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion The lesion instance that overwrites an existing lesion.
*/
void OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
/**
* @brief Add a newly created lesion to the set of already existing lesions. The lesion is added and a reference to
* the lesion is added to the segmentation. If the segmentation is already linked to a lesion, the
* old linkage is overwritten (this can be checked via 'IsRepresentingALesion').
*
* @pre The given segmentation data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr).
* @pre The UID of the lesion must not already exist for a lesion instance.
* @throw SemanticRelationException, if the UID of the lesion already exists for a lesion instance (this can be checked via 'InstanceExists').
*
* @param segmentationNode The segmentation identifier is extracted from the given segmentation data node. The segmentation node has DICOM information from its parent node.
* @param lesion The lesion instance to add and link.
*/
void AddLesionAndLinkSegmentation(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion);
/**
* @brief Remove the given lesion from the set of already existing lesions.
*
* @pre The UID of the lesion has to exist for a lesion instance.
* @throw SemanticRelationException, if the UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists').
* @pre The function needs to assure that no segmentation is still representing (linked to) this lesion.
* @throw SemanticRelationException, if the lesion instance to remove is still linked to by any segmentation (this can be checked via 'GetAllSegmentationsOfLesion').
*
* @param caseID The current case identifier is defined by the given string.
* @param lesion The lesion instance to remove.
*/
void RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion);
/**
* @brief Add a segmentation instance to the set of already existing segmentations - with no connection to a specific lesion.
*
* @param segmentationNode The segmentation identifier is extracted from the given segmentation data node. The segmentation node has DICOM information from its parent node.
* @param parentNode The node identifier of the parent node is extracted from the given parent data node.
*/
void AddSegmentation(const DataNode* segmentationNode, const DataNode* parentNode);
/**
* @brief Link the given segmentation instance to an an already existing lesion instance. If the segmentation is already linked to a lesion instance, the
* old linkage is overwritten (this can be checked via 'IsRepresentingALesion').
*
* @pre The given segmentation data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr).
* @pre The UID of the lesion has to exist for a lesion instance.
* @throw SemanticRelationException, if the UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists').
*
* @param segmentationNode The segmentation identifier is extracted from the given segmentation data node. The segmentation node has DICOM information from its parent node.
* @param lesion The lesion instance to link.
*/
void LinkSegmentationToLesion(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion);
/**
* @brief Unlink the given segmentation instance from the linked lesion instance.
* The lesion may stay unlinked to any segmentation.
*
* @pre The given segmentation data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr).
*
* @param segmentationNode The segmentation identifier is extracted from the given segmentation data node. The segmentation node has DICOM information from its parent node.
*/
void UnlinkSegmentationFromLesion(const DataNode* segmentationNode);
/**
* @brief Remove the given segmentation from the set of already existing segmentations.
*
* @pre The given segmentation data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr).
*
* @param segmentationNode The segmentation identifier is extracted from the given segmentation data node. The segmentation node has DICOM information from its parent node.
*/
void RemoveSegmentation(const DataNode* segmentationNode);
/**
* @brief Set the control point for the given image.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
*
* @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node.
* @param controlPoint The control point instance which is used for the given image.
*/
void SetControlPointOfImage(const DataNode* imageNode, const SemanticTypes::ControlPoint& controlPoint);
/**
* @brief Add a newly created control point to the set of already existing control points. A reference to the control point is added to the given image.
* This function combines adding a control point and linking it, since a control point with no associated data is not allowed.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
* @pre The UID of the control point must not already exist for a control point instance.
* @throw SemanticRelationException, if the UID of the control point already exists for a control point instance (this can be checked via 'InstanceExists').
* @pre The given control point must not already be contained in an existing control point interval.
* @throw SemanticRelationException, if the given control point is already contained in an existing control point interval (this can be checked via 'CheckContainingControlPoint').
* @pre The given control point must contain the date of the given image data node (if parameter 'checkConsistence = true').
* @throw SemanticRelationException, if the given control point does not contain the date of the given image data node and 'checkConsistence = true' (this can be checked via 'ControlPointManager::InsideControlPoint').
*
* @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node.
* @param controlPoint The control point instance to add. For a newly added control point always has "startDate = endDate".
* @param checkConsistence If true, the function checks, whether the date of the image data node actually lies inside the control point to link.
*/
void AddControlPointAndLinkImage(const DataNode* imageNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence = true);
/**
* @brief Link the given image to an already existing control point.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
* @pre The UID of the control point has to exist for a control point instance.
* @throw SemanticRelationException, if the UID of the control point does not exists for a control point instance (this can be checked via 'InstanceExists').
* @pre The given control point must contain the date of the given image data node (if parameter 'checkConsistence = true').
* @throw SemanticRelationException, if the given control point does not contain the date of the given image data node and 'checkConsistence = true' (this can be checked via 'ControlPointManager::InsideControlPoint').
*
* @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node.
* @param controlPoint The control point instance to link.
* @param checkConsistence If true, the function checks, whether the date of the image data node actually lies inside the control point to link.
*/
void LinkImageToControlPoint(const DataNode* imageNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence = true);
/**
* @brief Unlink the given image from the linked control point.
* If an image is unlinked from a control point, the function needs to check whether the control point is still linked to any other image:
* - if not, the control point instance will be removed (has to be removed since a control point with no associated image is not allowed).
* - if so, the function has to make sure that the control point instance is shortened to its minimum time period (e.g. moving the end point to an earlier date).
*
* @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node.
*/
void UnlinkImageFromControlPoint(const DataNode* imageNode);
/**
* @brief Add an examination period instance to the set of already existing examination periods - with no connection to a specific control point.
*
* @pre The UID of the examination period must not already exist for an examination period instance.
* @throw SemanticRelationException, if the UID of the examination period already exists for a examination period instance (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
* @param examinationPeriod The examination period to add.
*/
void AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod);
/**
+ * @brief Rename an already existing examination period instance.
+ *
+ * @pre The UID of the examination period has to exist for an examination period instance.
+ * @throw SemanticRelationException, if the UID of the examination period does not exist for an examination period instance (this can be checked via 'InstanceExists').
+ *
+ * @param caseID The current case identifier is defined by the given string.
+ * @param lesion The examination period instance that renames an existing examination period.
+ */
+ void RenameExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod);
+ /**
* @brief Add a control point to the vector of control point UIDs of an existing examination period.
*
* @pre The UID of the control point has to exist for a control point instance.
* @throw SemanticRelationException, if the UID of the control point does not exists for a control point instance (this can be checked via 'InstanceExists').
* @pre The UID of the examination period must not already exist for an examination period instance.
* @throw SemanticRelationException, if the UID of the examination period already exists for a examination period instance (this can be checked via 'InstanceExists').
*
* @param caseID The current case identifier is defined by the given string.
* @param controlPoint The control point instance to add to the examination period.
* @param examinationPeriod The examination period to which the control point should be added.
*/
void AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod);
/**
* @brief Set (and possibly overwrite) the information type of the given image.
* An already associated information type might be removed if is not referenced by any other image:
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
* @post If the information type instance did not exist before, it is now added.
*
* @param imageNode The current case identifier is extracted from the given image data node, which contains DICOM information about the case.
* @param informationType An information type that identifies the corresponding information type instance.
*/
void SetInformationType(const DataNode* imageNode, const SemanticTypes::InformationType& informationType);
/**
* @brief Set the information type of the given image.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
* @post If the information type instance did not exist before, it is now added.
*
* @param imageNode The current case identifier is extracted from the given image data node, which contains DICOM information about the case.
* @param informationType An information type that identifies the corresponding information type instance.
*/
void AddInformationTypeToImage(const DataNode* imageNode, const SemanticTypes::InformationType& informationType);
/**
* @brief Remove the information type of the given image.
* If the information type is removed, the function needs to check whether the information type is referenced by any other image:
* - if not, the information type instance can be removed (has to be removed since an information type with no associated image is not allowed).
* - if so, the information type is just removed from the given image.
*
* @pre The given image data node has to be valid (!nullptr).
* @throw SemanticRelationException, if the given image data node is invalid (==nullptr).
*
* @param imageNode The current case identifier is extracted from the given image data node, which contains DICOM information about the case.
*/
void RemoveInformationTypeFromImage(const DataNode* imageNode);
private:
/**
* @brief A vector that stores the currently registered observer of this observable subject.
*/
static std::vector m_ObserverVector;
/**
* @brief The class notifies (updates) the observer with a given case ID.
* The view's caseID was set before in the GUI. The parts of the view that observe changes in the semantic relations are only updated,
* if the given case ID is equal to the observer's current caseID and thus the observer currently shows the semantic information of the given case.
*
* @param caseID The caseID that identifies the currently active patient / case.
*/
virtual void NotifyObserver(const mitk::SemanticTypes::CaseID& caseID) const override;
/**
* @brief Remove all control points from the storage that are not referenced by any image anymore.
* This might happen if an image has been removed (and unlinked from the corresponding control point)
* or if the user sets a new control point for an image manually in the GUI.
*
* @param caseID The current case identifier is defined by the given string.
*/
void ClearControlPoints(const SemanticTypes::CaseID& caseID);
};
} // namespace mitk
#endif // MITKSEMANTICRELATIONSINTEGRATION_H
diff --git a/Modules/SemanticRelations/src/mitkControlPointManager.cpp b/Modules/SemanticRelations/src/mitkControlPointManager.cpp
index 98f1486379..01c041f871 100644
--- a/Modules/SemanticRelations/src/mitkControlPointManager.cpp
+++ b/Modules/SemanticRelations/src/mitkControlPointManager.cpp
@@ -1,179 +1,228 @@
/*===================================================================
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.
===================================================================*/
// semantic relations module
#include "mitkControlPointManager.h"
#include "mitkDICOMHelper.h"
+#include "mitkRelationStorage.h"
#include "mitkSemanticRelationException.h"
#include "mitkUIDGeneratorBoost.h"
// mitk core
#include
mitk::SemanticTypes::ControlPoint mitk::GenerateControlPoint(const DataNode* datanode)
{
SemanticTypes::ControlPoint controlPoint;
try
{
controlPoint = GetDICOMDateFromDataNode(datanode);
}
catch (SemanticRelationException& e)
{
- mitkReThrow(e) << "Cannot generate a control point from the DICOM tag of the given data node";
+ mitkReThrow(e) << "Cannot generate a control point from the DICOM tag of the given data node.";
}
controlPoint.UID = UIDGeneratorBoost::GenerateUID();
return controlPoint;
}
-mitk::SemanticTypes::ControlPoint mitk::GetControlPointByUID(const SemanticTypes::ID& controlPointUID, const std::vector& allControlPoints)
+mitk::SemanticTypes::ControlPoint mitk::GetControlPointByUID(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& controlPointUID)
{
auto lambda = [&controlPointUID](const SemanticTypes::ControlPoint& currentControlPoint)
{
return currentControlPoint.UID == controlPointUID;
};
+ SemanticTypes::ControlPointVector allControlPoints = RelationStorage::GetAllControlPointsOfCase(caseID);
const auto existingControlPoint = std::find_if(allControlPoints.begin(), allControlPoints.end(), lambda);
mitk::SemanticTypes::ControlPoint controlPoint;
if (existingControlPoint != allControlPoints.end())
{
controlPoint = *existingControlPoint;
}
return controlPoint;
}
-mitk::SemanticTypes::ControlPoint mitk::FindExistingControlPoint(const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ControlPointVector& allControlPoints)
+mitk::SemanticTypes::ControlPoint mitk::FindExistingControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint)
{
+ SemanticTypes::ControlPointVector allControlPoints = RelationStorage::GetAllControlPointsOfCase(caseID);
for (const auto& currentControlPoint : allControlPoints)
{
if (controlPoint.date == currentControlPoint.date)
{
return currentControlPoint;
}
}
return SemanticTypes::ControlPoint();
}
-mitk::SemanticTypes::ControlPoint mitk::FindClosestControlPoint(const SemanticTypes::ControlPoint& controlPoint, SemanticTypes::ControlPointVector& allControlPoints)
+mitk::SemanticTypes::ControlPoint mitk::FindClosestControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint)
{
+ SemanticTypes::ControlPointVector allControlPoints = RelationStorage::GetAllControlPointsOfCase(caseID);
if (allControlPoints.empty())
{
return SemanticTypes::ControlPoint();
}
// sort the vector of control points for easier lookup
std::sort(allControlPoints.begin(), allControlPoints.end());
// new control point does not match an existing control point
// check if the control point is close to an already existing control point
- std::vector::const_iterator it;
+ SemanticTypes::ControlPointVector::const_iterator it;
for (it = allControlPoints.begin(); it != allControlPoints.end(); ++it)
{
if (controlPoint.date < it->date)
{
break;
}
}
SemanticTypes::ControlPoint nextControlPoint;
SemanticTypes::ControlPoint previousControlPoint;
if (it == allControlPoints.begin())
{
// new date is smaller ("older") than the smallest already existing control point
nextControlPoint = *it;
}
else if (it != allControlPoints.end())
{
// new date is greater ("newer") than an already existing control point,
// but smaller ("older") than another already existing control point
nextControlPoint = *it;
previousControlPoint = *(--it);
}
else
{
// new date is greater ("newer") than the greatest already existing control point
previousControlPoint = *(--it);
}
// test distance to next and previous time period
double distanceToNextExaminationPeriod = nextControlPoint.DistanceInDays(controlPoint);
double distanceToPreviousExaminationPeriod = previousControlPoint.DistanceInDays(controlPoint);
SemanticTypes::ControlPoint closestControlPoint;
int closestDistanceInDays = 0;
if (distanceToNextExaminationPeriod < distanceToPreviousExaminationPeriod)
{
// control point is closer to the next control point
closestControlPoint = nextControlPoint;
closestDistanceInDays = distanceToNextExaminationPeriod;
}
else
{
// control point is closer to the previous control point
closestControlPoint = previousControlPoint;
closestDistanceInDays = distanceToPreviousExaminationPeriod;
}
int THRESHOLD_DISTANCE_IN_DAYS = 30;
if (closestDistanceInDays <= THRESHOLD_DISTANCE_IN_DAYS)
{
return closestControlPoint;
}
return SemanticTypes::ControlPoint();
}
-mitk::SemanticTypes::ExaminationPeriod mitk::FindExaminationPeriod(const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriodVector& allExaminationPeriods)
+mitk::SemanticTypes::ExaminationPeriod mitk::FindContainingExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint)
{
+ SemanticTypes::ExaminationPeriodVector allExaminationPeriods = RelationStorage::GetAllExaminationPeriodsOfCase(caseID);
for (const auto& examinationPeriod : allExaminationPeriods)
{
for (const auto& UID : examinationPeriod.controlPointUIDs)
{
if (controlPoint.UID == UID)
{
return examinationPeriod;
}
}
}
return SemanticTypes::ExaminationPeriod();
}
-void mitk::SortExaminationPeriods(SemanticTypes::ExaminationPeriodVector& allExaminationPeriods, const SemanticTypes::ControlPointVector& allControlPoints)
+mitk::SemanticTypes::ExaminationPeriod mitk::FindFittingExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint)
{
- auto lambda = [allControlPoints](const SemanticTypes::ExaminationPeriod& leftExaminationPeriod, const SemanticTypes::ExaminationPeriod& rightExaminationPeriod)
+ SemanticTypes::ExaminationPeriod specificExaminationPeriod;
+ SemanticTypes::ControlPoint specificControlPoint;
+ // find the closest control point
+ SemanticTypes::ControlPoint existingControlPoint = FindExistingControlPoint(caseID, controlPoint);
+ if (!existingControlPoint.UID.empty())
+ {
+ specificControlPoint = existingControlPoint;
+ }
+ else
+ {
+ auto closestControlPoint = FindClosestControlPoint(caseID, controlPoint);
+ if (!closestControlPoint.UID.empty())
+ {
+ specificControlPoint = closestControlPoint;
+ }
+ }
+
+ // find the containing examination period
+ return FindContainingExaminationPeriod(caseID, specificControlPoint);
+}
+
+mitk::SemanticTypes::ExaminationPeriod mitk::FindFittingExaminationPeriod(const DataNode* dataNode)
+{
+ SemanticTypes::CaseID caseID = "";
+ SemanticTypes::ControlPoint controlPoint;
+ try
+ {
+ caseID = GetCaseIDFromDataNode(dataNode);
+ controlPoint = GetDICOMDateFromDataNode(dataNode);
+ }
+ catch (SemanticRelationException& e)
+ {
+ mitkReThrow(e) << "Cannot find an examination period.";
+ }
+
+ return FindFittingExaminationPeriod(caseID, controlPoint);
+}
+
+void mitk::SortAllExaminationPeriods(const SemanticTypes::CaseID& caseID, SemanticTypes::ExaminationPeriodVector& allExaminationPeriods)
+{
+ SemanticTypes::ControlPointVector controlPoints = RelationStorage::GetAllControlPointsOfCase(caseID);
+ // sort the vector of control points for the timeline
+ std::sort(controlPoints.begin(), controlPoints.end());
+
+ auto lambda = [&caseID](const SemanticTypes::ExaminationPeriod& leftExaminationPeriod, const SemanticTypes::ExaminationPeriod& rightExaminationPeriod)
{
if (leftExaminationPeriod.controlPointUIDs.empty())
{
return true;
}
if (rightExaminationPeriod.controlPointUIDs.empty())
{
return false;
}
const auto leftUID = leftExaminationPeriod.controlPointUIDs.front();
const auto rightUID = rightExaminationPeriod.controlPointUIDs.front();
- const auto& leftControlPoint = GetControlPointByUID(leftUID, allControlPoints);
- const auto& rightControlPoint = GetControlPointByUID(rightUID, allControlPoints);
+ const auto& leftControlPoint = GetControlPointByUID(caseID, leftUID);
+ const auto& rightControlPoint = GetControlPointByUID(caseID, rightUID);
return leftControlPoint.date < rightControlPoint.date;
};
std::sort(allExaminationPeriods.begin(), allExaminationPeriods.end(), lambda);
}
diff --git a/Modules/SemanticRelations/src/mitkDICOMHelper.cpp b/Modules/SemanticRelations/src/mitkDICOMHelper.cpp
index 7be974ef13..21e2f1fc21 100644
--- a/Modules/SemanticRelations/src/mitkDICOMHelper.cpp
+++ b/Modules/SemanticRelations/src/mitkDICOMHelper.cpp
@@ -1,190 +1,190 @@
/*===================================================================
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.
===================================================================*/
// semantic relations module
#include "mitkDICOMHelper.h"
#include "mitkSemanticRelationException.h"
#include "mitkUIDGeneratorBoost.h"
// mitk core
#include
// c++
#include
mitk::SemanticTypes::ControlPoint GetControlPointFromString(const std::string& dateAsString)
{
// date expected to be YYYYMMDD (8 characters)
if (dateAsString.size() != 8)
{
// string does not represent a DICOM date
mitkThrowException(mitk::SemanticRelationException) << "Not a valid DICOM date format.";
}
mitk::SemanticTypes::ControlPoint controlPoint;
controlPoint.SetDateFromString(dateAsString);
return controlPoint;
}
std::string mitk::GetCaseIDDICOMProperty()
{
// extract suitable DICOM tag to use as the case id
// two alternatives can be used:
// - DICOM tag "0x0010, 0x0010" is PatientName
// - DICOM tag "0x0010, 0x0020" is PatientID
// in the current implementation the PatientName (0x0010, 0x0010) is used
return GeneratePropertyNameForDICOMTag(0x0010, 0x0010);
}
std::string mitk::GetNodeIDDICOMProperty()
{
// extract suitable DICOM tag to use as the data node id
// DICOM tag "0x0020, 0x000e" is SeriesInstanceUID
return GeneratePropertyNameForDICOMTag(0x0020, 0x000e);
}
std::string mitk::GetDateDICOMProperty()
{
// extract suitable DICOM tag to use as the data node id
// DICOM tag "0x0008, 0x0022" is AcquisitionDate
return GeneratePropertyNameForDICOMTag(0x0008, 0x0022);
}
std::string mitk::GetModalityDICOMProperty()
{
// extract suitable DICOM tag to use as the information type
// DICOM tag "0x0008, 0x0060" is Modality
return GeneratePropertyNameForDICOMTag(0x0008, 0x0060);
}
-mitk::SemanticTypes::CaseID mitk::GetCaseIDFromDataNode(const mitk::DataNode* dataNode)
+mitk::SemanticTypes::CaseID mitk::GetCaseIDFromDataNode(const DataNode* dataNode)
{
if (nullptr == dataNode)
{
mitkThrowException(SemanticRelationException) << "Not a valid data node.";
}
- mitk::BaseData* baseData = dataNode->GetData();
+ BaseData* baseData = dataNode->GetData();
if (nullptr == baseData)
{
mitkThrowException(SemanticRelationException) << "No valid base data.";
}
- mitk::BaseProperty* dicomTag = baseData->GetProperty(GetCaseIDDICOMProperty().c_str());
+ BaseProperty* dicomTag = baseData->GetProperty(GetCaseIDDICOMProperty().c_str());
if (nullptr == dicomTag)
{
mitkThrowException(SemanticRelationException) << "Not a valid DICOM property.";
}
std::string dicomTagAsString = dicomTag->GetValueAsString();
return dicomTagAsString;
}
-mitk::SemanticTypes::ID mitk::GetIDFromDataNode(const mitk::DataNode* dataNode)
+mitk::SemanticTypes::ID mitk::GetIDFromDataNode(const DataNode* dataNode)
{
if (nullptr == dataNode)
{
mitkThrowException(SemanticRelationException) << "Not a valid data node.";
}
- mitk::BaseData* baseData = dataNode->GetData();
+ BaseData* baseData = dataNode->GetData();
if (nullptr == baseData)
{
mitkThrowException(SemanticRelationException) << "No valid base data.";
}
- mitk::BaseProperty* dicomTag = baseData->GetProperty(GetNodeIDDICOMProperty().c_str());
+ BaseProperty* dicomTag = baseData->GetProperty(GetNodeIDDICOMProperty().c_str());
if (nullptr == dicomTag)
{
mitkThrowException(SemanticRelationException) << "Not a valid DICOM property.";
}
std::string dicomTagAsString = dicomTag->GetValueAsString();
return dicomTagAsString;
}
-mitk::SemanticTypes::ControlPoint mitk::GetDICOMDateFromDataNode(const mitk::DataNode* dataNode)
+mitk::SemanticTypes::ControlPoint mitk::GetDICOMDateFromDataNode(const DataNode* dataNode)
{
if (nullptr == dataNode)
{
mitkThrowException(SemanticRelationException) << "Not a valid data node.";
}
- mitk::BaseData* baseData = dataNode->GetData();
+ BaseData* baseData = dataNode->GetData();
if (nullptr == baseData)
{
mitkThrowException(SemanticRelationException) << "No valid base data.";
}
- mitk::BaseProperty* acquisitionDateProperty = baseData->GetProperty(GetDateDICOMProperty().c_str());
+ BaseProperty* acquisitionDateProperty = baseData->GetProperty(GetDateDICOMProperty().c_str());
if (nullptr == acquisitionDateProperty)
{
mitkThrowException(SemanticRelationException) << "Not a valid DICOM property.";
}
std::string acquisitionDateAsString = acquisitionDateProperty->GetValueAsString();
SemanticTypes::ControlPoint controlPoint;
try
{
controlPoint = GetControlPointFromString(acquisitionDateAsString);
}
catch (SemanticRelationException &e)
{
mitkReThrow(e) << "Cannot retrieve a valid DICOM date.";
}
return controlPoint;
}
-mitk::SemanticTypes::InformationType mitk::GetDICOMModalityFromDataNode(const mitk::DataNode* dataNode)
+mitk::SemanticTypes::InformationType mitk::GetDICOMModalityFromDataNode(const DataNode* dataNode)
{
if (nullptr == dataNode)
{
mitkThrowException(SemanticRelationException) << "Not a valid data node.";
}
- mitk::BaseData* baseData = dataNode->GetData();
+ BaseData* baseData = dataNode->GetData();
if (nullptr == baseData)
{
mitkThrowException(SemanticRelationException) << "No valid base data.";
}
- mitk::BaseProperty* dicomTag = baseData->GetProperty(GetModalityDICOMProperty().c_str());
+ BaseProperty* dicomTag = baseData->GetProperty(GetModalityDICOMProperty().c_str());
if (nullptr == dicomTag)
{
mitkThrowException(SemanticRelationException) << "Not a valid DICOM property.";
}
std::string dicomTagAsString = dicomTag->GetValueAsString();
return dicomTagAsString;
}
std::string mitk::TrimDICOM(const std::string& identifier)
{
if (identifier.empty())
{
return identifier;
}
// leading whitespace
std::size_t first = identifier.find_first_not_of(' ');
if (std::string::npos == first)
{
return "";
}
// trailing whitespace
std::size_t last = identifier.find_last_not_of(' ');
return identifier.substr(first, last - first + 1);
}
diff --git a/Modules/SemanticRelations/src/mitkLesionData.cpp b/Modules/SemanticRelations/src/mitkLesionData.cpp
index 172b364f65..d2c8ced6e4 100644
--- a/Modules/SemanticRelations/src/mitkLesionData.cpp
+++ b/Modules/SemanticRelations/src/mitkLesionData.cpp
@@ -1,43 +1,38 @@
/*===================================================================
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.
===================================================================*/
// semantic relations module
#include "mitkLesionData.h"
mitk::LesionData::LesionData(const SemanticTypes::Lesion& lesion/* = SemanticTypes::Lesion()*/)
{
m_Lesion = lesion;
}
-mitk::LesionData::~LesionData()
-{
- // nothing here
-}
-
void mitk::LesionData::SetLesion(const SemanticTypes::Lesion& lesion)
{
m_Lesion = lesion;
}
void mitk::LesionData::SetLesionPresence(const std::vector& lesionPresence)
{
m_LesionPresence = lesionPresence;
}
void mitk::LesionData::SetLesionVolume(const std::vector& lesionVolume)
{
m_LesionVolume = lesionVolume;
}
diff --git a/Modules/SemanticRelations/src/mitkLesionManager.cpp b/Modules/SemanticRelations/src/mitkLesionManager.cpp
index a9e83d88e2..6c623ad2c9 100644
--- a/Modules/SemanticRelations/src/mitkLesionManager.cpp
+++ b/Modules/SemanticRelations/src/mitkLesionManager.cpp
@@ -1,123 +1,106 @@
/*===================================================================
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.
===================================================================*/
// semantic relations module
#include "mitkLesionManager.h"
+#include "mitkRelationStorage.h"
#include "mitkSemanticRelationException.h"
#include "mitkSemanticRelationsInference.h"
-#include "mitkRelationStorage.h"
#include "mitkUIDGeneratorBoost.h"
-double GetLesionVolume(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controlPoint);
-
mitk::SemanticTypes::Lesion mitk::GenerateNewLesion(const std::string& lesionClassType/* = ""*/)
{
SemanticTypes::Lesion lesion;
- lesion.UID = mitk::UIDGeneratorBoost::GenerateUID();
+ lesion.UID = UIDGeneratorBoost::GenerateUID();
lesion.name = "New lesion";
lesion.lesionClass = GenerateNewLesionClass(lesionClassType);
return lesion;
}
mitk::SemanticTypes::LesionClass mitk::GenerateNewLesionClass(const std::string& lesionClassType/* = ""*/)
{
SemanticTypes::LesionClass lesionClass;
- lesionClass.UID = mitk::UIDGeneratorBoost::GenerateUID();
+ lesionClass.UID = UIDGeneratorBoost::GenerateUID();
lesionClass.classType = lesionClassType;
return lesionClass;
}
mitk::SemanticTypes::Lesion mitk::GetLesionByUID(const SemanticTypes::ID& lesionUID, const std::vector& allLesions)
{
auto lambda = [&lesionUID](const SemanticTypes::Lesion& currentLesion)
{
return currentLesion.UID == lesionUID;
};
const auto existingLesion = std::find_if(allLesions.begin(), allLesions.end(), lambda);
SemanticTypes::Lesion lesion;
if (existingLesion != allLesions.end())
{
lesion = *existingLesion;
}
return lesion;
}
mitk::SemanticTypes::LesionClass mitk::FindExistingLesionClass(const std::string& lesionClassType, const std::vector& allLesionClasses)
{
auto lambda = [&lesionClassType](const SemanticTypes::LesionClass& currentLesionClass)
{
return currentLesionClass.classType == lesionClassType;
};
const auto existingLesionClass = std::find_if(allLesionClasses.begin(), allLesionClasses.end(), lambda);
SemanticTypes::LesionClass lesionClass;
if (existingLesionClass != allLesionClasses.end())
{
lesionClass = *existingLesionClass;
}
return lesionClass;
}
-void mitk::GenerateAdditionalLesionData(LesionData& lesionData, const SemanticTypes::CaseID& caseID)
+void mitk::ComputeLesionPresence(LesionData& lesionData, const SemanticTypes::CaseID& caseID)
{
std::vector lesionPresence;
- std::vector lesionVolume;
- SemanticTypes::Lesion lesion = lesionData.GetLesion();
+ auto lesion = lesionData.GetLesion();
bool presence = false;
- double volume = 0.0;
-
- SemanticTypes::ControlPointVector controlPoints = RelationStorage::GetAllControlPointsOfCase(caseID);
+ auto controlPoints = RelationStorage::GetAllControlPointsOfCase(caseID);
// sort the vector of control points for the timeline
std::sort(controlPoints.begin(), controlPoints.end());
- for (const auto& controlPoint : controlPoints)
+ auto informationTypes = RelationStorage::GetAllInformationTypesOfCase(caseID);
+ for (const auto& informationType : informationTypes)
{
- try
+ for (const auto& controlPoint : controlPoints)
{
- presence = SemanticRelationsInference::IsLesionPresentAtControlPoint(caseID, lesion, controlPoint);
+ try
+ {
+ presence = SemanticRelationsInference::IsLesionPresentAtControlPoint(caseID, lesion, controlPoint);
+ }
+ catch (SemanticRelationException&)
+ {
+ presence = false;
+ }
+
+ lesionPresence.push_back(presence);
}
- catch (SemanticRelationException& e)
- {
- mitkReThrow(e) << "Cannot determine the lesion presence for generating additional lesion data.";
- }
-
- lesionPresence.push_back(presence);
- volume = GetLesionVolume(caseID, lesion, controlPoint);
- lesionVolume.push_back(volume);
}
lesionData.SetLesionPresence(lesionPresence);
- lesionData.SetLesionVolume(lesionVolume);
-}
-
-double GetLesionVolume(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controlPoint)
-{
- bool presence = mitk::SemanticRelationsInference::IsLesionPresentAtControlPoint(caseID, lesion, controlPoint);
- if (presence)
- {
- return 1.0;
- }
- else
- {
- return 0.0;
- }
}
diff --git a/Modules/SemanticRelations/src/mitkRelationStorage.cpp b/Modules/SemanticRelations/src/mitkRelationStorage.cpp
index 0a1f1c9e40..32156b5760 100644
--- a/Modules/SemanticRelations/src/mitkRelationStorage.cpp
+++ b/Modules/SemanticRelations/src/mitkRelationStorage.cpp
@@ -1,1539 +1,1571 @@
/*===================================================================
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 "mitkRelationStorage.h"
// semantic relations module
#include "mitkDICOMHelper.h"
// multi label module
#include
// mitk core
#include
#include
// c++
#include
#include
namespace
{
std::vector GetCaseIDs()
{
PERSISTENCE_GET_SERVICE_MACRO
if (nullptr == persistenceService)
{
MITK_DEBUG << "Persistence service could not be loaded";
return std::vector();
}
// the property list is valid for a certain scenario and contains all the case IDs of the radiological user's MITK session
std::string listIdentifier = "caseIDs";
mitk::PropertyList::Pointer propertyList = persistenceService->GetPropertyList(listIdentifier);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << listIdentifier << " for the current MITK workbench / session.";
return std::vector();
}
// retrieve a vector property that contains all case IDs
mitk::VectorProperty* caseIDsVectorProperty = dynamic_cast*>(propertyList->GetProperty(listIdentifier));
if (nullptr == caseIDsVectorProperty)
{
MITK_DEBUG << "Could not find the property " << listIdentifier << " for the " << listIdentifier << " property list.";
return std::vector();
}
return caseIDsVectorProperty->GetValue();
}
bool CaseIDExists(const mitk::SemanticTypes::CaseID& caseID)
{
auto allCaseIDs = GetCaseIDs();
auto existingCase = std::find(allCaseIDs.begin(), allCaseIDs.end(), caseID);
if (existingCase == allCaseIDs.end())
{
return false;
}
return true;
}
mitk::PropertyList::Pointer GetStorageData(const mitk::SemanticTypes::CaseID& caseID)
{
// access the storage
PERSISTENCE_GET_SERVICE_MACRO
if (nullptr == persistenceService)
{
MITK_DEBUG << "Persistence service could not be loaded";
return nullptr;
}
// The persistence service may create a new property list with the given ID, if no property list is found.
// Since we don't want to return a new property list but rather inform the user that the given case
// is not a valid, stored case, we will return nullptr in that case.
if (CaseIDExists(caseID))
{
// the property list is valid for a whole case and contains all the properties for the current case
return persistenceService->GetPropertyList(const_cast(caseID));
}
return nullptr;
}
mitk::SemanticTypes::Lesion GenerateLesion(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::ID& lesionID)
{
mitk::PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return mitk::SemanticTypes::Lesion();
}
mitk::VectorProperty* lesionDataProperty = dynamic_cast*>(propertyList->GetProperty(lesionID));
if (nullptr == lesionDataProperty)
{
MITK_DEBUG << "Lesion " << lesionID << " not found. Lesion can not be retrieved.";
return mitk::SemanticTypes::Lesion();
}
std::vector lesionData = lesionDataProperty->GetValue();
// a lesion date has to have exactly two values (the name of the lesion and the UID of the lesion class)
if (lesionData.size() != 2)
{
MITK_DEBUG << "Incorrect lesion data storage. Not two (2) strings of the lesion name and the lesion UID are stored.";
return mitk::SemanticTypes::Lesion();
}
// the lesion class ID is stored as the second property
std::string lesionClassID = lesionData[1];
mitk::StringProperty* lesionClassProperty = dynamic_cast(propertyList->GetProperty(lesionClassID));
if (nullptr != lesionClassProperty)
{
mitk::SemanticTypes::LesionClass generatedLesionClass;
generatedLesionClass.UID = lesionClassID;
generatedLesionClass.classType = lesionClassProperty->GetValue();
mitk::SemanticTypes::Lesion generatedLesion;
generatedLesion.UID = lesionID;
generatedLesion.name = lesionData[0];
generatedLesion.lesionClass = generatedLesionClass;
return generatedLesion;
}
MITK_DEBUG << "Incorrect lesion class storage. Lesion " << lesionID << " can not be retrieved.";
return mitk::SemanticTypes::Lesion();
}
mitk::SemanticTypes::ControlPoint GenerateControlpoint(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::ID& controlPointUID)
{
mitk::PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return mitk::SemanticTypes::ControlPoint();
}
// retrieve a vector property that contains the integer values of the date of a control point (0. year 1. month 2. day)
mitk::VectorProperty* controlPointVectorProperty = dynamic_cast*>(propertyList->GetProperty(controlPointUID));
if (nullptr == controlPointVectorProperty)
{
MITK_DEBUG << "Could not find the control point " << controlPointUID << " in the storage.";
return mitk::SemanticTypes::ControlPoint();
}
std::vector controlPointVectorPropertyValue = controlPointVectorProperty->GetValue();
// a control point has to have exactly three integer values (year, month and day)
if (controlPointVectorPropertyValue.size() != 3)
{
MITK_DEBUG << "Incorrect control point storage. Not three (3) values of the date are stored.";
return mitk::SemanticTypes::ControlPoint();
}
// set the values of the control point
mitk::SemanticTypes::ControlPoint generatedControlPoint;
generatedControlPoint.UID = controlPointUID;
generatedControlPoint.date = boost::gregorian::date(controlPointVectorPropertyValue[0],
controlPointVectorPropertyValue[1],
controlPointVectorPropertyValue[2]);
return generatedControlPoint;
}
}
mitk::SemanticTypes::LesionVector mitk::RelationStorage::GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::LesionVector();
}
// retrieve a vector property that contains the valid lesion-IDs for the current case
VectorProperty* lesionsVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions"));
if (nullptr == lesionsVectorProperty)
{
MITK_DEBUG << "Could not find any lesion in the storage.";
return SemanticTypes::LesionVector();
}
std::vector lesionsVectorPropertyValue = lesionsVectorProperty->GetValue();
SemanticTypes::LesionVector allLesionsOfCase;
for (const auto& lesionID : lesionsVectorPropertyValue)
{
SemanticTypes::Lesion generatedLesion = GenerateLesion(caseID, lesionID);
if (!generatedLesion.UID.empty())
{
allLesionsOfCase.push_back(generatedLesion);
}
}
return allLesionsOfCase;
}
mitk::SemanticTypes::Lesion mitk::RelationStorage::GetLesionOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::Lesion();
}
// retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID)
VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID));
if (nullptr == segmentationVectorProperty)
{
MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage.";
return SemanticTypes::Lesion();
}
std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue();
// the lesion ID of a segmentation is the second value in the vector
if (segmentationVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect segmentation storage. Not two (2) IDs stored.";
return SemanticTypes::Lesion();
}
std::string lesionID = segmentationVectorPropertyValue[1];
if (lesionID.empty())
{
// segmentation does not refer to any lesion; return empty lesion
return SemanticTypes::Lesion();
}
return GenerateLesion(caseID, lesionID);
}
mitk::SemanticTypes::ControlPointVector mitk::RelationStorage::GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::ControlPointVector();
}
// retrieve a vector property that contains the valid control point-IDs for the current case
VectorProperty* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints"));
if (nullptr == controlPointsVectorProperty)
{
MITK_DEBUG << "Could not find any control points in the storage.";
return SemanticTypes::ControlPointVector();
}
std::vector controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue();
SemanticTypes::ControlPointVector allControlPointsOfCase;
for (const auto& controlPointUID : controlPointsVectorPropertyValue)
{
SemanticTypes::ControlPoint generatedControlPoint = GenerateControlpoint(caseID, controlPointUID);
if (!generatedControlPoint.UID.empty())
{
allControlPointsOfCase.push_back(generatedControlPoint);
}
}
return allControlPointsOfCase;
}
mitk::SemanticTypes::ControlPoint mitk::RelationStorage::GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::ControlPoint();
}
// retrieve a vector property that contains the information type and the referenced ID of a control point (0. information type 1. control point ID)
VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID));
if (nullptr == imageVectorProperty)
{
MITK_DEBUG << "Could not find the image " << imageID << " in the storage.";
return SemanticTypes::ControlPoint();
}
std::vector imageVectorPropertyValue = imageVectorProperty->GetValue();
SemanticTypes::ControlPoint controlPoint;
// an image has to have exactly two values (the information type and the ID of the control point)
if (imageVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect data storage. Not two (2) values stored.";
return SemanticTypes::ControlPoint();
}
// the second value of the image vector is the ID of the referenced control point
std::string controlPointID = imageVectorPropertyValue[1];
// retrieve a vector property that contains the integer values of the date of a control point (0. year 1. month 2. day)
VectorProperty* controlPointVectorProperty = dynamic_cast*>(propertyList->GetProperty(controlPointID));
if (nullptr == controlPointVectorProperty)
{
MITK_DEBUG << "Could not find the control point " << controlPointID << " in the storage.";
return SemanticTypes::ControlPoint();
}
std::vector controlPointVectorPropertyValue = controlPointVectorProperty->GetValue();
// a control point has to have exactly three integer values (year, month and day)
if (controlPointVectorPropertyValue.size() != 3)
{
MITK_DEBUG << "Incorrect control point storage. Not three (3) values of the date are stored.";
return SemanticTypes::ControlPoint();
}
// set the values of the control point
controlPoint.UID = controlPointID;
controlPoint.date = boost::gregorian::date(controlPointVectorPropertyValue[0],
controlPointVectorPropertyValue[1],
controlPointVectorPropertyValue[2]);
return controlPoint;
}
mitk::SemanticTypes::ExaminationPeriodVector mitk::RelationStorage::GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::ExaminationPeriodVector();
}
// retrieve a vector property that contains the valid examination period UIDs for the current case
VectorProperty::Pointer examinationPeriodsVectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods"));
if (nullptr == examinationPeriodsVectorProperty)
{
MITK_DEBUG << "Could not find any examination periods in the storage.";
return SemanticTypes::ExaminationPeriodVector();
}
std::vector examinationPeriodsVectorPropertyValue = examinationPeriodsVectorProperty->GetValue();
SemanticTypes::ExaminationPeriodVector allExaminationPeriods;
for (const auto& examinationPeriodID : examinationPeriodsVectorPropertyValue)
{
// retrieve a vector property that contains the represented control point-IDs
VectorProperty::Pointer examinationPeriodVectorProperty = dynamic_cast*>(propertyList->GetProperty(examinationPeriodID));
if (nullptr == examinationPeriodVectorProperty)
{
MITK_DEBUG << "Could not find the examination period " << examinationPeriodID << " in the storage.";
continue;
}
std::vector examinationPeriodVectorPropertyValue = examinationPeriodVectorProperty->GetValue();
// an examination period has an arbitrary number of vector values (name and control point UIDs) (at least one for the name)
if (examinationPeriodVectorPropertyValue.empty())
{
MITK_DEBUG << "Incorrect examination period storage. At least one (1) value for the examination period name has to be stored.";
continue;
}
else
{
// set the values of the name and the control points
SemanticTypes::ExaminationPeriod generatedExaminationPeriod;
generatedExaminationPeriod.UID = examinationPeriodID;
generatedExaminationPeriod.name = examinationPeriodVectorPropertyValue[0];
for (size_t i = 1; i < examinationPeriodVectorPropertyValue.size(); ++i)
{
generatedExaminationPeriod.controlPointUIDs.push_back(examinationPeriodVectorPropertyValue[i]);
}
allExaminationPeriods.push_back(generatedExaminationPeriod);
}
}
return allExaminationPeriods;
}
mitk::SemanticTypes::InformationTypeVector mitk::RelationStorage::GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::InformationTypeVector();
}
// retrieve a vector property that contains the valid information types of the current case
VectorProperty* informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes"));
if (nullptr == informationTypesVectorProperty)
{
MITK_DEBUG << "Could not find any information types in the storage.";
return SemanticTypes::InformationTypeVector();
}
return informationTypesVectorProperty->GetValue();
}
mitk::SemanticTypes::InformationType mitk::RelationStorage::GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::InformationType();
}
// retrieve a vector property that contains the information type and the referenced ID of an image (0. information type 1. control point ID)
VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID));
if (nullptr == imageVectorProperty)
{
MITK_DEBUG << "Could not find the image " << imageID << " in the storage.";
return SemanticTypes::InformationType();
}
std::vector imageVectorPropertyValue = imageVectorProperty->GetValue();
// an image has to have exactly two values (the information type and the ID of the control point)
if (imageVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect data storage. Not two (2) values stored.";
return SemanticTypes::InformationType();
}
// the first value of the image vector is the information type
return imageVectorPropertyValue[0];
}
mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllImageIDsOfCase(const SemanticTypes::CaseID& caseID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::IDVector();
}
// retrieve a vector property that contains the valid image-IDs of the current case
VectorProperty* imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images"));
if (nullptr == imagesVectorProperty)
{
MITK_DEBUG << "Could not find any image in the storage.";
return SemanticTypes::IDVector();
}
return imagesVectorProperty->GetValue();
}
mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::IDVector();
}
// retrieve a vector property that contains the valid image-IDs of the current case
VectorProperty* imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images"));
if (nullptr == imagesVectorProperty)
{
MITK_DEBUG << "Could not find any image in the storage.";
return SemanticTypes::IDVector();
}
mitk::SemanticTypes::IDVector allImageIDsOfControlPoint;
std::vector imagesVectorPropertyValue = imagesVectorProperty->GetValue();
for (const auto& imageID : imagesVectorPropertyValue)
{
// retrieve a vector property that contains the referenced ID of an image (0. information type 1. control point ID)
VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID));
if (nullptr == imageVectorProperty)
{
continue;
}
std::vector imageVectorPropertyValue = imageVectorProperty->GetValue();
// an image has to have exactly two values (the information type and the ID of the control point)
if (imageVectorPropertyValue.size() != 2)
{
continue;
}
// the second value of the image vector is the ID of the referenced control point
if (imageVectorPropertyValue[1] == controlPoint.UID)
{
allImageIDsOfControlPoint.push_back(imageID);
}
}
return allImageIDsOfControlPoint;
}
mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::IDVector();
}
// retrieve a vector property that contains the valid image-IDs of the current case
VectorProperty* imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images"));
if (nullptr == imagesVectorProperty)
{
MITK_DEBUG << "Could not find any image in the storage.";
return SemanticTypes::IDVector();
}
mitk::SemanticTypes::IDVector allImageIDsOfInformationType;
std::vector imagesVectorPropertyValue = imagesVectorProperty->GetValue();
for (const auto& imageID : imagesVectorPropertyValue)
{
// retrieve a vector property that contains the referenced ID of an image (0. information type 1. control point ID)
VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID));
if (nullptr == imageVectorProperty)
{
continue;
}
std::vector imageVectorPropertyValue = imageVectorProperty->GetValue();
// an image has to have exactly two values (the information type and the ID of the control point)
if (imageVectorPropertyValue.size() != 2)
{
continue;
}
// the first value of the image vector is the ID of the referenced information type
if (imageVectorPropertyValue[0] == informationType)
{
allImageIDsOfInformationType.push_back(imageID);
}
}
return allImageIDsOfInformationType;
}
mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllSegmentationIDsOfCase(const SemanticTypes::CaseID& caseID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::IDVector();
}
// retrieve a vector property that contains the valid segmentation-IDs for the current case
VectorProperty* segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations"));
if (nullptr == segmentationsVectorProperty)
{
MITK_DEBUG << "Could not find any segmentation in the storage.";
return SemanticTypes::IDVector();
}
return segmentationsVectorProperty->GetValue();
}
mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllSegmentationIDsOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::IDVector();
}
// retrieve a vector property that contains the valid segmentation-IDs for the current case
VectorProperty* segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations"));
if (nullptr == segmentationsVectorProperty)
{
MITK_DEBUG << "Could not find any segmentation in the storage.";
return SemanticTypes::IDVector();
}
mitk::SemanticTypes::IDVector allSegmentationIDsOfImage;
std::vector segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue();
for (const auto& segmentationID : segmentationsVectorPropertyValue)
{
// retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID)
VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID));
if (nullptr == segmentationVectorProperty)
{
continue;
}
std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue();
// a segmentation has to have exactly two values (the ID of the referenced image and the ID of the referenced lesion)
if (segmentationVectorPropertyValue.size() != 2)
{
continue;
}
// the first value of the segmentation vector is the ID of the referenced image
if (segmentationVectorPropertyValue[0] == imageID)
{
allSegmentationIDsOfImage.push_back(segmentationID);
}
}
return allSegmentationIDsOfImage;
}
mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::IDVector();
}
// retrieve a vector property that contains the valid segmentation-IDs for the current case
VectorProperty* segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations"));
if (nullptr == segmentationsVectorProperty)
{
MITK_DEBUG << "Could not find any segmentation in the storage.";
return SemanticTypes::IDVector();
}
mitk::SemanticTypes::IDVector allSegmentationIDsOfLesion;
std::vector segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue();
for (const auto& segmentationID : segmentationsVectorPropertyValue)
{
// retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID)
VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID));
if (nullptr == segmentationVectorProperty)
{
continue;
}
std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue();
// a segmentation has to have exactly two values (the ID of the referenced image and the ID of the referenced lesion)
if (segmentationVectorPropertyValue.size() != 2)
{
continue;
}
// the second value of the segmentation vector is the ID of the referenced lesion
if (segmentationVectorPropertyValue[1] == lesion.UID)
{
allSegmentationIDsOfLesion.push_back(segmentationID);
}
}
return allSegmentationIDsOfLesion;
}
mitk::SemanticTypes::ID mitk::RelationStorage::GetImageIDOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return SemanticTypes::ID();
}
// retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID)
VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID));
if (nullptr == segmentationVectorProperty)
{
MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage.";
return SemanticTypes::ID();
}
std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue();
// the lesion ID of a segmentation is the second value in the vector
if (segmentationVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect segmentation storage. Not two (2) IDs stored.";
return SemanticTypes::ID();
}
return segmentationVectorPropertyValue[0];
}
std::vector mitk::RelationStorage::GetAllCaseIDs()
{
return GetCaseIDs();
}
bool mitk::RelationStorage::InstanceExists(const SemanticTypes::CaseID& caseID)
{
return CaseIDExists(caseID);
}
void mitk::RelationStorage::AddCase(const SemanticTypes::CaseID& caseID)
{
PERSISTENCE_GET_SERVICE_MACRO
if (nullptr == persistenceService)
{
MITK_DEBUG << "Persistence service could not be loaded";
return;
}
// the property list is valid for a certain scenario and contains all the case IDs of the radiological user's MITK session
std::string listIdentifier = "caseIDs";
PropertyList::Pointer propertyList = persistenceService->GetPropertyList(listIdentifier);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << listIdentifier << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains all case IDs
VectorProperty::Pointer caseIDsVectorProperty = dynamic_cast*>(propertyList->GetProperty(listIdentifier));
std::vector caseIDsVectorPropertyValue;
if (nullptr == caseIDsVectorProperty)
{
caseIDsVectorProperty = VectorProperty::New();
}
else
{
caseIDsVectorPropertyValue = caseIDsVectorProperty->GetValue();
}
auto existingCase = std::find(caseIDsVectorPropertyValue.begin(), caseIDsVectorPropertyValue.end(), caseID);
if (existingCase != caseIDsVectorPropertyValue.end())
{
return;
}
// add case to the "caseIDs" property list
caseIDsVectorPropertyValue.push_back(caseID);
caseIDsVectorProperty->SetValue(caseIDsVectorPropertyValue);
propertyList->SetProperty(listIdentifier, caseIDsVectorProperty);
}
void mitk::RelationStorage::AddImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid image-IDs for the current case
VectorProperty::Pointer imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images"));
std::vector imagesVectorPropertyValue;
if (nullptr == imagesVectorProperty)
{
imagesVectorProperty = VectorProperty::New();
}
else
{
imagesVectorPropertyValue = imagesVectorProperty->GetValue();
}
auto existingImage = std::find(imagesVectorPropertyValue.begin(), imagesVectorPropertyValue.end(), imageID);
if (existingImage != imagesVectorPropertyValue.end())
{
return;
}
// add image to the "images" property list
imagesVectorPropertyValue.push_back(imageID);
imagesVectorProperty->SetValue(imagesVectorPropertyValue);
propertyList->SetProperty("images", imagesVectorProperty);
// add the image itself
VectorProperty::Pointer imageVectorProperty = VectorProperty::New();
// an image has to have exactly two values (the information type and the ID of the control point)
std::vector imageVectorPropertyValue(2);
imageVectorProperty->SetValue(imageVectorPropertyValue);
propertyList->SetProperty(imageID, imageVectorProperty);
}
void mitk::RelationStorage::RemoveImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid image-IDs for the current case
VectorProperty::Pointer imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images"));
if (nullptr == imagesVectorProperty)
{
MITK_DEBUG << "Could not find any images in the storage.";
return;
}
// remove the image reference from the list of all images of the current case
std::vector imagesVectorPropertyValue = imagesVectorProperty->GetValue();
imagesVectorPropertyValue.erase(std::remove(imagesVectorPropertyValue.begin(), imagesVectorPropertyValue.end(), imageID), imagesVectorPropertyValue.end());
if (imagesVectorPropertyValue.empty())
{
// no more images stored -> remove the images property list
propertyList->DeleteProperty("images");
}
else
{
// or store the modified vector value
imagesVectorProperty->SetValue(imagesVectorPropertyValue);
}
// remove the image instance itself
propertyList->DeleteProperty(imageID);
}
void mitk::RelationStorage::AddSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::ID& parentID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid segmentation-IDs for the current case
VectorProperty::Pointer segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations"));
std::vector segmentationsVectorPropertyValue;
if (nullptr == segmentationsVectorProperty)
{
segmentationsVectorProperty = VectorProperty::New();
}
else
{
segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue();
}
auto existingSegmentation = std::find(segmentationsVectorPropertyValue.begin(), segmentationsVectorPropertyValue.end(), segmentationID);
if (existingSegmentation != segmentationsVectorPropertyValue.end())
{
return;
}
// add segmentation to the "segmentations" property list
segmentationsVectorPropertyValue.push_back(segmentationID);
segmentationsVectorProperty->SetValue(segmentationsVectorPropertyValue);
propertyList->SetProperty("segmentations", segmentationsVectorProperty);
// add the segmentation itself
VectorProperty::Pointer segmentationVectorProperty = VectorProperty::New();
// a segmentation has to have exactly two values (the ID of the referenced image and the ID of the referenced lesion)
std::vector segmentationVectorPropertyValue(2);
segmentationVectorPropertyValue[0] = parentID;
segmentationVectorProperty->SetValue(segmentationVectorPropertyValue);
propertyList->SetProperty(segmentationID, segmentationVectorProperty);
}
void mitk::RelationStorage::RemoveSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid segmentation-IDs for the current case
VectorProperty::Pointer segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations"));
if (nullptr == segmentationsVectorProperty)
{
MITK_DEBUG << "Could not find any segmentation in the storage.";
return;
}
// remove the lesion reference from the list of all lesions of the current case
std::vector segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue();
segmentationsVectorPropertyValue.erase(std::remove(segmentationsVectorPropertyValue.begin(), segmentationsVectorPropertyValue.end(), segmentationID), segmentationsVectorPropertyValue.end());
if (segmentationsVectorPropertyValue.empty())
{
// no more segmentations stored -> remove the segmentations property list
propertyList->DeleteProperty("segmentations");
}
else
{
// or store the modified vector value
segmentationsVectorProperty->SetValue(segmentationsVectorPropertyValue);
}
// remove the lesion instance itself
propertyList->DeleteProperty(segmentationID);
}
void mitk::RelationStorage::AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid lesion-IDs for the current case
VectorProperty::Pointer lesionsVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions"));
std::vector lesionsVectorPropertyValue;
if (nullptr == lesionsVectorProperty)
{
lesionsVectorProperty = VectorProperty::New();
}
else
{
lesionsVectorPropertyValue = lesionsVectorProperty->GetValue();
}
const auto& existingIndex = std::find(lesionsVectorPropertyValue.begin(), lesionsVectorPropertyValue.end(), lesion.UID);
if (existingIndex != lesionsVectorPropertyValue.end())
{
return;
}
// add the new lesion id from the given lesion to the vector of all current lesion IDs
lesionsVectorPropertyValue.push_back(lesion.UID);
// overwrite the current vector property with the new, extended string vector
lesionsVectorProperty->SetValue(lesionsVectorPropertyValue);
propertyList->SetProperty("lesions", lesionsVectorProperty);
// add the lesion with the lesion UID as the key and the lesion information as value
std::vector lesionData;
lesionData.push_back(lesion.name);
lesionData.push_back(lesion.lesionClass.UID);
VectorProperty::Pointer newLesionVectorProperty = VectorProperty::New();
newLesionVectorProperty->SetValue(lesionData);
propertyList->SetProperty(lesion.UID, newLesionVectorProperty);
// add the lesion class with the lesion class UID as key and the class type as value
std::string lesionClassType = lesion.lesionClass.classType;
propertyList->SetStringProperty(lesion.lesionClass.UID.c_str(), lesionClassType.c_str());
}
void mitk::RelationStorage::OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid lesion-IDs for the current case
VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions"));
if (nullptr == lesionVectorProperty)
{
MITK_DEBUG << "Could not find any lesion in the storage.";
return;
}
std::vector lesionVectorPropertyValue = lesionVectorProperty->GetValue();
const auto existingLesion = std::find(lesionVectorPropertyValue.begin(), lesionVectorPropertyValue.end(), lesion.UID);
if (existingLesion != lesionVectorPropertyValue.end())
{
// overwrite the referenced lesion class UID with the new, given lesion class data
std::vector lesionData;
lesionData.push_back(lesion.name);
lesionData.push_back(lesion.lesionClass.UID);
VectorProperty::Pointer newLesionVectorProperty = VectorProperty::New();
newLesionVectorProperty->SetValue(lesionData);
propertyList->SetProperty(lesion.UID, newLesionVectorProperty);
// overwrite the lesion class with the lesion class UID as key and the new, given class type as value
std::string lesionClassType = lesion.lesionClass.classType;
propertyList->SetStringProperty(lesion.lesionClass.UID.c_str(), lesionClassType.c_str());
}
else
{
MITK_DEBUG << "Could not find lesion " << lesion.UID << " in the storage. Cannot overwrite the lesion.";
}
}
void mitk::RelationStorage::LinkSegmentationToLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::Lesion& lesion)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid lesion-IDs for the current case
VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions"));
if (nullptr == lesionVectorProperty)
{
MITK_DEBUG << "Could not find any lesion in the storage.";
return;
}
std::vector lesionVectorPropertyValue = lesionVectorProperty->GetValue();
const auto existingLesion = std::find(lesionVectorPropertyValue.begin(), lesionVectorPropertyValue.end(), lesion.UID);
if (existingLesion != lesionVectorPropertyValue.end())
{
// set / overwrite the lesion reference of the given segmentation
// retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID)
VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID));
if (nullptr == segmentationVectorProperty)
{
MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage. Cannot link segmentation to lesion.";
return;
}
std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue();
if (segmentationVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect segmentation storage. Not two (2) IDs stored.";
return;
}
// the lesion ID of a segmentation is the second value in the vector
segmentationVectorPropertyValue[1] = lesion.UID;
segmentationVectorProperty->SetValue(segmentationVectorPropertyValue);
return;
}
MITK_DEBUG << "Could not find lesion " << lesion.UID << " in the storage. Cannot link segmentation to lesion.";
}
void mitk::RelationStorage::UnlinkSegmentationFromLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID)
VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID));
if (nullptr == segmentationVectorProperty)
{
MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage. Cannot unlink lesion from segmentation.";
return;
}
std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue();
// a segmentation has to have exactly two values (the ID of the linked image and the ID of the lesion)
if (segmentationVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect data storage. Not two (2) values stored.";
return;
}
// the second value of the segmentation vector is the ID of the referenced lesion
// set the lesion reference to an empty string for removal
segmentationVectorPropertyValue[1] = "";
segmentationVectorProperty->SetValue(segmentationVectorPropertyValue);
}
void mitk::RelationStorage::RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid lesions of the current case
VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions"));
if (nullptr == lesionVectorProperty)
{
MITK_DEBUG << "Could not find any lesion in the storage.";
return;
}
// remove the lesion reference from the list of all lesions of the current case
std::vector lesionsVectorPropertyValue = lesionVectorProperty->GetValue();
lesionsVectorPropertyValue.erase(std::remove(lesionsVectorPropertyValue.begin(), lesionsVectorPropertyValue.end(), lesion.UID), lesionsVectorPropertyValue.end());
if (lesionsVectorPropertyValue.empty())
{
// no more lesions stored -> remove the lesions property list
propertyList->DeleteProperty("lesions");
}
else
{
// or store the modified vector value
lesionVectorProperty->SetValue(lesionsVectorPropertyValue);
}
// remove the lesion instance itself
// the lesion data is stored under the lesion ID
VectorProperty* lesionDataProperty = dynamic_cast*>(propertyList->GetProperty(lesion.UID));
if (nullptr == lesionDataProperty)
{
MITK_DEBUG << "Lesion " << lesion.UID << " not found (already removed?). Cannot remove the lesion.";
return;
}
std::vector lesionData = lesionDataProperty->GetValue();
// a lesion date has to have exactly two values (the name of the lesion and the UID of the lesion class)
if (lesionData.size() != 2)
{
MITK_DEBUG << "Incorrect lesion data storage. Not two (2) strings of the lesion UID and the lesion name are stored.";
}
else
{
std::string lesionClassID = lesionData[1];
RemoveLesionClass(caseID, lesionClassID);
}
propertyList->DeleteProperty(lesion.UID);
}
void mitk::RelationStorage::RemoveLesionClass(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& lesionClassID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the lesion class
StringProperty* lesionClassProperty = dynamic_cast(propertyList->GetProperty(lesionClassID));
if (nullptr == lesionClassProperty)
{
MITK_DEBUG << "Lesion class " << lesionClassID << " not found (already removed?). Cannot remove the lesion class.";
return;
}
// retrieve a vector property that contains the valid lesions of the current case
VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions"));
if (nullptr == lesionVectorProperty)
{
return;
}
// check if the lesion class ID is referenced by any other lesion
std::vector lesionsVectorPropertyValue = lesionVectorProperty->GetValue();
const auto existingLesionClass = std::find_if(lesionsVectorPropertyValue.begin(), lesionsVectorPropertyValue.end(),
[&propertyList, &lesionClassID](const std::string& lesionID)
{
VectorProperty* lesionDataProperty = dynamic_cast*>(propertyList->GetProperty(lesionID));
if (nullptr == lesionDataProperty)
{
return false;
}
std::vector lesionData = lesionDataProperty->GetValue();
// a lesion date has to have exactly two values (the name of the lesion and the UID of the lesion class)
if (lesionData.size() != 2)
{
return false;
}
return lesionData[1] == lesionClassID;
});
if (existingLesionClass == lesionsVectorPropertyValue.end())
{
// lesion class ID not referenced; remove lesion class
propertyList->DeleteProperty(lesionClassID);
}
}
void mitk::RelationStorage::AddControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid controlPoint UIDs for the current case
VectorProperty::Pointer controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints"));
std::vector controlPointsVectorPropertyValue;
if (nullptr == controlPointsVectorProperty)
{
controlPointsVectorProperty = VectorProperty::New();
}
else
{
controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue();
}
const auto existingControlPoint = std::find(controlPointsVectorPropertyValue.begin(), controlPointsVectorPropertyValue.end(), controlPoint.UID);
if (existingControlPoint != controlPointsVectorPropertyValue.end())
{
return;
}
// add the new control point UID from the given control point to the vector of all current control point UIDs
controlPointsVectorPropertyValue.push_back(controlPoint.UID);
// overwrite the current vector property with the new, extended string vector
controlPointsVectorProperty->SetValue(controlPointsVectorPropertyValue);
propertyList->SetProperty("controlpoints", controlPointsVectorProperty);
// store the control point values (the three integer values of a date)
std::vector controlPointDate;
controlPointDate.push_back(controlPoint.date.year());
controlPointDate.push_back(controlPoint.date.month());
controlPointDate.push_back(controlPoint.date.day());
VectorProperty::Pointer newControlPointVectorProperty = VectorProperty::New();
newControlPointVectorProperty->SetValue(controlPointDate);
propertyList->SetProperty(controlPoint.UID, newControlPointVectorProperty);
}
void mitk::RelationStorage::LinkImageToControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::ControlPoint& controlPoint)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid controlPoint UIDs for the current case
VectorProperty* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints"));
if (nullptr == controlPointsVectorProperty)
{
MITK_DEBUG << "Could not find any control point in the storage.";
return;
}
std::vector controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue();
const auto existingControlPoint = std::find(controlPointsVectorPropertyValue.begin(), controlPointsVectorPropertyValue.end(), controlPoint.UID);
if (existingControlPoint != controlPointsVectorPropertyValue.end())
{
// set / overwrite the control point reference of the given data
// retrieve a vector property that contains the referenced ID of a image (0. information type 1. control point ID)
VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID));
if (nullptr == imageVectorProperty)
{
MITK_DEBUG << "Could not find the image " << imageID << " in the storage. Cannot link data to control point.";
return;
}
std::vector imageVectorPropertyValue = imageVectorProperty->GetValue();
// an image has to have exactly two values (the information type and the ID of the control point)
if (imageVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect data storage. Not two (2) values stored.";
return;
}
// the second value of the image vector is the ID of the referenced control point
imageVectorPropertyValue[1] = controlPoint.UID;
imageVectorProperty->SetValue(imageVectorPropertyValue);
return;
}
MITK_DEBUG << "Could not find control point " << controlPoint.UID << " in the storage. Cannot link data to control point.";
}
void mitk::RelationStorage::UnlinkImageFromControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the referenced ID of a date (0. information type 1. control point ID)
VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID));
if (nullptr == imageVectorProperty)
{
MITK_DEBUG << "Could not find the date " << imageID << " in the storage. Cannot unlink control point from date.";
return;
}
std::vector imageVectorPropertyValue = imageVectorProperty->GetValue();
// an image has to have exactly two values (the information type and the ID of the control point)
if (imageVectorPropertyValue.size() != 2)
{
MITK_DEBUG << "Incorrect data storage. Not two (2) values stored.";
return;
}
// the second value of the image vector is the ID of the referenced control point
// set the control point reference to an empty string for removal
imageVectorPropertyValue[1] = "";
imageVectorProperty->SetValue(imageVectorPropertyValue);
}
void mitk::RelationStorage::RemoveControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid controlPoint UIDs for the current case
VectorProperty* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints"));
if (nullptr == controlPointsVectorProperty)
{
MITK_DEBUG << "Could not find any control point in the storage.";
return;
}
// remove the control point reference from the list of all control points of the current case
std::vector controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue();
controlPointsVectorPropertyValue.erase(std::remove(controlPointsVectorPropertyValue.begin(), controlPointsVectorPropertyValue.end(), controlPoint.UID), controlPointsVectorPropertyValue.end());
if (controlPointsVectorPropertyValue.empty())
{
// no more control points stored -> remove the control point property list
propertyList->DeleteProperty("controlpoints");
}
else
{
// or store the modified vector value
controlPointsVectorProperty->SetValue(controlPointsVectorPropertyValue);
}
// remove the control point instance itself
propertyList->DeleteProperty(controlPoint.UID);
}
void mitk::RelationStorage::AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod)
{
PropertyList::Pointer propertyList = GetStorageData(caseID);
if (nullptr == propertyList)
{
MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
return;
}
// retrieve a vector property that contains the valid examination period UIDs for the current case
VectorProperty::Pointer examinationPeriodsVectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods"));
std::vector examinationPeriodsVectorPropertyValue;
if (nullptr == examinationPeriodsVectorProperty)
{
examinationPeriodsVectorProperty = VectorProperty::New();
}
else
{
examinationPeriodsVectorPropertyValue = examinationPeriodsVectorProperty->GetValue();
}
const auto& existingIndex = std::find(examinationPeriodsVectorPropertyValue.begin(), examinationPeriodsVectorPropertyValue.end(), examinationPeriod.UID);
if (existingIndex != examinationPeriodsVectorPropertyValue.end())
{
return;
}
// add the new examination period id from the given examination period to the vector of all current examination period UIDs
examinationPeriodsVectorPropertyValue.push_back(examinationPeriod.UID);
// overwrite the current vector property with the new, extended string vector
examinationPeriodsVectorProperty->SetValue(examinationPeriodsVectorPropertyValue);
propertyList->SetProperty("examinationperiods", examinationPeriodsVectorProperty);
// add the examination period with the UID as the key and the name as as the vector value
std::vector examinationPeriodData;
examinationPeriodData.push_back(examinationPeriod.name);
VectorProperty::Pointer newExaminationPeriodVectorProperty = VectorProperty::New();
newExaminationPeriodVectorProperty->SetValue(examinationPeriodData);
propertyList->SetProperty(examinationPeriod.UID, newExaminationPeriodVectorProperty);
}
+void mitk::RelationStorage::RenameExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod)
+{
+ PropertyList::Pointer propertyList = GetStorageData(caseID);
+ if (nullptr == propertyList)
+ {
+ MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session.";
+ return;
+ }
+ // retrieve a vector property that contains the data of the given examination period
+ VectorProperty* examinationPeriodDataVectorProperty = dynamic_cast*>(propertyList->GetProperty(examinationPeriod.UID));
+ if (nullptr == examinationPeriodDataVectorProperty)
+ {
+ MITK_DEBUG << "Could not find examination period " << examinationPeriod.UID << " in the storage. Cannot rename the examination period.";
+ return;
+ }
+
+ std::vector