# # File:: vector.rb # Description:: Vector classes (2, 3 and 4 component). # # Author:: David Muir # Date:: 28 February 2008 # #---------------------------------------------------------------------------- # Uses #---------------------------------------------------------------------------- require 'pipeline/math/angles' require 'pipeline/util/float' require 'mathn' #---------------------------------------------------------------------------- # Implementation #---------------------------------------------------------------------------- module Pipeline module Math # # == Description # 2D vector class. # class Vector2 attr_accessor :x attr_accessor :y # # == Description # Vector class constructor, taking two optional arguments. All # vector components must be of the same class otherwise an # ArgumentError exception is raised. # def initialize( x = 0.0, y = 0.0 ) throw ArgumentError.new( 'Not all vector components are same type' ) \ unless ( x.class == y.class ) @x = x @y = y end # # Addition with another vector object or scalar. # def +( v ) if ( v.is_a?( Vector ) ) Vector.new( @x + v.x, @y + v.y ) elsif ( v.is_a?( Numeric ) ) Vector.new( @x + v, @y + v ) else throw ArgumentError.new( "Addition of Vector2 and #{v.class} not supported." ) end end # # Subtraction of another vector object or scalar. # def -( v ) if ( v.is_a?( Vector ) ) Vector.new( @x - v.x, @y - v.y ) elsif ( v.is_a?( Numeric ) ) Vector.new( @x - v, @y - v ) else throw ArgumentError.new( "Subtraction of #{v.class} from Vector2 not supported." ) end end # # Multiplication by a scalar. # def *( s ) if ( v.is_a?( Numeric ) ) Vector.new( @x * s, @y * s ) else throw ArgumentError.new( "Multiplication by #{v.class} is not supported." ) end end # # == Description # Return magnitude of vector. # def magnitude ::Math::sqrt( @x*@x + @y*@y ) end # # == Description # Alias for vector magnitude. # alias length magnitude # # == Description # Return the inverse magnitude of this vector. # def inverse_magnitude ::Math::rsqrt( dot( self ) ) end # # == Description # Normalise this vector. # def normalise! scale!( inverse_magnitude ) end # # == Description # Return this vector normalised # def normalise scale( inverse_magnitude ) end alias normalize! normalise! alias normalize normalise # # == Description # Scale this vector. # def scale!( f ) @x *= f @y *= f end # # == Description # Return this vector scaled by multiplier f. # def scale( f ) Vector.new( @x * f, @y * f ) end # # == Description # Return this vector scaled by inverse of f. # def inverse_scale( f ) inv_f = 1.0 / f scale( inf_f ) end # # == Description # Scale this vector by the inverse of a value. def inverse_scale!( f ) inv_f = 1.0 / f scale!( inv_f ) end # # == Description # Find and return dot product of this vector and v2. # def dot( v2 ) ( (@x * v2.x) + (@y * v2.y) ) end #--------------------------------------------------------------------- # Operators #--------------------------------------------------------------------- # # == Description # [] operator for readonly access to components # def [](index) case index when 0 return @x when 1 return @y else raise ArgumentError.new( "0 <= index <= 1 for xy vector" ) end end #--------------------------------------------------------------------- # Overloaded Methods #--------------------------------------------------------------------- # # Return Vector2 as an Array object. # def to_a( ) [ @x, @y ] end # # == Description # String conversion function for vectors. Optional precision flag # can be used if x, y and z components are all Float. # def to_s( prec = nil ) all_float = ( Float == @x.class and Float == @y.class ) if ( all_float and !prec.nil? ) return "[ #{@x.to_s(prec)}, #{@y.to_s(prec)} ]" else return "[ #{@x}, #{@y} ]" end end end end # Math module end # Pipeline module # End of vector.rb