Module: Gosling::Transformable
- Included in:
- Actor
- Defined in:
- lib/gosling/transformable.rb
Overview
A helper class for performing vector transforms in 2D space. Relies heavily on the Vec3 and Mat3 classes of the SnowMath gem to remain performant.
Instance Attribute Summary collapse
-
#rotation ⇒ Object
Returns the value of attribute rotation.
Class Method Summary collapse
-
.rational_cos(r) ⇒ Object
Wraps Math.cos to produce rationals instead of floats.
-
.rational_sin(r) ⇒ Object
Wraps Math.sin to produce rationals instead of floats.
-
.transform_point(mat, v) ⇒ Object
Transforms a Vec3 using the provided Mat3 transform and returns the result as a new Vec3.
-
.untransform_point(mat, v) ⇒ Object
Transforms a Vec3 using the inverse of the provided Mat3 transform and returns the result as a new Vec3.
Instance Method Summary collapse
-
#center ⇒ Object
Returns a duplicate of the center Vec3 (@center is read-only).
-
#center=(args) ⇒ Object
(also: #set_center)
Sets this transform’s centerpoint.
-
#center_x ⇒ Object
Returns the x component of the centerpoint of this Transformable.
-
#center_x=(val) ⇒ Object
Sets the x component of the centerpoint of this Transformable.
-
#center_y ⇒ Object
Returns the y component of the centerpoint of this Transformable.
-
#center_y=(val) ⇒ Object
Sets the y component of the centerpoint of this Transformable.
-
#initialize ⇒ Object
Initializes this Transformable to have no transformations (identity matrix).
-
#reset ⇒ Object
Resets center and translation to [0, 0], scale to [1, 1], and rotation to 0, restoring this transformation to the identity matrix.
-
#scale ⇒ Object
Returns a duplicate of the scale Vec2 (@scale is read-only).
-
#scale=(args) ⇒ Object
(also: #set_scale)
Sets this transform’s x/y scaling.
-
#scale_x ⇒ Object
Returns the x component of the scaling of this Transformable.
-
#scale_x=(val) ⇒ Object
Wrapper method.
-
#scale_y ⇒ Object
Returns the y component of the scaling of this Transformable.
-
#scale_y=(val) ⇒ Object
Wrapper method.
-
#to_matrix ⇒ Object
Returns a Snow::Mat3 which combines our current center, scale, rotation, and translation into a single transform matrix.
-
#transform_point(v) ⇒ Object
Applies all of our transformations to the point, returning the resulting point as a new Vec3.
-
#translation ⇒ Object
(also: #pos)
Returns a duplicate of the translation Vec3 (@translation is read-only).
-
#translation=(args) ⇒ Object
(also: #set_translation, #pos=)
Sets this transform’s x/y translation in radians.
-
#untransform_point(v) ⇒ Object
Applies the inverse of all of our transformations to the point, returning the resulting point as a new Vec3.
-
#x ⇒ Object
Returns this Transformable’s x position in relative space.
-
#x=(val) ⇒ Object
Sets this Transformable’s x position in relative space.
-
#y ⇒ Object
Returns this Transformable’s y position in relative space.
-
#y=(val) ⇒ Object
Sets this Transformable’s y position in relative space.
Instance Attribute Details
#rotation ⇒ Object
Returns the value of attribute rotation.
54 55 56 |
# File 'lib/gosling/transformable.rb', line 54 def rotation @rotation end |
Class Method Details
.rational_cos(r) ⇒ Object
Wraps Math.cos to produce rationals instead of floats. Common values are returned quickly from a lookup table.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/gosling/transformable.rb', line 36 def self.rational_cos(r) type_check(r, Numeric) r = r % (2 * Math::PI) case r when 0.0 1.to_r when Math::PI / 2 0.to_r when Math::PI -1.to_r when Math::PI * 3 / 2 0.to_r else Math.cos(r).to_r end end |
.rational_sin(r) ⇒ Object
Wraps Math.sin to produce rationals instead of floats. Common values are returned quickly from a lookup table.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/gosling/transformable.rb', line 15 def self.rational_sin(r) type_check(r, Numeric) r = r % (2 * Math::PI) case r when 0.0 0.to_r when Math::PI / 2 1.to_r when Math::PI 0.to_r when Math::PI * 3 / 2 -1.to_r else Math.sin(r).to_r end end |
.transform_point(mat, v) ⇒ Object
Transforms a Vec3 using the provided Mat3 transform and returns the result as a new Vec3. This is the opposite of Transformable.untransform_point.
347 348 349 350 351 352 353 |
# File 'lib/gosling/transformable.rb', line 347 def self.transform_point(mat, v) type_check(mat, Snow::Mat3) type_check(v, Snow::Vec3) result = mat * Snow::Vec3[v[0], v[1], 1.to_r] result[2] = 0.to_r result end |
.untransform_point(mat, v) ⇒ Object
Transforms a Vec3 using the inverse of the provided Mat3 transform and returns the result as a new Vec3. This is the opposite of Transformable.transform_point.
367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/gosling/transformable.rb', line 367 def self.untransform_point(mat, v) type_check(mat, Snow::Mat3) type_check(v, Snow::Vec3) inverse_mat = mat.inverse unless inverse_mat raise "Unable to invert matrix: #{mat}!" end result = mat.inverse * Snow::Vec3[v[0], v[1], 1.to_r] result[2] = 0.to_r result end |
Instance Method Details
#center ⇒ Object
Returns a duplicate of the center Vec3 (@center is read-only).
80 81 82 |
# File 'lib/gosling/transformable.rb', line 80 def center @center.dup.freeze end |
#center=(args) ⇒ Object Also known as: set_center
Sets this transform’s centerpoint. All other transforms are performed relative to this central point.
The default centerpoint is [0, 0], which is the same as no transform. For a square defined by the vertices [[0, 0], [10, 0], [10, 10], [0, 10]], this would translate to that square’s upper left corner. In this case, when scaled larger or smaller, only the square’s right and bottom edges would expand or contract, and when rotated it would spin around its upper left corner. For most applications, this is probably not what we want.
By setting the centerpoint to something other than the origin, we can change the scaling and rotation to something that makes more sense. For the square defined above, we could set center to be the actual center of the square: [5, 5]. By doing so, scaling the square would cause it to expand evenly on all sides, and rotating it would cause it to spin about its center like a four-cornered wheel.
You can set the centerpoint to be any point in local space, inside or even outside of the shape in question.
If passed more than two numeric arguments, only the first two are used.
Usage:
-
transform.center = x, y
-
transform.center = [x, y]
-
transform.center = Snow::Vec2[x, y]
-
transform.center = Snow::Vec3[x, y, z]
-
transform.center = Snow::Vec4[x, y, z, c]
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/gosling/transformable.rb', line 165 def center=(args) case args[0] when Array self.center = args[0][0], args[0][1] when Snow::Vec2, Snow::Vec3, Snow::Vec4 @center.x = args[0].x @center.y = args[0].y when Numeric raise ArgumentError.new("Cannot set center from #{args.inspect}: numeric array requires at least two arguments!") unless args.length >= 2 args.each { |arg| type_check(arg, Numeric) } @center.x = args[0] @center.y = args[1] else raise ArgumentError.new("Cannot set center from #{args.inspect}: bad type!") end @center_is_dirty = @is_dirty = true end |
#center_x ⇒ Object
Returns the x component of the centerpoint of this Transformable. See Transformable#center.
87 88 89 |
# File 'lib/gosling/transformable.rb', line 87 def center_x @center.x end |
#center_x=(val) ⇒ Object
Sets the x component of the centerpoint of this Transformable. See Transformable#center.
187 188 189 190 191 |
# File 'lib/gosling/transformable.rb', line 187 def center_x=(val) type_check(val, Numeric) @center.x = val @center_is_dirty = @is_dirty = true end |
#center_y ⇒ Object
Returns the y component of the centerpoint of this Transformable. See Transformable#center.
94 95 96 |
# File 'lib/gosling/transformable.rb', line 94 def center_y @center.y end |
#center_y=(val) ⇒ Object
Sets the y component of the centerpoint of this Transformable. See Transformable#center.
196 197 198 199 200 |
# File 'lib/gosling/transformable.rb', line 196 def center_y=(val) type_check(val, Numeric) @center.y = val @center_is_dirty = @is_dirty = true end |
#initialize ⇒ Object
Initializes this Transformable to have no transformations (identity matrix).
59 60 61 62 63 64 |
# File 'lib/gosling/transformable.rb', line 59 def initialize @center = Snow::Vec3[0.to_r, 0.to_r, 1.to_r] @scale = Snow::Vec2[1.to_r, 1.to_r] @translation = Snow::Vec3[0.to_r, 0.to_r, 1.to_r] reset end |
#reset ⇒ Object
Resets center and translation to [0, 0], scale to [1, 1], and rotation to 0, restoring this transformation to the identity matrix.
70 71 72 73 74 75 |
# File 'lib/gosling/transformable.rb', line 70 def reset self.center = 0.to_r, 0.to_r self.scale = 1.to_r, 1.to_r self.rotation = 0.to_r self.translation = 0.to_r, 0.to_r end |
#scale ⇒ Object
Returns a duplicate of the scale Vec2 (@scale is read-only).
101 102 103 |
# File 'lib/gosling/transformable.rb', line 101 def scale @scale.dup.freeze end |
#scale=(args) ⇒ Object Also known as: set_scale
Sets this transform’s x/y scaling. A scale value of [1, 1] results in no scaling. Larger values make a shape bigger, while smaller values will make it smaller. Great for shrinking/growing animations, or to zoom the camera in/out.
If passed more than two numeric arguments, only the first two are used.
Usage:
-
transform.scale = x, y
-
transform.scale = [x, y]
-
transform.scale = Snow::Vec2[x, y]
-
transform.scale = Snow::Vec3[x, y, z]
-
transform.scale = Snow::Vec4[x, y, z, c]
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/gosling/transformable.rb', line 215 def scale=(args) case args[0] when Array self.scale = args[0][0], args[0][1] when Snow::Vec2, Snow::Vec3, Snow::Vec4 @scale.x = args[0].x @scale.y = args[0].y when Numeric raise ArgumentError.new("Cannot set scale from #{args.inspect}: numeric array requires at least two arguments!") unless args.length >= 2 args.each { |arg| type_check(arg, Numeric) } @scale.x = args[0] @scale.y = args[1] else raise ArgumentError.new("Cannot set scale from #{args.inspect}: bad type!") end @scale_is_dirty = @is_dirty = true end |
#scale_x ⇒ Object
Returns the x component of the scaling of this Transformable. See Transformable#scale.
108 109 110 |
# File 'lib/gosling/transformable.rb', line 108 def scale_x @scale.x end |
#scale_x=(val) ⇒ Object
Wrapper method. Sets the x component of the scaling of this Actor. See Transformable#scale.
237 238 239 240 241 |
# File 'lib/gosling/transformable.rb', line 237 def scale_x=(val) type_check(val, Numeric) @scale.x = val @scale_is_dirty = @is_dirty = true end |
#scale_y ⇒ Object
Returns the y component of the scaling of this Transformable. See Transformable#scale.
115 116 117 |
# File 'lib/gosling/transformable.rb', line 115 def scale_y @scale.y end |
#scale_y=(val) ⇒ Object
Wrapper method. Sets the y component of the scaling of this Actor. See Transformable#scale.
246 247 248 249 250 |
# File 'lib/gosling/transformable.rb', line 246 def scale_y=(val) type_check(val, Numeric) @scale.y = val @scale_is_dirty = @is_dirty = true end |
#to_matrix ⇒ Object
Returns a Snow::Mat3 which combines our current center, scale, rotation, and translation into a single transform matrix. When a point in space is multiplied by this transform, the centering, scaling, rotation, and translation will all be applied to that point.
This Snow::Mat3 is cached and will only be recalculated as needed.
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/gosling/transformable.rb', line 324 def to_matrix return @matrix unless @is_dirty || @matrix.nil? update_center_matrix update_scale_matrix update_rotate_matrix update_translate_matrix @matrix = Snow::Mat3.new unless @matrix @matrix.set(@center_mat) @matrix.multiply!(@scale_mat) @matrix.multiply!(@rotate_mat) @matrix.multiply!(@translate_mat) @is_dirty = false @matrix end |
#transform_point(v) ⇒ Object
Applies all of our transformations to the point, returning the resulting point as a new Vec3. This is the opposite of Transformable#untransform_point.
359 360 361 |
# File 'lib/gosling/transformable.rb', line 359 def transform_point(v) Transformable.transform_point(to_matrix, v) end |
#translation ⇒ Object Also known as: pos
Returns a duplicate of the translation Vec3 (@translation is read-only).
122 123 124 |
# File 'lib/gosling/transformable.rb', line 122 def translation @translation.dup.freeze end |
#translation=(args) ⇒ Object Also known as: set_translation, pos=
Sets this transform’s x/y translation in radians. A value of [0, 0] results in no translation. Great for moving actors across the screen or scrolling the camera.
If passed more than two numeric arguments, only the first two are used.
Usage:
-
transform.translation = x, y
-
transform.translation = [x, y]
-
transform.translation = Snow::Vec2[x, y]
-
transform.translation = Snow::Vec3[x, y, z]
-
transform.translation = Snow::Vec4[x, y, z, c]
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/gosling/transformable.rb', line 279 def translation=(args) case args[0] when Array self.translation = args[0][0], args[0][1] when Snow::Vec2, Snow::Vec3, Snow::Vec4 @translation.x = args[0].x @translation.y = args[0].y when Numeric raise ArgumentError.new("Cannot set translation from #{args.inspect}: numeric array requires at least two arguments!") unless args.length >= 2 args.each { |arg| type_check(arg, Numeric) } @translation.x = args[0] @translation.y = args[1] else raise ArgumentError.new("Cannot set translation from #{args.inspect}: bad type!") end @translate_is_dirty = @is_dirty = true end |
#untransform_point(v) ⇒ Object
Applies the inverse of all of our transformations to the point, returning the resulting point as a new Vec3. This is the opposite of Transformable#transform_point.
383 384 385 |
# File 'lib/gosling/transformable.rb', line 383 def untransform_point(v) Transformable.untransform_point(to_matrix, v) end |
#x ⇒ Object
Returns this Transformable’s x position in relative space. See Transformable#translation.
130 131 132 |
# File 'lib/gosling/transformable.rb', line 130 def x @translation.x end |
#x=(val) ⇒ Object
Sets this Transformable’s x position in relative space. See Transformable#translation.
302 303 304 305 306 |
# File 'lib/gosling/transformable.rb', line 302 def x=(val) type_check(val, Numeric) @translation.x = val @translate_is_dirty = @is_dirty = true end |
#y ⇒ Object
Returns this Transformable’s y position in relative space. See Transformable#translation.
137 138 139 |
# File 'lib/gosling/transformable.rb', line 137 def y @translation.y end |
#y=(val) ⇒ Object
Sets this Transformable’s y position in relative space. See Transformable#translation.
311 312 313 314 315 |
# File 'lib/gosling/transformable.rb', line 311 def y=(val) type_check(val, Numeric) @translation.y = val @translate_is_dirty = @is_dirty = true end |