sparse_voxel_grid.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #include "sparse_voxel_grid.h"
  2. #include <unordered_map>
  3. #include <array>
  4. #include <vector>
  5. template <typename DerivedS, typename DerivedP0, typename DerivedV, typename DerivedI>
  6. IGL_INLINE void igl::sparse_voxel_grid(const Eigen::MatrixBase<DerivedP0>& p0,
  7. const std::function<typename DerivedS::Scalar(const DerivedP0&)>& scalarFunc,
  8. const double eps,
  9. Eigen::PlainObjectBase<DerivedS>& CS,
  10. Eigen::PlainObjectBase<DerivedV>& CV,
  11. Eigen::PlainObjectBase<DerivedI>& CI,
  12. int expected_number_of_cubes)
  13. {
  14. typedef typename DerivedV::Scalar ScalarV;
  15. typedef typename DerivedS::Scalar ScalarS;
  16. typedef typename DerivedI::Scalar ScalarI;
  17. typedef Eigen::Matrix<ScalarV, 1, 3> VertexRowVector;
  18. typedef Eigen::Matrix<ScalarI, 1, 8> IndexRowVector;
  19. struct IndexRowVectorHash {
  20. std::size_t operator()(const Eigen::RowVector3i& key) const {
  21. std::size_t seed = 0;
  22. std::hash<int> hasher;
  23. for (int i = 0; i < 3; i++) {
  24. seed ^= hasher(key[i]) + 0x9e3779b9 + (seed<<6) + (seed>>2); // Copied from boost::hash_combine
  25. }
  26. return seed;
  27. }
  28. };
  29. auto sgn = [](ScalarS val) -> int {
  30. return (ScalarS(0) < val) - (val < ScalarS(0));
  31. };
  32. ScalarV half_eps = 0.5 * eps;
  33. std::vector<IndexRowVector> CI_vector(expected_number_of_cubes);
  34. std::vector<VertexRowVector> CV_vector(8*expected_number_of_cubes);
  35. std::vector<ScalarS> CS_vector(8*expected_number_of_cubes);
  36. // Track visisted neighbors
  37. std::unordered_map<Eigen::RowVector3i, int, IndexRowVectorHash> visited(6*expected_number_of_cubes);
  38. // BFS Queue
  39. std::vector<Eigen::RowVector3i> queue(expected_number_of_cubes*8);
  40. queue.push_back(Eigen::RowVector3i(0, 0, 0));
  41. while (queue.size() > 0)
  42. {
  43. Eigen::RowVector3i pi = queue.back();
  44. queue.pop_back();
  45. VertexRowVector ctr = p0 + eps*pi.cast<ScalarV>(); // R^3 center of this cube
  46. // X, Y, Z basis vectors, and array of neighbor offsets used to construct cubes
  47. const Eigen::RowVector3i bx(1, 0, 0), by(0, 1, 0), bz(0, 0, -1);
  48. const std::array<Eigen::RowVector3i, 6> neighbors = {
  49. bx, -bx, by, -by, bz, -bz
  50. };
  51. // Compute the position of the cube corners and the scalar values at those corners
  52. std::array<VertexRowVector, 8> cubeCorners = {
  53. ctr+half_eps*(bx+by+bz).cast<ScalarV>(), ctr+half_eps*(bx+by-bz).cast<ScalarV>(), ctr+half_eps*(-bx+by-bz).cast<ScalarV>(), ctr+half_eps*(-bx+by+bz).cast<ScalarV>(),
  54. ctr+half_eps*(bx-by+bz).cast<ScalarV>(), ctr+half_eps*(bx-by-bz).cast<ScalarV>(), ctr+half_eps*(-bx-by-bz).cast<ScalarV>(), ctr+half_eps*(-bx-by+bz).cast<ScalarV>()
  55. };
  56. std::array<ScalarS, 8> cubeScalars;
  57. for (int i = 0; i < 8; i++) { cubeScalars[i] = scalarFunc(cubeCorners[i]); }
  58. // If this cube doesn't intersect the surface, disregard it
  59. bool validCube = false;
  60. int sign = sgn(cubeScalars[0]);
  61. for (int i = 1; i < 8; i++) {
  62. if (sign != sgn(cubeScalars[i])) {
  63. validCube = true;
  64. break;
  65. }
  66. }
  67. if (!validCube) {
  68. continue;
  69. }
  70. // Add the cube vertices and indices to the output arrays if they are not there already
  71. IndexRowVector cube;
  72. uint8_t vertexAlreadyAdded = 0; // This is a bimask. If a bit is 1, it has been visited already by the BFS
  73. constexpr std::array<uint8_t, 6> zv = {
  74. (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5),
  75. (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7),
  76. (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
  77. (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
  78. (1 << 0) | (1 << 3) | (1 << 4) | (1 << 7),
  79. (1 << 1) | (1 << 2) | (1 << 5) | (1 << 6), };
  80. constexpr std::array<std::array<int, 4>, 6> zvv {{
  81. {{0, 1, 4, 5}}, {{3, 2, 7, 6}}, {{0, 1, 2, 3}},
  82. {{4, 5, 6, 7}}, {{0, 3, 4, 7}}, {{1, 2, 5, 6}} }};
  83. for (int n = 0; n < 6; n++) { // For each neighbor, check the hash table to see if its been added before
  84. Eigen::RowVector3i nkey = pi + neighbors[n];
  85. auto nbr = visited.find(nkey);
  86. if (nbr != visited.end()) { // We've already visited this neighbor, use references to its vertices instead of duplicating them
  87. vertexAlreadyAdded |= zv[n];
  88. for (int i = 0; i < 4; i++) { cube[zvv[n][i]] = CI_vector[nbr->second][zvv[n % 2 == 0 ? n + 1 : n - 1][i]]; }
  89. } else {
  90. queue.push_back(nkey); // Otherwise, we have not visited the neighbor, put it in the BFS queue
  91. }
  92. }
  93. for (int i = 0; i < 8; i++) { // Add new, non-visited,2 vertices to the arrays
  94. if (0 == ((1 << i) & vertexAlreadyAdded)) {
  95. cube[i] = CS_vector.size();
  96. CV_vector.push_back(cubeCorners[i]);
  97. CS_vector.push_back(cubeScalars[i]);
  98. }
  99. }
  100. visited[pi] = CI_vector.size();
  101. CI_vector.push_back(cube);
  102. }
  103. CV.conservativeResize(CV_vector.size(), 3);
  104. CS.conservativeResize(CS_vector.size(), 1);
  105. CI.conservativeResize(CI_vector.size(), 8);
  106. // If you pass in column-major matrices, this is going to be slooooowwwww
  107. for (int i = 0; i < CV_vector.size(); i++) {
  108. CV.row(i) = CV_vector[i];
  109. }
  110. for (int i = 0; i < CS_vector.size(); i++) {
  111. CS[i] = CS_vector[i];
  112. }
  113. for (int i = 0; i < CI_vector.size(); i++) {
  114. CI.row(i) = CI_vector[i];
  115. }
  116. }
  117. #ifdef IGL_STATIC_LIBRARY
  118. template void igl::sparse_voxel_grid<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, std::function<Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&)> const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, int);
  119. #endif