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.



2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
# File 'lib/rmath3d/rmath3d_plain.rb', line 2358

def initialize( *a )
  @e = []
  case a.length
  when 0
    @e = [0.0, 0.0, 0.0, 0.0]
  when 1
    case a[0]
    when Float, Integer
      @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 Float, Integer
        @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.



2557
2558
2559
2560
2561
2562
2563
# File 'lib/rmath3d/rmath3d_plain.rb', line 2557

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).



2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
# File 'lib/rmath3d/rmath3d_plain.rb', line 2571

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.



2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
# File 'lib/rmath3d/rmath3d_plain.rb', line 2738

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 Float, Integer
    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.



2712
2713
2714
2715
2716
2717
2718
# File 'lib/rmath3d/rmath3d_plain.rb', line 2712

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.



2694
2695
2696
# File 'lib/rmath3d/rmath3d_plain.rb', line 2694

def +@
  return self
end

#-(arg) ⇒ Object

call-seq: -

quat1 - quat2 : Binary minus operator.



2725
2726
2727
2728
2729
2730
2731
# File 'lib/rmath3d/rmath3d_plain.rb', line 2725

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.



2703
2704
2705
# File 'lib/rmath3d/rmath3d_plain.rb', line 2703

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

#==(other) ⇒ Object

call-seq: ==

quat1 == quat2 : evaluates equality.



2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
# File 'lib/rmath3d/rmath3d_plain.rb', line 2767

def ==( other )
  if other.class == RQuat
    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
  else
    return false
  end
end

#[](i) ⇒ Object

call-seq: quat -> value

Returns the element at i.



2492
2493
2494
# File 'lib/rmath3d/rmath3d_plain.rb', line 2492

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

#[]=(i, value) ⇒ Object

call-seq: quat= value

Stores value at i.



2440
2441
2442
# File 'lib/rmath3d/rmath3d_plain.rb', line 2440

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.



2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
# File 'lib/rmath3d/rmath3d_plain.rb', line 2787

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.



2413
2414
2415
2416
2417
2418
2419
2420
2421
# File 'lib/rmath3d/rmath3d_plain.rb', line 2413

def coerce( arg )
  case arg
  when Float, Integer
    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.



2634
2635
2636
2637
2638
2639
# File 'lib/rmath3d/rmath3d_plain.rb', line 2634

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.



2625
2626
2627
# File 'lib/rmath3d/rmath3d_plain.rb', line 2625

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

#getInverseObject

call-seq: getInverse -> inverse quaternion

Returns the inverse.



2646
2647
2648
2649
# File 'lib/rmath3d/rmath3d_plain.rb', line 2646

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.



2539
2540
2541
# File 'lib/rmath3d/rmath3d_plain.rb', line 2539

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.



2548
2549
2550
# File 'lib/rmath3d/rmath3d_plain.rb', line 2548

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.



2670
2671
2672
2673
# File 'lib/rmath3d/rmath3d_plain.rb', line 2670

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.



2656
2657
2658
2659
2660
2661
2662
2663
# File 'lib/rmath3d/rmath3d_plain.rb', line 2656

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



2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
# File 'lib/rmath3d/rmath3d_plain.rb', line 2825

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 Float, Integer
    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.



2680
2681
2682
2683
2684
2685
2686
2687
# File 'lib/rmath3d/rmath3d_plain.rb', line 2680

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.



2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
# File 'lib/rmath3d/rmath3d_plain.rb', line 2915

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).



2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
# File 'lib/rmath3d/rmath3d_plain.rb', line 2867

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.



2428
2429
2430
2431
2432
2433
# File 'lib/rmath3d/rmath3d_plain.rb', line 2428

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.



2612
2613
2614
2615
2616
2617
2618
# File 'lib/rmath3d/rmath3d_plain.rb', line 2612

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.



2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
# File 'lib/rmath3d/rmath3d_plain.rb', line 2806

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.



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

def to_a
  return @e
end

#to_sObject

call-seq: to_s

Returns human-readable string.



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

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

#toAxisAngleObject

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

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



2935
2936
2937
2938
2939
2940
# File 'lib/rmath3d/rmath3d_plain.rb', line 2935

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.



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

def w() return @e[3] end

#w=(value) ⇒ Object

call-seq: w= value

Stores value as w.



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

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

#xObject

call-seq: x -> value

Returns the value of x.



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

def x() return @e[0] end

#x=(value) ⇒ Object

call-seq: x= value

Stores value as x.



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

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).



2530
2531
2532
# File 'lib/rmath3d/rmath3d_plain.rb', line 2530

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.



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

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.



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

def y() return @e[1] end

#y=(value) ⇒ Object

call-seq: y= value

Stores value as y.



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

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

#zObject

call-seq: z -> value

Returns the value of z.



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

def z() return @e[2] end

#z=(value) ⇒ Object

call-seq: z= value

Stores value as z.



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

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