rtp-connect 1.6 → 1.11
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 +7 -0
- data/{CHANGELOG.rdoc → CHANGELOG.md} +137 -90
- data/COPYING +674 -674
- data/Gemfile +2 -2
- data/Gemfile.lock +31 -21
- data/README.md +161 -0
- data/lib/rtp-connect.rb +1 -0
- data/lib/rtp-connect/constants.rb +58 -57
- data/lib/rtp-connect/control_point.rb +158 -118
- data/lib/rtp-connect/dose_tracking.rb +37 -54
- data/lib/rtp-connect/extended_field.rb +36 -69
- data/lib/rtp-connect/extended_plan.rb +127 -0
- data/lib/rtp-connect/field.rb +158 -143
- data/lib/rtp-connect/methods.rb +85 -62
- data/lib/rtp-connect/plan.rb +645 -636
- data/lib/rtp-connect/plan_to_dcm.rb +668 -694
- data/lib/rtp-connect/prescription.rb +57 -74
- data/lib/rtp-connect/record.rb +225 -57
- data/lib/rtp-connect/ruby_extensions.rb +34 -3
- data/lib/rtp-connect/simulation_field.rb +606 -701
- data/lib/rtp-connect/site_setup.rb +112 -80
- data/lib/rtp-connect/version.rb +5 -5
- data/rakefile.rb +0 -1
- data/rtp-connect.gemspec +27 -27
- metadata +67 -58
- data/README.rdoc +0 -136
@@ -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
|
@@ -29,23 +32,8 @@ module RTP
|
|
29
32
|
# @raise [ArgumentError] if given a string containing an invalid number of elements
|
30
33
|
#
|
31
34
|
def self.load(string, parent)
|
32
|
-
# Get the quote-less values:
|
33
|
-
values = string.to_s.values
|
34
|
-
low_limit = 24
|
35
|
-
high_limit = 26
|
36
|
-
raise ArgumentError, "Invalid argument 'string': Expected at least #{low_limit} elements, got #{values.length}." if values.length < low_limit
|
37
|
-
RTP.logger.warn "The number of elements (#{values.length}) for this DoseTracking record exceeds the known number of data items for this record (#{high_limit}). This may indicate an invalid record or that the RTP format has recently been expanded with new items." if values.length > high_limit
|
38
35
|
d = self.new(parent)
|
39
|
-
|
40
|
-
d.keyword = values[0]
|
41
|
-
d.region_name = values[1]
|
42
|
-
d.region_prior_dose = values[2]
|
43
|
-
d.field_ids = values.values_at(3, 5, 7, 9, 11, 13, 15, 17, 19, 21)
|
44
|
-
d.region_coeffs = values.values_at(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
|
45
|
-
d.actual_dose = values[23]
|
46
|
-
d.actual_fractions = values[24]
|
47
|
-
d.crc = values[-1]
|
48
|
-
return d
|
36
|
+
d.load(string)
|
49
37
|
end
|
50
38
|
|
51
39
|
# Creates a new DoseTracking.
|
@@ -53,14 +41,25 @@ module RTP
|
|
53
41
|
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
54
42
|
#
|
55
43
|
def initialize(parent)
|
44
|
+
super('DOSE_DEF', 24, 26)
|
56
45
|
# Child records:
|
57
46
|
@dose_actions = Array.new
|
58
47
|
# Parent relation (may get more than one type of record here):
|
59
48
|
@parent = get_parent(parent.to_record, Plan)
|
60
49
|
@parent.add_dose_tracking(self)
|
61
|
-
@keyword = 'DOSE_DEF'
|
62
50
|
@field_ids = Array.new(10)
|
63
51
|
@region_coeffs = Array.new(10)
|
52
|
+
@attributes = [
|
53
|
+
# Required:
|
54
|
+
:keyword,
|
55
|
+
:region_name,
|
56
|
+
:region_prior_dose,
|
57
|
+
:field_ids,
|
58
|
+
:region_coeffs,
|
59
|
+
# Optional:
|
60
|
+
:actual_dose,
|
61
|
+
:actual_fractions
|
62
|
+
]
|
64
63
|
end
|
65
64
|
|
66
65
|
# Checks for equality.
|
@@ -105,7 +104,7 @@ module RTP
|
|
105
104
|
# @return [Array<String>] an array of attributes (in the same order as they appear in the RTP string)
|
106
105
|
#
|
107
106
|
def values
|
108
|
-
|
107
|
+
[
|
109
108
|
@keyword,
|
110
109
|
@region_name,
|
111
110
|
@region_prior_dose,
|
@@ -124,23 +123,6 @@ module RTP
|
|
124
123
|
self
|
125
124
|
end
|
126
125
|
|
127
|
-
# Encodes the DoseTracking object + any hiearchy of child objects,
|
128
|
-
# to a properly formatted RTPConnect ascii string.
|
129
|
-
#
|
130
|
-
# @return [String] an RTP string with a single or multiple lines/records
|
131
|
-
#
|
132
|
-
def to_s
|
133
|
-
str = encode
|
134
|
-
if children
|
135
|
-
children.each do |child|
|
136
|
-
str += child.to_s
|
137
|
-
end
|
138
|
-
end
|
139
|
-
return str
|
140
|
-
end
|
141
|
-
|
142
|
-
alias :to_str :to_s
|
143
|
-
|
144
126
|
# Sets the field_ids attribute.
|
145
127
|
#
|
146
128
|
# @note As opposed to the ordinary (string) attributes, this attribute
|
@@ -148,9 +130,7 @@ module RTP
|
|
148
130
|
# @param [Array<nil, #to_s>] array the new attribute values
|
149
131
|
#
|
150
132
|
def field_ids=(array)
|
151
|
-
|
152
|
-
raise ArgumentError, "Invalid argument 'array'. Expected length 10, got #{array.length}." unless array.length == 10
|
153
|
-
@field_ids = array.collect! {|e| e && e.to_s}
|
133
|
+
@field_ids = array.to_a.validate_and_process(10)
|
154
134
|
end
|
155
135
|
|
156
136
|
# Sets the region_coeffs attribute.
|
@@ -160,21 +140,7 @@ module RTP
|
|
160
140
|
# @param [Array<nil, #to_s>] array the new attribute values
|
161
141
|
#
|
162
142
|
def region_coeffs=(array)
|
163
|
-
|
164
|
-
raise ArgumentError, "Invalid argument 'array'. Expected length 10, got #{array.length}." unless array.length == 10
|
165
|
-
@region_coeffs = array.collect! {|e| e && e.to_s}
|
166
|
-
end
|
167
|
-
|
168
|
-
# Sets the keyword attribute.
|
169
|
-
#
|
170
|
-
# @note Since only a specific string is accepted, this is more of an argument check than a traditional setter method
|
171
|
-
# @param [#to_s] value the new attribute value
|
172
|
-
# @raise [ArgumentError] if given an unexpected keyword
|
173
|
-
#
|
174
|
-
def keyword=(value)
|
175
|
-
value = value.to_s.upcase
|
176
|
-
raise ArgumentError, "Invalid keyword. Expected 'DOSE_DEF', got #{value}." unless value == "DOSE_DEF"
|
177
|
-
@keyword = value
|
143
|
+
@region_coeffs = array.to_a.validate_and_process(10)
|
178
144
|
end
|
179
145
|
|
180
146
|
# Sets the region_name attribute.
|
@@ -220,6 +186,23 @@ module RTP
|
|
220
186
|
#
|
221
187
|
alias_method :state, :values
|
222
188
|
|
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
|
204
|
+
end
|
205
|
+
|
223
206
|
end
|
224
207
|
|
225
208
|
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
|
@@ -18,6 +18,8 @@ module RTP
|
|
18
18
|
attr_reader :accessory_code
|
19
19
|
attr_reader :accessory_type
|
20
20
|
attr_reader :high_dose_authorization
|
21
|
+
attr_reader :referenced_rt_plan_uid
|
22
|
+
attr_reader :referenced_rt_plan_relationship
|
21
23
|
|
22
24
|
# Creates a new (treatment) ExtendedField by parsing a RTPConnect string line.
|
23
25
|
#
|
@@ -27,26 +29,8 @@ module RTP
|
|
27
29
|
# @raise [ArgumentError] if given a string containing an invalid number of elements
|
28
30
|
#
|
29
31
|
def self.load(string, parent)
|
30
|
-
# Get the quote-less values:
|
31
|
-
values = string.to_s.values
|
32
|
-
low_limit = 4
|
33
|
-
high_limit = 10
|
34
|
-
raise ArgumentError, "Invalid argument 'string': Expected at least #{low_limit} elements, got #{values.length}." if values.length < low_limit
|
35
|
-
RTP.logger.warn "The number of elements (#{values.length}) for this ExtendedField record exceeds the known number of data items for this record (#{high_limit}). This may indicate an invalid record or that the RTP format has recently been expanded with new items." if values.length > high_limit
|
36
32
|
ef = self.new(parent)
|
37
|
-
|
38
|
-
ef.keyword = values[0]
|
39
|
-
ef.field_id = values[1]
|
40
|
-
ef.original_plan_uid = values[2]
|
41
|
-
# Optional attributes:
|
42
|
-
ef.original_beam_number = values[3]
|
43
|
-
ef.original_beam_name = values[4]
|
44
|
-
ef.is_fff = values[5] if values[5]
|
45
|
-
ef.accessory_code = values[6]
|
46
|
-
ef.accessory_type = values[7]
|
47
|
-
ef.high_dose_authorization = values[8]
|
48
|
-
ef.crc = values[-1]
|
49
|
-
return ef
|
33
|
+
ef.load(string)
|
50
34
|
end
|
51
35
|
|
52
36
|
# Creates a new (treatment) ExtendedField.
|
@@ -54,10 +38,25 @@ module RTP
|
|
54
38
|
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
55
39
|
#
|
56
40
|
def initialize(parent)
|
41
|
+
super('EXTENDED_FIELD_DEF', 4, 12)
|
57
42
|
# Parent relation (may get more than one type of record here):
|
58
43
|
@parent = get_parent(parent.to_record, Field)
|
59
44
|
@parent.add_extended_field(self)
|
60
|
-
@
|
45
|
+
@attributes = [
|
46
|
+
# Required:
|
47
|
+
:keyword,
|
48
|
+
:field_id,
|
49
|
+
:original_plan_uid,
|
50
|
+
# Optional:
|
51
|
+
:original_beam_number,
|
52
|
+
:original_beam_name,
|
53
|
+
:is_fff,
|
54
|
+
:accessory_code,
|
55
|
+
:accessory_type,
|
56
|
+
:high_dose_authorization,
|
57
|
+
:referenced_rt_plan_uid,
|
58
|
+
:referenced_rt_plan_relationship
|
59
|
+
]
|
61
60
|
end
|
62
61
|
|
63
62
|
# Checks for equality.
|
@@ -94,25 +93,6 @@ module RTP
|
|
94
93
|
state.hash
|
95
94
|
end
|
96
95
|
|
97
|
-
# Collects the values (attributes) of this instance.
|
98
|
-
#
|
99
|
-
# @note The CRC is not considered part of the actual values and is excluded.
|
100
|
-
# @return [Array<String>] an array of attributes (in the same order as they appear in the RTP string)
|
101
|
-
#
|
102
|
-
def values
|
103
|
-
return [
|
104
|
-
@keyword,
|
105
|
-
@field_id,
|
106
|
-
@original_plan_uid,
|
107
|
-
@original_beam_number,
|
108
|
-
@original_beam_name,
|
109
|
-
@is_fff,
|
110
|
-
@accessory_code,
|
111
|
-
@accessory_type,
|
112
|
-
@high_dose_authorization
|
113
|
-
]
|
114
|
-
end
|
115
|
-
|
116
96
|
# Returns self.
|
117
97
|
#
|
118
98
|
# @return [ExtendedField] self
|
@@ -121,35 +101,6 @@ module RTP
|
|
121
101
|
self
|
122
102
|
end
|
123
103
|
|
124
|
-
# Encodes the ExtendedField object + any hiearchy of child objects,
|
125
|
-
# to a properly formatted RTPConnect ascii string.
|
126
|
-
#
|
127
|
-
# @return [String] an RTP string with a single or multiple lines/records
|
128
|
-
#
|
129
|
-
def to_s
|
130
|
-
str = encode
|
131
|
-
if children
|
132
|
-
children.each do |child|
|
133
|
-
str += child.to_s
|
134
|
-
end
|
135
|
-
end
|
136
|
-
return str
|
137
|
-
end
|
138
|
-
|
139
|
-
alias :to_str :to_s
|
140
|
-
|
141
|
-
# Sets the keyword attribute.
|
142
|
-
#
|
143
|
-
# @note Since only a specific string is accepted, this is more of an argument check than a traditional setter method
|
144
|
-
# @param [#to_s] value the new attribute value
|
145
|
-
# @raise [ArgumentError] if given an unexpected keyword
|
146
|
-
#
|
147
|
-
def keyword=(value)
|
148
|
-
value = value.to_s.upcase
|
149
|
-
raise ArgumentError, "Invalid keyword. Expected 'EXTENDED_FIELD_DEF', got #{value}." unless value == "EXTENDED_FIELD_DEF"
|
150
|
-
@keyword = value
|
151
|
-
end
|
152
|
-
|
153
104
|
# Sets the field_id attribute.
|
154
105
|
#
|
155
106
|
# @param [nil, #to_s] value the new attribute value
|
@@ -214,6 +165,22 @@ module RTP
|
|
214
165
|
@high_dose_authorization = value && value.to_s
|
215
166
|
end
|
216
167
|
|
168
|
+
# Sets the referenced_rt_plan_uid attribute.
|
169
|
+
#
|
170
|
+
# @param [nil, #to_s] value the new attribute value
|
171
|
+
#
|
172
|
+
def referenced_rt_plan_uid=(value)
|
173
|
+
@referenced_rt_plan_uid = value && value.to_s
|
174
|
+
end
|
175
|
+
|
176
|
+
# Sets the referenced_rt_plan_relationship attribute.
|
177
|
+
#
|
178
|
+
# @param [nil, #to_s] value the new attribute value
|
179
|
+
#
|
180
|
+
def referenced_rt_plan_relationship=(value)
|
181
|
+
@referenced_rt_plan_relationship = value && value.to_s
|
182
|
+
end
|
183
|
+
|
217
184
|
|
218
185
|
private
|
219
186
|
|
@@ -0,0 +1,127 @@
|
|
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
|
+
attr_reader :patient_comments
|
16
|
+
|
17
|
+
# Creates a new ExtendedPlan by parsing a RTPConnect string line.
|
18
|
+
#
|
19
|
+
# @param [#to_s] string the extended plan definition record string line
|
20
|
+
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
21
|
+
# @return [ExtendedPlan] the created ExtendedPlan instance
|
22
|
+
# @raise [ArgumentError] if given a string containing an invalid number of elements
|
23
|
+
#
|
24
|
+
def self.load(string, parent)
|
25
|
+
ep = self.new(parent)
|
26
|
+
ep.load(string)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates a new ExtendedPlan.
|
30
|
+
#
|
31
|
+
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
32
|
+
#
|
33
|
+
def initialize(parent)
|
34
|
+
super('EXTENDED_PLAN_DEF', 4, 5)
|
35
|
+
# Parent relation (may get more than one type of record here):
|
36
|
+
@parent = get_parent(parent.to_record, Plan)
|
37
|
+
@parent.add_extended_plan(self)
|
38
|
+
@attributes = [
|
39
|
+
# Required:
|
40
|
+
:keyword,
|
41
|
+
:encoding,
|
42
|
+
:fullname,
|
43
|
+
# Optional:
|
44
|
+
:patient_comments
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Checks for equality.
|
49
|
+
#
|
50
|
+
# Other and self are considered equivalent if they are
|
51
|
+
# of compatible types and their attributes are equivalent.
|
52
|
+
#
|
53
|
+
# @param other an object to be compared with self.
|
54
|
+
# @return [Boolean] true if self and other are considered equivalent
|
55
|
+
#
|
56
|
+
def ==(other)
|
57
|
+
if other.respond_to?(:to_extended_plan)
|
58
|
+
other.send(:state) == state
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
alias_method :eql?, :==
|
63
|
+
|
64
|
+
# Gives an empty array, as these instances are child-less by definition.
|
65
|
+
#
|
66
|
+
# @return [Array] an emtpy array
|
67
|
+
#
|
68
|
+
def children
|
69
|
+
return Array.new
|
70
|
+
end
|
71
|
+
|
72
|
+
# Computes a hash code for this object.
|
73
|
+
#
|
74
|
+
# @note Two objects with the same attributes will have the same hash code.
|
75
|
+
#
|
76
|
+
# @return [Fixnum] the object's hash code
|
77
|
+
#
|
78
|
+
def hash
|
79
|
+
state.hash
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns self.
|
83
|
+
#
|
84
|
+
# @return [ExtendedPlan] self
|
85
|
+
#
|
86
|
+
def to_extended_plan
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
# Sets the encoding attribute.
|
91
|
+
#
|
92
|
+
# @param [nil, #to_s] value the new attribute value
|
93
|
+
#
|
94
|
+
def encoding=(value)
|
95
|
+
@encoding = value && value.to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
# Sets the fullname attribute.
|
99
|
+
#
|
100
|
+
# @param [nil, #to_s] value the new attribute value
|
101
|
+
#
|
102
|
+
def fullname=(value)
|
103
|
+
@fullname = value && value.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
# Sets the patient_comments attribute.
|
107
|
+
#
|
108
|
+
# @param [nil, #to_s] value the new attribute value
|
109
|
+
#
|
110
|
+
def patient_comments=(value)
|
111
|
+
@patient_comments = value && value.to_s
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
|
118
|
+
# Collects the attributes of this instance.
|
119
|
+
#
|
120
|
+
# @note The CRC is not considered part of the attributes of interest and is excluded
|
121
|
+
# @return [Array<String>] an array of attributes
|
122
|
+
#
|
123
|
+
alias_method :state, :values
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
data/lib/rtp-connect/field.rb
CHANGED
@@ -9,7 +9,7 @@ module RTP
|
|
9
9
|
class Field < Record
|
10
10
|
|
11
11
|
# The Record which this instance belongs to.
|
12
|
-
|
12
|
+
attr_accessor :parent
|
13
13
|
# The ExtendedField record (if any) that belongs to this Field.
|
14
14
|
attr_reader :extended_field
|
15
15
|
# An array of ControlPoint records (if any) that belongs to this Field.
|
@@ -61,6 +61,9 @@ module RTP
|
|
61
61
|
attr_reader :portfilm_delta_open
|
62
62
|
attr_reader :portfilm_mu_treat
|
63
63
|
attr_reader :portfilm_coeff_treat
|
64
|
+
attr_reader :iso_pos_x
|
65
|
+
attr_reader :iso_pos_y
|
66
|
+
attr_reader :iso_pos_z
|
64
67
|
|
65
68
|
# Creates a new (treatment) Field by parsing a RTPConnect string line.
|
66
69
|
#
|
@@ -70,64 +73,8 @@ module RTP
|
|
70
73
|
# @raise [ArgumentError] if given a string containing an invalid number of elements
|
71
74
|
#
|
72
75
|
def self.load(string, parent)
|
73
|
-
# Get the quote-less values:
|
74
|
-
values = string.to_s.values
|
75
|
-
low_limit = 27
|
76
|
-
high_limit = 49
|
77
|
-
raise ArgumentError, "Invalid argument 'string': Expected at least #{low_limit} elements, got #{values.length}." if values.length < low_limit
|
78
|
-
RTP.logger.warn "The number of elements (#{values.length}) for this Field record exceeds the known number of data items for this record (#{high_limit}). This may indicate an invalid record or that the RTP format has recently been expanded with new items." if values.length > high_limit
|
79
76
|
f = self.new(parent)
|
80
|
-
|
81
|
-
f.keyword = values[0]
|
82
|
-
f.rx_site_name = values[1]
|
83
|
-
f.field_name = values[2]
|
84
|
-
f.field_id = values[3]
|
85
|
-
f.field_note = values[4]
|
86
|
-
f.field_dose = values[5]
|
87
|
-
f.field_monitor_units = values[6]
|
88
|
-
f.wedge_monitor_units = values[7]
|
89
|
-
f.treatment_machine = values[8]
|
90
|
-
f.treatment_type = values[9]
|
91
|
-
f.modality = values[10]
|
92
|
-
f.energy = values[11]
|
93
|
-
f.time = values[12]
|
94
|
-
f.doserate = values[13]
|
95
|
-
f.sad = values[14]
|
96
|
-
f.ssd = values[15]
|
97
|
-
f.gantry_angle = values[16]
|
98
|
-
f.collimator_angle = values[17]
|
99
|
-
f.field_x_mode = values[18]
|
100
|
-
f.field_x = values[19]
|
101
|
-
f.collimator_x1 = values[20]
|
102
|
-
f.collimator_x2 = values[21]
|
103
|
-
f.field_y_mode = values[22]
|
104
|
-
f.field_y = values[23]
|
105
|
-
f.collimator_y1 = values[24]
|
106
|
-
f.collimator_y2 = values[25]
|
107
|
-
f.couch_vertical = values[26]
|
108
|
-
f.couch_lateral = values[27]
|
109
|
-
f.couch_longitudinal = values[28]
|
110
|
-
f.couch_angle = values[29]
|
111
|
-
f.couch_pedestal = values[30]
|
112
|
-
f.tolerance_table = values[31]
|
113
|
-
f.arc_direction = values[32]
|
114
|
-
f.arc_start_angle = values[33]
|
115
|
-
f.arc_stop_angle = values[34]
|
116
|
-
f.arc_mu_degree = values[35]
|
117
|
-
f.wedge = values[36]
|
118
|
-
f.dynamic_wedge = values[37]
|
119
|
-
f.block = values[38]
|
120
|
-
f.compensator = values[39]
|
121
|
-
f.e_applicator = values[40]
|
122
|
-
f.e_field_def_aperture = values[41]
|
123
|
-
f.bolus = values[42]
|
124
|
-
f.portfilm_mu_open = values[43]
|
125
|
-
f.portfilm_coeff_open = values[44]
|
126
|
-
f.portfilm_delta_open = values[45]
|
127
|
-
f.portfilm_mu_treat = values[46]
|
128
|
-
f.portfilm_coeff_treat = values[47]
|
129
|
-
f.crc = values[-1]
|
130
|
-
return f
|
77
|
+
f.load(string)
|
131
78
|
end
|
132
79
|
|
133
80
|
# Creates a new (treatment) Field.
|
@@ -135,13 +82,68 @@ module RTP
|
|
135
82
|
# @param [Record] parent a record which is used to determine the proper parent of this instance
|
136
83
|
#
|
137
84
|
def initialize(parent)
|
85
|
+
super('FIELD_DEF', 27, 52)
|
138
86
|
# Child records:
|
139
87
|
@control_points = Array.new
|
140
88
|
@extended_field = nil
|
141
89
|
# Parent relation (may get more than one type of record here):
|
142
90
|
@parent = get_parent(parent.to_record, Prescription)
|
143
91
|
@parent.add_field(self)
|
144
|
-
@
|
92
|
+
@attributes = [
|
93
|
+
# Required:
|
94
|
+
:keyword,
|
95
|
+
:rx_site_name,
|
96
|
+
:field_name,
|
97
|
+
:field_id,
|
98
|
+
:field_note,
|
99
|
+
:field_dose,
|
100
|
+
:field_monitor_units,
|
101
|
+
:wedge_monitor_units,
|
102
|
+
:treatment_machine,
|
103
|
+
:treatment_type,
|
104
|
+
:modality,
|
105
|
+
:energy,
|
106
|
+
:time,
|
107
|
+
:doserate,
|
108
|
+
:sad,
|
109
|
+
:ssd,
|
110
|
+
:gantry_angle,
|
111
|
+
:collimator_angle,
|
112
|
+
:field_x_mode,
|
113
|
+
:field_x,
|
114
|
+
:collimator_x1,
|
115
|
+
:collimator_x2,
|
116
|
+
:field_y_mode,
|
117
|
+
:field_y,
|
118
|
+
:collimator_y1,
|
119
|
+
:collimator_y2,
|
120
|
+
# Optional:
|
121
|
+
:couch_vertical,
|
122
|
+
:couch_lateral,
|
123
|
+
:couch_longitudinal,
|
124
|
+
:couch_angle,
|
125
|
+
:couch_pedestal,
|
126
|
+
:tolerance_table,
|
127
|
+
:arc_direction,
|
128
|
+
:arc_start_angle,
|
129
|
+
:arc_stop_angle,
|
130
|
+
:arc_mu_degree,
|
131
|
+
:wedge,
|
132
|
+
:dynamic_wedge,
|
133
|
+
:block,
|
134
|
+
:compensator,
|
135
|
+
:e_applicator,
|
136
|
+
:e_field_def_aperture,
|
137
|
+
:bolus,
|
138
|
+
:portfilm_mu_open,
|
139
|
+
:portfilm_coeff_open,
|
140
|
+
:portfilm_delta_open,
|
141
|
+
:portfilm_mu_treat,
|
142
|
+
:portfilm_coeff_treat,
|
143
|
+
:iso_pos_x,
|
144
|
+
:iso_pos_y,
|
145
|
+
:iso_pos_z
|
146
|
+
]
|
145
147
|
end
|
146
148
|
|
147
149
|
# Checks for equality.
|
@@ -166,6 +168,7 @@ module RTP
|
|
166
168
|
#
|
167
169
|
def add_control_point(child)
|
168
170
|
@control_points << child.to_control_point
|
171
|
+
child.parent = self
|
169
172
|
end
|
170
173
|
|
171
174
|
# Adds an extended treatment field record to this instance.
|
@@ -174,6 +177,7 @@ module RTP
|
|
174
177
|
#
|
175
178
|
def add_extended_field(child)
|
176
179
|
@extended_field = child.to_extended_field
|
180
|
+
child.parent = self
|
177
181
|
end
|
178
182
|
|
179
183
|
# Collects the child records of this instance in a properly sorted array.
|
@@ -184,109 +188,81 @@ module RTP
|
|
184
188
|
return [@extended_field, @control_points].flatten.compact
|
185
189
|
end
|
186
190
|
|
187
|
-
#
|
191
|
+
# Converts the collimator_x1 attribute to proper DICOM format.
|
188
192
|
#
|
189
|
-
# @
|
193
|
+
# @return [Float] the DICOM-formatted collimator_x1 attribute
|
190
194
|
#
|
191
|
-
|
195
|
+
def dcm_collimator_x1
|
196
|
+
dcm_collimator1(:x)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Converts the collimator_x2 attribute to proper DICOM format.
|
192
200
|
#
|
193
|
-
|
194
|
-
|
201
|
+
# @return [Float] the DICOM-formatted collimator_x2 attribute
|
202
|
+
#
|
203
|
+
def dcm_collimator_x2
|
204
|
+
value = @collimator_x2.to_f * 10
|
195
205
|
end
|
196
206
|
|
197
|
-
#
|
198
|
-
#
|
199
|
-
# @
|
200
|
-
#
|
201
|
-
|
202
|
-
|
203
|
-
return [
|
204
|
-
@keyword,
|
205
|
-
@rx_site_name,
|
206
|
-
@field_name,
|
207
|
-
@field_id,
|
208
|
-
@field_note,
|
209
|
-
@field_dose,
|
210
|
-
@field_monitor_units,
|
211
|
-
@wedge_monitor_units,
|
212
|
-
@treatment_machine,
|
213
|
-
@treatment_type,
|
214
|
-
@modality,
|
215
|
-
@energy,
|
216
|
-
@time,
|
217
|
-
@doserate,
|
218
|
-
@sad,
|
219
|
-
@ssd,
|
220
|
-
@gantry_angle,
|
221
|
-
@collimator_angle,
|
222
|
-
@field_x_mode,
|
223
|
-
@field_x,
|
224
|
-
@collimator_x1,
|
225
|
-
@collimator_x2,
|
226
|
-
@field_y_mode,
|
227
|
-
@field_y,
|
228
|
-
@collimator_y1,
|
229
|
-
@collimator_y2,
|
230
|
-
@couch_vertical,
|
231
|
-
@couch_lateral,
|
232
|
-
@couch_longitudinal,
|
233
|
-
@couch_angle,
|
234
|
-
@couch_pedestal,
|
235
|
-
@tolerance_table,
|
236
|
-
@arc_direction,
|
237
|
-
@arc_start_angle,
|
238
|
-
@arc_stop_angle,
|
239
|
-
@arc_mu_degree,
|
240
|
-
@wedge,
|
241
|
-
@dynamic_wedge,
|
242
|
-
@block,
|
243
|
-
@compensator,
|
244
|
-
@e_applicator,
|
245
|
-
@e_field_def_aperture,
|
246
|
-
@bolus,
|
247
|
-
@portfilm_mu_open,
|
248
|
-
@portfilm_coeff_open,
|
249
|
-
@portfilm_delta_open,
|
250
|
-
@portfilm_mu_treat,
|
251
|
-
@portfilm_coeff_treat
|
252
|
-
]
|
207
|
+
# Converts the collimator_y1 attribute to proper DICOM format.
|
208
|
+
#
|
209
|
+
# @return [Float] the DICOM-formatted collimator_y1 attribute
|
210
|
+
#
|
211
|
+
def dcm_collimator_y1
|
212
|
+
dcm_collimator1(:y)
|
253
213
|
end
|
254
214
|
|
255
|
-
#
|
215
|
+
# Converts the collimator_y2 attribute to proper DICOM format.
|
256
216
|
#
|
257
|
-
# @return [
|
217
|
+
# @return [Float] the DICOM-formatted collimator_y2 attribute
|
258
218
|
#
|
259
|
-
def
|
260
|
-
|
219
|
+
def dcm_collimator_y2
|
220
|
+
value = @collimator_y2.to_f * 10
|
261
221
|
end
|
262
222
|
|
263
|
-
#
|
264
|
-
# to a properly formatted RTPConnect ascii string.
|
223
|
+
# Removes the reference of the given instance from this instance.
|
265
224
|
#
|
266
|
-
# @
|
225
|
+
# @param [ControlPoint, ExtendedField] record a child record to be removed from this instance
|
267
226
|
#
|
268
|
-
def
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
227
|
+
def delete(record)
|
228
|
+
case record
|
229
|
+
when ControlPoint
|
230
|
+
delete_child(:control_points, record)
|
231
|
+
when ExtendedField
|
232
|
+
delete_extended_field
|
233
|
+
else
|
234
|
+
logger.warn("Unknown class (record) given to Field#delete: #{record.class}")
|
274
235
|
end
|
275
|
-
return str
|
276
236
|
end
|
277
237
|
|
278
|
-
|
238
|
+
# Removes all control point references from this instance.
|
239
|
+
#
|
240
|
+
def delete_control_points
|
241
|
+
delete_children(:control_points)
|
242
|
+
end
|
243
|
+
|
244
|
+
# Removes the extended field reference from this instance.
|
245
|
+
#
|
246
|
+
def delete_extended_field
|
247
|
+
delete_child(:extended_field)
|
248
|
+
end
|
279
249
|
|
280
|
-
#
|
250
|
+
# Computes a hash code for this object.
|
251
|
+
#
|
252
|
+
# @note Two objects with the same attributes will have the same hash code.
|
281
253
|
#
|
282
|
-
# @
|
283
|
-
# @param [#to_s] value the new attribute value
|
284
|
-
# @raise [ArgumentError] if given an unexpected keyword
|
254
|
+
# @return [Fixnum] the object's hash code
|
285
255
|
#
|
286
|
-
def
|
287
|
-
|
288
|
-
|
289
|
-
|
256
|
+
def hash
|
257
|
+
state.hash
|
258
|
+
end
|
259
|
+
|
260
|
+
# Returns self.
|
261
|
+
#
|
262
|
+
# @return [Field] self
|
263
|
+
#
|
264
|
+
def to_field
|
265
|
+
self
|
290
266
|
end
|
291
267
|
|
292
268
|
# Sets the rx_site_name attribute.
|
@@ -665,6 +641,30 @@ module RTP
|
|
665
641
|
@portfilm_coeff_treat = value && value.to_s
|
666
642
|
end
|
667
643
|
|
644
|
+
# Sets the iso_pos_x attribute.
|
645
|
+
#
|
646
|
+
# @param [nil, #to_s] value the new attribute value
|
647
|
+
#
|
648
|
+
def iso_pos_x=(value)
|
649
|
+
@iso_pos_x = value && value.to_s.strip
|
650
|
+
end
|
651
|
+
|
652
|
+
# Sets the iso_pos_y attribute.
|
653
|
+
#
|
654
|
+
# @param [nil, #to_s] value the new attribute value
|
655
|
+
#
|
656
|
+
def iso_pos_y=(value)
|
657
|
+
@iso_pos_y = value && value.to_s.strip
|
658
|
+
end
|
659
|
+
|
660
|
+
# Sets the iso_pos_z attribute.
|
661
|
+
#
|
662
|
+
# @param [nil, #to_s] value the new attribute value
|
663
|
+
#
|
664
|
+
def iso_pos_z=(value)
|
665
|
+
@iso_pos_z = value && value.to_s.strip
|
666
|
+
end
|
667
|
+
|
668
668
|
|
669
669
|
private
|
670
670
|
|
@@ -676,6 +676,21 @@ module RTP
|
|
676
676
|
#
|
677
677
|
alias_method :state, :values
|
678
678
|
|
679
|
+
# Converts the collimator attribute to proper DICOM format.
|
680
|
+
#
|
681
|
+
# @param [Symbol] axis a representation for the axis of interest (x or y)
|
682
|
+
# @return [Float] the DICOM-formatted collimator attribute
|
683
|
+
#
|
684
|
+
def dcm_collimator1(axis)
|
685
|
+
value = self.send("collimator_#{axis}1").to_f * 10
|
686
|
+
mode = self.send("field_#{axis}_mode")
|
687
|
+
if mode && mode.upcase == 'SYM' && value > 0
|
688
|
+
-value
|
689
|
+
else
|
690
|
+
value
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
679
694
|
end
|
680
695
|
|
681
696
|
end
|