rtp-connect 1.8 → 1.9
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.
- checksums.yaml +5 -13
- data/CHANGELOG.md +124 -114
- data/COPYING +674 -674
- data/Gemfile +2 -2
- data/Gemfile.lock +23 -19
- data/README.md +149 -149
- data/lib/rtp-connect/constants.rb +58 -58
- data/lib/rtp-connect/control_point.rb +38 -95
- data/lib/rtp-connect/dose_tracking.rb +19 -33
- data/lib/rtp-connect/extended_field.rb +1 -20
- data/lib/rtp-connect/extended_plan.rb +115 -134
- data/lib/rtp-connect/field.rb +30 -20
- data/lib/rtp-connect/methods.rb +85 -77
- data/lib/rtp-connect/plan.rb +645 -624
- data/lib/rtp-connect/plan_to_dcm.rb +668 -656
- data/lib/rtp-connect/prescription.rb +39 -20
- data/lib/rtp-connect/record.rb +201 -143
- data/lib/rtp-connect/simulation_field.rb +606 -625
- data/lib/rtp-connect/site_setup.rb +1 -20
- data/lib/rtp-connect/version.rb +5 -5
- data/rtp-connect.gemspec +27 -27
- metadata +32 -32
@@ -8,8 +8,11 @@ module RTP
|
|
8
8
|
#
|
9
9
|
class ControlPoint < Record
|
10
10
|
|
11
|
+
# The number of attributes not having their own variable for this record (200 - 2).
|
12
|
+
NR_SURPLUS_ATTRIBUTES = 198
|
13
|
+
|
11
14
|
# The Record which this instance belongs to.
|
12
|
-
|
15
|
+
attr_accessor :parent
|
13
16
|
# The MLC shape record (if any) that belongs to this ControlPoint.
|
14
17
|
attr_reader :mlc_shape
|
15
18
|
attr_reader :field_id
|
@@ -144,15 +147,7 @@ module RTP
|
|
144
147
|
# @return [Float] the DICOM-formatted collimator_x1 attribute
|
145
148
|
#
|
146
149
|
def dcm_collimator_x1(scale=nil)
|
147
|
-
|
148
|
-
axis = :x
|
149
|
-
if scale == :elekta
|
150
|
-
axis = :y
|
151
|
-
coeff = -1
|
152
|
-
elsif scale == :varian
|
153
|
-
coeff = -1
|
154
|
-
end
|
155
|
-
dcm_collimator1(axis, coeff)
|
150
|
+
dcm_collimator_1(scale, default_axis=:x)
|
156
151
|
end
|
157
152
|
|
158
153
|
# Converts the collimator_x2 attribute to proper DICOM format.
|
@@ -162,7 +157,7 @@ module RTP
|
|
162
157
|
#
|
163
158
|
def dcm_collimator_x2(scale=nil)
|
164
159
|
axis = (scale == :elekta ? :y : :x)
|
165
|
-
|
160
|
+
dcm_collimator(axis, coeff=1, side=2)
|
166
161
|
end
|
167
162
|
|
168
163
|
# Converts the collimator_y1 attribute to proper DICOM format.
|
@@ -171,15 +166,7 @@ module RTP
|
|
171
166
|
# @return [Float] the DICOM-formatted collimator_y1 attribute
|
172
167
|
#
|
173
168
|
def dcm_collimator_y1(scale=nil)
|
174
|
-
|
175
|
-
axis = :y
|
176
|
-
if scale == :elekta
|
177
|
-
axis = :x
|
178
|
-
coeff = -1
|
179
|
-
elsif scale == :varian
|
180
|
-
coeff = -1
|
181
|
-
end
|
182
|
-
dcm_collimator1(axis, coeff)
|
169
|
+
dcm_collimator_1(scale, default_axis=:y)
|
183
170
|
end
|
184
171
|
|
185
172
|
# Converts the collimator_y2 attribute to proper DICOM format.
|
@@ -189,7 +176,7 @@ module RTP
|
|
189
176
|
#
|
190
177
|
def dcm_collimator_y2(scale=nil)
|
191
178
|
axis = (scale == :elekta ? :x : :y)
|
192
|
-
|
179
|
+
dcm_collimator(axis, coeff=1, side=2)
|
193
180
|
end
|
194
181
|
|
195
182
|
# Converts the mlc_lp_a & mlc_lp_b attributes to a proper DICOM formatted string.
|
@@ -276,25 +263,6 @@ module RTP
|
|
276
263
|
self
|
277
264
|
end
|
278
265
|
|
279
|
-
# Encodes the ControlPoint object + any hiearchy of child objects,
|
280
|
-
# to a properly formatted RTPConnect ascii string.
|
281
|
-
#
|
282
|
-
# @param [Hash] options an optional hash parameter
|
283
|
-
# @option options [Float] :version the Mosaiq compatibility version number (e.g. 2.4) used for the output
|
284
|
-
# @return [String] an RTP string with a single or multiple lines/records
|
285
|
-
#
|
286
|
-
def to_s(options={})
|
287
|
-
str = encode(options)
|
288
|
-
if children
|
289
|
-
children.each do |child|
|
290
|
-
str += child.to_s(options)
|
291
|
-
end
|
292
|
-
end
|
293
|
-
return str
|
294
|
-
end
|
295
|
-
|
296
|
-
alias :to_str :to_s
|
297
|
-
|
298
266
|
# Sets the mlc_lp_a attribute.
|
299
267
|
#
|
300
268
|
# @note As opposed to the ordinary (string) attributes, this attribute
|
@@ -578,74 +546,49 @@ module RTP
|
|
578
546
|
#
|
579
547
|
# @param [Symbol] axis a representation for the axis of interest (x or y)
|
580
548
|
# @param [Integer] coeff a coeffecient (of -1 or 1) which the attribute is multiplied with
|
549
|
+
# @param [Integer] nr collimator side/index (1 or 2)
|
581
550
|
# @return [Float] the DICOM-formatted collimator attribute
|
582
551
|
#
|
583
|
-
def
|
552
|
+
def dcm_collimator(axis, coeff, nr)
|
584
553
|
mode = self.send("field_#{axis}_mode")
|
585
554
|
if mode && !mode.empty?
|
586
555
|
target = self
|
587
556
|
else
|
588
557
|
target = @parent
|
589
558
|
end
|
590
|
-
target.send("collimator_#{axis}
|
559
|
+
target.send("collimator_#{axis}#{nr}").to_f * 10 * coeff
|
591
560
|
end
|
592
561
|
|
593
|
-
# Converts the
|
562
|
+
# Converts the collimator1 attribute to proper DICOM format.
|
594
563
|
#
|
595
|
-
# @param [Symbol]
|
596
|
-
# @
|
597
|
-
# @return [Float] the DICOM-formatted collimator attribute
|
564
|
+
# @param [Symbol] scale if set, relevant device parameters are converted from a native readout format to IEC1217 (supported values are :elekta & :varian)
|
565
|
+
# @return [Float] the DICOM-formatted collimator_x1 attribute
|
598
566
|
#
|
599
|
-
def
|
600
|
-
|
601
|
-
if
|
602
|
-
|
603
|
-
|
604
|
-
|
567
|
+
def dcm_collimator_1(scale=nil, axis)
|
568
|
+
coeff = 1
|
569
|
+
if scale == :elekta
|
570
|
+
axis = (axis == :x ? :y : :x)
|
571
|
+
coeff = -1
|
572
|
+
elsif scale == :varian
|
573
|
+
coeff = -1
|
605
574
|
end
|
606
|
-
|
607
|
-
end
|
608
|
-
|
609
|
-
#
|
610
|
-
#
|
611
|
-
#
|
612
|
-
#
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
@energy = values[9]
|
624
|
-
@doserate = values[10]
|
625
|
-
@ssd = values[11]
|
626
|
-
@scale_convention = values[12]
|
627
|
-
@gantry_angle = values[13]
|
628
|
-
@gantry_dir = values[14]
|
629
|
-
@collimator_angle = values[15]
|
630
|
-
@collimator_dir = values[16]
|
631
|
-
@field_x_mode = values[17]
|
632
|
-
@field_x = values[18]
|
633
|
-
@collimator_x1 = values[19]
|
634
|
-
@collimator_x2 = values[20]
|
635
|
-
@field_y_mode = values[21]
|
636
|
-
@field_y = values[22]
|
637
|
-
@collimator_y1 = values[23]
|
638
|
-
@collimator_y2 = values[24]
|
639
|
-
@couch_vertical = values[25]
|
640
|
-
@couch_lateral = values[26]
|
641
|
-
@couch_longitudinal = values[27]
|
642
|
-
@couch_angle = values[28]
|
643
|
-
@couch_dir = values[29]
|
644
|
-
@couch_pedestal = values[30]
|
645
|
-
@couch_ped_dir = values[31]
|
646
|
-
@mlc_lp_a = [*values[32..131]]
|
647
|
-
@mlc_lp_b = [*values[132..231]]
|
648
|
-
@crc = values[-1]
|
575
|
+
dcm_collimator(axis, coeff, side=1)
|
576
|
+
end
|
577
|
+
|
578
|
+
# Gives an array of indices indicating where the attributes of this record gets its
|
579
|
+
# values from in the comma separated string which the instance is created from.
|
580
|
+
#
|
581
|
+
# @param [Integer] length the number of elements to create in the indices array
|
582
|
+
#
|
583
|
+
def import_indices(length)
|
584
|
+
# Note that this method is defined in the parent Record class, where it is
|
585
|
+
# used for most record types. However, because this record has two attributes
|
586
|
+
# which contain an array of values, we use a custom import_indices method.
|
587
|
+
ind = Array.new(length - NR_SURPLUS_ATTRIBUTES) { |i| [i] }
|
588
|
+
# Override indices for mlc_pl_a and mlc_lp_b:
|
589
|
+
ind[32] = (32..131).to_a
|
590
|
+
ind[33] = (132..231).to_a
|
591
|
+
ind
|
649
592
|
end
|
650
593
|
|
651
594
|
end
|
@@ -8,8 +8,11 @@ module RTP
|
|
8
8
|
#
|
9
9
|
class DoseTracking < Record
|
10
10
|
|
11
|
+
# The number of attributes not having their own variable for this record (20 - 2).
|
12
|
+
NR_SURPLUS_ATTRIBUTES = 18
|
13
|
+
|
11
14
|
# The Record which this instance belongs to.
|
12
|
-
|
15
|
+
attr_accessor :parent
|
13
16
|
# The DoseAction records (if any) that belongs to this DoseTracking.
|
14
17
|
attr_reader :dose_actions
|
15
18
|
attr_reader :region_name
|
@@ -120,25 +123,6 @@ module RTP
|
|
120
123
|
self
|
121
124
|
end
|
122
125
|
|
123
|
-
# Encodes the DoseTracking object + any hiearchy of child objects,
|
124
|
-
# to a properly formatted RTPConnect ascii string.
|
125
|
-
#
|
126
|
-
# @param [Hash] options an optional hash parameter
|
127
|
-
# @option options [Float] :version the Mosaiq compatibility version number (e.g. 2.4) used for the output
|
128
|
-
# @return [String] an RTP string with a single or multiple lines/records
|
129
|
-
#
|
130
|
-
def to_s(options={})
|
131
|
-
str = encode(options)
|
132
|
-
if children
|
133
|
-
children.each do |child|
|
134
|
-
str += child.to_s(options)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
return str
|
138
|
-
end
|
139
|
-
|
140
|
-
alias :to_str :to_s
|
141
|
-
|
142
126
|
# Sets the field_ids attribute.
|
143
127
|
#
|
144
128
|
# @note As opposed to the ordinary (string) attributes, this attribute
|
@@ -202,19 +186,21 @@ module RTP
|
|
202
186
|
#
|
203
187
|
alias_method :state, :values
|
204
188
|
|
205
|
-
#
|
206
|
-
#
|
207
|
-
#
|
208
|
-
#
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
189
|
+
# Gives an array of indices indicating where the attributes of this record gets its
|
190
|
+
# values from in the comma separated string which the instance is created from.
|
191
|
+
#
|
192
|
+
# @param [Integer] length the number of elements to create in the indices array
|
193
|
+
#
|
194
|
+
def import_indices(length)
|
195
|
+
# Note that this method is defined in the parent Record class, where it is
|
196
|
+
# used for most record types. However, because this record has two attributes
|
197
|
+
# which contain an array of values, we use a custom import_indices method.
|
198
|
+
ind = Array.new(length - NR_SURPLUS_ATTRIBUTES) { |i| i }
|
199
|
+
# Override indices for field_ids and region_coeffs:
|
200
|
+
ind[3] = [3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
|
201
|
+
ind[4] = [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
|
202
|
+
ind[5, 6] = [23, 24]
|
203
|
+
ind
|
218
204
|
end
|
219
205
|
|
220
206
|
end
|
@@ -9,7 +9,7 @@ module RTP
|
|
9
9
|
class ExtendedField < Record
|
10
10
|
|
11
11
|
# The Record which this instance belongs to.
|
12
|
-
|
12
|
+
attr_accessor :parent
|
13
13
|
attr_reader :field_id
|
14
14
|
attr_reader :original_plan_uid
|
15
15
|
attr_reader :original_beam_number
|
@@ -97,25 +97,6 @@ module RTP
|
|
97
97
|
self
|
98
98
|
end
|
99
99
|
|
100
|
-
# Encodes the ExtendedField object + any hiearchy of child objects,
|
101
|
-
# to a properly formatted RTPConnect ascii string.
|
102
|
-
#
|
103
|
-
# @param [Hash] options an optional hash parameter
|
104
|
-
# @option options [Float] :version the Mosaiq compatibility version number (e.g. 2.4) used for the output
|
105
|
-
# @return [String] an RTP string with a single or multiple lines/records
|
106
|
-
#
|
107
|
-
def to_s(options={})
|
108
|
-
str = encode(options)
|
109
|
-
if children
|
110
|
-
children.each do |child|
|
111
|
-
str += child.to_s(options)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
return str
|
115
|
-
end
|
116
|
-
|
117
|
-
alias :to_str :to_s
|
118
|
-
|
119
100
|
# Sets the field_id attribute.
|
120
101
|
#
|
121
102
|
# @param [nil, #to_s] value the new attribute value
|
@@ -1,135 +1,116 @@
|
|
1
|
-
module RTP
|
2
|
-
|
3
|
-
# The Extended plan class.
|
4
|
-
#
|
5
|
-
# @note Relations:
|
6
|
-
# * Parent: Plan
|
7
|
-
# * Children: none
|
8
|
-
#
|
9
|
-
class ExtendedPlan < Record
|
10
|
-
|
11
|
-
# The Record which this instance belongs to.
|
12
|
-
|
13
|
-
attr_reader :encoding
|
14
|
-
attr_reader :fullname
|
15
|
-
|
16
|
-
# Creates a new ExtendedPlan by parsing a RTPConnect string line.
|
17
|
-
#
|
18
|
-
# @param [#to_s] string the extended plan definition record string line
|
19
|
-
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
20
|
-
# @return [ExtendedPlan] the created ExtendedPlan instance
|
21
|
-
# @raise [ArgumentError] if given a string containing an invalid number of elements
|
22
|
-
#
|
23
|
-
def self.load(string, parent)
|
24
|
-
ep = self.new(parent)
|
25
|
-
ep.load(string)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Creates a new ExtendedPlan.
|
29
|
-
#
|
30
|
-
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
31
|
-
#
|
32
|
-
def initialize(parent)
|
33
|
-
super('EXTENDED_PLAN_DEF', 4, 4)
|
34
|
-
# Parent relation (may get more than one type of record here):
|
35
|
-
@parent = get_parent(parent.to_record, Plan)
|
36
|
-
@parent.add_extended_plan(self)
|
37
|
-
@attributes = [
|
38
|
-
# Required:
|
39
|
-
:keyword,
|
40
|
-
:encoding,
|
41
|
-
:fullname
|
42
|
-
]
|
43
|
-
end
|
44
|
-
|
45
|
-
# Checks for equality.
|
46
|
-
#
|
47
|
-
# Other and self are considered equivalent if they are
|
48
|
-
# of compatible types and their attributes are equivalent.
|
49
|
-
#
|
50
|
-
# @param other an object to be compared with self.
|
51
|
-
# @return [Boolean] true if self and other are considered equivalent
|
52
|
-
#
|
53
|
-
def ==(other)
|
54
|
-
if other.respond_to?(:to_extended_plan)
|
55
|
-
other.send(:state) == state
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
alias_method :eql?, :==
|
60
|
-
|
61
|
-
# Gives an empty array, as these instances are child-less by definition.
|
62
|
-
#
|
63
|
-
# @return [Array] an emtpy array
|
64
|
-
#
|
65
|
-
def children
|
66
|
-
return Array.new
|
67
|
-
end
|
68
|
-
|
69
|
-
# Computes a hash code for this object.
|
70
|
-
#
|
71
|
-
# @note Two objects with the same attributes will have the same hash code.
|
72
|
-
#
|
73
|
-
# @return [Fixnum] the object's hash code
|
74
|
-
#
|
75
|
-
def hash
|
76
|
-
state.hash
|
77
|
-
end
|
78
|
-
|
79
|
-
# Returns self.
|
80
|
-
#
|
81
|
-
# @return [ExtendedPlan] self
|
82
|
-
#
|
83
|
-
def to_extended_plan
|
84
|
-
self
|
85
|
-
end
|
86
|
-
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
# @param [nil, #to_s] value the new attribute value
|
117
|
-
#
|
118
|
-
def fullname=(value)
|
119
|
-
@fullname = value && value.to_s
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
|
126
|
-
# Collects the attributes of this instance.
|
127
|
-
#
|
128
|
-
# @note The CRC is not considered part of the attributes of interest and is excluded
|
129
|
-
# @return [Array<String>] an array of attributes
|
130
|
-
#
|
131
|
-
alias_method :state, :values
|
132
|
-
|
133
|
-
end
|
134
|
-
|
1
|
+
module RTP
|
2
|
+
|
3
|
+
# The Extended plan class.
|
4
|
+
#
|
5
|
+
# @note Relations:
|
6
|
+
# * Parent: Plan
|
7
|
+
# * Children: none
|
8
|
+
#
|
9
|
+
class ExtendedPlan < Record
|
10
|
+
|
11
|
+
# The Record which this instance belongs to.
|
12
|
+
attr_accessor :parent
|
13
|
+
attr_reader :encoding
|
14
|
+
attr_reader :fullname
|
15
|
+
|
16
|
+
# Creates a new ExtendedPlan by parsing a RTPConnect string line.
|
17
|
+
#
|
18
|
+
# @param [#to_s] string the extended plan definition record string line
|
19
|
+
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
20
|
+
# @return [ExtendedPlan] the created ExtendedPlan instance
|
21
|
+
# @raise [ArgumentError] if given a string containing an invalid number of elements
|
22
|
+
#
|
23
|
+
def self.load(string, parent)
|
24
|
+
ep = self.new(parent)
|
25
|
+
ep.load(string)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Creates a new ExtendedPlan.
|
29
|
+
#
|
30
|
+
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
31
|
+
#
|
32
|
+
def initialize(parent)
|
33
|
+
super('EXTENDED_PLAN_DEF', 4, 4)
|
34
|
+
# Parent relation (may get more than one type of record here):
|
35
|
+
@parent = get_parent(parent.to_record, Plan)
|
36
|
+
@parent.add_extended_plan(self)
|
37
|
+
@attributes = [
|
38
|
+
# Required:
|
39
|
+
:keyword,
|
40
|
+
:encoding,
|
41
|
+
:fullname
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Checks for equality.
|
46
|
+
#
|
47
|
+
# Other and self are considered equivalent if they are
|
48
|
+
# of compatible types and their attributes are equivalent.
|
49
|
+
#
|
50
|
+
# @param other an object to be compared with self.
|
51
|
+
# @return [Boolean] true if self and other are considered equivalent
|
52
|
+
#
|
53
|
+
def ==(other)
|
54
|
+
if other.respond_to?(:to_extended_plan)
|
55
|
+
other.send(:state) == state
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
alias_method :eql?, :==
|
60
|
+
|
61
|
+
# Gives an empty array, as these instances are child-less by definition.
|
62
|
+
#
|
63
|
+
# @return [Array] an emtpy array
|
64
|
+
#
|
65
|
+
def children
|
66
|
+
return Array.new
|
67
|
+
end
|
68
|
+
|
69
|
+
# Computes a hash code for this object.
|
70
|
+
#
|
71
|
+
# @note Two objects with the same attributes will have the same hash code.
|
72
|
+
#
|
73
|
+
# @return [Fixnum] the object's hash code
|
74
|
+
#
|
75
|
+
def hash
|
76
|
+
state.hash
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns self.
|
80
|
+
#
|
81
|
+
# @return [ExtendedPlan] self
|
82
|
+
#
|
83
|
+
def to_extended_plan
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
# Sets the encoding attribute.
|
88
|
+
#
|
89
|
+
# @param [nil, #to_s] value the new attribute value
|
90
|
+
#
|
91
|
+
def encoding=(value)
|
92
|
+
@encoding = value && value.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
# Sets the fullname attribute.
|
96
|
+
#
|
97
|
+
# @param [nil, #to_s] value the new attribute value
|
98
|
+
#
|
99
|
+
def fullname=(value)
|
100
|
+
@fullname = value && value.to_s
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
|
107
|
+
# Collects the attributes of this instance.
|
108
|
+
#
|
109
|
+
# @note The CRC is not considered part of the attributes of interest and is excluded
|
110
|
+
# @return [Array<String>] an array of attributes
|
111
|
+
#
|
112
|
+
alias_method :state, :values
|
113
|
+
|
114
|
+
end
|
115
|
+
|
135
116
|
end
|