Class: RMath3D::RQuat

Inherits:
Object
  • Object
show all
Defined in:
lib/rmath3d/rmath3d_plain.rb

Overview

Document-class: RMath3D::RQuat provies quaternion arithmetic.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*a) ⇒ RQuat

call-seq:

RQuat.new -> (0,0,0,0)
RQuat.new(e) -> (e,e,e,e)
RQuat.new( other ) : Copy Constructor
RQuat.new( e0, e1, e2, e3 ) -> (e0,e1,e2,e3)

Creates a new quaternion.



2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
# File 'lib/rmath3d/rmath3d_plain.rb', line 2223

def initialize( *a )
  @e = []
  case a.length
  when 0
    @e = [0.0, 0.0, 0.0, 0.0]
  when 1
    case a[0]
    when Fixnum, Float
      @e = [ a[0], a[0], a[0], a[0] ]
    when RQuat
      @e = [ a[0].x, a[0].y, a[0].z, a[0].w ]
    else
      raise TypeError, "RQuat#initialize : Unknown type #{a[0].class}."
      return nil
    end
  when 4
    a.each_with_index do |elem, index|
      case elem
      when Fixnum, Float
        @e[index] = elem
      else
        raise TypeError, "RQuat#initialize : Unknown type #{elem.class}."
        return nil
      end
    end
  else
    raise RuntimeError, "RQuat#initialize : wrong # of arguments (#{a.length})"
    return nil
  end
  return self
end

Class Method Details

.dot(q1, q2) ⇒ Object

call-seq: RQuat.dot(q_a,q_b) -> value

Calculates the dot product of q_a and q_b.



2422
2423
2424
2425
2426
2427
2428
# File 'lib/rmath3d/rmath3d_plain.rb', line 2422

def RQuat.dot( q1, q2 )
  if q1.class != RQuat || q2.class != RQuat
    raise TypeError, "RQuat#dot : Unknown type q1:#{q2.class}, q2:#{q2.class}."
    return nil
  end
  return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w
end

.slerp(q1, q2, t) ⇒ Object

call-seq: RQuat.slerp( q_a, q_b, t ) -> interpolated quaternion

Calculates the spherical linear interpolation between q_a and q_b at time t (0.0~1.0).



2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
# File 'lib/rmath3d/rmath3d_plain.rb', line 2436

def RQuat.slerp( q1, q2, t )
  if q1.class != RQuat || q2.class != RQuat
    raise TypeError, "RQuat#slerp : Unknown type q1:#{q2.class}, q2:#{q2.class}."
    return nil
  end
  s1 = 0.0
  s2 = 0.0
  it = 1.0 - t
  cosine = RQuat.dot( q1, q2 )

  qn1 = q1
  qn2 = q2

  if ( cosine < 0.0 )
    cosine *= -1.0
    qn1 *= -1.0
  end

  if ( (1.0 - cosine) > TOLERANCE )
    theta = Math.acos( cosine )
    sin_theta = Math.sin( theta )

    s1 = Math.sin( it * theta ) / sin_theta
    s2 = Math.sin(  t * theta ) / sin_theta
  else
    s1 = it
    s2 = t
  end

  qn1 *= s1
  qn2 *= s2
  qResult = qn1 + qn2

  return qResult
end

Instance Method Details

#*(arg) ⇒ Object

call-seq: *

quat1 * quat2 : Binary multiply operator.



2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
# File 'lib/rmath3d/rmath3d_plain.rb', line 2603

def *( arg )
  case arg
  when RQuat
    q1x = self.x
    q1y = self.y
    q1z = self.z
    q1w = self.w
    q2x = arg.x
    q2y = arg.y
    q2z = arg.z
    q2w = arg.w
    x = q1w*q2x + q1x*q2w + q1y*q2z - q1z*q2y
    y = q1w*q2y - q1x*q2z + q1y*q2w + q1z*q2x
    z = q1w*q2z + q1x*q2y - q1y*q2x + q1z*q2w
    w = q1w*q2w - q1x*q2x - q1y*q2y - q1z*q2z
    return RQuat.new( x, y, z, w )
  when Fixnum, Float
    return RQuat.new( @e[0]*arg, @e[1]*arg, @e[2]*arg, @e[3]*arg )
  else
    raise TypeError, "RQuat#* : Unknown type #{arg}."
    return nil
  end
end

#+(arg) ⇒ Object

call-seq: +

quat1 + quat2 : Binary plus operator.



2577
2578
2579
2580
2581
2582
2583
# File 'lib/rmath3d/rmath3d_plain.rb', line 2577

def +( arg )
  if arg.class != RQuat
    raise TypeError, "RQuat#+ : Unknown type #{arg.class}."
    return nil
  end
  RQuat.new( x+arg.x, y+arg.y, z+arg.z, w+arg.w )
