lib/rubysketch/processing.rb in rubysketch-0.3.2 vs lib/rubysketch/processing.rb in rubysketch-0.3.3
- old
+ new
@@ -4,45 +4,599 @@
# Processing compatible API
#
module Processing
+ # Vector class.
+ #
+ class Vector
+
+ include Comparable
+
+ # Initialize vector object.
+ #
+ # @overload new()
+ # @overload new(x)
+ # @overload new(x, y)
+ # @overload new(x, y, z)
+ # @overload new(v)
+ # @overload new(a)
+ #
+ # @param x [Numeric] x of vector
+ # @param y [Numeric] y of vector
+ # @param z [Numeric] z of vector
+ # @param v [Vector] vector object to copy
+ # @param a [Array] array like [x, y, z]
+ #
+ def initialize (x = 0, y = 0, z = 0, context: context)
+ @point = case x
+ when Rays::Point then x.dup
+ when Vector then x.getInternal__.dup
+ when Array then Rays::Point.new x[0] || 0, x[1] || 0, x[2] || 0
+ else Rays::Point.new x || 0, y || 0, z || 0
+ end
+ @context = context
+ end
+
+ # Initializer for dup or clone
+ #
+ def initialize_copy (o)
+ @point = o.getInternal__.dup
+ end
+
+ # Copy vector object
+ #
+ # @return [Vector] duplicated vector object
+ #
+ alias copy dup
+
+ # Sets x, y and z.
+ #
+ # @overload set(x)
+ # @overload set(x, y)
+ # @overload set(x, y, z)
+ # @overload set(v)
+ # @overload set(a)
+ #
+ # @param x [Numeric] x of vector
+ # @param y [Numeric] y of vector
+ # @param z [Numeric] z of vector
+ # @param v [Vector] vector object to copy
+ # @param a [Array] array with x, y, z
+ #
+ # @return [nil] nil
+ #
+ def set (*args)
+ initialize *args
+ self
+ end
+
+ # Gets x value.
+ #
+ # @return [Numeric] x value of vector
+ #
+ def x ()
+ @point.x
+ end
+
+ # Gets y value.
+ #
+ # @return [Numeric] y value of vector
+ #
+ def y ()
+ @point.y
+ end
+
+ # Gets z value.
+ #
+ # @return [Numeric] z value of vector
+ #
+ def z ()
+ @point.z
+ end
+
+ # Sets x value.
+ #
+ # @return [Numeric] x value of vector
+ #
+ def x= (x)
+ @point.x = x
+ end
+
+ # Sets y value.
+ #
+ # @return [Numeric] y value of vector
+ #
+ def y= (y)
+ @point.y = y
+ end
+
+ # Sets z value.
+ #
+ # @return [Numeric] z value of vector
+ #
+ def z= (z)
+ @point.z = z
+ end
+
+ # Returns the interpolated vector between 2 vectors.
+ #
+ # @overload lerp(v, amount)
+ # @overload lerp(x, y, amount)
+ # @overload lerp(x, y, z, amount)
+ #
+ # @param v [Vector] vector to interpolate
+ # @param x [Numeric] x of vector to interpolate
+ # @param y [Numeric] y of vector to interpolate
+ # @param z [Numeric] z of vector to interpolate
+ # @param amount [Numeric] amount to interpolate
+ #
+ # @return [Vector] interporated vector
+ #
+ def lerp (*args, amount)
+ v = toVector__ *args
+ self.x = x + (v.x - x) * amount
+ self.y = y + (v.y - y) * amount
+ self.z = z + (v.z - z) * amount
+ self
+ end
+
+ # Returns the interpolated vector between 2 vectors.
+ #
+ # @param v1 [Vector] vector to interpolate
+ # @param v2 [Vector] vector to interpolate
+ # @param amount [Numeric] amount to interpolate
+ #
+ # @return [Vector] interporated vector
+ #
+ def self.lerp (v1, v2, amount)
+ v1.dup.lerp v2, amount
+ end
+
+ # Returns x, y, z as an array
+ #
+ # @return [Array] array of x, y, z
+ #
+ def array ()
+ @point.to_a 3
+ end
+
+ # Adds a vector.
+ #
+ # @overload add(v)
+ # @overload add(x, y)
+ # @overload add(x, y, z)
+ #
+ # @param v [Vector] vector to add
+ # @param x [Vector] x of vector to add
+ # @param y [Vector] y of vector to add
+ # @param z [Vector] z of vector to add
+ #
+ # @return [Vector] added vector
+ #
+ def add (*args)
+ @point += toVector__(*args).getInternal__
+ self
+ end
+
+ # Subtracts a vector.
+ #
+ # @overload sub(v)
+ # @overload sub(x, y)
+ # @overload sub(x, y, z)
+ #
+ # @param v [Vector] vector to subtract
+ # @param x [Vector] x of vector to subtract
+ # @param y [Vector] y of vector to subtract
+ # @param z [Vector] z of vector to subtract
+ #
+ # @return [Vector] subtracted vector
+ #
+ def sub (*args)
+ @point -= toVector__(*args).getInternal__
+ self
+ end
+
+ # Multiplies a vector by scalar.
+ #
+ # @param num [Numeric] number to multiply the vector
+ #
+ # @return [Vector] multiplied vector
+ #
+ def mult (num)
+ @point *= num
+ self
+ end
+
+ # Divides a vector by scalar.
+ #
+ # @param num [Numeric] number to divide the vector
+ #
+ # @return [Vector] divided vector
+ #
+ def div (num)
+ @point /= num
+ self
+ end
+
+ # Adds a vector.
+ #
+ # @param v [Vector] vector to add
+ #
+ # @return [Vector] added vector
+ #
+ def + (v)
+ dup.add v
+ end
+
+ # Subtracts a vector.
+ #
+ # @param v [Vector] vector to subtract
+ #
+ # @return [Vector] subtracted vector
+ #
+ def - (v)
+ dup.sub v
+ end
+
+ # Multiplies a vector by scalar.
+ #
+ # @param num [Numeric] number to multiply the vector
+ #
+ # @return [Vector] multiplied vector
+ #
+ def * (num)
+ dup.mult num
+ end
+
+ # Divides a vector by scalar.
+ #
+ # @param num [Numeric] number to divide the vector
+ #
+ # @return [Vector] divided vector
+ #
+ def / (num)
+ dup.div num
+ end
+
+ # Adds 2 vectors.
+ #
+ # @overload add(v1, v2)
+ # @overload add(v1, v2, target)
+ #
+ # @param v1 [Vector] a vector
+ # @param v2 [Vector] another vector
+ # @param target [Vector] vector to store added vector
+ #
+ # @return [Vector] added vector
+ #
+ def self.add (v1, v2, target = nil)
+ v = v1 + v2
+ target.set v if self === target
+ v
+ end
+
+ # Subtracts 2 vectors.
+ #
+ # @overload sub(v1, v2)
+ # @overload sub(v1, v2, target)
+ #
+ # @param v1 [Vector] a vector
+ # @param v2 [Vector] another vector
+ # @param target [Vector] vector to store subtracted vector
+ #
+ # @return [Vector] subtracted vector
+ #
+ def self.sub (v1, v2, target = nil)
+ v = v1 - v2
+ target.set v if self === target
+ v
+ end
+
+ # Multiplies a vector by scalar.
+ #
+ # @overload mult(v, num)
+ # @overload mult(v, num, target)
+ #
+ # @param v [Vector] a vector
+ # @param num [Numeric] number to multiply the vector
+ # @param target [Vector] vector to store multiplied vector
+ #
+ # @return [Vector] multiplied vector
+ #
+ def self.mult (v1, num, target = nil)
+ v = v1 * num
+ target.set v if self === target
+ v
+ end
+
+ # Divides a vector by scalar.
+ #
+ # @overload div(v, num)
+ # @overload div(v, num, target)
+ #
+ # @param v [Vector] a vector
+ # @param num [Numeric] number to divide the vector
+ # @param target [Vector] vector to store divided vector
+ #
+ # @return [Vector] divided vector
+ #
+ def self.div (v1, num, target = nil)
+ v = v1 / num
+ target.set v if self === target
+ v
+ end
+
+ # Returns the length of the vector.
+ #
+ # @return [Numeric] length
+ #
+ def mag ()
+ @point.length
+ end
+
+ # Returns squared length of the vector.
+ #
+ # @return [Numeric] squared length
+ #
+ def magSq ()
+ Rays::Point::dot(@point, @point)
+ end
+
+ # Changes the length of the vector.
+ #
+ # @overload setMag(len)
+ # @overload setMag(target, len)
+ #
+ # @param len [Numeric] length of new vector
+ # @param target [Vector] vector to store new vector
+ #
+ # @return [Vector] vector with new length
+ #
+ def setMag (target = nil, len)
+ (target || self).set @point.normal * len
+ end
+
+ # Changes the length of the vector to 1.0.
+ #
+ # @param target [Vector] vector to store the normalized vector
+ #
+ # @return [Vector] normalized vector
+ #
+ def normalize (target = nil)
+ (target || self).set @point.normal
+ end
+
+ # Changes the length of the vector if it's length is greater than the max value.
+ #
+ # @param max [Numeric] max length
+ #
+ # @return [Vector] new vector
+ #
+ def limit (max)
+ setMag max if magSq > max ** 2
+ self
+ end
+
+ # Returns the distance of 2 vectors.
+ #
+ # @param v [Vector] a vector
+ #
+ # @return [Numeric] the distance
+ #
+ def dist (v)
+ (self - v).mag
+ end
+
+ # Returns the distance of 2 vectors.
+ #
+ # @param v1 [Vector] a vector
+ # @param v2 [Vector] another vector
+ #
+ # @return [Numeric] the distance
+ #
+ def self.dist (v1, v2)
+ v1.dist v2
+ end
+
+ # Calculates the dot product of 2 vectors.
+ #
+ # @overload dot(v)
+ # @overload dot(x, y)
+ # @overload dot(x, y, z)
+ #
+ # @param v [Vector] a vector
+ # @param x [Numeric] x of vector
+ # @param y [Numeric] y of vector
+ # @param z [Numeric] z of vector
+ #
+ # @return [Numeric] result of dot product
+ #
+ def dot (*args)
+ Rays::Point::dot getInternal__, toVector__(*args).getInternal__
+ end
+
+ # Calculates the dot product of 2 vectors.
+ #
+ # @param v1 [Vector] a vector
+ # @param v2 [Vector] another vector
+ #
+ # @return [Numeric] result of dot product
+ #
+ def self.dot (v1, v2)
+ v1.dot v2
+ end
+
+ # Calculates the cross product of 2 vectors.
+ #
+ # @overload cross(v)
+ # @overload cross(x, y)
+ # @overload cross(x, y, z)
+ #
+ # @param v [Vector] a vector
+ # @param x [Numeric] x of vector
+ # @param y [Numeric] y of vector
+ # @param z [Numeric] z of vector
+ #
+ # @return [Numeric] result of cross product
+ #
+ def cross (a, *rest)
+ target = self.class === rest.last ? rest.pop : nil
+ v = self.class.new Rays::Point::cross getInternal__, toVector__(a, *rest).getInternal__
+ target.set v if self.class === target
+ v
+ end
+
+ # Calculates the cross product of 2 vectors.
+ #
+ # @param v1 [Vector] a vector
+ # @param v2 [Vector] another vector
+ #
+ # @return [Numeric] result of cross product
+ #
+ def self.cross (v1, v2, target = nil)
+ v1.cross v2, target
+ end
+
+ # Rotate the vector.
+ #
+ # @param angle [Numeric] the angle of rotation
+ #
+ # @return [Vector] rotated this object
+ #
+ def rotate (angle)
+ angle = @context ? @context.toAngle__(angle) : angle * Utility::RAD2DEG__
+ @point.rotate! angle
+ self
+ end
+
+ # Returns the angle of rotation for this vector.
+ #
+ # @return [Numeric] the angle in radians
+ #
+ def heading ()
+ Math.atan2 y, x
+ end
+
+ # Returns rotated new vector.
+ #
+ # @param angle [Numeric] the angle of rotation
+ # @param target [Vector] vector to store new vector
+ #
+ # @return [Vector] rotated vector
+ #
+ def self.fromAngle (angle, target = nil)
+ v = self.new(1, 0, 0).rotate(angle)
+ target.set v if target
+ v
+ end
+
+ # Returns angle between 2 vectors.
+ #
+ # @param v1 [Vector] a vector
+ # @param v2 [Vector] another vector
+ #
+ # @return [Numeric] angle in radians
+ #
+ def self.angleBetween (v1, v2)
+ x1, y1, z1 = v1.array
+ x2, y2, z2 = v2.array
+ return 0 if (x1 == 0 && y1 == 0 && z1 == 0) || (x2 == 0 && y2 == 0 && z2 == 0)
+
+ x = dot(v1, v2) / (v1.mag * v2.mag)
+ return Math::PI if x <= -1
+ return 0 if x >= 1
+ return Math.acos x
+ end
+
+ # Returns a new 2D unit vector with a random direction.
+ #
+ # @param target [Vector] a vector to store the new vector
+ #
+ # @return [Vector] a random vector
+ #
+ def self.random2D (target = nil)
+ v = self.fromAngle rand 0.0...(Math::PI * 2)
+ target.set v if target
+ v
+ end
+
+ # Returns a new 3D unit vector with a random direction.
+ #
+ # @param target [Vector] a vector to store the new vector
+ #
+ # @return [Vector] a random vector
+ #
+ def self.random3D (target = nil)
+ angle = rand 0.0...(Math::PI * 2)
+ z = rand -1.0..1.0
+ z2 = z ** 2
+ x = Math.sqrt(1.0 - z2) * Math.cos(angle)
+ y = Math.sqrt(1.0 - z2) * Math.sin(angle)
+ v = self.new x, y, z
+ target.set v if target
+ v
+ end
+
+ # @private
+ def inspect ()
+ "<##{self.class.name} #{x}, #{y}, #{z}>"
+ end
+
+ # @private
+ def <=> (o)
+ @point <=> o.getInternal__
+ end
+
+ # @private
+ protected def getInternal__ ()
+ @point
+ end
+
+ # @private
+ private def toVector__ (*args)
+ self.class === args.first ? args.first : self.class.new(*args)
+ end
+
+ end# Vector
+
+
# Image object.
#
class Image
# @private
def initialize (image)
- @image__ = image
+ @image = image
end
# Gets width of image.
#
# @return [Numeric] width of image
#
def width ()
- @image__.width
+ @image.width
end
# Gets height of image.
#
# @return [Numeric] height of image
#
def height ()
- @image__.height
+ @image.height
end
# Resizes image.
#
# @param width [Numeric] width for resized image
# @param height [Numeric] height for resized image
#
# @return [nil] nil
#
def resize (width, height)
- @image__ = Rays::Image.new(width, height).paint do |painter|
- painter.image @image__, 0, 0, width, height
+ @image = Rays::Image.new(width, height).paint do |painter|
+ painter.image @image, 0, 0, width, height
end
nil
end
# Copies image.
@@ -62,26 +616,26 @@
#
# @return [nil] nil
#
def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
img ||= self
- @image__.paint do |painter|
+ @image.paint do |painter|
painter.image img.getInternal__, sx, sy, sw, sh, dx, dy, dw, dh
end
end
# Saves image to file.
#
# @param filename [String] file name to save image
#
def save (filename)
- @image__.save filename
+ @image.save filename
end
# @private
def getInternal__ ()
- @image__
+ @image
end
end# Image
@@ -367,11 +921,11 @@
end
nil
end
# @private
- private def toAngle__ (angle)
+ protected def toAngle__ (angle)
angle * @angleScale__
end
# Sets rect mode. Default is CORNER.
#
@@ -1023,15 +1577,15 @@
popMatrix
popStyle
end
# @private
- def getInternal__ ()
+ private def getInternal__ ()
@image__
end
# @private
- def assertDrawing__ ()
+ private def assertDrawing__ ()
raise "call beginDraw() before drawing" unless @drawing
end
end# GraphicsContext