snap_to_canonical_view_quat.cpp 2.5 KB

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