Skip to content

Commit

Permalink
ENH: Add real-time mode to Isodose computation
Browse files Browse the repository at this point in the history
Real-time mode can be enabled using the RealTime flag in the Isodose parameter node. When this flag is enabled, the following functions are prevented: use of subject hierarchy to organize the isodose model nodes, reporting of progress, batch processing, and update of dose color table from the isodose one. Instead, top-level isodose model nodes are re-used (by node name) at every computation. It is useful when isodose is needed to be computed on-the-fly for streamed dose data, when one set of isodose surfaces (the "current one") is all that is needed to be kept and displayed.
  • Loading branch information
cpinter committed Nov 30, 2022
1 parent aecc055 commit 41bd6e5
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 42 deletions.
69 changes: 50 additions & 19 deletions Isodose/Logic/vtkSlicerIsodoseModuleLogic.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -613,14 +613,21 @@ bool vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para
return false;
}

scene->StartState(vtkMRMLScene::BatchProcessState);
if (!parameterNode->GetRealTime())
{
scene->StartState(vtkMRMLScene::BatchProcessState);
}

// Get subject hierarchy item for the dose volume
vtkIdType doseShItemID = shNode->GetItemByDataNode(doseVolumeNode);
if (!doseShItemID)
vtkIdType doseShItemID = 0
if (!parameterNode->GetRealTime())
{
vtkErrorMacro("CreateIsodoseSurfaces: Failed to get subject hierarchy item for dose volume '" << doseVolumeNode->GetName() << "'");
return false;
doseShItemID = shNode->GetItemByDataNode(doseVolumeNode);
if (!doseShItemID)
{
vtkErrorMacro("CreateIsodoseSurfaces: Failed to get subject hierarchy item for dose volume '" << doseVolumeNode->GetName() << "'");
return false;
}
}

// Check if that absolute of relative values
Expand Down Expand Up @@ -705,9 +712,13 @@ bool vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para
vtkSmartPointer<vtkImageData> reslicedDoseVolumeImage = reslice->GetOutput();

// Report progress
++currentProgressStep;
double progress = (double)(currentProgressStep) / (double)progressStepCount;
this->InvokeEvent(vtkSlicerRtCommon::ProgressUpdated, (void*)&progress);
double progress = 0.0;
if (!parameterNode->GetRealTime())
{
++currentProgressStep;
progress = (double)(currentProgressStep) / (double)progressStepCount;
this->InvokeEvent(vtkSlicerRtCommon::ProgressUpdated, (void*)&progress);
}

// reference value for relative representation
double referenceValue = parameterNode->GetReferenceDoseValue();
Expand Down Expand Up @@ -788,10 +799,13 @@ bool vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para
append->AddInputData(isoSurface);
}

// Report progress
++currentProgressStep;
progress = (double)(currentProgressStep) / (double)progressStepCount;
this->InvokeEvent(vtkSlicerRtCommon::ProgressUpdated, (void*)&progress);
if (!parameterNode->GetRealTime())
{
// Report progress
++currentProgressStep;
progress = (double)(currentProgressStep) / (double)progressStepCount;
this->InvokeEvent(vtkSlicerRtCommon::ProgressUpdated, (void*)&progress);
}
} // For all isodose levels

// update appended isosurfaces
Expand Down Expand Up @@ -842,22 +856,39 @@ bool vtkSlicerIsodoseModuleLogic::CreateIsodoseSurfaces(vtkMRMLIsodoseNode* para
isodoseModelNode->SetAndObservePolyData(isoSurfaces);

// Put the new node as a child of dose volume
vtkIdType isodoseModelItemID = shNode->GetItemByDataNode(isodoseModelNode);
if (isodoseModelItemID) // There is no automatic SH creation in automatic tests
if (!parameterNode->GetRealTime())
{
shNode->SetItemParent(isodoseModelItemID, doseShItemID);
vtkIdType isodoseModelItemID = shNode->GetItemByDataNode(isodoseModelNode);
if (isodoseModelItemID) // There is no automatic SH creation in automatic tests
{
shNode->SetItemParent(isodoseModelItemID, doseShItemID);
}

// Update dose color table based on isodose
this->UpdateDoseColorTableFromIsodose(parameterNode);
}
}
else if (parameterNode->GetRealTime())
{
// In real-time mode we need to clear the polydata when there is no output
vtkMRMLModelNode* isodoseModelNode = parameterNode->GetIsosurfacesModelNode();
if (isodoseModelNode)
{
vtkNew<vtkPolyData> emptyPolyData;
isodoseModelNode->SetAndObservePolyData(emptyPolyData);
}

// Update dose color table based on isodose
this->UpdateDoseColorTableFromIsodose(parameterNode);
}
else
{
vtkErrorMacro("CreateIsodoseSurfaces: Failed to create isosurfaces for dose volume " << doseVolumeNode->GetName());
res = false;
}