end

#+@Object

call-seq: +

+quat : Unary plus operator.



2559
2560
2561
# File 'lib/rmath3d/rmath3d_plain.rb', line 2559

def +@
  return self
end

#-(arg) ⇒ Object

call-seq: -

quat1 - quat2 : Binary minus operator.



2590
2591
2592
2593
2594
2595
2596
# File 'lib/rmath3d/rmath3d_plain.rb', line 2590

def -( arg )
  if arg.class != RQuat
    raise TypeError, "RQuat#- : Unknown type #{arg.class}."
    return nil
  end
  RQuat.new( x-arg.x, y-arg.y, z-arg.z, w-arg.w )
end

#-@Object

call-seq: -

-quat : Unary minus operator.



2568
2569
2570
# File 'lib/rmath3d/rmath3d_plain.rb', line 2568

def -@
  return RQuat.new( -@e[0], -@e[1], -@e[2], -@e[3] )
end

#==(other) ⇒ Object

call-seq: ==

quat1 == quat2 : evaluates equality.



2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
# File 'lib/rmath3d/rmath3d_plain.rb', line 2632

def ==( other )
  if other.class != RQuat
    raise TypeError, "RQuat#== : Unknown type #{other.class}."
    return nil
  end

  if  (x-other.x).abs<=Float::EPSILON &&
      (y-other.y).abs<=Float::EPSILON &&
      (z-other.z).abs<=Float::EPSILON &&
      (w-other.w).abs<=Float::EPSILON
    return true
  else
    return false
  end
end

#[](i) ⇒ Object

call-seq: quat -> value

Returns the element at i.



2357
2358
2359
# File 'lib/rmath3d/rmath3d_plain.rb', line 2357

def [](i)
  @e[i]
end

#[]=(i, value) ⇒ Object

call-seq: quat= value

Stores value at i.



2305
2306
2307
# File 'lib/rmath3d/rmath3d_plain.rb', line 2305

def []=(i,value)
  @e[i] = value
end

#add!(other) ⇒ Object

call-seq: quat1.add!( quat2 )

quat1 += quat2 : appends the elements of quat2 into corresponding quat1 elements.



2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
# File 'lib/rmath3d/rmath3d_plain.rb', line 2653

def add!( other )
  if other.class != RQuat
    raise TypeError, "RQ#add! : Unknown type #{other.class}."
    return nil
  end

  self.x += other.x
  self.y += other.y
  self.z += other.z
  self.w += other.w

  return self
end

#coerce(arg) ⇒ Object

call-seq: coerse(other)

Resolves type mismatch.



2278
2279
2280
2281
2282
2283
2284
2285
2286
# File 'lib/rmath3d/rmath3d_plain.rb', line 2278

def coerce( arg )
  case arg
  when Fixnum, Float, Bignum
    return [ self, arg ]
  else
    raise TypeError, "RQuat#coerce : #{arg.self} can't be coerced into  #{self.class}."
    return nil
  end
end

#conjugate!Object

call-seq: conjugate!

Conjugates itself.



2499
2500
2501
2502
2503
2504
# File 'lib/rmath3d/rmath3d_plain.rb', line 2499

def conjugate!
  @e[0] *= -1.0
  @e[1] *= -1.0
  @e[2] *= -1.0
  return self
end

#getConjugatedObject

call-seq: getConjugated

Returns its conjugate quaternion.



2490
2491
2492
# File 'lib/rmath3d/rmath3d_plain.rb', line 2490

def getConjugated
  return RQuat.new( -@e[0], -@e[1], -@e[2], @e[3] )
end

#getInverseObject

call-seq: getInverse -> inverse quaternion

Returns the inverse.



2511
2512
2513
2514
# File 'lib/rmath3d/rmath3d_plain.rb', line 2511

def getInverse
  length_sq = getLengthSq()
  return RQuat.new( -@e[0]/length_sq, -@e[1]/length_sq, -@e[2]/length_sq, @e[3]/length_sq )
end

#getLengthObject

call-seq: getLength

Returns the Euclidean length.



2404
2405
2406
# File 'lib/rmath3d/rmath3d_plain.rb', line 2404

def getLength
  return Math.sqrt( @e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2] + @e[3]*@e[3] )
end

#getLengthSqObject

call-seq: getLengthSq

Returns the squared Euclidean length.



2413
2414
2415
# File 'lib/rmath3d/rmath3d_plain.rb', line 2413

def getLengthSq
  return (@e[0]*@e[0] + @e[1]*@e[1] + @e[2]*@e[2] + @e[3]*@e[3]).to_f
end

#getNormalizedObject

call-seq: getNormalized -> RQuat

Returns normalized quaternion.



2535
2536
2537
2538
# File 'lib/rmath3d/rmath3d_plain.rb', line 2535

