Class: RTKIT::Contour
- Inherits:
-
Object
- Object
- RTKIT::Contour
- Defined in:
- lib/rtkit/contour.rb
Overview
Contains DICOM data and methods related to a Contour. A set of Contours in a set of Slices defines a ROI.
Relations
-
The Contour belongs to a Slice.
-
A Contour has many Coordinates.
Resources
-
ROI Contour Module: PS 3.3, C.8.8.6
-
Patient Based Coordinate System: PS 3.3, C.7.6.2.1.1
Instance Attribute Summary collapse
-
#coordinates ⇒ Object
readonly
An array of Coordinates (x,y,z - triplets).
-
#number ⇒ Object
readonly
Contour Number.
-
#slice ⇒ Object
readonly
The Slice that the Contour belongs to.
-
#type ⇒ Object
readonly
Contour Geometric Type.
Class Method Summary collapse
-
.create_from_coordinates(x, y, z, slice) ⇒ Object
Creates a new Contour instance from x, y and z coordinate arrays.
-
.create_from_item(contour_item, slice) ⇒ Object
Creates a new Contour instance from a contour item.
Instance Method Summary collapse
-
#==(other) ⇒ Object
(also: #eql?)
Returns true if the argument is an instance with attributes equal to self.
-
#add_coordinate(coordinate) ⇒ Object
Adds a Coordinate instance to this Contour.
-
#contour_data ⇒ Object
Returns all Coordinates of this Contour, packed to a string in the format used in the Contour Data DICOM Element (3006,0050).
-
#coords ⇒ Object
Returns all Coordinates of this Contour, in arrays of x, y and z coordinates.
-
#create_coordinates(contour_data) ⇒ Object
Creates and connects Coordinate instances with this Contour instance by processing the value of the Contour Data element.
-
#hash ⇒ Object
Generates a Fixnum hash value for this instance.
-
#initialize(slice, options = {}) ⇒ Contour
constructor
Creates a new Contour instance.
-
#to_contour ⇒ Object
Returns self.
-
#to_item ⇒ Object
Creates and returns a Contour Sequence Item from the attributes of the Contour.
Constructor Details
#initialize(slice, options = {}) ⇒ Contour
Creates a new Contour instance.
Parameters
-
slice
– The Slice instance that this Contour belongs to. -
options
– A hash of parameters.
Options
-
:number
– Integer. The Contour Number. -
:type
– String. The Contour Geometric Type. Defaults to ‘CLOSED_PLANAR’.
89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/rtkit/contour.rb', line 89 def initialize(slice, ={}) raise ArgumentError, "Invalid argument 'slice'. Expected Slice, got #{slice.class}." unless slice.is_a?(Slice) raise ArgumentError, "Invalid option :number. Expected Integer, got #{[:number].class}." if [:number] && ![:number].is_a?(Integer) raise ArgumentError, "Invalid option :type. Expected String, got #{[:type].class}." if [:type] && ![:type].is_a?(String) # Key attributes: @coordinates = Array.new @slice = slice @type = [:type] || 'CLOSED_PLANAR' @number = [:number] # don't need a default value for this attribute # Register ourselves with the Slice: @slice.add_contour(self) end |
Instance Attribute Details
#coordinates ⇒ Object (readonly)
An array of Coordinates (x,y,z - triplets).
19 20 21 |
# File 'lib/rtkit/contour.rb', line 19 def coordinates @coordinates end |
#number ⇒ Object (readonly)
Contour Number.
21 22 23 |
# File 'lib/rtkit/contour.rb', line 21 def number @number end |
#slice ⇒ Object (readonly)
The Slice that the Contour belongs to.
23 24 25 |
# File 'lib/rtkit/contour.rb', line 23 def slice @slice end |
#type ⇒ Object (readonly)
Contour Geometric Type.
25 26 27 |
# File 'lib/rtkit/contour.rb', line 25 def type @type end |
Class Method Details
.create_from_coordinates(x, y, z, slice) ⇒ Object
Creates a new Contour instance from x, y and z coordinate arrays. This method also creates and connects any child Coordinates as indicated by the coordinate arrays. Returns the Contour instance.
Parameters
-
x
– An array of x coordinates (Floats). -
y
– An array of y coordinates (Floats). -
z
– An array of z coordinates (Floats). -
slice
– The Slice instance that this Contour belongs to.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/rtkit/contour.rb', line 38 def self.create_from_coordinates(x, y, z, slice) raise ArgumentError, "Invalid argument 'x'. Expected Array, got #{x.class}." unless x.is_a?(Array) raise ArgumentError, "Invalid argument 'y'. Expected Array, got #{y.class}." unless y.is_a?(Array) raise ArgumentError, "Invalid argument 'z'. Expected Array, got #{z.class}." unless z.is_a?(Array) raise ArgumentError, "Invalid argument 'slice'. Expected Slice, got #{slice.class}." unless slice.is_a?(Slice) raise ArgumentError, "The coordinate arrays are of unequal length [#{x.length}, #{y.length}, #{z.length}]." unless [x.length, y.length, z.length].uniq.length == 1 number = slice.roi.num_contours + 1 # Create the Contour: c = self.new(slice, :number => number) # Create the Coordinates belonging to this Contour: x.each_index do |i| Coordinate.new(x[i], y[i], z[i], c) end return c end |
.create_from_item(contour_item, slice) ⇒ Object
Creates a new Contour instance from a contour item. This method also creates and connects any Coordinates as indicated by the item. Returns the Contour instance.
Parameters
-
contour_item
– An array of contour items from the Contour Sequence in ROI Contour Sequence, belonging to the same slice. -
slice
– The Slice instance that this Contour belongs to.
63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/rtkit/contour.rb', line 63 def self.create_from_item(contour_item, slice) raise ArgumentError, "Invalid argument 'contour_item'. Expected Item, got #{contour_item.class}." unless contour_item.is_a?(DICOM::Item) raise ArgumentError, "Invalid argument 'slice'. Expected Slice, got #{slice.class}." unless slice.is_a?(Slice) raise ArgumentError, "Invalid argument 'contour_item'. The specified Item does not contain a Contour Data Value (Element '3006,0050')." unless contour_item.value(CONTOUR_DATA) number = (contour_item.value(CONTOUR_NUMBER) ? contour_item.value(CONTOUR_NUMBER).to_i : nil) type = contour_item.value(CONTOUR_GEO_TYPE) #size = contour_item.value(NR_CONTOUR_POINTS) # May be used for QA of the content of the item, but not needed in the Contour object. # Create the Contour: c = self.new(slice, :type => type, :number => number) # Create the Coordinates belonging to this Contour: c.create_coordinates(contour_item.value(CONTOUR_DATA)) return c end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
Returns true if the argument is an instance with attributes equal to self.
104 105 106 107 108 |
# File 'lib/rtkit/contour.rb', line 104 def ==(other) if other.respond_to?(:to_contour) other.send(:state) == state end end |
#add_coordinate(coordinate) ⇒ Object
Adds a Coordinate instance to this Contour.
114 115 116 117 |
# File 'lib/rtkit/contour.rb', line 114 def add_coordinate(coordinate) raise ArgumentError, "Invalid argument 'coordinate'. Expected Coordinate, got #{coordinate.class}." unless coordinate.is_a?(Coordinate) @coordinates << coordinate unless @coordinates.include?(coordinate) end |
#contour_data ⇒ Object
Returns all Coordinates of this Contour, packed to a string in the format used in the Contour Data DICOM Element (3006,0050). Returns an empty string if the Contour contains no coordinates.
123 124 125 126 |
# File 'lib/rtkit/contour.rb', line 123 def contour_data x, y, z = coords return [x, y, z].transpose.flatten.join("\\") end |
#coords ⇒ Object
Returns all Coordinates of this Contour, in arrays of x, y and z coordinates.
130 131 132 133 134 135 136 137 138 |
# File 'lib/rtkit/contour.rb', line 130 def coords x, y, z = Array.new, Array.new, Array.new @coordinates.each do |coord| x << coord.x y << coord.y z << coord.z end return x, y, z end |
#create_coordinates(contour_data) ⇒ Object
Creates and connects Coordinate instances with this Contour instance by processing the value of the Contour Data element.
Parameters
-
contour_data
– The value of the Contour Data Element (A String of backslash-separated of xyz coordinate triplets).
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/rtkit/contour.rb', line 147 def create_coordinates(contour_data) raise ArgumentError, "Invalid argument 'contour_data'. Expected String (or nil), got #{contour_data.class}." unless [String, NilClass].include?(contour_data.class) if contour_data && contour_data != "" # Split the number strings, sperated by a '\', into an array: string_values = contour_data.split("\\") size = string_values.length/3 # Extract every third value of the string array as x, y, and z, respectively, and collect them as floats instead of strings: x = string_values.values_at(*(Array.new(size){|i| i*3 })).collect{|val| val.to_f} y = string_values.values_at(*(Array.new(size){|i| i*3+1})).collect{|val| val.to_f} z = string_values.values_at(*(Array.new(size){|i| i*3+2})).collect{|val| val.to_f} x.each_index do |i| Coordinate.new(x[i], y[i], z[i], self) end end end |
#hash ⇒ Object
Generates a Fixnum hash value for this instance.
165 166 167 |
# File 'lib/rtkit/contour.rb', line 165 def hash state.hash end |
#to_contour ⇒ Object
Returns self.
181 182 183 |
# File 'lib/rtkit/contour.rb', line 181 def to_contour self end |
#to_item ⇒ Object
Creates and returns a Contour Sequence Item from the attributes of the Contour.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/rtkit/contour.rb', line 187 def to_item # FIXME: We need to decide on how to principally handle the situation when an image series has not been # loaded, and how to set up the ROI slices. A possible solution is to create Image instances if they hasn't been loaded. item = DICOM::Item.new item.add(DICOM::Sequence.new(CONTOUR_IMAGE_SQ)) item[CONTOUR_IMAGE_SQ].add_item item[CONTOUR_IMAGE_SQ][0].add(DICOM::Element.new(REF_SOP_CLASS_UID, @slice.image ? @slice.image.series.class_uid : '1.2.840.10008.5.1.4.1.1.2')) # Deafult to CT if image ref. doesn't exist. item[CONTOUR_IMAGE_SQ][0].add(DICOM::Element.new(REF_SOP_UID, @slice.uid)) item.add(DICOM::Element.new(CONTOUR_GEO_TYPE, @type)) item.add(DICOM::Element.new(NR_CONTOUR_POINTS, @coordinates.length.to_s)) item.add(DICOM::Element.new(CONTOUR_NUMBER, @number.to_s)) item.add(DICOM::Element.new(CONTOUR_DATA, contour_data)) return item end |