diff --git a/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp b/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp index b096c27417..995ff2ab01 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp @@ -1,425 +1,431 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ +#include "mitkModelFitInfo.h" + #include +#include #include #include "mitkDataNode.h" #include "mitkDataStorage.h" -#include "mitkModelFitInfo.h" + #include "mitkScalarListLookupTableProperty.h" #include "mitkModelFitException.h" #include "mitkModelFitResultRelationRule.h" void mitk::modelFit::ModelFitInfo::AddParameter(Parameter::Pointer p) { if (p.IsNull()) { mitkThrow() << "Given parameter must not be NULL"; } if (GetParameter(p->name, p->type).IsNull()) { MITK_DEBUG << "Adding parameter '" << p->name << "with type " << p->type << "' to modelFit '" << uid << "'."; LockType lock(mutex); parameterList.push_back(p); } else { MITK_DEBUG << "Parameter '" << p->name << "' of modelFit '" << uid << "' already exists. Aborting."; } } mitk::modelFit::Parameter::ConstPointer mitk::modelFit::ModelFitInfo::GetParameter(const std::string& name, const Parameter::Type& type) const { for (ConstIterType iter = parameterList.begin(); iter != parameterList.end(); ++iter) { Parameter::ConstPointer p = static_cast(*iter); if (p->name == name && p->type == type) { return p; } } return nullptr; } const mitk::modelFit::ModelFitInfo::ParamListType& mitk::modelFit::ModelFitInfo::GetParameters() const { return this->parameterList; }; void mitk::modelFit::ModelFitInfo::DeleteParameter(const std::string& name, const Parameter::Type& type) { for (IterType iter = parameterList.begin(); iter != parameterList.end(); ++iter) { Parameter::ConstPointer p = static_cast(*iter); if (p->name == name && p->type == type) { MITK_DEBUG << "Deleting parameter '" << name << " with type " << type << "' from modelFit '" << uid << "'."; LockType lock(mutex); parameterList.erase(iter); return; } } } const std::string mitk::modelFit::GetMandatoryProperty(const mitk::DataNode* node, const std::string& prop) { std::string result; if (!node || !node->GetData() || !node->GetData()->GetPropertyList()->GetStringProperty(prop.c_str(), result) || result.empty()) { mitkThrowException(mitk::modelFit::ModelFitException) << "Node " << node->GetName() << " is lacking the required " << "property '" << prop << "' or contains an empty string."; } return result; } const std::string mitk::modelFit::GetMandatoryProperty(const mitk::BaseData* data, const std::string& prop) { std::string result; if (!data || !data->GetPropertyList()->GetStringProperty(prop.c_str(), result) || result.empty()) { mitkThrowException(mitk::modelFit::ModelFitException) << "Data is lacking the required " << "property '" << prop << "' or contains an empty string."; } return result; } mitk::modelFit::ModelFitInfo::Pointer mitk::modelFit::CreateFitInfoFromNode(const ModelFitInfo::UIDType& uid, const mitk::DataStorage* storage) { if (!storage) { return nullptr; } mitk::DataStorage::SetOfObjects::ConstPointer nodes = GetNodesOfFit(uid, storage); if (nodes.IsNull() || nodes->empty()) { return nullptr; } mitk::DataNode::ConstPointer node = nodes->GetElement( 0).GetPointer(); //take one of the nodes as template if (!node->GetData()) { return nullptr; } ModelFitInfo::Pointer fit = ModelFitInfo::New(); fit->uid = uid; // Mandatory properties try { fit->fitType = GetMandatoryProperty(node, mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME()); fit->modelType = GetMandatoryProperty(node, mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME()); fit->modelName = GetMandatoryProperty(node, mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME()); } catch (const ModelFitException& e) { MITK_ERROR << e.what(); return nullptr; } // Either a function string or a function class must exist if (!node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), fit->function)) { fit->function = ""; } try { fit->functionClassID = GetMandatoryProperty(node, mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME()); } catch (const ModelFitException&) { if (fit->function.empty()) { MITK_ERROR << "The properties '" << mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME() << "'and '" << mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME() << "' are both empty or missing. One of these is required."; return nullptr; } } node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), fit->fitName); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), fit->x); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), fit->xAxisName); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), fit->xAxisUnit); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), fit->yAxisName); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), fit->yAxisUnit); // Parameter for (DataStorage::SetOfObjects::ConstIterator pos = nodes->Begin(); pos != nodes->End(); ++pos) { modelFit::Parameter::Pointer param = ExtractParameterFromData(pos->Value()->GetData()); if (param.IsNotNull()) { fit->AddParameter(param); } } // Static parameters mitk::ScalarListLookupTableProperty::ConstPointer varProp = dynamic_cast(node->GetData()->GetProperty(mitk::ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME().c_str()).GetPointer()); if (varProp.IsNotNull()) { const mitk::ScalarListLookupTable lut = varProp->GetValue(); const mitk::ScalarListLookupTable::LookupTableType& varMap = lut.GetLookupTable(); for (mitk::ScalarListLookupTable::LookupTableType::const_iterator mapIter = varMap.begin(); mapIter != varMap.end(); ++mapIter) { fit->staticParamMap.Add(mapIter->first, mapIter->second); } } //fit input and ROI if (storage) { auto inputRule = ModelFitResultRelationRule::New(); auto inputPredicate = inputRule->GetDestinationsDetector(node); auto inputNodes = storage->GetSubset(inputPredicate); if (inputNodes->empty()) { MITK_ERROR << "Cannot create valid model fit info. Input node cannot be found."; return nullptr; } if (inputNodes->size()>1) { MITK_WARN << "More then one node found as input node. This could indicate an invalid state as only one input node should be present. Used first found input node."; } auto inputNode = inputNodes->front(); mitk::Image::ConstPointer inputImage = dynamic_cast(inputNode->GetData()); if (inputImage.IsNull()) { MITK_ERROR << "Cannot create valid model fit info. input node does not contain an image."; return nullptr; } fit->inputImage = inputImage; } node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME().c_str(), fit->roiUID); mitk::ScalarListLookupTableProperty::ConstPointer inputDataProp = dynamic_cast(node->GetData()->GetProperty(mitk::ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME().c_str()).GetPointer()); if (inputDataProp.IsNotNull()) { fit->inputData = inputDataProp->GetValue(); } return fit; } mitk::modelFit::ModelFitInfo::Pointer mitk::modelFit::CreateFitInfoFromModelParameterizer(const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage, const std::string& fitType, const std::string& fitName, const ModelFitInfo::UIDType& roiUID) { if (!usedParameterizer) { return nullptr; } UIDGenerator generator("FitUID_"); std::string uid = generator.GetUID(); ModelFitInfo::Pointer fit = ModelFitInfo::New(); fit->uid = uid; fit->fitType = fitType; fit->fitName = fitName; fit->inputImage = dynamic_cast(inputImage); if (fit->inputImage.IsNull()) { mitkThrow() << "Cannot generate model fit info. Input node does not contain an image."; } fit->modelType = usedParameterizer->GetModelType(); fit->modelName = usedParameterizer->GetModelDisplayName(); fit->function = usedParameterizer->GetFunctionString(); fit->x = usedParameterizer->GetXName(); fit->functionClassID = usedParameterizer->GetClassID(); fit->xAxisName = usedParameterizer->GetXAxisName(); fit->xAxisUnit = usedParameterizer->GetXAxisUnit(); fit->yAxisName = usedParameterizer->GetYAxisName(); fit->yAxisUnit = usedParameterizer->GetYAxisUnit(); // Parameter ModelTraitsInterface::ParameterNamesType paramNames = usedParameterizer->GetParameterNames(); ModelTraitsInterface::ParamterScaleMapType paramScales = usedParameterizer->GetParameterScales(); ModelTraitsInterface::ParamterUnitMapType paramUnits = usedParameterizer->GetParameterUnits(); for (ModelTraitsInterface::ParameterNamesType::iterator pos = paramNames.begin(); pos != paramNames.end(); ++pos) { modelFit::Parameter::Pointer param = modelFit::Parameter::New(); param->name = *pos; param->type = Parameter::ParameterType; if (paramScales.find(*pos) == paramScales.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (scales do not include parameter). Parameter name: " << *pos; } if (paramUnits.find(*pos) == paramUnits.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (units do not include parameter). Parameter name: " << *pos; } param->scale = paramScales[*pos]; param->unit = paramUnits[*pos]; fit->AddParameter(param); } //derived parameter ModelTraitsInterface::DerivedParameterNamesType derivedNames = usedParameterizer->GetDerivedParameterNames(); ModelTraitsInterface::DerivedParamterScaleMapType derivedScales = usedParameterizer->GetDerivedParameterScales(); ModelTraitsInterface::DerivedParamterUnitMapType derivedUnits = usedParameterizer->GetDerivedParameterUnits(); for (ModelTraitsInterface::ParameterNamesType::iterator pos = derivedNames.begin(); pos != derivedNames.end(); ++pos) { modelFit::Parameter::Pointer param = modelFit::Parameter::New(); param->name = *pos; param->type = Parameter::DerivedType; if (derivedScales.find(*pos) == derivedScales.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (scales do not include parameter). Parameter name: " << *pos; } if (derivedUnits.find(*pos) == derivedUnits.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (units do not include parameter). Parameter name: " << *pos; } param->scale = derivedScales[*pos]; param->unit = derivedUnits[*pos]; fit->AddParameter(param); } // Static parameters (but transfer only the global ones) ModelParameterizerBase::StaticParameterMapType staticParamMap = usedParameterizer->GetGlobalStaticParameters(); for (ModelParameterizerBase::StaticParameterMapType::const_iterator pos = staticParamMap.begin(); pos != staticParamMap.end(); ++pos) { fit->staticParamMap.Add(pos->first, pos->second); } fit->roiUID = roiUID; return fit; } mitk::modelFit::ModelFitInfo::Pointer mitk::modelFit::CreateFitInfoFromModelParameterizer(const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage, const std::string& fitType, const ScalarListLookupTable& inputData, const std::string& fitName, const ModelFitInfo::UIDType& roiUID) { mitk::modelFit::ModelFitInfo::Pointer info = CreateFitInfoFromModelParameterizer(usedParameterizer, inputImage, fitType, fitName, roiUID); info->inputData = inputData; return info; } mitk::DataStorage::SetOfObjects::ConstPointer mitk::modelFit::GetNodesOfFit(const ModelFitInfo::UIDType& fitUID, const mitk::DataStorage* storage) { if (!storage) { return nullptr; } mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(fitUID)); return storage->GetSubset(predicate); }; mitk::modelFit::NodeUIDSetType mitk::modelFit::GetFitUIDsOfNode(const mitk::DataNode* node, const mitk::DataStorage* storage) { + auto rule = ModelFitResultRelationRule::New(); mitk::modelFit::NodeUIDSetType result; if (node && storage) { - mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New( + auto fitUIDPredicate = mitk::NodePredicateDataProperty::New( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str()); - mitk::DataStorage::SetOfObjects::ConstPointer nodes = storage->GetDerivations(node, predicate, - false); + auto rulePredicate = rule->GetSourcesDetector(node); + auto predicate = NodePredicateAnd::New(fitUIDPredicate, rulePredicate); + mitk::DataStorage::SetOfObjects::ConstPointer nodes = storage->GetSubset(predicate); for (mitk::DataStorage::SetOfObjects::ConstIterator pos = nodes->Begin(); pos != nodes->End(); ++pos) { mitk::modelFit::ModelFitInfo::UIDType uid; pos->Value()->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), uid); + result.insert(uid); } } return result; }; diff --git a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp index a48a2fb8ae..214a53b123 100644 --- a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp @@ -1,905 +1,922 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include #include // mitk #include // Qt #include #include #include #include #include "QmitkPlotWidget.h" #include "mitkNodePredicateFunction.h" #include "mitkScalarListLookupTableProperty.h" #include "mitkModelFitConstants.h" #include "mitkExtractTimeGrid.h" #include "mitkModelGenerator.h" #include "mitkModelFitException.h" #include "mitkModelFitParameterValueExtraction.h" #include "mitkTimeGridHelper.h" +#include "mitkModelFitResultRelationRule.h" #include "mitkModelFitPlotDataHelper.h" #include "ModelFitInspectorView.h" const std::string ModelFitInspectorView::VIEW_ID = "org.mitk.gui.gt.fit.inspector"; const unsigned int ModelFitInspectorView::INTERPOLATION_STEPS = 10; const std::string DEFAULT_X_AXIS = "Time [s]"; ModelFitInspectorView::ModelFitInspectorView() : m_renderWindowPart(nullptr), m_internalUpdateFlag(false), m_currentFit(nullptr), m_currentModelParameterizer(nullptr), m_currentModelProviderService(nullptr), m_currentSelectedTimeStep(0), m_currentSelectedNode(nullptr) { m_currentSelectedPosition.Fill(0.0); m_modelfitList.clear(); } ModelFitInspectorView::~ModelFitInspectorView() { } void ModelFitInspectorView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_renderWindowPart != renderWindowPart) { m_renderWindowPart = renderWindowPart; } this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { m_renderWindowPart = nullptr; this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void ModelFitInspectorView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_SelectionServiceConnector = std::make_unique(); m_SelectionServiceConnector->AddPostSelectionListener(this->GetSite()->GetWorkbenchWindow()->GetSelectionService()); m_Controls.inputNodeSelector->SetDataStorage(GetDataStorage()); m_Controls.inputNodeSelector->SetEmptyInfo(QString("Please select input data to be viewed.")); m_Controls.inputNodeSelector->SetInvalidInfo(QString("No input data is selected")); m_Controls.inputNodeSelector->SetPopUpTitel(QString("Choose 3D+t input data that should be viewed!")); m_Controls.inputNodeSelector->SetSelectionIsOptional(false); m_Controls.inputNodeSelector->SetSelectOnlyVisibleNodes(true); auto predicate = mitk::NodePredicateFunction::New([](const mitk::DataNode *node) { bool isModelFitNode = node->GetData() && node->GetData()->GetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str()).IsNotNull(); return isModelFitNode || (node && node->GetData() && node->GetData()->GetTimeSteps() > 1); }); m_Controls.inputNodeSelector->SetNodePredicate(predicate); connect(m_SelectionServiceConnector.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.inputNodeSelector, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); connect(m_Controls.inputNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ModelFitInspectorView::OnInputChanged); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); connect(m_Controls.cmbFit, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFitSelectionChanged(int))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.btnScaleToData, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedYChecked(bool))); connect(m_Controls.btnScaleToData, SIGNAL(clicked()), this, SLOT(OnScaleToDataYClicked())); connect(m_Controls.sbFixMax, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.sbFixMin, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.btnScaleToData_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedXChecked(bool))); connect(m_Controls.btnScaleToData_x, SIGNAL(clicked()), this, SLOT(OnScaleToDataXClicked())); connect(m_Controls.sbFixMax_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); connect(m_Controls.sbFixMin_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); connect(m_Controls.btnFullPlot, SIGNAL(clicked(bool)), this, SLOT(OnFullPlotClicked(bool))); this->EnsureBookmarkPointSet(); m_Controls.inspectionPositionWidget->SetPositionBookmarkNode(m_PositionBookmarksNode.Lock()); connect(m_Controls.inspectionPositionWidget, SIGNAL(PositionBookmarksChanged()), this, SLOT(OnPositionBookmarksChanged())); // For some reason this needs to be called to set the plot widget's minimum width to an // acceptable level (since Qwt 6). // Otherwise it tries to keep both axes equal in length, resulting in a minimum width of // 400-500px which is way too much. m_Controls.widgetPlot->GetPlot()->updateAxes(); m_Controls.cmbFit->clear(); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::SetFocus() { } void ModelFitInspectorView::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_currentSelectedNode) { QmitkSingleNodeSelectionWidget::NodeList emptylist; this->m_Controls.inputNodeSelector->SetCurrentSelection(emptylist); } } void ModelFitInspectorView::OnScaleFixedYChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::yLeft, !checked); if (checked) { OnScaleToDataYClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleFixedXChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::xBottom, !checked); if (checked) { OnScaleToDataXClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleToDataYClicked() { auto minmax = this->m_PlotCurves.GetYMinMax(); auto min = minmax.first - std::abs(minmax.first) * 0.01; auto max = minmax.second + std::abs(minmax.second) * 0.01; m_Controls.sbFixMin->setValue(min); m_Controls.sbFixMax->setValue(max); }; void ModelFitInspectorView::OnScaleToDataXClicked() { auto minmax = this->m_PlotCurves.GetXMinMax(); auto min = minmax.first - std::abs(minmax.first) * 0.01; auto max = minmax.second + std::abs(minmax.second) * 0.01; m_Controls.sbFixMin_x->setValue(min); m_Controls.sbFixMax_x->setValue(max); }; void ModelFitInspectorView::OnFixedScalingYChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::yLeft, m_Controls.sbFixMin->value(), m_Controls.sbFixMax->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnFixedScalingXChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::xBottom, m_Controls.sbFixMin_x->value(), m_Controls.sbFixMax_x->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnFullPlotClicked(bool checked) { m_Controls.tabWidget->setVisible(!checked); }; int ModelFitInspectorView::ActualizeFitSelectionWidget() { mitk::modelFit::ModelFitInfo::UIDType selectedFitUD = ""; - bool isModelFitNode = this->m_currentSelectedNode->GetData()->GetPropertyList()->GetStringProperty( - mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); + bool isModelFitNode = false; + if (this->m_Controls.inputNodeSelector->GetSelectedNode().IsNotNull()) + { + isModelFitNode = this->m_Controls.inputNodeSelector->GetSelectedNode()->GetData()->GetPropertyList()->GetStringProperty( + mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); + } mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::modelFit::NodeUIDSetType fitUIDs = mitk::modelFit::GetFitUIDsOfNode( this->m_currentSelectedNode, storage); this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); for (const auto & fitUID : fitUIDs) { mitk::modelFit::ModelFitInfo::ConstPointer info = mitk::modelFit::CreateFitInfoFromNode(fitUID, storage).GetPointer(); if (info.IsNotNull()) { this->m_modelfitList.insert(std::make_pair(info->uid, info)); std::ostringstream nameStrm; if (info->fitName.empty()) { nameStrm << info->uid; } else { nameStrm << info->fitName; } nameStrm << " (" << info->modelName << ")"; QVariant data(info->uid.c_str()); m_Controls.cmbFit->addItem(QString::fromStdString(nameStrm.str()), data); } else { MITK_ERROR << "Was not able to extract model fit information from storage. Node properties in storage may be invalid. Failed fit UID:" << fitUID; } } int cmbIndex = 0; if (m_modelfitList.empty()) { cmbIndex = -1; }; if (isModelFitNode) { //model was selected, thus select this one in combobox QVariant data(selectedFitUD.c_str()); cmbIndex = m_Controls.cmbFit->findData(data); if (cmbIndex == -1) { MITK_WARN << "Model fit Inspector in invalid state. Selected fit seems to be not avaible in plugin selection. Failed fit UID:" << selectedFitUD; } }; m_Controls.cmbFit->setCurrentIndex(cmbIndex); return cmbIndex; } void ModelFitInspectorView::OnInputChanged(const QList& nodes) { if (nodes.size() > 0) { if (nodes.front() != this->m_currentSelectedNode) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nodes.front(); mitk::modelFit::ModelFitInfo::UIDType selectedFitUD = ""; bool isModelFitNode = this->m_currentSelectedNode->GetData()->GetPropertyList()->GetStringProperty( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); if (isModelFitNode) { - this->m_currentSelectedNode = this->GetParentNode(this->m_currentSelectedNode); + this->m_currentSelectedNode = this->GetInputNode(this->m_currentSelectedNode); + if (this->m_currentSelectedNode.IsNull()) + { + MITK_WARN << + "Model fit Inspector in invalid state. Input image for selected fit cannot be found in data storage. Failed fit UID:" + << selectedFitUD; + } } auto cmbIndex = ActualizeFitSelectionWidget(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); if (cmbIndex == -1) { //only raw 4D data selected. Just update plots for current position m_currentFit = nullptr; m_currentFitTime.Modified(); OnSliceChanged(); m_Controls.plotDataWidget->SetXName(DEFAULT_X_AXIS); } else { //refresh fit selection (and implicitly update plots) OnFitSelectionChanged(cmbIndex); } } } else { if (this->m_currentSelectedNode.IsNotNull()) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nullptr; this->m_currentFit = nullptr; this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); OnFitSelectionChanged(0); RefreshPlotData(); m_Controls.plotDataWidget->SetPlotData(&(this->m_PlotCurves)); m_Controls.fitParametersWidget->setFits(QmitkFitParameterModel::FitVectorType()); RenderPlot(); } } } mitk::DataNode::ConstPointer -ModelFitInspectorView::GetParentNode(mitk::DataNode::ConstPointer node) +ModelFitInspectorView::GetInputNode(mitk::DataNode::ConstPointer node) { if (node.IsNotNull()) { + std::string selectedFitUD = ""; + bool isModelFitNode = node->GetData()->GetPropertyList()->GetStringProperty( + mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); + + auto rule = mitk::ModelFitResultRelationRule::New(); + auto predicate = rule->GetDestinationsDetector(node); mitk::DataStorage::SetOfObjects::ConstPointer parentNodeList = - GetDataStorage()->GetSources(node); + GetDataStorage()->GetSubset(predicate); if (parentNodeList->size() > 0) { return parentNodeList->front().GetPointer(); } } return mitk::DataNode::ConstPointer(); } void ModelFitInspectorView::ValidateAndSetCurrentPosition() { mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(nullptr); unsigned int currentSelectedTimestep = m_renderWindowPart->GetTimeNavigationController()->GetTime()-> GetPos(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimeStep != currentSelectedTimestep || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimeStep = currentSelectedTimestep; m_currentPositionTime.Modified(); m_validSelectedPosition = false; auto inputImage = this->GetCurrentInputImage(); if (inputImage.IsNull()) { return; } mitk::BaseGeometry::ConstPointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep( m_currentSelectedTimeStep); // check for invalid time step if (geometry.IsNull()) { geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); } if (geometry.IsNull()) { return; } m_validSelectedPosition = geometry->IsInside(m_currentSelectedPosition); } } mitk::Image::ConstPointer ModelFitInspectorView::GetCurrentInputImage() const { mitk::Image::ConstPointer result = nullptr; if (this->m_currentFit.IsNotNull()) { result = m_currentFit->inputImage; } else if (this->m_currentSelectedNode.IsNotNull()) { result = dynamic_cast(this->m_currentSelectedNode->GetData()); if (result.IsNotNull() && result->GetTimeSteps() <= 1) { //if the image is not dynamic, we can't use it. result = nullptr; } } return result; }; const mitk::ModelBase::TimeGridType ModelFitInspectorView::GetCurrentTimeGrid() const { if (m_currentModelProviderService && m_currentFit.IsNotNull()) { return m_currentModelProviderService->GetVariableGrid(m_currentFit); } else { //fall back if there is no model provider we assume to use the normal time grid. return ExtractTimeGrid(GetCurrentInputImage()); } }; void ModelFitInspectorView::OnSliceChanged() { ValidateAndSetCurrentPosition(); m_Controls.widgetPlot->setEnabled(m_validSelectedPosition); if (m_currentSelectedNode.IsNotNull()) { m_Controls.inspectionPositionWidget->SetCurrentPosition(m_currentSelectedPosition); if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } } void ModelFitInspectorView::OnPositionBookmarksChanged() { if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } void ModelFitInspectorView::OnFitSelectionChanged(int index) { if (!m_internalUpdateFlag) { MITK_DEBUG << "selected fit index: " << index; std::string uid = ""; if (m_Controls.cmbFit->count() > index) { uid = m_Controls.cmbFit->itemData(index).toString().toStdString(); } mitk::modelFit::ModelFitInfo::ConstPointer newFit = nullptr; ModelFitInfoListType::iterator finding = m_modelfitList.find(uid); if (finding != m_modelfitList.end()) { newFit = finding->second; } if (m_currentFit != newFit) { m_currentModelParameterizer = nullptr; m_currentModelProviderService = nullptr; if (newFit.IsNotNull()) { m_currentModelParameterizer = mitk::ModelGenerator::GenerateModelParameterizer(*newFit); m_currentModelProviderService = mitk::ModelGenerator::GetProviderService(newFit->functionClassID); } m_currentFit = newFit; m_currentFitTime.Modified(); auto name = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { name += " [" + m_currentFit->xAxisUnit + "]"; } m_Controls.plotDataWidget->SetXName(name); OnSliceChanged(); } } } mitk::PlotDataCurveCollection::Pointer ModelFitInspectorView::RefreshPlotDataCurveCollection(const mitk::Point3D& position, const mitk::Image* input, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer) { mitk::PlotDataCurveCollection::Pointer result = mitk::PlotDataCurveCollection::New(); //sample curve if (input) { result->InsertElement(mitk::MODEL_FIT_PLOT_SAMPLE_NAME(), GenerateImageSamplePlotData(position, input, timeGrid)); } //model signal curve if (fitInfo) { // Interpolate time grid (x values) so the curve looks smooth const mitk::ModelBase::TimeGridType interpolatedTimeGrid = mitk::GenerateSupersampledTimeGrid(timeGrid, INTERPOLATION_STEPS); auto hires_curve = mitk::GenerateModelSignalPlotData(position, fitInfo, interpolatedTimeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME(), hires_curve); auto curve = mitk::GenerateModelSignalPlotData(position, fitInfo, timeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_SIGNAL_NAME(), curve); } return result; }; bool ModelFitInspectorView::RefreshPlotData() { bool changed = false; if (m_currentSelectedNode.IsNull()) { this->m_PlotCurves = mitk::ModelFitPlotData(); changed = m_selectedNodeTime > m_lastRefreshTime; m_lastRefreshTime.Modified(); } else { assert(GetRenderWindowPart() != NULL); const mitk::Image* input = GetCurrentInputImage(); const mitk::ModelBase::TimeGridType timeGrid = GetCurrentTimeGrid(); if (m_currentFitTime > m_lastRefreshTime || m_currentPositionTime > m_lastRefreshTime) { if (m_validSelectedPosition) { m_PlotCurves.currentPositionPlots = RefreshPlotDataCurveCollection(m_currentSelectedPosition,input,m_currentFit, timeGrid, m_currentModelParameterizer); } else { m_PlotCurves.currentPositionPlots = mitk::PlotDataCurveCollection::New(); } changed = true; } auto bookmarks = m_PositionBookmarks.Lock(); if (bookmarks.IsNotNull()) { if (m_currentFitTime > m_lastRefreshTime || bookmarks->GetMTime() > m_lastRefreshTime) { m_PlotCurves.positionalPlots.clear(); auto endIter = bookmarks->End(); for (auto iter = bookmarks->Begin(); iter != endIter; iter++) { auto collection = RefreshPlotDataCurveCollection(iter.Value(), input, m_currentFit, timeGrid, m_currentModelParameterizer); m_PlotCurves.positionalPlots.emplace(iter.Index(), std::make_pair(iter.Value(), collection)); } changed = true; } } else { m_PlotCurves.positionalPlots.clear(); } // input data curve if (m_currentFitTime > m_lastRefreshTime) { m_PlotCurves.staticPlots->clear(); if (m_currentFit.IsNotNull()) { m_PlotCurves.staticPlots = GenerateAdditionalModelFitPlotData(m_currentSelectedPosition, m_currentFit, timeGrid); } changed = true; } m_lastRefreshTime.Modified(); } return changed; } void ModelFitInspectorView::RenderFitInfo() { assert(m_renderWindowPart != nullptr); // configure fit information if (m_currentFit.IsNull()) { m_Controls.lFitType->setText(""); m_Controls.lFitUID->setText(""); m_Controls.lModelName->setText(""); m_Controls.lModelType->setText(""); } else { m_Controls.lFitType->setText(QString::fromStdString(m_currentFit->fitType)); m_Controls.lFitUID->setText(QString::fromStdString(m_currentFit->uid)); m_Controls.lModelName->setText(QString::fromStdString(m_currentFit->modelName)); m_Controls.lModelType->setText(QString::fromStdString(m_currentFit->modelType)); } // print results std::stringstream infoOutput; m_Controls.fitParametersWidget->setVisible(false); m_Controls.groupSettings->setVisible(false); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else if (!m_validSelectedPosition) { infoOutput << "Current position is outside of the input image of the selected fit.\nInspector is deactivated."; } else { m_Controls.fitParametersWidget->setVisible(true); m_Controls.fitParametersWidget->setFits({ m_currentFit }); m_Controls.fitParametersWidget->setPositionBookmarks(m_PositionBookmarks.Lock()); m_Controls.fitParametersWidget->setCurrentPosition(m_currentSelectedPosition); } // configure data table m_Controls.tableInputData->clearContents(); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else { m_Controls.groupSettings->setVisible(true); m_Controls.tableInputData->setRowCount(m_PlotCurves.staticPlots->size()); unsigned int rowIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos, ++rowIndex) { QColor dataColor; if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing free iso lines. dataColor.setHsv(((rowIndex + 1) * 85) % 360, 255, 255); } QTableWidgetItem* newItem = new QTableWidgetItem(QString::fromStdString(pos->first)); m_Controls.tableInputData->setItem(rowIndex, 0, newItem); newItem = new QTableWidgetItem(); newItem->setBackgroundColor(dataColor); m_Controls.tableInputData->setItem(rowIndex, 1, newItem); } } m_Controls.lInfo->setText(QString::fromStdString(infoOutput.str())); } void ModelFitInspectorView::RenderPlotCurve(const mitk::PlotDataCurveCollection* curveCollection, const QColor& sampleColor, const QColor& signalColor, const std::string& posString) { auto sampleCurve = mitk::ModelFitPlotData::GetSamplePlot(curveCollection); if (sampleCurve) { std::string name = mitk::MODEL_FIT_PLOT_SAMPLE_NAME() + posString; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, sampleCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Diamond, sampleColor, sampleColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } //draw model curve auto signalCurve = mitk::ModelFitPlotData::GetInterpolatedSignalPlot(curveCollection); if (signalCurve) { std::string name = mitk::MODEL_FIT_PLOT_SIGNAL_NAME() + posString; QPen pen; pen.setColor(signalColor); pen.setWidth(2); unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, signalCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, pen); // Manually set the legend attribute to use the symbol as the legend icon and alter its // size. Otherwise it would revert to default which is drawing a square which is the color // of the curve's pen, so in this case none which defaults to black. // Unfortunately, QmitkPlotWidget offers no way to set the legend attribute and icon size so // this looks a bit hacky. QwtPlotCurve* fitCurve = dynamic_cast(m_Controls.widgetPlot->GetPlot()-> itemList(QwtPlotItem::Rtti_PlotCurve).back()); fitCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine); } } void ModelFitInspectorView::RenderPlot() { m_Controls.widgetPlot->Clear(); std::string xAxis = DEFAULT_X_AXIS; std::string yAxis = "Intensity"; std::string plotTitle = "Raw data plot: no data"; if (m_currentSelectedNode.IsNotNull()) { plotTitle = "Raw data plot: " + m_currentSelectedNode->GetName(); } if (m_currentFit.IsNotNull()) { plotTitle = m_currentFit->modelName.c_str(); xAxis = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { xAxis += " [" + m_currentFit->xAxisUnit + "]"; } yAxis = m_currentFit->yAxisName; if (!m_currentFit->yAxisUnit.empty()) { yAxis += " [" + m_currentFit->yAxisUnit + "]"; } } m_Controls.widgetPlot->SetAxisTitle(QwtPlot::xBottom, xAxis.c_str()); m_Controls.widgetPlot->SetAxisTitle(QwtPlot::yLeft, yAxis.c_str()); m_Controls.widgetPlot->SetPlotTitle(plotTitle.c_str()); // Draw static curves unsigned int colorIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos) { QColor dataColor; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(pos->first.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, pos->second->GetValues()); if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); QPen pen; pen.setColor(dataColor); pen.setStyle(Qt::SolidLine); m_Controls.widgetPlot->SetCurvePen(curveId, pen); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing curves. dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); } // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Triangle, dataColor, dataColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } // Draw positional curves for (const auto& posIter : this->m_PlotCurves.positionalPlots) { QColor dataColor; dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); this->RenderPlotCurve(posIter.second.second, dataColor, dataColor, " @ "+mitk::ModelFitPlotData::GetPositionalCollectionName(posIter)); } // Draw current pos curve this->RenderPlotCurve(m_PlotCurves.currentPositionPlots, QColor(Qt::red), QColor(Qt::black), ""); QwtLegend* legend = new QwtLegend(); legend->setFrameShape(QFrame::Box); legend->setFrameShadow(QFrame::Sunken); legend->setLineWidth(1); m_Controls.widgetPlot->SetLegend(legend, QwtPlot::BottomLegend); m_Controls.widgetPlot->Replot(); } void ModelFitInspectorView::EnsureBookmarkPointSet() { if (m_PositionBookmarks.IsExpired() || m_PositionBookmarksNode.IsExpired()) { const char* nodeName = "org.mitk.gui.qt.fit.inspector.positions"; mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (!node) { node = mitk::DataNode::New(); node->SetName(nodeName); node->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(node); } m_PositionBookmarksNode = node; mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNull()) { pointSet = mitk::PointSet::New(); node->SetData(pointSet); } m_PositionBookmarks = pointSet; } } diff --git a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h index c0e49afda6..45287d9aaf 100644 --- a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h +++ b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h @@ -1,201 +1,202 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef ModelFitInspectorView_h #define ModelFitInspectorView_h // Blueberry //#include #include // mitk #include #include #include "QmitkSliceNavigationListener.h" #include "mitkModelFitStaticParameterMap.h" #include "mitkModelParameterizerBase.h" #include "mitkModelFitInfo.h" #include "mitkIModelFitProvider.h" #include "mitkModelFitPlotDataHelper.h" #include "QmitkSelectionServiceConnector.h" #include "QmitkFitParameterModel.h" // Qt #include "ui_ModelFitInspectorViewControls.h" /** * @brief View class defining the UI part of the ModelFitInspector plug-in. */ class ModelFitInspectorView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: ModelFitInspectorView(); ~ModelFitInspectorView() override; static const std::string VIEW_ID; protected slots: void OnSliceChanged(); /** * @brief Triggered when the selection of the "Modelfit" combo box changes. * Sets the selected fit as the current one. * @param index The index (in the combo box) of the selected item. */ void OnFitSelectionChanged(int index); void OnInputChanged(const QList& nodes); void OnPositionBookmarksChanged(); /** Triggered when the selection of "fixed" y axis scaling changes*/ void OnScaleFixedYChecked(bool checked); void OnScaleToDataYClicked(); void OnFixedScalingYChanged(double value); /** Triggered when the selection of "fixed" x axis scaling changes*/ void OnScaleFixedXChecked(bool checked); void OnScaleToDataXClicked(); void OnFixedScalingXChanged(double value); void OnFullPlotClicked(bool checked); protected: void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; void NodeRemoved(const mitk::DataNode* node) override; /** Helper that actualizes the fit selection widget and returns the index of the currently selected * fit.*/ int ActualizeFitSelectionWidget(); void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; /** * @brief Calculates the curve data using the current fit's model and parameterizer. * @param position Indicating the point in the input image for which the model curve should be calculated. * @return A vector of points for the curve data. */ QmitkPlotWidget::XYDataVector CalcCurveFromModel(const mitk::Point3D& position); /** * @brief Calculates the curve data using the current fit's function string. * @param timeGrid The time grid containing the (interpolated) x values for the curve data. * @return A vector of points for the curve data. */ QmitkPlotWidget::XYDataVector CalcCurveFromFunction(const mitk::Point3D& position, const mitk::ModelBase::TimeGridType& timeGrid); /** - * @brief Returns the parent node of the given node if it exists. - * @param node The node whose parent node should be returned. - * @return The parent node of the given node or NULL if it doesn't exist. + * @brief Returns the input node that was used to generate the passed model fit node if it exists. + * @param node Node that is a model fit result. + * @return The input node that was used to generate the passed node. If the input node cannot + * be found in the storage or the passed node is not a model fit result node, a nullptr will be returned. */ - mitk::DataNode::ConstPointer GetParentNode(mitk::DataNode::ConstPointer node); + mitk::DataNode::ConstPointer GetInputNode(mitk::DataNode::ConstPointer node); /** Sets m_currentSelectedPosition to the current selection and validates if this position is valid * for the input image of the currently selected fit. If it is valid, m_validSelectedPosition is set to true. * If the fit, his input image or geometry is not specified, it will also handled as invalid.*/ void ValidateAndSetCurrentPosition(); /** Returns the current input image. If a current fit is set it will be its input image. * Otherwise it will be the image stored in the currently selected node. If the node is not set, contains no image * or the image is not 4D, NULL will be returned.*/ mitk::Image::ConstPointer GetCurrentInputImage() const; /** Returns the variable/time grid of the GetCurrentInputImage(). If a model fit is selected its provider will be used to get the correct grid, otherwise just a simple time grid will be extracted.*/ const mitk::ModelBase::TimeGridType GetCurrentTimeGrid() const; Ui::ModelFitInspectorViewControls m_Controls; mitk::IRenderWindowPart* m_renderWindowPart; /** @brief Is a visualization currently running? */ bool m_internalUpdateFlag; /** @brief List of modelfits currently in the data manager */ typedef std::map ModelFitInfoListType; ModelFitInfoListType m_modelfitList; /** @brief The currently selected modelfit */ mitk::modelFit::ModelFitInfo::ConstPointer m_currentFit; /** @brief Pointer to the instance of the model parameterizer for the current fit */ mitk::ModelParameterizerBase::Pointer m_currentModelParameterizer; mitk::IModelFitProvider* m_currentModelProviderService; /** @brief currently valid selected position in the inspector*/ mitk::Point3D m_currentSelectedPosition; /** @brief indicates if the currently selected position is valid for the currently selected fit. * This it is within the input image */ bool m_validSelectedPosition; /** @brief currently selected time step of the selected node for the visualization logic*/ unsigned int m_currentSelectedTimeStep; /** @brief currently selected node for the visualization logic*/ mitk::DataNode::ConstPointer m_currentSelectedNode; mitk::WeakPointer m_PositionBookmarksNode; mitk::WeakPointer m_PositionBookmarks; /** @brief Number of interpolation steps between two x values */ static const unsigned int INTERPOLATION_STEPS; /*************************************/ /* Members for visualizing the model */ itk::TimeStamp m_selectedNodeTime; itk::TimeStamp m_currentFitTime; itk::TimeStamp m_currentPositionTime; itk::TimeStamp m_lastRefreshTime; mitk::ModelFitPlotData m_PlotCurves; std::unique_ptr m_SelectionServiceConnector; QmitkFitParameterModel* m_FitParameterModel; QmitkSliceNavigationListener m_SliceChangeListener; /** Check and updates the plot data if needed. * @return indicates if something was refreshed (true)*/ bool RefreshPlotData(); void RenderPlot(); void RenderPlotCurve(const mitk::PlotDataCurveCollection* curveCollection, const QColor& sampleColor, const QColor& signalColor, const std::string& posString); void RenderFitInfo(); void EnsureBookmarkPointSet(); static mitk::PlotDataCurveCollection::Pointer RefreshPlotDataCurveCollection(const mitk::Point3D& position, const mitk::Image* input, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer); }; #endif // ModelFitInspectorView_h