Module: Rabbit::TrackBall

Defined in:
lib/rabbit/trackball.rb

Defined Under Namespace

Classes: Vector

Constant Summary collapse

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.

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

97
@@quats_count =
0

Class Method Summary collapse

Class Method Details

.add_quats(q1, q2) ⇒ Object


210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# 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) ⇒ Object

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.


185
186
187
188
189
190
191
192
193
194
# 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) ⇒ Object


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# 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