class PerfectShape::AffineTransform
Represents an affine transform
Attributes
Public Class Methods
Creates a new AffineTransform
with the following Matrix:
- xxp xyp xt
- yxp yyp yt
-
The Matrix is used to transform (x,y) point coordinates as follows:
xxp is the x coordinate x product (m11) xyp is the x coordinate y product (m12) yxp is the y coordinate x product (m21) yyp is the y coordinate y product (m22) xt is the x coordinate translation (m13) yt is the y coordinate translation (m23)
The constructor accepts either the (x,y)-operation related argument/kwarg names or traditional Matrix element kwarg names
Example with (x,y)-operation kwarg names:
AffineTransform.new
(xxp: 2, xyp: 3, yxp: 4, yyp: 5, xt: 6, yt: 7)Example with traditional Matrix element kwarg names:
AffineTransform.new
(m11: 2, m12: 3, m21: 4, m22: 5, m13: 6, m23: 7)Example with standard arguments:
AffineTransform.new
(2, 3, 4, 5, 6, 7)If no arguments are supplied, it constructs an identity matrix (i.e. like calling ‘::new(xxp: 1, xyp: 0, yxp: 0, yyp: 1, xt: 0, yt: 0)`)
# File lib/perfect_shape/affine_transform.rb, line 74 def initialize(xxp_element = nil, xyp_element = nil, yxp_element = nil, yyp_element = nil, xt_element = nil, yt_element = nil, xxp: nil, xyp: nil, yxp: nil, yyp: nil, xt: nil, yt: nil, m11: nil, m12: nil, m21: nil, m22: nil, m13: nil, m23: nil) self.xxp = xxp_element || xxp || m11 || 1 self.xyp = xyp_element || xyp || m12 || 0 self.yxp = yxp_element || yxp || m21 || 0 self.yyp = yyp_element || yyp || m22 || 1 self.xt = xt_element || xt || m13 || 0 self.yt = yt_element || yt || m23 || 0 end
Public Instance Methods
Resets to identity matrix Returns self to support fluent interface chaining
# File lib/perfect_shape/affine_transform.rb, line 117 def identity! self.xxp = 1 self.xyp = 0 self.yxp = 0 self.yyp = 1 self.xt = 0 self.yt = 0 self end
# File lib/perfect_shape/affine_transform.rb, line 219 def inverse_transform_point(x_or_point, y = nil) clone.invert!.transform_point(x_or_point, y) end
# File lib/perfect_shape/affine_transform.rb, line 229 def inverse_transform_points(*xy_coordinates_or_points) points = xy_coordinates_or_points.first.is_a?(Array) ? xy_coordinates_or_points.first : xy_coordinates_or_points points = MultiPoint.normalize_point_array(points) points.map { |point| inverse_transform_point(point) } end
Inverts AffineTransform
matrix if invertible Raises an error if affine transform matrix is not invertible Returns self to support fluent interface chaining
# File lib/perfect_shape/affine_transform.rb, line 132 def invert! raise 'Cannot invert (matrix is not invertible)!' if !invertible? self.matrix_3d = matrix_3d.inverse self end
# File lib/perfect_shape/affine_transform.rb, line 140 def invertible? (m11 * m22 - m12 * m21) != 0 end
Returns Ruby Matrix representing Affine Transform matrix elements in 3D
# File lib/perfect_shape/affine_transform.rb, line 208 def matrix_3d Matrix[[xxp, xyp, xt], [yxp, yyp, yt], [0, 0, 1]] end
Sets elements from a Ruby Matrix representing Affine Transform matrix elements in 3D
# File lib/perfect_shape/affine_transform.rb, line 198 def matrix_3d=(the_matrix_3d) self.xxp = the_matrix_3d[0, 0] self.xyp = the_matrix_3d[0, 1] self.xt = the_matrix_3d[0, 2] self.yxp = the_matrix_3d[1, 0] self.yyp = the_matrix_3d[1, 1] self.yt = the_matrix_3d[1, 2] end
Multiplies by other AffineTransform
# File lib/perfect_shape/affine_transform.rb, line 145 def multiply!(other_affine_transform) self.matrix_3d = matrix_3d*other_affine_transform.matrix_3d self end
Rotates AffineTransform
counter-clockwise for positive angle value in degrees or clockwise for negative angle value in degrees
# File lib/perfect_shape/affine_transform.rb, line 175 def rotate!(degrees) degrees = Math.normalize_degrees(degrees) radians = Math.degrees_to_radians(degrees) rotation_affine_transform = AffineTransform.new(xxp: Math.cos(radians), xyp: -Math.sin(radians), yxp: Math.sin(radians), yyp: Math.cos(radians), xt: 0, yt: 0) multiply!(rotation_affine_transform) self end
Scales AffineTransform
# File lib/perfect_shape/affine_transform.rb, line 163 def scale!(x_or_point, y = nil) x, y = Point.normalize_point(x_or_point, y) return unless x && y scale_affine_transform = AffineTransform.new(xxp: x, xyp: 0, yxp: 0, yyp: y, xt: 0, yt: 0) multiply!(scale_affine_transform) self end
Shears AffineTransform
by (x,y) amount
# File lib/perfect_shape/affine_transform.rb, line 186 def shear!(x_or_point, y = nil) x, y = Point.normalize_point(x_or_point, y) return unless x && y shear_affine_transform = AffineTransform.new(xxp: 1 + x*y, xyp: x, yxp: y, yyp: 1, xt: 0, yt: 0) multiply!(shear_affine_transform) self end
# File lib/perfect_shape/affine_transform.rb, line 212 def transform_point(x_or_point, y = nil) x, y = Point.normalize_point(x_or_point, y) return unless x && y [xxp*x + xyp*y + xt, yxp*x + yyp*y + yt] end
# File lib/perfect_shape/affine_transform.rb, line 223 def transform_points(*xy_coordinates_or_points) points = xy_coordinates_or_points.first.is_a?(Array) ? xy_coordinates_or_points.first : xy_coordinates_or_points points = MultiPoint.normalize_point_array(points) points.map { |point| transform_point(point) } end
Translates AffineTransform
# File lib/perfect_shape/affine_transform.rb, line 152 def translate!(x_or_point, y = nil) x, y = Point.normalize_point(x_or_point, y) return unless x && y translation_affine_transform = AffineTransform.new(xxp: 1, xyp: 0, yxp: 0, yyp: 1, xt: x, yt: y) multiply!(translation_affine_transform) self end
# File lib/perfect_shape/affine_transform.rb, line 105 def xt=(value) @xt = BigDecimal(value.to_s) end
# File lib/perfect_shape/affine_transform.rb, line 85 def xxp=(value) @xxp = BigDecimal(value.to_s) end
# File lib/perfect_shape/affine_transform.rb, line 90 def xyp=(value) @xyp = BigDecimal(value.to_s) end
# File lib/perfect_shape/affine_transform.rb, line 110 def yt=(value) @yt = BigDecimal(value.to_s) end
# File lib/perfect_shape/affine_transform.rb, line 95 def yxp=(value) @yxp = BigDecimal(value.to_s) end
# File lib/perfect_shape/affine_transform.rb, line 100 def yyp=(value) @yyp = BigDecimal(value.to_s) end