Files
2025-09-29 00:52:08 +02:00

213 lines
4.4 KiB
Ruby
Executable File

#
# File:: vector.rb
# Description:: Vector classes (2, 3 and 4 component).
#
# Author:: David Muir <david.muir@rockstarnorth.com>
# 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