sparse_voxel_grid.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #include "sparse_voxel_grid.h"
  2. #include <unordered_map>
  3. #include <array>
  4. #include <vector>
  5. #include <cstdint>
  6. template <typename DerivedP0, typename Func, typename DerivedS, typename DerivedV, typename DerivedI>
  7. IGL_INLINE void igl::sparse_voxel_grid(const Eigen::MatrixBase<DerivedP0>& p0,
  8. const Func& scalarFunc,
  9. const double eps,
  10. const int expected_number_of_cubes,
  11. Eigen::PlainObjectBase<DerivedS>& CS,
  12. Eigen::PlainObjectBase<DerivedV>& CV,
  13. Eigen::PlainObjectBase<DerivedI>& CI)
  14. {
  15. typedef typename DerivedV::Scalar ScalarV;
  16. typedef typename DerivedS::Scalar ScalarS;
  17. typedef typename DerivedI::Scalar ScalarI;
  18. typedef Eigen::Matrix<ScalarV, 1, 3> VertexRowVector;
  19. typedef Eigen::Matrix<ScalarI, 1, 8> IndexRowVector;
  20. struct IndexRowVectorHash {
  21. std::size_t operator()(const Eigen::RowVector3i& key) const {
  22. std::size_t seed = 0;
  23. std::hash<int> hasher;
  24. for (int i = 0; i < 3; i++) {
  25. seed ^= hasher(key[i]) + 0x9e3779b9 + (seed<<6) + (seed>>2); // Copied from boost::hash_combine
  26. }
  27. return seed;
  28. }
  29. };
  30. auto sgn = [](ScalarS val) -> int {
  31. return (ScalarS(0) < val) - (val < ScalarS(0));
  32. };
  33. ScalarV half_eps = 0.5 * eps;
  34. std::vector<IndexRowVector> CI_vector;
  35. std::vector<VertexRowVector> CV_vector;
  36. std::vector<ScalarS> CS_vector;
  37. CI_vector.reserve(expected_number_of_cubes);
  38. CV_vector.reserve(8 * expected_number_of_cubes);
  39. CS_vector.reserve(8 * expected_number_of_cubes);
  40. // Track visisted neighbors
  41. std::unordered_map<Eigen::RowVector3i, int, IndexRowVectorHash> visited;
  42. visited.reserve(6 * expected_number_of_cubes);
  43. visited.max_load_factor(0.5);
  44. // BFS Queue
  45. std::vector<Eigen::RowVector3i> queue;
  46. queue.reserve(expected_number_of_cubes * 8);
  47. queue.push_back(Eigen::RowVector3i(0, 0, 0));
  48. while (queue.size() > 0)
  49. {
  50. Eigen::RowVector3i pi = queue.back();
  51. queue.pop_back();
  52. if(visited.count(pi)){ continue; }
  53. VertexRowVector ctr = p0 + eps*pi.cast<ScalarV>(); // R^3 center of this cube
  54. // X, Y, Z basis vectors, and array of neighbor offsets used to construct cubes
  55. const Eigen::RowVector3i bx(1, 0, 0), by(0, 1, 0), bz(0, 0, -1);
  56. const std::array<Eigen::RowVector3i, 26> neighbors = {
  57. bx, -bx, by, -by, bz, -bz,
  58. by-bz, -by+bz, // 1-2 4-7
  59. bx+by, -bx-by, // 0-1 7-6
  60. by+bz, -by-bz, // 0-3 6-5
  61. by-bx, -by+bx, // 2-3 5-4
  62. bx-bz, -bx+bz, // 1-5 3-7
  63. bx+bz, -bx-bz, // 0-4 2-6
  64. -bx+by+bz, bx-by-bz, // 3 5
  65. bx+by+bz, -bx-by-bz, // 0 6
  66. bx+by-bz, -bx-by+bz, //1 7
  67. -bx+by-bz, bx-by+bz, // 2 4,
  68. };
  69. // Compute the position of the cube corners and the scalar values at those corners
  70. //
  71. // Cube corners are ordered y-x-z, so their xyz offsets are:
  72. //
  73. // +++
  74. // ++-
  75. // -+-
  76. // -++
  77. // +-+
  78. // +--
  79. // ---
  80. // --+
  81. std::array<VertexRowVector, 8> cubeCorners = {
  82. 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>(),
  83. 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>()
  84. };
  85. std::array<ScalarS, 8> cubeScalars;
  86. for (int i = 0; i < 8; i++) { cubeScalars[i] = scalarFunc(cubeCorners[i]); }
  87. // If this cube doesn't intersect the surface, disregard it
  88. bool validCube = false;
  89. int sign = sgn(cubeScalars[0]);
  90. for (int i = 1; i < 8; i++) {
  91. if (sign != sgn(cubeScalars[i])) {
  92. validCube = true;
  93. break;
  94. }
  95. }
  96. if (!validCube) {
  97. continue;
  98. }
  99. // Add the cube vertices and indices to the output arrays if they are not there already
  100. IndexRowVector cube;
  101. std::uint8_t vertexAlreadyAdded = 0; // This is a bimask. If a bit is 1, it has been visited already by the BFS
  102. constexpr std::array<std::uint8_t, 26> zv = {
  103. (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5),
  104. (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7),
  105. (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
  106. (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
  107. (1 << 0) | (1 << 3) | (1 << 4) | (1 << 7),
  108. (1 << 1) | (1 << 2) | (1 << 5) | (1 << 6),
  109. (1 << 1) | (1 << 2),
  110. (1 << 4) | (1 << 7),
  111. (1 << 0) | (1 << 1),
  112. (1 << 6) | (1 << 7),
  113. (1 << 0) | (1 << 3),
  114. (1 << 5) | (1 << 6),
  115. (1 << 2) | (1 << 3),
  116. (1 << 4) | (1 << 5),
  117. (1 << 1) | (1 << 5),
  118. (1 << 3) | (1 << 7),
  119. (1 << 0) | (1 << 4),
  120. (1 << 2) | (1 << 6),
  121. (1 << 3), (1 << 5), // diagonals
  122. (1 << 0), (1 << 6),
  123. (1 << 1), (1 << 7),
  124. (1 << 2), (1 << 4),
  125. };
  126. constexpr std::array<std::array<int, 4>, 26> zvv {{
  127. {{0, 1, 4, 5}}, {{3, 2, 7, 6}}, {{0, 1, 2, 3}},
  128. {{4, 5, 6, 7}}, {{0, 3, 4, 7}}, {{1, 2, 5, 6}},
  129. {{-1,-1,1,2}}, {{-1,-1,4,7}}, {{-1,-1,0,1}},{{-1,-1,7,6}},
  130. {{-1,-1,0,3}}, {{-1,-1,5,6}}, {{-1,-1,2,3}}, {{-1,-1,5,4}},
  131. {{-1,-1,1,5}}, {{-1,-1,3,7}}, {{-1,-1,0,4}}, {{-1,-1,2,6}},
  132. {{-1,-1,-1,3}}, {{-1,-1,-1,5}}, {{-1,-1,-1,0}}, {{-1,-1,-1,6}},
  133. {{-1,-1,-1,1}}, {{-1,-1,-1,7}}, {{-1,-1,-1,2}}, {{-1,-1,-1,4}} }};
  134. for (int n = 0; n < 26; n++) { // For each neighbor, check the hash table to see if its been added before
  135. Eigen::RowVector3i nkey = pi + neighbors[n];
  136. auto nbr = visited.find(nkey);
  137. if (nbr != visited.end()) { // We've already visited this neighbor, use references to its vertices instead of duplicating them
  138. vertexAlreadyAdded |= zv[n];
  139. for (int i = 0; i < 4; i++)
  140. {
  141. if (zvv[n][i]!=-1)
  142. {
  143. cube[zvv[n][i]] = CI_vector[nbr->second][zvv[n % 2 == 0 ? n + 1 : n - 1][i]];
  144. }
  145. }
  146. } else {
  147. queue.push_back(nkey); // Otherwise, we have not visited the neighbor, put it in the BFS queue
  148. }
  149. }
  150. for (int i = 0; i < 8; i++) { // Add new, non-visited,2 vertices to the arrays
  151. if (0 == ((1 << i) & vertexAlreadyAdded)) {
  152. cube[i] = CS_vector.size();
  153. CV_vector.push_back(cubeCorners[i]);
  154. CS_vector.push_back(cubeScalars[i]);
  155. }
  156. }
  157. visited[pi] = CI_vector.size();
  158. CI_vector.push_back(cube);
  159. }
  160. CV.conservativeResize(CV_vector.size(), 3);
  161. CS.conservativeResize(CS_vector.size(), 1);
  162. CI.conservativeResize(CI_vector.size(), 8);
  163. // If you pass in column-major matrices, this is going to be slooooowwwww
  164. for (int i = 0; i < CV_vector.size(); i++) {
  165. CV.row(i) = CV_vector[i];
  166. }
  167. for (int i = 0; i < CS_vector.size(); i++) {
  168. CS(i) = CS_vector[i];
  169. }
  170. for (int i = 0; i < CI_vector.size(); i++) {
  171. CI.row(i) = CI_vector[i];
  172. }
  173. }
  174. #ifdef IGL_STATIC_LIBRARY
  175. // Explicit template instantiation
  176. // generated by autoexplicit.sh
  177. template void igl::sparse_voxel_grid<Eigen::Matrix<double, 1, 3, 1, 1, 3>, std::function<double (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&)>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 8, 0, -1, 8> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, std::function<double (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&)> const&, double, int, 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, 8, 0, -1, 8> >&);
  178. template void igl::sparse_voxel_grid<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class std::function<double(class Eigen::Matrix<double, -1, -1, 0, -1, -1> const &)>, class Eigen::Matrix<double, -1, 1, 0, -1, 1>, class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1> >(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1> > const &, class std::function<double(class Eigen::Matrix<double, -1, -1, 0, -1, -1> const &)> const &, double, int, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 1, 0, -1, 1> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > &);
  179. template void igl::sparse_voxel_grid<Eigen::Matrix<double, 1, 3, 1, 1, 3>, std::function<double (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&)>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, 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<double (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&)> const&, double, int, 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> >&);
  180. template void igl::sparse_voxel_grid<Eigen::Matrix<double, 1, 3, 1, 1, 3>, std::function<double (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&)>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, 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<double (Eigen::Matrix<double, 1, 3, 1, 1, 3> const&)> const&, double, int, 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> >&);
  181. #endif