14#include "ui_QmitkUSNavigationStepPlacementPlanning.h"
20#include "usModuleRegistry.h"
27#include "mitkLookupTableProperty.h"
28#include "mitkSurface.h"
29#include <mitkBaseGeometry.h>
31#include "mitkLayoutAnnotationRenderer.h"
32#include "mitkTextAnnotation3D.h"
34#include "vtkFloatArray.h"
35#include "vtkLookupTable.h"
36#include "vtkPointData.h"
37#include "vtkPolyData.h"
38#include "vtkSmartPointer.h"
40#include "vtkLineSource.h"
41#include <vtkSphereSource.h>
43#include "vtkCenterOfMass.h"
44#include "vtkLinearTransform.h"
46#include "vtkTransformPolyDataFilter.h"
47#include "vtkUnstructuredGrid.h"
54 m_CurrentTargetIndex(0),
55 m_BodyMarkerValid(false),
56 m_PointMarkInteractor(
mitk::USPointMarkInteractor::New()),
57 m_TargetUpdateFilter(
mitk::USNavigationTargetUpdateFilter::New()),
58 m_NodeDisplacementFilter(
mitk::NodeDisplacementFilter::New()),
59 m_NeedleProjectionFilter(
mitk::NeedleProjectionFilter::New()),
60 m_TargetIntersectionFilter(
mitk::USNavigationTargetIntersectionFilter::New()),
61 m_PlacementQualityCalculator(
mitk::USTargetPlacementQualityCalculator::New()),
62 m_ReferenceSensorIndex(1),
63 m_NeedleSensorIndex(0),
69 connect(ui->freezeImageButton, SIGNAL(SignalFreezed(
bool)),
this, SLOT(
OnFreeze(
bool)));
84 mitk::DataNode::Pointer node =
87 node->SetBoolProperty(
"show contour",
true);
116 dataStorage->Remove(*it);
125 dataStorage->Remove(*it);
132 if (targetsNode.IsNotNull())
134 dataStorage->Remove(targetsNode);
140 if (targetPathsNode.IsNotNull())
142 dataStorage->Remove(targetPathsNode);
146 ui->freezeImageButton->Unfreeze();
164 mitk::USNavigationTargetUpdateFilter::Pointer planningSurfaceFilter = mitk::USNavigationTargetUpdateFilter::New();
165 planningSurfaceFilter->SetOptimalAngle(0);
166 planningSurfaceFilter->SetScalarArrayIdentifier(
"USNavigation::PlanningScalars");
167 planningSurfaceFilter->SetUseMaximumScore(
true);
168 planningSurfaceFilter->SetTargetStructure(
m_TargetNode);
176 if (((*it)->GetBoolProperty(
"surface_empty", isSurfaceEmpty)) && isSurfaceEmpty)
185 planningSurfaceFilter->SetControlNode(n, *it);
193 ui->freezeImageButton->Unfreeze();
227 (*it)->SetBoolProperty(
"visible",
true);
239 ui->freezeImageButton->Unfreeze();
249 mitk::NavigationDataSource::Pointer navigationDataSource = this->
GetCombinedModality()->GetNavigationDataSource();
250 if (navigationDataSource.IsNull())
252 MITK_ERROR(
"QmitkUSAbstractNavigationStep")
253 (
"QmitkUSNavigationStepPunctuationIntervention") <<
"Navigation Data Source of Combined Modality must not be null.";
254 mitkThrow() <<
"Navigation Data Source of Combined Modality must not be null.";
257 navigationDataSource->Update();
263 if (needleProjectionPointSet->GetSize() == 2)
272 ui->placeTargetButton->setToolTip(
"");
276 mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New();
278 mitk::PointSet::PointIdentifier n = 0;
283 targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin());
292 ui->placeTargetButton->setEnabled(
false);
293 ui->placeTargetButton->setToolTip(
294 "Target cannot be placed as the needle path is not intersecting the target surface.");
300 ui->angleDifferenceValue->setText(
"");
301 ui->centersOfMassValue->setText(
"");
310 if (settingsNode->GetIntProperty(
"settings.number-of-targets", numberOfTargets))
318 std::string referenceSensorName;
319 if (settingsNode->GetStringProperty(
"settings.reference-name-selected", referenceSensorName))
324 std::string needleSensorName;
325 if (settingsNode->GetStringProperty(
"settings.needle-name-selected", needleSensorName))
335 return "Placement Planning";
348 mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->
GetCombinedModality(
false);
349 if (combinedModality.IsNotNull())
351 mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration();
352 if (calibration.IsNotNull())
370 m_PointMarkInteractor->LoadStateMachine(
"USPointMarkInteractions.xml", us::ModuleRegistry::GetModule(
"MitkUS"));
393 currentNode->SetBoolProperty(
"surface_empty",
false);
402 currentNode->GetData()->GetGeometry()->SetOrigin(intersectionPoint);
405 mitk::PointSet::Pointer plannedPath = mitk::PointSet::New();
407 plannedPath->SetPoint(0, needleProjection->GetPoint(0));
408 plannedPath->SetPoint(1, intersectionPoint);
421 MITK_INFO(
"QmitkUSAbstractNavigationStep")
422 (
"QmitkUSNavigationStepPlacementPlanning") <<
"Target " <<
m_CurrentTargetIndex + 1 <<
" planned at position "
423 << intersectionPoint <<
".";
430 mitkThrow() <<
"Cannot go to previous target as current target is first target.";
449 MITK_WARN <<
"Cannot remove current target as there aren't as much planned target nodes.";
463 QString(
"Target %1").arg(n + 1,
m_NumberOfTargets / 10 + 1, 10, QLatin1Char(
'0')).toStdString());
466 QString(
"Target Path %1").arg(n + 1,
m_NumberOfTargets / 10 + 1, 10, QLatin1Char(
'0')).toStdString());
475 MITK_INFO(
"QmitkUSAbstractNavigationStep")
476 (
"QmitkUSNavigationStepPlacementPlanning") <<
"Planned target " <<
m_CurrentTargetIndex + 1 <<
" removed.";
485 QString targetNumber =
490 targetNode->SetOpacity(0.5);
491 targetNode->SetBoolProperty(
"surface_empty",
true);
492 targetNode->SetData(mitk::Surface::New());
496 mitk::DataNode::Pointer targetPathNode =
499 targetPathNode->SetOpacity(0.5);
500 targetPathNode->SetColor(1, 1, 1);
501 targetPathNode->SetColor(1, 1, 1,
nullptr,
"contourcolor");
502 targetPathNode->SetBoolProperty(
"show contour",
true);
505 mitk::Surface::Pointer pathSurface = mitk::Surface::New();
506 targetPathNode->SetData(pathSurface);
513 if (dataNode->GetBoolProperty(
"surface_empty", surfaceEmpty) && surfaceEmpty)
515 mitk::Point3D origin = dataNode->GetData()->GetGeometry()->GetOrigin();
517 dataNode->SetBoolProperty(
"surface_empty",
false);
518 dataNode->GetData()->GetGeometry()->SetOrigin(origin);
523 mitk::BaseData *baseData = dataNode->GetData();
526 mitkThrow() <<
"Data of the data node must not be null.";
529 mitk::BaseGeometry::Pointer geometry = baseData->GetGeometry();
530 if (geometry.IsNull())
532 mitkThrow() <<
"Geometry of the data node must not be null.";
537 MITK_INFO(
"QmitkUSAbstractNavigationStep")
538 (
"QmitkUSNavigationStepPlacementPlanning") <<
"Target " <<
m_CurrentTargetIndex + 1 <<
" planned at position "
539 << geometry->GetOrigin() <<
".";
541 if (ui->freezeImageButton->isChecked())
543 ui->freezeImageButton->Unfreeze();
563 mitk::BaseData *targetNodeData =
m_TargetNode->GetData();
564 if (targetNodeData ==
nullptr)
569 mitk::Surface::Pointer targetNodeSurface =
dynamic_cast<mitk::Surface *
>(targetNodeData);
572 vtkFloatArray *targetScoreScalars =
dynamic_cast<vtkFloatArray *
>(
573 targetNodeSurface->GetVtkPolyData()->GetPointData()->GetScalars(
"USNavigation::PlanningPlacement"));
575 if (!targetScoreScalars)
580 unsigned int numberOfTupels = targetScoreScalars->GetNumberOfTuples();
583 colors->SetNumberOfComponents(1);
584 colors->SetNumberOfTuples(numberOfTupels);
585 colors->SetName(
"Colors");
589 for (
unsigned int n = 0; n < numberOfTupels; n++)
591 targetScoreScalars->GetTuple(n, &markerScore);
592 colors->SetTuple(n, &markerScore);
595 if (numberOfTupels > 0)
597 targetNodeSurfaceVtk->GetPointData()->SetScalars(colors);
598 targetNodeSurfaceVtk->GetPointData()->Update();
608 ui->currentTargetLabel->setText(
619 lookupTable->SetHueRange(0.0, 0.27);
620 lookupTable->SetSaturationRange(1.0, 1.0);
621 lookupTable->SetValueRange(1.0, 1.0);
622 lookupTable->SetTableRange(0.0, 1.0);
623 lookupTable->Build();
625 mitk::LookupTable::Pointer lut = mitk::LookupTable::New();
626 lut->SetVtkLookupTable(lookupTable);
638 if (it->IsNotNull() && (*it)->GetData() !=
nullptr)
647 if (it->IsNotNull() && (*it)->GetData() !=
nullptr)
658 ui->angleDifferenceLabel->setEnabled(
false);
659 ui->centersOfMassLabel->setEnabled(
false);
660 ui->allTargetsPlannedLabel->setEnabled(
false);
661 ui->angleDifferenceValue->setText(
"");
662 ui->centersOfMassValue->setText(
"");
666 ui->angleDifferenceLabel->setEnabled(
true);
667 ui->centersOfMassLabel->setEnabled(
true);
668 ui->allTargetsPlannedLabel->setEnabled(
true);
670 mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New();
672 mitk::PointSet::PointIdentifier n = 0;
677 targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin());
680 mitk::DataNode::Pointer planningQualityResult =
686 mitk::Surface::Pointer targetSurface, mitk::PointSet::Pointer targetPoints)
688 if (targetSurface.IsNull())
690 mitkThrow() <<
"Target surface must not be null.";
697 mitk::DataNode::Pointer planningQualityResult = mitk::DataNode::New();
698 planningQualityResult->SetName(
"PlanningQuality");
701 ui->centersOfMassValue->setText(QString::number(centersOfMassDistance, 103, 2) +
" mm");
702 planningQualityResult->SetFloatProperty(
"USNavigation::CentersOfMassDistance", centersOfMassDistance);
707 ui->angleDifferenceValue->setText(QString::number(meanAnglesDifference, 103, 2) + QString::fromLatin1(
" °"));
709 planningQualityResult->SetFloatProperty(
"USNavigation::MeanAngleDifference", meanAnglesDifference);
710 planningQualityResult->SetProperty(
711 "USNavigation::AngleDifferences",
716 ui->angleDifferenceValue->setText(
"not valid for one point");
719 return planningQualityResult;
724 mitk::Surface::Pointer surface = mitk::Surface::New();
728 vtkSphere->SetRadius(5);
729 vtkSphere->SetCenter(0, 0, 0);
731 surface->SetVtkPolyData(vtkSphere->GetOutput());
738 if (bodyMarker.IsNull())
740 MITK_ERROR(
"QmitkUSAbstractNavigationStep")
741 (
"QmitkUSNavigationStepPunctuationIntervention")
742 <<
"Current Navigation Data for body marker of Combined Modality must not be null.";
743 mitkThrow() <<
"Current Navigation Data for body marker of Combined Modality must not be null.";
751 ui->bodyMarkerTrackingStatusLabel->setStyleSheet(
752 "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey");
753 ui->bodyMarkerTrackingStatusLabel->setText(
"Body marker is inside the tracking volume.");
757 ui->bodyMarkerTrackingStatusLabel->setStyleSheet(
758 "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey");
759 ui->bodyMarkerTrackingStatusLabel->setText(
"Body marker is not inside the tracking volume.");
765 mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->
GetCombinedModality(
false);
766 if (combinedModality.IsNull())
771 mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource();
772 if (navigationDataSource.IsNull())
783 catch (
const std::exception &e)
785 MITK_WARN(
"QmitkUSAbstractNavigationStep")
786 (
"QmitkUSNavigationStepPlacementPlanning") <<
"Cannot get index for needle sensor name: " << e.what();
800 catch (
const std::exception &e)
802 MITK_WARN(
"QmitkUSAbstractNavigationStep")
803 (
"QmitkUSNavigationStepPlacementPlanning") <<
"Cannot get index for reference sensor name: " << e.what();
Abstract base class for navigation step widgets.
itk::SmartPointer< mitk::DataStorage > GetDataStorage(bool throwNull=true)
Returns the data storage set for the navigation step.
NavigationStepState GetNavigationStepState()
Get the current state of the navigation step.
void SignalReadyForNextStep()
Signals that all necessary actions where done. The user can proceed with the next stept after this wa...
static const char * DATANAME_BASENODE
itk::SmartPointer< mitk::DataNode > GetNamedDerivedNodeAndCreate(const char *name, const char *sourceName)
Returns node with the given name and the given source node (parent) from the data storage....
itk::SmartPointer< mitk::AbstractUltrasoundTrackerDevice > GetCombinedModality(bool throwNull=true)
Returns the combined modality set for the navigation step.
std::vector< itk::SmartPointer< mitk::NavigationDataToNavigationDataFilter > > FilterVector
void SignalIntermediateResult(const itk::SmartPointer< mitk::DataNode >)
Signals that an intermediate result was produced. The properties of the given data node must contain ...
itk::SmartPointer< mitk::DataNode > GetNamedDerivedNode(const char *name, const char *sourceName)
Returns node with the given name and the given source node (parent) from the data storage.
static const char * DATANAME_TUMOUR
static const char * DATANAME_TARGETSURFACE
static const char * DATANAME_TARGETS_PATHS
static const char * DATANAME_TARGETS
Navigation step for planning the positions for implanting markers.
bool OnRestartStep() override
Called when restarting a navigation step. This method may be implemented by a concrete subclass to ha...
void OnSetCombinedModality() override
Called every time SetCombinedModality() was called. This method may be implemented by a concrete subc...
void OnFreeze(bool freezed)
Freezes or unfreezes the combined modality. In freeze state an interactor is activated in the render ...
void OnUpdate() override
Called periodically while a navigation step is active. This method has to be implemented by a concret...
void OnRemoveCurrentTargetClicked()
The currently active target is removed from the data storage.
FilterVector GetFilter() override
Getter for navigation data filters of the navigation step. This method may be implemented by a concre...
bool OnStartStep() override
Called when the navigation step gets started. This method has to be implemented by a concrete subclas...
bool OnActivateStep() override
Called when the navigation step gets activated. This method has to be implemented by a concrete subcl...
std::string m_ReferenceSensorName
itk::SmartPointer< mitk::USTargetPlacementQualityCalculator > m_PlacementQualityCalculator
itk::SmartPointer< mitk::USNavigationTargetUpdateFilter > m_TargetUpdateFilter
bool OnFinishStep() override
Called when all necessary actions for the step where done. This method has to be implemented by a con...
void OnPlaceTargetButtonClicked()
Plan target position at the intersection between needle path and target surface.
itk::SmartPointer< mitk::LookupTableProperty > m_TargetColorLookupTableProperty
void OnGoToPreviousTarget()
Selects the previous target as active target.
itk::SmartPointer< mitk::USPointMarkInteractor > m_PointMarkInteractor
void UpdateTargetCoordinates(mitk::DataNode *)
void OnSettingsChanged(const itk::SmartPointer< mitk::DataNode > settingsNode) override
Called every time the settings for the navigation process where changed. This method may be implement...
bool OnDeactivateStep() override
Called when the navigation step gets deactivated (-> state started). This method may be implemented b...
itk::SmartPointer< mitk::NodeDisplacementFilter > m_NodeDisplacementFilter
QVector< itk::SmartPointer< mitk::DataNode > > m_PlannedNeedlePaths
itk::SmartPointer< mitk::Surface > CreateSphere(float radius)
void UpdateTargetColors()
std::string m_NeedleSensorName
QString GetTitle() override
Getter for the title of the navigation step. This title should be human readable and can be used to d...
void ReinitNodeDisplacementFilter()
unsigned int m_ReferenceSensorIndex
QmitkUSNavigationStepPlacementPlanning(QWidget *parent=nullptr)
void CreateTargetNodesIfNecessary()
bool OnStopStep() override
Callen when the navigation step gets stopped. This method may be implemented by a concrete subclass t...
void UpdateTargetDescriptions()
~QmitkUSNavigationStepPlacementPlanning() override
itk::SmartPointer< mitk::NeedleProjectionFilter > m_NeedleProjectionFilter
unsigned int m_NeedleSensorIndex
void CalculatePlanningQuality()
itk::SmartPointer< mitk::DataNode > m_TargetNode
itk::SmartPointer< mitk::USNavigationTargetIntersectionFilter > m_TargetIntersectionFilter
QVector< itk::SmartPointer< mitk::DataNode > > m_PlannedTargetNodes
void UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker)
void GenerateTargetColorLookupTable()
void OnGoToNextTarget()
Selects the next target as active target.
void UpdateSensorsNames()