snap_to_canonical_view_quat.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. double min_sign = 0;
  40. // loop over canonical view quaternions
  41. for(double 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. // Double cast because of bug in llvm version 4.2 with -O3
  50. distance +=
  51. (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j))*
  52. (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j));
  53. }
  54. if(min_distance > distance)
  55. {
  56. min_distance = distance;
  57. min_index = i;
  58. min_sign = sign;
  59. }
  60. }
  61. }
  62. if(MAX_DISTANCE < min_distance)
  63. {
  64. fprintf(
  65. stderr,
  66. "ERROR: found new max MIN_DISTANCE: %g\n"
  67. "PLEASE update snap_to_canonical_quat()",
  68. min_distance);
  69. }
  70. assert(min_distance < MAX_DISTANCE);
  71. assert(min_index >= 0);
  72. if( min_distance/MAX_DISTANCE <= threshold)
  73. {
  74. // loop over coordinates
  75. for(int j = 0;j<4;j++)
  76. {
  77. s[j] = min_sign*igl::CANONICAL_VIEW_QUAT<Q_type>(min_index,j);
  78. }
  79. return true;
  80. }
  81. return false;
  82. }
  83. #ifndef IGL_HEADER_ONLY
  84. // Explicit template specialization
  85. // generated by autoexplicit.sh
  86. template bool igl::snap_to_canonical_view_quat<double>(double const*, double, double*);
  87. // generated by autoexplicit.sh
  88. template bool igl::snap_to_canonical_view_quat<float>(float const*, float, float*);
  89. #endif