def getNormalized
  length = getLength()
  return RQuat.new( @e[0]/length, @e[1]/length, @e[2]/length, @e[3]/length )
end

#invert!Object

call-seq: invert! -> self

Inverts itself.



2521
2522
2523
2524
2525
2526
2527
2528
# File 'lib/rmath3d/rmath3d_plain.rb', line 2521

def invert!
  length_sq = getLengthSq()
  @e[0] /= -length_sq
  @e[1] /= -length_sq
  @e[2] /= -length_sq
  @e[3] /= length_sq
  return self
end

#mul!(other) ⇒ Object

call-seq: quat1.mul!( quat2 )

quat1 *= quat2



2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
# File 'lib/rmath3d/rmath3d_plain.rb', line 2691

def mul!( other )
  case other
  when RQuat
    q1x = self.x
    q1y = self.y
    q1z = self.z
    q1w = self.w
    q2x = other.x
    q2y = other.y
    q2z = other.z
    q2w = other.w

    x = q1w*q2x + q1x*q2w + q1y*q2z - q1z*q2y
    y = q1w*q2y - q1x*q2z + q1y*q2w + q1z*q2x
    z = q1w*q2z + q1x*q2y - q1y*q2x + q1z*q2w
    w = q1w*q2w - q1x*q2x - q1y*q2y - q1z*q2z

    self.x = x
    self.y = y
    self.z = z
    self.w = w

    return self

  when Fixnum, Float
    self.x *= other
    self.y *= other
    self.z *= other
    self.w *= other
    return self

  else
    raise TypeError, "RQuat#mul! : Unknown type #{other.class}."
    return nil
  end
end

#normalize!Object

call-seq: normalize! -> self

Normalizes itself.



2545
2546
2547
2548
2549
2550
2551
2552
# File 'lib/rmath3d/rmath3d_plain.rb', line 2545

def normalize!
  length = getLength()
  @e[0] /= length
  @e[1] /= length
  @e[2] /= length
  @e[3] /= length
  return self
end

#rotationAxis(axis, radian) ⇒ Object

call-seq: rotationAxis(axis,radian) -> self

Makes a quaternion that rotates around the axis.



2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
# File 'lib/rmath3d/rmath3d_plain.rb', line 2781

def rotationAxis( axis, radian )
  if axis.class != RVec3
    raise TypeError, "RQuat#rotationAxis : Unknown type #{axis.class}."
    return nil
  end

  s = Math.sin( radian / 2.0 )
  self.x = s * axis.x
  self.y = s * axis.y
  self.z = s * axis.z
  self.w = Math.cos( radian / 2.0 )

  return self
end

#rotationMatrix(mtx) ⇒ Object

call-seq: rotationMarix(mtx4) -> self

Makes a rotation quaternion from a rotation matrix mtx4 (RMtx4).



2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
# File 'lib/rmath3d/rmath3d_plain.rb', line 2733

def rotationMatrix( mtx )
  if mtx.class != RMtx3 && mtx.class != RMtx4
    raise TypeError, "RQuat#rotationMatrix : Unknown type #{mtx.class}."
    return nil
  end

  diag00 = mtx.getElement(0,0)
  diag11 = mtx.getElement(1,1)
  diag22 = mtx.getElement(2,2)

  if ( diag00 + diag11 + diag22 > 0.0 )
    t = diag00 + diag11 + diag22 + 1.0
    s = 1.0 / ( Math.sqrt( t ) * 2.0 )
    self.w = s * t
    self.z = (mtx.getElement(1,0) - mtx.getElement(0,1)) * s
    self.y = (mtx.getElement(0,2) - mtx.getElement(2,0)) * s
    self.x = (mtx.getElement(2,1) - mtx.getElement(1,2)) * s
  elsif ( diag00 > diag11 && diag00 > diag22 )
    t = diag00 - diag11 - diag22 + 1.0
    s = 1.0 / ( Math.sqrt( t ) * 2.0 )
    self.x = s * t
    self.y = (mtx.getElement(1,0) + mtx.getElement(0,1)) * s
    self.z = (mtx.getElement(0,2) + mtx.getElement(2,0)) * s
    self.w = (mtx.getElement(2,1) - mtx.getElement(1,2)) * s
  elsif ( diag11 > diag22 )
    t = -diag00 + diag11 - diag22 + 1.0
    s = 1.0 / ( Math.sqrt( t ) * 2.0 )
    self.y = s * t
    self.x = (mtx.getElement(1,0) + mtx.getElement(0,1)) * s
    self.w = (mtx.getElement(0,2) - mtx.getElement(2,0)) * s
    self.z = (mtx.getElement(2,1) + mtx.getElement(1,2)) * s
  else
    t = -diag00 - diag11 + diag22 + 1.0
    s = 1.0 / ( Math.sqrt( t ) * 2.0 )
    self.z = s * t
    self.w = (mtx.getElement(1,0) - mtx.getElement(0,1)) * s
    self.x = (mtx.getElement(0,2) + mtx.getElement(2,0)) * s
    self.y = (mtx.getElement(2,1) + mtx.getElement(1,2)) * s
  end

  return self
