class PerfectShape::AffineTransform

Represents an affine transform

Attributes

m11[R]
m12[R]
m13[R]
m21[R]
m22[R]
m23[R]
xt[R]
xxp[R]
xyp[R]
yt[R]
yxp[R]
yyp[R]

Public Class Methods

new(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) click to toggle source

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 xyp xt
  • x

    [ xxp * x + xyp * y + xt ]

yxp yyp yt
  • y

    [ yxp * x + yyp * y + yt ]

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

identity!() click to toggle source

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
Also aliased as: reset!
inverse_transform_point(x_or_point, y = nil) click to toggle source
# 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
inverse_transform_points(*xy_coordinates_or_points) click to toggle source
# 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
invert!() click to toggle source

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
invertible?() click to toggle source
# File lib/perfect_shape/affine_transform.rb, line 140
def invertible?
  (m11 * m22 - m12 * m21) != 0
end
m11=(value)
Alias for: xxp=
m12=(value)
Alias for: xyp=
m13=(value)
Alias for: xt=
m21=(value)
Alias for: yxp=
m22=(value)
Alias for: yyp=
m23=(value)
Alias for: yt=
matrix_3d() click to toggle source

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
matrix_3d=(the_matrix_3d) click to toggle source

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
multiply!(other_affine_transform) click to toggle source

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
reset!()
Alias for: identity!
rotate!(degrees) click to toggle source

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
scale!(x_or_point, y = nil) click to toggle source

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
shear!(x_or_point, y = nil) click to toggle source

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
Also aliased as: skew!
skew!(x_or_point, y = nil)
Alias for: shear!
transform_point(x_or_point, y = nil) click to toggle source
# 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
transform_points(*xy_coordinates_or_points) click to toggle source
# 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
translate!(x_or_point, y = nil) click to toggle source

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
xt=(value) click to toggle source
# File lib/perfect_shape/affine_transform.rb, line 105
def xt=(value)
  @xt = BigDecimal(value.to_s)
end
Also aliased as: m13=
xxp=(value) click to toggle source
# File lib/perfect_shape/affine_transform.rb, line 85
def xxp=(value)
  @xxp = BigDecimal(value.to_s)
end
Also aliased as: m11=
xyp=(value) click to toggle source
# File lib/perfect_shape/affine_transform.rb, line 90
def xyp=(value)
  @xyp = BigDecimal(value.to_s)
end
Also aliased as: m12=
yt=(value) click to toggle source
# File lib/perfect_shape/affine_transform.rb, line 110
def yt=(value)
  @yt = BigDecimal(value.to_s)
end
Also aliased as: m23=
yxp=(value) click to toggle source
# File lib/perfect_shape/affine_transform.rb, line 95
def yxp=(value)
  @yxp = BigDecimal(value.to_s)
end
Also aliased as: m21=
yyp=(value) click to toggle source
# File lib/perfect_shape/affine_transform.rb, line 100
def yyp=(value)
  @yyp = BigDecimal(value.to_s)
end
Also aliased as: m22=