Trackball.cpp

From Immersive Visualization Lab Wiki
Revision as of 22:56, 28 October 2011 by Jschulze (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
/** Applies a rotation to a matrix according to a fictitious trackball, placed in
    the middle of the window.
    The trackball is approximated by a Gaussian curve.
    The trackball coordinate system is: x=right, y=up, z=to viewer<BR>
    The origin of the mouse coordinates zero (0,0) is considered to be top left.
  @param width, height  window size in pixels
  @param fromX, fromY   mouse starting position in pixels
  @param toX, toY       mouse end position in pixels
*/
Matrix trackballRotation(int width, int height, int fromX, int fromY, int toX, int toY)
{
  const float TRACKBALL_SIZE = 1.3f;            // virtual trackball size
  Matrix mInv;                                  // inverse of ObjectView matrix
  Vector3 v1, v2;                               // mouse drag positions in normalized 3D space
  float smallSize;                              // smaller window size between width and height
  float halfWidth, halfHeight;                  // half window sizes
  float angle;                                  // rotational angle
  float d;                                      // distance

  // Compute mouse coordinates in window and normalize to -1..1
  // ((0,0)=window center, (-1,-1) = bottom left, (1,1) = top right)
  halfWidth   = (float)width  / 2.0;
  halfHeight  = (float)height / 2.0;
  smallSize   = (halfWidth < halfHeight) ? halfWidth : halfHeight;
  v1.x     = ((float)fromX - halfWidth)  / smallSize;
  v1.y     = ((float)(height-fromY) - halfHeight) / smallSize;
  v2.x     = ((float)toX   - halfWidth)  / smallSize;
  v2.y     = ((float)(height-toY)   - halfHeight) / smallSize;

  // Compute z-coordinates on Gaussian trackball:
  d       = sqrtf(v1.x * v1.x + v1.y * v1.y);
  v1.z    = expf(-TRACKBALL_SIZE * d * d);
  d       = sqrtf(v2.x * v2.x + v2.y * v2.y);
  v2.z    = expf(-TRACKBALL_SIZE * d * d);

  // Compute rotational angle:
  angle = v1.angle(v2);                           // angle between v1 and v2

  // Compute rotational axis:
  v2.cross(v1);                                   // v2 = v2 x v1 (cross product)

  // Convert axis coordinates (v2) from world coordinates to object coordinates:
  mInv.identity();
  mInv.copyRot(this);                             // copy rotational part of mv to mInv
  mInv.invertOrtho();                             // invert orthogonal matrix mInv
  v2.multiply(mInv);                              // v2 = v2 x mInv (matrix multiplication)
  v2.normalize();                                 // normalize v2 before rotation

  // Perform acutal model view matrix modification:
  return rotate(-angle, v2.x, v2.y, v2.z);      // rotate model view matrix
}