snap_to_canonical_view_quat.h 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. #ifndef IGL_SNAP_TO_CANONICAL_QUAT_H
  2. #define IGL_SNAP_TO_CANONICAL_QUAT_H
  3. // A Quaternion, q, is defined here as an arrays of four scalars (x,y,z,w),
  4. // such that q = x*i + y*j + z*k + w
  5. namespace igl
  6. {
  7. // Snap a given quaternion to the "canonical quaternion" rotations.
  8. // Inputs:
  9. // q input quaternion
  10. // threshold threshold between 0 and 1, where 0 means
  11. template <typename Q_type>
  12. inline bool snap_to_canonical_view_quat(
  13. const Q_type q[4],
  14. const Q_type threshold,
  15. Q_type s[4]);
  16. }
  17. // Implementation
  18. #include "canonical_quaternions.h"
  19. #include "normalize_quat.h"
  20. // Note: For the canonical view quaternions it should be completely possible to
  21. // determine this anaylitcally. That is the max_distance should be a
  22. // theoretical known value
  23. // Also: I'm not sure it matters in this case, but. We are dealing with
  24. // quaternions on the 4d unit sphere, but measuring distance in general 4d
  25. // space (i.e. not geodesics on the sphere). Probably something with angles
  26. // would be better.
  27. template <typename Q_type>
  28. inline bool igl::snap_to_canonical_view_quat(
  29. const Q_type q[4],
  30. const Q_type threshold,
  31. Q_type s[4])
  32. {
  33. // Copy input into output
  34. // CANNOT use std::copy here according to:
  35. // http://www.cplusplus.com/reference/algorithm/copy/
  36. s[0] = q[0];
  37. s[1] = q[1];
  38. s[2] = q[2];
  39. s[3] = q[3];
  40. // Normalize input quaternion
  41. Q_type qn[4];
  42. bool valid_len =
  43. igl::normalize_quat(q,qn);
  44. // If normalizing valid then don't bother
  45. if(!valid_len)
  46. {
  47. return false;
  48. }
  49. // 0.290019
  50. const Q_type MAX_DISTANCE = 0.4;
  51. Q_type min_distance = 2*MAX_DISTANCE;
  52. int min_index = -1;
  53. int min_sign = 0;
  54. // loop over canonical view quaternions
  55. for(int sign = -1;sign<=1;sign+=2)
  56. {
  57. for(int i = 0; i<(int)NUM_CANONICAL_VIEW_QUAT; i++)
  58. {
  59. Q_type distance = 0.0;
  60. // loop over coordinates
  61. for(int j = 0;j<4;j++)
  62. {
  63. distance +=
  64. (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j))*
  65. (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j));
  66. }
  67. if(min_distance > distance)
  68. {
  69. min_distance = distance;
  70. min_index = i;
  71. min_sign = sign;
  72. }
  73. }
  74. }
  75. if(MAX_DISTANCE < min_distance)
  76. {
  77. fprintf(
  78. stderr,
  79. "ERROR: found new max MIN_DISTANCE: %g\n"
  80. "PLEASE update snap_to_canonical_quat()",
  81. min_distance);
  82. }
  83. assert(min_distance < MAX_DISTANCE);
  84. assert(min_index >= 0);
  85. if( min_distance/MAX_DISTANCE <= threshold)
  86. {
  87. // loop over coordinates
  88. for(int j = 0;j<4;j++)
  89. {
  90. s[j] = min_sign*igl::CANONICAL_VIEW_QUAT<Q_type>(min_index,j);
  91. }
  92. return true;
  93. }
  94. return false;
  95. }
  96. #endif