diff --git a/Isodose/CMakeLists.txt b/Isodose/CMakeLists.txt index b175f1792..83a4c7190 100644 --- a/Isodose/CMakeLists.txt +++ b/Isodose/CMakeLists.txt @@ -7,7 +7,6 @@ string(TOUPPER ${MODULE_NAME} MODULE_NAME_UPPER) #----------------------------------------------------------------------------- add_subdirectory(Logic) add_subdirectory(Widgets) -add_subdirectory(SubjectHierarchyPlugins) #----------------------------------------------------------------------------- set(MODULE_EXPORT_DIRECTIVE "Q_SLICER_QTMODULES_${MODULE_NAME_UPPER}_EXPORT") @@ -19,8 +18,6 @@ set(MODULE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/Widgets ${CMAKE_CURRENT_BINARY_DIR}/Widgets ${SlicerRtCommon_INCLUDE_DIRS} - ${CMAKE_CURRENT_SOURCE_DIR}/SubjectHierarchyPlugins - ${CMAKE_CURRENT_BINARY_DIR}/SubjectHierarchyPlugins ${qSlicerSubjectHierarchyModuleWidgets_INCLUDE_DIRS} ) @@ -44,7 +41,6 @@ set(MODULE_UI_SRCS set(MODULE_TARGET_LIBRARIES vtkSlicer${MODULE_NAME}ModuleLogic vtkSlicer${MODULE_NAME}ModuleWidgets - qSlicer${MODULE_NAME}SubjectHierarchyPlugins ) set(MODULE_RESOURCES diff --git a/Isodose/Logic/CMakeLists.txt b/Isodose/Logic/CMakeLists.txt index 3119630ff..955ca3d79 100644 --- a/Isodose/Logic/CMakeLists.txt +++ b/Isodose/Logic/CMakeLists.txt @@ -7,6 +7,8 @@ set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_LOGIC_EXPORT") set(${KIT}_INCLUDE_DIRECTORIES ${SlicerRtCommon_INCLUDE_DIRS} ${vtkSlicerSubjectHierarchyModuleLogic_INCLUDE_DIRS} + ${vtkSlicerSegmentationsModuleMRML_INCLUDE_DIRS} + ${vtkSlicerDicomRtImportExportConversionRules_INCLUDE_DIRS} ) set(${KIT}_SRCS @@ -19,6 +21,8 @@ set(${KIT}_SRCS set(${KIT}_TARGET_LIBRARIES vtkSlicerRtCommon vtkSlicerSubjectHierarchyModuleLogic + vtkSlicerSegmentationsModuleMRML + vtkSlicerDicomRtImportExportConversionRules MRMLCore ${ITK_LIBRARIES} ${VTK_LIBRARIES} diff --git a/Isodose/Logic/vtkMRMLIsodoseNode.cxx b/Isodose/Logic/vtkMRMLIsodoseNode.cxx index d0365377f..5ca82af01 100644 --- a/Isodose/Logic/vtkMRMLIsodoseNode.cxx +++ b/Isodose/Logic/vtkMRMLIsodoseNode.cxx @@ -53,6 +53,7 @@ vtkMRMLIsodoseNode::vtkMRMLIsodoseNode() this->DoseUnits = DoseUnitsType::Unknown; this->ReferenceDoseValue = -1.; this->RelativeRepresentationFlag = false; + this->BorderMode = BorderModeType::Single; this->HideFromEditors = false; } @@ -73,6 +74,7 @@ void vtkMRMLIsodoseNode::WriteXML(ostream& of, int nIndent) vtkMRMLWriteXMLBooleanMacro(ShowScalarBar2D, ShowScalarBar2D); vtkMRMLWriteXMLBooleanMacro(ShowDoseVolumesOnly, ShowDoseVolumesOnly); vtkMRMLWriteXMLIntMacro(DoseUnits, DoseUnits); + vtkMRMLWriteXMLIntMacro(BorderMode, BorderMode); vtkMRMLWriteXMLFloatMacro(ReferenceDoseValue, ReferenceDoseValue); vtkMRMLWriteXMLBooleanMacro(RelativeRepresentationFlag, RelativeRepresentationFlag); @@ -92,6 +94,7 @@ void vtkMRMLIsodoseNode::ReadXMLAttributes(const char** atts) vtkMRMLReadXMLBooleanMacro(ShowScalarBar2D, ShowScalarBar2D); vtkMRMLReadXMLBooleanMacro(ShowDoseVolumesOnly, ShowDoseVolumesOnly); vtkMRMLReadXMLIntMacro(DoseUnits, DoseUnits); + vtkMRMLReadXMLIntMacro(BorderMode, BorderMode); vtkMRMLReadXMLFloatMacro(ReferenceDoseValue, ReferenceDoseValue); vtkMRMLReadXMLBooleanMacro(RelativeRepresentationFlag, RelativeRepresentationFlag); vtkMRMLReadXMLEndMacro(); @@ -115,6 +118,7 @@ void vtkMRMLIsodoseNode::Copy(vtkMRMLNode *anode) vtkMRMLCopyBooleanMacro(ShowScalarBar2D); vtkMRMLCopyBooleanMacro(ShowDoseVolumesOnly); vtkMRMLCopyIntMacro(DoseUnits); + vtkMRMLCopyIntMacro(BorderMode); vtkMRMLCopyFloatMacro(ReferenceDoseValue); vtkMRMLCopyBooleanMacro(RelativeRepresentationFlag); vtkMRMLCopyEndMacro(); @@ -134,6 +138,7 @@ void vtkMRMLIsodoseNode::PrintSelf(ostream& os, vtkIndent indent) vtkMRMLPrintBooleanMacro(ShowScalarBar2D); vtkMRMLPrintBooleanMacro(ShowDoseVolumesOnly); vtkMRMLPrintIntMacro(DoseUnits); + vtkMRMLPrintIntMacro(BorderMode); vtkMRMLPrintFloatMacro(ReferenceDoseValue); vtkMRMLPrintBooleanMacro(RelativeRepresentationFlag); vtkMRMLPrintEndMacro(); @@ -194,15 +199,30 @@ void vtkMRMLIsodoseNode::SetDoseUnits(int doseUnits) { switch (doseUnits) { - case 0: - SetDoseUnits(DoseUnitsType::Gy); - break; - case 1: - SetDoseUnits(DoseUnitsType::Relative); - break; - case -1: - default: - SetDoseUnits(DoseUnitsType::Unknown); - break; + case 0: + this->SetDoseUnits(DoseUnitsType::Gy); + break; + case 1: + this->SetDoseUnits(DoseUnitsType::Relative); + break; + case -1: + default: + this->SetDoseUnits(DoseUnitsType::Unknown); + break; + } +} + +//---------------------------------------------------------------------------- +void vtkMRMLIsodoseNode::SetBorderMode(int doseBorder) +{ + switch (doseBorder) + { + case 2: + this->SetBorderMode(BorderModeType::Double); + break; + case 1: + default: + this->SetBorderMode(BorderModeType::Single); + break; } } diff --git a/Isodose/Logic/vtkMRMLIsodoseNode.h b/Isodose/Logic/vtkMRMLIsodoseNode.h index 6bf5d4723..ed729152f 100644 --- a/Isodose/Logic/vtkMRMLIsodoseNode.h +++ b/Isodose/Logic/vtkMRMLIsodoseNode.h @@ -38,6 +38,10 @@ class VTK_SLICER_ISODOSE_LOGIC_EXPORT vtkMRMLIsodoseNode : public vtkMRMLNode { public: enum DoseUnitsType { Unknown = -1, Gy = 0, Relative = 1 }; + enum BorderModeType { + Single = 1, /// solid shape. Shows dose higher that thesholdMin. + Double = 2 /// hollow shape aka ring-shaped. Shows dose higher than thesholdMin but lower than thesholdMax. + }; static const char* COLOR_TABLE_REFERENCE_ROLE; static vtkMRMLIsodoseNode *New(); @@ -103,6 +107,10 @@ class VTK_SLICER_ISODOSE_LOGIC_EXPORT vtkMRMLIsodoseNode : public vtkMRMLNode vtkGetMacro(DoseUnits, DoseUnitsType); vtkSetMacro(DoseUnits, DoseUnitsType); + /// Get/Set dose border mode type + vtkGetMacro(BorderMode, BorderModeType); + vtkSetMacro(BorderMode, BorderModeType); + /// Get/Set relative representation flag vtkGetMacro(RelativeRepresentationFlag, bool); vtkSetMacro(RelativeRepresentationFlag, bool); @@ -115,6 +123,7 @@ class VTK_SLICER_ISODOSE_LOGIC_EXPORT vtkMRMLIsodoseNode : public vtkMRMLNode void operator=(const vtkMRMLIsodoseNode&); void SetDoseUnits(int doseUnits); + void SetBorderMode(int doseBorder); protected: /// State of Show isodose lines checkbox @@ -135,6 +144,9 @@ class VTK_SLICER_ISODOSE_LOGIC_EXPORT vtkMRMLIsodoseNode : public vtkMRMLNode /// Type of dose units DoseUnitsType DoseUnits; + /// Type of isodose border surface + BorderModeType BorderMode; + /// Reference dose value double ReferenceDoseValue; diff --git a/Isodose/Logic/vtkSlicerIsodoseModuleLogic.cxx b/Isodose/Logic/vtkSlicerIsodoseModuleLogic.cxx index 6852fe047..704c256d3 100644 --- a/Isodose/Logic/vtkSlicerIsodoseModuleLogic.cxx +++ b/Isodose/Logic/vtkSlicerIsodoseModuleLogic.cxx @@ -39,6 +39,11 @@ #include #include #include +#include +#include + +// DicomRtImportExport includes +#include // MRMLLogic includes #include @@ -59,8 +64,13 @@ #include #include #include +#include +#include #include "vtksys/SystemTools.hxx" +// STD includes +#include + //---------------------------------------------------------------------------- const char* DEFAULT_ISODOSE_COLOR_TABLE_FILE_NAME = "Isodose_ColorTable.ctbl"; const char* DEFAULT_ISODOSE_COLOR_TABLE_NODE_NAME = "Isodose_ColorTable_Default"; @@ -659,13 +669,6 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para return; } - // Check existing isodose set and remove if exists - vtkIdType isodoseFolderItemID = this->GetIsodoseFolderItemID(doseVolumeNode); - if (isodoseFolderItemID) - { - shNode->RemoveItem(isodoseFolderItemID, true, true); - } - // Check if that absolute of relative values bool relativeFlag = false; vtkMRMLIsodoseNode::DoseUnitsType doseUnits = parameterNode->GetDoseUnits(); @@ -683,9 +686,38 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para vtkSlicerIsodoseModuleLogic::ISODOSE_RELATIVE_ROOT_HIERARCHY_NAME_POSTFIX : vtkSlicerIsodoseModuleLogic::ISODOSE_ROOT_HIERARCHY_NAME_POSTFIX; - // Setup isodose subject hierarchy folder + // Segmentation node data + vtkIdType segmentationShItemID = vtkMRMLSubjectHierarchyNode::INVALID_ITEM_ID; + + // Setup isodose subject hierarchy folder if isodose representation is not segmentation node std::string isodoseFolderName = std::string(doseVolumeNode->GetName()) + isodoseName; - isodoseFolderItemID = shNode->CreateFolderItem(doseShItemID, isodoseFolderName); + + vtkNew segmentationNode; + std::string segmentationNodeName = scene->GenerateUniqueName(isodoseFolderName.c_str()); + segmentationNode->SetName(segmentationNodeName.c_str()); + scene->AddNode(segmentationNode); + + // Set master representation to closed surface + segmentationNode->SetMasterRepresentationToClosedSurface(); + + double doseVolumeSpacing[3] = { 0.0, 0.0, 0.0 }; + + // Get image geometry from previously loaded volume if found + // Segmentation node checks added nodes and sets the geometry parameter in case the referenced volume is loaded later + segmentationNode->SetReferenceImageGeometryParameterFromVolumeNode(doseVolumeNode); + doseVolumeNode->GetSpacing(doseVolumeSpacing); + + // Set up subject hierarchy node for segmentation + segmentationShItemID = shNode->CreateItem(shNode->GetSceneItemID(), segmentationNode); + shNode->SetItemUID(segmentationShItemID, vtkMRMLSubjectHierarchyConstants::GetDICOMUIDName(), ""); + shNode->SetItemAttribute(segmentationShItemID, vtkSlicerRtCommon::DICOMRTIMPORT_ROI_REFERENCED_SERIES_UID_ATTRIBUTE_NAME, ""); + shNode->SetItemAttribute(segmentationShItemID, vtkMRMLSubjectHierarchyConstants::GetDICOMReferencedInstanceUIDsAttributeName(), "" ); + + // Setup segmentation display and storage + vtkNew segmentationDisplayNode; + scene->AddNode(segmentationDisplayNode); + segmentationNode->SetAndObserveDisplayNodeID(segmentationDisplayNode->GetID()); + segmentationDisplayNode->SetBackfaceCulling(0); // Get color table vtkMRMLColorTableNode* colorTableNode = parameterNode->GetColorTableNode(); @@ -722,19 +754,19 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para int currentProgressStep = 0; // Reslice dose volume - vtkSmartPointer inputIJK2RASMatrix = vtkSmartPointer::New(); + vtkNew inputIJK2RASMatrix; doseVolumeNode->GetIJKToRASMatrix(inputIJK2RASMatrix); - vtkSmartPointer inputRAS2IJKMatrix = vtkSmartPointer::New(); + vtkNew inputRAS2IJKMatrix; doseVolumeNode->GetRASToIJKMatrix(inputRAS2IJKMatrix); - vtkSmartPointer outputIJK2IJKResliceTransform = vtkSmartPointer::New(); + vtkNew outputIJK2IJKResliceTransform; outputIJK2IJKResliceTransform->Identity(); outputIJK2IJKResliceTransform->PostMultiply(); outputIJK2IJKResliceTransform->SetMatrix(inputIJK2RASMatrix); vtkSmartPointer inputVolumeNodeTransformNode = doseVolumeNode->GetParentTransformNode(); - vtkSmartPointer inputRAS2RASMatrix = vtkSmartPointer::New(); - if (inputVolumeNodeTransformNode!=nullptr) + vtkNew inputRAS2RASMatrix; + if (inputVolumeNodeTransformNode) { inputVolumeNodeTransformNode->GetMatrixTransformToWorld(inputRAS2RASMatrix); outputIJK2IJKResliceTransform->Concatenate(inputRAS2RASMatrix); @@ -745,14 +777,13 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para int dimensions[3] = {0, 0, 0}; doseVolumeNode->GetImageData()->GetDimensions(dimensions); - vtkSmartPointer reslice = vtkSmartPointer::New(); + vtkNew reslice; reslice->SetInputData(doseVolumeNode->GetImageData()); reslice->SetOutputOrigin(0, 0, 0); reslice->SetOutputSpacing(1, 1, 1); reslice->SetOutputExtent(0, dimensions[0]-1, 0, dimensions[1]-1, 0, dimensions[2]-1); reslice->SetResliceTransform(outputIJK2IJKResliceTransform); reslice->Update(); - vtkSmartPointer reslicedDoseVolumeImage = reslice->GetOutput(); // Report progress ++currentProgressStep; @@ -762,10 +793,12 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para // reference value for relative representation double referenceValue = parameterNode->GetReferenceDoseValue(); + std::vector< std::tuple< std::string, std::array< double, 6>, vtkSmartPointer > > singleBorderData; + // Create isodose surfaces for (int i = 0; i < colorTableNode->GetNumberOfColors(); i++) { - double val[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + std::array< double, 6 > val; const char* strIsoLevel = colorTableNode->GetColorName(i); double isoLevel = vtkVariant(strIsoLevel).ToDouble(); // change isoLevel value for relative representation @@ -776,10 +809,10 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para isoLevel = isoLevel * referenceValue / 100.; } } - colorTableNode->GetColor(i, val); - - vtkSmartPointer marchingCubes = vtkSmartPointer::New(); - marchingCubes->SetInputData(reslicedDoseVolumeImage); + colorTableNode->GetColor(i, val.data()); + + vtkNew marchingCubes; + marchingCubes->SetInputData(reslice->GetOutput()); marchingCubes->SetNumberOfContours(1); marchingCubes->SetValue(0, isoLevel); marchingCubes->ComputeScalarsOff(); @@ -787,14 +820,14 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para marchingCubes->ComputeNormalsOff(); marchingCubes->Update(); - vtkSmartPointer isoPolyData= marchingCubes->GetOutput(); - if (isoPolyData->GetNumberOfPoints() >= 1) + vtkPolyData* isoPolyData = marchingCubes->GetOutput(); + if (isoPolyData && isoPolyData->GetNumberOfPoints() > 0) { - vtkSmartPointer triangleFilter = vtkSmartPointer::New(); + vtkNew triangleFilter; triangleFilter->SetInputData(marchingCubes->GetOutput()); triangleFilter->Update(); - vtkSmartPointer decimate = vtkSmartPointer::New(); + vtkNew decimate; decimate->SetInputData(triangleFilter->GetOutput()); decimate->SetTargetReduction(0.6); decimate->SetFeatureAngle(60); @@ -803,55 +836,30 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para decimate->SetMaximumError(1); decimate->Update(); - vtkSmartPointer smootherSinc = vtkSmartPointer::New(); + vtkNew smootherSinc; smootherSinc->SetPassBand(0.1); - smootherSinc->SetInputData(decimate->GetOutput() ); + smootherSinc->SetInputData(decimate->GetOutput()); smootherSinc->SetNumberOfIterations(2); smootherSinc->FeatureEdgeSmoothingOff(); smootherSinc->BoundarySmoothingOff(); smootherSinc->Update(); - vtkSmartPointer normals = vtkSmartPointer::New(); + vtkNew normals; normals->SetInputData(smootherSinc->GetOutput()); normals->ComputePointNormalsOn(); normals->SetFeatureAngle(60); normals->Update(); - vtkSmartPointer inputIJKToRASTransform = vtkSmartPointer::New(); + vtkNew inputIJKToRASTransform; inputIJKToRASTransform->Identity(); inputIJKToRASTransform->SetMatrix(inputIJK2RASMatrix); - vtkSmartPointer transformPolyData = vtkSmartPointer::New(); + vtkNew transformPolyData; transformPolyData->SetInputData(normals->GetOutput()); transformPolyData->SetTransform(inputIJKToRASTransform); transformPolyData->Update(); - - vtkSmartPointer displayNode = vtkSmartPointer::New(); - displayNode = vtkMRMLModelDisplayNode::SafeDownCast(scene->AddNode(displayNode)); - displayNode->Visibility2DOn(); - displayNode->VisibilityOn(); - displayNode->SetColor(val[0], val[1], val[2]); - displayNode->SetOpacity(val[3]); - - // Disable backface culling to make the back side of the model visible as well - displayNode->SetBackfaceCulling(0); - - vtkSmartPointer isodoseModelNode = vtkSmartPointer::New(); - std::string isodoseModelNodeName = vtkSlicerIsodoseModuleLogic::ISODOSE_MODEL_NODE_NAME_PREFIX + strIsoLevel + doseUnitName; - isodoseModelNode->SetName(isodoseModelNodeName.c_str()); - isodoseModelNode->SetSelectable(1); - isodoseModelNode->SetAttribute(vtkSlicerRtCommon::DICOMRTIMPORT_ISODOSE_MODEL_IDENTIFIER_ATTRIBUTE_NAME.c_str(), "1"); // The attribute above distinguishes isodoses from regular models - scene->AddNode(isodoseModelNode); - isodoseModelNode->SetAndObserveDisplayNodeID(displayNode->GetID()); - isodoseModelNode->SetAndObservePolyData(transformPolyData->GetOutput()); - shNode->RequestOwnerPluginSearch(isodoseModelNode); //TODO: Why is this needed? - - // Put the new node in the isodose folder - vtkIdType isodoseModelItemID = shNode->GetItemByDataNode(isodoseModelNode); - if (isodoseModelItemID) // There is no automatic SH creation in automatic tests - { - shNode->SetItemParent(isodoseModelItemID, isodoseFolderItemID); - } + + singleBorderData.push_back({ std::string(strIsoLevel), val, transformPolyData->GetOutput()}); } // Report progress @@ -864,6 +872,72 @@ void vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para this->UpdateDoseColorTableFromIsodose(parameterNode); scene->EndState(vtkMRMLScene::BatchProcessState); + + switch (parameterNode->GetBorderMode()) + { + case vtkMRMLIsodoseNode::Double: + { + for (size_t i = 1; i < singleBorderData.size(); ++i) + { + vtkNew append; + std::string prevLevelString; + vtkSmartPointer prevPolyData; + std::tie( prevLevelString, std::ignore, prevPolyData) = singleBorderData[i - 1]; + + std::string currLevelString; + std::array< double, 6 > currColor; + vtkSmartPointer currPolyData; + std::tie( currLevelString, currColor, currPolyData) = singleBorderData[i]; + const double* currVal = currColor.data(); + + append->AddInputData(prevPolyData); + append->AddInputData(currPolyData); + append->Update(); + + // Add segment for double border isolevels + std::string name = prevLevelString + "-" + currLevelString; + vtkNew segment; + segment->SetName(name.c_str()); + segment->SetColor(currVal[0], currVal[1], currVal[2]); + segment->AddRepresentation(vtkSegmentationConverter::GetSegmentationClosedSurfaceRepresentationName(), append->GetOutput()); + segmentationNode->GetSegmentation()->AddSegment(segment); + + // Add DICOM ROI number as tag to the segment + segment->SetTag(vtkSlicerRtCommon::DICOMRTIMPORT_ROI_NUMBER_SEGMENT_TAG_NAME, std::to_string(i).c_str()); + } + } + break; + case vtkMRMLIsodoseNode::Single: + { + // Fill segmentation node data with single border mode + int i = 0; + for (const auto& tupleValue : singleBorderData) + { + std::string isoLevelString; + std::array< double, 6 > colorValue; + vtkSmartPointer polyData; + std::tie( isoLevelString, colorValue, polyData) = tupleValue; + const double* val = colorValue.data(); + + // Add segment for current structure + vtkNew segment; + segment->SetName(isoLevelString.c_str()); + segment->SetColor(val[0], val[1], val[2]); + segment->AddRepresentation(vtkSegmentationConverter::GetSegmentationClosedSurfaceRepresentationName(), polyData); + segmentationNode->GetSegmentation()->AddSegment(segment); + + // Add DICOM ROI number as tag to the segment + segment->SetTag(vtkSlicerRtCommon::DICOMRTIMPORT_ROI_NUMBER_SEGMENT_TAG_NAME, std::to_string(i).c_str()); + ++i; + } // For all isodose levels + } + break; + } + // Set fill opacity and parent +// segmentationDisplayNode->SetAllSegmentsOpacity2DFill(0.); +// segmentationDisplayNode->SetAllSegmentsVisibility(true); + // dose volume as a parent in subject hierarchy + shNode->SetItemParent( segmentationShItemID, doseShItemID); } //--------------------------------------------------------------------------- diff --git a/Isodose/Resources/Icons/IsodoseDoubleBorder.png b/Isodose/Resources/Icons/IsodoseDoubleBorder.png new file mode 100644 index 000000000..9bb4e2eea Binary files /dev/null and b/Isodose/Resources/Icons/IsodoseDoubleBorder.png differ diff --git a/Isodose/Resources/Icons/IsodoseSingleBorder.png b/Isodose/Resources/Icons/IsodoseSingleBorder.png new file mode 100644 index 000000000..5a77dd035 Binary files /dev/null and b/Isodose/Resources/Icons/IsodoseSingleBorder.png differ diff --git a/Isodose/Resources/UI/qSlicerIsodoseModule.ui b/Isodose/Resources/UI/qSlicerIsodoseModule.ui index ccd20758d..dbc6c5ca8 100644 --- a/Isodose/Resources/UI/qSlicerIsodoseModule.ui +++ b/Isodose/Resources/UI/qSlicerIsodoseModule.ui @@ -6,7 +6,7 @@ 0 0 - 373 + 392 604 @@ -27,8 +27,8 @@ - - + + vtkMRMLIsodoseNode @@ -49,6 +49,98 @@ Input + + + + + + Number of iso levels: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1 + + + 6 + + + + + + + + 0 + 0 + + + + Represent isodose as a surface with a single border aka solid mode. Surface shows dose higher that thesholdMin. + + + + + + + :/Icons/IsodoseSingleBorder.png:/Icons/IsodoseSingleBorder.png + + + true + + + false + + + + + + + + + true + + + + + + + Show dose volumes only + + + true + + + + + + + Dose volume: + + + + + + + false + + + + vtkMRMLScalarVolumeNode + + + + false + + + true + + + @@ -506,68 +598,6 @@ - - - - false - - - - vtkMRMLScalarVolumeNode - - - - false - - - true - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 6 - - - - - - - Dose volume: - - - - - - - Show dose volumes only - - - true - - - - - - - true - - - - - - - Number of iso levels: - - - @@ -776,6 +806,12 @@ QWidget
ctkSliderWidget.h
+ + qSlicerWidget + QWidget +
qSlicerWidget.h
+ 1 +
qMRMLColorTableView QTableView @@ -787,14 +823,10 @@
qMRMLNodeComboBox.h
1
- - qSlicerWidget - QWidget -
qSlicerWidget.h
- 1 -
- + + + qSlicerIsodoseModule diff --git a/Isodose/Resources/qSlicerIsodoseModule.qrc b/Isodose/Resources/qSlicerIsodoseModule.qrc index 6c889ac26..273687938 100644 --- a/Isodose/Resources/qSlicerIsodoseModule.qrc +++ b/Isodose/Resources/qSlicerIsodoseModule.qrc @@ -1,5 +1,7 @@ Icons/Isodose.png + Icons/IsodoseSingleBorder.png + Icons/IsodoseDoubleBorder.png diff --git a/Isodose/SubjectHierarchyPlugins/CMakeLists.txt b/Isodose/SubjectHierarchyPlugins/CMakeLists.txt deleted file mode 100644 index c532ac12f..000000000 --- a/Isodose/SubjectHierarchyPlugins/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ -project(qSlicer${MODULE_NAME}SubjectHierarchyPlugins) - -set(KIT ${PROJECT_NAME}) - -set(${KIT}_EXPORT_DIRECTIVE "Q_SLICER_${MODULE_NAME_UPPER}_SUBJECT_HIERARCHY_PLUGINS_EXPORT") - -set(${KIT}_INCLUDE_DIRECTORIES - ${SlicerRtCommon_INCLUDE_DIRS} - ${vtkSlicerIsodoseModuleLogic_INCLUDE_DIRS} - ${vtkSlicerSubjectHierarchyModuleLogic_INCLUDE_DIRS} - ${qSlicerSubjectHierarchyModuleWidgets_INCLUDE_DIRS} - ${MRMLCore_INCLUDE_DIRS} - ${MRMLLogic_INCLUDE_DIRS} - ${qMRMLWidgets_INCLUDE_DIRS} - ${MRMLCLI_INCLUDE_DIRS} - ${Slicer_Libs_INCLUDE_DIRS} - ) - -set(${KIT}_SRCS - qSlicerSubjectHierarchy${MODULE_NAME}Plugin.cxx - qSlicerSubjectHierarchy${MODULE_NAME}Plugin.h - ) - -set(${KIT}_MOC_SRCS - qSlicerSubjectHierarchy${MODULE_NAME}Plugin.h - ) - -set(${KIT}_UI_SRCS - ) - -set(${KIT}_RESOURCES - Resources/${KIT}.qrc - ) - -SET (${KIT}_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "" FORCE) - -#----------------------------------------------------------------------------- -set(${KIT}_TARGET_LIBRARIES - vtkSlicerIsodoseModuleLogic - vtkSlicerSubjectHierarchyModuleLogic - qSlicerSubjectHierarchyModuleWidgets - MRMLCore - MRMLLogic - MRMLCLI - qMRMLWidgets - ${QT_LIBRARIES} - ) - -#----------------------------------------------------------------------------- -SlicerMacroBuildModuleQtLibrary( - NAME ${KIT} - EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE} - INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES} - SRCS ${${KIT}_SRCS} - MOC_SRCS ${${KIT}_MOC_SRCS} - UI_SRCS ${${KIT}_UI_SRCS} - TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES} - RESOURCES ${${KIT}_RESOURCES} - WRAP_PYTHONQT - ) \ No newline at end of file diff --git a/Isodose/SubjectHierarchyPlugins/Resources/Icons/IsodoseLines.png b/Isodose/SubjectHierarchyPlugins/Resources/Icons/IsodoseLines.png deleted file mode 100644 index 6f2d8fa9d..000000000 Binary files a/Isodose/SubjectHierarchyPlugins/Resources/Icons/IsodoseLines.png and /dev/null differ diff --git a/Isodose/SubjectHierarchyPlugins/Resources/qSlicerIsodoseSubjectHierarchyPlugins.qrc b/Isodose/SubjectHierarchyPlugins/Resources/qSlicerIsodoseSubjectHierarchyPlugins.qrc deleted file mode 100644 index ec7193b13..000000000 --- a/Isodose/SubjectHierarchyPlugins/Resources/qSlicerIsodoseSubjectHierarchyPlugins.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - Icons/IsodoseLines.png - - diff --git a/Isodose/SubjectHierarchyPlugins/qSlicerSubjectHierarchyIsodosePlugin.cxx b/Isodose/SubjectHierarchyPlugins/qSlicerSubjectHierarchyIsodosePlugin.cxx deleted file mode 100644 index 71adceef3..000000000 --- a/Isodose/SubjectHierarchyPlugins/qSlicerSubjectHierarchyIsodosePlugin.cxx +++ /dev/null @@ -1,192 +0,0 @@ -/*============================================================================== - - Copyright (c) Laboratory for Percutaneous Surgery (PerkLab) - Queen's University, Kingston, ON, Canada. All Rights Reserved. - - See COPYRIGHT.txt - or http://www.slicer.org/copyright/copyright.txt for details. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - This file was originally developed by Csaba Pinter, PerkLab, Queen's University - and was supported through the Applied Cancer Research Unit program of Cancer Care - Ontario with funds provided by the Ontario Ministry of Health and Long-Term Care - -==============================================================================*/ - -// SlicerRt includes -#include "vtkSlicerRtCommon.h" - -// Isodose includes -#include "qSlicerSubjectHierarchyIsodosePlugin.h" -#include "vtkMRMLIsodoseNode.h" -#include "vtkSlicerIsodoseModuleLogic.h" - -// SubjectHierarchy MRML includes -#include "vtkMRMLSubjectHierarchyConstants.h" -#include "vtkMRMLSubjectHierarchyNode.h" - -// SubjectHierarchy Plugins includes -#include "qSlicerSubjectHierarchyPluginHandler.h" -#include "qSlicerSubjectHierarchyDefaultPlugin.h" - -// MRML includes -#include -#include -#include - -// MRML Widgets includes -#include - -// VTK includes -#include -#include -#include - -// Qt includes -#include -#include -#include -#include - -// SlicerQt includes -#include "qSlicerAbstractModuleWidget.h" - -//----------------------------------------------------------------------------- -/// \ingroup SlicerRt_QtModules_RtHierarchy -class qSlicerSubjectHierarchyIsodosePluginPrivate: public QObject -{ - Q_DECLARE_PUBLIC(qSlicerSubjectHierarchyIsodosePlugin); -protected: - qSlicerSubjectHierarchyIsodosePlugin* const q_ptr; -public: - qSlicerSubjectHierarchyIsodosePluginPrivate(qSlicerSubjectHierarchyIsodosePlugin& object); - ~qSlicerSubjectHierarchyIsodosePluginPrivate(); -public: - QIcon IsodoseLinesIcon; -}; - -//----------------------------------------------------------------------------- -// qSlicerSubjectHierarchyIsodosePluginPrivate methods - -//----------------------------------------------------------------------------- -qSlicerSubjectHierarchyIsodosePluginPrivate::qSlicerSubjectHierarchyIsodosePluginPrivate(qSlicerSubjectHierarchyIsodosePlugin& object) - : q_ptr(&object) -{ - this->IsodoseLinesIcon = QIcon(":Icons/IsodoseLines.png"); -} - -//----------------------------------------------------------------------------- -qSlicerSubjectHierarchyIsodosePluginPrivate::~qSlicerSubjectHierarchyIsodosePluginPrivate() = default; - -//----------------------------------------------------------------------------- -// qSlicerSubjectHierarchyIsodosePlugin methods - -//----------------------------------------------------------------------------- -qSlicerSubjectHierarchyIsodosePlugin::qSlicerSubjectHierarchyIsodosePlugin(QObject* parent) - : Superclass(parent) - , d_ptr( new qSlicerSubjectHierarchyIsodosePluginPrivate(*this) ) -{ - this->m_Name = QString("Isodose"); -} - -//----------------------------------------------------------------------------- -qSlicerSubjectHierarchyIsodosePlugin::~qSlicerSubjectHierarchyIsodosePlugin() = default; - -//--------------------------------------------------------------------------- -double qSlicerSubjectHierarchyIsodosePlugin::canOwnSubjectHierarchyItem(vtkIdType itemID)const -{ - if (!itemID) - { - qCritical() << Q_FUNC_INFO << ": Invalid input item"; - return 0.0; - } - vtkMRMLSubjectHierarchyNode* shNode = qSlicerSubjectHierarchyPluginHandler::instance()->subjectHierarchyNode(); - if (!shNode) - { - qCritical() << Q_FUNC_INFO << ": Failed to access subject hierarchy node"; - return 0.0; - } - - // Isodose lines - vtkMRMLNode* associatedNode = shNode->GetItemDataNode(itemID); - if (associatedNode && vtkSlicerRtCommon::IsIsodoseModelNode(associatedNode)) - { - return 1.0; - } - - return 0.0; -} - -//--------------------------------------------------------------------------- -const QString qSlicerSubjectHierarchyIsodosePlugin::roleForPlugin()const -{ - return "Isodose surface"; -} - -//--------------------------------------------------------------------------- -QIcon qSlicerSubjectHierarchyIsodosePlugin::icon(vtkIdType itemID) -{ - Q_D(qSlicerSubjectHierarchyIsodosePlugin); - - if (!itemID) - { - qCritical() << Q_FUNC_INFO << ": Invalid input item"; - return QIcon(); - } - - if (this->canOwnSubjectHierarchyItem(itemID)) - { - return d->IsodoseLinesIcon; - } - - // Item unknown by plugin - return QIcon(); -} - -//--------------------------------------------------------------------------- -QIcon qSlicerSubjectHierarchyIsodosePlugin::visibilityIcon(int visible) -{ - // Have the default plugin (which is not registered) take care of this - return qSlicerSubjectHierarchyPluginHandler::instance()->defaultPlugin()->visibilityIcon(visible); -} - -//--------------------------------------------------------------------------- -void qSlicerSubjectHierarchyIsodosePlugin::editProperties(vtkIdType itemID) -{ - Q_UNUSED(itemID); - - // Switch to isodose module with parameter set node already selected - qSlicerAbstractModuleWidget* moduleWidget = qSlicerSubjectHierarchyAbstractPlugin::switchToModule("Isodose"); - if (moduleWidget) - { - // Get node selector combobox - qMRMLNodeComboBox* nodeSelector = moduleWidget->findChild("MRMLNodeComboBox_ParameterSet"); - - //TODO: Get parameter set node for isodose model and model hierarchy node - // and set corresponding dose volume too when changes in #580 are implemented - vtkMRMLIsodoseNode* isodoseParameterSetNode = nullptr; //TODO: - - // Choose current data node - if (nodeSelector && isodoseParameterSetNode) - { - nodeSelector->setCurrentNode(isodoseParameterSetNode); - } - } -} - -//----------------------------------------------------------------------------- -void qSlicerSubjectHierarchyIsodosePlugin::setDisplayColor(vtkIdType itemID, QColor color, QMap terminologyMetaData) -{ - qSlicerSubjectHierarchyPluginHandler::instance()->pluginByName("Models")->setDisplayColor(itemID, color, terminologyMetaData); -} - -//----------------------------------------------------------------------------- -QColor qSlicerSubjectHierarchyIsodosePlugin::getDisplayColor(vtkIdType itemID, QMap &terminologyMetaData)const -{ - return qSlicerSubjectHierarchyPluginHandler::instance()->pluginByName("Models")->getDisplayColor(itemID, terminologyMetaData); -} diff --git a/Isodose/SubjectHierarchyPlugins/qSlicerSubjectHierarchyIsodosePlugin.h b/Isodose/SubjectHierarchyPlugins/qSlicerSubjectHierarchyIsodosePlugin.h deleted file mode 100644 index a05aa5172..000000000 --- a/Isodose/SubjectHierarchyPlugins/qSlicerSubjectHierarchyIsodosePlugin.h +++ /dev/null @@ -1,84 +0,0 @@ -/*============================================================================== - - Copyright (c) Laboratory for Percutaneous Surgery (PerkLab) - Queen's University, Kingston, ON, Canada. All Rights Reserved. - - See COPYRIGHT.txt - or http://www.slicer.org/copyright/copyright.txt for details. - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - This file was originally developed by Csaba Pinter, PerkLab, Queen's University - and was supported through the Applied Cancer Research Unit program of Cancer Care - Ontario with funds provided by the Ontario Ministry of Health and Long-Term Care - -==============================================================================*/ - -#ifndef __qSlicerSubjectHierarchyIsodosePlugin_h -#define __qSlicerSubjectHierarchyIsodosePlugin_h - -// SlicerRt includes -#include "qSlicerSubjectHierarchyAbstractPlugin.h" - -#include "qSlicerIsodoseSubjectHierarchyPluginsExport.h" - -class qSlicerSubjectHierarchyIsodosePluginPrivate; -class vtkMRMLNode; -class vtkMRMLSubjectHierarchyNode; - -/// \ingroup SlicerRt_QtModules_RtHierarchy -class Q_SLICER_ISODOSE_SUBJECT_HIERARCHY_PLUGINS_EXPORT qSlicerSubjectHierarchyIsodosePlugin : public qSlicerSubjectHierarchyAbstractPlugin -{ -public: - Q_OBJECT - -public: - typedef qSlicerSubjectHierarchyAbstractPlugin Superclass; - qSlicerSubjectHierarchyIsodosePlugin(QObject* parent = nullptr); - ~qSlicerSubjectHierarchyIsodosePlugin() override; - -public: - /// Determines if the actual plugin can handle a subject hierarchy item. The plugin with - /// the highest confidence number will "own" the item in the subject hierarchy (set icon, tooltip, - /// set context menu etc.) - /// \param item Item to handle in the subject hierarchy tree - /// \return Floating point confidence number between 0 and 1, where 0 means that the plugin cannot handle the - /// item, and 1 means that the plugin is the only one that can handle the item (by node type or identifier attribute) - double canOwnSubjectHierarchyItem(vtkIdType itemID)const override; - - /// Get role that the plugin assigns to the subject hierarchy item. - /// Each plugin should provide only one role. - Q_INVOKABLE const QString roleForPlugin()const override; - - /// Get icon of an owned subject hierarchy item - /// \return Icon to set, empty icon if nothing to set - QIcon icon(vtkIdType itemID) override; - - /// Get visibility icon for a visibility state - Q_INVOKABLE QIcon visibilityIcon(int visible) override; - - /// Open module belonging to item and set inputs in opened module - Q_INVOKABLE void editProperties(vtkIdType itemID) override; - - /// Set display color of an owned subject hierarchy item - /// \param color Display color to set - /// \param terminologyMetaData Map containing terminology meta data - void setDisplayColor(vtkIdType itemID, QColor color, QMap terminologyMetaData) override; - - /// Get display color of an owned subject hierarchy item - /// \param terminologyMetaData Output map containing terminology meta data - QColor getDisplayColor(vtkIdType itemID, QMap &terminologyMetaData)const override; - -protected: - QScopedPointer d_ptr; - -private: - Q_DECLARE_PRIVATE(qSlicerSubjectHierarchyIsodosePlugin); - Q_DISABLE_COPY(qSlicerSubjectHierarchyIsodosePlugin); -}; - -#endif diff --git a/Isodose/qSlicerIsodoseModule.cxx b/Isodose/qSlicerIsodoseModule.cxx index 2ac77b4b1..22ea447d0 100644 --- a/Isodose/qSlicerIsodoseModule.cxx +++ b/Isodose/qSlicerIsodoseModule.cxx @@ -19,10 +19,6 @@ ==============================================================================*/ -// SubjectHierarchy Plugins includes -#include "qSlicerSubjectHierarchyPluginHandler.h" -#include "qSlicerSubjectHierarchyIsodosePlugin.h" - // Isodose Logic includes #include @@ -30,12 +26,6 @@ #include "qSlicerIsodoseModule.h" #include "qSlicerIsodoseModuleWidget.h" -//----------------------------------------------------------------------------- -#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) -#include -Q_EXPORT_PLUGIN2(qSlicerIsodoseModule, qSlicerIsodoseModule); -#endif - //----------------------------------------------------------------------------- /// \ingroup SlicerRt_QtModules_Isodose class qSlicerIsodoseModulePrivate @@ -104,9 +94,6 @@ QIcon qSlicerIsodoseModule::icon()const void qSlicerIsodoseModule::setup() { this->Superclass::setup(); - - // Register Subject Hierarchy plugins - qSlicerSubjectHierarchyPluginHandler::instance()->registerPlugin(new qSlicerSubjectHierarchyIsodosePlugin()); } //----------------------------------------------------------------------------- diff --git a/Isodose/qSlicerIsodoseModuleWidget.cxx b/Isodose/qSlicerIsodoseModuleWidget.cxx index 1cb0af74d..60e616f74 100644 --- a/Isodose/qSlicerIsodoseModuleWidget.cxx +++ b/Isodose/qSlicerIsodoseModuleWidget.cxx @@ -313,6 +313,16 @@ void qSlicerIsodoseModuleWidget::updateWidgetFromMRML() d->checkBox_ScalarBar2D->setChecked(paramNode->GetShowScalarBar2D()); d->checkBox_ShowDoseVolumesOnly->setChecked(paramNode->GetShowDoseVolumesOnly()); + switch (paramNode->GetBorderMode()) + { + case vtkMRMLIsodoseNode::Double: + d->toggleButton_IsoLevelsBorderMode->setChecked(true); + break; + default: + case vtkMRMLIsodoseNode::Single: + d->toggleButton_IsoLevelsBorderMode->setChecked(false); + break; + } } } @@ -343,6 +353,7 @@ void qSlicerIsodoseModuleWidget::setup() connect( d->checkBox_ScalarBar, SIGNAL(toggled(bool)), this, SLOT( setScalarBarVisibility(bool) ) ); connect( d->checkBox_ScalarBar2D, SIGNAL(toggled(bool)), this, SLOT( setScalarBar2DVisibility(bool) ) ); + connect( d->toggleButton_IsoLevelsBorderMode, SIGNAL(toggled(bool)), this, SLOT(onIsoLevelsBorderModeToggled(bool)) ); connect( d->pushButton_Apply, SIGNAL(clicked()), this, SLOT(applyClicked()) ); connect( d->groupBox_RelativeIsolevels, SIGNAL(toggled(bool)), this, SLOT(setRelativeIsolevelsFlag(bool))); connect( d->sliderWidget_ReferenceDose, SIGNAL(valueChanged(double)), this, SLOT(setReferenceDoseValue(double))); @@ -922,6 +933,37 @@ void qSlicerIsodoseModuleWidget::updateButtonsState() d->pushButton_Apply->setEnabled(applyEnabled); } +//----------------------------------------------------------------------------- +void qSlicerIsodoseModuleWidget::onIsoLevelsBorderModeToggled(bool toggled) +{ + Q_D(qSlicerIsodoseModuleWidget); + + vtkMRMLIsodoseNode* paramNode = vtkMRMLIsodoseNode::SafeDownCast(d->MRMLNodeComboBox_ParameterSet->currentNode()); + if (paramNode) + { + if (toggled) + { + paramNode->SetBorderMode(vtkMRMLIsodoseNode::Double); + } + else + { + paramNode->SetBorderMode(vtkMRMLIsodoseNode::Single); + } + } + + if (!toggled) + { + d->toggleButton_IsoLevelsBorderMode->setIcon(QIcon(":/Icons/IsodoseSingleBorder.png")); + d->toggleButton_IsoLevelsBorderMode->setToolTip(tr("Represent isodose as a surface with a single border aka solid mode. Surface shows dose higher that thesholdMin")); + } + else + { + d->toggleButton_IsoLevelsBorderMode->setIcon(QIcon(":/Icons/IsodoseDoubleBorder.png")); + d->toggleButton_IsoLevelsBorderMode->setToolTip(tr("Represent isodose as a surface with double borders aka ring mode. Surface shows dose higher than thesholdMin but lower than thesholdMax")); + } + +} + //----------------------------------------------------------- bool qSlicerIsodoseModuleWidget::setEditedNode( vtkMRMLNode* node, QString role /* = QString()*/, QString context /* = QString() */) diff --git a/Isodose/qSlicerIsodoseModuleWidget.h b/Isodose/qSlicerIsodoseModuleWidget.h index df80e80c9..8fcedb653 100644 --- a/Isodose/qSlicerIsodoseModuleWidget.h +++ b/Isodose/qSlicerIsodoseModuleWidget.h @@ -105,6 +105,9 @@ protected slots: /// Slot called to set reference dose value void setReferenceDoseValue(double value); + /// Slot called to set isodose representation + void onIsoLevelsBorderModeToggled(bool toggled); + protected: // Generates a new isodose level name QString generateNewIsodoseLevel() const; diff --git a/Testing/Python/IGRTWorkflow_SelfTest.py b/Testing/Python/IGRTWorkflow_SelfTest.py index fa41f0c78..e944335e5 100644 --- a/Testing/Python/IGRTWorkflow_SelfTest.py +++ b/Testing/Python/IGRTWorkflow_SelfTest.py @@ -294,7 +294,7 @@ def TestSection_03A_ComputeIsodoseForDay1(self): shNode.SetDisplayVisibilityForBranch(planShItemID, 0) slicer.util.selectModule('Isodose') - numOfModelNodesBeforeLoad = len( slicer.util.getNodes('vtkMRMLModelNode*') ) + numOfSegmentationNodesBeforeLoad = len( slicer.util.getNodes('vtkMRMLSegmentationNode*') ) isodoseWidget = slicer.modules.isodose.widgetRepresentation() doseVolumeMrmlNodeCombobox = slicer.util.findChildren(widget=isodoseWidget, className='qMRMLNodeComboBox', name='MRMLNodeComboBox_DoseVolume')[0] @@ -305,7 +305,7 @@ def TestSection_03A_ComputeIsodoseForDay1(self): doseVolumeMrmlNodeCombobox.setCurrentNodeID(day1Dose.GetID()) applyButton.click() - self.assertEqual( len( slicer.util.getNodes('vtkMRMLModelNode*') ), numOfModelNodesBeforeLoad + 6 ) + self.assertEqual( len( slicer.util.getNodes('vtkMRMLSegmentationNode*') ), numOfSegmentationNodesBeforeLoad + 1 ) # Show day 1 isodose day1CT = slicer.util.getNode(self.day1CTName) @@ -331,9 +331,9 @@ def TestSection_03B_ComputeIsodoseForDay2(self): try: scene = slicer.mrmlScene slicer.util.selectModule('Isodose') - modelNodeCollection = slicer.mrmlScene.GetNodesByClass('vtkMRMLModelNode') - modelNodeCollection.UnRegister(None) - numOfModelNodesBeforeLoad = modelNodeCollection.GetNumberOfItems() + segmentationNodeCollection = slicer.mrmlScene.GetNodesByClass('vtkMRMLSegmentationNode') + segmentationNodeCollection.UnRegister(None) + numOfSegmentationNodesBeforeLoad = segmentationNodeCollection.GetNumberOfItems() isodoseWidget = slicer.modules.isodose.widgetRepresentation() doseVolumeMrmlNodeCombobox = slicer.util.findChildren(widget=isodoseWidget, className='qMRMLNodeComboBox', name='MRMLNodeComboBox_DoseVolume')[0] @@ -344,9 +344,9 @@ def TestSection_03B_ComputeIsodoseForDay2(self): doseVolumeMrmlNodeCombobox.setCurrentNodeID(day2Dose.GetID()) applyButton.click() - modelNodeCollection = slicer.mrmlScene.GetNodesByClass('vtkMRMLModelNode') - modelNodeCollection.UnRegister(None) - self.assertEqual( modelNodeCollection.GetNumberOfItems(), numOfModelNodesBeforeLoad + 6 ) + segmentationNodeCollection = slicer.mrmlScene.GetNodesByClass('vtkMRMLSegmentationNode') + segmentationNodeCollection.UnRegister(None) + self.assertEqual( segmentationNodeCollection.GetNumberOfItems(), numOfSegmentationNodesBeforeLoad + 1 ) # Show day 2 isodose shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)