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.



2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
# File 'lib/rmath3d/rmath3d_plain.rb', line 2261

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.



2460
2461
2462
2463
2464
2465
2466
# File 'lib/rmath3d/rmath3d_plain.rb', line 2460

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



2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
# File 'lib/rmath3d/rmath3d_plain.rb', line 2474

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.



2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
# File 'lib/rmath3d/rmath3d_plain.rb', line 2641

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.



2615
2616
2617
2618
2619
2620
2621
# File 'lib/rmath3d/rmath3d_plain.rb', line 2615

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.



2597
2598
2599
# File 'lib/rmath3d/rmath3d_plain.rb', line 2597

def +@
  return self
end

#-(arg) ⇒ Object

call-seq: -

quat1 - quat2 : Binary minus operator.



2628
2629
2630
2631
2632
2633
2634
# File 'lib/rmath3d/rmath3d_plain.rb', line 2628

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.



2606
2607
2608
# File 'lib/rmath3d/rmath3d_plain.rb', line 2606

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

#==(other) ⇒ Object

call-seq: ==

quat1 == quat2 : evaluates equality.



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

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.



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

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

#[]=(i, value) ⇒ Object

call-seq: quat= value

Stores value at i.



2343
2344
2345
# File 'lib/rmath3d/rmath3d_plain.rb', line 2343

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.



2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
# File 'lib/rmath3d/rmath3d_plain.rb', line 2690

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.



2316
2317
2318
2319
2320
2321
2322
2323
2324
# File 'lib/rmath3d/rmath3d_plain.rb', line 2316

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.



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

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.



2528
2529
2530
# File 'lib/rmath3d/rmath3d_plain.rb', line 2528

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

#getInverseObject

call-seq: getInverse -> inverse quaternion

Returns the inverse.



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

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.



2442
2443
2444
# File 'lib/rmath3d/rmath3d_plain.rb', line 2442

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.



2451
2452
2453
# File 'lib/rmath3d/rmath3d_plain.rb', line 2451

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.



2573
2574
2575
2576
# File 'lib/rmath3d/rmath3d_plain.rb', line 2573

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.



2559
2560
2561
2562
2563
2564
2565
2566
# File 'lib/rmath3d/rmath3d_plain.rb', line 2559

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



2728
2729
2730
2731
2732
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
# File 'lib/rmath3d/rmath3d_plain.rb', line 2728

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.



2583
2584
2585
2586
2587
2588
2589
2590
# File 'lib/rmath3d/rmath3d_plain.rb', line 2583

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.



2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
# File 'lib/rmath3d/rmath3d_plain.rb', line 2818

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



2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
# File 'lib/rmath3d/rmath3d_plain.rb', line 2770

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.



2331
2332
2333
2334
2335
2336
# File 'lib/rmath3d/rmath3d_plain.rb', line 2331

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.



2515
2516
2517
2518
2519
2520
2521
# File 'lib/rmath3d/rmath3d_plain.rb', line 2515

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.



2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
# File 'lib/rmath3d/rmath3d_plain.rb', line 2709

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.



2307
2308
2309
# File 'lib/rmath3d/rmath3d_plain.rb', line 2307

def to_a
  return @e
end

#to_sObject

call-seq: to_s

Returns human-readable string.



2298
2299
2300
# File 'lib/rmath3d/rmath3d_plain.rb', line 2298

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



2838
2839
2840
2841
2842
2843
# File 'lib/rmath3d/rmath3d_plain.rb', line 2838

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.



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

def w() return @e[3] end

#w=(value) ⇒ Object

call-seq: w= value

Stores value as w.



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

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

#xObject

call-seq: x -> value

Returns the value of x.



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

def x() return @e[0] end

#x=(value) ⇒ Object

call-seq: x= value

Stores value as x.



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

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



2433
2434
2435
# File 'lib/rmath3d/rmath3d_plain.rb', line 2433

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.



2380
2381
2382
2383
2384
2385
2386
2387
2388
# File 'lib/rmath3d/rmath3d_plain.rb', line 2380

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.



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

def y() return @e[1] end

#y=(value) ⇒ Object

call-seq: y= value

Stores value as y.



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

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

#zObject

call-seq: z -> value

Returns the value of z.



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

def z() return @e[2] end

#z=(value) ⇒ Object

call-seq: z= value

Stores value as z.



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

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