trackball.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. namespace igl
  2. {
  3. // Applies a trackball drag to a given rotation
  4. // Inputs:
  5. // w width of the trackball context
  6. // h height of the trackball context
  7. // speed_factor controls how fast the trackball feels, 1 is normal
  8. // down_quat rotation at mouse down, i.e. the rotation we're applying the
  9. // trackball motion to (as quaternion)
  10. // down_mouse_x x position of mouse down
  11. // down_mouse_y y position of mouse down
  12. // mouse_x current x position of mouse
  13. // mouse_y current y position of mouse
  14. // Outputs:
  15. // quat the resulting rotation (as quaternion)
  16. void trackball(
  17. const int w,
  18. const int h,
  19. const double speed_factor,
  20. const float * down_quat,
  21. const int down_mouse_x,
  22. const int down_mouse_y,
  23. const int mouse_x,
  24. const int mouse_y,
  25. float * quat);
  26. }
  27. // Implementation
  28. #include <dot.h>
  29. #include <cross.h>
  30. #include <axis_angle_to_quat.h>
  31. #include <quat_mult.h>
  32. #include <cmath>
  33. #include <cstdlib>
  34. #include <algorithm>
  35. // Utility inline functions
  36. static inline float _QuatD(int w, int h)
  37. {
  38. return (float)std::min(abs(w), abs(h)) - 4;
  39. }
  40. static inline float _QuatIX(int x, int w, int h)
  41. {
  42. return (2.0f*(float)x - (float)w - 1.0f)/_QuatD(w, h);
  43. }
  44. static inline float _QuatIY(int y, int w, int h)
  45. {
  46. return (-2.0f*(float)y + (float)h - 1.0f)/_QuatD(w, h);
  47. }
  48. // This is largely the trackball as implemented in AntTweakbar. Much of the
  49. // code is straight from its source in TwMgr.cpp
  50. // http://www.antisphere.com/Wiki/tools:anttweakbar
  51. void igl::trackball(
  52. const int w,
  53. const int h,
  54. const double speed_factor,
  55. const float * down_quat,
  56. const int down_mouse_x,
  57. const int down_mouse_y,
  58. const int mouse_x,
  59. const int mouse_y,
  60. float * quat)
  61. {
  62. double original_x =
  63. _QuatIX(speed_factor*(down_mouse_x-w/2)+w/2, w, h);
  64. double original_y =
  65. _QuatIY(speed_factor*(down_mouse_y-h/2)+h/2, w, h);
  66. double x = _QuatIX(speed_factor*(mouse_x-w/2)+w/2, w, h);
  67. double y = _QuatIY(speed_factor*(mouse_y-h/2)+h/2, w, h);
  68. double z = 1;
  69. double n0 = sqrt(original_x*original_x + original_y*original_y + z*z);
  70. double n1 = sqrt(x*x + y*y + z*z);
  71. if(n0>DOUBLE_EPS && n1>DOUBLE_EPS)
  72. {
  73. double v0[] = { original_x/n0, original_y/n0, z/n0 };
  74. double v1[] = { x/n1, y/n1, z/n1 };
  75. double axis[3];
  76. cross(v0,v1,axis);
  77. double sa = sqrt(dot(axis, axis));
  78. double ca = dot(v0, v1);
  79. double angle = atan2(sa, ca);
  80. if( x*x+y*y>1.0 )
  81. {
  82. angle *= 1.0 + 0.2f*(sqrt(x*x+y*y)-1.0);
  83. }
  84. double qrot[4], qres[4], qorig[4];
  85. axis_angle_to_quat(axis,angle,qrot);
  86. double nqorig =
  87. sqrt(down_quat[0]*down_quat[0]+
  88. down_quat[1]*down_quat[1]+
  89. down_quat[2]*down_quat[2]+
  90. down_quat[3]*down_quat[3]);
  91. if( fabs(nqorig)>DOUBLE_EPS_SQ )
  92. {
  93. qorig[0] = down_quat[0]/nqorig;
  94. qorig[1] = down_quat[1]/nqorig;
  95. qorig[2] = down_quat[2]/nqorig;
  96. qorig[3] = down_quat[3]/nqorig;
  97. quat_mult(qrot,qorig,qres);
  98. quat[0] = qres[0];
  99. quat[1] = qres[1];
  100. quat[2] = qres[2];
  101. quat[3] = qres[3];
  102. }
  103. else
  104. {
  105. quat[0] = qrot[0];
  106. quat[1] = qrot[1];
  107. quat[2] = qrot[2];
  108. quat[3] = qrot[3];
  109. }
  110. }
  111. }