Skip to content

Commit b99b16e

Browse files
author
Mikhail Polkovnikov
committed
DOC: initial ExternalBeamPlanning module description file added
1 parent a101663 commit b99b16e

File tree

8 files changed

+199
-87
lines changed

8 files changed

+199
-87
lines changed

Beams/Logic/vtkSlicerBeamsModuleLogic.cxx

+3-6
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ bool vtkSlicerBeamsModuleLogic::CreateArcBeamDynamicSequence(
409409

410410
vtkMRMLScene* scene = planNode->GetScene();
411411

412-
vtkMRMLSubjectHierarchyNode* shNode = vtkMRMLSubjectHierarchyNode::GetSubjectHierarchyNode(scene);
412+
vtkMRMLSubjectHierarchyNode* shNode = scene->GetSubjectHierarchyNode();
413413
if (!shNode)
414414
{
415415
vtkErrorMacro("CreateArcBeamDynamicSequence: Failed to access subject hierarchy node");
@@ -466,10 +466,7 @@ bool vtkSlicerBeamsModuleLogic::CreateArcBeamDynamicSequence(
466466
// SAD for RTPlan, source to beam limiting devices (Jaws, MLC)
467467
if (beamNode)
468468
{
469-
// beamNode->SetSAD(rtReader->GetBeamSourceAxisDistance(dicomBeamNumber));
470-
// beamNode->SetSourceToJawsDistanceX(rtReader->GetBeamSourceToJawsDistanceX(dicomBeamNumber));
471-
// beamNode->SetSourceToJawsDistanceY(rtReader->GetBeamSourceToJawsDistanceY(dicomBeamNumber));
472-
// beamNode->SetSourceToMultiLeafCollimatorDistance(rtReader->GetBeamSourceToMultiLeafCollimatorDistance(dicomBeamNumber));
469+
// TODO: Add beam parameters for each angle step
473470
}
474471

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

492489
vtkTransform* transform = vtkTransform::SafeDownCast(transformNode->GetTransformToParent());
493-
if (isocenter)
490+
if (transform)
494491
{
495492
// Actual translation to isocenter
496493
transform->Translate( isocenter[0], isocenter[1], isocenter[2]);

Beams/Logic/vtkSlicerBeamsModuleLogic.h

+15-15
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,24 @@ class VTK_SLICER_BEAMS_LOGIC_EXPORT vtkSlicerBeamsModuleLogic :
5454

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

6565
/// Create arc delivery beam sequence
66-
/// @param initialAngle - initial angle in degrees
67-
/// @param finalAngle - final angle in degrees
68-
/// @param angleStep - single angle step within arc
69-
/// @param direction - 0 - clockwise, 1 - counter-clockwise
70-
/// @param planNode - input plan node, which contains reference volume node and isocenter position
71-
/// @param sequenceBrowserNode - output sequence browser node
72-
/// @param sequenceBeamNode - output beam node
73-
/// @param sequenceTransformNode - output transform node
74-
bool CreateArcBeamDynamicSequence( double initialAngle, double finalAngle,
66+
/// \param initialAngle initial angle in degrees
67+
/// \param finalAngle final angle in degrees
68+
/// \param angleStep single angle step within arc
69+
/// \param direction 0 - clockwise, 1 - counter-clockwise
70+
/// \param planNode input plan node, which contains reference volume node and isocenter position
71+
/// \param sequenceBrowserNode output sequence browser node
72+
/// \param sequenceBeamNode output beam node
73+
/// \param sequenceTransformNode output transform node
74+
bool CreateArcBeamDynamicSequence(double initialAngle, double finalAngle,
7575
double angleStep, bool direction, vtkMRMLRTPlanNode* planNode,
7676
vtkMRMLSequenceBrowserNode* beamSequenceBrowserNode,
7777
vtkMRMLSequenceNode* beamSequenceNode, vtkMRMLSequenceNode* transformSequenceNode);
@@ -95,7 +95,7 @@ class VTK_SLICER_BEAMS_LOGIC_EXPORT vtkSlicerBeamsModuleLogic :
9595
vtkSlicerBeamsModuleLogic(const vtkSlicerBeamsModuleLogic&) = delete;
9696
void operator=(const vtkSlicerBeamsModuleLogic&) = delete;
9797

98-
vtkSlicerMLCPositionLogic* MLCPositionLogic;
98+
vtkSlicerMLCPositionLogic* MLCPositionLogic{ nullptr };
9999
};
100100

101101
#endif

DicomRtImportExport/Logic/vtkSlicerDicomRtReader.cxx

+2-3
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ class vtkSlicerDicomRtReader::vtkInternal
319319
std::string InstitutionalDepartmentName;
320320
std::string ManufacturerModelName;
321321
};
322-
322+
323323
/// List of loaded beams from external beam plan
324324
std::vector<BeamEntry> BeamSequenceVector;
325325

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

591591
res = point0 && point1;
592-
if (point0 && point1)
592+
if (res)
593593
{
594-
res = true;
595594
initialAngle = cp0.GantryAngle;
596595
finalAngle = cp1.GantryAngle;
597596
// rotation: 0 - clockwise, 1 - counter clockwise
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
## "External Beam Planning" module description
2+
3+
The ExternalBeamPlanning module is a generic, extensible module for forward
4+
planning of external beam radiation therapy treatments.
5+
6+
The "External Beam Planning" module is responsible for creating a beam plan or ion beam plan
7+
according to DICOM RT standard. Only a few basic features are supported.
8+
Each plan consists of a number of beams: static or dynamic. Each plan supports
9+
only one isocenter point, multiple isocenters per a single plan are not allowed.
10+
11+
This work was in part funded by An Applied Cancer Research Unit of Cancer Care Ontario
12+
with funds provided by the Ministry of Health and Long-Term Care and the Ontario Consortium
13+
for Adaptive Interventions in Radiation Oncology (OCAIRO) to provide free, open-source toolset
14+
for radiotherapy and related image-guided interventions.
15+
16+
Author: Csaba Pinter (PerkLab, Queen's University), Greg Sharp (Massachusetts General Hospital)
17+
Contact: Csaba Pinter, <email>[email protected]</email>
18+
19+
![image](https://www.slicer.org/w/img_auth.php/3/3f/LogoCco.png)
20+
![image](https://www.slicer.org/w/img_auth.php/2/27/LogoOCAIRO.jpg)
21+
22+
### Use Cases
23+
- Proton dose calculation
24+
- Any dose engine can be integrated (C++, Python, Matlab)
25+
26+
### Tutorials
27+
[Orthovoltage RT treatment planning tutorial](https://github.com/SlicerRt/SlicerRtDoc/blob/master/tutorials/SlicerRT_Tutorial_OrthovoltageDoseEngine.pptx) (uses EGSnrc)
28+
29+
### Graphical User Interface loadable module (GUI). Panels and their use
30+
31+
![image](https://user-images.githubusercontent.com/3785912/183899734-d4795313-fd39-4c40-8df6-e84f0469c3b0.png)
32+
33+
Loadable GUI module "External Beam Planning" is used to setup beam parameters
34+
for beams or ion beams, or modify already created beams.
35+
Static RT beam is setup by: Isocenter position, SAD, SID, Jaws borders, MLC positions. Static beam is fixed.
36+
37+
Dynamic RT and Ion RT beams are setup by: initial and final angles of rotation around gantry axis,
38+
direction of rotation, isocenter position, SAD, SID, Jaws borders, MLC positions, scanning spot map, etc.
39+
Dynamic beam changes it position over time by means of rotation or (and) changing the position of phase space of the beam.
40+
41+
#### Active RT plan
42+
43+
![image](https://user-images.githubusercontent.com/3785912/183899795-762b8b13-4ad5-4112-bcb6-e3f5fbd21fe2.png)
44+
45+
1. **Active RT plan**: Selected RT Plan
46+
2. **Ion plan**: flag to generate RTIonPlan instead of RTPlan
47+
48+
#### Plan parameters
49+
50+
![image](https://user-images.githubusercontent.com/3785912/183899832-fb178c71-900f-48d8-97a5-35c4d532bfb3.png)
51+
52+
1. **Reference volume**: Reference volume node data (usually CT)
53+
2. **Structure set**: Segmentation node data
54+
3. **Points of interest**: Markups fiducial to be used as isocenter
55+
4. **Isocenter**: Isocenter position in RAS
56+
5. **Center views**: Center slice views on isocenter
57+
6. **Target volume**: Select targer ROI
58+
7. **Isocenter at target center**: Set isocenter in the center of the targer ROI
59+
8. **Dose engine**: Select a dose engine calculator **Not implemented**
60+
9. **Rx Dose (Gy)**: Setup an amount of dose in Gy
61+
62+
#### Output
63+
64+
![image](https://user-images.githubusercontent.com/3785912/183899869-580d00a9-aa86-405d-b22c-d11a35f2f6df.png)
65+
66+
1. **Output dose volume**: Setup output dose volume
67+
2. **Clear dose**: Clear dose volume
68+
3. **Calculate WED**: Calculate water-equivalent distance **Not implemented**
69+
4. **Calculate Dose**: Calculate dose according to the engine parameters **Not implemented**
70+
71+
#### Beams
72+
73+
![image](https://user-images.githubusercontent.com/3785912/183899904-6f8e76fd-1574-462e-bf31-21f2cf5fa740.png)
74+
75+
1. **Arc beam sequence**: Activate dynamic beam arc movement around gantry rotation axis
76+
2. **Initial angle**: Initial angle position in degrees
77+
3. **Final angle**: Final angle position in degrees
78+
4. **Angle step**: Angle step
79+
5. **Rotation direction**: Clockwise (CW) of CounterClockwise (CCW) rotation
80+
5. **Add beam**: Add static or dynamic arc beam to the plan
81+
6. **Remove beam**: Remove selected beam from the plan
82+
83+
### Arc beam
84+
85+
The beam movement around rotation axis could be used to calculate a filtered back-projection reconstruction for cone-beam geometries.
86+
For fast forward and back projection reconstruction the [RTK](https://www.openrtk.org) library can be used.
87+
88+
### References
89+
90+
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.
91+
92+
### Information for Developers
93+
94+
- 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)
95+
- 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)
96+
- Future plans
97+
- Inverse planning capabilities
98+
- Matlab plugin adapter
99+
- Ports module (apertures, MLC, target volume)
100+
- Beam groups (common parameters for a group of beams)
101+

ExternalBeamPlanning/Resources/UI/qSlicerExternalBeamPlanningModule.ui

+61-55
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>483</width>
10-
<height>704</height>
9+
<width>485</width>
10+
<height>787</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -489,58 +489,7 @@
489489
<property name="spacing">
490490
<number>4</number>
491491
</property>
492-
<item row="1" column="0">
493-
<layout class="QHBoxLayout" name="horizontalLayout_6">
494-
<item>
495-
<widget class="QPushButton" name="pushButton_AddBeam">
496-
<property name="minimumSize">
497-
<size>
498-
<width>112</width>
499-
<height>0</height>
500-
</size>
501-
</property>
502-
<property name="text">
503-
<string>Add beam</string>
504-
</property>
505-
<property name="icon">
506-
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
507-
<normaloff>:/Icons/Add.png</normaloff>:/Icons/Add.png</iconset>
508-
</property>
509-
</widget>
510-
</item>
511-
<item>
512-
<spacer name="horizontalSpacer_3">
513-
<property name="orientation">
514-
<enum>Qt::Horizontal</enum>
515-
</property>
516-
<property name="sizeHint" stdset="0">
517-
<size>
518-
<width>40</width>
519-
<height>20</height>
520-
</size>
521-
</property>
522-
</spacer>
523-
</item>
524-
<item>
525-
<widget class="QPushButton" name="pushButton_RemoveBeam">
526-
<property name="minimumSize">
527-
<size>
528-
<width>112</width>
529-
<height>0</height>
530-
</size>
531-
</property>
532-
<property name="text">
533-
<string>Remove beam</string>
534-
</property>
535-
<property name="icon">
536-
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
537-
<normaloff>:/Icons/Remove.png</normaloff>:/Icons/Remove.png</iconset>
538-
</property>
539-
</widget>
540-
</item>
541-
</layout>
542-
</item>
543-
<item row="2" column="0">
492+
<item row="3" column="0">
544493
<widget class="qMRMLBeamsTableView" name="BeamsTableView">
545494
<property name="sizePolicy">
546495
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@@ -551,7 +500,7 @@
551500
</widget>
552501
</item>
553502
<item row="0" column="0">
554-
<widget class="QGroupBox" name="GroupBox_ArcBeamSequence">
503+
<widget class="ctkCollapsibleGroupBox" name="CollapsibleGroupBox_ArcBeamSequence">
555504
<property name="title">
556505
<string>Arc beam sequence</string>
557506
</property>
@@ -663,6 +612,57 @@
663612
</layout>
664613
</widget>
665614
</item>
615+
<item row="2" column="0">
616+
<layout class="QHBoxLayout" name="horizontalLayout_6">
617+
<item>
618+
<widget class="QPushButton" name="pushButton_AddBeam">
619+
<property name="minimumSize">
620+
<size>
621+
<width>112</width>
622+
<height>0</height>
623+
</size>
624+
</property>
625+
<property name="text">
626+
<string>Add beam</string>
627+
</property>
628+
<property name="icon">
629+
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
630+
<normaloff>:/Icons/Add.png</normaloff>:/Icons/Add.png</iconset>
631+
</property>
632+
</widget>
633+
</item>
634+
<item>
635+
<spacer name="horizontalSpacer_3">
636+
<property name="orientation">
637+
<enum>Qt::Horizontal</enum>
638+
</property>
639+
<property name="sizeHint" stdset="0">
640+
<size>
641+
<width>40</width>
642+
<height>20</height>
643+
</size>
644+
</property>
645+
</spacer>
646+
</item>
647+
<item>
648+
<widget class="QPushButton" name="pushButton_RemoveBeam">
649+
<property name="minimumSize">
650+
<size>
651+
<width>112</width>
652+
<height>0</height>
653+
</size>
654+
</property>
655+
<property name="text">
656+
<string>Remove beam</string>
657+
</property>
658+
<property name="icon">
659+
<iconset resource="../qSlicerExternalBeamPlanningModule.qrc">
660+
<normaloff>:/Icons/Remove.png</normaloff>:/Icons/Remove.png</iconset>
661+
</property>
662+
</widget>
663+
</item>
664+
</layout>
665+
</item>
666666
</layout>
667667
</widget>
668668
</item>
@@ -675,6 +675,12 @@
675675
<header>ctkCollapsibleButton.h</header>
676676
<container>1</container>
677677
</customwidget>
678+
<customwidget>
679+
<class>ctkCollapsibleGroupBox</class>
680+
<extends>QGroupBox</extends>
681+
<header>ctkCollapsibleGroupBox.h</header>
682+
<container>1</container>
683+
</customwidget>
678684
<customwidget>
679685
<class>ctkCoordinatesWidget</class>
680686
<extends>QWidget</extends>

ExternalBeamPlanning/Widgets/qSlicerDoseEngineLogic.cxx

+9
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,15 @@ vtkMRMLRTBeamNode* qSlicerDoseEngineLogic::createArcBeamInPlan( vtkMRMLRTPlanNod
534534
proxyBeamNode->SetAndObserveTransformNodeID(proxyTransformNode->GetID());
535535
return proxyBeamNode;
536536
}
537+
else
538+
{
539+
qWarning() << Q_FUNC_INFO << ": Proxy beam node or proxy transform node in beam sequence is invalid";
540+
}
537541
}
542+
else
543+
{
544+
qWarning() << Q_FUNC_INFO << ": Unable to create arc beam sequence";
545+
}
546+
538547
return nullptr;
539548
}

ExternalBeamPlanning/Widgets/qSlicerDoseEngineLogic.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ class Q_SLICER_MODULE_EXTERNALBEAMPLANNING_WIDGETS_EXPORT qSlicerDoseEngineLogic
7070
Q_INVOKABLE void removeIntermediateResults(vtkMRMLRTPlanNode* planNode);
7171

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

0 commit comments

Comments
 (0)