#--
# $Id: transformable.rb,v 1.1 2005/03/12 17:02:00 rmagick Exp $
# Copyright (C) 2005 Timothy P. Hunter
#++
class Magick::RVG
# Transforms is an Array with a deep_copy method.
# During unit-testing it also has a deep_equal method.
class Transforms < Array #:nodoc:
def deep_copy(h=nil)
copy = self.class.new
each { |transform| copy << [transform[0], transform[1].dup] }
return copy
end
end # class Transform
# Transformations are operations on the coordinate system.
# All the transformations defined within a container (an RVG object
# or a group) are applied before drawing any shapes or text.
# All transformations are applied in the order they were
# defined. Note: This means that
# g.translate(10,20).scale(2)
# is not the same as
# g.scale(2).translate(10,20)
module Transformable
private
# Apply transforms in the same order they were specified!
def add_transform_primitives(gc)
@transforms.each { |transform| gc.__send__(transform[0], *transform[1]) }
end
def initialize(*args, &block)
super()
@transforms = Transforms.new
end
public
# Applies the transformation matrix [sx, rx, ry, sy, tx, ty]
def matrix(sx, rx, ry, sy, tx, ty)
begin
@transforms << [:affine, [Float(sx), Float(rx), Float(ry), Float(sy), Float(tx), Float(ty)]]
rescue ArgumentError
raise ArgumentError, "arguments must be convertable to float (got #{sx.class}, #{rx.class}, #{ry.class}, #{sy.class}, #{sx.class}, #{sx.class}, #{tx.class}, #{ty.class})"
end
yield(self) if block_given?
self
end
# Add tx to all x-coordinates and ty
# to all y-coordinates. If ty is omitted it defaults
# to tx.
def translate(tx, ty=nil)
ty ||= tx
begin
@transforms << [:translate, [Float(tx), Float(ty)]]
rescue ArgumentError
raise ArgumentError, "arguments must be convertable to float (got #{tx.class}, #{ty.class})"
end
yield(self) if block_given?
self
end
# Multiply the x-coordinates by sx and the y-coordinates
# by sy. If sy is omitted it defaults to sx.
def scale(sx, sy=nil)
sy ||= sx
begin
@transforms << [:scale, [Float(sx), Float(sy)]]
rescue ArgumentError
raise ArgumentError, "arguments must be convertable to float (got #{sx.class}, #{sy.class})"
end
yield(self) if block_given?
self
end
# This method can take either of two argument lists:
# [rotate(angle)] rotate by angle degrees
# [rotate(angle, cx, cy)] rotate by angle degrees about
# the point [cx, cy].
def rotate(angle, *args)
begin
case args.length
when 0
@transforms << [:rotate, [Float(angle)]]
when 2
cx, cy = Float(args[0]), Float(args[1])
@transforms << [:translate, [cx, cy]]
@transforms << [:rotate, [angle]]
@transforms << [:translate, [-cx, -cy]]
else
raise ArgumentError, "wrong number of arguments (#{args.length} for 1 or 3)"
end
rescue ArgumentError
raise ArgumentError, "arguments must be convertable to float (got #{[angle, *args].collect {|a| a.class}.join(', ')})"
end
yield(self) if block_given?
self
end
# Skew the X-axis by angle degrees.
def skewX(angle)
begin
@transforms << [:skewx, [Float(angle)]]
rescue ArgumentError
raise ArgumentError, "argument must be convertable to float (got #{angle.class})"
end
yield(self) if block_given?
self
end
# Skew the Y-axis by angle degrees.
def skewY(angle)
begin
@transforms << [:skewy, [Float(angle)]]
rescue ArgumentError
raise ArgumentError, "argument must be convertable to float (got #{angle.class})"
end
yield(self) if block_given?
self
end
end # module Transformable
end # class Magick::RVG