Class: Geometry::Vector
- Inherits:
-
Object
- Object
- Geometry::Vector
- Defined in:
- lib/geometry/vector/vector.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#x ⇒ Object
Returns the value of attribute x.
-
#y ⇒ Object
Returns the value of attribute y.
-
#z ⇒ Object
Returns the value of attribute z.
Class Method Summary collapse
-
.from_polar(magnitude, angle, options = {}) ⇒ Object
Return an x/y vector based on a magnitude and a heading.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #add(other) ⇒ Object (also: #+)
-
#angle(other) ⇒ Object
Return the angle (in radians) between self and the passed in vector.
-
#cross(other) ⇒ Object
(also: #vector_product)
Return the cross product of self and the passed in vector.
-
#cross_length(other) ⇒ Object
Return the magnitude of the cross product of self and the passed in vector.
-
#cross_normal(other) ⇒ Object
Return the unit vector of the cross product of self and the passed in vector.
-
#distance(other) ⇒ Object
Return the cartesian distance between self and the passed vector.
-
#distance_from_line(point_a, point_b) ⇒ Object
Calculate the distance of self from the infinite line passing through the two passed in points.
-
#distance_from_line_segment(point_a, point_b) ⇒ Object
Calculate the distance of self from the line segment starting and ending with the two passed in points.
- #distance_from_polyline(polyline) ⇒ Object
- #divide(n) ⇒ Object (also: #/)
-
#dot(other) ⇒ Object
(also: #scalar_product)
Return the dot product of self and the passed in vector.
- #heading ⇒ Object
-
#initialize(x, y, z = 0) ⇒ Vector
constructor
A new instance of Vector.
- #inspect ⇒ Object
-
#magnitude ⇒ Object
(also: #r)
Return the magnitude of self.
- #multiply(n) ⇒ Object (also: #*)
-
#normalize ⇒ Object
Normalize self, that is, return the unit vector with the same direction as self.
-
#orthogonal?(other) ⇒ Boolean
Returns true of the passed in vector is perpendicular to self.
-
#parallel?(other) ⇒ Boolean
Returns true if the passed in vector is parallel to self.
- #scale(scalar) ⇒ Object
- #subtract(other) ⇒ Object (also: #-)
Constructor Details
#initialize(x, y, z = 0) ⇒ Vector
Returns a new instance of Vector.
18 19 20 21 22 |
# File 'lib/geometry/vector/vector.rb', line 18 def initialize(x, y, z = 0) @x = x.to_f @y = y.to_f @z = z.to_f end |
Instance Attribute Details
#x ⇒ Object
Returns the value of attribute x.
16 17 18 |
# File 'lib/geometry/vector/vector.rb', line 16 def x @x end |
#y ⇒ Object
Returns the value of attribute y.
16 17 18 |
# File 'lib/geometry/vector/vector.rb', line 16 def y @y end |
#z ⇒ Object
Returns the value of attribute z.
16 17 18 |
# File 'lib/geometry/vector/vector.rb', line 16 def z @z end |
Class Method Details
.from_polar(magnitude, angle, options = {}) ⇒ Object
Return an x/y vector based on a magnitude and a heading.
7 8 9 10 11 12 13 14 |
# File 'lib/geometry/vector/vector.rb', line 7 def self.from_polar(magnitude, angle, = {}) angle = Geometry.deg_to_rad(angle) if [:unit] = :deg y = Math.sin(angle) * magnitude x = Math.cos(angle) * magnitude self.new(x,y) end |
Instance Method Details
#==(other) ⇒ Object
134 135 136 |
# File 'lib/geometry/vector/vector.rb', line 134 def ==(other) @x == other.x && @y == other.y && @z == other.z end |
#add(other) ⇒ Object Also known as: +
24 25 26 |
# File 'lib/geometry/vector/vector.rb', line 24 def add(other) self.class.new(@x + other.x, @y + other.y, @z + other.z) end |
#angle(other) ⇒ Object
Return the angle (in radians) between self and the passed in vector.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/geometry/vector/vector.rb', line 99 def angle(other) # Two options here: # # 1. Math.atan2(other.cross_length(self), dot(other)) # # This is stable but slower (x 1.5) # # 2. Math.acos(dot(other) / (r * other.r)) # # This is faster but unstable around 0 and pi where the gradient of acos approaches # infinity. An alternative way to view this is that the gradient of cos approaches # zero and small differences in angle can be indistinguishable at some number of # decimal places. # # Math.acos(dot(other) / (r * other.r)) Math.atan2(other.cross_length(self), dot(other)) end |
#cross(other) ⇒ Object Also known as: vector_product
Return the cross product of self and the passed in vector.
70 71 72 73 74 75 76 |
# File 'lib/geometry/vector/vector.rb', line 70 def cross(other) new_x = (@y * other.z) - (@z * other.y) new_y = (@z * other.x) - (@x * other.z) new_z = (@x * other.y) - (@y * other.x) self.class.new(new_x, new_y, new_z) end |
#cross_length(other) ⇒ Object
Return the magnitude of the cross product of self and the passed in vector.
81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/geometry/vector/vector.rb', line 81 def cross_length(other) # cross(other).magnitude # It is more efficient to not create a new Vector object since we are only returning # a scalar value new_x = (@y * other.z) - (@z * other.y) new_y = (@z * other.x) - (@x * other.z) new_z = (@x * other.y) - (@y * other.x) Math.sqrt(new_x ** 2 + new_y ** 2 + new_z ** 2) end |
#cross_normal(other) ⇒ Object
Return the unit vector of the cross product of self and the passed in vector.
94 95 96 |
# File 'lib/geometry/vector/vector.rb', line 94 def cross_normal(other) cross(other).normalize end |
#distance(other) ⇒ Object
Return the cartesian distance between self and the passed vector
120 121 122 |
# File 'lib/geometry/vector/vector.rb', line 120 def distance(other) (other - self).magnitude.abs end |
#distance_from_line(point_a, point_b) ⇒ Object
Calculate the distance of self from the infinite line passing through the two passed in points.
139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/geometry/vector/vector.rb', line 139 def distance_from_line(point_a,point_b) # Define the line as the vector between two points line_vector = point_b - point_a # Define a second vector representing the distance between self and the line start point_vector = self - point_a # The magnitude of the cross product is equal to the area of the parallelogram described # by the two vectors. Dividing by the line length gives the perpendicular distance. (line_vector.cross(point_vector).magnitude / line_vector.magnitude).abs end |
#distance_from_line_segment(point_a, point_b) ⇒ Object
Calculate the distance of self from the line segment starting and ending with the two passed in points.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/geometry/vector/vector.rb', line 153 def distance_from_line_segment(point_a,point_b) # Define the line as the vector between two points line_vector = point_b - point_a # Define a second vector representing the distance between self and the line start point_vector = self - point_a # Determine if self falls within the perpendicular 'shadow' of the line by calculating # the projection of the point vector onto the line. # # The dot product divided by the magnitude of the line gives the absolute projection # of the point vector onto the line. # # Dividing again by the line magnitude gives the relative projection along the line, # i.e. the ratio of the projection to the line. Values between 0-1 indicate that the # point falls within the perpendicular shadow. # projection_ratio = line_vector.dot(point_vector) / line_vector.magnitude ** 2 if projection_ratio >= 1 # The point is beyond point b, calculate distance to point b distance = (point_b - self).magnitude elsif projection_ratio <= 0 # The point is beyond point a, calculate distance to point a distance = (point_a - self).magnitude else # The point is in the shadow of the line, return the perpendicular distance distance = line_vector.cross(point_vector).magnitude / line_vector.magnitude end return distance.abs end |
#distance_from_polyline(polyline) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/geometry/vector/vector.rb', line 187 def distance_from_polyline(polyline) # memoize the last processed point as both array and vector objects last_array = polyline.first last_vector = self.class.new(last_array[0], last_array[1], last_array[2]) # this should support 3 arguments surely?! minimum_distance = 999999999999 polyline[1..-1].each do |vertex| next if vertex == last_array start_vector = last_vector end_vector = self.class.new(vertex[0],vertex[1], vertex[2]) # this should support 3 arguments surely?! this_segment_distance = distance_from_line_segment(start_vector, end_vector) if(this_segment_distance < minimum_distance) minimum_distance = this_segment_distance end last_array = vertex last_vector = end_vector end return minimum_distance end |
#divide(n) ⇒ Object Also known as: /
39 40 41 |
# File 'lib/geometry/vector/vector.rb', line 39 def divide(n) scale(1.0/n.to_f) end |
#dot(other) ⇒ Object Also known as: scalar_product
Return the dot product of self and the passed in vector.
64 65 66 |
# File 'lib/geometry/vector/vector.rb', line 64 def dot(other) return (@x * other.x) + (@y * other.y) + (@z * other.z) end |
#heading ⇒ Object
59 60 61 |
# File 'lib/geometry/vector/vector.rb', line 59 def heading Math.atan2(@y,@x) end |
#inspect ⇒ Object
215 216 217 |
# File 'lib/geometry/vector/vector.rb', line 215 def inspect puts "[#{@x}, #{@y}, #{@z}]" end |
#magnitude ⇒ Object Also known as: r
Return the magnitude of self.
45 46 47 |
# File 'lib/geometry/vector/vector.rb', line 45 def magnitude Math.sqrt(@x ** 2 + @y ** 2 + @z ** 2) end |
#multiply(n) ⇒ Object Also known as: *
34 35 36 |
# File 'lib/geometry/vector/vector.rb', line 34 def multiply(n) scale(n.to_f) end |
#normalize ⇒ Object
Normalize self, that is, return the unit vector with the same direction as self.
55 56 57 |
# File 'lib/geometry/vector/vector.rb', line 55 def normalize divide(magnitude) end |
#orthogonal?(other) ⇒ Boolean
Returns true of the passed in vector is perpendicular to self.
125 126 127 |
# File 'lib/geometry/vector/vector.rb', line 125 def orthogonal?(other) dot(other) == 0 end |
#parallel?(other) ⇒ Boolean
Returns true if the passed in vector is parallel to self.
130 131 132 |
# File 'lib/geometry/vector/vector.rb', line 130 def parallel?(other) cross(other).magnitude == 0 end |
#scale(scalar) ⇒ Object
50 51 52 |
# File 'lib/geometry/vector/vector.rb', line 50 def scale(scalar) self.class.new(@x * scalar, @y * scalar, @z * scalar) end |
#subtract(other) ⇒ Object Also known as: -
29 30 31 |
# File 'lib/geometry/vector/vector.rb', line 29 def subtract(other) self.class.new(@x - other.x, @y - other.y, @z - other.z) end |