scene->EndState(vtkMRMLScene::BatchProcessState);
if (!parameterNode->GetRealTime())
{
scene->EndState(vtkMRMLScene::BatchProcessState);
}

return res;
}

Expand Down
17 changes: 7 additions & 10 deletions Isodose/MRML/vtkMRMLIsodoseNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
See the License for the specific language governing permissions and
limitations under the License.
This file was originally developed by Kevin Wang, Princess Margaret Cancer Centre
and was supported by Cancer Care Ontario (CCO)'s ACRU program
This file was originally developed by Kevin Wang, Princess Margaret Cancer Centre
and was supported by Cancer Care Ontario (CCO)'s ACRU program
with funds provided by the Ontario Ministry of Health and Long-Term Care
and Ontario Consortium for Adaptive Interventions in Radiation Oncology (OCAIRO).
Expand Down Expand Up @@ -49,13 +49,6 @@ vtkMRMLNodeNewMacro(vtkMRMLIsodoseNode);
//----------------------------------------------------------------------------
vtkMRMLIsodoseNode::vtkMRMLIsodoseNode()
{
this->ShowIsodoseLines = true;
this->ShowIsodoseSurfaces = true;
this->ShowDoseVolumesOnly = true;
this->DoseUnits = DoseUnitsType::Unknown;
this->ReferenceDoseValue = -1.;
this->RelativeRepresentationFlag = false;

this->HideFromEditors = false;
}

Expand All @@ -75,8 +68,9 @@ void vtkMRMLIsodoseNode::WriteXML(ostream& of, int nIndent)
vtkMRMLWriteXMLEnumMacro(DoseUnits, DoseUnits);
vtkMRMLWriteXMLFloatMacro(ReferenceDoseValue, ReferenceDoseValue);
vtkMRMLWriteXMLBooleanMacro(RelativeRepresentationFlag, RelativeRepresentationFlag);
vtkMRMLWriteXMLBooleanMacro(RealTime, RealTime);

vtkMRMLWriteXMLEndMacro();
vtkMRMLWriteXMLEndMacro();
}

//----------------------------------------------------------------------------
Expand All @@ -92,6 +86,7 @@ void vtkMRMLIsodoseNode::ReadXMLAttributes(const char** atts)
vtkMRMLReadXMLEnumMacro(DoseUnits, DoseUnits);
vtkMRMLReadXMLFloatMacro(ReferenceDoseValue, ReferenceDoseValue);
vtkMRMLReadXMLBooleanMacro(RelativeRepresentationFlag, RelativeRepresentationFlag);
vtkMRMLReadXMLBooleanMacro(RealTime, RealTime);
vtkMRMLReadXMLEndMacro();

this->EndModify(disabledModify);
Expand All @@ -113,6 +108,7 @@ void vtkMRMLIsodoseNode::Copy(vtkMRMLNode *anode)
vtkMRMLCopyEnumMacro(DoseUnits);
vtkMRMLCopyFloatMacro(ReferenceDoseValue);
vtkMRMLCopyBooleanMacro(RelativeRepresentationFlag);
vtkMRMLCopyBooleanMacro(RealTime);
vtkMRMLCopyEndMacro();

this->EndModify(disabledModify);
Expand All @@ -130,6 +126,7 @@ void vtkMRMLIsodoseNode::PrintSelf(ostream& os, vtkIndent indent)
vtkMRMLPrintEnumMacro(DoseUnits);
vtkMRMLPrintFloatMacro(ReferenceDoseValue);
vtkMRMLPrintBooleanMacro(RelativeRepresentationFlag);
vtkMRMLPrintBooleanMacro(RealTime);
vtkMRMLPrintEndMacro();
}

Expand Down
51 changes: 38 additions & 13 deletions Isodose/MRML/vtkMRMLIsodoseNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
See the License for the specific language governing permissions and
limitations under the License.
This file was originally developed by Kevin Wang, Princess Margaret Cancer Centre
and was supported by Cancer Care Ontario (CCO)'s ACRU program
This file was originally developed by Kevin Wang, Princess Margaret Cancer Centre
and was supported by Cancer Care Ontario (CCO)'s ACRU program
with funds provided by the Ontario Ministry of Health and Long-Term Care
and Ontario Consortium for Adaptive Interventions in Radiation Oncology (OCAIRO).
Expand Down Expand Up @@ -44,19 +44,19 @@ class VTK_SLICER_ISODOSE_MODULE_MRML_EXPORT vtkMRMLIsodoseNode : public vtkMRMLN
vtkTypeMacro(vtkMRMLIsodoseNode, vtkMRMLNode);
void PrintSelf(ostream& os, vtkIndent indent) override;

