trackball.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #include "trackball.h"
  2. #include "EPS.h"
  3. #include "dot.h"
  4. #include "cross.h"
  5. #include "axis_angle_to_quat.h"
  6. #include "quat_mult.h"
  7. #include <cmath>
  8. #include <cstdlib>
  9. #include <cassert>
  10. #include <algorithm>
  11. // Utility IGL_INLINE functions
  12. template <typename Q_type>
  13. static IGL_INLINE Q_type _QuatD(int w, int h)
  14. {
  15. return (Q_type)(abs(w) < abs(h) ? abs(w) : abs(h)) - 4;
  16. }
  17. template <typename Q_type>
  18. static IGL_INLINE Q_type _QuatIX(int x, int w, int h)
  19. {
  20. return (2.0f*(Q_type)x - (Q_type)w - 1.0f)/_QuatD<Q_type>(w, h);
  21. }
  22. template <typename Q_type>
  23. static IGL_INLINE Q_type _QuatIY(int y, int w, int h)
  24. {
  25. return (-2.0f*(Q_type)y + (Q_type)h - 1.0f)/_QuatD<Q_type>(w, h);
  26. }
  27. // This is largely the trackball as implemented in AntTweakbar. Much of the
  28. // code is straight from its source in TwMgr.cpp
  29. // http://www.antisphere.com/Wiki/tools:anttweakbar
  30. template <typename Q_type>
  31. IGL_INLINE void igl::trackball(
  32. const int w,
  33. const int h,
  34. const Q_type speed_factor,
  35. const int down_mouse_x,
  36. const int down_mouse_y,
  37. const int mouse_x,
  38. const int mouse_y,
  39. Q_type * quat)
  40. {
  41. assert(speed_factor > 0);
  42. double original_x =
  43. _QuatIX<Q_type>(speed_factor*(down_mouse_x-w/2)+w/2, w, h);
  44. double original_y =
  45. _QuatIY<Q_type>(speed_factor*(down_mouse_y-h/2)+h/2, w, h);
  46. double x = _QuatIX<Q_type>(speed_factor*(mouse_x-w/2)+w/2, w, h);
  47. double y = _QuatIY<Q_type>(speed_factor*(mouse_y-h/2)+h/2, w, h);
  48. double z = 1;
  49. double n0 = sqrt(original_x*original_x + original_y*original_y + z*z);
  50. double n1 = sqrt(x*x + y*y + z*z);
  51. if(n0>igl::DOUBLE_EPS && n1>igl::DOUBLE_EPS)
  52. {
  53. double v0[] = { original_x/n0, original_y/n0, z/n0 };
  54. double v1[] = { x/n1, y/n1, z/n1 };
  55. double axis[3];
  56. cross(v0,v1,axis);
  57. double sa = sqrt(dot(axis, axis));
  58. double ca = dot(v0, v1);
  59. double angle = atan2(sa, ca);
  60. if( x*x+y*y>1.0 )
  61. {
  62. angle *= 1.0 + 0.2f*(sqrt(x*x+y*y)-1.0);
  63. }
  64. double qrot[4];
  65. axis_angle_to_quat(axis,angle,qrot);
  66. quat[0] = qrot[0];
  67. quat[1] = qrot[1];
  68. quat[2] = qrot[2];
  69. quat[3] = qrot[3];
  70. }
  71. }
  72. template <typename Q_type>
  73. IGL_INLINE void igl::trackball(
  74. const int w,
  75. const int h,
  76. const Q_type speed_factor,
  77. const Q_type * down_quat,
  78. const int down_mouse_x,
  79. const int down_mouse_y,
  80. const int mouse_x,
  81. const int mouse_y,
  82. Q_type * quat)
  83. {
  84. double qrot[4], qres[4], qorig[4];
  85. igl::trackball<double>(
  86. w,h,
  87. speed_factor,
  88. down_mouse_x,down_mouse_y,
  89. mouse_x,mouse_y,
  90. qrot);
  91. double nqorig =
  92. sqrt(down_quat[0]*down_quat[0]+
  93. down_quat[1]*down_quat[1]+
  94. down_quat[2]*down_quat[2]+
  95. down_quat[3]*down_quat[3]);
  96. if( fabs(nqorig)>igl::DOUBLE_EPS_SQ )
  97. {
  98. qorig[0] = down_quat[0]/nqorig;
  99. qorig[1] = down_quat[1]/nqorig;
  100. qorig[2] = down_quat[2]/nqorig;
  101. qorig[3] = down_quat[3]/nqorig;
  102. igl::quat_mult<double>(qrot,qorig,qres);
  103. quat[0] = qres[0];
  104. quat[1] = qres[1];
  105. quat[2] = qres[2];
  106. quat[3] = qres[3];
  107. }
  108. else
  109. {
  110. quat[0] = qrot[0];
  111. quat[1] = qrot[1];
  112. quat[2] = qrot[2];
  113. quat[3] = qrot[3];
  114. }
  115. }
  116. #ifndef IGL_HEADER_ONLY
  117. // Explicit template specialization
  118. // generated by autoexplicit.sh
  119. template void igl::trackball<double>(int, int, double, double const*, int, int, int, int, double*);
  120. // generated by autoexplicit.sh
  121. template void igl::trackball<float>(int, int, float, float const*, int, int, int, int, float*);
  122. #endif