module Rabbit::TrackBall

Constants

RENORM_COUNT

Given two rotations, e2 and e2, expressed as quaternion rotations, figure out the equivalent single rotation and stuff it into dest.

This routine also normalizes the result every RENORM_COUNT times it is called, to keep error from creeping in.

NOTE: This routine is written so that q1 or q2 may be the same as dest (or each other).

SIZE

This size should really be based on the distance from the center of rotation to the point on the object underneath the mouse. That point would then track the mouse as closely as possible. This is a simple example, though, so that is left as an Exercise for the Programmer.

Public Instance Methods

add_quats(q1, q2) click to toggle source
# File lib/rabbit/trackball.rb, line 210
def add_quats(q1, q2)
  t1 = q1.vscale(q2[3])
  t2 = q2.vscale(q1[3])
  t3 = q2.vcross(q1)
  tf = t1.vadd(t2)
  tf = t3.vadd(tf)
  
  tf[3] = q1[3] * q2[3] - q1.vdot(q2, 3)
  
  @@quats_count += 1
  ret = tf
  if (@@quats_count > RENORM_COUNT)
    @@quats_count = 0
    ret = tf.normalize_quat
  end
  ret
end
tb_project_to_sphere(r, x, y) click to toggle source

Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet if we are away from the center of the sphere.

# File lib/rabbit/trackball.rb, line 185
def tb_project_to_sphere(r, x, y)
  d = Math.sqrt(x * x + y * y)
  if (d < r * 0.70710678118654752440)     # Inside sphere
    z = Math.sqrt(r * r - d * d)
  else          # On hyperbola
    t = r / 1.41421356237309504880
    z = t * t / d
  end
  z
end
trackball(p1x, p1y, p2x, p2y) click to toggle source
# File lib/rabbit/trackball.rb, line 156
def trackball(p1x, p1y, p2x, p2y)
  if (p1x == p2x && p1y == p2y)
    return Vector.new([0.0, 0.0, 0.0, 1.0])
  end

  # First, figure out z-coordinates for projection of P1 and P2 to
  # deformed sphere
  p1 = Vector.new([p1x, p1y, tb_project_to_sphere(SIZE, p1x, p1y)])
  p2 = Vector.new([p2x, p2y, tb_project_to_sphere(SIZE, p2x, p2y)])

  # Now, we want the cross product of P1 and P2
  a = p2.vcross(p1)
  
  # Figure out how much to rotate around that axis.
  d = p1.vsub(p2)
  t = d.vlength / (2.0 * SIZE)
  
  # Avoid problems with out-of-control values...
  t = 1.0 if (t > 1.0)
  t = -1.0 if (t < -1.0)
  phi = 2.0 * Math.asin(t)
  
  a.axis_to_quat(phi)
end