rtkit 0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,157 @@
1
+ module RTKIT
2
+
3
+ # Contains DICOM data and methods related to a RT Beam Limiting Device
4
+ # item, defined in a Beam.
5
+ #
6
+ # === Relations
7
+ #
8
+ # * A Beam has many Collimators.
9
+ #
10
+ class Collimator
11
+
12
+ # The Beam that the CollimatorSetup is defined for.
13
+ attr_reader :beam
14
+ # Collimator boundaries (for multi leaf collimators only: the number of boundaries equals the number of leaves + 1).
15
+ attr_reader :boundaries
16
+ # The number of Leaf/Jaw (Collimator) Pairs.
17
+ attr_reader :num_pairs
18
+ # Collimator type.
19
+ attr_reader :type
20
+
21
+ # Creates a new Collimator instance from the RT Beam Limiting Device item of the RTPlan file.
22
+ # Returns the Collimator instance.
23
+ #
24
+ # === Parameters
25
+ #
26
+ # * <tt>coll_item</tt> -- The patient setup item from the DObject of a RTPlan file.
27
+ # * <tt>beam</tt> -- The Beam instance that this Collimator belongs to.
28
+ #
29
+ def self.create_from_item(coll_item, beam)
30
+ raise ArgumentError, "Invalid argument 'coll_item'. Expected DICOM::Item, got #{coll_item.class}." unless coll_item.is_a?(DICOM::Item)
31
+ raise ArgumentError, "Invalid argument 'beam'. Expected Beam, got #{beam.class}." unless beam.is_a?(Beam)
32
+ options = Hash.new
33
+ # Values from the Beam Limiting Device Type Item:
34
+ type = coll_item.value(COLL_TYPE)
35
+ num_pairs = coll_item.value(NR_COLLIMATORS)
36
+ boundaries = coll_item.value(COLL_BOUNDARIES)
37
+ # Create the Collimator instance:
38
+ c = self.new(type, num_pairs, beam, :boundaries => boundaries)
39
+ return c
40
+ end
41
+
42
+ # Creates a new Collimator instance.
43
+ #
44
+ # === Parameters
45
+ #
46
+ # * <tt>type</tt> -- String. The RT Beam Limiting Device Type.
47
+ # * <tt>num_pairs</tt> -- Integer. The Number of Leaf/Jaw Pairs.
48
+ # * <tt>beam</tt> -- The Beam instance that this Collimator belongs to.
49
+ # * <tt>options</tt> -- A hash of parameters.
50
+ #
51
+ # === Options
52
+ #
53
+ # * <tt>:boundaries</tt> -- Array/String. The Leaf Position Boundaries (300A,00BE). Defaults to nil.
54
+ #
55
+ def initialize(type, num_pairs, beam, options={})
56
+ raise ArgumentError, "Invalid argument 'beam'. Expected Beam, got #{beam.class}." unless beam.is_a?(Beam)
57
+ # Set values:
58
+ self.type = type
59
+ self.num_pairs = num_pairs
60
+ self.boundaries = options[:boundaries]
61
+ # Set references:
62
+ @beam = beam
63
+ # Register ourselves with the Beam:
64
+ @beam.add_collimator(self)
65
+ end
66
+
67
+ # Returns true if the argument is an instance with attributes equal to self.
68
+ #
69
+ def ==(other)
70
+ if other.respond_to?(:to_collimator)
71
+ other.send(:state) == state
72
+ end
73
+ end
74
+
75
+ alias_method :eql?, :==
76
+
77
+ # Generates a Fixnum hash value for this instance.
78
+ #
79
+ def hash
80
+ state.hash
81
+ end
82
+
83
+ # Creates and returns a Beam Limiting Device Sequence Item
84
+ # from the attributes of the Collimator.
85
+ #
86
+ def to_item
87
+ item = DICOM::Item.new
88
+ item.add(DICOM::Element.new(ROI_COLOR, @color))
89
+ s = DICOM::Sequence.new(CONTOUR_SQ)
90
+ item.add(s)
91
+ item.add(DICOM::Element.new(REF_ROI_NUMBER, @number.to_s))
92
+ # Add Contour items to the Contour Sequence (one or several items per Slice):
93
+ @slices.each do |slice|
94
+ slice.contours.each do |contour|
95
+ s.add_item(contour.to_item)
96
+ end
97
+ end
98
+ return item
99
+ end
100
+
101
+ # Sets new Leaf Position Boundaries (an array of positions).
102
+ #
103
+ # === Parameters
104
+ #
105
+ # * <tt>value</tt> -- Array/String. The Leaf Position Boundaries (300A,00BE).
106
+ #
107
+ def boundaries=(value)
108
+ if !value
109
+ @boundaries = nil
110
+ elsif value.is_a?(Array)
111
+ @boundaries = value
112
+ else
113
+ # Split the string & convert to float:
114
+ @boundaries = value.to_s.split("\\").collect {|str| str.to_f}
115
+ end
116
+ end
117
+
118
+ # Sets a new RT Beam Limiting Device Type.
119
+ #
120
+ # === Parameters
121
+ #
122
+ # * <tt>value</tt> -- Integer. The Number of Leaf/Jaw Pairs (300A,00BC).
123
+ #
124
+ def num_pairs=(value)
125
+ raise ArgumentError, "Argument 'value' must be defined (got #{value.class})." unless value
126
+ @num_pairs = value.to_i
127
+ end
128
+
129
+ # Returns self.
130
+ #
131
+ def to_collimator
132
+ self
133
+ end
134
+
135
+ # Sets a new RT Beam Limiting Device Type.
136
+ #
137
+ # === Parameters
138
+ #
139
+ # * <tt>value</tt> -- String. The RT Beam Limiting Device Type (300A,00B8).
140
+ #
141
+ def type=(value)
142
+ raise ArgumentError, "Argument 'value' must be defined (got #{value.class})." unless value
143
+ @type = value.to_s
144
+ end
145
+
146
+
147
+ private
148
+
149
+
150
+ # Returns the attributes of this instance in an array (for comparison purposes).
151
+ #
152
+ def state
153
+ [@boundaries, @num_pairs, @type]
154
+ end
155
+
156
+ end
157
+ end
@@ -0,0 +1,143 @@
1
+ module RTKIT
2
+
3
+ # Contains DICOM data and methods related to a RT Beam Limiting Device
4
+ # Position item, defined in a ControlPoint.
5
+ #
6
+ # === Relations
7
+ #
8
+ # * A ControlPoint has many CollimatorSetups.
9
+ #
10
+ class CollimatorSetup
11
+
12
+ # The ControlPoint that the Collimator is defined for.
13
+ attr_reader :control_point
14
+ # Collimator pairs of positions.
15
+ attr_reader :positions
16
+ # Collimator type.
17
+ attr_reader :type
18
+
19
+ # Creates a new CollimatorSetup instance from the RT Beam Limiting Device Position item of the RTPlan file.
20
+ # Returns the CollimatorSetup instance.
21
+ #
22
+ # === Parameters
23
+ #
24
+ # * <tt>coll_item</tt> -- The RT Beam Limiting Device Position item from the DObject of a RTPlan file.
25
+ # * <tt>control_point</tt> -- The ControlPoint instance that this CollimatorSetup belongs to.
26
+ #
27
+ def self.create_from_item(coll_item, control_point)
28
+ raise ArgumentError, "Invalid argument 'coll_item'. Expected DICOM::Item, got #{coll_item.class}." unless coll_item.is_a?(DICOM::Item)
29
+ raise ArgumentError, "Invalid argument 'control_point'. Expected ControlPoint, got #{control_point.class}." unless control_point.is_a?(ControlPoint)
30
+ options = Hash.new
31
+ # Values from the Beam Limiting Device Position Item:
32
+ type = coll_item.value(COLL_TYPE)
33
+ positions = coll_item.value(COLL_POS)
34
+ #positions = coll_item.value(COLL_POS).split("\\").collect {|str| str.to_f}
35
+ # Regroup the positions values so they appear in pairs:
36
+ #positions = positions.each_slice(2).collect{|i| i}.transpose
37
+ # Create the Collimator instance:
38
+ c = self.new(type, positions, control_point)
39
+ return c
40
+ end
41
+
42
+ # Creates a new CollimatorSetup instance.
43
+ #
44
+ # === Parameters
45
+ #
46
+ # * <tt>type</tt> -- String. The RT Beam Limiting Device Type.
47
+ # * <tt>positions</tt> -- Array. The collimator positions, organised in pairs of two values.
48
+ # * <tt>control_point</tt> -- The ControlPoint instance that this CollimatorSetup belongs to.
49
+ #
50
+ def initialize(type, positions, control_point)
51
+ raise ArgumentError, "Invalid argument 'control_point'. Expected ControlPoint, got #{control_point.class}." unless control_point.is_a?(ControlPoint)
52
+ # Set values:
53
+ self.type = type
54
+ self.positions = positions
55
+ # Set references:
56
+ @control_point = control_point
57
+ # Register ourselves with the ControlPoint:
58
+ @control_point.add_collimator(self)
59
+ end
60
+
61
+ # Returns true if the argument is an instance with attributes equal to self.
62
+ #
63
+ def ==(other)
64
+ if other.respond_to?(:to_collimator_setup)
65
+ other.send(:state) == state
66
+ end
67
+ end
68
+
69
+ alias_method :eql?, :==
70
+
71
+ # Generates a Fixnum hash value for this instance.
72
+ #
73
+ def hash
74
+ state.hash
75
+ end
76
+
77
+ # Sets new Leaf/Jaw Positions (an array with pairs of positions).
78
+ #
79
+ # === Parameters
80
+ #
81
+ # * <tt>value</tt> -- Array. The Leaf/Jaw positions (300A,011C).
82
+ #
83
+ def positions=(value)
84
+ raise ArgumentError, "Argument 'value' must be defined (got #{value.class})." unless value
85
+ if value.is_a?(Array)
86
+ @positions = value
87
+ else
88
+ # Split the string, convert to float, and regroup the positions so they appear in pairs:
89
+ positions = value.to_s.split("\\").collect {|str| str.to_f}
90
+ if positions.length == 2
91
+ @positions = [positions]
92
+ else
93
+ @positions = positions.each_slice(2).collect{|i| i}.transpose
94
+ end
95
+ end
96
+ end
97
+
98
+ # Returns self.
99
+ #
100
+ def to_collimator_setup
101
+ self
102
+ end
103
+
104
+ # Creates and returns a Beam Limiting Device Position Sequence Item
105
+ # from the attributes of the CollimatorSetup.
106
+ #
107
+ def to_item
108
+ item = DICOM::Item.new
109
+ item.add(DICOM::Element.new(COLL_TYPE, @type))
110
+ item.add(DICOM::Element.new(COLL_POS, positions_string))
111
+ return item
112
+ end
113
+
114
+ # Sets a new RT Beam Limiting Device Type.
115
+ #
116
+ # === Parameters
117
+ #
118
+ # * <tt>value</tt> -- String. The RT Beam Limiting Device Type (300A,00B8).
119
+ #
120
+ def type=(value)
121
+ raise ArgumentError, "Argument 'value' must be defined (got #{value.class})." unless value
122
+ @type = value.to_s
123
+ end
124
+
125
+
126
+ private
127
+
128
+
129
+ # Returns the position values converted to a '\' separated string with values
130
+ # appearing in the order as specified by the dicom standard.
131
+ #
132
+ def positions_string
133
+ @positions.transpose.join("\\")
134
+ end
135
+
136
+ # Returns the attributes of this instance in an array (for comparison purposes).
137
+ #
138
+ def state
139
+ [@positions, @type]
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,215 @@
1
+ module RTKIT
2
+
3
+ # Instance Creation Date.
4
+ IMAGE_DATE = '0008,0012'
5
+ # Instance Creation Time.
6
+ IMAGE_TIME = '0008,0013'
7
+ # SOP Class UID.
8
+ SOP_CLASS = '0008,0016'
9
+ # SOP Instance UID.
10
+ SOP_UID = '0008,0018'
11
+ # Study Date.
12
+ STUDY_DATE = '0008,0020'
13
+ # Series Date.
14
+ SERIES_DATE = '0008,0021'
15
+ # Study Time.
16
+ STUDY_TIME = '0008,0030'
17
+ # Series Time.
18
+ SERIES_TIME = '0008,0031'
19
+ # Modality.
20
+ MODALITY = '0008,0060'
21
+ # Study description.
22
+ STUDY_DESCR = '0008,1030'
23
+ # Series description.
24
+ SERIES_DESCR = '0008,103E'
25
+ # Referenced SOP Class UID.
26
+ REF_SOP_CLASS_UID = '0008,1150'
27
+ # Referenced SOP Instance UID.
28
+ REF_SOP_UID = '0008,1155'
29
+ # Patient's Name.
30
+ PATIENTS_NAME = '0010,0010'
31
+ # Patient's Name.
32
+ PATIENTS_ID = '0010,0020'
33
+ # Patient's Name.
34
+ BIRTH_DATE = '0010,0030'
35
+ # Patient's Name.
36
+ SEX = '0010,0040'
37
+ # Patient Position.
38
+ PATIENT_POSITION = '0018,5100'
39
+ # Study Instance UID.
40
+ STUDY_UID = '0020,000D'
41
+ # Series Instance UID.
42
+ SERIES_UID = '0020,000E'
43
+ # Study ID.
44
+ STUDY_ID = '0020,0010'
45
+ # Image Position (Patient).
46
+ IMAGE_POSITION = '0020,0032'
47
+ # Image Orientation (Patient):
48
+ IMAGE_ORIENTATION = '0020,0037'
49
+ # Frame of Reference UID.
50
+ FRAME_OF_REF = '0020,0052'
51
+ # Position Reference Indicator.
52
+ POS_REF_INDICATOR = '0020,1040'
53
+ # Number of Frames.
54
+ NR_FRAMES = '0028,0008'
55
+ # Rows.
56
+ ROWS = '0028,0010'
57
+ # Columns.
58
+ COLUMNS = '0028,0011'
59
+ # Pixel Spacing.
60
+ SPACING = '0028,0030'
61
+ # Image Plane Pixel Spacing.
62
+ IMAGE_PLANE_SPACING = '3002,0011'
63
+ # RT Image Position.
64
+ RT_IMAGE_POSITION = '3002,0012'
65
+ # Grid Frame Offset Vector.
66
+ GRID_FRAME_OFFSETS = '3004,000C'
67
+ # Dose Grid Scaling.
68
+ DOSE_GRID_SCALING = '3004,000E'
69
+ # Referenced Frame of Reference Sequence.
70
+ REF_FRAME_OF_REF_SQ = '3006,0010'
71
+ # RT Referenced Study Sequence.
72
+ RT_REF_STUDY_SQ = '3006,0012'
73
+ # RT Referenced Series Sequence.
74
+ RT_REF_SERIES_SQ = '3006,0014'
75
+ # Contour Image Sequence.
76
+ CONTOUR_IMAGE_SQ = '3006,0016'
77
+ # Structure Set ROI Sequence.
78
+ STRUCTURE_SET_ROI_SQ = '3006,0020'
79
+ # ROI Number.
80
+ ROI_NUMBER = '3006,0022'
81
+ # Referenced Frame of Reference UID.
82
+ REF_FRAME_OF_REF = '3006,0024'
83
+ # ROI Name.
84
+ ROI_NAME = '3006,0026'
85
+ # ROI Display Color.
86
+ ROI_COLOR = '3006,002A'
87
+ # ROI Generation Algorithm.
88
+ ROI_ALGORITHM = '3006,0036'
89
+ # ROI Contour Sequence.
90
+ ROI_CONTOUR_SQ = '3006,0039'
91
+ # Contour Sequence.
92
+ CONTOUR_SQ = '3006,0040'
93
+ # Contour Geometric Type.
94
+ CONTOUR_GEO_TYPE = '3006,0042'
95
+ # Number of Contour Points.
96
+ NR_CONTOUR_POINTS = '3006,0046'
97
+ # Contour Number.
98
+ CONTOUR_NUMBER = '3006,0048'
99
+ # Contour Data.
100
+ CONTOUR_DATA = '3006,0050'
101
+ # RT ROI Observations Sequence.
102
+ RT_ROI_OBS_SQ = '3006,0080'
103
+ # Obervation Number.
104
+ OBS_NUMBER = '3006,0082'
105
+ # Referenced ROI Number.
106
+ REF_ROI_NUMBER = '3006,0084'
107
+ # RT ROI Interpreted Type.
108
+ ROI_TYPE = '3006,00A4'
109
+ # ROI Interpreter.
110
+ ROI_INTERPRETER = '3006,00A6'
111
+ # Frame of Reference Relationship Sequence.
112
+ FRAME_OF_REF_REL_SQ = '3006,00C0'
113
+ # Fraction Group Sequence.
114
+ FRACTION_GROUP_SQ = '300A,0070'
115
+ # Fraction Group Number.
116
+ FRACTION_GROUP_NUMBER = '300A,0071'
117
+ # Beam Meterset.
118
+ BEAM_METERSET = '300A,0086'
119
+ # Beam Sequence.
120
+ BEAM_SQ = '300A,00B0'
121
+ # Treatment Machine Name.
122
+ MACHINE_NAME = '300A,00B2'
123
+ # Primary Dosimeter Unit.
124
+ DOSIMETER_UNIT = '300A,00B3'
125
+ # Source-Axis Distance.
126
+ SAD = '300A,00B4'
127
+ # RT Beam Limiting Device Sequence.
128
+ COLL_SQ = '300A,00B6'
129
+ # RT Beam Limiting Device Type.
130
+ COLL_TYPE = '300A,00B8'
131
+ # Number of Leaf/Jaw Pairs.
132
+ NR_COLLIMATORS = '300A,00BC'
133
+ # Leaf Position Boundaries.
134
+ COLL_BOUNDARIES = '300A,00BE'
135
+ # Beam Number.
136
+ BEAM_NUMBER = '300A,00C0'
137
+ # Beam Name.
138
+ BEAM_NAME = '300A,00C2'
139
+ # Beam Description.
140
+ BEAM_DESCR = '300A,00C3'
141
+ # Beam Type.
142
+ BEAM_TYPE = '300A,00C4'
143
+ # Radiation Type.
144
+ RAD_TYPE = '300A,00C6'
145
+ # Treatment Delivery Type.
146
+ DELIVERY_TYPE = '300A,00CE'
147
+ # Final Cumulative Meterset Weight.
148
+ FINAL_METERSET_WEIGHT = '300A,010E'
149
+ # Control Point Sequence.
150
+ CONTROL_POINT_SQ = '300A,0111'
151
+ # Cumulative Meterset Weight.
152
+ CONTROL_POINT_INDEX = '300A,0112'
153
+ # Nominal Beam Energy.
154
+ BEAM_ENERGY = '300A,0114'
155
+ # RT Beam Limiting Device Type Sequence.
156
+ COLL_POS_SQ = '300A,011A'
157
+ # Leaf/Jaw Positions.
158
+ COLL_POS = '300A,011C'
159
+ # Gantry Angle.
160
+ GANTRY_ANGLE = '300A,011E'
161
+ # Gantry Rotation Direction.
162
+ GANTRY_DIRECTION = '300A,011F'
163
+ # Beam Limiting Device Angle.
164
+ COLL_ANGLE = '300A,0120'
165
+ # Beam Limiting Device Rotation Direction.
166
+ COLL_DIRECTION = '300A,0121'
167
+ # Patient Support Angle.
168
+ PEDESTAL_ANGLE = '300A,0122'
169
+ # Patient Support Rotation Direction.
170
+ PEDESTAL_DIRECTION = '300A,0123'
171
+ # Table Top Eccentric Angle.
172
+ TABLE_TOP_ANGLE = '300A,0125'
173
+ # Table Top Eccentric Rotation Direction.
174
+ TABLE_TOP_DIRECTION = '300A,0126'
175
+ # Table Top Vertical Position.
176
+ TABLE_TOP_VERTICAL = '300A,0128'
177
+ # Table Top Longitudinal Position.
178
+ TABLE_TOP_LONGITUDINAL = '300A,0129'
179
+ # Table Top Lateral Position.
180
+ TABLE_TOP_LATERAL = '300A,012A'
181
+ # Isocenter Position.
182
+ ISO_POS = '300A,012C'
183
+ # Source to Surface Distance.
184
+ SSD = '300A,0130'
185
+ # Cumulative Meterset Weight.
186
+ CUM_METERSET_WEIGHT = '300A,0134'
187
+ # Patient Setup Sequence.
188
+ PATIENT_SETUP_SQ = '300A,0180'
189
+ # Patient Setup Number.
190
+ PATIENT_SETUP_NUMBER = '300A,0182'
191
+ # Setup technique.
192
+ SETUP_TECHNIQUE = '300A,01B0'
193
+ # Table Top Vertical Setup Displacement.
194
+ OFFSET_VERTICAL = '300A,01D2'
195
+ # Table Top Longitudinal Setup Displacement.
196
+ OFFSET_LONG = '300A,01D4'
197
+ # Table Top Lateral Setup Displacement.
198
+ OFFSET_LATERAL = '300A,01D6'
199
+ # Referenced RT Plan Sequence.
200
+ REF_PLAN_SQ = '300C,0002'
201
+ # Referenced Beam Sequence.
202
+ REF_BEAM_SQ = '300C,0004'
203
+ # Referenced Beam Number.
204
+ REF_BEAM_NUMBER = '300C,0006'
205
+ # Referenced Structure Set Sequence.
206
+ REF_STRUCT_SQ = '300C,0060'
207
+
208
+ # The modalities that contain multiple images per series.
209
+ IMAGE_SERIES = ['CT', 'MR']
210
+ # The modalities that contain pixel data:
211
+ IMAGE_MODALITIES = ['CT', 'MR', 'RTDOSE', 'RTIMAGE']
212
+ # The modalities supported by RTKIT.
213
+ SUPPORTED_MODALITIES = ['CT', 'MR', 'RTDOSE', 'RTIMAGE', 'RTPLAN', 'RTSTRUCT']
214
+
215
+ end