14#include "ui_QmitkUSNavigationStepMarkerIntervention.h"
16#include "mitkBaseRenderer.h"
17#include "mitkContourModel.h"
20#include "mitkSurface.h"
21#include "mitkTextAnnotation2D.h"
22#include <mitkBaseGeometry.h>
23#include <mitkManualPlacementAnnotationRenderer.h>
34#include "usModuleRegistry.h"
36#include "mitkLookupTable.h"
37#include "mitkLookupTableProperty.h"
39#include "mitkSurface.h"
42#include "vtkCellLocator.h"
43#include "vtkDataSet.h"
44#include "vtkDoubleArray.h"
45#include "vtkFloatArray.h"
47#include "vtkLinearTransform.h"
48#include "vtkLookupTable.h"
50#include "vtkOBBTree.h"
51#include "vtkPointData.h"
52#include "vtkPointData.h"
53#include "vtkPolyData.h"
54#include "vtkSelectEnclosedPoints.h"
55#include "vtkSmartPointer.h"
56#include <vtkSphereSource.h>
57#include "vtkTransformPolyDataFilter.h"
58#include "vtkWarpScalar.h"
64 m_PlannedTargetsNodes(),
65 m_ReachedTargetsNodes(),
66 m_TargetProgressBar(new
QmitkZoneProgressBar(QString::fromStdString(
"Target: %1 mm"), 200, 0, this)),
67 m_PlannedTargetProgressBar(nullptr),
68 m_CurrentTargetIndex(0),
69 m_CurrentTargetReached(false),
70 m_ShowPlanningColors(false),
71 m_PointMarkInteractor(
mitk::USPointMarkInteractor::New()),
72 m_TargetNode(nullptr),
73 m_TargetColorLookupTableProperty(nullptr),
74 m_TargetSurface(nullptr),
75 m_NeedleProjectionFilter(
mitk::NeedleProjectionFilter::New()),
76 m_NodeDisplacementFilter(
mitk::NodeDisplacementFilter::New()),
77 m_TargetUpdateFilter(
mitk::USNavigationTargetUpdateFilter::New()),
78 m_TargetOcclusionFilter(
mitk::USNavigationTargetOcclusionFilter::New()),
79 m_TargetIntersectionFilter(
mitk::USNavigationTargetIntersectionFilter::New()),
80 m_PlacementQualityCalculator(
mitk::USTargetPlacementQualityCalculator::New()),
81 m_TargetStructureWarnOverlay(
mitk::TextAnnotation2D::New()),
82 m_ReferenceSensorName(),
84 m_ReferenceSensorIndex(1),
85 m_NeedleSensorIndex(0),
101 connect(ui->freezeImageButton, SIGNAL(SignalFreezed(
bool)),
this, SLOT(
OnFreeze(
bool)));
103 connect(ui->targetReachedButton, SIGNAL(clicked()),
this, SLOT(
OnTargetLeft()));
106 connect(ui->riskStructuresRangeWidget,
107 SIGNAL(SignalZoneViolated(
const mitk::DataNode *, mitk::Point3D)),
123 mitk::DataStorage::Pointer dataStorage = this->
GetDataStorage(
false);
124 if (dataStorage.IsNotNull())
127 mitk::DataNode::Pointer node =
129 if (node.IsNotNull())
131 dataStorage->Remove(node);
145 mitk::DataNode::Pointer node =
148 node->SetBoolProperty(
"show contour",
true);
155 mitk::Point2D overlayPosition;
156 overlayPosition.SetElement(0, 10.0f);
157 overlayPosition.SetElement(1, 10.0f);
168 auto allRenderWindows = mitk::BaseRenderer::GetAll3DRenderWindows();
169 for (
auto mapit = allRenderWindows.begin(); mapit != allRenderWindows.end(); ++mapit)
186 dataStorage->Remove(*it);
192 ui->freezeImageButton->setEnabled(
false);
193 ui->backToLastTargetButton->setEnabled(
false);
194 ui->targetReachedButton->setEnabled(
true);
197 ui->freezeImageButton->Unfreeze();
202 if (reachedTargetsNode.IsNotNull())
204 dataStorage->Remove(reachedTargetsNode);
232 <<
") data must be of type mitk::Surface";
249 if (tumourNode.IsNotNull())
252 tumourNode->SetBoolProperty(
"visible",
false);
255 ui->riskStructuresRangeWidget->AddZone(tumourNode);
268 mitk::DataStorage::SetOfObjects::ConstPointer plannedTargetNodes;
269 if (targetsBaseNode.IsNotNull())
271 plannedTargetNodes = this->
GetDataStorage()->GetDerivations(targetsBaseNode);
273 if (plannedTargetNodes.IsNotNull() && plannedTargetNodes->Size() > 0)
275 for (mitk::DataStorage::SetOfObjects::ConstIterator it = plannedTargetNodes->Begin();
276 it != plannedTargetNodes->End();
290 if (zonesBaseNode.IsNotNull())
292 mitk::DataStorage::SetOfObjects::ConstPointer zoneNodes = this->
GetDataStorage()->GetDerivations(zonesBaseNode);
294 for (mitk::DataStorage::SetOfObjects::ConstIterator it = zoneNodes->Begin(); it != zoneNodes->End(); ++it)
296 ui->riskStructuresRangeWidget->AddZone(it->Value());
308 ui->freezeImageButton->Unfreeze();
316 mitk::NavigationDataSource::Pointer navigationDataSource = this->
GetCombinedModality()->GetNavigationDataSource();
317 if (navigationDataSource.IsNull())
319 MITK_ERROR(
"QmitkUSAbstractNavigationStep")
320 (
"QmitkUSNavigationStepMarkerIntervention") <<
"Navigation Data Source of Combined Modality must not be null.";
321 mitkThrow() <<
"Navigation Data Source of Combined Modality must not be null.";
324 ui->riskStructuresRangeWidget->UpdateDistancesToNeedlePosition(navigationDataSource->GetOutput(
m_NeedleSensorIndex));
335 if (settingsNode.IsNull())
341 if (settingsNode->GetIntProperty(
"settings.number-of-targets", numberOfTargets))
349 std::string referenceSensorName;
350 if (settingsNode->GetStringProperty(
"settings.reference-name-selected", referenceSensorName))
355 std::string needleSensorName;
356 if (settingsNode->GetStringProperty(
"settings.needle-name-selected", needleSensorName))
366 return "Computer-assisted Intervention";
385 mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->
GetCombinedModality(
false);
386 if (combinedModality.IsNotNull())
388 mitk::AffineTransform3D::Pointer calibration = combinedModality->GetCalibration();
389 if (calibration.IsNotNull())
413 ui->targetReachedButton->setDisabled(
true);
416 ui->backToLastTargetButton->setEnabled(
true);
417 ui->freezeImageButton->setEnabled(
true);
423 mitk::DataNode::Pointer node = mitk::DataNode::New();
425 (QString(
"Target ") + QString(
"%1").arg(
m_CurrentTargetIndex, 2, 10, QLatin1Char(
'0'))).toStdString());
434 mitk::Surface::Pointer zone = mitk::Surface::New();
438 vtkSphere->SetRadius(5);
439 vtkSphere->SetCenter(0, 0, 0);
441 zone->SetVtkPolyData(vtkSphere->GetOutput());
445 node->GetData()->GetGeometry()->SetOrigin(
447 node->SetColor(0.2, 0.9, 0.2);
455 MITK_WARN <<
"Cannot go back to last target as there is no last target.";
464 MITK_INFO(
"QmitkUSAbstractNavigationStep")
471 ui->backToLastTargetButton->setDisabled(
true);
475 ui->targetReachedButton->setEnabled(
true);
478 ui->freezeImageButton->setEnabled(
false);
479 ui->freezeImageButton->Unfreeze();
492 m_PointMarkInteractor->LoadStateMachine(
"USPointMarkInteractions.xml", us::ModuleRegistry::GetModule(
"MitkUS"));
497 mitkThrow() <<
"Current target index has to be greater zero when freeze button is clicked.";
502 mitk::DataNode::Pointer node = mitk::DataNode::New();
504 (QString(
"Target ") + QString(
"%1").arg(
m_CurrentTargetIndex, 2, 10, QLatin1Char(
'0'))).toStdString());
528 MITK_INFO <<
"Risk zone (" << node->GetName() <<
") violated at position " << position <<
".";
533 ui->riskStructuresRangeWidget->ClearZones();
542 dataStorage->Remove(*it);
555 if (it->IsNotNull() && (*it)->GetData() !=
nullptr)
561 mitk::BaseData *baseData = dataNode->GetData();
564 mitkThrow() <<
"Data of the data node must not be null.";
567 mitk::BaseGeometry::Pointer geometry = baseData->GetGeometry();
568 if (geometry.IsNull())
570 mitkThrow() <<
"Geometry of the data node must not be null.";
580 MITK_INFO(
"QmitkUSAbstractNavigationStep")
581 (
"QmitkUSNavigationStepMarkerIntervention") <<
"Target " <<
m_CurrentTargetIndex <<
" reached at position "
582 << geometry->GetOrigin();
589 if (bodyMarker.IsNull())
591 MITK_ERROR(
"QmitkUSAbstractNavigationStep")
592 (
"QmitkUSNavigationStepMarkerIntervention")
593 <<
"Current Navigation Data for body marker of Combined Modality must not be null.";
594 mitkThrow() <<
"Current Navigation Data for body marker of Combined Modality must not be null.";
597 bool valid = bodyMarker->IsDataValid();
602 ui->bodyMarkerTrackingStatusLabel->setStyleSheet(
603 "background-color: #8bff8b; margin-right: 1em; margin-left: 1em; border: 1px solid grey");
604 ui->bodyMarkerTrackingStatusLabel->setText(
"Body marker is inside the tracking volume.");
608 ui->bodyMarkerTrackingStatusLabel->setStyleSheet(
609 "background-color: #ff7878; margin-right: 1em; margin-left: 1em; border: 1px solid grey");
610 ui->bodyMarkerTrackingStatusLabel->setText(
"Body marker is not inside the tracking volume.");
613 ui->targetStructuresRangeGroupBox->setEnabled(valid);
614 ui->riskStructuresRangeGroupBox->setEnabled(valid);
620 lookupTable->SetHueRange(0.0, 0.33);
621 lookupTable->SetSaturationRange(1.0, 1.0);
622 lookupTable->SetValueRange(1.0, 1.0);
623 lookupTable->SetTableRange(0.0, 1.0);
624 lookupTable->Build();
626 mitk::LookupTable::Pointer lut = mitk::LookupTable::New();
627 lut->SetVtkLookupTable(lookupTable);
641 mitk::BaseData *targetNodeData =
m_TargetNode->GetData();
642 if (targetNodeData ==
nullptr)
647 mitk::Surface::Pointer targetNodeSurface =
dynamic_cast<mitk::Surface *
>(targetNodeData);
650 vtkPointData *targetPointData = targetNodeSurface->GetVtkPolyData()->GetPointData();
652 vtkFloatArray *scalars =
dynamic_cast<vtkFloatArray *
>(targetPointData->GetScalars(
"USNavigation::Occlusion"));
653 vtkFloatArray *targetScoreScalars;
657 targetScoreScalars =
dynamic_cast<vtkFloatArray *
>(targetPointData->GetScalars(
"USNavigation::PlanningScalars"));
662 dynamic_cast<vtkFloatArray *
>(targetPointData->GetScalars(
"USNavigation::ReachedTargetScores"));
665 if (!scalars || !targetScoreScalars)
670 unsigned int numberOfTupels = scalars->GetNumberOfTuples();
673 colors->SetNumberOfComponents(1);
674 colors->SetNumberOfTuples(numberOfTupels);
675 colors->SetName(
"Colors");
677 double color, intersection, markerScore;
679 for (
unsigned int n = 0; n < numberOfTupels; n++)
681 scalars->GetTuple(n, &intersection);
682 targetScoreScalars->GetTuple(n, &markerScore);
684 if (intersection > 0)
693 colors->SetTuple(n, &color);
696 if (numberOfTupels > 0)
698 targetNodeSurfaceVtk->GetPointData()->SetScalars(colors);
699 targetNodeSurfaceVtk->GetPointData()->Update();
719 vtkFloatArray *scalars =
720 dynamic_cast<vtkFloatArray *
>(targetSurfaceVtk->GetPointData()->GetScalars(
"USNavigation::ReachedTargetScores"));
728 colorF[0] = color[0];
729 colorF[1] = color[1];
730 colorF[2] = color[2];
737 vtkFloatArray *scalars =
738 dynamic_cast<vtkFloatArray *
>(targetSurfaceVtk->GetPointData()->GetScalars(
"USNavigation::PlanningScalars"));
748 colorF[0] = color[0];
749 colorF[1] = color[1];
750 colorF[2] = color[2];
757 mitk::ScalarType minDistance = -1;
762 mitk::ScalarType distance =
763 intersectionPoint.EuclideanDistanceTo((*it)->GetData()->GetGeometry()->GetOrigin());
764 if (minDistance < 0 || distance < minDistance)
766 minDistance = distance;
785 description =
"All Targets Reached";
793 description = QString(
"Distance to Target ") + QString::number(
m_CurrentTargetIndex + 1) + QString(
" of ") +
801 ui->targetStructuresRangeGroupBox->setTitle(description);
823 vtkFloatArray *scalars =
dynamic_cast<vtkFloatArray *
>(targetSurfaceVtk->GetPointData()->GetScalars(
"Colors"));
831 colorF[0] = color[0];
832 colorF[1] = color[1];
833 colorF[2] = color[2];
840 float red[3] = {0.6f, 0.0f, 0.0f};
851 transformFilter->SetTransform(
m_TargetSurface->GetGeometry()->GetVtkTransform());
852 transformFilter->Update();
855 enclosedPoints->Initialize(transformFilter->GetOutput());
860 if (enclosedPoints->IsInsideSurface(needleTip[0], needleTip[1], needleTip[2]))
866 mitk::DataNode::Pointer targetViolationResult = mitk::DataNode::New();
867 targetViolationResult->SetName(
"TargetViolation");
868 targetViolationResult->SetProperty(
"USNavigation::TargetViolationPoint", mitk::Point3dProperty::New(needleTip));
873 MITK_INFO(
"QmitkUSAbstractNavigationStep")
874 (
"QmitkUSNavigationStepMarkerIntervention") <<
"Target surface violated at " << needleTip <<
".";
887 ui->placementQualityGroupBox->setEnabled(
false);
888 ui->angleDifferenceValue->setText(
"");
889 ui->centersOfMassValue->setText(
"");
893 ui->placementQualityGroupBox->setEnabled(
true);
895 mitk::Surface::Pointer targetSurface =
dynamic_cast<mitk::Surface *
>(
m_TargetNode->GetData());
896 if (targetSurface.IsNull())
898 mitkThrow() <<
"Target surface must not be null.";
902 mitk::PointSet::Pointer targetPointSet = mitk::PointSet::New();
906 mitk::PointSet::PointIdentifier n = 0;
911 targetPointSet->InsertPoint(n++, (*it)->GetData()->GetGeometry()->GetOrigin());
918 ui->centersOfMassValue->setText(QString::number(centersOfMassDistance, 103, 2) +
" mm");
921 ui->angleDifferenceValue->setText(QString::number(meanAnglesDifference, 103, 2) + QString::fromLatin1(
" °"));
924 mitk::DataNode::Pointer placementQualityResult = mitk::DataNode::New();
925 placementQualityResult->SetName(
"PlacementQuality");
926 placementQualityResult->SetFloatProperty(
"USNavigation::CentersOfMassDistance", centersOfMassDistance);
927 placementQualityResult->SetFloatProperty(
"USNavigation::MeanAngleDifference", meanAnglesDifference);
928 placementQualityResult->SetProperty(
929 "USNavigation::AngleDifferences",
934 mitk::VnlVector reachedPlannedDifferences;
935 double reachedPlannedDifferencesSum = 0;
936 double reachedPlannedDifferencesMax = 0;
942 mitk::ScalarType distance =
946 reachedPlannedDifferences.put(n, distance);
947 reachedPlannedDifferencesSum += distance;
949 if (distance > reachedPlannedDifferencesMax)
951 reachedPlannedDifferencesMax = distance;
956 placementQualityResult->SetProperty(
"USNavigation::PlanningRealityDistances",
957 mitk::GenericProperty<mitk::VnlVector>::New(reachedPlannedDifferences));
958 placementQualityResult->SetProperty(
959 "USNavigation::MeanPlanningRealityDistance",
960 mitk::DoubleProperty::New(reachedPlannedDifferencesSum /
static_cast<double>(
m_NumberOfTargets)));
961 placementQualityResult->SetProperty(
"USNavigation::MaximumPlanningRealityDistance",
962 mitk::DoubleProperty::New(reachedPlannedDifferencesMax));
970 mitk::AbstractUltrasoundTrackerDevice::Pointer combinedModality = this->
GetCombinedModality(
false);
971 if (combinedModality.IsNull())
976 mitk::NavigationDataSource::Pointer navigationDataSource = combinedModality->GetNavigationDataSource();
977 if (navigationDataSource.IsNull())
988 catch (
const std::exception &e)
990 MITK_WARN(
"QmitkUSAbstractNavigationStep")
991 (
"QmitkUSNavigationStepPlacementPlanning") <<
"Cannot get index for needle sensor name: " << e.what();
1005 catch (
const std::exception &e)
1007 MITK_WARN(
"QmitkUSAbstractNavigationStep")
1008 (
"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.
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_REACHED_TARGETS
static const char * DATANAME_ZONES
static const char * DATANAME_TARGETS
Navigation step for the actual marker placement.
mitk::ScalarType m_InactiveTargetColor[3]
~QmitkUSNavigationStepMarkerIntervention() override
itk::SmartPointer< mitk::USPointMarkInteractor > m_PointMarkInteractor
QmitkZoneProgressBar * m_PlannedTargetProgressBar
mitk::ScalarType m_ActiveTargetColor[3]
bool OnStopStep() override
Callen when the navigation step gets stopped. This method may be implemented by a concrete subclass t...
void UpdateBodyMarkerStatus(mitk::NavigationData::Pointer bodyMarker)
QVector< itk::SmartPointer< mitk::DataNode > > m_ReachedTargetsNodes
itk::SmartPointer< mitk::NeedleProjectionFilter > m_NeedleProjectionFilter
bool OnActivateStep() override
Called when the navigation step gets activated. This method has to be implemented by a concrete subcl...
itk::SmartPointer< mitk::USNavigationTargetUpdateFilter > m_TargetUpdateFilter
void OnShowPlanningView(bool)
void OnRiskZoneViolated(const mitk::DataNode *, mitk::Point3D)
itk::SmartPointer< mitk::LookupTableProperty > m_TargetColorLookupTableProperty
void UpdateTargetProgressDisplay()
Updates display showing the number of the currently active target.
void OnUpdate() override
Called periodically while a navigation step is active. This method has to be implemented by a concret...
QmitkUSNavigationStepMarkerIntervention(QWidget *parent=nullptr)
void OnBackToLastTargetClicked()
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...
void OnSetCombinedModality() override
Called every time SetCombinedModality() was called. This method may be implemented by a concrete subc...
void UpdateTargetViolationStatus()
Tests for target violation and updates the display accordingly. This method tests if the needle tip i...
mitk::ScalarType m_ReachedTargetColor[3]
void UpdateTargetCoordinates(mitk::DataNode *)
void CalculateTargetPlacementQuality()
Calculates and display quality metrics if all three markers are placed.
itk::SmartPointer< mitk::NodeDisplacementFilter > m_NodeDisplacementFilter
bool m_ShowPlanningColors
std::string m_NeedleSensorName
itk::SmartPointer< mitk::TextAnnotation2D > m_TargetStructureWarnOverlay
bool OnFinishStep() override
Called when all necessary actions for the step where done. This method has to be implemented by a con...
void GenerateTargetColorLookupTable()
itk::SmartPointer< mitk::Surface > m_TargetSurface
bool GetIsRestartable() override
Indicates if it makes sense to be able to restart the step. This method must be implemented by concre...
itk::SmartPointer< mitk::DataNode > m_TargetNode
std::string m_ReferenceSensorName
unsigned int m_NeedleSensorIndex
bool m_CurrentTargetReached
QString GetTitle() override
Getter for the title of the navigation step. This title should be human readable and can be used to d...
QmitkZoneProgressBar * m_TargetProgressBar
bool OnDeactivateStep() override
Called when the navigation step gets deactivated (-> state started). This method may be implemented b...
void UpdateSensorsNames()
QVector< itk::SmartPointer< mitk::DataNode > > m_PlannedTargetsNodes
unsigned int m_NumberOfTargets
void UpdateTargetColors()
unsigned int m_ReferenceSensorIndex
bool OnStartStep() override
Called when the navigation step gets started. This method has to be implemented by a concrete subclas...
itk::SmartPointer< mitk::USNavigationTargetIntersectionFilter > m_TargetIntersectionFilter
itk::SmartPointer< mitk::USTargetPlacementQualityCalculator > m_PlacementQualityCalculator
itk::SmartPointer< mitk::USNavigationTargetOcclusionFilter > m_TargetOcclusionFilter
void UpdatePlannedTargetProgressDisplay()
Updates color and distance of the progress bar for the planned target. The intersection between needl...
FilterVector GetFilter() override
Getter for navigation data filters of the navigation step. This method may be implemented by a concre...
QProgressBar for displaying distances to zones. Colors are changed according to the distance to the z...
void SetBorderColor(float color[3])
void setValueInvalid()
Can be called to indicate that there is currently no valid distance value available....
void SetTextFormatValid(QString format)
Setter for the text on the progress bar. Defaults to the string given as name to the constructor....
void SetColor(float color[3])
void SetTextFormatInvalid(QString format)