Class | ODE::Quaternion |
In: |
lib/ode/quaternion.rb
(CVS)
|
Parent: | Object |
Version | = | /([\d\.]+)/.match( %q{$Revision: 1.3 $} )[1] | Class constants | |
Rcsid | = | %q$Id: quaternion.rb 91 2005-07-27 23:45:01Z ged $ | ||
X | = | 0; | ||
Y | = | 1; | ||
Z | = | 2; | ||
W | = | 3 |
vv2q | -> | rotation |
elem | [RW] | Internal array of elements |
Return the identity quaternion (multiplicative)
# File lib/ode/quaternion.rb, line 87 def identity new( 0,0,0,1 ) end
Create and return a new ODE:Quaternion object from the arguments given. The arguments can be in the following forms:
angle:: angle = Numeric axis, angle:: axis = 3-element Array/Vector, angle = Numeric two vectors:: 2 Array/Vector objects euler angles:: roll, pitch, and yaw as 3 floating-point numbers axis:: 3-element
# File lib/ode/quaternion.rb, line 137 def initialize( *args ) case args.length when 0 @elem = self.class.identity.elem when 1 @elem = oneArgInit( *args ) when 2 @elem = twoArgInit( *args ) when 3 @elem = threeArgInit( *args ) when 4 @elem = args.collect {|elem| Float(elem)} else raise ArgumentError, "wrong number of arguments (%d for 1, 2, or 4)" % args.length end end
Construct a new Quaternion from the given roll, pitch, and yaw.
# File lib/ode/quaternion.rb, line 122 def rpy2q( roll, pitch, yaw ) new( roll, pitch, yaw ) end
Construct a new Quaternion from a scalar scalar and an ODE::Vector vector.
# File lib/ode/quaternion.rb, line 115 def sv2q( scalar, vector ) new( vector, scalar ) # array-concatenation, not vec addition end
Construct a new Quaternion by rotating ODE::Vector f to ODE::Vector t (up to scale)
# File lib/ode/quaternion.rb, line 94 def vv2q( f, t ) raise TypeError, "no implicit conversion to ODE::Vector for %s" % f.class.name unless f.is_a?( ODE::Vector ) raise IndexError, "Vector must be a 3rd-order vector" unless f.size == 3 raise TypeError, "no implicit conversion to ODE::Vector for %s" % t.class.name unless t.is_a?( ODE::Vector ) raise IndexError, "Vector must be a 3rd-order vector" unless t.size == 3 f.normalize! t.normalize! ft = f.gp( t ) sv2q( 1.0 + ft[3], ft[0..2] ) / (f + t).mag end
Multiplication operator — return the receiving quaternion multiplied by the other object, which can be a Numeric or another ODE::Quaternion.
# File lib/ode/quaternion.rb, line 497 def *( other ) case other when Float, Fixnum other = other.to_f return self.class.new( @elem[0] * other, @elem[1] * other, @elem[2] * other, @elem[3] * other ) when ODE::Quaternion s = self.scalar * other.scalar - self.vec.dot( other.vec ) v = self.scalar * other.vec - self.vec.cross( other.vec ) + self.vec * other.scalar return self.class.new( v, s ) else raise TypeError, "no implicit conversion of %s to %s" % [ other.class.name, 'Float, Fixnum, or ODE::Quaternion' ] end end
Addition operator — add the specified otherQuat (ODE::Quaternion object) to the receiver and return the results as a new instance of the receiver.
# File lib/ode/quaternion.rb, line 540 def +( otherQuat ) self.class.new( @elem[0] + otherQuat[0], @elem[1] + otherQuat[1], @elem[2] + otherQuat[2], @elem[3] + otherQuat[3] ) end
Subtraction operator — subtract the specified otherQuat (ODE::Quaternion object) from the receiver and return the results as a new instance of the receiver.
# File lib/ode/quaternion.rb, line 551 def -( otherQuat ) self.class.new( @elem[0] - otherQuat[0], @elem[1] - otherQuat[1], @elem[2] - otherQuat[2], @elem[3] - otherQuat[3] ) end
Division operator — return the receiving quaternion divided by the given value (a Float or a Fixnum).
# File lib/ode/quaternion.rb, line 522 def /( value ) case value when Float, Fixnum value = value.to_f return self.class.new( @elem[0] / value, @elem[1] / value, @elem[2] / value, @elem[3] / value ) else raise TypeError, "No implicit conversion from %s to %s" % [ value.class.name, "Float or Fixnum" ] end end
Element reference operator — returns the ith element of the quaternion.
# File lib/ode/quaternion.rb, line 251 def [](i) @elem[i] end
Element assignment operator — assigns the value x to the ith element of the vector.
# File lib/ode/quaternion.rb, line 258 def []=(i, x) @elem[i] = Float(x) end
Return the angle of the quaternion in Radians as a Float.
# File lib/ode/quaternion.rb, line 473 def angle_rads 2.0 * Math.atan2( self.vec.mag, self.scalar ) end
Return the axis of the quaternion as an ODE::Vector.
# File lib/ode/quaternion.rb, line 462 def axis vlen = self.vec.mag if vlen > 0.0 return self.vec/vlen else return ODE::Vector::new( 0.0, 0.0, 0.0 ) end end
Transform the quaternion by rotating it about the given axis by angle radians.
# File lib/ode/quaternion.rb, line 480 def axis_rotation( axis, angle ) raise TypeError, "no implicit conversion of %s to ODE::Vector" unless axis.is_a?( ODE::Vector ) angle = Float(angle) if len = axis.abs a = axis/len * sin( angle / 2.0 ); self.class.new( a, cos(angle/2.0) ) else self.class.identity end end
Returns the conjugate of the quaternion as a new instance of the receiver.
# File lib/ode/quaternion.rb, line 422 def conjugate self.class.new( -@elem[0], -@elem[1], -@elem[2], @elem[3] ) end
Return a distinct copy of the receiver (as opposed to dup, which only returns a shallow copy).
# File lib/ode/quaternion.rb, line 384 def copy return self.dup.copy_object( self ) end
Returns the natural exponent of the vector. The result will be a unit quaternion.
# File lib/ode/quaternion.rb, line 391 def exp mag = self.vec.mag Math::exp( self.scalar ) * Quaternion::sv2q( cos(mag), sin(mag) * self.vec/mag ) end
Return the inverse of the quaternion as new instance of the receiver.
# File lib/ode/quaternion.rb, line 444 def inverse return self.copy.inverse! end
Transform the receiving quaternion into its inverse.
# File lib/ode/quaternion.rb, line 450 def inverse! smag = self.sqr @elem = [ -@elem[0] / smag, -@elem[1] / smag, -@elem[2] / smag, @elem[3] / smag ] end
Return the magnitude of the quaternion
# File lib/ode/quaternion.rb, line 407 def mag Math::sqrt(self.sqr) end
Return a normalized copy of the receiver.
# File lib/ode/quaternion.rb, line 437 def normalize return self.copy.normalize! end
Normalize the quaternion in place.
# File lib/ode/quaternion.rb, line 429 def normalize! magnitude = self.mag @elem.collect! {|elem| elem / magnitude} return self end
Return the quaternion’s value as the "pitch" euler angle (in radians).
# File lib/ode/quaternion.rb, line 298 def pitch # sin(pitch) = -2(xz - wy) x = @elem[X]; y = @elem[Y]; z = @elem[Z]; w = @elem[W] return Math::asin( -2 * (x*z - w*y) ) end
Return the quaternion’s value as the "roll" euler angle (in radians).
# File lib/ode/quaternion.rb, line 290 def roll # tan(roll) = 2(wx + yz) / (w^2 - x^2 - y^2 + z^2) x = @elem[X]; y = @elem[Y]; z = @elem[Z]; w = @elem[W] return Math::atan( (2 * (w * x + y * z)) / (w**2 - x**2 - y**2 + z**2) ) end
Returns a new ODE::Vector created by transforming the given vector by the rotation represented by the unit quaternion. Results are undefined if the quaternion is not a unit quaternion.
# File lib/ode/quaternion.rb, line 401 def rotate( vector ) (self.inverse * self.class.new(vector) * self ).vec end
Return the scalar part of the quaternion as a Float.
# File lib/ode/quaternion.rb, line 313 def scalar @elem[3] end
Return the squared magnitude of the quaternion.
# File lib/ode/quaternion.rb, line 414 def sqr @elem[0] ** 2 + @elem[1] ** 2 + @elem[2] ** 2 + @elem[3] ** 2 end
Return the elements of the quaternion as an Array.
# File lib/ode/quaternion.rb, line 377 def to_ary return @elem.to_ary end
Return the quaternion as a 3x3 ODE::Matrix.
# File lib/ode/quaternion.rb, line 339 def to_matrix unitq = self.unit # For the unit quaternion: # Matrix = [ 1 - 2y^2 - 2z^2 2xy - 2wz 2xz + 2wy # 2xy + 2wz 1 - 2x^2 - 2z^2 2yz - 2wx # 2xz - 2wy 2yz + 2wx 1 - 2x^2 - 2y^2 ] return Matrix[ [ 1 - 2 * (unitq.y ** 2 - unitq.z ** 2), 2 * (unitq.x * unitq.y + unitq.z * unitq.w), 2 * (unitq.x * unitq.z - unitq.y * unitq.w), 0 ], [ 2 * (unitq.x * unitq.y - unitq.z * unitq.w), 1 - 2 * (unitq.x ** 2 - unitq.z ** 2), 2 * (unitq.y * unitq.z + unitq.x * unitq.w), 0 ], [ 2 * (unitq.x * unitq.z + unitq.y * unitq.w), 2 * (unitq.y * unitq.z - unitq.x * unitq.w), 1 - 2 * (unitq.x ** 2 - unitq.y ** 2), 0 ], [ 0.0, 0.0, 0.0, 1.0 ], ] end
Return the receiver as a 4th-order ODE::Vector.
# File lib/ode/quaternion.rb, line 371 def to_vector return ODE::Vector::new( *@elem ) end
Return a new quaternion normalized to unit length
# File lib/ode/quaternion.rb, line 327 def unit unitq = self.copy magnitude = self.abs unitq[0] /= magnitude unitq[1] /= magnitude unitq[2] /= magnitude unitq[3] /= magnitude return unitq end
Return the dual of the bivector part
# File lib/ode/quaternion.rb, line 320 def vec ODE::Vector::new( @elem[0..2] ) end
Return the ‘w’ (4th) element of the quaternion.
# File lib/ode/quaternion.rb, line 282 def w; self[W]; end
Set the ‘w’ (4th) element of the quaternion to value.
# File lib/ode/quaternion.rb, line 285 def w=(value); self[W] = Float(value); end
Return the ‘x’ (1st) element of the quaternion.
# File lib/ode/quaternion.rb, line 264 def x; self[X]; end
Set the ‘x’ (1st) element of the quaternion to value.
# File lib/ode/quaternion.rb, line 267 def x=(value); self[X] = Float(value); end
Return the ‘y’ (2nd) element of the quaternion.
# File lib/ode/quaternion.rb, line 270 def y; self[Y]; end
Set the ‘y’ (2nd) element of the quaternion to value.
# File lib/ode/quaternion.rb, line 273 def y=(value); self[Y] = Float(value); end
Return the quaternion’s value as the "yaw" euler angle (in radians).
# File lib/ode/quaternion.rb, line 305 def yaw # tan(yaw) = 2(xy+wz) / (w^2 + x^2 - y^2 - z^2) x = @elem[X]; y = @elem[Y]; z = @elem[Z]; w = @elem[W] return Math::atan( (2 * (x*y + w*z)) / (w**2 + x**2 - y**2 - z**2) ) end
Return the ‘z’ (3rd) element of the quaternion.
# File lib/ode/quaternion.rb, line 276 def z; self[Z]; end
Set the ‘z’ (3rd) element of the quaternion to value.
# File lib/ode/quaternion.rb, line 279 def z=(value); self[Z] = Float(value); end
Initialize the quaternion from one argument (angle or vector)
# File lib/ode/quaternion.rb, line 166 def oneArgInit( arg ) case arg # Angle when Numeric @elem = [0.0, 0.0, 0.0, Float(arg)] # 3rd- or 4th-order vector when ODE::Vector case arg.size when 3 @elem = [ arg.elements.collect {|i| Float(i)}, 0.0 ].flatten when 4 @elem = arg.elements.collect {|i| Float(i)} else raise ArgumentError, "Cannot create a %s from a %d-dimensional %s" % [ self.class.name, arg.size, arg.class.name ] end else raise TypeError, "wrong type of argument '%s': Expected a %s" % [ arg.class.name, "Numeric or ODE::Vector" ] end end
Initialize the quaternion from the given roll, pitch, and yaw.
# File lib/ode/quaternion.rb, line 221 def threeArgInit( roll, pitch, yaw ) roll = Float(roll) / 2 pitch = Float(pitch) / 2 yaw = Float(yaw) / 2 sr = sin( roll ); cr = cos( roll ); sp = sin( pitch ); cp = cos( pitch ); sy = sin( yaw ); cy = cos( yaw ); return [ sr * cp * cy - cr * sp * sy, cr * sp * cy + sr * cp * sy, cr * cp * sy - sr * sp * cy, cr * cp * cy + sr * sp * sy ] end
Initialize the quaternion from two arguments (axis + angle or two vectors).
# File lib/ode/quaternion.rb, line 197 def twoArgInit( arg1, arg2 ) # Axis + angle if arg2.kind_of?( Numeric ) && arg1.respond_to?( :to_ary ) args = [ arg1.to_ary, arg2 ].flatten # Two vectors else args.each {|v| raise "No implicit conversion to ODE::Vector for #{v.class.name}" unless v.respond_to?( :to_ary ) } v1 = ODE::Vector::new( arg1 ).normalize v2 = ODE::Vector::new( arg2 ).normalize args = [ v1.cross(v2).to_ary, v1.dot(v2) ].flatten end end