/// Create instance of a GAD node.
/// Create instance of a GAD node.
vtkMRMLNode* CreateNodeInstance() override;

/// Set node attributes from name/value pairs
/// Set node attributes from name/value pairs
void ReadXMLAttributes(const char** atts) override;

/// Write this node's information to a MRML file in XML format.
/// Write this node's information to a MRML file in XML format.
void WriteXML(ostream& of, int indent) override;

/// Copy the node's attributes to this object
/// Copy the node's attributes to this object
void Copy(vtkMRMLNode *node) override;

/// Get unique node XML tag name (like Volume, Model)
/// Get unique node XML tag name (like Volume, Model)
const char* GetNodeTagName() override { return "Isodose"; };

public:
Expand All @@ -79,29 +79,47 @@ class VTK_SLICER_ISODOSE_MODULE_MRML_EXPORT vtkMRMLIsodoseNode : public vtkMRMLN
vtkGetMacro(ShowIsodoseLines, bool);
vtkSetMacro(ShowIsodoseLines, bool);
vtkBooleanMacro(ShowIsodoseLines, bool);
//@}

//@{
/// Get/Set show isodose surfaces checkbox state
vtkGetMacro(ShowIsodoseSurfaces, bool);
vtkSetMacro(ShowIsodoseSurfaces, bool);
vtkBooleanMacro(ShowIsodoseSurfaces, bool);
//@}

//@{
/// Get/Set show dose volumes only checkbox state
vtkGetMacro(ShowDoseVolumesOnly, bool);
vtkSetMacro(ShowDoseVolumesOnly, bool);
vtkBooleanMacro(ShowDoseVolumesOnly, bool);
//@}

//@{
/// Get/Set reference dose value
vtkGetMacro(ReferenceDoseValue, double);
vtkSetMacro(ReferenceDoseValue, double);
//@}

//@{
/// Get/Set dose units type
vtkGetMacro(DoseUnits, DoseUnitsType);
vtkSetMacro(DoseUnits, DoseUnitsType);
//@}

//@{
/// Get/Set relative representation flag
vtkGetMacro(RelativeRepresentationFlag, bool);
vtkSetMacro(RelativeRepresentationFlag, bool);
vtkBooleanMacro(RelativeRepresentationFlag, bool);
//@}

//@{
/// Get/Set real time flag
vtkGetMacro(RealTime, bool);
vtkSetMacro(RealTime, bool);
vtkBooleanMacro(RealTime, bool);
//@}

protected:
vtkMRMLIsodoseNode();
Expand All @@ -114,23 +132,30 @@ class VTK_SLICER_ISODOSE_MODULE_MRML_EXPORT vtkMRMLIsodoseNode : public vtkMRMLN
void SetDoseUnits(int id);

/// State of Show isodose lines checkbox
bool ShowIsodoseLines;
bool ShowIsodoseLines{true};

/// State of Show isodose surfaces checkbox
bool ShowIsodoseSurfaces;
bool ShowIsodoseSurfaces{true};

/// State of Show dose volumes only checkbox
bool ShowDoseVolumesOnly;
bool ShowDoseVolumesOnly{true};

/// Type of dose units
DoseUnitsType DoseUnits;
DoseUnitsType DoseUnits{DoseUnitsType::Unknown};

/// Reference dose value
double ReferenceDoseValue;
double ReferenceDoseValue{-1.};

/// Whether use relative isolevels representation
/// for absolute dose (Gy) and unknown units or not
bool RelativeRepresentationFlag;
bool RelativeRepresentationFlag{false};

/// Flag supporting real time applications, when there is strictly one set of isodose surfaces.
/// When this flag is enabled, the following functions are prevented: use of subject hierarchy to organize the isodose
/// model nodes, reporting of progress, batch processing, and update of dose color table from the isodose one.
/// Instead, top-level isodose model nodes are re-used (by node name) at every computation. It is useful when isodose is needed
/// to be computed on-the-fly for streamed dose data, when one set of isodose surfaces is all that is needed to be kept and displayed.
bool RealTime{false};
};

#endif

0 comments on commit 41bd6e5

Please sign in to comment.