class Object
# This is a shorthand to define vector object coordinates.
#
# Creates a vector object at coordinates x,y,z
def v(x, y, z)
Ogre::Vector3.new(x, y, z)
end
end
class SymbolToVectorError < StandardError #:nodoc:
end
class Symbol #:nodoc:
# Vectors in symbol form can be any of the following:
# :x => v(1,0,0)
# :y => v(0,1,0)
# :z => v(0,0,1),
# :up => v(0,1,0)
# :down => v(0,-1,0)
# :left => v(-1,0,0)
# :right => v(1,0,0)
# :forward => v(0,0,1)
# :backward => v(0,0,-1)
# :zero => v(0,0,0)
def to_v
@definitions ||= {:x => v(1,0,0),:y => v(0,1,0),:z => v(0,0,1),
:up => v(0,1,0),:down => v(0,-1,0),
:left => v(-1,0,0),:right => v(1,0,0),
:forward => v(0,0,1),:backward => v(0,0,-1),
:zero => v(0,0,0)}
return @definitions[self] unless @definitions[self].nil?
raise SymbolToVectorError, "Undefined vector for symbol #{self}"
end
# Multiplication defined for vectors carries over to their symbolic equivalence.
def *(number)
return to_v * number
end
# Addition for vectors
def +(number)
return to_v + number
end
# Subtraction for numbers
def -(number)
return to_v - number
end
end
class Array #:nodoc:
# Vector extensions for array. Allows for coersion of a 3 element Array into a vector.
# Randomize the order of an array
#
# [1, 2, 3].shuffle #=> [2, 3, 1]
#
def shuffle
sort_by {rand}
end
# Create a vector from an array.
#
# [1, 2, 3].to_v #=> same as Vector.new(1, 2, 3)
#
def to_v
raise StandardError, "vector #{self.inspect} does not have 3 elements" if self.length < 3
Ogre::Vector3.new self[0], self[1] ,self[2]
end
end
module Ogre
# Vector is a three dimensional array, that allows for various operations on itself.
# To create a vector, use the shorthand:
# v(0,0,0) # Creates a zero vector
#
#
# *NOTE:* The recomended way to create Vector objects is to use the v(1,2,3) shorthand.
class Vector3
# Iterate through x, y and z with a block. The passed value is the value of each component of
# the vector.
def each(&block)
self.to_a.each do |component|
yield component
end
end
# Returns self
def to_v
self
end
# Returns an array with x, y and z dumped into its elements.
# v(1, 2, 3).to_a #=> [1.0, 2.0, 3.0]
def to_a
[x, y, z]
end
# Add 2 Vectors together.
# v(1,1,1) + v(1,2,3) #=> v(2,3,4)
alias_method :ogre_plus, :+
def +(*args)
v = convert_args_to_vector args
ogre_plus v
end
# Subtract one Vector from another.
# v(1,2,3) - v(1,1,1) #=> v(0,1,2)
alias_method :ogre_minus, :-
def -(*args)
v = convert_args_to_vector args
ogre_minus v
end
# Multiply all components of a vector by a scalar amount.
# v(1,2,3) * 3 #=> v(3,6,9)
alias_method :ogre_multiply, :*
def *(*args)
#Handle numbers and vectors
unless args[0].is_a? Symbol
return ogre_multiply(args[0])
end
#Symbol to vector conversion
v = convert_args_to_vector args
ogre_multiply v
end
# Returns this Vector but normalized to a length of 1.
# v(9, 0, 0).normalize #=> v(1,0,0)
alias_method :normalize, :normalised_copy
alias_method :normalise, :normalised_copy
# Same as #normalize but modifies the receiver in place.
alias_method :normalize!, :normalise!
# Return the value specified by bracket notation. Integers, Symbols or Strings
# are accepted as keys.
#
# vector = v(1,2,3)
# vector[:x] #=> 1
# vector['y'] #=> 2
# vector[2] #=> 3
def [](index)
case
when index == 0 || index == :x || index == 'x'
x
when index == 1 || index == :y || index == 'y'
y
when index == 2 || index == :z || index == 'z'
z
end
end
# Set the value specified by bracket notation. Accepts the same keys as the #[]
# method.
def []=(index, value)
case
when index == 0 || index == :x || index == 'x'
self.x = value.to_f
when index == 1 || index == :y || index == 'y'
self.y = value.to_f
when index == 2 || index == :z || index == 'z'
self.z = value.to_f
end
end
# Converts the vector into an easily identifiable form. Mostly used for debugging
# and console output.
# v(1,2,3).to_s #=> "#"
def to_s
"#"
end
# Equality test. This method will return true if all components of both vectors are
# indentical.
def ==(vector)
vector = vector.to_v if vector.is_a?(Symbol)
vector.kind_of?(Ogre::Vector3) &&
x == vector.x &&
y == vector.y &&
z == vector.z
end
# Create a unique identifier based on x, y and z.
def hash
return self.to_a.hash
end
# Equality test for hash indexes.
def eql?(other)
return self.to_a.eql?(other.to_a)
end
private
# Convert passed in arguments to vector form.
# Supports Symbol, Array, and vectors
def convert_args_to_vector(*args)
args.flatten!
if(args.first.is_a?(Ogre::Vector3) || args.first.is_a?(Symbol))
args.first.to_v
else
args.to_v
end
end
end
end