unique_sparse_voxel_corners.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2025 Alec Jacobson <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "unique_sparse_voxel_corners.h"
  9. #include "matlab_format.h"
  10. #include "unique.h"
  11. #include <cassert>
  12. #include <iostream>
  13. namespace
  14. {
  15. // Match the yxz binary counting order in marching_cubes/sparse_voxel_grid
  16. const int marching_cubes_reoder[] = {1,0,2,3,5,4,6,7};
  17. }
  18. template <
  19. typename Derivedijk,
  20. typename Derivedunique_ijk,
  21. typename DerivedJ
  22. >
  23. IGL_INLINE void igl::unique_sparse_voxel_corners(
  24. const int depth,
  25. const Eigen::MatrixBase<Derivedijk> & ijk,
  26. Eigen::PlainObjectBase<Derivedunique_ijk> & unique_ijk,
  27. Eigen::PlainObjectBase<DerivedJ> & J)
  28. {
  29. using MatrixiX3R = Eigen::Matrix<int,Eigen::Dynamic,3,Eigen::RowMajor>;
  30. // slow, precise hashing. Not sure why I didn't just use unique_rows on #ijk*8
  31. // by 3...
  32. const Eigen::Matrix<std::int64_t,1,3> coeffs(
  33. 1,
  34. //static_cast<std::int64_t>(std::pow(2,depth) + 1),
  35. (1 << depth) + 1,
  36. //static_cast<std::int64_t>(std::pow(2,depth) + 1) * (std::pow(2,depth) + 1));
  37. ((1 << depth) +1)*((1 << depth) +1));
  38. const auto ijk2code = [&coeffs](const int i, const int j, const int k)->std::int64_t
  39. {
  40. // code = i*(2.^depth + 1)^0 + j*(2.^depth + 1)^1 + k*(2.^depth + 1)^2;
  41. // Probably can just use 2.^(depth+1) instead of (2.^depth + 1) and use bit
  42. // shifting?
  43. const std::int64_t code =
  44. static_cast<std::int64_t>(i) * coeffs[0] +
  45. static_cast<std::int64_t>(j) * coeffs[1] +
  46. static_cast<std::int64_t>(k) * coeffs[2];
  47. return code;
  48. };
  49. const auto code2ijk = [&coeffs](const std::int64_t code, int & i, int & j, int & k)
  50. {
  51. k = static_cast<int>(code / coeffs[2]);
  52. j = static_cast<int>((code - k * coeffs[2]) / coeffs[1]);
  53. i = static_cast<int>(code - j * coeffs[1] - k * coeffs[2]);
  54. };
  55. // Should use parallel_for
  56. Eigen::Matrix<std::int64_t,Eigen::Dynamic,8,Eigen::RowMajor> codes(ijk.rows(),8);
  57. for(int c = 0;c<ijk.rows();c++)
  58. {
  59. for(int i = 0;i<8;i++)
  60. {
  61. Eigen::RowVector3i ijk_c(
  62. ijk(c,0) + ((i&2) ? 1 : 0),
  63. ijk(c,1) + ((i&4) ? 1 : 0),
  64. ijk(c,2) + ((i&1) ? 1 : 0));
  65. const std::int64_t code = ijk2code(ijk_c(0), ijk_c(1), ijk_c(2));
  66. const int k = marching_cubes_reoder[i];
  67. codes(c,k) = code;
  68. #ifndef NDEBUG
  69. Eigen::RowVector3i ijk_c_check;
  70. code2ijk(code,ijk_c_check(0),ijk_c_check(1),ijk_c_check(2));
  71. //printf("ijk2code(%d,%d,%d) = %ld\n",
  72. // ijk_c(0),ijk_c(1),ijk_c(2),code);
  73. //printf(" code2ijk(%ld) = %d,%d,%d\n",
  74. // code, ijk_c_check(0),ijk_c_check(1),ijk_c_check(2));
  75. // Check that the code is correct
  76. assert(ijk_c_check(0) == ijk_c(0) && ijk_c_check(1) == ijk_c(1) &&
  77. ijk_c_check(2) == ijk_c(2) &&
  78. "ijk2code and code2ijk are not consistent");
  79. #endif
  80. }
  81. }
  82. // igl::unique is the bottleneck by far.
  83. // unique_rows might actually be faster because it doesn't do roundtrips to
  84. // std::vector
  85. Eigen::VectorXi I;
  86. {
  87. Eigen::Matrix<std::int64_t,Eigen::Dynamic,1> _;
  88. Eigen::Matrix<typename DerivedJ::Scalar,Eigen::Dynamic,1> Jvec;
  89. // igl::unique has a lot of internal copies :-(
  90. igl::unique(codes,_,I,Jvec);
  91. // reshape Jvec into ijk.rows() by 8
  92. J = Jvec.reshaped(ijk.rows(),8);
  93. }
  94. // Map of codes as vector
  95. const auto codes_vec = codes.reshaped();
  96. unique_ijk.resize(I.size(),3);
  97. for(int c = 0;c<I.size();c++)
  98. {
  99. code2ijk(codes_vec(I(c)),unique_ijk(c,0),unique_ijk(c,1),unique_ijk(c,2));
  100. }
  101. }
  102. template<
  103. typename Derivedorigin,
  104. typename Derivedijk,
  105. typename Derivedunique_ijk,
  106. typename DerivedJ,
  107. typename Derivedunique_corners
  108. >
  109. IGL_INLINE void igl::unique_sparse_voxel_corners(
  110. const Eigen::MatrixBase<Derivedorigin> & origin,
  111. const typename Derivedorigin::Scalar h0,
  112. const int depth,
  113. const Eigen::MatrixBase<Derivedijk> & ijk,
  114. Eigen::PlainObjectBase<Derivedunique_ijk> & unique_ijk,
  115. Eigen::PlainObjectBase<DerivedJ> & J,
  116. Eigen::PlainObjectBase<Derivedunique_corners> & unique_corners)
  117. {
  118. unique_sparse_voxel_corners(depth,ijk,unique_ijk,J);
  119. using Scalar = typename Derivedunique_corners::Scalar;
  120. const Scalar h = h0 / (1 << depth);
  121. unique_corners.resize(unique_ijk.rows(),3);
  122. for(int c = 0;c<unique_ijk.rows();c++)
  123. {
  124. unique_corners(c,0) = origin(0) + h * unique_ijk(c,1);
  125. unique_corners(c,1) = origin(1) + h * unique_ijk(c,0);
  126. unique_corners(c,2) = origin(2) + h * unique_ijk(c,2);
  127. }
  128. }
  129. #ifdef IGL_STATIC_LIBRARY
  130. // Explicit template instantiation
  131. template void igl::unique_sparse_voxel_corners<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 8, 1, -1, 8>>(int, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 8, 1, -1, 8>>&);
  132. template void igl::unique_sparse_voxel_corners<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 8, 1, -1, 8>, Eigen::Matrix<double, -1, 3, 1, -1, 3>>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3>> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3>::Scalar, int, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3>>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 8, 1, -1, 8>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3>>&);
  133. #endif