Skip to content

Commit

Permalink
DOC: initial ExternalBeamPlanning module description file added
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikhail Polkovnikov committed Aug 10, 2022
1 parent a101663 commit b99b16e
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 87 deletions.
9 changes: 3 additions & 6 deletions Beams/Logic/vtkSlicerBeamsModuleLogic.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ bool vtkSlicerBeamsModuleLogic::CreateArcBeamDynamicSequence(

vtkMRMLScene* scene = planNode->GetScene();

vtkMRMLSubjectHierarchyNode* shNode = vtkMRMLSubjectHierarchyNode::GetSubjectHierarchyNode(scene);
vtkMRMLSubjectHierarchyNode* shNode = scene->GetSubjectHierarchyNode();
if (!shNode)
{
vtkErrorMacro("CreateArcBeamDynamicSequence: Failed to access subject hierarchy node");
Expand Down Expand Up @@ -466,10 +466,7 @@ bool vtkSlicerBeamsModuleLogic::CreateArcBeamDynamicSequence(
// SAD for RTPlan, source to beam limiting devices (Jaws, MLC)
if (beamNode)
{
// beamNode->SetSAD(rtReader->GetBeamSourceAxisDistance(dicomBeamNumber));
// beamNode->SetSourceToJawsDistanceX(rtReader->GetBeamSourceToJawsDistanceX(dicomBeamNumber));
// beamNode->SetSourceToJawsDistanceY(rtReader->GetBeamSourceToJawsDistanceY(dicomBeamNumber));
// beamNode->SetSourceToMultiLeafCollimatorDistance(rtReader->GetBeamSourceToMultiLeafCollimatorDistance(dicomBeamNumber));
// TODO: Add beam parameters for each angle step
}

// Add beam to beam sequence node
Expand All @@ -490,7 +487,7 @@ bool vtkSlicerBeamsModuleLogic::CreateArcBeamDynamicSequence(
this->UpdateTransformForBeam( beamSequenceNode->GetSequenceScene(), beamNode, transformNode, isocenter);

vtkTransform* transform = vtkTransform::SafeDownCast(transformNode->GetTransformToParent());
if (isocenter)
if (transform)
{
// Actual translation to isocenter
transform->Translate( isocenter[0], isocenter[1], isocenter[2]);
Expand Down
30 changes: 15 additions & 15 deletions Beams/Logic/vtkSlicerBeamsModuleLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,24 +54,24 @@ class VTK_SLICER_BEAMS_LOGIC_EXPORT vtkSlicerBeamsModuleLogic :

/// Update parent transform of a given beam using its parameters and the IEC logic
/// without using plan node (only isocenter position)
/// @param beamSequenceScene - inner scene of the beam sequence node
/// @param beamNode - a current beam node (must be added to the beam sequence node beforehand)
/// @param beamTransformNode - parent transform of the beam according to the beam parameters and isocenter
/// @param isocenter - isocenter position
/// \param beamSequenceScene inner scene of the beam sequence node
/// \param beamNode a current beam node (must be added to the beam sequence node beforehand)
/// \param beamTransformNode parent transform of the beam according to the beam parameters and isocenter
/// \param isocenter isocenter position
/// \warning This method is used only in vtkSlicerDicomRtImportExportModuleLogic::vtkInternal::LoadDynamicBeamSequence
void UpdateTransformForBeam( vtkMRMLScene* beamSequenceScene, vtkMRMLRTBeamNode* beamNode,
void UpdateTransformForBeam(vtkMRMLScene* beamSequenceScene, vtkMRMLRTBeamNode* beamNode,
vtkMRMLLinearTransformNode* beamTransformNode, double isocenter[3]);

/// Create arc delivery beam sequence
/// @param initialAngle - initial angle in degrees
/// @param finalAngle - final angle in degrees
/// @param angleStep - single angle step within arc
/// @param direction - 0 - clockwise, 1 - counter-clockwise
/// @param planNode - input plan node, which contains reference volume node and isocenter position
/// @param sequenceBrowserNode - output sequence browser node
/// @param sequenceBeamNode - output beam node
/// @param sequenceTransformNode - output transform node
bool CreateArcBeamDynamicSequence( double initialAngle, double finalAngle,
/// \param initialAngle initial angle in degrees
/// \param finalAngle final angle in degrees
/// \param angleStep single angle step within arc
/// \param direction 0 - clockwise, 1 - counter-clockwise
/// \param planNode input plan node, which contains reference volume node and isocenter position
/// \param sequenceBrowserNode output sequence browser node
/// \param sequenceBeamNode output beam node
/// \param sequenceTransformNode output transform node
bool CreateArcBeamDynamicSequence(double initialAngle, double finalAngle,
double angleStep, bool direction, vtkMRMLRTPlanNode* planNode,
vtkMRMLSequenceBrowserNode* beamSequenceBrowserNode,
vtkMRMLSequenceNode* beamSequenceNode, vtkMRMLSequenceNode* transformSequenceNode);
Expand All @@ -95,7 +95,7 @@ class VTK_SLICER_BEAMS_LOGIC_EXPORT vtkSlicerBeamsModuleLogic :
vtkSlicerBeamsModuleLogic(const vtkSlicerBeamsModuleLogic&) = delete;
void operator=(const vtkSlicerBeamsModuleLogic&) = delete;

vtkSlicerMLCPositionLogic* MLCPositionLogic;
vtkSlicerMLCPositionLogic* MLCPositionLogic{ nullptr };
};

#endif
Expand Down
5 changes: 2 additions & 3 deletions DicomRtImportExport/Logic/vtkSlicerDicomRtReader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ class vtkSlicerDicomRtReader::vtkInternal
std::string InstitutionalDepartmentName;
std::string ManufacturerModelName;
};

/// List of loaded beams from external beam plan
std::vector<BeamEntry> BeamSequenceVector;

Expand Down Expand Up @@ -589,9 +589,8 @@ bool vtkSlicerDicomRtReader::vtkInternal::BeamEntry::IsArcDeliverySequence(
(cp1.GantryAngle >= 0. && cp1.GantryAngle <= 360.);

res = point0 && point1;
if (point0 && point1)
if (res)
{
res = true;
initialAngle = cp0.GantryAngle;
finalAngle = cp1.GantryAngle;
// rotation: 0 - clockwise, 1 - counter clockwise
Expand Down
101 changes: 101 additions & 0 deletions Docs/user_guide/modules/externalbeamplanning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
## "External Beam Planning" module description

The ExternalBeamPlanning module is a generic, extensible module for forward
planning of external beam radiation therapy treatments.

The "External Beam Planning" module is responsible for creating a beam plan or ion beam plan
according to DICOM RT standard. Only a few basic features are supported.
Each plan consists of a number of beams: static or dynamic. Each plan supports
only one isocenter point, multiple isocenters per a single plan are not allowed.

This work was in part funded by An Applied Cancer Research Unit of Cancer Care Ontario
with funds provided by the Ministry of Health and Long-Term Care and the Ontario Consortium
for Adaptive Interventions in Radiation Oncology (OCAIRO) to provide free, open-source toolset
for radiotherapy and related image-guided interventions.

Author: Csaba Pinter (PerkLab, Queen's University), Greg Sharp (Massachusetts General Hospital)
Contact: Csaba Pinter, <email>[email protected]</email>

![image](https://www.slicer.org/w/img_auth.php/3/3f/LogoCco.png)
![image](https://www.slicer.org/w/img_auth.php/2/27/LogoOCAIRO.jpg)

### Use Cases
- Proton dose calculation
- Any dose engine can be integrated (C++, Python, Matlab)

### Tutorials
[Orthovoltage RT treatment planning tutorial](https://github.com/SlicerRt/SlicerRtDoc/blob/master/tutorials/SlicerRT_Tutorial_OrthovoltageDoseEngine.pptx) (uses EGSnrc)

### Graphical User Interface loadable module (GUI). Panels and their use

![image](https://user-images.githubusercontent.com/3785912/183899734-d4795313-fd39-4c40-8df6-e84f0469c3b0.png)

Loadable GUI module "External Beam Planning" is used to setup beam parameters
for beams or ion beams, or modify already created beams.
Static RT beam is setup by: Isocenter position, SAD, SID, Jaws borders, MLC positions. Static beam is fixed.

Dynamic RT and Ion RT beams are setup by: initial and final angles of rotation around gantry axis,
direction of rotation, isocenter position, SAD, SID, Jaws borders, MLC positions, scanning spot map, etc.
Dynamic beam changes it position over time by means of rotation or (and) changing the position of phase space of the beam.

#### Active RT plan

![image](https://user-images.githubusercontent.com/3785912/183899795-762b8b13-4ad5-4112-bcb6-e3f5fbd21fe2.png)

1. **Active RT plan**: Selected RT Plan
2. **Ion plan**: flag to generate RTIonPlan instead of RTPlan

#### Plan parameters

![image](https://user-images.githubusercontent.com/3785912/183899832-fb178c71-900f-48d8-97a5-35c4d532bfb3.png)

1. **Reference volume**: Reference volume node data (usually CT)
2. **Structure set**: Segmentation node data
3. **Points of interest**: Markups fiducial to be used as isocenter
4. **Isocenter**: Isocenter position in RAS
5. **Center views**: Center slice views on isocenter
6. **Target volume**: Select targer ROI
7. **Isocenter at target center**: Set isocenter in the center of the targer ROI
8. **Dose engine**: Select a dose engine calculator **Not implemented**
9. **Rx Dose (Gy)**: Setup an amount of dose in Gy

#### Output

![image](https://user-images.githubusercontent.com/3785912/183899869-580d00a9-aa86-405d-b22c-d11a35f2f6df.png)

1. **Output dose volume**: Setup output dose volume
2. **Clear dose**: Clear dose volume
3. **Calculate WED**: Calculate water-equivalent distance **Not implemented**
4. **Calculate Dose**: Calculate dose according to the engine parameters **Not implemented**

#### Beams

![image](https://user-images.githubusercontent.com/3785912/183899904-6f8e76fd-1574-462e-bf31-21f2cf5fa740.png)

1. **Arc beam sequence**: Activate dynamic beam arc movement around gantry rotation axis
2. **Initial angle**: Initial angle position in degrees
3. **Final angle**: Final angle position in degrees
4. **Angle step**: Angle step
5. **Rotation direction**: Clockwise (CW) of CounterClockwise (CCW) rotation
5. **Add beam**: Add static or dynamic arc beam to the plan
6. **Remove beam**: Remove selected beam from the plan

### Arc beam

The beam movement around rotation axis could be used to calculate a filtered back-projection reconstruction for cone-beam geometries.
For fast forward and back projection reconstruction the [RTK](https://www.openrtk.org) library can be used.

### References

1. Sharp, G., Pinter, C., Unkelbach, J., Fichtinger, G. (2017). Open Source Proton Treatment Planning in 3D Slicer: Status Update. Proceedings to the 56 Annual Meeting of the Particle Therapy Cooperative Group (PTCOG), 8-13 May 2017. International Journal of Particle Therapy: Summer 2017, Vol. 4, No. 1, pp. 14-83.

### Information for Developers

- Sample C++ dose engine: [https://github.com/SlicerRt/SlicerRT/blob/master/ExternalBeamPlanning/Widgets/qSlicerMockDoseEngine.h](https://github.com/SlicerRt/SlicerRT/blob/master/ExternalBeamPlanning/Widgets/qSlicerMockDoseEngine.h)
- Sample Python dose engine: [https://github.com/SlicerRt/SlicerRT/blob/master/ExternalBeamPlanning/Widgets/Python/MockPythonDoseEngine.py](https://github.com/SlicerRt/SlicerRT/blob/master/ExternalBeamPlanning/Widgets/Python/MockPythonDoseEngine.py)
- Future plans
- Inverse planning capabilities
- Matlab plugin adapter
- Ports module (apertures, MLC, target volume)
- Beam groups (common parameters for a group of beams)

116 changes: 61 additions & 55 deletions ExternalBeamPlanning/Resources/UI/qSlicerExternalBeamPlanningModule.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>483</width>
<height>704</height>
<width>485</width>
<height>787</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -489,58 +489,7 @@
<property name="spacing">
<number>4</number>
</property>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="pushButton_AddBeam">
<property name="minimumSize">
<size>
<width>112</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Add beam</string>
</property>
<property name="icon">
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
<normaloff>:/Icons/Add.png</normaloff>:/Icons/Add.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_RemoveBeam">
<property name="minimumSize">
<size>
<width>112</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Remove beam</string>
</property>
<property name="icon">
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
<normaloff>:/Icons/Remove.png</normaloff>:/Icons/Remove.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="qMRMLBeamsTableView" name="BeamsTableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
Expand All @@ -551,7 +500,7 @@
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="GroupBox_ArcBeamSequence">
<widget class="ctkCollapsibleGroupBox" name="CollapsibleGroupBox_ArcBeamSequence">
<property name="title">
<string>Arc beam sequence</string>
</property>
Expand Down Expand Up @@ -663,6 +612,57 @@
</layout>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QPushButton" name="pushButton_AddBeam">
<property name="minimumSize">
<size>
<width>112</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Add beam</string>
</property>
<property name="icon">
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
<normaloff>:/Icons/Add.png</normaloff>:/Icons/Add.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_RemoveBeam">
<property name="minimumSize">
<size>
<width>112</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Remove beam</string>
</property>
<property name="icon">
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
<normaloff>:/Icons/Remove.png</normaloff>:/Icons/Remove.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
Expand All @@ -675,6 +675,12 @@
<header>ctkCollapsibleButton.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ctkCollapsibleGroupBox</class>
<extends>QGroupBox</extends>
<header>ctkCollapsibleGroupBox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ctkCoordinatesWidget</class>
<extends>QWidget</extends>
Expand Down
9 changes: 9 additions & 0 deletions ExternalBeamPlanning/Widgets/qSlicerDoseEngineLogic.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,15 @@ vtkMRMLRTBeamNode* qSlicerDoseEngineLogic::createArcBeamInPlan( vtkMRMLRTPlanNod
proxyBeamNode->SetAndObserveTransformNodeID(proxyTransformNode->GetID());
return proxyBeamNode;
}
else
{
qWarning() << Q_FUNC_INFO << ": Proxy beam node or proxy transform node in beam sequence is invalid";
}
}
else
{
qWarning() << Q_FUNC_INFO << ": Unable to create arc beam sequence";
}

return nullptr;
}
12 changes: 6 additions & 6 deletions ExternalBeamPlanning/Widgets/qSlicerDoseEngineLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ class Q_SLICER_MODULE_EXTERNALBEAMPLANNING_WIDGETS_EXPORT qSlicerDoseEngineLogic
Q_INVOKABLE void removeIntermediateResults(vtkMRMLRTPlanNode* planNode);

/// Create a beam for a plan (with beam parameters defined by the dose engine of the plan)
/// @param planNode - node of the current plan
/// \param planNode node of the current plan
Q_INVOKABLE vtkMRMLRTBeamNode* createBeamInPlan(vtkMRMLRTPlanNode* planNode);
/// Create a beam for a RT plan (with beam parameters defined by the dose engine of the plan)
/// @param planNode - node of the current plan
/// @param initialAngle - initial angle
/// @param finalAngle - final angle
/// @param stepAngle - step angle
/// @param direction - rotation direction (0 == CW, 1 == CCW)
/// \param planNode node of the current plan
/// \param initialAngle initial angle
/// \param finalAngle final angle
/// \param stepAngle step angle
/// \param direction rotation direction (0 == CW, 1 == CCW)
Q_INVOKABLE vtkMRMLRTBeamNode* createArcBeamInPlan(vtkMRMLRTPlanNode* planNode,
double initialAngle = 0., double finalAngle = 360., double stepAngle = 1., bool rotationDirection = false);

Expand Down
Loading

0 comments on commit b99b16e

Please sign in to comment.