end

#setElements(x, y, z, w) ⇒ Object

call-seq: setElements( e0, e1, e2, e3 )

Stores given 4 new values.



2293
2294
2295
2296
2297
2298
# File 'lib/rmath3d/rmath3d_plain.rb', line 2293

def setElements( x, y, z, w )
  self.x = x
  self.y = y
  self.z = z
  self.w = w
end

#setIdentityObject

call-seq: setIdentity

Sets as identity quaternion.



2477
2478
2479
2480
2481
2482
2483
# File 'lib/rmath3d/rmath3d_plain.rb', line 2477

def setIdentity
  self.x = 0.0
  self.y = 0.0
  self.z = 0.0
  self.w = 1.0
  return self
end

#sub!(other) ⇒ Object

call-seq: quat1.sub!( quat2 )

quat1 -= quat2 : subtracts the elements of quat2 from corresponding quat1 elements.



2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
# File 'lib/rmath3d/rmath3d_plain.rb', line 2672

def sub!( other )
  if other.class != RQuat
    raise TypeError, "RQuat#sub! : Unknown type #{other.class}."
    return nil
  end

  self.x -= other.x
  self.y -= other.y
  self.z -= other.z
  self.w -= other.w

  return self
end

#to_aObject

call-seq: to_a

Returns its elements as a new Array.



2269
2270
2271
# File 'lib/rmath3d/rmath3d_plain.rb', line 2269

def to_a
  return @e
end

#to_sObject

call-seq: to_s

Returns human-readable string.



2260
2261
2262
# File 'lib/rmath3d/rmath3d_plain.rb', line 2260

def to_s
  return "( #{@e[0]}, #{@e[1]}, #{@e[2]}, #{@e[3]} )\n"
end

#toAxisAngleObject

call-seq: toAxisAngle -> [axis,radian]

Returns its rotation axis (RVec3) and rotation angle (in radian).



2801
2802
2803
2804
2805
2806
# File 'lib/rmath3d/rmath3d_plain.rb', line 2801

def toAxisAngle
  axis = RVec3.new( self.x, self.y, self.z ).normalize!
  radian = 2.0 * Math.acos( self.w )

  return [ axis, radian ]
end

#wObject

call-seq: w -> value

Returns the value of w.



2388
# File 'lib/rmath3d/rmath3d_plain.rb', line 2388

def w() return @e[3] end

#w=(value) ⇒ Object

call-seq: w= value

Stores value as w.



2335
# File 'lib/rmath3d/rmath3d_plain.rb', line 2335

def w=(value) @e[3] = value end

#xObject

call-seq: x -> value

Returns the value of x.



2367
# File 'lib/rmath3d/rmath3d_plain.rb', line 2367

def x() return @e[0] end

#x=(value) ⇒ Object

call-seq: x= value

Stores value as x.



2314
# File 'lib/rmath3d/rmath3d_plain.rb', line 2314

def x=(value) @e[0] = value end

#xyzObject

call-seq: xyz -> RVec3

Returns the values of x, y and z with new RVec3(x,y,z).



2395
2396
2397
# File 'lib/rmath3d/rmath3d_plain.rb', line 2395

def xyz()
  return RVec3.new( @e[0], @e[1], @e[2] )
end

#xyz=(arg) ⇒ Object

call-seq: xyz= vXYZ

Copies the values of vXYZ(RVec3) into x, y and z.



2342
2343
2344
2345
2346
2347
2348
2349
2350
# File 'lib/rmath3d/rmath3d_plain.rb', line 2342

def xyz=( arg )
  if arg.class != RVec3
    raise TypeError, "RQuat#xyz= : Unknown type #{arg.class}."
    return nil
  end
  @e[0] = arg.x
  @e[1] = arg.y
  @e[2] = arg.z
end

#yObject

call-seq: y -> value

Returns the value of y.



2374
# File 'lib/rmath3d/rmath3d_plain.rb', line 2374

def y() return @e[1] end

#y=(value) ⇒ Object

call-seq: y= value

Stores value as y.



2321
# File 'lib/rmath3d/rmath3d_plain.rb', line 2321

def y=(value) @e[1] = value end

#zObject

call-seq: z -> value

Returns the value of z.



2381
# File 'lib/rmath3d/rmath3d_plain.rb', line 2381

def z() return @e[2] end

#z=(value) ⇒ Object

call-seq: z= value

Stores value as z.



2328
# File 'lib/rmath3d/rmath3d_plain.rb', line 2328

def z=(value) @e[2] = value end